vendorificator 0.5.git.v0.4.0.17.g26d50d8 → 0.5.git.v0.4.0.60.g9c35209

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,23 +6,28 @@ require 'vendorificator/config'
6
6
  module Vendorificator
7
7
  class Environment
8
8
  attr_reader :config
9
- attr_accessor :shell, :vendor_instances
9
+ attr_accessor :vendor_instances, :io
10
10
 
11
- def initialize(vendorfile=nil, &block)
11
+ def initialize(shell, verbosity = :default, vendorfile = nil, &block)
12
12
  @vendor_instances = []
13
+ @io = IOProxy.new(shell, verbosity)
14
+ @vendorfile = find_vendorfile(vendorfile)
15
+ @vendor_block = block
13
16
 
14
17
  @config = Vendorificator::Config.new
15
18
  @config.environment = self
16
- if vendorfile || !block_given?
17
- @config.read_file(find_vendorfile(vendorfile).to_s)
18
- end
19
- @config.instance_eval(&block) if block_given?
19
+ end
20
+
21
+ def shell
22
+ io.shell
23
+ end
20
24
 
21
- self.each_vendor_instance{ |mod| mod.compute_dependencies! }
25
+ def say(*args)
26
+ io.say(*args)
22
27
  end
23
28
 
24
29
  def say_status(*args)
25
- shell.say_status(*args) if shell
30
+ io.say_status(*args)
26
31
  end
27
32
 
28
33
  # Main MiniGit instance
@@ -49,10 +54,12 @@ module Vendorificator
49
54
  #
50
55
  # Returns nothing.
51
56
  def pull_all(options = {})
57
+ load_vendorfile
58
+
52
59
  ensure_clean!
53
60
  remotes = options[:remote] ? options[:remote].split(',') : config[:remotes]
54
61
  remotes.each do |remote|
55
- indent 'remote', remote do
62
+ indent :default, 'remote', remote do
56
63
  pull(remote, options)
57
64
  end
58
65
  end
@@ -68,7 +75,10 @@ module Vendorificator
68
75
 
69
76
  git.fetch(remote)
70
77
  git.fetch({:tags => true}, remote)
71
- git.fetch(remote, 'refs/notes/vendor:refs/notes/vendor')
78
+ begin
79
+ git.fetch(remote, 'refs/notes/vendor:refs/notes/vendor')
80
+ rescue MiniGit::GitError # ignore
81
+ end
72
82
 
73
83
  ref_rx = /^refs\/remotes\/#{Regexp.quote(remote)}\//
