vendorificator 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +19 -0
- data/.travis.yml +9 -0
- data/Gemfile +11 -0
- data/LICENSE +22 -0
- data/README.md +45 -0
- data/Rakefile +29 -0
- data/bin/vendor +4 -0
- data/bin/vendorify +6 -0
- data/examples/Vendorfile +25 -0
- data/features/chef_cookbook.feature +44 -0
- data/features/deprecated.feature +17 -0
- data/features/fixtures/git/testrepo/HEAD +1 -0
- data/features/fixtures/git/testrepo/config +7 -0
- data/features/fixtures/git/testrepo/description +1 -0
- data/features/fixtures/git/testrepo/hooks/applypatch-msg.sample +15 -0
- data/features/fixtures/git/testrepo/hooks/commit-msg.sample +24 -0
- data/features/fixtures/git/testrepo/hooks/post-update.sample +8 -0
- data/features/fixtures/git/testrepo/hooks/pre-applypatch.sample +14 -0
- data/features/fixtures/git/testrepo/hooks/pre-commit.sample +50 -0
- data/features/fixtures/git/testrepo/hooks/pre-rebase.sample +169 -0
- data/features/fixtures/git/testrepo/hooks/prepare-commit-msg.sample +36 -0
- data/features/fixtures/git/testrepo/hooks/update.sample +128 -0
- data/features/fixtures/git/testrepo/info/exclude +6 -0
- data/features/fixtures/git/testrepo/info/refs +5 -0
- data/features/fixtures/git/testrepo/objects/info/packs +2 -0
- data/features/fixtures/git/testrepo/objects/pack/pack-46f7621b6a6b9b1c22dd15c08d457dfedf76e55f.idx +0 -0
- data/features/fixtures/git/testrepo/objects/pack/pack-46f7621b6a6b9b1c22dd15c08d457dfedf76e55f.pack +0 -0
- data/features/fixtures/git/testrepo/packed-refs +6 -0
- data/features/fixtures/git/testrepo/refs/heads/.sentinel +0 -0
- data/features/fixtures/git/testrepo/refs/tags/.sentinel +0 -0
- data/features/fixtures/vcr_cassettes/vendorificator.yml +2375 -0
- data/features/git.feature +12 -0
- data/features/needed.feature +16 -0
- data/features/smoke.feature +14 -0
- data/features/status.feature +47 -0
- data/features/step_definitions/basic.rb +52 -0
- data/features/step_definitions/git.rb +39 -0
- data/features/step_definitions/vendorificator.rb +27 -0
- data/features/support/env.rb +32 -0
- data/features/support/transform_pattern.rb +12 -0
- data/features/support/world_git.rb +40 -0
- data/features/support/world_runs.rb +90 -0
- data/features/tarball.feature +63 -0
- data/features/tarball_edit.feature +15 -0
- data/features/vendor.feature +16 -0
- data/lib/vendorificator/cli.rb +233 -0
- data/lib/vendorificator/config.rb +72 -0
- data/lib/vendorificator/hooks/chef_cookbook.rb +23 -0
- data/lib/vendorificator/repo.rb +69 -0
- data/lib/vendorificator/vendor/archive.rb +90 -0
- data/lib/vendorificator/vendor/chef_cookbook.rb +58 -0
- data/lib/vendorificator/vendor/git.rb +47 -0
- data/lib/vendorificator/vendor.rb +260 -0
- data/lib/vendorificator/version.rb +3 -0
- data/lib/vendorificator.rb +9 -0
- data/vendorificator.gemspec +30 -0
- 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
|