vendorificator 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/.gitignore +19 -0
  2. data/.travis.yml +9 -0
  3. data/Gemfile +11 -0
  4. data/LICENSE +22 -0
  5. data/README.md +45 -0
  6. data/Rakefile +29 -0
  7. data/bin/vendor +4 -0
  8. data/bin/vendorify +6 -0
  9. data/examples/Vendorfile +25 -0
  10. data/features/chef_cookbook.feature +44 -0
  11. data/features/deprecated.feature +17 -0
  12. data/features/fixtures/git/testrepo/HEAD +1 -0
  13. data/features/fixtures/git/testrepo/config +7 -0
  14. data/features/fixtures/git/testrepo/description +1 -0
  15. data/features/fixtures/git/testrepo/hooks/applypatch-msg.sample +15 -0
  16. data/features/fixtures/git/testrepo/hooks/commit-msg.sample +24 -0
  17. data/features/fixtures/git/testrepo/hooks/post-update.sample +8 -0
  18. data/features/fixtures/git/testrepo/hooks/pre-applypatch.sample +14 -0
  19. data/features/fixtures/git/testrepo/hooks/pre-commit.sample +50 -0
  20. data/features/fixtures/git/testrepo/hooks/pre-rebase.sample +169 -0
  21. data/features/fixtures/git/testrepo/hooks/prepare-commit-msg.sample +36 -0
  22. data/features/fixtures/git/testrepo/hooks/update.sample +128 -0
  23. data/features/fixtures/git/testrepo/info/exclude +6 -0
  24. data/features/fixtures/git/testrepo/info/refs +5 -0
  25. data/features/fixtures/git/testrepo/objects/info/packs +2 -0
  26. data/features/fixtures/git/testrepo/objects/pack/pack-46f7621b6a6b9b1c22dd15c08d457dfedf76e55f.idx +0 -0
  27. data/features/fixtures/git/testrepo/objects/pack/pack-46f7621b6a6b9b1c22dd15c08d457dfedf76e55f.pack +0 -0
  28. data/features/fixtures/git/testrepo/packed-refs +6 -0
  29. data/features/fixtures/git/testrepo/refs/heads/.sentinel +0 -0
  30. data/features/fixtures/git/testrepo/refs/tags/.sentinel +0 -0
  31. data/features/fixtures/vcr_cassettes/vendorificator.yml +2375 -0
  32. data/features/git.feature +12 -0
  33. data/features/needed.feature +16 -0
  34. data/features/smoke.feature +14 -0
  35. data/features/status.feature +47 -0
  36. data/features/step_definitions/basic.rb +52 -0
  37. data/features/step_definitions/git.rb +39 -0
  38. data/features/step_definitions/vendorificator.rb +27 -0
  39. data/features/support/env.rb +32 -0
  40. data/features/support/transform_pattern.rb +12 -0
  41. data/features/support/world_git.rb +40 -0
  42. data/features/support/world_runs.rb +90 -0
  43. data/features/tarball.feature +63 -0
  44. data/features/tarball_edit.feature +15 -0
  45. data/features/vendor.feature +16 -0
  46. data/lib/vendorificator/cli.rb +233 -0
  47. data/lib/vendorificator/config.rb +72 -0
  48. data/lib/vendorificator/hooks/chef_cookbook.rb +23 -0
  49. data/lib/vendorificator/repo.rb +69 -0
  50. data/lib/vendorificator/vendor/archive.rb +90 -0
  51. data/lib/vendorificator/vendor/chef_cookbook.rb +58 -0
  52. data/lib/vendorificator/vendor/git.rb +47 -0
  53. data/lib/vendorificator/vendor.rb +260 -0
  54. data/lib/vendorificator/version.rb +3 -0
  55. data/lib/vendorificator.rb +9 -0
  56. data/vendorificator.gemspec +30 -0
  57. metadata +321 -0
