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

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.
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