vendorificator 0.5.git.v0.4.0.63.g8e9d54d → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +9 -9
  2. data/.travis.yml +2 -2
  3. data/CHANGELOG.md +10 -0
  4. data/Gemfile +5 -12
  5. data/README.md +27 -1
  6. data/Rakefile +2 -8
  7. data/features/chef_cookbook.feature +4 -4
  8. data/features/download.feature +1 -1
  9. data/features/edgecases.feature +15 -0
  10. data/features/environment.feature +3 -2
  11. data/features/fake_mode.feature +15 -0
  12. data/features/git.feature +4 -4
  13. data/features/overlay.feature +99 -0
  14. data/features/step_definitions/basic.rb +22 -0
  15. data/features/step_definitions/git.rb +16 -0
  16. data/features/step_definitions/vendorificator.rb +9 -4
  17. data/features/support/aruba_ext.rb +4 -0
  18. data/features/support/env.rb +3 -0
  19. data/features/tarball.feature +2 -2
  20. data/features/tarball_edit.feature +3 -3
  21. data/features/tool.feature +6 -4
  22. data/features/tool_shortcuts.feature +3 -3
  23. data/features/tool_specs.feature +62 -0
  24. data/features/vendor.feature +4 -3
  25. data/lib/vendorificator.rb +7 -1
  26. data/lib/vendorificator/cli.rb +12 -11
  27. data/lib/vendorificator/config.rb +32 -1
  28. data/lib/vendorificator/environment.rb +23 -27
  29. data/lib/vendorificator/hooks/chef_cookbook.rb +2 -2
  30. data/lib/vendorificator/overlay.rb +17 -0
  31. data/lib/vendorificator/segment.rb +376 -0
  32. data/lib/vendorificator/segment/overlay.rb +114 -0
  33. data/lib/vendorificator/segment/vendor.rb +115 -0
  34. data/lib/vendorificator/vendor.rb +25 -279
  35. data/lib/vendorificator/vendor/tool.rb +40 -23
  36. data/lib/vendorificator/version.rb +1 -1
  37. data/spec/vendorificator/config_spec.rb +66 -0
  38. data/spec/vendorificator/environment_spec.rb +7 -7
  39. data/spec/vendorificator/fixtures/vendorfiles/overlay.rb +4 -0
  40. data/spec/vendorificator/segment/vendor_spec.rb +19 -0
  41. data/spec/vendorificator/segment_spec.rb +106 -0
  42. data/spec/vendorificator/vendor_spec.rb +0 -89
  43. data/vendorificator.gemspec +5 -5
  44. metadata +45 -29
@@ -0,0 +1,115 @@
1
+ require 'tmpdir'
2
+
3
+ module Vendorificator
4
+ class Segment::Vendor < Segment
5
+ attr_reader :overlay, :vendor
6
+
7
+ def initialize(options)
8
+ @vendor = options.delete(:vendor)
9
+ @overlay = options.delete(:overlay)
10
+ super
11
+ end
12
+
13
+ def name
14
+ @vendor.name
15
+ end
16
+
17
+ def group
18
+ @vendor.group
19
+ end
20
+
21
+ def version
22
+ @vendor.version
23
+ end
24
+
25
+ def branch_name
26
+ if overlay
27
+ _join overlay.branch_name, group, name
28
+ else
29
+ super
30
+ end
31
+ end
32
+
33
+ def compute_dependencies!
34
+ @vendor.compute_dependencies!
35
+ end
36
+
37
+ # Public: Conjures the vendor module without merging back.
38
+ #
39
+ # options - available options: :metadata - Hash with metadata information
40
+ #
41
+ # Returns nothing.
42
+ def conjure(options = {})
43
+ shell.padding += 1
44
+ @vendor.before_conjure!
45
+ Dir.mktmpdir "vendorificator-#{name}" do |tmpdir|
46
+ in_branch(branch_name, clean: true) do |tmpgit|
47
+ begin
48
+ @git = tmpgit
49
+ @vendor.git = tmpgit
50
+
51
+ Dir.chdir tmpdir do
52
+ @vendor.conjure!
53
+
54
+ subdir = @vendor.args[:subdirectory]
55
+ make_subdir_root subdir if subdir && !subdir.empty?
56
+ end
57
+
58
+ FileUtils.mkdir_p work_dir
59
+ tmpdir_entries = (Dir.entries(tmpdir) - %w'. ..').
60
+ map { |e| File.join(tmpdir, e) }
61
+ FileUtils.mv tmpdir_entries, work_dir
62
+ commit_and_annotate(options[:metadata] || {})
63
+ ensure
64
+ @git = nil
65
+ @vendor.git = nil
66
+ end
67
+ end
68
+ end
69
+ ensure
70
+ shell.padding -= 1
71
+ end
72
+
73
+ # Public: Merges back to the original branch (usually master).
74
+ #
75
+ # commit - git ref/branch to merge, defaults to segment branch
76
+ #
77
+ # Returns nothing.
78
+ def merge_back(commit = branch_name)
79
+ git.capturing.merge({no_edit: true, no_ff: true}, commit) unless config.fake_mode?
80
+ @vendor.postprocess! if @vendor.respond_to? :postprocess!
81
+ @vendor.compute_dependencies!
82
+ end
83
+
84
+ private
85
+
86
+ def update(options = {})
87
+ shell.padding += 1
88
+ conjure options
89
+ merge_back
90
+ ensure
91
+ shell.padding -= 1
92
+ end
93
+
94
+ def environment
95
+ @vendor.environment
96
+ end
97
+
98
+ def path
99
+ if overlay
100
+ _join overlay.path, group, name
101
+ else
102
+ @vendor.args[:path] || _join(group, name)
103
+ end
104
+ end
105
+
106
+ def work_subdir
107
+ if overlay
108
+ _join overlay.path
109
+ else
110
+ _join config[:basedir], path
111
+ end
112
+ end
113
+
114
+ end
115
+ end
@@ -19,7 +19,8 @@ module Vendorificator
19
19
  end