74
84
  remote_branches = Hash[ git.capturing.show_ref.
@@ -82,20 +92,20 @@ module Vendorificator
82
92
  theirs = remote_branches[mod.branch_name]
83
93
  if theirs
84
94
  if not ours
85
- say_status 'new', mod.branch_name, :yellow
95
+ say_status :default, 'new', mod.branch_name, :yellow
86
96
  git.branch({:track => true}, mod.branch_name, theirs) unless options[:dry_run]
87
97
  elsif ours == theirs
88
- say_status 'unchanged', mod.branch_name
98
+ say_status :default, 'unchanged', mod.branch_name
89
99
  elsif fast_forwardable?(theirs, ours)
90
- say_status 'updated', mod.name, :yellow
100
+ say_status :default, 'updated', mod.name, :yellow
91
101
  mod.in_branch { git.merge({:ff_only => true}, theirs) } unless options[:dry_run]
92
102
  elsif fast_forwardable?(ours, theirs)
93
- say_status 'older', mod.branch_name
103
+ say_status :default, 'older', mod.branch_name
94
104
  else
95
- say_status 'complicated', mod.branch_name, :red
105
+ say_status :default, 'complicated', mod.branch_name, :red
96
106
  end
97
107
  else
98
- say_status 'unknown', mod.branch_name
108
+ say_status :default, 'unknown', mod.branch_name
99
109
  end
100
110
  end
101
111
  end
@@ -107,35 +117,64 @@ module Vendorificator
107
117
  #
108
118
  # Returns nothing.
109
119
  def info(mod_name, options = {})
120
+ load_vendorfile
121
+
110
122
  if vendor = find_vendor_instance_by_name(mod_name)
111
- shell.say "Module name: #{vendor.name}\n"
112
- shell.say "Module category: #{vendor.category}\n"
113
- shell.say "Module merged version: #{vendor.merged_version}\n"
114
- shell.say "Module merged notes: #{vendor.merged_notes.ai}\n"
123
+ say :default, "Module name: #{vendor.name}\n"
124
+ say :default, "Module group: #{vendor.group}\n"
125
+ say :default, "Module merged version: #{vendor.merged_version}\n"
126
+ say :default, "Module merged notes: #{vendor.merged_notes.ai}\n"
115
127
  elsif (commit = Commit.new(mod_name, git)).exists?
116
- shell.say "Branches that contain this commit: #{commit.branches.join(', ')}\n"
117
- shell.say "Vendorificator notes on this commit: #{commit.notes.ai}\n"
128
+ say :default, "Branches that contain this commit: #{commit.branches.join(', ')}\n"
129
+ say :default, "Vendorificator notes on this commit: #{commit.notes.ai}\n"
118
130
  else
119
- shell.say "Module or ref #{mod_name.inspect} not found."
131
+ say :default, "Module or ref #{mod_name.inspect} not found."
120
132
  end
121
133
  end
122
134
 
135
+ # Public: Displays info about current modules.
136
+ #
137
+ # Returns nothing.
138
+ def list
139
+ load_vendorfile
140
+
141
+ each_vendor_instance do |mod|
142
+ shell.say "Module: #{mod.name}, version: #{mod.version}"
143
+ end
144
+ end
145
+
146
+ # Public: Displays info about outdated modules.
147
+ #
148
+ # Returns nothing.
149
+ def outdated
150
+ load_vendorfile
151
+
152
+ outdated = []
153
+ each_vendor_instance do |mod|
154
+ outdated << mod if [:unpulled, :unmerged, :outdated].include? mod.status
155
+ end
156
+
157
+ outdated.each { |mod| say_status :quiet, 'outdated', mod.name }
158
+ end
159
+
123
160
  # Public: Push changes on module branches.
124
161
  #
125
162
  # options - The Hash containing options
126
163
  #
127
164
  # Returns nothing.
128
165
  def push(options = {})
166
+ load_vendorfile
167
+
129
168
  ensure_clean!
130
169
 
131
170
  pushable = []
132
- each_vendor_instance{ |mod| pushable += mod.pushable_refs }
171
+ each_vendor_instance { |mod| pushable += mod.pushable_refs }
172
+
173
+ pushable << 'refs/notes/vendor' if has_notes?
133
174
 
134
175
  remotes = options[:remote] ? options[:remote].split(',') : config[:remotes]
135
176
  remotes.each do |remote|
136
177
  git.push remote, pushable
137
- git.push remote, :tags => true
138
- git.push remote, 'refs/notes/vendor'
139
178
  end
140
179
  end
141
180
 
@@ -145,12 +184,14 @@ module Vendorificator
145
184
  #
146
185
  # Returns nothing.
147
186
  def sync(options = {})
187
+ load_vendorfile
188
+
148
189
  ensure_clean!
149
190
  config[:use_upstream_version] = options[:update]
150
191
  metadata = metadata_snapshot
151
192
 
152
193
  each_vendor_instance(*options[:modules]) do |mod|
153
- say_status :module, mod.name
194
+ say_status :default, :module, mod.name
154
195
  indent do
155
196
  mod.run!(:metadata => metadata)
156
197
  end
@@ -159,12 +200,10 @@ module Vendorificator
159
200
 
160
201
  # Public: Goes through all the Vendor instances and runs the block
161
202
  #
162
- # modules - ?
203
+ # modules - An Array of vendor modules to yield the block for.
163
204
  #
164
205
  # Returns nothing.
165
206
  def each_vendor_instance(*modules)
166
- modpaths = modules.map { |m| File.expand_path(m) }
167
-
168
207
  # We don't use @vendor_instances.each here, because Vendor#run! is
169
208
  # explicitly allowed to append to instantiate new dependencies, and #each
170
209
  # fails to catch up on some Ruby implementations.
@@ -172,9 +211,7 @@ module Vendorificator
172
211
  while true
173
212
  break if i >= @vendor_instances.length
174
213
  mod = @vendor_instances[i]
175
- yield mod if modules.empty? ||
176
- modules.include?(mod.name) ||
177
- modpaths.include?(mod.work_dir)
214
+ yield mod if modules.empty? || mod.included_in_list?(modules)
178
215
  i += 1
179
216
  end
180
217
  end
@@ -204,7 +241,8 @@ module Vendorificator
204
241
  # Public: returns `config[:root_dir]` relative to Git repository root
205
242
  def relative_root_dir
206
243
  @relative_root_dir ||= config[:root_dir].relative_path_from(
207
- Pathname.new(git.git_work_tree))
244
+ Pathname.new(git.git_work_tree)
245
+ )
208
246
  end
