falkorlib 0.1.0 → 0.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/falkorlib.rb CHANGED
@@ -1,10 +1,39 @@
1
+ # -*- encoding: utf-8 -*-
2
+ ################################################################################
3
+ # Time-stamp: <Ven 2014-06-06 17:06 svarrette>
4
+ ################################################################################
5
+ # _____ _ _ _ _ _
6
+ # | ___|_ _| | | _____ _ __| | (_) |__
7
+ # | |_ / _` | | |/ / _ \| '__| | | | '_ \
8
+ # | _| (_| | | < (_) | | | |___| | |_) |
9
+ # |_| \__,_|_|_|\_\___/|_| |_____|_|_.__/
1
10
  #
2
- # Sebastien Varrette aka Falkor's Common library to share Ruby code and `{rake,cap}` tasks
11
+ ################################################################################
12
+ # @author Sebastien Varrette <Sebastien.Varrette@uni.lu>
3
13
  #
14
+ # * [Source code](https://github.com/Falkor/falkorlib)
15
+ # * [Official Gem](https://rubygems.org/gems/falkorlib)
16
+ ################################################################################
17
+
18
+ require "awesome_print"
19
+
20
+ begin
21
+ require 'term/ansicolor'
22
+ COLOR = true
23
+ rescue Exception => e
24
+ puts "/!\\ cannot find the 'term/ansicolor' library"
25
+ puts " Consider installing it by 'gem install term-ansicolor'"
26
+ COLOR = false
27
+ end
28
+
29
+ require 'yaml'
30
+
31
+ # Sebastien Varrette aka Falkor's Common library to share Ruby code
32
+ # and `{rake,cap}` tasks
4
33
  module FalkorLib
5
34
 
6
35
  end # module FalkorLib
7
36
 
8
37
  require "falkorlib/version"
9
38
  require "falkorlib/loader"
10
- require "falkorlib/common"
39
+
@@ -1,23 +1,41 @@
1
- #!/usr/bin/ruby
2
-
3
- ### Configure colors ###
4
- begin
5
- require 'term/ansicolor'
6
- COLOR = true
7
- rescue Exception => e
8
- puts "/!\\ cannot find the 'term/ansicolor' library"
9
- puts " Consider installing it by 'gem install term-ansicolor'"
10
- COLOR = false
11
- end
12
-
13
- require 'yaml'
14
-
15
- module FalkorLib
1
+ # -*- encoding: utf-8 -*-
2
+ ################################################################################
3
+ # Time-stamp: <Jeu 2014-06-19 18:10 svarrette>
4
+ ################################################################################
5
+
6
+ require "falkorlib"
7
+ require 'open3'
8
+
9
+
10
+ module FalkorLib #:nodoc:
11
+
12
+ # @abstract
13
+ # Recipe for all my toolbox and versatile Ruby functions I'm using
14
+ # everywhere.
15
+ # You'll typically want to include the `FalkorLib::Common` module to bring
16
+ # the corresponding definitions into yoru scope.
17
+ #
18
+ # @example:
19
+ # require 'falkorlib'
20
+ # include FalkorLib::Common
21
+ #
22
+ # info 'exemple of information text'
23
+ # really_continue?
24
+ # run %{ echo 'this is an executed command' }
25
+ #
26
+ # Falkor.config.debug = true
27
+ # run %{ echo 'this is a simulated command that *will not* be executed' }
28
+ # error "that's an error text, let's exit with status code 1"
29
+ #
16
30
  module Common
17
- module_function
31
+ module_function
18
32
  ##################################
19
33
  ### Default printing functions ###
20
34
  ##################################
35
+ # Print a text in bold
36
+ def bold(str)
37
+ COLOR == true ? Term::ANSIColor.bold(str) : str
38
+ end
21
39
 
22
40
  # Print a text in green
23
41
  def green(str)
@@ -43,15 +61,16 @@ module FalkorLib
43
61
  def warning(str)
44
62
  puts cyan("/!\\ WARNING: " + str)
45
63
  end
46
- def warn(str)
47
- warning(str)
48
- end
64
+ alias :warn :warning
65
+
49
66
  ## Print an error message and abort
50
67
  def error(str)
51
68
  #abort red("*** ERROR *** " + str)
