Module: FalkorLib::Git

Defined in:
lib/falkorlib/git/base.rb

Overview

Management of Git operations

Class Method Summary collapse

Class Method Details

.add(path, msg = "") ⇒ Object

Add a file/whatever to Git and commit it



214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/falkorlib/git/base.rb', line 214

def add(path, msg = "")
 exit_status = 0
    dir  = File.realpath File.dirname(path)
    root = rootdir(path)
    relative_path_to_root = Pathname.new( File.realpath(path) ).relative_path_from Pathname.new(root)
    real_msg = (msg.empty? ? "add '#{relative_path_to_root}'" : msg)
    Dir.chdir( dir ) do
  exit_status = run %{
          git add #{path}
          git commit -s -m "#{real_msg}" #{path}
        }
    end
 exit_status.to_i
end

.branch?(path = Dir.pwd) ⇒ Boolean

Get the current git branch

Returns:

  • (Boolean)


165
166
167
# File 'lib/falkorlib/git/base.rb', line 165

def branch?(path = Dir.pwd)
    list_branch(path)[0]
end

.command?(cmd, path = Dir.pwd) ⇒ Boolean

Check the availability of a given git command

Returns:

  • (Boolean)


57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/falkorlib/git/base.rb', line 57

def command?(cmd, path = Dir.pwd)
    cg = MiniGit::Capturing.new(path)
    cmd_list = cg.help :a => true
    # typical run:
    # usage: git [--version] [--help] [-C <path>] [-c name=value]
    #            [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
    #            [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]
    #            [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
    #            <command> [<args>]
    #
    # available git commands in '/usr/local/Cellar/git/1.8.5.2/libexec/git-core'
    #
    #   add   [...]        #   [...]          | The part we are interested in, delimited by '\n\n' sequence
    #   [...]         /
    #
    # 'git help -a' and 'git help -g' lists available subcommands and some
    # concept guides. See 'git help <command>' or 'git help <concept>'
    # to read about a specific subcommand or concept
    l = cmd_list.split("\n\n")
    l.shift # useless first part
    #ap l
    subl = l.each_index.select{|i| l[i] =~ /^\s\s+/ } # find sublines that starts with at least two whitespaces
    #ap subl
    return false if subl.empty?
    subl.any? { |i| l[i].split.include?(cmd) }
end

.config_warn(type = :subtrees) ⇒ Object

Raise a warning message if subtree/submodule section is not present



398
399
400
401
402
403
404
405
406
407
408
409
410
411
# File 'lib/falkorlib/git/base.rb', line 398

def config_warn(type = :subtrees)
    warn "You shall setup 'FalkorLib.config.git[#{type.to_sym}]' to configure #{type} as follows:"
    warn "     FalkorLib.config.git do |c|"
    warn "       c[#{type.to_sym}] = {"
    warn "          '<subdir>' => {"
    warn "             :url    => '<giturl>',"
    warn "             :branch => 'develop'   # if different from master"
    warn "          },"
    warn "        }"
    warn "     end"
    if type == :submodules
        warn "This will configure the Git submodule into FalkorLib.config.git.submodulesdir i.e. '#{ FalkorLib.config.git.submodulesdir}'"
    end
end

.create_branch(branch, path = Dir.pwd) ⇒ Object

Create a new branch



128
129
130
131
132
133
# File 'lib/falkorlib/git/base.rb', line 128

def create_branch(branch, path = Dir.pwd)
 #ap method(__method__).parameters.map { |arg| arg[1] }
 g = MiniGit.new(path)
 error "not yet any commit performed -- You shall do one" unless has_commits?(path) 
    g.branch "#{branch}"
end

.delete_branch(branch, path = Dir.pwd, opts = { :force => false }) ⇒ Object

Delete a branch.



136
137
138
139
140
# File 'lib/falkorlib/git/base.rb', line 136

def delete_branch(branch, path = Dir.pwd, opts = { :force => false })
    g = MiniGit.new(path)
 error "'#{branch}' is not a valid existing branch" unless list_branch(path).include?( branch )
 g.branch (opts[:force] ? :D : :d) => "#{branch}"
end

.dirty?(path = Dir.pwd) ⇒ Boolean

Check if a git directory is in dirty mode git diff –shortstat 2> /dev/null | tail -n1

Returns:

  • (Boolean)


231
232
233
234
235
236
# File 'lib/falkorlib/git/base.rb', line 231

def dirty?(path = Dir.pwd)
    g = MiniGit.new(path)
    a = g.capturing.diff :shortstat => true
    #ap a
    ! a.empty?