209
247
 
210
248
  # Public: Returns module with given name
@@ -212,16 +250,41 @@ module Vendorificator
212
250
  vendor_instances.find { |v| v.name == name }
213
251
  end
214
252
 
253
+ # Public: Loads the vendorfile.
254
+ #
255
+ # Returns nothing.
256
+ def load_vendorfile
257
+ raise RuntimeError, 'Vendorfile has been already loaded!' if @vendorfile_loaded
258
+
259
+ if @vendorfile
260
+ @config.read_file @vendorfile.to_s
261
+ else
262
+ raise MissingVendorfileError unless @vendor_block
263
+ end
264
+ @config.instance_eval(&@vendor_block) if @vendor_block
265
+
266
+ each_vendor_instance{ |mod| mod.compute_dependencies! }
267
+
268
+ @vendorfile_loaded = true
269
+ end
270
+
271
+ # Public: Checks if vendorfile has been already loaded.
272
+ #
273
+ # Returns boolean.
274
+ def vendorfile_loaded?
275
+ defined?(@vendorfile_loaded) && @vendorfile_loaded
276
+ end
277
+
215
278
  private
216
279
 
217
- # Private: Finds a vendor instance by module name.
280
+ # Private: Finds a vendor instance by module (qualified) name, path or branch.
218
281
  #
219
- # mod_name - The String containing the module name.
282
+ # mod_name - The String containing the module id.
220
283
  #
221
284
  # Returns Vendor instance.
222
285
  def find_vendor_instance_by_name(mod_name)
223
- each_vendor_instance do |mod|
224
- return mod if mod.name == mod_name
286
+ each_vendor_instance(mod_name) do |mod|
287
+ return mod
225
288
  end
226
289
  nil
227
290
  end
@@ -231,8 +294,8 @@ module Vendorificator
231
294
  # given - the optional String containing vendorfile path.
232
295
  #
233
296
  # Returns a String containing the vendorfile path.
234
- def find_vendorfile(given=nil)
235
- given = [ given, ENV['VENDORFILE'] ].find do |candidate|
297
+ def find_vendorfile(given = nil)
298
+ given = [given, ENV['VENDORFILE']].find do |candidate|
236
299
  candidate && !(candidate.respond_to?(:empty?) && candidate.empty?)
237
300
  end
238
301
  return given if given
@@ -247,11 +310,11 @@ module Vendorificator
247
310
  # avoid stepping above the tmp directory when testing
248
311
  if ENV['VENDORIFICATOR_SPEC_RUN'] &&
249
312
  dir.join('vendorificator.gemspec').exist?
250
- raise ArgumentError, "Vendorfile not found"
313
+ break
251
314
  end
252
315
  end
253
316
 
254
- raise ArgumentError, "Vendorfile not found"
317
+ return nil
255
318
  end
256
319
 
257
320
  # Private: Aborts on a dirty repository.
@@ -264,12 +327,23 @@ module Vendorificator
264
327
  # Private: Indents the output.
265
328
  #
266
329
  # Returns nothing.
267
- def indent(*args, &block)
268
- say_status *args unless args.empty?
330
+ def indent(verb_level = :default, *args, &block)
331
+ say_status verb_level, *args unless args.empty?
269
332
  shell.padding += 1 if shell