20
20
  end
21
21
 
22
- attr_reader :environment, :name, :args, :block
22
+ attr_reader :environment, :name, :args, :block, :segment
23
+ attr_accessor :git
23
24
  arg_reader :version
24
25
 
25
26
  def initialize(environment, name, args = {}, &block)
@@ -27,231 +28,35 @@ module Vendorificator
27
28
  @name = name
28
29
  @block = block
29
30
  @metadata = {
30
- :module_name => @name,
31
31
  :unparsed_args => args.clone
32
32
  }
33
33
  @metadata[:parsed_args] = @args = parse_initialize_args(args)
34
34
  @metadata[:module_annotations] = @args[:annotate] if @args[:annotate]
35
35
 
36
- @environment.vendor_instances << self
36
+ @segment = Segment::Vendor.new(vendor: self, overlay: config.overlay_instance)
37
+ if config.overlay_instance
38
+ config.overlay_instance.segments << @segment
39
+ else
40
+ @environment.segments << @segment
41
+ end
37
42
  end
38
43
 
39
44
  def ===(other)
40
- other === self.name or File.expand_path(other.to_s) == self.work_dir
41
- end
42
-
43
- def path
44
- args[:path] || _join(group, name)
45
- end
46
-
47
- def shell
48
- @environment.shell
49
- end
50
-
51
- def say(verb_level= :default, &block)
52
- output = yield
53
- @environment.say verb_level, output
54
- end
55
-
56
- def say_status(*args, &block)
57
- @environment.say_status(*args, &block)
45
+ other === name || File.expand_path(other.to_s) == work_dir
58
46
  end
59
47
 
60
48
  def group
61
49
  defined?(@group) ? @group : self.class.group
62
50
  end
63
51
 
64
- def branch_name
65
- _join(config[:branch_prefix], group, name)
66
- end
67
-
68
- def to_s
69
- _join(name, version)
70
- end
71
-
72
52
  def inspect
73
53
  "#<#{self.class} #{self}>"
74
54
  end
75
55
 
76
- def work_subdir
77
- _join(config[:basedir], path)
78
- end
79
-
80
- def work_dir
81
- _join(git.git_work_tree, environment.relative_root_dir, work_subdir)
82
- end
83
-
84
- def head
85
- git.capturing.rev_parse({:verify => true, :quiet => true}, "refs/heads/#{branch_name}").strip
86
- rescue MiniGit::GitError
87
- nil
88
- end
89
-
90
- def tag_name
91
- _join(tag_name_base, version)
92
- end
93
-
94
- def merged
95
- unless @_has_merged
96
- if ( head = self.head )
97
- merged = git.capturing.merge_base(head, 'HEAD').strip
98
- @merged = merged unless merged.empty?
99
- end
100
- @_has_merged = true
101
- end
102
- @merged
103
- rescue MiniGit::GitError
104
- @_has_merged = true
105
- @merged = nil
106
- end
107
-
108
- def merged_tag
109
- unless @_has_merged_tag
110
- if merged
111
- tag = git.capturing.describe( {
112
- :exact_match => true,
113
- :match => _join(tag_name_base, '*') },
114
- merged).strip
115
- @merged_tag = tag unless tag.empty?
116
- end
117
- @_has_merged_tag = true
118
- end
119
- @merged_tag
120
- end
121
-
122
- def merged_version
123
- merged_tag && merged_tag[(1+tag_name_base.length)..-1]
124
- end
125
-
126
- # Public: Get git vendor notes of the merged commit.
127
- #
128
- # Returns the Hash of git vendor notes.
129
- def merged_notes
130
- Commit.new(merged, git).notes?
131
- end
132
-
133
56
  def version
