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.
- data/.rspec +2 -0
- data/.rvmrc +1 -1
- data/.travis.yml +1 -0
- data/Gemfile +0 -4
- data/Gemfile.lock +56 -19
- data/Guardfile +12 -0
- data/README.markdown +107 -113
- data/bin/soloist +3 -25
- data/lib/soloist/cli.rb +83 -0
- data/lib/soloist/config.rb +50 -0
- data/lib/soloist/royal_crown.rb +56 -0
- data/lib/soloist/spotlight.rb +41 -0
- data/lib/soloist/version.rb +1 -1
- data/lib/soloist.rb +2 -11
- data/script/ci.sh +3 -0
- data/soloist.gemspec +15 -5
- data/spec/lib/soloist/cli_spec.rb +133 -0
- data/spec/lib/soloist/config_spec.rb +107 -0
- data/spec/lib/soloist/royal_crown_spec.rb +54 -0
- data/spec/lib/soloist/spotlight_spec.rb +67 -0
- data/spec/spec_helper.rb +5 -8
- metadata +167 -18
- data/Rakefile +0 -10
- data/lib/soloist/chef_config_generator.rb +0 -80
- data/lib/soloist/cookbook_gem_linker.rb +0 -54
- data/lib/soloist/util.rb +0 -42
- data/spec/chef_config_generator_spec.rb +0 -252
- data/spec/cookbook_gem_linker_spec.rb +0 -64
- data/spec/pivotal_workstation_cookbook.rb +0 -6
- data/spec/util_spec.rb +0 -19
data/.rspec
ADDED
data/.rvmrc
CHANGED
@@ -1 +1 @@
|
|
1
|
-
rvm --create ruby-1.9.3-
|
1
|
+
rvm --create use ruby-1.9.3-p286@soloist
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,19 +1,23 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
soloist (0.
|
4
|
+
soloist (1.0.0.pre)
|
5
5
|
chef
|
6
|
+
hashie
|
7
|
+
librarian
|
8
|
+
thor
|
6
9
|
|
7
10
|
GEM
|
8
11
|
remote: http://rubygems.org/
|
9
12
|
specs:
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
+
archive-tar-minitar (0.5.2)
|
14
|
+
bunny (0.7.9)
|
15
|
+
chef (10.16.2)
|
16
|
+
bunny (>= 0.6.0, < 0.8.0)
|
13
17
|
erubis
|
14
18
|
highline (>= 1.6.9)
|
15
19
|
json (>= 1.4.4, <= 1.6.1)
|
16
|
-
mixlib-authentication (>= 1.
|
20
|
+
mixlib-authentication (>= 1.3.0)
|
17
21
|
mixlib-cli (>= 1.1.0)
|
18
22
|
mixlib-config (>= 1.1.2)
|
19
23
|
mixlib-log (>= 1.3.0)
|
@@ -26,11 +30,33 @@ GEM
|
|
26
30
|
treetop (~> 1.4.9)
|
27
31
|
uuidtools
|
28
32
|
yajl-ruby (~> 1.1)
|
29
|
-
|
33
|
+
coderay (1.0.8)
|
34
|
+
diff-lcs (1.1.3)
|
30
35
|
erubis (2.7.0)
|
31
|
-
|
36
|
+
gem-release (0.4.1)
|
37
|
+
guard (1.5.4)
|
38
|
+
listen (>= 0.4.2)
|
39
|
+
lumberjack (>= 1.0.2)
|
40
|
+
pry (>= 0.9.10)
|
41
|
+
thor (>= 0.14.6)
|
42
|
+
guard-bundler (1.0.0)
|
43
|
+
bundler (~> 1.0)
|
44
|
+
guard (~> 1.1)
|
45
|
+
guard-rspec (2.1.1)
|
46
|
+
guard (>= 1.1)
|
47
|
+
rspec (~> 2.11)
|
48
|
+
hashie (1.2.0)
|
49
|
+
highline (1.6.15)
|
32
50
|
ipaddress (0.8.0)
|
33
51
|
json (1.6.1)
|
52
|
+
librarian (0.0.25)
|
53
|
+
archive-tar-minitar (>= 0.5.2)
|
54
|
+
chef (>= 0.10)
|
55
|
+
highline
|
56
|
+
thor (~> 0.15)
|
57
|
+
listen (0.5.3)
|
58
|
+
lumberjack (1.0.2)
|
59
|
+
method_source (0.8.1)
|
34
60
|
mime-types (1.19)
|
35
61
|
mixlib-authentication (1.3.0)
|
36
62
|
mixlib-log
|
@@ -53,19 +79,26 @@ GEM
|
|
53
79
|
systemu
|
54
80
|
yajl-ruby
|
55
81
|
polyglot (0.3.3)
|
56
|
-
|
82
|
+
pry (0.9.10)
|
83
|
+
coderay (~> 1.0.5)
|
84
|
+
method_source (~> 0.8)
|
85
|
+
slop (~> 3.3.1)
|
86
|
+
rb-fsevent (0.9.2)
|
57
87
|
rest-client (1.6.7)
|
58
88
|
mime-types (>= 1.16)
|
59
|
-
rspec (2.
|
60
|
-
rspec-core (~> 2.
|
61
|
-
rspec-expectations (~> 2.
|
62
|
-
rspec-mocks (~> 2.
|
63
|
-
rspec-core (2.
|
64
|
-
rspec-expectations (2.
|
65
|
-
diff-lcs (~> 1.1.
|
66
|
-
rspec-mocks (2.
|
89
|
+
rspec (2.11.0)
|
90
|
+
rspec-core (~> 2.11.0)
|
91
|
+
rspec-expectations (~> 2.11.0)
|
92
|
+
rspec-mocks (~> 2.11.0)
|
93
|
+
rspec-core (2.11.1)
|
94
|
+
rspec-expectations (2.11.3)
|
95
|
+
diff-lcs (~> 1.1.3)
|
96
|
+
rspec-mocks (2.11.3)
|
97
|
+
slop (3.3.3)
|
67
98
|
systemu (2.5.2)
|
68
|
-
|
99
|
+
terminal-notifier-guard (1.5.3)
|
100
|
+
thor (0.16.0)
|
101
|
+
treetop (1.4.12)
|
69
102
|
polyglot
|
70
103
|
polyglot (>= 0.3.1)
|
71
104
|
uuidtools (2.1.3)
|
@@ -75,6 +108,10 @@ PLATFORMS
|
|
75
108
|
ruby
|
76
109
|
|
77
110
|
DEPENDENCIES
|
78
|
-
|
79
|
-
|
111
|
+
gem-release
|
112
|
+
guard-bundler
|
113
|
+
guard-rspec
|
114
|
+
rb-fsevent
|
115
|
+
rspec
|
80
116
|
soloist!
|
117
|
+
terminal-notifier-guard
|
data/Guardfile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
guard 'rspec', cli: '--fail-fast --tag ~@slow:true' do
|
4
|
+
watch(%r{^spec/.+_spec\.rb$})
|
5
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
6
|
+
watch('spec/spec_helper.rb') { "spec" }
|
7
|
+
end
|
8
|
+
|
9
|
+
guard 'bundler' do
|
10
|
+
watch('Gemfile')
|
11
|
+
watch('soloist.gemspec')
|
12
|
+
end
|
data/README.markdown
CHANGED
@@ -1,122 +1,116 @@
|
|
1
|
+
# Soloist
|
2
|
+
|
1
3
|
[![Build Status](https://secure.travis-ci.org/mkocher/soloist.png)](http://travis-ci.org/mkocher/soloist)
|
2
4
|
|
3
|
-
Soloist
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
soloistrc
|
42
|
-
---------
|
43
|
-
cookbook_paths:
|
44
|
-
- ./cookbooks/
|
45
|
-
recipes:
|
46
|
-
- pivotal_workstation::ack
|
47
|
-
- pivotal_workstation::bash_path_order
|
48
|
-
- pivotal_workstation::bash_profile-better_history
|
49
|
-
- pivotal_workstation::defaults_fast_key_repeat_rate
|
50
|
-
- pivotal_workstation::finder_display_full_path
|
51
|
-
- pivotal_workstation::git_config_global_defaults
|
52
|
-
- pivotal_workstation::git_scripts
|
53
|
-
- pivotal_workstation::google_chrome
|
54
|
-
- pivotal_workstation::inputrc
|
55
|
-
- pivotal_workstation::rvm
|
56
|
-
- pivotal_workstation::turn_on_ssh
|
57
|
-
|
58
|
-
Packaging Gems as Cookbooks (alpha)
|
59
|
-
===========================
|
60
|
-
|
61
|
-
If you're a ruby developer, you're probably very comfortable wrangling gems. Bundler makes it easy to lock your dependencies and keep them in sync in all your environments. Soloist adds the ability to load cookbooks out of these gems. This means you can install the pivotal_workstation_cookbook gem, and add it to your soloistrc like so:
|
62
|
-
|
63
|
-
cookbook_gems:
|
64
|
-
- pivotal_workstation_cookbook
|
65
|
-
|
66
|
-
Easy cookbook dependency tracking, no more git cloning, no more chef recipes that aren't yours checked into your project and easy forking with bundler and github.
|
67
|
-
|
68
|
-
Environment Variable Switching
|
69
|
-
==============================
|
70
|
-
The soloistrc file allows for selecting all options based on environment variables. Cap should allow setting environment variables fairly easily on deploy, and they can be set permanently on the machine if desired. To use these, add a env_variable_switches key to your soloistrc. They keys of the hash should be the environment variable you wish to change the configuration based on, and the value should be a hash keyed by the value of the variable. It's easier than it sounds - see the example below.
|
71
|
-
|
72
|
-
cookbook_paths:
|
73
|
-
- ./chef/cookbooks/
|
74
|
-
recipes:
|
75
|
-
- pivotal_workstation::ack
|
76
|
-
env_variable_switches:
|
77
|
-
RACK_ENV:
|
78
|
-
production:
|
79
|
-
cookbook_paths:
|
80
|
-
- ./chef/production_cookbooks/
|
81
|
-
recipes:
|
82
|
-
- production::foo
|
83
|
-
|
84
|
-
The values are merged in, so this results in a cookbook path of
|
85
|
-
[
|
86
|
-
"./chef/cookbooks/",
|
87
|
-
"./chef/production_cookbooks/"
|
88
|
-
]
|
89
|
-
and a recipe list of
|
90
|
-
[
|
91
|
-
"pivotal_workstation::ack",
|
92
|
-
"production::foo"
|
93
|
-
]
|
94
|
-
|
95
|
-
Log Level
|
96
|
-
=========
|
97
|
-
Soloist runs chef at log level info by default. Debug is very verbose, but makes debugging chef recipes much easier. Just set the LOG_LEVEL environment variable to 'debug' (or other valid chef log level) and it will be passed through.
|
98
|
-
|
99
|
-
Local Overrides
|
100
|
-
==============================
|
101
|
-
Soloist is an easy way to share configuration across workstations. If you want to have configuration in chef that you don't want to share with the rest of the project, you can create a soloistrc_local file in addition to the soloistrc file. This file will be processed after the soloistrc, and everything in it will be added to the run list. Be careful that you are clear what goes where - if it's a dependency of the project, it should be checked into the soloistrc file in the project.
|
102
|
-
|
103
|
-
Setting Node Attributes
|
104
|
-
=======================
|
105
|
-
You can set node attributes in your soloistrc file that will be included in the JSON attributes file passed to chef-solo.
|
5
|
+
Soloist lets you quickly and easily converge [Chef](http://opscode.com/chef) recipes using [chef-solo](http://wiki.opscode.com/display/chef/Chef+Solo). It does not require a Chef server, but can exploit [community cookbooks](http://community.opscode.com/cookbooks), github-hosted cookbooks and locally-sourced cookbooks through [Librarian](https://github.com/applicationsonline/librarian).
|
6
|
+
|
7
|
+
Soloist was originally built to support the [Pivotal Labs Workstation Cookbook](https://github.com/pivotal/pivotal_workstation).
|
8
|
+
|
9
|
+
|
10
|
+
Using Soloist
|
11
|
+
-------------
|
12
|
+
|
13
|
+
Let's say you want to converge the Pivotal Labs Workstation default recipe and install Sublime Text 2.
|
14
|
+
|
15
|
+
1. You'll need to have Soloist installed:
|
16
|
+
|
17
|
+
$ gem install soloist
|
18
|
+
|
19
|
+
1. You'll need a `Cheffile` in your home directory that points Librarian to all the cookbooks you've included:
|
20
|
+
|
21
|
+
$ cat /Users/pivotal/Cheffile
|
22
|
+
site "http://community.opscode.com/api/v1"
|
23
|
+
cookbook "pivotal_workstation",
|
24
|
+
:git => "https://github.com/pivotal/pivotal_workstation"
|
25
|
+
|
26
|
+
1. You'll need to create a `soloistrc` file in your home directory to tell Chef which recipes to converge:
|
27
|
+
|
28
|
+
$ cat /Users/pivotal/soloistrc
|
29
|
+
recipes:
|
30
|
+
- pivotal_workstation::default
|
31
|
+
- pivotal_workstation::sublime_text
|
32
|
+
|
33
|
+
1. You'll need to run `soloist` for anything to happen:
|
34
|
+
|
35
|
+
$ soloist
|
36
|
+
|
37
|
+
|
38
|
+
Examples
|
39
|
+
--------
|
40
|
+
|
41
|
+
##### Running a set of recipes
|
42
|
+
|
43
|
+
Here's an example of a `soloistrc`:
|
106
44
|
|
107
45
|
cookbook_paths:
|
108
|
-
|
46
|
+
- /opt/beans
|
109
47
|
recipes:
|
110
|
-
|
111
|
-
|
48
|
+
- beans::chili
|
49
|
+
- beans::food_fight
|
50
|
+
- napkins
|
51
|
+
|
52
|
+
This tells Soloist to search in both `/opt/beans` and `./cookbooks` (relative to the `soloistrc`) for cookbooks to run. Then, it attempts to converge the `beans::chili`, `beans::food_fight` and `napkins` recipes.
|
53
|
+
|
54
|
+
|
55
|
+
##### Setting node attributes
|
56
|
+
|
57
|
+
Soloist lets you override node attributes. Let's say we've got a `bash::prompt` recipe for which we want to set `node['bash']['prompt']['color']='p!nk'`. No problem!
|
58
|
+
|
59
|
+
recipes:
|
60
|
+
- bash::prompt
|
112
61
|
node_attributes:
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
62
|
+
bash:
|
63
|
+
prompt:
|
64
|
+
color: p!nk
|
65
|
+
|
66
|
+
|
67
|
+
##### Conditionally modifying Soloist
|
68
|
+
|
69
|
+
Soloist allows conditionally switching on environment variables. Let's say we only want to include the `embarrassment::parental` recipe when the `MEGA_PRODUCTION` environment variable is set to `juggalos`. Here's the `soloistrc`:
|
70
|
+
|
71
|
+
cookbook_paths:
|
72
|
+
- /fresno
|
73
|
+
recipes:
|
74
|
+
- disaster
|
75
|
+
env_variable_switches:
|
76
|
+
MEGA_PRODUCTION:
|
77
|
+
juggalos:
|
78
|
+
recipes:
|
79
|
+
- embarrassment::parental
|
80
|
+
|
81
|
+
So now, this is the result of our Soloist run:
|
82
|
+
|
83
|
+
$ MEGA_PRODUCTION=juggalos soloist
|
84
|
+
Installing disaster (1.0.0)
|
85
|
+
Installing embarrassment (1.0.0)
|
86
|
+
… chef output …
|
87
|
+
INFO: Run List expands to [disaster, embarrassment::parental, faygo]
|
88
|
+
… chef output …
|
89
|
+
|
90
|
+
If we set `MEGA_PRODUCTION=godspeed`, the `embarrassment::parental` recipe is not converged.
|
91
|
+
|
92
|
+
|
93
|
+
##### Running one-off recipes
|
94
|
+
|
95
|
+
Soloist can also run one-off recipes:
|
96
|
+
|
97
|
+
$ soloist DO_IT_LIVE lice::box
|
98
|
+
Installing lice (1.0.0)
|
99
|
+
… chef output …
|
100
|
+
INFO: Run List expands to [lice::box]
|
101
|
+
… chef output …
|
102
|
+
|
103
|
+
This just runs the `lice::box` recipe from your current set of cookbooks. It still uses all the `node_attributes` and `env_variable_switches` logic.
|
104
|
+
|
105
|
+
|
106
|
+
##### Chef logging
|
107
|
+
|
108
|
+
Soloist runs `chef-solo` at log level `info` by default, which is helpful when you need to see what your Chef run is doing. If you need more information, you can set the `LOG_LEVEL` environment variable:
|
109
|
+
|
110
|
+
$ LOG_LEVEL=debug soloist
|
111
|
+
|
119
112
|
|
120
113
|
License
|
121
114
|
=======
|
122
|
-
|
115
|
+
|
116
|
+
See MIT-LICENSE for details.
|
data/bin/soloist
CHANGED
@@ -1,26 +1,4 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
log_level = ENV['LOG_LEVEL'] || "info"
|
7
|
-
|
8
|
-
soloistrc_contents, soloistrc_path = walk_up_and_find_file(with_or_without_dot("soloistrc"))
|
9
|
-
config_generator = Soloist::ChefConfigGenerator.new(YAML.load(soloistrc_contents), soloistrc_path)
|
10
|
-
|
11
|
-
soloistrc_contents, soloistrc_path = walk_up_and_find_file(with_or_without_dot("soloistrc_local"), :required => false)
|
12
|
-
config_generator.merge_config(YAML.load(soloistrc_contents), soloistrc_path) if soloistrc_contents
|
13
|
-
|
14
|
-
if ARGV.length >= 1
|
15
|
-
requested_recipe = ARGV[0]
|
16
|
-
config_generator.recipes = [requested_recipe]
|
17
|
-
end
|
18
|
-
|
19
|
-
solo_rb = fileify(config_generator.solo_rb)
|
20
|
-
metadata_json = fileify(config_generator.json_file)
|
21
|
-
|
22
|
-
system "sudo mkdir -p /var/chef/cache" unless File.directory?("/var/chef/cache")
|
23
|
-
|
24
|
-
command = "sudo bash -c '#{config_generator.preserved_environment_variables_string} chef-solo -j #{metadata_json.path} -c #{solo_rb.path} -l #{log_level}'"
|
25
|
-
puts "running chef: " + command
|
26
|
-
system(command) || exit(1)
|
2
|
+
$:.push File.expand_path("../../lib", __FILE__)
|
3
|
+
require "soloist"
|
4
|
+
Soloist::CLI.start
|
data/lib/soloist/cli.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
require "librarian/chef/cli"
|
2
|
+
require "soloist/spotlight"
|
3
|
+
require "soloist/config"
|
4
|
+
require "tempfile"
|
5
|
+
require "thor"
|
6
|
+
|
7
|
+
module Soloist
|
8
|
+
class CLI < Thor
|
9
|
+
default_task :chef
|
10
|
+
|
11
|
+
desc "chef", "Runs chef-solo like a baws"
|
12
|
+
def chef
|
13
|
+
ensure_chef_cache_path
|
14
|
+
write_solo_rb
|
15
|
+
write_node_json
|
16
|
+
install_cookbooks if cheffile_exists?
|
17
|
+
exec("sudo -E bash -c '#{chef_solo}'")
|
18
|
+
end
|
19
|
+
|
20
|
+
desc "run_recipe", "Runs an individual recipe with chef-solo"
|
21
|
+
def DO_IT_LIVE(*recipes)
|
22
|
+
config.royal_crown.recipes = recipes
|
23
|
+
chef
|
24
|
+
end
|
25
|
+
|
26
|
+
no_tasks do
|
27
|
+
def write_solo_rb
|
28
|
+
content = config.as_solo_rb
|
29
|
+
content.each{ |line| puts line } if log_level == "debug"
|
30
|
+
File.open(solo_rb.path, "w") { |f| f.write(content) }
|
31
|
+
end
|
32
|
+
|
33
|
+
def write_node_json
|
34
|
+
content = config.as_json
|
35
|
+
puts JSON.pretty_generate(content) if log_level == "debug"
|
36
|
+
File.open(node_json.path, "w") { |f| f.write(JSON.dump(content)) }
|
37
|
+
end
|
38
|
+
|
39
|
+
def ensure_chef_cache_path
|
40
|
+
unless File.directory?("/var/chef/cache")
|
41
|
+
system("sudo mkdir -p /var/chef/cache")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def install_cookbooks
|
46
|
+
Dir.chdir(File.dirname(rc_path)) do
|
47
|
+
Librarian::Chef::Cli.with_environment do
|
48
|
+
Librarian::Chef::Cli.new.install
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def config
|
54
|
+
@config ||= Soloist::Config.from_file(rc_path)
|
55
|
+
end
|
56
|
+
|
57
|
+
def chef_solo
|
58
|
+
"chef-solo -j '#{node_json.path}' -c '#{solo_rb.path}' -l '#{log_level}'"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
def cheffile_exists?
|
64
|
+
File.exists?(File.expand_path("../Cheffile", rc_path))
|
65
|
+
end
|
66
|
+
|
67
|
+
def log_level
|
68
|
+
ENV["LOG_LEVEL"] || "info"
|
69
|
+
end
|
70
|
+
|
71
|
+
def solo_rb
|
72
|
+
@solo_rb ||= Tempfile.new(["solo", ".rb"])
|
73
|
+
end
|
74
|
+
|
75
|
+
def node_json
|
76
|
+
@node_json ||= Tempfile.new(["node", ".json"])
|
77
|
+
end
|
78
|
+
|
79
|
+
def rc_path
|
80
|
+
@rc_path ||= Soloist::Spotlight.find!("soloistrc", ".soloistrc")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "soloist/royal_crown"
|
2
|
+
|
3
|
+
module Soloist
|
4
|
+
class Config
|
5
|
+
attr_reader :royal_crown
|
6
|
+
|
7
|
+
def self.from_file(royal_crown_path)
|
8
|
+
rc = Soloist::RoyalCrown.from_file(royal_crown_path)
|
9
|
+
new(rc)
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(royal_crown)
|
13
|
+
@royal_crown = royal_crown
|
14
|
+
end
|
15
|
+
|
16
|
+
def as_solo_rb
|
17
|
+
paths = cookbook_paths.uniq.map do |cookbook_path|
|
18
|
+
File.expand_path(cookbook_path, bash_path)
|
19
|
+
end
|
20
|
+
"cookbook_path #{paths.inspect}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def as_json
|
24
|
+
{
|
25
|
+
"recipes" => compiled_rc.recipes
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def compiled_rc
|
30
|
+
@compiled_rc ||= royal_crown.dup.tap do |rc|
|
31
|
+
while rc["env_variable_switches"]
|
32
|
+
rc.delete("env_variable_switches").each do |variable, switch|
|
33
|
+
switch.each do |value, inner|
|
34
|
+
rc.merge!(inner) if ENV[variable] == value
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
def bash_path
|
43
|
+
File.dirname(royal_crown.path)
|
44
|
+
end
|
45
|
+
|
46
|
+
def cookbook_paths
|
47
|
+
["cookbooks"] + compiled_rc.cookbook_paths
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "hashie"
|
2
|
+
|
3
|
+
module Soloist
|
4
|
+
class RoyalCrown < Hashie::Trash
|
5
|
+
property :path
|
6
|
+
property :recipes, :default => []
|
7
|
+
property :cookbook_paths, :default => []
|
8
|
+
property :node_attributes, :default => Hashie::Mash.new,
|
9
|
+
:transform_with => lambda { |v| Hashie::Mash.new(v) }
|
10
|
+
property :env_variable_switches, :default => Hashie::Mash.new,
|
11
|
+
:transform_with => lambda { |v| Hashie::Mash.new(v) }
|
12
|
+
|
13
|
+
def node_attributes=(hash)
|
14
|
+
self["node_attributes"] = Hashie::Mash.new(hash)
|
15
|
+
end
|
16
|
+
|
17
|
+
def env_variable_switches=(hash)
|
18
|
+
self["env_variable_switches"] = Hashie::Mash.new(hash)
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_yaml
|
22
|
+
to_hash.tap do |hash|
|
23
|
+
hash.delete("path")
|
24
|
+
self.class.nilable_properties.each { |k| hash[k] = nil if hash[k].empty? }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def save
|
29
|
+
return self unless path
|
30
|
+
File.open(path, "w+") { |file| file.write(YAML.dump(to_yaml)) }
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
def reload
|
35
|
+
self.class.from_file(path)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.from_file(file_path)
|
39
|
+
new(read_config(file_path).merge("path" => file_path))
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.read_config(yaml_file)
|
43
|
+
content = File.read(yaml_file)
|
44
|
+
YAML.load(content).tap do |hash|
|
45
|
+
nilable_properties.each do |key|
|
46
|
+
hash.delete(key) if hash[key].nil?
|
47
|
+
end if hash
|
48
|
+
end || {}
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
def self.nilable_properties
|
53
|
+
(properties - [:path]).map(&:to_s)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module Soloist
|
4
|
+
class NotFound < RuntimeError; end
|
5
|
+
|
6
|
+
class Spotlight
|
7
|
+
attr_reader :pathname
|
8
|
+
|
9
|
+
def self.find(*file_names)
|
10
|
+
new(Dir.pwd).find(*file_names)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.find!(*file_names)
|
14
|
+
new(Dir.pwd).find!(*file_names)
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(path)
|
18
|
+
@pathname = Pathname.new(path)
|
19
|
+
end
|
20
|
+
|
21
|
+
def find(*file_names)
|
22
|
+
pathname.ascend do |path|
|
23
|
+
file_name = file_names.detect { |fn| path.join(fn).file? }
|
24
|
+
break path.join(file_name) if file_name
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def find!(*file_names)
|
29
|
+
file_path = find(*file_names)
|
30
|
+
unless file_path
|
31
|
+
file_names = if file_names.length > 2
|
32
|
+
file_names[0...-1].join(", ") + " or " + file_names.last
|
33
|
+
else
|
34
|
+
file_names.join(" or ")
|
35
|
+
end
|
36
|
+
raise Soloist::NotFound.new("Could not find #{file_names}")
|
37
|
+
end
|
38
|
+
file_path
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/soloist/version.rb
CHANGED
data/lib/soloist.rb
CHANGED
@@ -1,11 +1,2 @@
|
|
1
|
-
require
|
2
|
-
require "
|
3
|
-
require 'fileutils'
|
4
|
-
require 'yaml'
|
5
|
-
require 'tempfile'
|
6
|
-
require 'tmpdir'
|
7
|
-
require 'set'
|
8
|
-
|
9
|
-
require File.join(File.dirname(__FILE__), 'soloist', 'util')
|
10
|
-
require File.join(File.dirname(__FILE__), 'soloist', 'chef_config_generator')
|
11
|
-
require File.join(File.dirname(__FILE__), 'soloist', 'cookbook_gem_linker')
|
1
|
+
require "soloist/version"
|
2
|
+
require "soloist/cli"
|
data/script/ci.sh
ADDED