end

.fetch(path = Dir.pwd) ⇒ Object

Fetch the latest changes



143
144
145
146
147
# File 'lib/falkorlib/git/base.rb', line 143

def fetch(path = Dir.pwd)
    Dir.chdir( path ) do
        execute "git fetch --all -v"
    end
end

.gitdir(path = Dir.pwd) ⇒ Object

Return the git root directory for the path (current directory by default)



122
123
124
125
# File 'lib/falkorlib/git/base.rb', line 122

def gitdir(path = Dir.pwd)
    g = MiniGit.new
    g.find_git_dir(path)[0]
end

.grab(branch, path = Dir.pwd, remote = 'origin') ⇒ Object

Grab a remote branch



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/falkorlib/git/base.rb', line 170

def grab(branch, path = Dir.pwd, remote = 'origin')
    exit_status = 1
    error "no branch provided" if branch.nil?
    remotes  = FalkorLib::Git.remotes(path)
    branches = FalkorLib::Git.list_branch(path)
    Dir.chdir(FalkorLib::Git.rootdir( path ) ) do
        if branches.include? "remotes/#{remote}/#{branch}"
            info "Grab the branch '#{remote}/#{branch}'"
            exit_status = execute "git branch --set-upstream #{branch} #{remote}/#{branch}"
        else
            warning "the remote branch '#{remote}/#{branch}' cannot be found"
        end
    end
    exit_status
end

.has_commits?(path) ⇒ Boolean

Check if the repositories already holds some commits

Returns:

  • (Boolean)


47
48
49
50
51
52
53
54
# File 'lib/falkorlib/git/base.rb', line 47

def has_commits?(path)
 res = false
 Dir.chdir(path) do
  stdout, stderr, exit_status = Open3.capture3( "git rev-parse HEAD" ) 
  res = (exit_status == 0)
 end
 res
end

.init(path = Dir.pwd) ⇒ Object

Initialize a git repository



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/falkorlib/git/base.rb', line 86

def init(path = Dir.pwd)
    # FIXME for travis test: ensure the global git configurations
    # 'user.email' and 'user.name' are set
    [ 'user.name', 'user.email' ].each do |userconf|
        if MiniGit[userconf].nil?
            warn "The Git global configuration '#{userconf}' is not set so"
            warn "you should *seriously* consider setting them by running\n\t git config --global #{userconf} 'your_#{userconf.sub(/\./, '_')}'"
            default_val = ENV['USER']
            default_val += '@domain.org' if userconf =~ /email/
            warn "Now putting a default value '#{default_val}' you could change later on"
            run %{
                 git config --global #{userconf} "#{default_val}"
            }
            #MiniGit[userconf] = default_val
        end
    end
 exit_status = 1
 #info "Initialize "
 Dir.chdir( path ) do 
  execute "git init" unless FalkorLib.config.debug 
  exit_status = $?.to_i
 end
    # #puts "#init #{path}"
    # Dir.chdir( "#{path}" ) do
    #     %x[ pwd && git init ] unless FalkorLib.config.debug
    # end
 exit_status
end

.init?(path = Dir.pwd) ⇒ Boolean

Check if a git directory has been initialized

Returns:

  • (Boolean)


37
38
39
40
41
42
43
44
# File 'lib/falkorlib/git/base.rb', line 37

def init?(path = Dir.pwd)
    begin
        g = MiniGit.new(path)
    rescue Exception
        return false
    end
    return true
end

.last_tag_commit(path = Dir.pwd) ⇒ Object

Get the last tag commit, or nil if no tag can be found



239
240
241
242
243
244
245
# File 'lib/falkorlib/git/base.rb', line 239

def last_tag_commit(path = Dir.pwd)
 res = nil
 g = MiniGit.new(path)
 # git rev-list --tags --max-count=1)
    a = g.capturing.rev_list :tags => true, :max_count => 1
 a          
end

.list_branch(path = Dir.pwd) ⇒ Object

Get an array of the local branches present (first element is always the current branch)



151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/falkorlib/git/base.rb', line 151

def list_branch(path = Dir.pwd)
    cg = MiniGit::Capturing.new(path)
    res = cg.branch :a => true
    res = res.split("\n")
    # Eventually reorder to make the first element of the array the current branch
    i = res.find_index { |e| e =~ /^\*\s/ }
    unless (i.nil? || i == 0)
        res[0], res[i] = res[i], res[0]
    end
    res.each { |e| e.sub!(/^\*?\s+/, '')  }
    res