134
- @args[:version] || (!config[:use_upstream_version] && merged_version) || upstream_version
135
- end
136
-
137
- def upstream_version
138
- # To be overriden
139
- end
140
-
141
- def updatable?
142
- return nil if self.status == :up_to_date
143
- return false if !head
144
- return false if head && merged == head
145
- git.describe({:abbrev => 0, :always => true}, branch_name)
146
- end
147
-
148
- def status
149
- # If there's no branch yet, it's a completely new module
150
- return :new unless head
151
-
152
- # If there's a branch but no tag, it's a known module that's not
153
- # been updated for the new definition yet.
154
- return :outdated unless tagged_sha1
155
-
156
- # Well, this is awkward: branch is in config and exists, but is
157
- # not merged into current branch at all.
158
- return :unmerged unless merged
159
-
160
- # Merge base is tagged with our tag. We're good.
161
- return :up_to_date if tagged_sha1 == merged
162
-
163
- return :unpulled if environment.fast_forwardable?(tagged_sha1, merged)
164
-
165
- return :unknown
166
- end
167
-
168
- def needed?
169
- return self.status != :up_to_date
170
- end
171
-
172
- def in_branch(options={}, &block)
173
- branch_exists = !!self.head
174
- notes_exist = begin
175
- git.capturing.rev_parse({verify: true, quiet: true}, 'refs/notes/vendor')
176
- rescue MiniGit::GitError
177
- nil
178
- end
179
- Dir.mktmpdir("vendor-#{group}-#{name}") do |tmpdir|
180
- clone_opts = {:shared => true, :no_checkout => true}
181
- clone_opts[:branch] = branch_name if branch_exists
182
- say { MiniGit::Capturing.git(:clone, clone_opts, git.git_dir, tmpdir) }
183
- tmpgit = MiniGit.new(tmpdir)
184
- #TODO: Silence/handle the stderr output from git-checkout
185
- tmpgit.capturing.checkout({orphan: true}, branch_name) unless branch_exists
186
- tmpgit.fetch(git.git_dir, "refs/notes/vendor:refs/notes/vendor") if notes_exist
187
- if options[:clean] || !branch_exists
188
- tmpgit.rm({ :r => true, :f => true, :q => true, :ignore_unmatch => true }, '.')
189
- end
190
-
191
- begin
192
- @git = tmpgit
193
- Dir.chdir(tmpdir) do
194
- yield
195
- end
196
- ensure
197
- @git = nil
198
- end
199
-
200
- #TODO: Silence/handle the stderr output from git-fetch
201
- git.fetch(tmpdir)
202
- git.fetch({tags: true}, tmpdir)
203
- git.fetch(tmpdir,
204
- "refs/heads/#{branch_name}:refs/heads/#{branch_name}",
205
- "refs/notes/vendor:refs/notes/vendor")
206
- end
207
- end
208
-
209
- def run!(options = {})
210
- case status
211
-
212
- when :up_to_date
213
- say_status :default, 'up to date', self.to_s
214
-
215
- when :unpulled, :unmerged
216
- say_status :default, 'merging', self.to_s, :yellow
217
- git.merge({:no_edit => true, :no_ff => true}, tagged_sha1)
218
- postprocess! if self.respond_to? :postprocess!
219
- compute_dependencies!
220
-
221
- when :outdated, :new
222
- say_status :default, 'fetching', self.to_s, :yellow
223
- begin
224
- shell.padding += 1
225
- before_conjure!
226
- in_branch(:clean => true) do
227
- FileUtils::mkdir_p work_dir
228
-
229
- # Actually fill the directory with the wanted content
230
- Dir::chdir work_dir do
231
- begin
232
- shell.padding += 1
233
- self.conjure!
234
- ensure
235
- shell.padding -= 1
236
- end
237
-
238
- subdir = args[:subdirectory]
239
- make_subdir_root subdir if subdir && !subdir.empty?
240
- end
241
-
242
- commit_and_annotate(options[:metadata])
243
- end
244
- # Merge back to the original branch
245
- git.capturing.merge( {:no_edit => true, :no_ff => true}, branch_name )
246
- postprocess! if self.respond_to? :postprocess!
247
- compute_dependencies!
248
- ensure
249
- shell.padding -= 1
250
- end
251
-
252
- else
253
- say_status :quiet, self.status, "I'm unsure what to do.", :red
254
- end
57
+ @args[:version] ||
58
+ (!config[:use_upstream_version] && segment.merged_version) ||
59
+ upstream_version
255
60
  end