270
333
  yield
271
334
  ensure
272
335
  shell.padding -= 1 if shell
273
336
  end
337
+
338
+ # Private: Checks if there are git vendor notes.
339
+ #
340
+ # Returns true/false.
341
+ def has_notes?
342
+ git.capturing.rev_parse({:quiet => true, :verify => true}, 'refs/notes/vendor')
343
+ true
344
+ rescue MiniGit::GitError
345
+ false
346
+ end
347
+
274
348
  end
275
349
  end
@@ -1,3 +1,4 @@
1
1
  module Vendorificator
2
2
  class DirtyRepoError < StandardError; end
3
+ class MissingVendorfileError < StandardError; end
3
4
  end
@@ -26,7 +26,7 @@ module Vendorificator::Hooks
26
26
  metadata = File.join(self.work_dir, 'metadata.rb')
27
27
 
28
28
  unless File.exist?(metadata)
29
- shell.say_status 'WARNING', "Metadata of #{name} does not exist at #{metadata}, could not gather dependencies", :red
29
+ say_status :quiet, 'WARNING', "Metadata of #{name} does not exist at #{metadata}, could not gather dependencies", :red
30
30
  return super
31
31
  end
32
32
 
@@ -0,0 +1,46 @@
1
+ require 'stringio'
2
+
3
+ module Vendorificator
4
+ class IOProxy < StringIO
5
+ attr_reader :shell
6
+
7
+ def initialize(shell, verbosity = :default)
8
+ @shell = shell
9
+ @verbosity = verbosity
10
+
11
+ super()
12
+ capture_stdout
13
+ end
14
+
15
+ def puts(value, verb_level = :default)
16
+ @orig_stdout.puts value if should_speak?(verb_level)
17
+ super
18
+ end
19
+
20
+ def say_status(verb_level, *args)
21
+ write args[0..1].join(' ' * @shell.padding)
22
+ @shell.say_status(*args) if @shell && should_speak?(verb_level)
23
+ end
24
+
25
+ def say(verb_level, *args)
26
+ write args[0]
27
+ @shell.say(*args) if @shell && should_speak?(verb_level)
28
+ end
29
+
30
+ private
31
+
32
+ def capture_stdout
33
+ @orig_stdout = $stdout
34
+
35
+ $stdout = self
36
+ end
37
+
38
+ def should_speak?(level)
39
+ levels = {:quiet => 1, :default => 2, :chatty => 3, :debug => 9}
40
+ raise "Unknown verbosity level: #{level.inspect}" if levels[level].nil?
41
+
42
+ levels[level] <= levels[@verbosity]
43
+ end
44
+ end
45
+ end
46
+
@@ -13,9 +13,9 @@ module Vendorificator
13
13
  attr_reader :conjured_checksum, :conjured_filesize
14
14
 
15
15
  def conjure!
16
- shell.say_status :download, url
16
+ say_status :default, :download, url
17
17
  archive = download_file
18
- shell.say_status :unpack, filename
18
+ say_status :default, :unpack, filename
19
19
  unpack_file archive
20
20
  add_archive_metadata
21
21
  super
@@ -10,7 +10,7 @@ module Vendorificator
10
10
  include Hooks::ChefCookbookDependencies
11
11
 
12
12
  @method_name = :chef_cookbook
13
- @category = :cookbooks
13
+ @group = :cookbooks
14
14
 
15
15
  API_PREFIX = 'http://cookbooks.opscode.com/api/v1/cookbooks/'
16
16
 
@@ -11,11 +11,11 @@ module Vendorificator
11
11
  attr_reader :conjured_checksum, :conjured_filesize
12
12
 
13
13
  def path
14
- args[:path] || category
14
+ args[:path] || group
15
15
  end
16
16
 
17
17
  def conjure!
18
- shell.say_status :download, url
18
+ say_status :default, :download, url
19
19
  File.open name, 'w' do |outf|
20
20
  outf.write( open(url).read )
21
21
  end
@@ -7,7 +7,7 @@ module Vendorificator
7
7
  attr_reader :conjured_revision