end

.list_files(path = Dir.pwd) ⇒ Object

List the files currently version



208
209
210
211
# File 'lib/falkorlib/git/base.rb', line 208

def list_files(path = Dir.pwd)
 g = MiniGit.new(path)
 g.capturing.ls_files.split
end

.publish(branch, path = Dir.pwd, remote = 'origin') ⇒ Object

Publish a branch on the remote



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/falkorlib/git/base.rb', line 187

def publish(branch, path = Dir.pwd, remote = 'origin')
    exit_status = 1
    error "no branch provided" if branch.nil?
    remotes  = FalkorLib::Git.remotes(path)
    branches = FalkorLib::Git.list_branch(path)
    Dir.chdir(FalkorLib::Git.rootdir( path ) ) do
        if branches.include? "remotes/#{remote}/#{branch}"
            warning "the  remote branch '#{remote}/#{branch}' already exists"
        else
            info "Publish the branch '#{branch}' on the remote '#{remote}'"
            exit_status = run %{
                  git push #{remote} #{branch}:refs/heads/#{branch}
                  git fetch #{remote}
                  git branch --set-upstream-to #{remote}/#{branch} #{branch}
        }
        end
    end
    exit_status
end

.remotes(path = Dir.pwd) ⇒ Object

List of Git remotes



248
249
250
251
# File 'lib/falkorlib/git/base.rb', line 248

def remotes(path = Dir.pwd)
    g = MiniGit.new(path)
    g.capturing.remote.split()
end

.remotes?(path = Dir.pwd) ⇒ Boolean

remotes?(path = Dir.pw)

Returns:

  • (Boolean)


254
255
256
# File 'lib/falkorlib/git/base.rb', line 254

def remotes?(path = Dir.pwd)
 return ! remotes(path).empty?
end

.rootdir(path = Dir.pwd) ⇒ Object

Return the Git working tree from the proposed path (current directory by default)



116
117
118
119
# File 'lib/falkorlib/git/base.rb', line 116

def rootdir(path = Dir.pwd)
    g = MiniGit.new
    g.find_git_dir(path)[1]
end

.submodule_init(path = Dir.pwd) ⇒ Object

Initialize git subtrees from the configuration



259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
# File 'lib/falkorlib/git/base.rb', line 259

def submodule_init(path = Dir.pwd)
    exit_status  = 1
    git_root_dir = rootdir(path)
    if File.exists?("#{git_root_dir}/.gitmodules")
        unless FalkorLib.config.git[:submodules].empty?
            # TODO: Check if it contains all submodules of the configuration
        end
    end
    #ap FalkorLib.config.git
    Dir.chdir(git_root_dir) do
        exit_status = FalkorLib::Git.submodule_update( git_root_dir )
        FalkorLib.config.git[:submodules].each do |subdir,conf|
            next if conf[:url].nil?
            url = conf[:url]
            dir = "#{FalkorLib.config.git[:submodulesdir]}/#{subdir}"
            branch = conf[:branch].nil? ? 'master' : conf[:branch]
            unless File.directory?( dir )
                info "Adding Git submodule '#{dir}' from '#{url}'"
                exit_status = run %{
                   git submodule add -b #{branch} #{url} #{dir}
                   git commit -s -m "Add Git submodule '#{dir}' from '#{url}'" .gitmodules #{dir}
                }
            end
        end
    end
    exit_status
end

.submodule_update(path = Dir.pwd) ⇒ Object

Update the Git submodules to the local registered version



288
289
290
291
292
293
294
# File 'lib/falkorlib/git/base.rb', line 288

def submodule_update(path = Dir.pwd)
 execute_in_dir(rootdir(path), 
                %{
           git submodule init
           git submodule update
    })
end

.submodule_upgrade(path = Dir.pwd) ⇒ Object

Upgrade the Git submodules to the latest HEAD version from the remote



297
298
299
300
301
302
# File 'lib/falkorlib/git/base.rb', line 297

def submodule_upgrade(path = Dir.pwd)
  execute_in_dir(rootdir(path), 
                %{
           git submodule foreach 'git fetch origin; git checkout $(git rev-parse --abbrev-ref HEAD); git reset --hard origin/$(git rev-parse --abbrev-ref HEAD); git submodule update --recursive; git clean -dfx'
     })         
end

.subtree_diff(path = Dir.pwd) ⇒ Object

Show difference between local subtree(s) and their remotes“

Raises:

  • (ArgumentError)


347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
# File 'lib/falkorlib/git/base.rb', line 347

