knife_cookbook_dependencies 0.0.3 → 0.0.5
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.
- data/.gitignore +4 -1
- data/README.rdoc +41 -2
- data/Rakefile +42 -0
- data/features/lib/chef/knife/error_messages.feature +16 -0
- data/features/lib/chef/knife/lockfile.feature +25 -0
- data/features/lib/chef/knife/without.feature +27 -0
- data/features/support/env.rb +30 -0
- data/features/support/step_definitions.rb +22 -0
- data/knife_cookbook_dependencies.gemspec +6 -2
- data/lib/chef/knife/cookbook_dependencies_install.rb +12 -6
- data/lib/kcd.rb +1 -0
- data/lib/{knife_cookbook_dependencies → kcd}/cookbook.rb +72 -40
- data/lib/{knife_cookbook_dependencies → kcd}/cookbookfile.rb +12 -11
- data/lib/kcd/dsl.rb +13 -0
- data/lib/{knife_cookbook_dependencies → kcd}/error_messages.rb +1 -1
- data/lib/{knife_cookbook_dependencies → kcd}/git.rb +0 -0
- data/lib/{knife_cookbook_dependencies → kcd}/knife_utils.rb +1 -1
- data/lib/{knife_cookbook_dependencies → kcd}/lockfile.rb +8 -5
- data/lib/{knife_cookbook_dependencies → kcd}/metacookbook.rb +1 -1
- data/lib/{knife_cookbook_dependencies → kcd}/shelf.rb +30 -5
- data/lib/{knife_cookbook_dependencies → kcd}/version.rb +1 -1
- data/lib/knife_cookbook_dependencies.rb +20 -13
- data/spec/acceptance/knife_cookbook_dependencies_spec.rb +1 -11
- data/spec/fixtures/lockfile_spec/with_lock/Cookbookfile +1 -0
- data/spec/fixtures/lockfile_spec/without_lock/Cookbookfile.lock +5 -0
- data/spec/lib/{knife_cookbook_dependencies → kcd}/cookbook_spec.rb +43 -14
- data/spec/lib/{knife_cookbook_dependencies → kcd}/cookbookfile_spec.rb +3 -3
- data/spec/lib/kcd/dsl_spec.rb +56 -0
- data/spec/lib/{knife_cookbook_dependencies → kcd}/git_spec.rb +0 -0
- data/spec/lib/kcd/lockfile_spec.rb +54 -0
- data/spec/lib/kcd/shelf_spec.rb +81 -0
- data/spec/spec_helper.rb +22 -2
- data/todo.txt +8 -8
- metadata +98 -51
- data/lib/knife_cookbook_dependencies/dependency_reader.rb +0 -46
- data/lib/knife_cookbook_dependencies/dsl.rb +0 -7
- data/spec/lib/knife_cookbook_dependencies/dependency_reader_spec.rb +0 -42
- data/spec/lib/knife_cookbook_dependencies/dsl_spec.rb +0 -29
- data/spec/lib/knife_cookbook_dependencies/shelf_spec.rb +0 -37
@@ -1,37 +1,38 @@
|
|
1
|
-
require 'knife_cookbook_dependencies/dsl'
|
2
|
-
|
3
1
|
module KnifeCookbookDependencies
|
4
2
|
class Cookbookfile
|
5
3
|
class << self
|
6
4
|
include DSL
|
7
|
-
|
5
|
+
|
6
|
+
def read(content)
|
8
7
|
# This will populate KnifeCookbookDependencies.shelf. TODO: consider making this
|
9
8
|
# build and return the shelf rather than building the shelf as
|
10
9
|
# a side effect.
|
11
10
|
instance_eval(content)
|
12
11
|
end
|
13
12
|
|
14
|
-
def process_install
|
13
|
+
def process_install(without=nil)
|
15
14
|
# TODO: friendly error message when the file doesn't exist
|
16
15
|
|
17
|
-
filename =
|
16
|
+
filename = KCD::DEFAULT_FILENAME + ".lock"
|
18
17
|
lockfile = false
|
19
18
|
|
20
19
|
if File.exist?(filename)
|
21
20
|
lockfile = true
|
22
21
|
else
|
23
|
-
filename =
|
22
|
+
filename = KCD::DEFAULT_FILENAME unless File.exist?(filename)
|
24
23
|
end
|
25
24
|
|
26
25
|
begin
|
27
|
-
read File.
|
26
|
+
read File.read(filename)
|
28
27
|
rescue Errno::ENOENT => e
|
29
|
-
|
28
|
+
KCD.ui.fatal ErrorMessages.missing_cookbookfile
|
30
29
|
exit 100
|
31
30
|
end
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
|
32
|
+
KCD.shelf.exclude(without)
|
33
|
+
KCD.shelf.resolve_dependencies
|
34
|
+
KCD.shelf.populate_cookbooks_directory
|
35
|
+
KCD.shelf.write_lockfile unless lockfile
|
35
36
|
end
|
36
37
|
end
|
37
38
|
end
|
data/lib/kcd/dsl.rb
ADDED
@@ -1,7 +1,7 @@
|
|
1
1
|
module KnifeCookbookDependencies
|
2
2
|
module ErrorMessages
|
3
3
|
class << self
|
4
|
-
def missing_cookbook
|
4
|
+
def missing_cookbook(name)
|
5
5
|
"The cookbook #{name} was not found on the Opscode Community site. Provide a git or path key for #{name} if it is unpublished."
|
6
6
|
end
|
7
7
|
|
File without changes
|
@@ -4,7 +4,7 @@ require 'chef/config'
|
|
4
4
|
module KnifeCookbookDependencies
|
5
5
|
module KnifeUtils
|
6
6
|
def self.capture_knife_output(knife_obj)
|
7
|
-
knife_obj.ui = Chef::Knife::UI.new(StringIO.new, StringIO.new, StringIO.new,
|
7
|
+
knife_obj.ui = Chef::Knife::UI.new(StringIO.new, StringIO.new, StringIO.new, :format => :json)
|
8
8
|
knife_obj.run
|
9
9
|
knife_obj.ui.stdout.rewind
|
10
10
|
knife_obj.ui.stdout.read
|
@@ -1,12 +1,10 @@
|
|
1
|
-
require 'knife_cookbook_dependencies/cookbookfile'
|
2
|
-
|
3
1
|
module KnifeCookbookDependencies
|
4
2
|
class Lockfile
|
5
3
|
def initialize(cookbooks)
|
6
4
|
@cookbooks = cookbooks
|
7
5
|
end
|
8
6
|
|
9
|
-
def write(filename =
|
7
|
+
def write(filename = KCD::DEFAULT_FILENAME)
|
10
8
|
content = @cookbooks.map do |cookbook|
|
11
9
|
get_cookbook_definition(cookbook)
|
12
10
|
end.join("\n")
|
@@ -14,9 +12,14 @@ module KnifeCookbookDependencies
|
|
14
12
|
end
|
15
13
|
|
16
14
|
def get_cookbook_definition(cookbook)
|
17
|
-
definition = "cookbook '#{cookbook.name}'
|
18
|
-
|
15
|
+
definition = "cookbook '#{cookbook.name}'"
|
16
|
+
|
17
|
+
if cookbook.from_git?
|
19
18
|
definition += ", :git => '#{cookbook.git_repo}', :ref => '#{cookbook.git_ref || 'HEAD'}'"
|
19
|
+
elsif cookbook.from_path?
|
20
|
+
definition += ", :path => '#{cookbook.local_path}'"
|
21
|
+
else
|
22
|
+
definition += ", :locked_version => '#{cookbook.locked_version}'"
|
20
23
|
end
|
21
24
|
|
22
25
|
return definition
|
@@ -1,10 +1,8 @@
|
|
1
|
-
require 'knife_cookbook_dependencies/lockfile'
|
2
|
-
|
3
1
|
module KnifeCookbookDependencies
|
4
2
|
class Shelf
|
5
3
|
META_COOKBOOK_NAME = 'cookbook_dependencies_shelf'
|
6
4
|
|
7
|
-
attr_accessor :cookbooks
|
5
|
+
attr_accessor :cookbooks, :active_group, :excluded_groups
|
8
6
|
|
9
7
|
def initialize
|
10
8
|
@cookbooks = []
|
@@ -17,8 +15,10 @@ module KnifeCookbookDependencies
|
|
17
15
|
def resolve_dependencies
|
18
16
|
graph = DepSelector::DependencyGraph.new
|
19
17
|
|
18
|
+
post_exclusions = requested_cookbooks
|
19
|
+
cookbooks_to_install = @cookbooks.select {|c| post_exclusions.include?(c.name)}
|
20
20
|
# all cookbooks in the Cookbookfile are dependencies of the shelf
|
21
|
-
shelf = MetaCookbook.new(META_COOKBOOK_NAME,
|
21
|
+
shelf = MetaCookbook.new(META_COOKBOOK_NAME, cookbooks_to_install)
|
22
22
|
|
23
23
|
self.class.populate_graph graph, shelf
|
24
24
|
|
@@ -29,7 +29,7 @@ module KnifeCookbookDependencies
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def write_lockfile
|
32
|
-
|
32
|
+
KCD::Lockfile.new(@cookbooks).write
|
33
33
|
end
|
34
34
|
|
35
35
|
def get_cookbook(name)
|
@@ -50,6 +50,31 @@ module KnifeCookbookDependencies
|
|
50
50
|
@cookbooks = @cookbooks.uniq.reject { |x| x.locked_version.nil? }
|
51
51
|
end
|
52
52
|
|
53
|
+
def exclude(groups)
|
54
|
+
groups = groups.to_s.split(/[,:]/) unless groups.is_a?(Array)
|
55
|
+
@excluded_groups = groups.collect {|c| c.to_sym}
|
56
|
+
end
|
57
|
+
|
58
|
+
def cookbook_groups
|
59
|
+
{}.tap do |groups|
|
60
|
+
@cookbooks.each do |cookbook|
|
61
|
+
cookbook.groups.each do |group|
|
62
|
+
groups[group] ||= []
|
63
|
+
groups[group] << cookbook.name
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def requested_cookbooks
|
70
|
+
return @cookbooks.collect(&:name) unless @excluded_groups
|
71
|
+
[].tap do |r|
|
72
|
+
cookbook_groups.each do |group, cookbooks|
|
73
|
+
r << cookbooks unless @excluded_groups.include?(group.to_sym)
|
74
|
+
end
|
75
|
+
end.flatten.uniq
|
76
|
+
end
|
77
|
+
|
53
78
|
class << self
|
54
79
|
def populate_graph(graph, cookbook)
|
55
80
|
package = graph.package cookbook.name
|
@@ -1,28 +1,32 @@
|
|
1
1
|
require 'dep_selector'
|
2
2
|
require 'zlib'
|
3
3
|
require 'archive/tar/minitar'
|
4
|
-
|
5
|
-
require '
|
6
|
-
|
7
|
-
require '
|
8
|
-
require '
|
9
|
-
require '
|
10
|
-
require '
|
11
|
-
require '
|
12
|
-
require '
|
13
|
-
require '
|
14
|
-
require 'knife_cookbook_dependencies/git'
|
15
|
-
require 'knife_cookbook_dependencies/error_messages'
|
4
|
+
|
5
|
+
require 'kcd/version'
|
6
|
+
require 'kcd/shelf'
|
7
|
+
require 'kcd/cookbook'
|
8
|
+
require 'kcd/metacookbook'
|
9
|
+
require 'kcd/dsl'
|
10
|
+
require 'kcd/cookbookfile'
|
11
|
+
require 'kcd/lockfile'
|
12
|
+
require 'kcd/git'
|
13
|
+
require 'kcd/error_messages'
|
16
14
|
|
17
15
|
module KnifeCookbookDependencies
|
18
16
|
DEFAULT_FILENAME = 'Cookbookfile'
|
19
17
|
COOKBOOKS_DIRECTORY = 'cookbooks'
|
20
18
|
|
19
|
+
autoload :KnifeUtils, 'kcd/knife_utils'
|
20
|
+
|
21
21
|
class << self
|
22
22
|
attr_accessor :ui
|
23
23
|
|
24
|
+
def root
|
25
|
+
File.join(File.dirname(__FILE__), '..')
|
26
|
+
end
|
27
|
+
|
24
28
|
def shelf
|
25
|
-
@shelf ||=
|
29
|
+
@shelf ||= KCD::Shelf.new
|
26
30
|
end
|
27
31
|
|
28
32
|
def clear_shelf!
|
@@ -39,3 +43,6 @@ module KnifeCookbookDependencies
|
|
39
43
|
end
|
40
44
|
end
|
41
45
|
end
|
46
|
+
|
47
|
+
# Alias for {KnifeCookbookDependencies}
|
48
|
+
KCD = KnifeCookbookDependencies
|
@@ -7,16 +7,6 @@ describe "knife cookbook dependencies install" do
|
|
7
7
|
describe "should print a friendly error message" do
|
8
8
|
include Aruba::Api
|
9
9
|
|
10
|
-
it "for
|
11
|
-
pending "Knife commands produce no output when run with aruba. I'm not sure why." # TODO FIXME
|
12
|
-
|
13
|
-
cookbook_name = 'thisisamissingcookbook'
|
14
|
-
with_cookbookfile %Q[cookbook "#{cookbook_name}"] do
|
15
|
-
cmd = 'cat nofile' #'knife cookbook dependencies install'
|
16
|
-
process = run(cmd)
|
17
|
-
process.output(true).should match(/#{KnifeCookbookDependencies::ErrorMessages.missing_cookbook(cookbook_name)}/)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
it "for missing Cookbookfile"
|
10
|
+
it "for --without option"
|
21
11
|
end
|
22
12
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
cookbook 'nginx', '= 0.101.0'
|
@@ -15,7 +15,7 @@ module KnifeCookbookDependencies
|
|
15
15
|
|
16
16
|
# FIXME: This test is flakey
|
17
17
|
it "should raise an error if the cookbook is unpacked without being downloaded first" do
|
18
|
-
-> { subject.unpack(subject.unpacked_cookbook_path, true, false) }.should raise_error
|
18
|
+
-> { subject.unpack(subject.unpacked_cookbook_path, :clean => true, :download => false) }.should raise_error
|
19
19
|
end
|
20
20
|
|
21
21
|
describe '#unpacked_cookbook_path' do
|
@@ -36,7 +36,7 @@ module KnifeCookbookDependencies
|
|
36
36
|
describe "#copy_to" do
|
37
37
|
it "should copy from the unpacked cookbook directory to the target" do
|
38
38
|
example_cookbook_from_path.copy_to_cookbooks_directory
|
39
|
-
File.exists?(File.join(
|
39
|
+
File.exists?(File.join(KCD::COOKBOOKS_DIRECTORY, example_cookbook_from_path.name)).should be_true
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
@@ -47,17 +47,9 @@ module KnifeCookbookDependencies
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
-
describe '#
|
51
|
-
it "should
|
52
|
-
|
53
|
-
|
54
|
-
subject.version_from_metadata_file.should == DepSelector::Version.new('1.2.3')
|
55
|
-
end
|
56
|
-
|
57
|
-
it "should be able to handle double quoted strings" do
|
58
|
-
Cookbook.any_instance.stub(:metadata_file).and_return(%Q{version "1.2.3"})
|
59
|
-
|
60
|
-
subject.version_from_metadata_file.should == DepSelector::Version.new('1.2.3')
|
50
|
+
describe '#version_from_metadata' do
|
51
|
+
it "should return the correct version" do
|
52
|
+
subject.version_from_metadata.should == DepSelector::Version.new('1.1.8')
|
61
53
|
end
|
62
54
|
end
|
63
55
|
|
@@ -90,7 +82,14 @@ module KnifeCookbookDependencies
|
|
90
82
|
describe '#dependencies' do
|
91
83
|
it "should not contain the cookbook itself" do
|
92
84
|
# TODO: Mock
|
93
|
-
Cookbook.new('
|
85
|
+
Cookbook.new('nginx').dependencies.collect(&:name).include?('nginx').should_not be_true
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should compute the correct dependencies" do
|
89
|
+
cookbook = Cookbook.new('mysql')
|
90
|
+
cookbook.dependencies.should == [Cookbook.new('openssl')]
|
91
|
+
# Second computation is intentional, to make sure it doesn't change the dependency list.
|
92
|
+
cookbook.dependencies.should == [Cookbook.new('openssl')]
|
94
93
|
end
|
95
94
|
end
|
96
95
|
|
@@ -102,5 +101,35 @@ module KnifeCookbookDependencies
|
|
102
101
|
# subject.unpack
|
103
102
|
# end
|
104
103
|
# end
|
104
|
+
|
105
|
+
describe '#groups' do
|
106
|
+
it "should have the default group" do
|
107
|
+
subject.groups.should == [:default]
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe '#add_group' do
|
112
|
+
it "should store strings as symbols" do
|
113
|
+
subject.add_group "foo"
|
114
|
+
subject.groups.should == [:default, :foo]
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should not store duplicate groups" do
|
118
|
+
subject.add_group "bar"
|
119
|
+
subject.add_group "bar"
|
120
|
+
subject.add_group :bar
|
121
|
+
subject.groups.should == [:default, :bar]
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should add multiple groups" do
|
125
|
+
subject.add_group "baz", "quux"
|
126
|
+
subject.groups.should == [:default, :baz, :quux]
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should handle multiple groups as an array" do
|
130
|
+
subject.add_group ["baz", "quux"]
|
131
|
+
subject.groups.should == [:default, :baz, :quux]
|
132
|
+
end
|
133
|
+
end
|
105
134
|
end
|
106
135
|
end
|
@@ -4,7 +4,7 @@ module KnifeCookbookDependencies
|
|
4
4
|
describe Cookbookfile do
|
5
5
|
describe '::read' do
|
6
6
|
after do
|
7
|
-
|
7
|
+
KCD.shelf.cookbooks.each(&:clean)
|
8
8
|
end
|
9
9
|
|
10
10
|
it "should read the cookbookfile and build a dependency list" do
|
@@ -16,10 +16,10 @@ cookbook 'ssh_known_hosts2', :git => 'https://github.com/erikh/chef-ssh_known_ho
|
|
16
16
|
COOKBOOKFILE
|
17
17
|
|
18
18
|
['ntp', 'mysql', 'nginx', 'ssh_known_hosts2'].each do |dep|
|
19
|
-
|
19
|
+
KCD.shelf.cookbooks.collect(&:name).should include dep
|
20
20
|
end
|
21
21
|
|
22
|
-
|
22
|
+
KCD.shelf.populate_cookbooks_directory
|
23
23
|
end
|
24
24
|
end
|
25
25
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'kcd/dsl'
|
3
|
+
|
4
|
+
module KnifeCookbookDependencies
|
5
|
+
describe DSL do
|
6
|
+
include DSL
|
7
|
+
|
8
|
+
describe "#cookbook" do
|
9
|
+
after do
|
10
|
+
KnifeCookbookDependencies.shelf.cookbooks.each(&:clean)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should add the cookbooks to the shelf' do
|
14
|
+
cookbook "ntp"
|
15
|
+
cookbook "nginx"
|
16
|
+
|
17
|
+
['ntp', 'nginx'].each do |cookbook|
|
18
|
+
KnifeCookbookDependencies.shelf.cookbooks.collect(&:name).should include cookbook
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should take version constraints' do
|
23
|
+
Cookbook.any_instance.stub(:clean)
|
24
|
+
cookbook 'ntp', '= 1.2.3'
|
25
|
+
KnifeCookbookDependencies.shelf.cookbooks.select {|c| c.name == 'ntp'}.first.version_constraints.first.should == DepSelector::VersionConstraint.new('= 1.2.3')
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should take group' do
|
29
|
+
cookbook 'nginx', :group => 'web'
|
30
|
+
KnifeCookbookDependencies.shelf.cookbooks.select {|c| c.name == 'nginx'}.first.groups.should == [:web]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#group' do
|
35
|
+
it "should set the group on all cookbooks" do
|
36
|
+
cookbooks = %w[hashbrowns mashed_potatoes bourbon]
|
37
|
+
group "awesome" do
|
38
|
+
cookbooks.each {|c| cookbook c}
|
39
|
+
end
|
40
|
+
cookbooks.each do |c|
|
41
|
+
KnifeCookbookDependencies.shelf.cookbooks.select {|n| n.name == c}.first.groups.should == [:awesome]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should not set the group on cookbooks after the group" do
|
46
|
+
cookbooks = %w[apple orange strawberry]
|
47
|
+
group "fruit" do
|
48
|
+
cookbooks.each {|c| cookbook c}
|
49
|
+
end
|
50
|
+
cookbook 'sesame_chicken'
|
51
|
+
KnifeCookbookDependencies.shelf.cookbooks.select {|n| n.name == 'sesame_chicken'}.first.groups.should == [:default]
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|