8
8
 
9
9
  def conjure!
10
- shell.say_status :clone, repository
10
+ say_status :default, :clone, repository
11
11
  MiniGit.git :clone, repository, '.'
12
12
  local_git = MiniGit.new('.')
13
13
 
@@ -8,7 +8,7 @@ module Vendorificator
8
8
  class Vendor
9
9
 
10
10
  class << self
11
- attr_accessor :category, :method_name
11
+ attr_accessor :group, :method_name
12
12
 
13
13
  def arg_reader(*names)
14
14
  names.each do |name|
@@ -41,19 +41,28 @@ module Vendorificator
41
41
  end
42
42
 
43
43
  def path
44
- args[:path] || _join(category, name)
44
+ args[:path] || _join(group, name)
45
45
  end
46
46
 
47
47
  def shell
48
- @shell ||= config[:shell] || Thor::Shell::Basic.new
48
+ @environment.shell
49
49
  end
50
50
 
51
- def category
52
- defined?(@category) ? @category : self.class.category
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)
58
+ end
59
+
60
+ def group
61
+ defined?(@group) ? @group : self.class.group
53
62
  end
54
63
 
55
64
  def branch_name
56
- _join(config[:branch_prefix], category, name)
65
+ _join(config[:branch_prefix], group, name)
57
66
  end
58
67
 
59
68
  def to_s
@@ -167,14 +176,17 @@ module Vendorificator
167
176
  rescue MiniGit::GitError
168
177
  nil
169
178
  end
170
- Dir.mktmpdir("vendor-#{category}-#{name}") do |tmpdir|
179
+ Dir.mktmpdir("vendor-#{group}-#{name}") do |tmpdir|
171
180
  clone_opts = {:shared => true, :no_checkout => true}
172
181
  clone_opts[:branch] = branch_name if branch_exists
173
- MiniGit.git(:clone, clone_opts, git.git_dir, tmpdir)
174
- tmpgit = MiniGit::new(tmpdir)
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
175
186
  tmpgit.fetch(git.git_dir, "refs/notes/vendor:refs/notes/vendor") if notes_exist
176
- tmpgit.checkout({orphan: true}, branch_name) unless branch_exists
177
- tmpgit.rm( { :r => true, :f => true, :q => true, :ignore_unmatch => true }, '.') if options[:clean] || !branch_exists
187
+ if options[:clean] || !branch_exists
188
+ tmpgit.rm({ :r => true, :f => true, :q => true, :ignore_unmatch => true }, '.')
189
+ end
178
190
 
179
191
  begin
180
192
  @git = tmpgit
@@ -185,6 +197,7 @@ module Vendorificator
185
197
  @git = nil
186
198
  end
187
199
 
200
+ #TODO: Silence/handle the stderr output from git-fetch
188
201
  git.fetch(tmpdir)
189
202
  git.fetch({tags: true}, tmpdir)
190
203
  git.fetch(tmpdir,
@@ -197,16 +210,16 @@ module Vendorificator
197
210
  case status
198
211
 
199
212
  when :up_to_date
200
- shell.say_status 'up to date', self.to_s
213
+ say_status :default, 'up to date', self.to_s
201
214
 
202
215
  when :unpulled, :unmerged
203
- shell.say_status 'merging', self.to_s, :yellow
216
+ say_status :default, 'merging', self.to_s, :yellow
204
217
  git.merge({:no_edit => true, :no_ff => true}, tagged_sha1)
205
218
  postprocess! if self.respond_to? :postprocess!
206
219
  compute_dependencies!
207
220
 
208
221
  when :outdated, :new
209
- shell.say_status 'fetching', self.to_s, :yellow
222
+ say_status :default, 'fetching', self.to_s, :yellow
210
223
  begin
211
224
  shell.padding += 1
212
225
  before_conjure!
@@ -237,7 +250,7 @@ module Vendorificator
237
250
  end
238
251
 
239
252
  else
240
- say_status self.status, "I'm unsure what to do.", :red
253
+ say_status :quiet, self.status, "I'm unsure what to do.", :red
241
254
  end
242
255
  end
243
256
 
@@ -245,30 +258,41 @@ module Vendorificator
245
258
  block.call(self) if block
246
259
  end
247
260
 
248
- #
249
261
  # Hook points
250
262
  def git_add_extra_paths ; [] ; end
251
263
  def before_conjure! ; end
252
264
  def compute_dependencies! ; end
253
265
 
254
266
  def pushable_refs
255
- created_tags.
256
- map { |tag| '+' << tag }.
257
- unshift("+refs/heads/#{branch_name}")
267
+ created_tags.unshift("refs/heads/#{branch_name}")
258
268
  end
259
269
 
260
270
  def metadata
261
271
  default = {
262
272
  :module_version => version,
263
- :module_category => @category,
273
+ :module_group => @group,
264
274
  }
265
275
  default.merge @metadata
266
276
  end
267
277
 
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)
286
+ end
287
+
268
288
  private