def subtree_diff(path = Dir.pwd)
    raise ArgumentError, "Git 'subtree' command is not available" unless FalkorLib::Git.command? "subtree"
    if FalkorLib.config.git[:subtrees].empty?
        FalkorLib::Git.config_warn(:subtrees)
        return 1
    end
    exit_status = 0
    git_root_dir = rootdir(path)
    Dir.chdir(git_root_dir) do
        FalkorLib.config.git[:subtrees].each do |dir,conf|
            next if conf[:url].nil?
            url    = conf[:url]
            remote = dir.gsub(/\//, '-')
            branch = conf[:branch].nil? ? 'master' : conf[:branch]
            remotes = FalkorLib::Git.remotes
            raise IOError, "The git remote '#{remote}' is not configured" unless remotes.include?( remote )
            raise IOError, "The git subtree directory '#{dir}' does not exists" unless File.directory? ( File.join(git_root_dir, dir) )
            info "Git diff on subtree '#{dir}' with remote '#{remote}/#{branch}'"
            exit_status = execute "git diff #{remote}/#{branch} #{FalkorLib::Git.branch?( git_root_dir )}:#{dir}"
        end
    end
    exit_status
end

.subtree_init(path = Dir.pwd) ⇒ Object

Initialize git subtrees from the configuration

Raises:

  • (ArgumentError)


306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# File 'lib/falkorlib/git/base.rb', line 306

def subtree_init(path = Dir.pwd)
    raise ArgumentError, "Git 'subtree' command is not available" unless FalkorLib::Git.command? "subtree"
    if FalkorLib.config.git[:subtrees].empty?
        FalkorLib::Git.config_warn(:subtrees)
        return 1
    end
    exit_status = 0
    git_root_dir = rootdir(path)
    Dir.chdir(git_root_dir) do
        FalkorLib.config.git[:subtrees].each do |dir,conf|
            next if conf[:url].nil?
            url    = conf[:url]
            remote = dir.gsub(/\//, '-')
            branch = conf[:branch].nil? ? 'master' : conf[:branch]
            remotes = FalkorLib::Git.remotes
            unless remotes.include?( remote )
                info "Initialize Git remote '#{remote}' from URL '#{url}'"
                exit_status = execute "git remote add -f #{remote} #{url}"
            end
            unless File.directory?( File.join(git_root_dir, dir) )
                info "initialize Git subtree '#{dir}'"
                exit_status = execute "git subtree add --prefix #{dir} --squash #{remote}/#{branch}"
            end
        end

    end
    exit_status
end

.subtree_init?(path = Dir.pwd) ⇒ Boolean

Check if the subtrees have been initialized. Actually based on a naive check of sub-directory existence

Returns:

  • (Boolean)


337
338
339
340
341
342
343
# File 'lib/falkorlib/git/base.rb', line 337

def subtree_init?(path = Dir.pwd)
 res = true
 FalkorLib.config.git[:subtrees].keys.each do |dir| 
  res = res && File.directory?(File.join(path, dir)) 
 end
 res
end

.subtree_up(path = Dir.pwd) ⇒ Object Also known as: subtree_pull

Pull the latest changes, assuming the git repository is not dirty



372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
# File 'lib/falkorlib/git/base.rb', line 372

def subtree_up(path = Dir.pwd)
    error "Unable to pull subtree(s): Dirty Git repository" if FalkorLib::Git.dirty?( path )
    exit_status = 0
    git_root_dir = rootdir(path)
    Dir.chdir(git_root_dir) do
        FalkorLib.config.git[:subtrees].each do |dir,conf|
            next if conf[:url].nil?
            url    = conf[:url]
            remote = dir.gsub(/\//, '-')
            branch = conf[:branch].nil? ? 'master' : conf[:branch]
            remotes = FalkorLib::Git.remotes
            info "Pulling changes into subtree '#{dir}' using remote '#{remote}/#{branch}'"
            raise IOError, "The git remote '#{remote}' is not configured" unless remotes.include?( remote )
            info "\t\\__ fetching remote '#{remotes.join(',')}'"
            FalkorLib::Git.fetch( git_root_dir )
            raise IOError, "The git subtree directory '#{dir}' does not exists" unless File.directory? ( File.join(git_root_dir, dir) )
            info "\t\\__ pulling changes"
            exit_status = execute "git subtree pull --prefix #{dir} --squash #{remote} #{branch}"
            #exit_status = puts "git subtree pull --prefix #{dir} --squash #{remote} #{branch}"
        end
    end
    exit_status
end