256
61
 
257
62
  def conjure!
@@ -262,27 +67,19 @@ module Vendorificator
262
67
  def git_add_extra_paths ; [] ; end
263
68
  def before_conjure! ; end
264
69
  def compute_dependencies! ; end
265
-
266
- def pushable_refs
267
- created_tags.unshift("refs/heads/#{branch_name}")
268
- end
70
+ def upstream_version ; end
269
71
 
270
72
  def metadata
271
73
  default = {
74
+ :module_name => @name,
272
75
  :module_version => version,
273
76
  :module_group => @group,
274
77
  }
275
78
  default.merge @metadata
276
79
  end
277
80
 
278
- def included_in_list?(module_list)
279
- modpaths = module_list.map { |m| File.expand_path(m) }
280
-
281
- module_list.include?(name) ||
282
- module_list.include?("#{group}/#{name}") ||
283
- modpaths.include?(File.expand_path(work_dir)) ||
284
- module_list.include?(merged) ||
285
- module_list.include?(branch_name)
81
+ def conjure_commit_message
82
+ "Conjured vendor module #{name} version #{version}"
286
83
  end
287
84
 
288
85
  private
@@ -305,31 +102,6 @@ module Vendorificator
305
102
  args
306
103
  end
307
104
 
308
- def tag_name_base
309
- _join('vendor', group, name)
310
- end
311
-
312
- def conjure_commit_message
313
- "Conjured vendor module #{name} version #{version}"
314
- end
315
-
316
- def tag_message
317
- conjure_commit_message
318
- end
319
-
320
- def tagged_sha1
321
- @tagged_sha1 ||= git.capturing.rev_parse(
322
- {:verify => true, :quiet => true}, "refs/tags/#{tag_name}^{commit}"
323
- ).strip
324
- rescue MiniGit::GitError
325
- nil
326
- end
327
-
328
- def created_tags
329
- git.capturing.show_ref.lines.map{ |line| line.split(' ')[1] }.
330
- select{ |ref| ref =~ /\Arefs\/tags\/#{tag_name_base}\// }
331
- end
332
-
333
105
  def git
334
106
  @git || environment.git
335
107
  end
@@ -338,47 +110,21 @@ module Vendorificator
338
110
  environment.config
339
111
  end
340
112
 
341
- def _join(*parts)
342
- parts.compact.map(&:to_s).join('/')
113
+ def work_dir
114
+ segment.work_dir
343
115
  end
344
116
 
345
- def make_subdir_root(subdir_path)
346
- curdir = Pathname.pwd
347
- tmpdir = Pathname.pwd.dirname.join("#{Pathname.pwd.basename}.tmp")
348
- subdir = Pathname.pwd.join(subdir_path)
349
-
350
- Dir.chdir('..')
351
-
352
- subdir.rename(tmpdir.to_s)
353
- curdir.rmtree
354
- tmpdir.rename(curdir.to_s)
355
- ensure
356
- Dir.chdir(curdir.to_s) if curdir.exist?
117
+ def shell
118
+ environment.shell
357
119
  end
358
120
 
359
- # Private: Commits and annotates the conjured module.
360
- #
361
- # environment_metadata - Hash with environment metadata where vendor was run
362
- #
363
- # Returns nothing.
364
- def commit_and_annotate(environment_metadata = {})
365
- git.capturing.add work_dir, *git_add_extra_paths
366
- git.capturing.commit :m => conjure_commit_message
367
- git.capturing.notes({:ref => 'vendor'}, 'add', {:m => conjure_note(environment_metadata)}, 'HEAD')
368
- git.capturing.tag( { :a => true, :m => tag_message }, tag_name )
369
- say_status :default, :tag, tag_name
121
+ def say(verb_level= :default, &block)
122
+ output = yield
123
+ environment.say verb_level, output
370
124
  end
371
125
 
372
- # Private: Merges all the data we use for the commit note.
373
- #
374
- # environment_metadata - Hash with environment metadata where vendor was run
375
- #
376
- # Returns: The note in the YAML format.
377
- def conjure_note(environment_metadata = {})
378
- config.metadata.
379
- merge(environment_metadata).
380
- merge(metadata).
381
- to_yaml
126
+ def say_status(*args, &block)
127
+ environment.say_status(*args, &block)
382
128
  end
383
129
  end
384
130