52
- $stderr.puts red("*** ERROR *** " + str)
53
- exit 1
69
+ $stderr.puts red("*** ERROR *** " + str)
70
+ exit 1
54
71
  end
72
+
73
+ ## simple helper text to mention a non-implemented feature
55
74
  def not_implemented()
56
75
  error("NOT YET IMPLEMENTED")
57
76
  end
@@ -83,28 +102,61 @@ module FalkorLib
83
102
 
84
103
  ## Check for the presence of a given command
85
104
  def command?(name)
86
- `which #{name}`
87
- $?.success?
105
+ `which #{name}`
106
+ $?.success?
88
107
  end
89
108
 
90
- ## Execute a given command - exit if status != 0
91
- def execute(cmd)
92
- sh %{#{cmd}} do |ok, res|
93
- if ! ok
94
- error("The command '#{cmd}' failed with exit status #{res.exitstatus}")
109
+ ## Execute a given command, return exit code and print nicely stdout and stderr
110
+ def nice_execute(cmd)
111
+ puts bold("[Running] #{cmd.gsub(/^\s*/, ' ')}")
112
+ stdout, stderr, exit_status = Open3.capture3( cmd )
113
+ unless stdout.empty?
114
+ stdout.each_line do |line|
115
+ print "** [out] #{line}"
116
+ $stdout.flush
95
117
  end
96
- end
118
+ end
119
+ unless stderr.empty?
120
+ stderr.each_line do |line|
121
+ print red("** [err] #{line}")
122
+ $stderr.flush
123
+ end
124
+ end
125
+ exit_status
126
+ end
127
+
128
+ # Simpler version that use the system call
129
+ def execute(cmd)
130
+ puts bold("[Running] #{cmd.gsub(/^\s*/, ' ')}")
131
+ system(cmd)
132
+ $?
133
+ end
134
+
135
+
136
+
137
+
138
+ ## Execute a given command - exit if status != 0
139
+ def exec_or_exit(cmd)
140
+ status = execute(cmd)
141
+ if (status.to_i != 0)
142
+ error("The command '#{cmd}' failed with exit status #{status.to_i}")
143
+ end
144
+ res
97
145
  end
98
146
 
99
147
  ## "Nice" way to present run commands
100
148
  ## Ex: run %{ hostname -f }
101
149
  def run(cmds)
102
- puts bold("[Running]\n#{cmds.gsub(/^\s*/, ' ')}")
103
- #puts cmds.split(/\n */).inspect
104
- cmds.split(/\n */).each do |cmd|
105
- next if cmd.empty?
106
- system("#{cmd}") unless DEBUG
107
- end
150
+ exit_status = 0
151
+ puts bold("[Running]\n#{cmds.gsub(/^\s*/, ' ')}")
152
+ $stdout.flush
153
+ #puts cmds.split(/\n */).inspect
154
+ cmds.split(/\n */).each do |cmd|
155
+ next if cmd.empty?
156
+ system("#{cmd}") unless FalkorLib.config.debug
157
+ exit_status = $?
158
+ end
159
+ exit_status
108
160
  end
109
161
 
110
162
  ###############################
@@ -113,16 +165,16 @@ module FalkorLib
113
165
 
114
166
  # Return the yaml content as a Hash object
115
167
  def load_config(filepath)
116
- YAML::load_file(filepath)
168
+ YAML::load_file(filepath)
117
169
  end
118
170
 
119
171
  # Store the Hash object as a Yaml file
120
172
  def store_config(filepath, hash)
121
- File.open( filepath, 'w') do |f|
122
- f.print "# ", File.basename(filepath), "\n"
123
- f.puts "# /!\\ DO NOT EDIT THIS FILE: it has been automatically generated"
124
- f.puts hash.to_yaml
125
- end
173
+ File.open( filepath, 'w') do |f|
174
+ f.print "# ", File.basename(filepath), "\n"
175
+ f.puts "# /!\\ DO NOT EDIT THIS FILE: it has been automatically generated"
176
+ f.puts hash.to_yaml
177
+ end
126
178
  end
127
179
 
128
180
 
@@ -0,0 +1,91 @@
1
+ # -*- encoding: utf-8 -*-
2
+ ################################################################################
3
+ # Time-stamp: <Mer 2014-06-18 17:17 svarrette>
4
+ ################################################################################
5
+ # FalkorLib Configuration
6
+ #
7
+ # Resources:
8
+ # * https://github.com/markbates/cover_me/blob/master/lib/cover_me/config.rb
9
+ ################################################################################
10
+ require "falkorlib"
11
+
12
+ require "configatron"
13
+ require "configatron/store"
14
+
15
+ module FalkorLib #:nodoc:
16
+
17
+ class << self
18
+ # Yields up a configuration object when given a block.
19
+ # Without a block it just returns the configuration object.
20
+ # Uses Configatron under the covers.
21
+ #
22
+ # Example:
23
+ # FalkorLib.config do |c|
24
+ # c.foo = :bar
25
+ # end
26
+ #
27
+ # FalkorLib.config.foo # => :bar
28
+ def config(&block)
29
+ yield configuration if block_given?
30
+ configuration
31
+ end
32
+
33
+ ## initiate the configuration (with default value) if needed
34
+ def configuration
35
+ @config ||= Configatron::Store.new(options = FalkorLib::Config.default)
36
+ end
37
+ end
38
+
39
+
40
+ module Config
41
+ # Defaults global settings
42
+ DEFAULTS = {
43
+ :debug => false,
44
+ :root => Dir.pwd
45
+ }
46
+
47
+ module_function
48
+
49
+ ## Build the default configuration hash, to be used to initiate the default.
50
+ # The hash is built depending on the loaded files.
51
+ def default
52
+ res = FalkorLib::Config::DEFAULTS
53
+ $LOADED_FEATURES.each do |path|
54
+ res[:git] = FalkorLib::Config::Git::DEFAULTS if path.include?('lib/falkorlib/git.rb')
55
+ res[:gitflow] = FalkorLib::Config::GitFlow::DEFAULTS if path.include?('lib/falkorlib/git.rb')
56
+ res[:versioning] = FalkorLib::Config::Versioning::DEFAULTS if path.include?('lib/falkorlib/versioning.rb')
57
+ end
58
+ res
59
+ end
60
+
61
+ end
62
+
63
+ # config = Thread.current[:config] ||= Configatron::Store.new
64
+
65
+ # # Singleton configuration class
66
+ # class Config
67
+ # include Singleton
68
+
69
+ # # Give memoized defaults for locked configuration options found in /config/falkorlib.yml file
70
+ # #
71
+ # # @example Usage
72
+ # # conf = Configuration.instance.defaults
73
+ # # conf.base_url #=> "http://ambito.com/economia/mercados/monedas/dolar/"
74
+ # # conf.blue.buy.xpath #=> "//*[@id=\"contenido\"]/div[1]/div[2]/div/div/div[2]/big"
75
+ # #
76
+ # # @return [Configatron::Store] the magic configuration instance with hash and dot '.' indifferent access
77
+ # def defaults
78
+ # return @config if @config
79
+
80
+ # @config = Configatron::Store.new
81
+ # file_path = File.expand_path('../../../config/falkorlib.yml', __FILE__)
82
+ # hash_config = YAML::load_file(file_path)
83
+
84
+ # @config.configure_from_hash(hash_config)
85
+ # @config.lock!
86
+ # @config
87
+ # end
88
+ # end
89
+
90
+
91
+ end # module FalkorLib
@@ -0,0 +1,15 @@
1
+ # -*- encoding: utf-8 -*-
2
+ ################################################################################
3
+ # Time-stamp: <Ven 2014-06-06 13:12 svarrette>
4
+ ################################################################################
5
+ # Management of Git [flow] operations
6
+
7
+ require "falkorlib"
8
+
9
+ module FalkorLib #:nodoc:
10
+
11
+ end # module FalkorLib
12
+
13
+ require "falkorlib/git/base"
14
+ require "falkorlib/git/flow"
15
+
@@ -0,0 +1,405 @@
1
+ # -*- encoding: utf-8 -*-
2
+ ################################################################################
3
+ # Time-stamp: <Mer 2014-06-18 21:59 svarrette>
4
+ ################################################################################
5
+ # Interface for the main Git operations
6
+ #
7
+ # On purpose, I try to avoid using the Git library to avoid instanciate the Git
8
+ # class and thus managing the working directory
9
+
10
+ require "falkorlib"
11
+ require "falkorlib/common"
12
+
13
+ require "minigit"
14
+ require "pathname"
15
+
16
+ include FalkorLib::Common
17
+
18
+ module FalkorLib #:nodoc:
19
+ module Config
20
+
21
+ # Default configuration for Git
22
+ module Git
23
+ # Git defaults for FalkorLib
24
+ DEFAULTS = {
25
+ :submodulesdir => '.submodules',
26
+ :submodules => {},
27
+ :subtrees => {}
28
+ }
29
+ end
30
+ end
31
+
32
+ # Management of Git operations
33
+ module Git
34
+ module_function
35
+
36
+ ## Check if a git directory has been initialized
37
+ def init?(path = Dir.pwd)
38
+ begin
39
+ g = MiniGit.new(path)
40
+ rescue Exception
41
+ return false
42
+ end
43
+ return true
44
+ end
45
+
46
+ ## Check if the repositories already holds some commits
47
+ def has_commits?(path)
48
+ res = false
49
+ Dir.chdir(path) do
50
+ stdout, stderr, exit_status = Open3.capture3( "git rev-parse HEAD" )
51
+ res = (exit_status == 0)
52
+ end
53
+ res
54
+ end
55
+
56
+ ## Check the availability of a given git command
57
+ def command?(cmd, path = Dir.pwd)
58
+ cg = MiniGit::Capturing.new(path)
59
+ cmd_list = cg.help :a => true
60
+ # typical run:
61
+ # usage: git [--version] [--help] [-C <path>] [-c name=value]
62
+ # [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
63
+ # [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]
64
+ # [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
65
+ # <command> [<args>]
66
+ #
67
+ # available git commands in '/usr/local/Cellar/git/1.8.5.2/libexec/git-core'
68
+ #
69
+ # add [...] \
70
+ # [...] | The part we are interested in, delimited by '\n\n' sequence
71
+ # [...] /
72
+ #
73
+ # 'git help -a' and 'git help -g' lists available subcommands and some
74
+ # concept guides. See 'git help <command>' or 'git help <concept>'
75
+ # to read about a specific subcommand or concept
76
+ l = cmd_list.split("\n\n")
77
+ l.shift # useless first part
78
+ #ap l
79
+ subl = l.each_index.select{|i| l[i] =~ /^\s\s+/ } # find sublines that starts with at least two whitespaces
80
+ #ap subl
81
+ return false if subl.empty?
82
+ subl.any? { |i| l[i].split.include?(cmd) }
83
+ end
84
+
85
+ ## Initialize a git repository
86
+ def init(path = Dir.pwd)
87
+ # FIXME for travis test: ensure the global git configurations
88
+ # 'user.email' and 'user.name' are set
89
+ [ 'user.name', 'user.email' ].each do |userconf|
90
+ if MiniGit[userconf].nil?
91
+ warn "The Git global configuration '#{userconf}' is not set so"
92
+ warn "you should *seriously* consider setting them by running\n\t git config --global #{userconf} 'your_#{userconf.sub(/\./, '_')}'"
93
+ default_val = ENV['USER']
94
+ default_val += '@domain.org' if userconf =~ /email/
95
+ warn "Now putting a default value '#{default_val}' you could change later on"
96
+ run %{
97
+ git config --global #{userconf} "#{default_val}"
98
+ }
99
+ #MiniGit[userconf] = default_val
100
+ end
101
+ end
102
+ #puts "#init #{path}"
103
+ Dir.chdir( "#{path}" ) do
104
+ %x[ pwd && git init ] unless FalkorLib.config.debug
105
+ end
106
+ end
107
+
108
+ # Return the Git working tree from the proposed path (current directory by default)
109
+ def rootdir(path = Dir.pwd)
110
+ g = MiniGit.new
111
+ g.find_git_dir(path)[1]
112
+ end
113
+
114
+ # Return the git root directory for the path (current directory by default)
115
+ def gitdir(path = Dir.pwd)
116
+ g = MiniGit.new
117
+ g.find_git_dir(path)[0]
118
+ end
119
+
120
+ # Create a new branch
121
+ def create_branch(branch, path = Dir.pwd)
122
+ #ap method(__method__).parameters.map { |arg| arg[1] }
123
+ g = MiniGit.new(path)
124
+ error "not yet any commit performed -- You shall do one" unless has_commits?(path)
125
+ g.branch "#{branch}"
126
+ end
127
+
128
+ # Delete a branch.
129
+ def delete_branch(branch, path = Dir.pwd, opts = { :force => false })
130
+ g = MiniGit.new(path)
131
+ error "'#{branch}' is not a valid existing branch" unless list_branch(path).include?( branch )
132
+ g.branch (opts[:force] ? :D : :d) => "#{branch}"
133
+ end
134
+
135
+ ## Fetch the latest changes
136
+ def fetch(path = Dir.pwd)
137
+ Dir.chdir( path ) do
138
+ execute "git fetch --all -v"
139
+ end
140
+ end
141
+
142
+ ## Get an array of the local branches present (first element is always the
143
+ ## current branch)
144
+ def list_branch(path = Dir.pwd)
145
+ cg = MiniGit::Capturing.new(path)
146
+ res = cg.branch :a => true
147
+ res = res.split("\n")
148
+ # Eventually reorder to make the first element of the array the current branch
149
+ i = res.find_index { |e| e =~ /^\*\s/ }
150
+ unless (i.nil? || i == 0)
151
+ res[0], res[i] = res[i], res[0]
152
+ end
153
+ res.each { |e| e.sub!(/^\*?\s+/, '') }
154
+ res
155
+ end
156
+
157
+ ## Get the current git branch
158
+ def branch?(path = Dir.pwd)
159
+ list_branch(path)[0]
160
+ end
161
+
162
+ ## Grab a remote branch
163
+ def grab(branch, path = Dir.pwd, remote = 'origin')
164
+ exit_status = 1
165
+ error "no branch provided" if branch.nil?
166
+ remotes = FalkorLib::Git.remotes(path)
167
+ branches = FalkorLib::Git.list_branch(path)
168
+ Dir.chdir(FalkorLib::Git.rootdir( path ) ) do
169
+ if branches.include? "remotes/#{remote}/#{branch}"
170
+ info "Grab the branch '#{remote}/#{branch}'"
171
+ exit_status = execute "git branch --set-upstream #{branch} #{remote}/#{branch}"
172
+ else
173
+ warning "the remote branch '#{remote}/#{branch}' cannot be found"
174
+ end
175
+ end
176
+ exit_status
177
+ end
178
+
179
+ ## Publish a branch on the remote
180
+ def publish(branch, path = Dir.pwd, remote = 'origin')
181
+ exit_status = 1
182
+ error "no branch provided" if branch.nil?
183
+ remotes = FalkorLib::Git.remotes(path)
184
+ branches = FalkorLib::Git.list_branch(path)
185
+ Dir.chdir(FalkorLib::Git.rootdir( path ) ) do
186
+ if branches.include? "remotes/#{remote}/#{branch}"
187
+ warning "the remote branch '#{remote}/#{branch}' already exists"
188
+ else
189
+ info "Publish the branch '#{branch}' on the remote '#{remote}'"
190
+ exit_status = run %{
191
+ git push #{remote} #{branch}:refs/heads/#{branch}
192
+ git fetch #{remote}
193
+ git branch --set-upstream-to #{remote}/#{branch} #{branch}
194
+ }
195
+ end
196
+ end
197
+ exit_status
198
+ end
199
+
200
+ ## List the files currently version
201
+ def list_files(path = Dir.pwd)
202
+ g = MiniGit.new(path)
203
+ g.capturing.ls_files.split
204
+ end
205
+
206
+
207
+
208
+ ## Add a file/whatever to Git and commit it
209
+ def add(path, msg = "")
210
+ exit_status = 0
211
+ dir = File.realpath File.dirname(path)
212
+ root = rootdir(path)
213
+ relative_path_to_root = Pathname.new( File.realpath(path) ).relative_path_from Pathname.new(root)
214
+ real_msg = (msg.empty? ? "add '#{relative_path_to_root}'" : msg)
215
+ Dir.chdir( dir ) do
216
+ exit_status = run %{
217
+ git add #{path}
218
+ git commit -s -m "#{real_msg}" #{path}
219
+ }
220
+ end
221
+ exit_status.to_i
222
+ end
223
+
224
+ ## Check if a git directory is in dirty mode
225
+ # git diff --shortstat 2> /dev/null | tail -n1
226
+ def dirty?(path = Dir.pwd)
227
+ g = MiniGit.new(path)
228
+ a = g.capturing.diff :shortstat => true
229
+ #ap a
230
+ ! a.empty?
231
+ end
232
+
233
+ ## Get the last tag commit, or nil if no tag can be found
234
+ def last_tag_commit(path = Dir.pwd)
235
+ res = nil
236
+ g = MiniGit.new(path)
237
+ # git rev-list --tags --max-count=1)
238
+ a = g.capturing.rev_list :tags => true, :max_count => 1
239
+ a
240
+ end # last_tag_commit
241
+
242
+ ## List of Git remotes
243
+ def remotes(path = Dir.pwd)
244
+ g = MiniGit.new(path)
245
+ g.capturing.remote.split()
246
+ end
247
+
248
+ ## Initialize git subtrees from the configuration
249
+ def submodule_init(path = Dir.pwd)
250
+ exit_status = 1
251
+ git_root_dir = rootdir(path)
252
+ if File.exists?("#{git_root_dir}/.gitmodules")
253
+ unless FalkorLib.config.git[:submodules].empty?
254
+ # TODO: Check if it contains all submodules of the configuration
255
+ end
256
+ end
257
+ #ap FalkorLib.config.git
258
+ Dir.chdir(git_root_dir) do
259
+ exit_status = FalkorLib::Git.submodule_update( git_root_dir )
260
+ FalkorLib.config.git[:submodules].each do |subdir,conf|
261
+ next if conf[:url].nil?
262
+ url = conf[:url]
263
+ dir = "#{FalkorLib.config.git[:submodulesdir]}/#{subdir}"
264
+ branch = conf[:branch].nil? ? 'master' : conf[:branch]
265
+ unless File.directory?( dir )
266
+ info "Adding Git submodule '#{dir}' from '#{url}'"
267
+ exit_status = run %{
268
+ git submodule add -b #{branch} #{url} #{dir}
269
+ git commit -s -m "Add Git submodule '#{dir}' from '#{url}'" .gitmodules #{dir}
270
+ }
271
+ end
272
+ end
273
+ end
274
+ exit_status
275
+ end
276
+
277
+ ## Update the Git submodules to the **local** registered version
278
+ def submodule_update(path = Dir.pwd)
279
+ exit_status = 1
280
+ git_root_dir = rootdir(path)
281
+ Dir.chdir(git_root_dir) do
282
+ exit_status = run %{
283
+ git submodule init
284
+ git submodule update
285
+ }
286
+ end
287
+ exit_status
288
+ end
289
+
290
+ ## Upgrade the Git submodules to the latest HEAD version from the remote
291
+ def submodule_upgrade(path = Dir.pwd)
292
+ exit_status = 1
293
+ git_root_dir = rootdir(path)
294
+ Dir.chdir(git_root_dir) do
295
+ exit_status = run %{
296
+ 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'
297
+ }
298
+ end
299
+ exit_status
300
+ end
301
+
302
+
303
+ ## Initialize git subtrees from the configuration
304
+ def subtree_init(path = Dir.pwd)
305
+ raise ArgumentError, "Git 'subtree' command is not available" unless FalkorLib::Git.command? "subtree"
306
+ if FalkorLib.config.git[:subtrees].empty?
307
+ FalkorLib::Git.config_warn(:subtrees)
308
+ return 1
309
+ end
310
+ exit_status = 0
311
+ git_root_dir = rootdir(path)
312
+ Dir.chdir(git_root_dir) do
313
+ FalkorLib.config.git[:subtrees].each do |dir,conf|
314
+ next if conf[:url].nil?
315
+ url = conf[:url]
316
+ remote = dir
317
+ branch = conf[:branch].nil? ? 'master' : conf[:branch]
318
+ remotes = FalkorLib::Git.remotes
319
+ unless remotes.include?( remote )
320
+ info "Initialize Git remote '#{remote}' from URL '#{url}'"
321
+ exit_status = execute "git remote add -f #{dir} #{url}"
322
+ end
323
+ unless File.directory?( File.join(git_root_dir, dir) )
324
+ info "initialize Git subtree '#{dir}'"
325
+ exit_status = execute "git subtree add --prefix #{dir} --squash #{remote}/#{branch}"
326
+ end
327
+ end
328
+
329
+ end
330
+ exit_status
331
+ end
332
+
333
+ ## Show difference between local subtree(s) and their remotes"
334
+ def subtree_diff(path = Dir.pwd)
335
+ raise ArgumentError, "Git 'subtree' command is not available" unless FalkorLib::Git.command? "subtree"
336
+ if FalkorLib.config.git[:subtrees].empty?
337
+ FalkorLib::Git.config_warn(:subtrees)
338
+ return 1
339
+ end
340
+ exit_status = 0
341
+ git_root_dir = rootdir(path)
342
+ Dir.chdir(git_root_dir) do
343
+ FalkorLib.config.git[:subtrees].each do |dir,conf|
344
+ next if conf[:url].nil?
345
+ url = conf[:url]
346
+ remote = dir
347
+ branch = conf[:branch].nil? ? 'master' : conf[:branch]
348
+ remotes = FalkorLib::Git.remotes
349
+ raise IOError, "The git remote '#{remote}' is not configured" unless remotes.include?( remote )
350
+ raise IOError, "The git subtree directory '#{dir}' does not exists" unless File.directory? ( File.join(git_root_dir, dir) )
351
+ info "Git diff on subtree '#{dir}' with remote '#{remote}/#{branch}'"
352
+ exit_status = execute "git diff #{remote}/#{branch} #{FalkorLib::Git.branch?( git_root_dir )}:#{dir}"
353
+ end
354
+ end
355
+ exit_status
356
+ end
357
+
358
+ # Pull the latest changes, assuming the git repository is not dirty
359
+ def subtree_up(path = Dir.pwd)
360
+ error "Unable to pull subtree(s): Dirty Git repository" if FalkorLib::Git.dirty?( path )
361
+ exit_status = 0
362
+ git_root_dir = rootdir(path)
363
+ Dir.chdir(git_root_dir) do
364
+ FalkorLib.config.git[:subtrees].each do |dir,conf|
365
+ next if conf[:url].nil?
366
+ url = conf[:url]
367
+ remote = dir
368
+ branch = conf[:branch].nil? ? 'master' : conf[:branch]
369
+ remotes = FalkorLib::Git.remotes
370
+ info "Pulling changes into subtree '#{dir}' using remote '#{remote}/#{branch}'"
371
+ raise IOError, "The git remote '#{remote}' is not configured" unless remotes.include?( remote )
372
+ info "\t\\__ fetching remote '#{remotes.join(',')}'"
373
+ FalkorLib::Git.fetch( git_root_dir )
374
+ raise IOError, "The git subtree directory '#{dir}' does not exists" unless File.directory? ( File.join(git_root_dir, dir) )
375
+ info "\t\\__ pulling changes"
376
+ exit_status = execute "git subtree pull --prefix #{dir} --squash #{remote} #{branch}"
377
+ end
378
+ end
379
+ exit_status
380
+ end
381
+ alias :subtree_pull :subtree_up
382
+
383
+ # Raise a warning message if subtree/submodule section is not present
384
+ def config_warn(type = :subtrees)
385
+ warn "You shall setup 'FalkorLib.config.git[#{type.to_sym}]' to configure #{type} as follows:"
386
+ warn " FalkorLib.config.git do |c|"
387
+ warn " c[#{type.to_sym}] = {"
388
+ warn " '<subdir>' => {"
389
+ warn " :url => '<giturl>',"
390
+ warn " :branch => 'develop' # if different from master"
391
+ warn " },"
392
+ warn " }"
393
+ warn " end"
394
+ if type == :submodules
395
+ warn "This will configure the Git submodule into FalkorLib.config.git.submodulesdir i.e. '#{ FalkorLib.config.git.submodulesdir}'"
396
+ end
397
+ end
398
+
399
+
400
+
401
+
402
+
403
+
404
+ end # module FalkorLib::Git
405
+ end # module FalkorLib