269
289
 
270
290
  def parse_initialize_args(args = {})
271
- @category = args.delete(:category) if args.key?(:category)
291
+ @group = args.delete(:group) if args.key?(:group)
292
+ if args.key?(:category)
293
+ @group ||= args.delete(:category)
294
+ say_status :default, 'DEPRECATED', 'Using :category option is deprecated and will be removed in future versions. Use :group instead.'
295
+ end
272
296
 
273
297
  unless (hooks = Array(args.delete(:hooks))).empty?
274
298
  hooks.each do |hook|
@@ -282,7 +306,7 @@ module Vendorificator
282
306
  end
283
307
 
284
308
  def tag_name_base
285
- _join('vendor', category, name)
309
+ _join('vendor', group, name)
286
310
  end
287
311
 
288
312
  def conjure_commit_message
@@ -294,7 +318,9 @@ module Vendorificator
294
318
  end
295
319
 
296
320
  def tagged_sha1
297
- @tagged_sha1 ||= git.capturing.rev_parse({:verify => true, :quiet => true}, "refs/tags/#{tag_name}^{commit}").strip
321
+ @tagged_sha1 ||= git.capturing.rev_parse(
322
+ {:verify => true, :quiet => true}, "refs/tags/#{tag_name}^{commit}"
323
+ ).strip
298
324
  rescue MiniGit::GitError
299
325
  nil
300
326
  end
@@ -340,7 +366,7 @@ module Vendorificator
340
366
  git.capturing.commit :m => conjure_commit_message
341
367
  git.capturing.notes({:ref => 'vendor'}, 'add', {:m => conjure_note(environment_metadata)}, 'HEAD')
342
368
  git.capturing.tag( { :a => true, :m => tag_message }, tag_name )
343
- shell.say_status :tag, tag_name
369
+ say_status :default, :tag, tag_name
344
370
  end
345
371
 
346
372
  # Private: Merges all the data we use for the commit note.
@@ -6,6 +6,7 @@ require 'vendorificator/config'
6
6
  require 'vendorificator/environment'
7
7
  require 'vendorificator/errors'
8
8
  require 'vendorificator/commit'
9
+ require 'vendorificator/io_proxy'
9
10
 
10
11
  require 'vendorificator/vendor'
11
12
  require 'vendorificator/vendor/download'
data/spec/spec_helper.rb CHANGED
@@ -44,8 +44,9 @@ class MiniTest::Spec
44
44
  include Vendorificator::Spec::Helpers::Wrong
45
45
 
46
46
  before do
47
- _git = stub
48
- _git.stubs(:capturing).returns(stub)
47
+ _git = stub('git')
48
+ _capturing = stub('git.capturing')
49
+ _git.stubs(:capturing).returns(_capturing)
49
50
  Vendorificator::Environment.any_instance.stubs(:git).returns(_git)
50
51
  end
51
52
 
@@ -55,7 +56,7 @@ class MiniTest::Spec
55
56
 
56
57
  def basic_environment
57
58
  @basic_environment ||= Vendorificator::Environment.new(
58
- 'spec/vendorificator/fixtures/vendorfiles/empty_vendor.rb'
59
+ Thor::Shell::Basic.new, :quiet, nil
59
60
  )
60
61
  end
61
62