soloist 0.9.7 → 1.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,80 +0,0 @@
1
- require 'yaml'
2
-
3
- module Soloist
4
- class Soloist::ChefConfigGenerator
5
- include Soloist::Util
6
-
7
- def initialize(config, relative_path_to_soloistrc)
8
- @recipes = []
9
- @cookbook_paths = []
10
- @cookbook_gems = []
11
- @preserved_environment_variables = %w{PATH BUNDLE_PATH GEM_HOME GEM_PATH RAILS_ENV RACK_ENV}
12
- @node_attributes = config['node_attributes'] || {}
13
- merge_config(config, relative_path_to_soloistrc)
14
- end
15
-
16
- attr_reader :preserved_environment_variables, :cookbook_paths, :cookbook_gems
17
- attr_accessor :recipes
18
-
19
- def support_old_format(hash)
20
- hash['recipes'] ||= hash.delete('Recipes')
21
- hash['cookbook_paths'] ||= hash.delete('Cookbook_Paths')
22
- hash
23
- end
24
-
25
- def append_path(paths, relative_path_to_soloistrc)
26
- paths.map do |path|
27
- path.slice(0,1) == '/' ? path : "#{FileUtils.pwd}/#{relative_path_to_soloistrc}/#{path}"
28
- end
29
- end
30
-
31
- def merge_config(sub_hash, relative_path_to_soloistrc)
32
- sub_hash = support_old_format(sub_hash)
33
- if sub_hash["recipes"]
34
- @recipes = (@recipes + sub_hash["recipes"]).uniq
35
- end
36
- if sub_hash["cookbook_paths"]
37
- @cookbook_paths = (@cookbook_paths + append_path(sub_hash["cookbook_paths"], relative_path_to_soloistrc)).uniq
38
- end
39
- if sub_hash["cookbook_gems"]
40
- (@cookbook_gems += sub_hash["cookbook_gems"]).uniq!
41
- end
42
- if sub_hash["env_variable_switches"]
43
- merge_env_variable_switches(sub_hash["env_variable_switches"], relative_path_to_soloistrc)
44
- end
45
- end
46
-
47
- def merge_env_variable_switches(hash_to_merge, relative_path_to_soloistrc)
48
- hash_to_merge.keys.each do |variable|
49
- @preserved_environment_variables << variable
50
- ENV[variable] && ENV[variable].split(',').each do |env_variable_value|
51
- sub_hash = hash_to_merge[variable] && hash_to_merge[variable][env_variable_value]
52
- merge_config(sub_hash, relative_path_to_soloistrc) if sub_hash
53
- end
54
- end
55
- end
56
-
57
- def solo_rb
58
- linker = CookbookGemLinker.new(cookbook_gems)
59
- linker.link_gem_cookbooks
60
- "cookbook_path #{(cookbook_paths+[linker.cookbook_gem_temp_dir]).inspect}"
61
- end
62
-
63
- def json_hash
64
- {
65
- "recipes" => @recipes
66
- }.merge(@node_attributes)
67
- end
68
-
69
- def json_file
70
- json_hash.to_json
71
- end
72
-
73
- def preserved_environment_variables_string
74
- variable_array = []
75
- preserved_environment_variables.map do |env_variable|
76
- "#{env_variable}=#{ENV[env_variable]}" unless ENV[env_variable].nil?
77
- end.compact.join(" ")
78
- end
79
- end
80
- end
@@ -1,54 +0,0 @@
1
- class CookbookGemLinker
2
- include Soloist::Util
3
- attr_reader :gems_and_dependencies
4
- def initialize(gems=[])
5
- @gems = gems
6
- end
7
-
8
- def link_gem_cookbooks
9
- gems_and_dependencies.each do |gem_cookbook|
10
- link_cookbook(gem_cookbook)
11
- end
12
- end
13
-
14
- def gems_and_dependencies
15
- unless @gems_and_dependencies
16
- @gems_and_dependencies = Set.new
17
- calculate_gems_and_dependencies
18
- end
19
- @gems_and_dependencies
20
- end
21
-
22
- def cookbook_gem_temp_dir
23
- @cookbook_gem_temp_dir ||= Dir.mktmpdir
24
- end
25
-
26
- def path_to(gem_name)
27
- require gem_name
28
- path = Kernel.const_get(camelize(gem_name)).const_get('COOKBOOK_PATH')
29
- end
30
-
31
- def link_cookbook(gem_name)
32
- File.symlink(path_to(gem_name), File.join(cookbook_gem_temp_dir, gem_name.chomp("_cookbook")))
33
- end
34
-
35
- private
36
-
37
- def dependencies_of(gem_name)
38
- if Gem::Specification.respond_to?(:find_by_name)
39
- Gem::Specification.find_by_name(gem_name)
40
- else
41
- Gem.searcher.find(gem_name)
42
- end.dependencies.map(&:name)
43
- end
44
-
45
- def calculate_gems_and_dependencies(gems=@gems)
46
- gems.each do |gem_cookbook|
47
- @gems_and_dependencies.add(gem_cookbook)
48
- dependencies_of(gem_cookbook).each do |dependency|
49
- @gems_and_dependencies.add(dependency)
50
- calculate_gems_and_dependencies([dependency])
51
- end
52
- end
53
- end
54
- end
data/lib/soloist/util.rb DELETED
@@ -1,42 +0,0 @@
1
- module Soloist
2
- module Util
3
- def with_or_without_dot(file_name)
4
- [file_name, ".#{file_name}"]
5
- end
6
-
7
- def fileify(contents)
8
- file = Tempfile.new("soloist")
9
- puts "==== Temp File Contents ====\n#{contents}" if ENV['LOG_LEVEL'] == 'debug'
10
- file << contents
11
- file.flush
12
- file
13
- end
14
-
15
- def walk_up_and_find_file(filenames, opts={})
16
- pwd = FileUtils.pwd
17
- file = nil
18
- path_to_file = ""
19
- while !file && FileUtils.pwd != '/'
20
- file = filenames.detect { |f| File.exists?(f) }
21
- FileUtils.cd("..")
22
- path_to_file << "../" unless file
23
- end
24
- FileUtils.cd(pwd)
25
- if file
26
- file_contents = File.read(path_to_file + file) if file
27
- [file_contents, path_to_file]
28
- elsif opts[:required] == false
29
- [nil, nil]
30
- else
31
- raise Errno::ENOENT, "#{filenames.join(" or ")} not found" unless file || opts[:required] == false
32
- end
33
- end
34
-
35
- # stolen from activesupport
36
- def camelize(term)
37
- string = term.to_s
38
- string = string.sub(/^[a-z\d]*/) { $&.capitalize }
39
- string.gsub(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }.gsub('/', '::')
40
- end
41
- end
42
- end
@@ -1,252 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Soloist::ChefConfigGenerator do
4
- describe "generation" do
5
- before do
6
- @config = <<-CONFIG
7
- Cookbook_Paths:
8
- - ./chef/cookbooks/
9
- cookbook_gems:
10
- - pivotal_workstation_cookbook
11
- Recipes:
12
- - pivotal_workstation::ack
13
- CONFIG
14
- @config = YAML.load(@config)
15
- FileUtils.stub(:pwd).and_return("/current/working/directory")
16
- @generator = Soloist::ChefConfigGenerator.new(@config, "../..")
17
- mock_gem("pivotal_workstation_cookbook")
18
- end
19
-
20
- it "appends the current path and relative path to the cookbooks directory" do
21
- @generator.cookbook_paths.should == ["/current/working/directory/../.././chef/cookbooks/"]
22
- end
23
-
24
- it "does not append if an absolute path is given" do
25
- @config['cookbook_paths'] = ["/foo/bar"]
26
- @generator = Soloist::ChefConfigGenerator.new(@config, "../..")
27
- @generator.cookbook_paths.should == ["/foo/bar"]
28
- end
29
-
30
- describe ".solo_rb" do
31
- it "can generate a solo.rb contents" do
32
- @generator.solo_rb.should =~ %r{cookbook_path \["/current/working/directory/../.././chef/cookbooks/"}
33
- end
34
-
35
- it "should include a tempdir with pivotal_workstation in it" do
36
- @generator.solo_rb.match(%r{cookbook_path \[".*", "(.*)"\]})
37
- File.exist?("#{$1}/pivotal_workstation").should be
38
- end
39
- end
40
-
41
- it "can generate the json contents" do
42
- @generator.json_hash.should == {
43
- "recipes" => ['pivotal_workstation::ack']
44
- }
45
- end
46
-
47
- it "can generate json files" do
48
- JSON.parse(@generator.json_file).should == {
49
- "recipes" => ['pivotal_workstation::ack']
50
- }
51
- end
52
-
53
- describe "passing env variables to chef-solo through sudo" do
54
- it "has a list of env variables which are passed through" do
55
- @generator.preserved_environment_variables.should == %w{PATH BUNDLE_PATH GEM_HOME GEM_PATH RAILS_ENV RACK_ENV}
56
- end
57
-
58
- it "can generate an env_variable_string which is passed through sudo to chef-solo" do
59
- ENV["FOO"]="BAR"
60
- ENV["FAZ"]="FUZ"
61
- @generator.stub!(:preserved_environment_variables).and_return(["FOO", "FAZ"])
62
- @generator.preserved_environment_variables_string.should == "FOO=BAR FAZ=FUZ"
63
- end
64
-
65
- it "adds any environment variables that are switched in the config" do
66
- @config = <<-CONFIG
67
- cookbook_paths:
68
- - ./chef/cookbooks/
69
- recipes:
70
- - pivotal_workstation::ack
71
- env_variable_switches:
72
- ME_TOO:
73
- development:
74
- cookbook_paths:
75
- - ./chef/dev_cookbooks/
76
- recipes:
77
- - pivotal_dev::foo
78
- CONFIG
79
- @generator = Soloist::ChefConfigGenerator.new(YAML.load(@config), "")
80
- @generator.preserved_environment_variables.should =~ %w{PATH BUNDLE_PATH GEM_HOME GEM_PATH RAILS_ENV RACK_ENV ME_TOO}
81
- end
82
- end
83
- end
84
-
85
- describe "yaml config values" do
86
- before do
87
- FileUtils.stub(:pwd).and_return("/")
88
- end
89
-
90
- it "accepts Cookbook_Paths, because the CamelSnake is a typo that must be supported" do
91
- @config = "Cookbook_Paths:\n- ./chef/cookbooks/\n"
92
- @generator = Soloist::ChefConfigGenerator.new(YAML.load(@config), "..")
93
- @generator.cookbook_paths.should == ["//.././chef/cookbooks/"]
94
- end
95
-
96
- it "accepts cookbook_paths, because it is sane" do
97
- @config = "cookbook_paths:\n- ./chef/cookbooks/\n"
98
- @generator = Soloist::ChefConfigGenerator.new(YAML.load(@config), "..")
99
- @generator.cookbook_paths.should == ["//.././chef/cookbooks/"]
100
- end
101
-
102
- it "accepts Recipes, because that's the way it was" do
103
- @config = "Recipes:\n- pivotal_workstation::ack"
104
- @generator = Soloist::ChefConfigGenerator.new(YAML.load(@config), "")
105
- @generator.json_hash.should == { "recipes" => ["pivotal_workstation::ack"]}
106
- end
107
-
108
- it "accepts recipes, because it's snake now" do
109
- @config = "recipes:\n- pivotal_workstation::ack"
110
- @generator = Soloist::ChefConfigGenerator.new(YAML.load(@config), "")
111
- @generator.json_hash.should == { "recipes" => ["pivotal_workstation::ack"]}
112
- end
113
-
114
- it "should set node attributes" do
115
- @config = "node_attributes:\n github_username: avh4"
116
- @generator = Soloist::ChefConfigGenerator.new(YAML.load(@config), "")
117
- @generator.json_hash.should == { "recipes" => [], "github_username" => "avh4" }
118
- end
119
- end
120
-
121
- describe "environment variable merging" do
122
- before do
123
- FileUtils.stub(:pwd).and_return("/")
124
- end
125
-
126
- it "merges in if the variable is set to the the value" do
127
- @config = <<-CONFIG
128
- cookbook_paths:
129
- - ./chef/cookbooks/
130
- recipes:
131
- - pivotal_workstation::ack
132
- env_variable_switches:
133
- RACK_ENV:
134
- development:
135
- cookbook_paths:
136
- - ./chef/dev_cookbooks/
137
- recipes:
138
- - pivotal_dev::foo
139
- CONFIG
140
- ENV["RACK_ENV"]="development"
141
- @generator = Soloist::ChefConfigGenerator.new(YAML.load(@config), "../..")
142
- @generator.cookbook_paths.should == [
143
- "//../.././chef/cookbooks/",
144
- "//../.././chef/dev_cookbooks/"
145
- ]
146
- @generator.json_hash["recipes"].should == [
147
- "pivotal_workstation::ack",
148
- "pivotal_dev::foo"
149
- ]
150
- end
151
-
152
- it "merges cookbook_gems" do
153
- @config = <<-CONFIG
154
- cookbook_gems:
155
- - pivotal_shared
156
- env_variable_switches:
157
- RACK_ENV:
158
- development:
159
- cookbook_gems:
160
- - pivotal_shared
161
- - pivotal_workstation
162
- CONFIG
163
- @generator = Soloist::ChefConfigGenerator.new(YAML.load(@config), "../..")
164
- @generator.cookbook_gems.should =~ [
165
- "pivotal_shared",
166
- "pivotal_workstation"
167
- ]
168
- end
169
-
170
- it "splits the value on comma and applies all matching" do
171
- ENV["ROLES"]="application,database"
172
- @config = <<-CONFIG
173
- cookbook_paths:
174
- - ./chef/cookbooks/
175
- recipes:
176
- - pivotal_workstation::ack
177
- env_variable_switches:
178
- ROLES:
179
- application:
180
- cookbook_paths:
181
- - ./chef/app_cookbooks/
182
- recipes:
183
- - pivotal_app::application
184
- database:
185
- cookbook_paths:
186
- - ./chef/db_cookbooks/
187
- recipes:
188
- - pivotal_db::database
189
- CONFIG
190
- @generator = Soloist::ChefConfigGenerator.new(YAML.load(@config), "../..")
191
- @generator.cookbook_paths.should =~ [
192
- "//../.././chef/cookbooks/",
193
- "//../.././chef/app_cookbooks/",
194
- "//../.././chef/db_cookbooks/"
195
- ]
196
- @generator.json_hash["recipes"].should =~ [
197
- "pivotal_workstation::ack",
198
- "pivotal_app::application",
199
- "pivotal_db::database",
200
- ]
201
- end
202
-
203
- it "can deal with empty env switched variables, and passes them through" do
204
- config = <<-CONFIG
205
- env_variable_switches:
206
- RACK_ENV:
207
- CONFIG
208
- @generator = Soloist::ChefConfigGenerator.new(YAML.load(config), "../..")
209
- @generator.preserved_environment_variables.should include("RACK_ENV")
210
- end
211
-
212
-
213
- it "can deal with only having environment switched recipes/cookbooks" do
214
- config = <<-CONFIG
215
- env_variable_switches:
216
- RACK_ENV:
217
- development:
218
- cookbook_paths:
219
- - ./chef/development_cookbooks/
220
- recipes:
221
- - pivotal_development::foo
222
- CONFIG
223
- @generator = Soloist::ChefConfigGenerator.new(YAML.load(config), "../..")
224
- @generator.cookbook_paths.should == [
225
- "//../.././chef/development_cookbooks/"
226
- ]
227
- @generator.json_hash["recipes"].should == [
228
- "pivotal_development::foo"
229
- ]
230
- end
231
- it "can deal with only having empty recipes/cookbooks" do
232
- config = <<-CONFIG
233
- cookbook_paths:
234
- recipes:
235
- env_variable_switches:
236
- RACK_ENV:
237
- development:
238
- cookbook_paths:
239
- - ./chef/development_cookbooks/
240
- recipes:
241
- - pivotal_development::foo
242
- CONFIG
243
- @generator = Soloist::ChefConfigGenerator.new(YAML.load(config), "../..")
244
- @generator.cookbook_paths.should == [
245
- "//../.././chef/development_cookbooks/"
246
- ]
247
- @generator.json_hash["recipes"].should == [
248
- "pivotal_development::foo"
249
- ]
250
- end
251
- end
252
- end
@@ -1,64 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe CookbookGemLinker do
4
- let(:linker) { CookbookGemLinker.new(["pivotal_workstation_cookbook"]) }
5
-
6
- describe ".cookbook_gem_temp_dir" do
7
- it "returns a tmpdir" do
8
- Dir.should_receive(:mktmpdir).once.and_return("/tmp/foo")
9
- 2.times { linker.cookbook_gem_temp_dir.should == "/tmp/foo" }
10
- end
11
- end
12
-
13
- describe ".path_to" do
14
- it "returns the path to the gem" do
15
- linker.path_to("pivotal_workstation_cookbook").should == File.expand_path('../..', __FILE__)
16
- end
17
- end
18
-
19
- describe ".link_cookbook" do
20
- it "creates a symbolic link in the tempdir" do
21
- linker.link_cookbook("pivotal_workstation_cookbook")
22
- File.exist?(File.expand_path('pivotal_workstation', linker.cookbook_gem_temp_dir)).should be
23
- end
24
- end
25
-
26
- describe '.gems_and_dependencies' do
27
- it "returns what you pass in dependencies" do
28
- mock_gem("pivotal_workstation_cookbook")
29
-
30
- linker.gems_and_dependencies.to_a.should == ["pivotal_workstation_cookbook"]
31
- end
32
-
33
- it "gets the dependencies from rubygems" do
34
- mock_gem("pivotal_workstation_cookbook", ['osx_dmg_cookbook'])
35
- mock_gem("osx_dmg_cookbook")
36
-
37
- linker.gems_and_dependencies.to_a.should =~ ["pivotal_workstation_cookbook", 'osx_dmg_cookbook']
38
- end
39
-
40
- it "gets dependencies for dependencies" do
41
- mock_gem("pivotal_workstation_cookbook", ['osx_dmg_cookbook'])
42
- mock_gem("osx_dmg_cookbook", ["osx_installer_thing"])
43
- mock_gem("osx_installer_thing")
44
-
45
- linker.gems_and_dependencies.to_a.should =~ ["pivotal_workstation_cookbook", 'osx_dmg_cookbook', 'osx_installer_thing']
46
- end
47
-
48
- it "works on old rubygems" do
49
- Gem::Specification.stub('respond_to?').with(:find_by_name).and_return(false)
50
- Gem::Specification.should_receive(:find_by_name).exactly(0).times
51
- mock_gem("pivotal_workstation_cookbook")
52
-
53
- linker.gems_and_dependencies.to_a.should == ["pivotal_workstation_cookbook"]
54
- end
55
- end
56
-
57
- describe ".link_gem_cookbooks" do
58
- it "creates a directory of symlinks" do
59
- mock_gem("pivotal_workstation_cookbook")
60
- linker.link_gem_cookbooks
61
- File.exist?(File.expand_path('pivotal_workstation', linker.cookbook_gem_temp_dir)).should be
62
- end
63
- end
64
- end
@@ -1,6 +0,0 @@
1
- # this file is loaded by the tests instead of the actual pivotal_workstation_cookbook
2
-
3
- module PivotalWorkstationCookbook
4
- COOKBOOK_PATH = File.expand_path('../..', __FILE__)
5
- VERSION = "1.0.0"
6
- end
data/spec/util_spec.rb DELETED
@@ -1,19 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Soloist::Util do
4
- class TestClass
5
- extend Soloist::Util
6
- end
7
-
8
- describe "walk_up_and_find_file" do
9
- it "raises an error when the file isn't found" do
10
- lambda do
11
- TestClass.walk_up_and_find_file(["file_not_on_the_filesystem"])
12
- end.should raise_error(Errno::ENOENT, "No such file or directory - file_not_on_the_filesystem not found")
13
- end
14
-
15
- it "doesn't raise an error if :required => false is passed" do
16
- TestClass.walk_up_and_find_file(["file_not_on_the_filesystem"], :required => false).should == [nil, nil]
17
- end
18
- end
19
- end