@@ -0,0 +1,233 @@
1
+ require 'thor'
2
+
3
+ require 'vendorificator'
4
+
5
+ module Vendorificator
6
+ class CLI < Thor
7
+ include Vendorificator
8
+
9
+ check_unknown_options! :except => [:git, :diff, :log]
10
+ stop_on_unknown_option! :git, :diff, :log
11
+
12
+ default_task :sync
13
+
14
+ class_option :file, :aliases => '-f', :type => :string, :banner => 'PATH'
15
+ class_option :debug, :aliases => '-d', :type => :boolean, :default => false
16
+ class_option :quiet, :aliases => ['-q'], :default => false, :type => :boolean
17
+ class_option :modules, :type => :string, :default => '',
18
+ :banner => 'mod1,mod2,...,modN',
19
+ :desc => 'Run only for specified modules (name or path, comma separated)'
20
+
21
+ def initialize(*args)
22
+ super
23
+ Grit.debug = true if options[:debug]
24
+ Vendorificator::Config.from_file(find_vendorfile)
25
+ Vendorificator::Config[:shell] = shell
26
+
27
+ class << shell
28
+ # Make say_status always say it.
29
+ def quiet?
30
+ false
31
+ end
32
+ end
33
+ end
34
+
35
+ desc :sync, "Download new or updated vendor files"
36
+ def sync
37
+ ensure_clean_repo!
38
+ Vendorificator::Config.each_module(*modules) do |mod|
39
+ say_status :module, mod.name
40
+ begin
41
+ shell.padding += 1
42
+ mod.run!
43
+ ensure
44
+ shell.padding -= 1
45
+ end
46
+ end
47
+ end
48
+
49
+ desc "status", "List known vendor modules and their status"
50
+ def status
51
+ say_status 'WARNING', 'Git repository is not clean', :red unless repo.clean?
52
+ Vendorificator::Config.each_module(*modules) do |mod|
53
+ status_line = mod.to_s
54
+
55
+ updatable = mod.updatable?
56
+ if updatable
57
+ if updatable == true
58
+ status_line << ' (updatable)'
59
+ else
60
+ status_line << " (updatable to #{updatable.name})"
61
+ end
62
+ end
63
+
64
+ say_status( mod.status.to_s.gsub('_', ' '), status_line,
65
+ ( mod.status==:up_to_date ? :green : :yellow ) )
66
+ end
67
+ end
68
+
69
+ desc :pull, "Pull upstream branches from a remote repository"
70
+ method_option :remote, :aliases => ['-r'], :default => nil
71
+ method_option :dry_run, :aliases => ['-n'], :default => false, :type => :boolean
72
+ def pull
73
+ ensure_clean_repo!
74
+ remotes = options[:remote] ? options[:remote].split(',') : conf[:remotes]
75
+ remotes.each do |remote|
76
+ indent 'remote', remote do
77
+ repo.pull(remote, options)
78
+ end
79
+ end
80
+ end
81
+ desc "git GIT_COMMAND [GIT_ARGS [...]]",
82
+ "Run a git command for specified modules"
83
+ long_desc <<EOF
84
+ Run a git command for specified modules. Within GIT_ARGS arguments,
85
+ you can use @MERGED@ and @PATH@ tags, which will be substituted with
86
+ mo#dule's most recently merged revision and full path of its work
87
+ directory.
88
+
89
+ The 'diff' and 'log' commands are simple aliases for 'git' command.
90
+
91
+ Examples:
92
+ vendor git log @MERGED@..HEAD -- @PATH@ # basic 'vendor log'
93
+ vendor git diff --stat @MERGED@ -- @PATH@ # 'vendor diff', as diffstat
94
+ EOF
95
+ method_option :only_changed, :default => false, :type => :boolean
96
+ def git(command, *args)
97
+ Vendorificator::Config.each_module(*modules) do |mod|
98
+ unless mod.merged
99
+ say_status 'unmerged', mod.to_s, :red unless options[:only_changed]
100
+ next
101
+ end
102
+
103
+ actual_args = args.dup.map do |arg|
104
+ arg.
105
+ gsub('@MERGED@', mod.merged).
106
+ gsub('@PATH@', mod.work_dir)
107
+ end
108
+
109
+ output = repo.git.native(command, {}, *actual_args)
110
+ if output.empty?
111
+ say_status 'unchanged', mod.to_s, :green unless options[:only_changed]
112
+ else
113
+ say_status 'changed', mod.to_s, :yellow
114
+ end
115
+ puts output unless options[:quiet] || output.empty?
116
+ end
117
+ end
118
+
119
+ desc "diff [OPTIONS] [GIT OPTIONS]",
120
+ "Show differences between work tree and upstream module(s)"
121
+ method_option :only_changed, :default => false, :type => :boolean
122
+ def diff(*args)
123
+ invoke :git, %w'diff' + args + %w'@MERGED@ -- @PATH@'
124
+ end
125
+
126
+ desc "log [OPTIONS] [GIT OPTIONS]",
127
+ "Show git log of commits added to upstream module(s)"
128
+ method_option :only_changed, :default => false, :type => :boolean
129
+ def log(*args)
130
+ invoke :git, %w'log' + args + %w'@MERGED@..HEAD -- @PATH@'
131
+ end
132
+
133
+ desc :pry, 'Pry into the binding', :hide => true
134
+ def pry
135
+ require 'pry'
136
+ binding.pry
137
+ end
138
+
139
+ def self.start
140
+ # Make --git-options always quoted
141
+ if i = ARGV.index('--git-options')
142
+ ARGV[i+1,0] = '--'
143
+ end
144
+
145
+ if ENV['FIXTURES_DIR']
146
+ require 'vcr'
147
+ VCR.configure do |c|
148
+ c.cassette_library_dir = File.join(ENV['FIXTURES_DIR'], 'vcr_cassettes')
149
+ c.default_cassette_options = { :record => :new_episodes }
150
+ c.hook_into :fakeweb
151
+ end
152
+ VCR.use_cassette(ENV['VCR_CASSETTE'] || 'vendorificator') do
153
+ super
154
+ end
155
+ else
156
+ super
157
+ end
158
+ end
159
+
160
+ private
161
+
162
+ def split_git_options(args)
163
+ case i = args.index('--git-options')
164
+ when nil then [ args, [] ]
165
+ when 0 then [ [], args[1..-1] ]
166
+ else [ args[0..(i-1)], args[(i+1)..-1] ]
167
+ end
168
+ end
169
+
170
+ def modules
171
+ options[:modules].split(',').map(&:strip)
172
+ end
173
+
174
+ def conf
175
+ Vendorificator::Config
176
+ end
177
+
178
+ def repo
179
+ Vendorificator::Config.repo
180
+ end
181
+
182
+ def fail!(message, exception_message='I give up.')
183
+ say_status('FATAL', message, :red)
184
+ raise Thor::Error, 'I give up.'
185
+ end
186
+
187
+ def indent(*args, &block)
188
+ say_status *args unless args.empty?
189
+ shell.padding += 1
190
+ yield
191
+ ensure
192
+ shell.padding -= 1
193
+ end
194
+
195
+ # Find proper Vendorfile
196
+ def find_vendorfile
197
+ given = options.file || ENV['VENDORFILE']
198
+ return Pathname.new(given).expand_path if given && !given.empty?
199
+
200
+ Pathname.pwd.ascend do |dir|
201
+ vf = dir.join('Vendorfile')
202
+ return vf if vf.exist?
203
+
204
+ vf = dir.join('config/vendor.rb')
205
+ return vf if vf.exist?
206
+
207
+ # avoid stepping above the tmp directory when testing
208
+ if ENV['VENDORIFICATOR_SPEC_RUN'] &&
209
+ dir.join('vendorificator.gemspec').exist?
210
+ raise RuntimeError, "Vendorfile not found"
211
+ end
212
+ end
213
+
214
+ raise RuntimeError, "Vendorfile not found"
215
+ end
216
+
217
+ def ensure_clean_repo!
218
+ unless repo.clean?
219
+ fail!('Repository is not clean.')
220
+ end
221
+ end
222
+ end
223
+ end
224
+
225
+ # Monkey patch over https://github.com/wycats/thor/pull/298
226
+ class Thor::Options
227
+ alias_method :_orig_current_is_switch?, :current_is_switch?
228
+ def current_is_switch?
229
+ rv = _orig_current_is_switch?
230
+ @parsing_options = false if !rv[0] && @stop_on_unknown && @parsing_options
231
+ rv
232
+ end
233
+ end
@@ -0,0 +1,72 @@
1
+ require 'pathname'
2
+
3
+ require 'mixlib/config'
4
+
5
+ require 'vendorificator/repo'
6
+
7
+ module Vendorificator
8
+ class Config
9
+ extend Mixlib::Config
10
+
11
+ configure do |c|
12
+ c[:root] = Pathname.getwd
13
+ c[:basedir] = 'vendor'
14
+ c[:branch_prefix] = 'vendor'
15
+ c[:modules] = []
16
+ c[:remotes] = %w(origin)
17
+ end
18
+
19
+ def self.from_file(filename)
20
+ pathname = Pathname.new(filename).cleanpath.expand_path
21
+ self[:root_dir] =
22
+ if ( pathname.basename.to_s == 'vendor.rb' &&
23
+ pathname.dirname.basename.to_s == 'config' )
24
+ # Correctly recognize root dir if main config is 'config/vendor.rb'
25
+ pathname.dirname.dirname
26
+ else
27
+ pathname.dirname
28
+ end
29
+ self[:vendorfile_path] = pathname
30
+ self[:lockfile_path] = pathname.dirname.join(pathname.basename.to_s + '.lock')
31
+ super(pathname.to_s)
32
+ end
33
+
34
+ def self.repo
35
+ @repo ||= begin
36
+ git_root_path = self[:repo_dir] || _find_git_root
37
+ raise "Can't find Git repository" unless git_root_path
38
+ Vendorificator::Repo.new( git_root_path.to_s )
39
+ end
40
+ end
41
+
42
+ def self.each_module(*modules)
43
+ module_paths = modules.map { |m| File.expand_path(m) }
44
+
45
+ # We don't use self[:modules].each here, because mod.run! is
46
+ # explicitly allowed to append to Config[:modules], and #each
47
+ # fails to catch up on some Ruby implementations.
48
+ i = 0
49
+ while true
50
+ break if i >= Vendorificator::Config[:modules].length
51
+ mod = Vendorificator::Config[:modules][i]
52
+ yield mod if
53
+ modules.empty? ||
54
+ modules.include?(mod.name) ||
55
+ module_paths.include?(mod.work_dir)
56
+ i += 1
57
+
58
+ # Add dependencies
59
+ work_dirs = Vendorificator::Config[:modules].map(&:work_dir)
60
+ Vendorificator::Config[:modules] +=
61
+ mod.dependencies.reject { |dep| work_dirs.include?(dep.work_dir) }
62
+ end
63
+ end
64
+
65
+ def self._find_git_root
66
+ self[:root_dir].ascend do |dir|
67
+ return dir if dir.join('.git').exist?
68
+ end
69
+ end
70
+ private_class_method :_find_git_root
71
+ end
72
+ end
@@ -0,0 +1,23 @@
1
+ require 'chef/cookbook/metadata'
2
+
3
+ module Vendorificator::Hooks
4
+ module ChefCookbookDependencies
5
+ # Add required Chef cookbooks to vendor modules
6
+ def dependencies
7
+ ignored = Vendorificator::Config[:chef_cookbook_ignore_dependencies] || []
8
+ metadata = File.join(self.work_dir, 'metadata.rb')
9
+
10
+ unless File.exist?(metadata)
11
+ shell.say_status 'WARNING', "Metadata of #{name} does not exist at #{metadata}, could not gather dependencies", :red
12
+ return super
13
+ end
14
+
15
+ cbmd = Chef::Cookbook::Metadata.new
16
+ cbmd.from_file(metadata)
17
+
18
+ super + cbmd.dependencies.
19
+ reject { |name, version| ignored.include?(name) }.
20
+ map { |name, version| Vendorificator::Vendor::ChefCookbook.new(name) }
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,69 @@
1
+ require 'grit'
2
+
3
+ module Vendorificator
4
+ class Repo < Grit::Repo
5
+ # True if repository doesn't contain uncommitted changes.
6
+ def clean?
7
+ # copy code from http://stackoverflow.com/a/3879077/16390
8
+ git.native :update_index, {}, '-q', '--ignore-submodules', '--refresh'
9
+ git.native :diff_files, {:raise => true}, '--quiet', '--ignore-submodules', '--'
10
+ git.native :diff_index, {:raise => true}, '--cached', '--quiet', 'HEAD', '--ignore-submodules', '--'
11
+ true
12
+ rescue Grit::Git::CommandFailed
13
+ false
14
+ end
15
+
16
+ # Update vendor branches & tags from an upstream repository
17
+ def pull(remote, options={})
18
+ raise RuntimeError, "Unknown remote #{remote}" unless remote_list.include?(remote)
19
+
20
+ git.fetch({}, remote)
21
+ git.fetch({:tags => true}, remote)
22
+
23
+ ref_rx = /^#{Regexp.quote(remote)}\//
24
+ remote_branches = Hash[remotes.map{|r| [$',r] if r.name =~ ref_rx }.compact]
25
+
26
+ # FIXME: should we depend on Vendorificator::Config here?
27
+ Vendorificator::Config.each_module do |mod|
28
+ remote_head = remote_branches[mod.branch_name]
29
+ ours = mod.head && mod.head.commit.sha
30
+ theirs = remote_head && remote_head.commit.sha
31
+
32
+ if remote_head
33
+ if not mod.head
34
+ say_status 'new', mod.branch_name, :yellow
35
+ git.branch({:track=>true}, mod.branch_name, remote_head.name) unless options[:dry_run]
36
+ elsif ours == theirs
37
+ say_status 'unchanged', mod.branch_name
38
+ elsif fast_forwardable?(theirs, ours)
39
+ say_status 'updated', mod.name, :yellow
40
+ unless options[:dry_run]
41
+ mod.in_branch do
42
+ git.merge({:ff_only => true}, remote_head.name)
43
+ end
44
+ end
45
+ elsif fast_forwardable?(ours, theirs)
46
+ say_status 'older', mod.branch_name
47
+ else
48
+ say_status 'complicated', mod.branch_name, :red
49
+ indent do
50
+ say 'Merge it yourself.'
51
+ end
52
+ end
53
+ else
54
+ say_status 'unknown', mod.branch_name
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def conf
61
+ Vendorificator::Config
62
+ end
63
+
64
+ def say_status(*args)
65
+ conf[:shell].say_status(*args) if conf[:shell]
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,90 @@
1
+ require 'digest'
2
+ require 'open-uri'
3
+ require 'tempfile'
4
+ require 'uri'
5
+
6
+ require 'escape'
7
+
8
+ require 'vendorificator/vendor'
9
+
10
+ class Vendorificator::Vendor::Archive < Vendorificator::Vendor
11
+ arg_reader :url, :strip_root, :type, :checksum, :filename, :basename, :extname, :unpack
12
+ attr_reader :conjured_checksum
13
+
14
+ def initialize(name, args={}, &block)
15
+ no_url_given = !args[:url]
16
+
17
+ args[:url] ||= name
18
+ args[:filename] ||= URI::parse(args[:url]).path.split('/').last
19
+
20
+ case args[:filename]
21
+ when /\.(tar\.|t)gz$/
22
+ args[:type] ||= :targz
23
+ args[:unpack] ||= 'tar -xzf'
24
+ when /\.tar\.bz2$/
25
+ args[:type] ||= :tarbz2
26
+ args[:unpack] ||= 'tar -xjf'
27
+ when /\.zip$/
28
+ args[:type] ||= :zip
29
+ args[:unpack] ||= 'unzip'
30
+ when /\.[^\.][^\.]?[^\.]?[^\.]?$/
31
+ args[:type] ||=
32
+ begin
33
+ unless args[:unpack]
34
+ raise RuntimeError,
35
+ "Unknown file type #{$&.inspect}, please provide :unpack argument"
36
+ end
37
+ $&
38
+ end
39
+ else
40
+ args[:basename] ||= args[:filename]
41
+ args[:extname] ||= ''
42
+ unless args[:unpack] || [:targz, :tarbz2, :zip].include?(args[:type])
43
+ raise RuntimeError, "Unknown file type for #{args[:filename].inspect}, please provide :unpack or :type argument"
44
+ end
45
+ end
46
+ args[:basename] ||= $`
47
+ args[:extname] ||= $&
48
+
49
+ name = args[:basename] if no_url_given
50
+
51
+ super(name, args, &block)
52
+ end
53
+
54
+ def conjure!
55
+ shell.say_status :download, url
56
+ archive = Tempfile.new([basename, extname])
57
+ archive.write( open(url).read )
58
+ archive.close
59
+ @conjured_checksum = Digest::SHA256.file(archive.path).hexdigest
60
+ raise RuntimeError, "Checksum error" if checksum && checksum!=conjured_checksum
61
+ shell.say_status :unpack, filename
62
+ system "#{unpack} #{Escape.shell_single_word archive.path}"
63
+ if Dir.entries('.').length == 3 && !args[:no_strip_root]
64
+ root = (Dir.entries('.') - %w(.. .)).first
65
+ root_entries = Dir.entries(root) - %w(.. .)
66
+ while root_entries.include?(root)
67
+ FileUtils::mv root, root+"~"
68
+ root << "~"
69
+ end
70
+ FileUtils::mv root_entries.map { |e| File.join(root, e) }, '.'
71
+ FileUtils::rmdir root
72
+ end
73
+ super
74
+ ensure
75
+ archive.close
76
+ archive.unlink
77
+ end
78
+
79
+ def upstream_version
80
+ filename
81
+ end
82
+
83
+ def conjure_commit_message
84
+ rv = "Conjured archive #{name} from #{filename}\nOrigin: #{url}\nChecksum: #{conjured_checksum}\n"
85
+ rv << "Version: #{version}\n" if version
86
+ rv
87
+ end
88
+
89
+ install!
90
+ end
@@ -0,0 +1,58 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+ require 'json'
4
+
5
+ require 'vendorificator/vendor/archive'
6
+ require 'vendorificator/hooks/chef_cookbook'
7
+
8
+ class Vendorificator::Vendor::ChefCookbook < Vendorificator::Vendor::Archive
9
+ include Vendorificator::Hooks::ChefCookbookDependencies
10
+
11
+ @method_name = :chef_cookbook
12
+ @category = :cookbooks
13
+
14
+ API_PREFIX = 'http://cookbooks.opscode.com/api/v1/cookbooks/'
15
+
16
+ def initialize(name, args={}, &block)
17
+ args[:url] ||= true # to avoid having name treated as url
18
+ args[:filename] ||= "#{name}.tgz"
19
+
20
+ super(name, args, &block)
21
+ end
22
+
23
+ def api_data(v=nil)
24
+ v = v.gsub(/[^0-9]/, '_') if v
25
+ @api_data ||= {}
26
+ @api_data[v] ||=
27
+ begin
28
+ url = "#{API_PREFIX}#{name}"
29
+ url << "/versions/#{v}" if v
30
+ JSON::load(Net::HTTP.get_response(URI.parse(url)).body)
31
+ end
32
+ end
33
+
34
+ def cookbook_data
35
+ @cookbook_data ||= api_data(version)
36
+ end
37
+
38
+ def upstream_version
39
+ URI::parse(api_data['latest_version']).path.split('/').last.gsub('_', '.')
40
+ end
41
+
42
+ def url
43
+ cookbook_data['file']
44
+ end
45
+
46
+ def conjure!
47
+ super
48
+ # Some Opscode Community tarballs include a confusing .git file,
49
+ # we don't want this.
50
+ FileUtils::rm_f '.git'
51
+ end
52
+
53
+ def conjure_commit_message
54
+ "Conjured cookbook #{name} version #{version}\nOrigin: #{url}\nChecksum: #{conjured_checksum}\n"
55
+ end
56
+
57
+ install!
58
+ end
@@ -0,0 +1,47 @@
1
+ require 'fileutils'
2
+
3
+ require 'grit'
4
+
5
+ require 'vendorificator/vendor'
6
+
7
+ class Vendorificator::Vendor::Git < Vendorificator::Vendor
8
+ arg_reader :repository, :revision, :branch
9
+ attr_reader :module_repo, :conjured_revision
10
+
11
+ def initialize(name, args={}, &block)
12
+ unless args.include?(:repository)
13
+ args[:repository] = name
14
+ name = name.split('/').last.sub(/\.git$/, '')
15
+ end
16
+ super(name, args, &block)
17
+ end
18
+
19
+ def conjure!
20
+ shell.say_status :clone, repository
21
+ Grit::Git.new('.').clone({}, repository, '.')
22
+ @module_repo = Grit::Repo.new('.')
23
+
24
+ if revision
25
+ module_repo.git.checkout({:b => 'vendorified'}, revision)
26
+ elsif branch
27
+ module_repo.git.checkout({:b => 'vendorified'}, "origin/#{branch}")
28
+ end
29
+
30
+ super
31
+ @conjured_revision = module_repo.head.commit.id
32
+ FileUtils::rm_rf '.git'
33
+ end
34
+
35
+ def upstream_version
36
+ conjured_revision
37
+ end
38
+
39
+ def conjure_commit_message
40
+ rv = "Conjured git module #{name} "
41
+ rv << "version #{version} " if version
42
+ rv << "revision #{conjured_revision}"
43
+ rv
44
+ end
45
+
46
+ install!
47
+ end