chef 0.10.0.beta.3 → 0.10.0.beta.4
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/chef/application/knife.rb +7 -12
- data/lib/chef/knife.rb +10 -3
- data/lib/chef/knife/bootstrap.rb +11 -2
- data/lib/chef/knife/cookbook_bulk_delete.rb +4 -3
- data/lib/chef/knife/cookbook_download.rb +2 -2
- data/lib/chef/knife/cookbook_list.rb +4 -1
- data/lib/chef/knife/cookbook_site_download.rb +1 -1
- data/lib/chef/knife/cookbook_site_install.rb +272 -0
- data/lib/chef/knife/ssh.rb +8 -0
- data/lib/chef/knife/ui.rb +8 -4
- data/lib/chef/version.rb +1 -1
- metadata +3 -3
- data/lib/chef/knife/cookbook_site_vendor.rb +0 -142
@@ -32,17 +32,13 @@ class Chef::Application::Knife < Chef::Application
|
|
32
32
|
:description => "The configuration file to use",
|
33
33
|
:proc => lambda { |path| File.expand_path(path, Dir.pwd) }
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
:
|
38
|
-
:
|
39
|
-
:
|
40
|
-
|
41
|
-
|
42
|
-
:short => "-L LOGLOCATION",
|
43
|
-
:long => "--logfile LOGLOCATION",
|
44
|
-
:description => "Set the log file location, defaults to STDOUT",
|
45
|
-
:proc => nil
|
35
|
+
verbosity_level = 0
|
36
|
+
option :verbosity,
|
37
|
+
:short => '-V',
|
38
|
+
:long => '--verbose',
|
39
|
+
:description => "More verbose output. Use twice for max verbosity",
|
40
|
+
:proc => Proc.new { verbosity_level += 1},
|
41
|
+
:default => 0
|
46
42
|
|
47
43
|
option :environment,
|
48
44
|
:short => "-E ENVIRONMENT",
|
@@ -94,7 +90,6 @@ class Chef::Application::Knife < Chef::Application
|
|
94
90
|
:description => "Accept default values for all questions"
|
95
91
|
|
96
92
|
option :print_after,
|
97
|
-
:short => "-p",
|
98
93
|
:long => "--print-after",
|
99
94
|
:description => "Show the data after a destructive operation"
|
100
95
|
|
data/lib/chef/knife.rb
CHANGED
@@ -151,7 +151,7 @@ class Chef
|
|
151
151
|
load_commands
|
152
152
|
subcommand_class = subcommand_class_from(args)
|
153
153
|
subcommand_class.options = options.merge!(subcommand_class.options)
|
154
|
-
subcommand_class.load_deps
|
154
|
+
subcommand_class.load_deps unless want_help?(args)
|
155
155
|
instance = subcommand_class.new(args)
|
156
156
|
instance.configure_chef
|
157
157
|
instance.run
|
@@ -282,8 +282,15 @@ class Chef
|
|
282
282
|
self.msg("No knife configuration file found")
|
283
283
|
end
|
284
284
|
|
285
|
-
|
286
|
-
|
285
|
+
case config[:verbosity]
|
286
|
+
when 0
|
287
|
+
Chef::Config[:log_level] = :error
|
288
|
+
when 1
|
289
|
+
Chef::Config[:log_level] = :info
|
290
|
+
else
|
291
|
+
Chef::Config[:log_level] = :debug
|
292
|
+
end
|
293
|
+
|
287
294
|
Chef::Config[:node_name] = config[:node_name] if config[:node_name]
|
288
295
|
Chef::Config[:client_key] = config[:client_key] if config[:client_key]
|
289
296
|
Chef::Config[:chef_server_url] = config[:chef_server_url] if config[:chef_server_url]
|
data/lib/chef/knife/bootstrap.rb
CHANGED
@@ -26,6 +26,9 @@ class Chef
|
|
26
26
|
require 'chef/json_compat'
|
27
27
|
require 'tempfile'
|
28
28
|
require 'erubis'
|
29
|
+
require 'highline'
|
30
|
+
require 'net/ssh'
|
31
|
+
require 'net/ssh/multi'
|
29
32
|
end
|
30
33
|
|
31
34
|
banner "knife bootstrap FQDN [RUN LIST...] (options)"
|
@@ -41,6 +44,13 @@ class Chef
|
|
41
44
|
:long => "--ssh-password PASSWORD",
|
42
45
|
:description => "The ssh password"
|
43
46
|
|
47
|
+
option :ssh_port,
|
48
|
+
:short => "-p PORT",
|
49
|
+
:long => "--ssh-port PORT",
|
50
|
+
:description => "The ssh port",
|
51
|
+
:default => "22",
|
52
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:ssh_port] = key }
|
53
|
+
|
44
54
|
option :identity_file,
|
45
55
|
:short => "-i IDENTITY_FILE",
|
46
56
|
:long => "--identity-file IDENTITY_FILE",
|
@@ -118,8 +128,6 @@ class Chef
|
|
118
128
|
end
|
119
129
|
|
120
130
|
def run
|
121
|
-
require 'highline'
|
122
|
-
require 'net/ssh'
|
123
131
|
|
124
132
|
validate_name_args!
|
125
133
|
@node_name = Array(@name_args).first
|
@@ -156,6 +164,7 @@ class Chef
|
|
156
164
|
ssh.name_args = [ server_name, ssh_command ]
|
157
165
|
ssh.config[:ssh_user] = config[:ssh_user]
|
158
166
|
ssh.config[:ssh_password] = config[:ssh_password]
|
167
|
+
ssh.config[:ssh_port] = Chef::Config[:knife][:ssh_port] || config[:ssh_port]
|
159
168
|
ssh.config[:identity_file] = config[:identity_file]
|
160
169
|
ssh.config[:manual] = true
|
161
170
|
ssh.config[:no_host_key_verify] = config[:no_host_key_verify]
|
@@ -25,6 +25,7 @@ class Chef
|
|
25
25
|
|
26
26
|
deps do
|
27
27
|
require 'chef/knife/cookbook_delete'
|
28
|
+
require 'chef/cookbook_version'
|
28
29
|
end
|
29
30
|
|
30
31
|
option :purge, :short => '-p', :long => '--purge', :boolean => true, :description => 'Permanently remove files from backing data store'
|
@@ -44,12 +45,12 @@ class Chef
|
|
44
45
|
cookbooks_to_delete = cookbooks_names.inject({}) { |hash, name| hash[name] = all_cookbooks[name];hash }
|
45
46
|
output(format_list_for_display(cookbooks_to_delete))
|
46
47
|
|
47
|
-
confirm("Do you really want to delete these cookbooks? All versions will be deleted. (Y/N) ", false)
|
48
|
+
ui.confirm("Do you really want to delete these cookbooks? All versions will be deleted. (Y/N) ", false)
|
48
49
|
|
49
|
-
confirm("Files that are common to multiple cookbooks are shared, so purging the files may disable other cookbooks. Are you sure you want to purge files instead of just deleting the cookbooks") if config[:purge]
|
50
|
+
ui.confirm("Files that are common to multiple cookbooks are shared, so purging the files may disable other cookbooks. Are you sure you want to purge files instead of just deleting the cookbooks") if config[:purge]
|
50
51
|
|
51
52
|
cookbooks_names.each do |cookbook_name|
|
52
|
-
versions = rest.get_rest("cookbooks/#{cookbook_name}").
|
53
|
+
versions = rest.get_rest("cookbooks/#{cookbook_name}")[cookbook_name]["versions"].map {|v| v["version"]}.flatten
|
53
54
|
versions.each do |version|
|
54
55
|
object = rest.delete_rest("cookbooks/#{cookbook_name}/#{version}#{config[:purge] ? "?purge=true" : ""}")
|
55
56
|
ui.info("Deleted cookbook #{cookbook_name.ljust(25)} [#{version}]")
|
@@ -95,7 +95,7 @@ class Chef
|
|
95
95
|
if available_versions.size == 1
|
96
96
|
@version = available_versions.first
|
97
97
|
elsif config[:latest]
|
98
|
-
@version = available_versions.map { |v| Chef::
|
98
|
+
@version = available_versions.map { |v| Chef::Version.new(v) }.sort.last
|
99
99
|
else
|
100
100
|
ask_which_version
|
101
101
|
end
|
@@ -104,7 +104,7 @@ class Chef
|
|
104
104
|
def available_versions
|
105
105
|
@available_versions ||= begin
|
106
106
|
versions = Chef::CookbookVersion.available_versions(@cookbook_name).map do |version|
|
107
|
-
Chef::
|
107
|
+
Chef::Version.new(version)
|
108
108
|
end
|
109
109
|
versions.sort!
|
110
110
|
versions
|
@@ -40,7 +40,10 @@ class Chef
|
|
40
40
|
num_versions = config[:all_versions] ? "num_versions=all" : "num_versions=1"
|
41
41
|
api_endpoint = env ? "/environments/#{env}/cookbooks?#{num_versions}" : "/cookbooks?#{num_versions}"
|
42
42
|
ui.info("Showing latest versions. Use --show-all to list all available versions.") unless config[:all_versions]
|
43
|
-
|
43
|
+
cookbook_versions = rest.get_rest(api_endpoint)
|
44
|
+
format_cookbook_list_for_display(cookbook_versions).each do |line|
|
45
|
+
ui.msg(line)
|
46
|
+
end
|
44
47
|
end
|
45
48
|
end
|
46
49
|
end
|
@@ -41,7 +41,7 @@ class Chef
|
|
41
41
|
|
42
42
|
@version = cookbook_data['version']
|
43
43
|
|
44
|
-
ui.info("Downloading #{@name_args[0]} from the cookbooks site at version #{cookbook_data['version']}")
|
44
|
+
ui.info("Downloading #{@name_args[0]} from the cookbooks site at version #{cookbook_data['version']} to #{config[:file]}")
|
45
45
|
rest.sign_on_redirect = false
|
46
46
|
tf = rest.get_rest(cookbook_data["file"], true)
|
47
47
|
unless config[:file]
|
@@ -0,0 +1,272 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Adam Jacob (<adam@opscode.com>)
|
3
|
+
# Copyright:: Copyright (c) 2010 Opscode, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'chef/knife'
|
20
|
+
require 'chef/mixin/shell_out'
|
21
|
+
|
22
|
+
class Chef
|
23
|
+
class Knife
|
24
|
+
class CookbookRepo
|
25
|
+
|
26
|
+
DIRTY_REPO = /^[\s]+M/
|
27
|
+
|
28
|
+
include Chef::Mixin::ShellOut
|
29
|
+
|
30
|
+
attr_reader :repo_path
|
31
|
+
attr_reader :default_branch
|
32
|
+
attr_reader :ui
|
33
|
+
|
34
|
+
def initialize(repo_path, ui, opts={})
|
35
|
+
@repo_path = repo_path
|
36
|
+
@ui = ui
|
37
|
+
@default_branch = 'master'
|
38
|
+
end
|
39
|
+
|
40
|
+
def sanity_check
|
41
|
+
unless ::File.directory?(repo_path)
|
42
|
+
ui.error("The cookbook repo path #{repo_path} does not exist or is not a directory")
|
43
|
+
exit 1
|
44
|
+
end
|
45
|
+
unless git_repo?(repo_path)
|
46
|
+
ui.error "The cookbook repo #{repo_path} is not a git repository."
|
47
|
+
ui.info("Use `git init` to initialize a git repo")
|
48
|
+
exit 1
|
49
|
+
end
|
50
|
+
unless branch_exists?(default_branch)
|
51
|
+
ui.error "The default branch '#{default_branch}' does not exist"
|
52
|
+
ui.info "If this is a new git repo, make sure you have at least one commit before installing cookbooks"
|
53
|
+
exit 1
|
54
|
+
end
|
55
|
+
cmd = git('status --porcelain')
|
56
|
+
if cmd.stdout =~ DIRTY_REPO
|
57
|
+
ui.error "You have uncommitted changes to your cookbook repo (#{repo_path}):"
|
58
|
+
ui.msg cmd.stdout
|
59
|
+
ui.info "Commit or stash your changes before importing cookbooks"
|
60
|
+
exit 1
|
61
|
+
end
|
62
|
+
# TODO: any untracked files in the cookbook directory will get nuked later
|
63
|
+
# make this an error condition also.
|
64
|
+
true
|
65
|
+
end
|
66
|
+
|
67
|
+
def reset_to_default_state
|
68
|
+
ui.info("Checking out the #{default_branch} branch.")
|
69
|
+
git("checkout #{default_branch}")
|
70
|
+
end
|
71
|
+
|
72
|
+
def prepare_to_import(cookbook_name)
|
73
|
+
branch = "chef-vendor-#{cookbook_name}"
|
74
|
+
if branch_exists?(branch)
|
75
|
+
ui.info("Pristine copy branch (#{branch}) exists, switching to it.")
|
76
|
+
git("checkout #{branch}")
|
77
|
+
else
|
78
|
+
ui.info("Creating pristine copy branch #{branch}")
|
79
|
+
git("checkout -b #{branch}")
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def finalize_updates_to(cookbook_name, version)
|
84
|
+
if update_count = updated?(cookbook_name)
|
85
|
+
ui.info "#{update_count} files updated, committing changes"
|
86
|
+
git("add #{cookbook_name}")
|
87
|
+
git("commit -m 'Import #{cookbook_name} version #{version}' -- #{cookbook_name}")
|
88
|
+
ui.info("Creating tag cookbook-site-imported-#{cookbook_name}-#{version}")
|
89
|
+
git("tag -f cookbook-site-imported-#{cookbook_name}-#{version}")
|
90
|
+
true
|
91
|
+
else
|
92
|
+
ui.info("No changes made to #{cookbook_name}")
|
93
|
+
false
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def merge_updates_from(cookbook_name, version)
|
98
|
+
branch = "chef-vendor-#{cookbook_name}"
|
99
|
+
Dir.chdir(repo_path) do
|
100
|
+
if system("git merge #{branch}")
|
101
|
+
ui.info("Cookbook #{cookbook_name} version #{version} successfully installed")
|
102
|
+
else
|
103
|
+
ui.error("You have merge conflicts - please resolve manually")
|
104
|
+
ui.info("Merge status (cd #{repo_path}; git status):")
|
105
|
+
system("git status")
|
106
|
+
exit 3
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def updated?(cookbook_name)
|
112
|
+
update_count = git("status --porcelain -- #{cookbook_name}").stdout.strip.lines.count
|
113
|
+
update_count == 0 ? nil : update_count
|
114
|
+
end
|
115
|
+
|
116
|
+
def branch_exists?(branch_name)
|
117
|
+
git("branch --no-color").stdout.lines.any? {|l| l.include?(branch_name) }
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
def git_repo?(directory)
|
123
|
+
if File.directory?(File.join(directory, '.git'))
|
124
|
+
return true
|
125
|
+
elsif File.dirname(directory) == directory
|
126
|
+
return false
|
127
|
+
else
|
128
|
+
git_repo?(File.dirname(directory))
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def apply_opts(opts)
|
133
|
+
opts.each do |option, value|
|
134
|
+
case option.to_s
|
135
|
+
when 'default_branch'
|
136
|
+
@default_branch = value
|
137
|
+
else
|
138
|
+
raise ArgumentError, "invalid option `#{option}' passed to CookbookRepo.new()"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def git(command)
|
144
|
+
shell_out!("git #{command}", :cwd => repo_path)
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
class CookbookSiteInstall < Knife
|
150
|
+
|
151
|
+
deps do
|
152
|
+
require 'chef/mixin/shell_out'
|
153
|
+
require 'chef/cookbook/metadata'
|
154
|
+
end
|
155
|
+
|
156
|
+
banner "knife cookbook site vendor COOKBOOK [VERSION] (options)"
|
157
|
+
category "cookbook site"
|
158
|
+
|
159
|
+
option :deps,
|
160
|
+
:short => "-d",
|
161
|
+
:long => "--dependencies",
|
162
|
+
:boolean => true,
|
163
|
+
:description => "Grab dependencies automatically"
|
164
|
+
|
165
|
+
option :cookbook_path,
|
166
|
+
:short => "-o PATH:PATH",
|
167
|
+
:long => "--cookbook-path PATH:PATH",
|
168
|
+
:description => "A colon-separated path to look for cookbooks in",
|
169
|
+
:proc => lambda { |o| o.split(":") }
|
170
|
+
|
171
|
+
option :branch_default,
|
172
|
+
:short => "-B BRANCH",
|
173
|
+
:long => "--branch BRANCH",
|
174
|
+
:description => "Default branch to work with",
|
175
|
+
:default => "master"
|
176
|
+
|
177
|
+
attr_reader :cookbook_name
|
178
|
+
attr_reader :vendor_path
|
179
|
+
|
180
|
+
def run
|
181
|
+
extend Chef::Mixin::ShellOut
|
182
|
+
|
183
|
+
if config[:cookbook_path]
|
184
|
+
Chef::Config[:cookbook_path] = config[:cookbook_path]
|
185
|
+
else
|
186
|
+
config[:cookbook_path] = Chef::Config[:cookbook_path]
|
187
|
+
end
|
188
|
+
|
189
|
+
@cookbook_name = parse_name_args!
|
190
|
+
# Check to ensure we have a valid source of cookbooks before continuing
|
191
|
+
#
|
192
|
+
@install_path = config[:cookbook_path].first
|
193
|
+
ui.info "Installing #@cookbook_name to #{@install_path}"
|
194
|
+
|
195
|
+
@repo = CookbookRepo.new(@install_path, ui, config)
|
196
|
+
#cookbook_path = File.join(vendor_path, name_args[0])
|
197
|
+
upstream_file = File.join(@install_path, "#{@cookbook_name}.tar.gz")
|
198
|
+
|
199
|
+
@repo.sanity_check
|
200
|
+
@repo.reset_to_default_state
|
201
|
+
@repo.prepare_to_import(@cookbook_name)
|
202
|
+
|
203
|
+
downloader = download_cookbook_to(upstream_file)
|
204
|
+
clear_existing_files(File.join(@install_path, @cookbook_name))
|
205
|
+
extract_cookbook(upstream_file, @install_path)
|
206
|
+
|
207
|
+
# TODO: it'd be better to store these outside the cookbook repo and
|
208
|
+
# keep them around, e.g., in ~/Library/Caches on OS X.
|
209
|
+
ui.info("removing downloaded tarball")
|
210
|
+
shell_out!("rm #{upstream_file}", :cwd => vendor_path)
|
211
|
+
|
212
|
+
if @repo.finalize_updates_to(@cookbook_name, downloader.version)
|
213
|
+
@repo.reset_to_default_state
|
214
|
+
@repo.merge_updates_from(@cookbook_name, downloader.version)
|
215
|
+
else
|
216
|
+
@repo.reset_to_default_state
|
217
|
+
end
|
218
|
+
|
219
|
+
|
220
|
+
if config[:deps]
|
221
|
+
md = Chef::Cookbook::Metadata.new
|
222
|
+
md.from_file(File.join(cookbook_path, "metadata.rb"))
|
223
|
+
md.dependencies.each do |cookbook, version_list|
|
224
|
+
# Doesn't do versions.. yet
|
225
|
+
nv = Chef::Knife::CookbookSiteVendor.new
|
226
|
+
nv.config = config
|
227
|
+
nv.name_args = [ cookbook ]
|
228
|
+
nv.run
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
def parse_name_args!
|
234
|
+
if name_args.empty?
|
235
|
+
ui.error("please specify a cookbook to download and install")
|
236
|
+
exit 1
|
237
|
+
elsif name_args.size > 1
|
238
|
+
ui.error("Installing multiple cookbooks at once is not supported")
|
239
|
+
exit 1
|
240
|
+
else
|
241
|
+
name_args.first
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def download_cookbook_to(download_path)
|
246
|
+
downloader = Chef::Knife::CookbookSiteDownload.new
|
247
|
+
downloader.config[:file] = download_path
|
248
|
+
downloader.name_args = name_args
|
249
|
+
downloader.run
|
250
|
+
downloader
|
251
|
+
end
|
252
|
+
|
253
|
+
def extract_cookbook(upstream_file, version)
|
254
|
+
ui.info("Uncompressing #{@cookbook_name} version #{version}.")
|
255
|
+
shell_out!("tar zxvf #{upstream_file}", :cwd => @install_path)
|
256
|
+
end
|
257
|
+
|
258
|
+
def clear_existing_files(cookbook_path)
|
259
|
+
ui.info("Removing pre-existing version.")
|
260
|
+
shell_out!("rm -r #{cookbook_path}", :cwd => @install_path) if File.directory?(cookbook_path)
|
261
|
+
end
|
262
|
+
|
263
|
+
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
|
269
|
+
|
270
|
+
|
271
|
+
|
272
|
+
|
data/lib/chef/knife/ssh.rb
CHANGED
@@ -62,6 +62,13 @@ class Chef
|
|
62
62
|
:long => "--ssh-password PASSWORD",
|
63
63
|
:description => "The ssh password"
|
64
64
|
|
65
|
+
option :ssh_port,
|
66
|
+
:short => "-p PORT",
|
67
|
+
:long => "--ssh-port PORT",
|
68
|
+
:description => "The ssh port",
|
69
|
+
:default => "22",
|
70
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:ssh_port] = key }
|
71
|
+
|
65
72
|
option :identity_file,
|
66
73
|
:short => "-i IDENTITY_FILE",
|
67
74
|
:long => "--identity-file IDENTITY_FILE",
|
@@ -115,6 +122,7 @@ class Chef
|
|
115
122
|
session_opts = {}
|
116
123
|
session_opts[:keys] = File.expand_path(config[:identity_file]) if config[:identity_file]
|
117
124
|
session_opts[:password] = config[:ssh_password] if config[:ssh_password]
|
125
|
+
session_opts[:port] = Chef::Config[:knife][:ssh_port] || config[:ssh_port]
|
118
126
|
session_opts[:logger] = Chef::Log.logger if Chef::Log.level == :debug
|
119
127
|
|
120
128
|
if config[:no_host_key_verify]
|
data/lib/chef/knife/ui.rb
CHANGED
@@ -147,10 +147,14 @@ class Chef
|
|
147
147
|
if config[:with_uri]
|
148
148
|
item
|
149
149
|
else
|
150
|
-
item.inject({})
|
151
|
-
|
152
|
-
|
153
|
-
|
150
|
+
versions_by_cookbook = item.inject({}) do |collected, ( cookbook, versions )|
|
151
|
+
collected[cookbook] = versions["versions"].map {|v| v['version']}
|
152
|
+
collected
|
153
|
+
end
|
154
|
+
key_length = versions_by_cookbook.keys.map {|name| name.size }.max + 2
|
155
|
+
versions_by_cookbook.sort.map do |cookbook, versions|
|
156
|
+
"#{cookbook.ljust(key_length)} #{versions.join(',')}"
|
157
|
+
end
|
154
158
|
end
|
155
159
|
end
|
156
160
|
|
data/lib/chef/version.rb
CHANGED
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: chef
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease: 7
|
5
|
-
version: 0.10.0.beta.
|
5
|
+
version: 0.10.0.beta.4
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Adam Jacob
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-03-
|
13
|
+
date: 2011-03-31 00:00:00 -07:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -319,12 +319,12 @@ files:
|
|
319
319
|
- lib/chef/knife/cookbook_metadata_from_file.rb
|
320
320
|
- lib/chef/knife/cookbook_show.rb
|
321
321
|
- lib/chef/knife/cookbook_site_download.rb
|
322
|
+
- lib/chef/knife/cookbook_site_install.rb
|
322
323
|
- lib/chef/knife/cookbook_site_list.rb
|
323
324
|
- lib/chef/knife/cookbook_site_search.rb
|
324
325
|
- lib/chef/knife/cookbook_site_share.rb
|
325
326
|
- lib/chef/knife/cookbook_site_show.rb
|
326
327
|
- lib/chef/knife/cookbook_site_unshare.rb
|
327
|
-
- lib/chef/knife/cookbook_site_vendor.rb
|
328
328
|
- lib/chef/knife/cookbook_test.rb
|
329
329
|
- lib/chef/knife/cookbook_upload.rb
|
330
330
|
- lib/chef/knife/data_bag_create.rb
|
@@ -1,142 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Author:: Adam Jacob (<adam@opscode.com>)
|
3
|
-
# Copyright:: Copyright (c) 2010 Opscode, Inc.
|
4
|
-
# License:: Apache License, Version 2.0
|
5
|
-
#
|
6
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
-
# you may not use this file except in compliance with the License.
|
8
|
-
# You may obtain a copy of the License at
|
9
|
-
#
|
10
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
-
#
|
12
|
-
# Unless required by applicable law or agreed to in writing, software
|
13
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
-
# See the License for the specific language governing permissions and
|
16
|
-
# limitations under the License.
|
17
|
-
#
|
18
|
-
|
19
|
-
require 'chef/knife'
|
20
|
-
|
21
|
-
class Chef
|
22
|
-
class Knife
|
23
|
-
class CookbookSiteVendor < Knife
|
24
|
-
|
25
|
-
deps do
|
26
|
-
require 'chef/cookbook/metadata'
|
27
|
-
end
|
28
|
-
|
29
|
-
banner "knife cookbook site vendor COOKBOOK [VERSION] (options)"
|
30
|
-
category "cookbook site"
|
31
|
-
|
32
|
-
option :deps,
|
33
|
-
:short => "-d",
|
34
|
-
:long => "--dependencies",
|
35
|
-
:boolean => true,
|
36
|
-
:description => "Grab dependencies automatically"
|
37
|
-
|
38
|
-
option :cookbook_path,
|
39
|
-
:short => "-o PATH:PATH",
|
40
|
-
:long => "--cookbook-path PATH:PATH",
|
41
|
-
:description => "A colon-separated path to look for cookbooks in",
|
42
|
-
:proc => lambda { |o| o.split(":") }
|
43
|
-
|
44
|
-
option :branch_default,
|
45
|
-
:short => "-B BRANCH",
|
46
|
-
:long => "--branch BRANCH",
|
47
|
-
:description => "Default branch to work with",
|
48
|
-
:default => "master"
|
49
|
-
|
50
|
-
def run
|
51
|
-
if config[:cookbook_path]
|
52
|
-
Chef::Config[:cookbook_path] = config[:cookbook_path]
|
53
|
-
else
|
54
|
-
config[:cookbook_path] = Chef::Config[:cookbook_path]
|
55
|
-
end
|
56
|
-
|
57
|
-
# Check to ensure we have a valid source of cookbooks before continuing
|
58
|
-
unless File.directory?(config[:cookbook_path].first)
|
59
|
-
ui.error( File.join(config[:cookbook_path].first, " doesn't exist!. Make sure you have cookbook_path configured correctly"))
|
60
|
-
exit 1
|
61
|
-
end
|
62
|
-
|
63
|
-
vendor_path = File.expand_path(File.join(config[:cookbook_path].first))
|
64
|
-
cookbook_path = File.join(vendor_path, name_args[0])
|
65
|
-
upstream_file = File.join(vendor_path, "#{name_args[0]}.tar.gz")
|
66
|
-
branch_name = "chef-vendor-#{name_args[0]}"
|
67
|
-
|
68
|
-
download = Chef::Knife::CookbookSiteDownload.new
|
69
|
-
download.config[:file] = upstream_file
|
70
|
-
download.name_args = name_args
|
71
|
-
download.run
|
72
|
-
|
73
|
-
ui.info("Checking out the #{config[:branch_default]} branch.")
|
74
|
-
Chef::Mixin::Command.run_command(:command => "git checkout #{config[:branch_default]}", :cwd => vendor_path)
|
75
|
-
ui.info("Checking the status of the vendor branch.")
|
76
|
-
status, branch_output, branch_error = Chef::Mixin::Command.output_of_command("git branch --no-color | grep #{branch_name}", :cwd => vendor_path)
|
77
|
-
if branch_output =~ /#{Regexp.escape(branch_name)}$/m
|
78
|
-
ui.info("Vendor branch found.")
|
79
|
-
Chef::Mixin::Command.run_command(:command => "git checkout #{branch_name}", :cwd => vendor_path)
|
80
|
-
else
|
81
|
-
ui.info("Creating vendor branch.")
|
82
|
-
Chef::Mixin::Command.run_command(:command => "git checkout -b #{branch_name}", :cwd => vendor_path)
|
83
|
-
end
|
84
|
-
ui.info("Removing pre-existing version.")
|
85
|
-
Chef::Mixin::Command.run_command(:command => "rm -r #{cookbook_path}", :cwd => vendor_path) if File.directory?(cookbook_path)
|
86
|
-
ui.info("Uncompressing #{name_args[0]} version #{download.version}.")
|
87
|
-
Chef::Mixin::Command.run_command(:command => "tar zxvf #{upstream_file}", :cwd => vendor_path)
|
88
|
-
Chef::Mixin::Command.run_command(:command => "rm #{upstream_file}", :cwd => vendor_path)
|
89
|
-
ui.info("Adding changes.")
|
90
|
-
Chef::Mixin::Command.run_command(:command => "git add #{name_args[0]}", :cwd => vendor_path)
|
91
|
-
|
92
|
-
ui.info("Committing changes.")
|
93
|
-
changes = true
|
94
|
-
begin
|
95
|
-
Chef::Mixin::Command.run_command(:command => "git commit -a -m 'Import #{name_args[0]} version #{download.version}'", :cwd => vendor_path)
|
96
|
-
rescue Chef::Exceptions::Exec => e
|
97
|
-
ui.warn("Checking out the #{config[:branch_default]} branch.")
|
98
|
-
ui.warn("No changes from current vendor #{name_args[0]}")
|
99
|
-
Chef::Mixin::Command.run_command(:command => "git checkout #{config[:branch_default]}", :cwd => vendor_path)
|
100
|
-
changes = false
|
101
|
-
end
|
102
|
-
|
103
|
-
if changes
|
104
|
-
ui.info("Creating tag chef-vendor-#{name_args[0]}-#{download.version}.")
|
105
|
-
Chef::Mixin::Command.run_command(:command => "git tag -f chef-vendor-#{name_args[0]}-#{download.version}", :cwd => vendor_path)
|
106
|
-
ui.info("Checking out the #{config[:branch_default]} branch.")
|
107
|
-
Chef::Mixin::Command.run_command(:command => "git checkout #{config[:branch_default]}", :cwd => vendor_path)
|
108
|
-
ui.info("Merging changes from #{name_args[0]} version #{download.version}.")
|
109
|
-
|
110
|
-
Dir.chdir(vendor_path) do
|
111
|
-
if system("git merge #{branch_name}")
|
112
|
-
ui.info("Cookbook #{name_args[0]} version #{download.version} successfully vendored!")
|
113
|
-
else
|
114
|
-
ui.error("You have merge conflicts - please resolve manually!")
|
115
|
-
ui.error("(Hint: cd #{vendor_path}; git status)")
|
116
|
-
exit 1
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
if config[:deps]
|
122
|
-
md = Chef::Cookbook::Metadata.new
|
123
|
-
md.from_file(File.join(cookbook_path, "metadata.rb"))
|
124
|
-
md.dependencies.each do |cookbook, version_list|
|
125
|
-
# Doesn't do versions.. yet
|
126
|
-
nv = Chef::Knife::CookbookSiteVendor.new
|
127
|
-
nv.config = config
|
128
|
-
nv.name_args = [ cookbook ]
|
129
|
-
nv.run
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|