batali 0.3.10 → 0.3.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +18 -0
- data/batali.gemspec +2 -0
- data/lib/batali.rb +1 -0
- data/lib/batali/b_file.rb +27 -7
- data/lib/batali/chefspec.rb +5 -0
- data/lib/batali/command.rb +1 -1
- data/lib/batali/command/install.rb +3 -3
- data/lib/batali/command/resolve.rb +6 -5
- data/lib/batali/git.rb +5 -4
- data/lib/batali/manifest.rb +3 -3
- data/lib/batali/monkey.rb +5 -1
- data/lib/batali/origin.rb +1 -0
- data/lib/batali/origin/chef_server.rb +3 -2
- data/lib/batali/origin/git.rb +3 -2
- data/lib/batali/origin/path.rb +6 -4
- data/lib/batali/origin/remote_site.rb +5 -5
- data/lib/batali/requirement_list.rb +8 -1
- data/lib/batali/score_keeper.rb +19 -8
- data/lib/batali/source.rb +15 -11
- data/lib/batali/source/chef_server.rb +2 -4
- data/lib/batali/source/path.rb +1 -1
- data/lib/batali/source/site.rb +1 -3
- data/lib/batali/tag_lines.rb +7 -5
- data/lib/batali/unit.rb +16 -4
- data/lib/batali/unit_loader.rb +15 -9
- data/lib/batali/utility.rb +3 -1
- data/lib/batali/version.rb +2 -1
- data/lib/chef/knife/batali_sync.rb +5 -4
- metadata +30 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 011f26a3e8a17db988eb207d7fc79cbdc51e1306
|
4
|
+
data.tar.gz: e0bd881f9cf5be081f73c315e6be9ee50a206ff7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dc6e7955b3163d94389ee1b71b61ce63651ea760f39e4061682f8fbb91505642129159252e95d851e3ae6cae6b6600d1bebf9f580adad9613e358ed1ef082abb
|
7
|
+
data.tar.gz: fa4b45f0b1c202a9ada821e6d64456c78316b21b52e969281f7ef6fbc07a9395aec2209dea78b724035430445f9b9498ea0c39ec657a0805d389be7af31811d3
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -240,6 +240,24 @@ $ batali resolve --infrastructure
|
|
240
240
|
|
241
241
|
_NOTE: Depending on constraints defined within the Batali file, this can be a very large manifest_
|
242
242
|
|
243
|
+
#### Single cookbook, multiple sources
|
244
|
+
|
245
|
+
When running in infrastructure mode, Batali supports single cookbooks being loaded from
|
246
|
+
multiple sources. For example, if all the `users` cookbooks greater than version `1.0` should
|
247
|
+
be available _and_ an unreleased development version that lives in a git repository, Batali
|
248
|
+
will properly include all versions:
|
249
|
+
|
250
|
+
```ruby
|
251
|
+
Batali.define do
|
252
|
+
source 'https://supermarket.chef.io'
|
253
|
+
cookbook 'users', '> 1.0'
|
254
|
+
cookbook 'users', git: 'git://example.com/org/users.git', ref: 'development'
|
255
|
+
end
|
256
|
+
```
|
257
|
+
|
258
|
+
The resulting Batali manifest file will include all available versions greater than `1.0`
|
259
|
+
from the supermarket source _and_ the version defined at the specified git end point.
|
260
|
+
|
243
261
|
#### Uploading infrastructure cookbooks
|
244
262
|
|
245
263
|
When the infrastructure cookbooks are installed locally, the cookbook directories will have
|
data/batali.gemspec
CHANGED
@@ -18,6 +18,8 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.add_runtime_dependency 'bogo-ui', '~> 0.1.6'
|
19
19
|
s.add_runtime_dependency 'http', '>= 0.8.2', '< 1.0.0'
|
20
20
|
s.add_runtime_dependency 'git'
|
21
|
+
s.add_development_dependency 'rake'
|
22
|
+
s.add_development_dependency 'rubocop'
|
21
23
|
s.add_development_dependency 'minitest'
|
22
24
|
s.add_development_dependency 'pry'
|
23
25
|
s.add_development_dependency 'chef'
|
data/lib/batali.rb
CHANGED
data/lib/batali/b_file.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
require 'batali'
|
2
2
|
require 'pathname'
|
3
3
|
|
4
|
+
# Batali namespace
|
4
5
|
module Batali
|
5
6
|
|
7
|
+
# Custom struct class for file processing
|
6
8
|
class Struct < AttributeStruct
|
7
9
|
|
8
10
|
def cookbook(*args)
|
@@ -85,8 +87,22 @@ module Batali
|
|
85
87
|
struct
|
86
88
|
end
|
87
89
|
|
90
|
+
# Custom file loading class
|
88
91
|
class BFile < Bogo::Config
|
89
92
|
|
93
|
+
# @return [String] path to cache
|
94
|
+
attr_reader :cache
|
95
|
+
|
96
|
+
# Create a new BFile instance
|
97
|
+
#
|
98
|
+
# @param b_file [String] path to file
|
99
|
+
# @param cache_path [String] path to cache directory
|
100
|
+
# @return [self]
|
101
|
+
def initialize(b_file, cache_path)
|
102
|
+
@cache = cache_path
|
103
|
+
super(b_file)
|
104
|
+
end
|
105
|
+
|
90
106
|
# @return [Proc] cookbook convert
|
91
107
|
def self.cookbook_coerce
|
92
108
|
proc do |v|
|
@@ -107,19 +123,23 @@ module Batali
|
|
107
123
|
end
|
108
124
|
end
|
109
125
|
|
126
|
+
# Cookbook entry
|
110
127
|
class Cookbook < Utility
|
111
128
|
attribute :name, String, :required => true
|
112
129
|
attribute :constraint, String, :multiple => true
|
113
130
|
attribute :git, String
|
114
131
|
attribute :ref, String
|
115
132
|
attribute :path, String
|
133
|
+
attribute :restrict, [TrueClass, FalseClass], :default => false
|
116
134
|
end
|
117
135
|
|
136
|
+
# Restriction entry
|
118
137
|
class Restriction < Utility
|
119
138
|
attribute :cookbook, String, :required => true
|
120
139
|
attribute :source, String, :required => true
|
121
140
|
end
|
122
141
|
|
142
|
+
# Group entry
|
123
143
|
class Group < Utility
|
124
144
|
attribute :name, String, :required => true
|
125
145
|
attribute :cookbook, Cookbook, :multiple => true, :required => true, :coerce => BFile.cookbook_coerce
|
@@ -133,7 +153,7 @@ module Batali
|
|
133
153
|
Restriction.new(:cookbook => v.first, :source => v.last.to_smash[:source])
|
134
154
|
end
|
135
155
|
}
|
136
|
-
attribute :source, Origin::RemoteSite, :multiple => true, :default => [], :coerce => lambda{|v|
|
156
|
+
attribute :source, Origin::RemoteSite, :multiple => true, :default => [], :coerce => lambda{|v, b_file|
|
137
157
|
if(v.is_a?(Hash))
|
138
158
|
args = v
|
139
159
|
else
|
@@ -142,9 +162,9 @@ module Batali
|
|
142
162
|
args.merge!(v.last)
|
143
163
|
end
|
144
164
|
end
|
145
|
-
Origin::RemoteSite.new(args)
|
165
|
+
Origin::RemoteSite.new(args.merge(:cache_path => b_file.cache))
|
146
166
|
}
|
147
|
-
attribute :chef_server, Origin::ChefServer, :multiple => true, :default => [], :coerce => lambda{|v|
|
167
|
+
attribute :chef_server, Origin::ChefServer, :multiple => true, :default => [], :coerce => lambda{|v, b_file|
|
148
168
|
if(v.is_a?(Hash))
|
149
169
|
args = v
|
150
170
|
else
|
@@ -153,7 +173,7 @@ module Batali
|
|
153
173
|
args.merge!(v.last)
|
154
174
|
end
|
155
175
|
end
|
156
|
-
Origin::ChefServer.new(args)
|
176
|
+
Origin::ChefServer.new(args.merge(:cache_path => b_file.cache))
|
157
177
|
}
|
158
178
|
attribute :group, Group, :multiple => true, :coerce => lambda{|v| Group.new(v)}
|
159
179
|
attribute :cookbook, Cookbook, :multiple => true, :coerce => BFile.cookbook_coerce, :default => []
|
@@ -162,7 +182,7 @@ module Batali
|
|
162
182
|
ckbk = Cookbook.new(v)
|
163
183
|
else
|
164
184
|
dir = Pathname.new(File.dirname(b_file.path)).relative_path_from(Pathname.new(Dir.pwd)).to_path
|
165
|
-
m_unit = Origin::Path.new(:name => 'metadata', :path => dir).units.first
|
185
|
+
m_unit = Origin::Path.new(:name => 'metadata', :path => dir, :cache_path => b_file.cache).units.first
|
166
186
|
ckbk = Cookbook.new(:name => m_unit.name, :version => m_unit.version, :path => dir)
|
167
187
|
end
|
168
188
|
unless(b_file.cookbook.map(&:name).include?(ckbk.name))
|
@@ -186,7 +206,7 @@ module Batali
|
|
186
206
|
result[:name] => result[:cookbooks]
|
187
207
|
)
|
188
208
|
end
|
189
|
-
end.compact.inject(Smash.new){|m,n| m.merge(n)}
|
209
|
+
end.compact.inject(Smash.new){|m, n| m.merge(n)}
|
190
210
|
environment_items.each do |e_name, items|
|
191
211
|
next if environment && e_name != environment
|
192
212
|
debug "Discovery processing of environment: #{e_name}"
|
@@ -315,7 +335,7 @@ module Batali
|
|
315
335
|
env.fetch(
|
316
336
|
:cookbook_versions,
|
317
337
|
Smash.new
|
318
|
-
).map{|k,v| [k, v.to_s.split(',')]}
|
338
|
+
).map{|k, v| [k, v.to_s.split(',')]}
|
319
339
|
]
|
320
340
|
)
|
321
341
|
end
|
data/lib/batali/chefspec.rb
CHANGED
@@ -3,7 +3,9 @@ require 'stringio'
|
|
3
3
|
require 'fileutils'
|
4
4
|
require 'tmpdir'
|
5
5
|
|
6
|
+
# ChefSpec namespace
|
6
7
|
module ChefSpec
|
8
|
+
# Batali integration class
|
7
9
|
class Batali
|
8
10
|
|
9
11
|
class << self
|
@@ -13,10 +15,12 @@ module ChefSpec
|
|
13
15
|
|
14
16
|
include Singleton
|
15
17
|
|
18
|
+
# Create new instance
|
16
19
|
def initialize
|
17
20
|
@vendor_path = Dir.mktmpdir
|
18
21
|
end
|
19
22
|
|
23
|
+
# Setup the environment (load cookbooks)
|
20
24
|
def setup!
|
21
25
|
output = ''
|
22
26
|
begin
|
@@ -44,6 +48,7 @@ module ChefSpec
|
|
44
48
|
end
|
45
49
|
end
|
46
50
|
|
51
|
+
# Clean up after complete
|
47
52
|
def teardown!
|
48
53
|
if(File.directory?(@vendor_path))
|
49
54
|
FileUtils.rm_rf(@vendor_path)
|
data/lib/batali/command.rb
CHANGED
@@ -28,7 +28,7 @@ module Batali
|
|
28
28
|
# TODO: Add directory traverse searching
|
29
29
|
path = config.fetch(:file, File.join(Dir.pwd, 'Batali'))
|
30
30
|
ui.verbose "Loading Batali file from: #{path}"
|
31
|
-
bfile = BFile.new(path)
|
31
|
+
bfile = BFile.new(path, cache_directory)
|
32
32
|
if(bfile.discover)
|
33
33
|
bfile.auto_discover!(config[:environment])
|
34
34
|
end
|
@@ -17,12 +17,12 @@ module Batali
|
|
17
17
|
nil
|
18
18
|
end
|
19
19
|
if(manifest.cookbook.nil? || manifest.cookbook.empty?)
|
20
|
-
ui.error
|
20
|
+
ui.error 'No cookbooks defined within manifest! Try resolving first. (`batali resolve`)'
|
21
21
|
else
|
22
22
|
run_action('Installing cookbooks') do
|
23
23
|
manifest.cookbook.each do |unit|
|
24
|
-
if(unit.source.respond_to?(:
|
25
|
-
unit.source.
|
24
|
+
if(unit.source.respond_to?(:cache_path))
|
25
|
+
unit.source.cache_path = cache_directory(
|
26
26
|
Bogo::Utility.snake(unit.source.class.name.split('::').last)
|
27
27
|
)
|
28
28
|
end
|
@@ -14,7 +14,8 @@ module Batali
|
|
14
14
|
UnitLoader.new(
|
15
15
|
:file => batali_file,
|
16
16
|
:system => system,
|
17
|
-
:cache => cache_directory(:git)
|
17
|
+
:cache => cache_directory(:git),
|
18
|
+
:auto_path_restrict => !infrastructure?
|
18
19
|
).populate!
|
19
20
|
nil
|
20
21
|
end
|
@@ -101,7 +102,7 @@ module Batali
|
|
101
102
|
unless(u_diff.empty?)
|
102
103
|
diff_output = "[#{u_diff.values.map{|v| v.join(' -> ')}.join(' | ')}]"
|
103
104
|
end
|
104
|
-
ui.puts ui.color("#{unit_name} <#{version_output}> #{diff_output}"
|
105
|
+
ui.puts ui.color("#{unit_name} <#{version_output}> #{diff_output}", :yellow)
|
105
106
|
end
|
106
107
|
else
|
107
108
|
ui.puts ui.color("#{unit_name} <#{manifest_units[unit_name].version}>", :red)
|
@@ -169,15 +170,15 @@ module Batali
|
|
169
170
|
uv.last ? ui.color(uv.first.to_s, uv.last) : uv.first.to_s
|
170
171
|
end
|
171
172
|
unless(added.empty? && removed.empty?)
|
172
|
-
ui.puts "#{ui.color(unit_name, :yellow)} #{ui.color('<', :yellow)}#{unit_versions.join(ui.color(', ', :yellow))}#{ui.color('>', :yellow)}"
|
173
|
+
ui.puts "#{ui.color(unit_name, :yellow)} #{ui.color('<', :yellow)}#{unit_versions.join(ui.color(', ', :yellow))}#{ui.color('>', :yellow)}" # rubocop:disable Metrics/LineLength
|
173
174
|
else
|
174
175
|
ui.puts "#{unit_name} <#{unit_versions.join(', ')}>"
|
175
176
|
end
|
176
177
|
else
|
177
|
-
ui.puts ui.color("#{unit_name} <#{manifest_units[unit_name].map(&:version).sort.map(&:to_s).join(', ')}>", :red)
|
178
|
+
ui.puts ui.color("#{unit_name} <#{manifest_units[unit_name].map(&:version).sort.map(&:to_s).join(', ')}>", :red) # rubocop:disable Metrics/LineLength
|
178
179
|
end
|
179
180
|
else
|
180
|
-
ui.puts ui.color("#{unit_name} <#{solution_units[unit_name].map(&:version).sort.map(&:to_s).join(', ')}>", :green)
|
181
|
+
ui.puts ui.color("#{unit_name} <#{solution_units[unit_name].map(&:version).sort.map(&:to_s).join(', ')}>", :green) # rubocop:disable Metrics/LineLength
|
181
182
|
end
|
182
183
|
end
|
183
184
|
end
|
data/lib/batali/git.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
require 'git'
|
2
2
|
require 'batali'
|
3
3
|
|
4
|
+
# Batali namespace
|
4
5
|
module Batali
|
6
|
+
# Helper module for git interactions
|
5
7
|
module Git
|
6
8
|
|
7
9
|
# @return [String] path to repository clone
|
8
10
|
def base_path
|
9
|
-
File.join(
|
11
|
+
File.join(cache_path, Base64.urlsafe_encode64(url))
|
10
12
|
end
|
11
13
|
|
12
14
|
# Clone the repository to the local machine
|
@@ -33,13 +35,13 @@ module Batali
|
|
33
35
|
git.checkout(ref)
|
34
36
|
git.pull('origin', ref)
|
35
37
|
self.ref = git.log.first.sha
|
36
|
-
self.path = File.join(
|
38
|
+
self.path = File.join(cache_path, 'git', ref)
|
37
39
|
unless(File.directory?(path))
|
38
40
|
FileUtils.mkdir_p(path)
|
39
41
|
FileUtils.cp_r(File.join(base_path, '.'), path)
|
40
42
|
FileUtils.rm_rf(File.join(path, '.git'))
|
41
43
|
end
|
42
|
-
|
44
|
+
path
|
43
45
|
end
|
44
46
|
|
45
47
|
# Load attributes into class
|
@@ -47,7 +49,6 @@ module Batali
|
|
47
49
|
klass.class_eval do
|
48
50
|
attribute :url, String, :required => true, :equivalent => true
|
49
51
|
attribute :ref, String, :required => true, :equivalent => true
|
50
|
-
attribute :cache, String, :default => File.join(Dir.home, '.batali', 'cache', 'git')
|
51
52
|
end
|
52
53
|
end
|
53
54
|
|
data/lib/batali/manifest.rb
CHANGED
@@ -16,10 +16,10 @@ module Batali
|
|
16
16
|
# @param path [String] path to manifest
|
17
17
|
# @return [Manifest]
|
18
18
|
def self.build(path)
|
19
|
-
if(File.
|
20
|
-
|
19
|
+
if(File.exist?(path))
|
20
|
+
new(Bogo::Config.new(path).data.merge(:path => path))
|
21
21
|
else
|
22
|
-
|
22
|
+
new(:path => path)
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
data/lib/batali/monkey.rb
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
require 'batali'
|
2
2
|
require 'bogo/http_proxy'
|
3
3
|
|
4
|
+
# Batali namespace
|
4
5
|
module Batali
|
5
|
-
#
|
6
|
+
# Custom named unit version
|
6
7
|
class UnitVersion < Grimoire::VERSION_CLASS; end
|
8
|
+
# Custom named unit requirement
|
7
9
|
class UnitRequirement < Grimoire::REQUIREMENT_CLASS; end
|
10
|
+
# Custom named unit dependency
|
8
11
|
class UnitDependency < Grimoire::DEPENDENCY_CLASS
|
12
|
+
# Override to properly convert to JSON
|
9
13
|
def to_json(*args)
|
10
14
|
result = [
|
11
15
|
name,
|
data/lib/batali/origin.rb
CHANGED
@@ -20,7 +20,7 @@ module Batali
|
|
20
20
|
init_chef!
|
21
21
|
self.identifier = Digest::SHA256.hexdigest(endpoint)
|
22
22
|
unless(name?)
|
23
|
-
self.name =
|
23
|
+
self.name = identifier
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
@@ -48,7 +48,8 @@ module Batali
|
|
48
48
|
:dependencies => c_deps,
|
49
49
|
:endpoint => endpoint,
|
50
50
|
:client_key => client_key,
|
51
|
-
:client_name => client_name
|
51
|
+
:client_name => client_name,
|
52
|
+
:cache_path => cache_path
|
52
53
|
)
|
53
54
|
)
|
54
55
|
end.flatten
|
data/lib/batali/origin/git.rb
CHANGED
@@ -18,7 +18,7 @@ module Batali
|
|
18
18
|
:subdirectory => subdirectory
|
19
19
|
).checksum
|
20
20
|
unless(name?)
|
21
|
-
self.name =
|
21
|
+
self.name = identifier
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -29,7 +29,8 @@ module Batali
|
|
29
29
|
items.first.source = Source::Git.new(
|
30
30
|
:url => url,
|
31
31
|
:ref => ref,
|
32
|
-
:subdirectory => subdirectory
|
32
|
+
:subdirectory => subdirectory,
|
33
|
+
:cache_path => cache_path
|
33
34
|
)
|
34
35
|
items
|
35
36
|
end
|
data/lib/batali/origin/path.rb
CHANGED
@@ -5,6 +5,7 @@ module Batali
|
|
5
5
|
# Fetch unit from local path
|
6
6
|
class Path < Origin
|
7
7
|
|
8
|
+
# Helper class for loading metadata ruby files
|
8
9
|
class Metadata < AttributeStruct
|
9
10
|
|
10
11
|
# Perform constant lookup if required
|
@@ -33,7 +34,7 @@ module Batali
|
|
33
34
|
super
|
34
35
|
self.identifier = Smash.new(:path => path).checksum
|
35
36
|
unless(name?)
|
36
|
-
self.name =
|
37
|
+
self.name = identifier
|
37
38
|
end
|
38
39
|
end
|
39
40
|
|
@@ -63,7 +64,8 @@ module Batali
|
|
63
64
|
:type => :path,
|
64
65
|
:version => info[:version],
|
65
66
|
:path => path,
|
66
|
-
:dependencies => info.fetch(:depends, [])
|
67
|
+
:dependencies => info.fetch(:depends, []),
|
68
|
+
:cache_path => cache_path
|
67
69
|
)
|
68
70
|
)
|
69
71
|
]
|
@@ -73,9 +75,9 @@ module Batali
|
|
73
75
|
# @return [Smash] metadata information
|
74
76
|
def load_metadata
|
75
77
|
memoize(:metadata) do
|
76
|
-
if(File.
|
78
|
+
if(File.exist?(json = File.join(path, 'metadata.json')))
|
77
79
|
MultiJson.load(json).to_smash
|
78
|
-
elsif(File.
|
80
|
+
elsif(File.exist?(rb = File.join(path, 'metadata.rb')))
|
79
81
|
struct = Metadata.new
|
80
82
|
struct.set_state!(:value_collapse => true)
|
81
83
|
struct.instance_eval(File.read(rb), rb, 1)
|
@@ -19,21 +19,20 @@ module Batali
|
|
19
19
|
attribute :endpoint, String, :required => true
|
20
20
|
attribute :force_update, [TrueClass, FalseClass], :required => true, :default => false
|
21
21
|
attribute :update_interval, Integer, :required => true, :default => 60
|
22
|
-
attribute :cache, String, :default => File.join(Dir.home, '.batali', 'cache', 'remote_site'), :required => true
|
23
22
|
|
24
23
|
def initialize(*_)
|
25
24
|
super
|
26
25
|
endpoint = URI.join(self.endpoint, COOKBOOK_API_SUFFIX).to_s
|
27
26
|
self.identifier = Digest::SHA256.hexdigest(endpoint)
|
28
27
|
unless(name?)
|
29
|
-
self.name =
|
28
|
+
self.name = identifier
|
30
29
|
end
|
31
30
|
end
|
32
31
|
|
33
32
|
# @return [String] cache directory path
|
34
33
|
def cache_directory
|
35
34
|
memoize(:cache_directory) do
|
36
|
-
c_path = File.join(
|
35
|
+
c_path = File.join(cache_path, 'remote_site', identifier)
|
37
36
|
FileUtils.mkdir_p(c_path)
|
38
37
|
c_path
|
39
38
|
end
|
@@ -52,7 +51,8 @@ module Batali
|
|
52
51
|
:type => :site,
|
53
52
|
:url => info[:download_url],
|
54
53
|
:version => version,
|
55
|
-
:dependencies => info[:dependencies]
|
54
|
+
:dependencies => info[:dependencies],
|
55
|
+
:cache_path => cache_path
|
56
56
|
)
|
57
57
|
)
|
58
58
|
end
|
@@ -75,7 +75,7 @@ module Batali
|
|
75
75
|
def fetch
|
76
76
|
do_fetch = true
|
77
77
|
cache_directory # init directory creation
|
78
|
-
if(File.
|
78
|
+
if(File.exist?(universe_path))
|
79
79
|
age = Time.now - File.mtime(universe_path)
|
80
80
|
if(age < update_interval)
|
81
81
|
do_fetch = false
|
@@ -1,8 +1,15 @@
|
|
1
1
|
require 'batali'
|
2
2
|
|
3
|
+
# Batali namespace
|
3
4
|
module Batali
|
4
5
|
# Customized Unit
|
5
6
|
class RequirementList < Grimoire::RequirementList
|
6
|
-
attribute
|
7
|
+
attribute(:requirements, [Batali::UnitDependency, Grimoire::DEPENDENCY_CLASS],
|
8
|
+
:multiple => true,
|
9
|
+
:default => [],
|
10
|
+
:coerce => lambda{ |v|
|
11
|
+
Batali::UnitDependency.new(val.first, *val.last)
|
12
|
+
}
|
13
|
+
)
|
7
14
|
end
|
8
15
|
end
|
data/lib/batali/score_keeper.rb
CHANGED
@@ -4,6 +4,14 @@ module Batali
|
|
4
4
|
# Provide scores for units
|
5
5
|
class ScoreKeeper < Grimoire::UnitScoreKeeper
|
6
6
|
|
7
|
+
# Score multiplier values
|
8
|
+
MULTIPLIERS = {
|
9
|
+
:preferred => 10_000_000,
|
10
|
+
:patch => 1_000_000,
|
11
|
+
:minor => 1_000,
|
12
|
+
:major => 100
|
13
|
+
}
|
14
|
+
|
7
15
|
attribute :manifest, Manifest, :required => true
|
8
16
|
|
9
17
|
# Always prefer higher scoring units
|
@@ -28,25 +36,28 @@ module Batali
|
|
28
36
|
# If the unit version matches the manifest version, this
|
29
37
|
# should be _the_ preferred version
|
30
38
|
if(manifest_unit.version == unit.version)
|
31
|
-
multiplier =
|
39
|
+
multiplier = MULTIPLIERS[:preferred]
|
32
40
|
elsif(opts[:solver] && opts[:solver].new_world)
|
33
41
|
new_world_unit = opts[:solver].new_world.units.detect do |n_unit|
|
34
42
|
n_unit.name == unit.name &&
|
35
43
|
n_unit.version == unit.version
|
36
44
|
end
|
37
|
-
multiplier =
|
45
|
+
multiplier = MULTIPLIERS[:preferred] if new_world_unit
|
38
46
|
else
|
39
47
|
# If the unit version satisfies within the patch segment of
|
40
48
|
# the manifest version score those versions highest for upgrade
|
41
49
|
if(UnitRequirement.new("~> #{manifest_unit.version}").satisfied_by?(unit.version))
|
42
|
-
multiplier =
|
50
|
+
multiplier = MULTIPLIERS[:patch]
|
43
51
|
else
|
44
52
|
# If the unit version satisfies within the minor or major
|
45
53
|
# version segments of the manifest version, bump score
|
46
54
|
# value up (with satisfaction within minor segment being
|
47
55
|
# worth more than satisfaction within major segment)
|
48
|
-
|
49
|
-
|
56
|
+
satisfied = UnitRequirement.new(
|
57
|
+
"~> #{manifest_unit.version.segments.slice(0, 2).join('.')}"
|
58
|
+
).satisfied_by?(unit.version)
|
59
|
+
pos = satisfied ? 1 : 0
|
60
|
+
multi_val = pos == 1 ? MULTIPLIERS[:minor] : MULTIPLIERS[:major]
|
50
61
|
distance = (manifest_unit.version.segments[pos] - unit.version.segments[pos])
|
51
62
|
if(distance > 0)
|
52
63
|
distance = 1.0 / distance
|
@@ -62,17 +73,17 @@ module Batali
|
|
62
73
|
n_unit.name == unit.name &&
|
63
74
|
n_unit.version == unit.version
|
64
75
|
end
|
65
|
-
multiplier =
|
76
|
+
multiplier = MULTIPLIERS[:preferred] if new_world_unit
|
66
77
|
end
|
67
78
|
end
|
68
79
|
score = []
|
69
80
|
# Generate a "value" for each segment of the version with
|
70
81
|
# growing importance (major > minor > patch)
|
71
|
-
unit.version.segments.reverse.each_with_index.map do |val,
|
82
|
+
unit.version.segments.reverse.each_with_index.map do |val, v_pos|
|
72
83
|
if(val == 0)
|
73
84
|
score.push 0
|
74
85
|
else
|
75
|
-
score
|
86
|
+
score << (2 - (1.0 / val)) * ((v_pos + 1)**10)
|
76
87
|
end
|
77
88
|
end
|
78
89
|
# Sum the score for each segment to provide the score for the
|
data/lib/batali/source.rb
CHANGED
@@ -9,7 +9,15 @@ module Batali
|
|
9
9
|
autoload :Git, 'batali/source/git'
|
10
10
|
autoload :ChefServer, 'batali/source/chef_server'
|
11
11
|
|
12
|
-
|
12
|
+
# @return [String] path to local cache
|
13
|
+
attr_accessor :cache_path
|
14
|
+
|
15
|
+
attribute :type, String, :required => true, :default => lambda{ self.name } # rubocop:disable Style/RedundantSelf
|
16
|
+
|
17
|
+
def initialize(args={})
|
18
|
+
@cache_path = args.delete(:cache_path)
|
19
|
+
super
|
20
|
+
end
|
13
21
|
|
14
22
|
# @return [String]
|
15
23
|
def unit_version
|
@@ -28,15 +36,11 @@ module Batali
|
|
28
36
|
|
29
37
|
# @return [TrueClass, FalseClass]
|
30
38
|
def clean_asset(asset_path)
|
31
|
-
if(
|
32
|
-
|
39
|
+
if(cache_path && asset_path.include?(cache_path) && File.exist?(asset_path))
|
40
|
+
FileUtils.rm_rf(asset_path)
|
41
|
+
true
|
33
42
|
else
|
34
|
-
|
35
|
-
FileUtils.rm_rf(asset_path)
|
36
|
-
true
|
37
|
-
else
|
38
|
-
false
|
39
|
-
end
|
43
|
+
false
|
40
44
|
end
|
41
45
|
end
|
42
46
|
|
@@ -55,7 +59,7 @@ module Batali
|
|
55
59
|
# @return [Smash]
|
56
60
|
def diff(s)
|
57
61
|
Smash.new.tap do |_diff|
|
58
|
-
self.class.attributes.each do |k,v|
|
62
|
+
self.class.attributes.each do |k, v|
|
59
63
|
if(v[:equivalent])
|
60
64
|
s_attrs = s.respond_to?(:attributes) ? s.attributes : {}
|
61
65
|
unless(attributes[k] == s_attrs[k])
|
@@ -77,7 +81,7 @@ module Batali
|
|
77
81
|
raise ArgumentError.new 'Missing required option `:type`!'
|
78
82
|
end
|
79
83
|
unless(type.to_s.include?('::'))
|
80
|
-
type = [
|
84
|
+
type = [name, Bogo::Utility.camel(type)].join('::')
|
81
85
|
end
|
82
86
|
klass = Bogo::Utility.constantize(type)
|
83
87
|
unless(klass)
|
@@ -48,9 +48,7 @@ module Batali
|
|
48
48
|
# @return [String] path to cache
|
49
49
|
def cache_directory
|
50
50
|
memoize(:cache_directory) do
|
51
|
-
|
52
|
-
@cache = File.join(Dir.home, '.batali', 'cache', 'chef_server', endpoint)
|
53
|
-
end
|
51
|
+
@cache ||= File.join(cache_path, 'chef_server', endpoint)
|
54
52
|
cache
|
55
53
|
end
|
56
54
|
end
|
@@ -63,7 +61,7 @@ module Batali
|
|
63
61
|
cookbook = rest.get_rest("cookbooks/#{name}/#{version}")
|
64
62
|
manifest = cookbook.manifest
|
65
63
|
Chef::CookbookVersion::COOKBOOK_SEGMENTS.each do |segement|
|
66
|
-
if(manifest.
|
64
|
+
if(manifest.key?(segment))
|
67
65
|
manifest[segement].each do |s_file|
|
68
66
|
new_path = File.join(path, s_file['path'].gsub('/', File::SEPARATOR))
|
69
67
|
FileUtils.mkdir_p(File.dirname(new_path))
|
data/lib/batali/source/path.rb
CHANGED
@@ -23,7 +23,7 @@ module Batali
|
|
23
23
|
dir = Dir.mktmpdir
|
24
24
|
chefignore = IGNORE_FILE.map do |c_name|
|
25
25
|
c_path = File.join(path, c_name)
|
26
|
-
c_path if File.
|
26
|
+
c_path if File.exist?(c_path)
|
27
27
|
end.compact.first
|
28
28
|
chefignore = chefignore ? File.readlines(chefignore) : []
|
29
29
|
chefignore += DEFAULT_IGNORE
|
data/lib/batali/source/site.rb
CHANGED
@@ -43,9 +43,7 @@ module Batali
|
|
43
43
|
# @return [String] path to cache
|
44
44
|
def cache_directory
|
45
45
|
memoize(:cache_directory) do
|
46
|
-
|
47
|
-
@cache = File.join(Dir.home, '.batali', 'cache', 'remote_site')
|
48
|
-
end
|
46
|
+
@cache ||= File.join(cache_path, 'remote_site')
|
49
47
|
cache
|
50
48
|
end
|
51
49
|
end
|
data/lib/batali/tag_lines.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
require 'batali'
|
2
2
|
|
3
|
+
# Batali namespace
|
3
4
|
module Batali
|
4
5
|
|
6
|
+
# Version output taglines
|
5
7
|
TAG_LINES = [
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
'I got 99 problems but a policyfile ain\'t one',
|
9
|
+
'Solve the way you want, not the way you\'re told',
|
10
|
+
'Build environments, not applications',
|
11
|
+
'DRY should be the rule, not the exception',
|
12
|
+
'Solve for the forest, not just a tree'
|
11
13
|
]
|
12
14
|
|
13
15
|
end
|
data/lib/batali/unit.rb
CHANGED
@@ -1,11 +1,23 @@
|
|
1
1
|
require 'batali'
|
2
2
|
|
3
|
+
# Batali namespace
|
3
4
|
module Batali
|
4
5
|
# Customized Unit
|
5
6
|
class Unit < Grimoire::Unit
|
6
7
|
attribute :source, Source, :coerce => lambda{|v| Batali::Source.build(v)}
|
7
|
-
attribute
|
8
|
-
|
8
|
+
attribute(:dependencies, [Batali::UnitDependency, Grimoire::DEPENDENCY_CLASS],
|
9
|
+
:multiple => true,
|
10
|
+
:default => [],
|
11
|
+
:coerce => lambda{ |val|
|
12
|
+
Batali::UnitDependency.new(val.first, *val.last)
|
13
|
+
}
|
14
|
+
)
|
15
|
+
attribute(:version, [Batali::UnitVersion, Grimoire::VERSION_CLASS],
|
16
|
+
:required => true,
|
17
|
+
:coerce => lambda{ |val|
|
18
|
+
Batali::UnitVersion.new(val)
|
19
|
+
}
|
20
|
+
)
|
9
21
|
|
10
22
|
# @return [TrueClass, FalseClass]
|
11
23
|
def diff?(u)
|
@@ -21,8 +33,8 @@ module Batali
|
|
21
33
|
def diff(u)
|
22
34
|
Smash.new.tap do |_diff|
|
23
35
|
[:name, :version].each do |k|
|
24
|
-
unless(
|
25
|
-
_diff[k] = [
|
36
|
+
unless(send(k) == u.send(k))
|
37
|
+
_diff[k] = [send(k), u.send(k)]
|
26
38
|
end
|
27
39
|
end
|
28
40
|
if(source)
|
data/lib/batali/unit_loader.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'batali'
|
2
2
|
|
3
|
+
# Batali namespace
|
3
4
|
module Batali
|
4
5
|
|
6
|
+
# Load cookbook units
|
5
7
|
class UnitLoader < Utility
|
6
8
|
|
7
9
|
include Bogo::Memoization
|
@@ -9,6 +11,7 @@ module Batali
|
|
9
11
|
attribute :file, BFile, :required => true
|
10
12
|
attribute :system, Grimoire::System, :required => true
|
11
13
|
attribute :cache, String, :required => true
|
14
|
+
attribute :auto_path_restrict, [TrueClass, FalseClass], :default => true
|
12
15
|
|
13
16
|
# Populate the system with units
|
14
17
|
#
|
@@ -33,12 +36,13 @@ module Batali
|
|
33
36
|
:url => ckbk.git,
|
34
37
|
:subdirectory => ckbk.path,
|
35
38
|
:ref => ckbk.ref || 'master',
|
36
|
-
:
|
39
|
+
:cache_path => cache
|
37
40
|
)
|
38
41
|
elsif(ckbk.path)
|
39
42
|
source = Origin::Path.new(
|
40
43
|
:name => ckbk.name,
|
41
|
-
:path => ckbk.path
|
44
|
+
:path => ckbk.path,
|
45
|
+
:cache_path => cache
|
42
46
|
)
|
43
47
|
end
|
44
48
|
if(source)
|
@@ -53,13 +57,15 @@ module Batali
|
|
53
57
|
memoize(:restrictions) do
|
54
58
|
rest = (file.restrict || Smash.new).to_smash
|
55
59
|
file.cookbook.each do |ckbk|
|
56
|
-
if(ckbk.
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
60
|
+
if(auto_path_restrict || ckbk.restrict)
|
61
|
+
if(ckbk.path)
|
62
|
+
rest[ckbk.name] = Smash.new(:path => ckbk.path).checksum
|
63
|
+
elsif(ckbk.git)
|
64
|
+
rest[ckbk.name] = Smash.new(
|
65
|
+
:url => ckbk.git,
|
66
|
+
:ref => ckbk.ref
|
67
|
+
).checksum
|
68
|
+
end
|
63
69
|
end
|
64
70
|
end
|
65
71
|
rest
|
data/lib/batali/utility.rb
CHANGED
@@ -32,12 +32,14 @@ module Batali
|
|
32
32
|
:c_name => :node_name,
|
33
33
|
:c_key => :client_key
|
34
34
|
).each do |local_attr, config_key|
|
35
|
-
unless(self.send(local_attr))
|
35
|
+
unless(self.send(local_attr)) # rubocop:disable Style/RedundantSelf
|
36
36
|
memoize(:knife_configure, :global) do
|
37
37
|
require 'chef/knife'
|
38
38
|
::Chef::Knife.new.configure_chef
|
39
39
|
end
|
40
|
+
# rubocop:disable Style/RedundantSelf
|
40
41
|
debug "Settting #{config_key} from knife configuration file for #{self.class} <#{endpoint}>"
|
42
|
+
# rubocop:disable Style/RedundantSelf
|
41
43
|
self.send("#{local_attr}=", ::Chef::Config[config_key])
|
42
44
|
end
|
43
45
|
end
|
data/lib/batali/version.rb
CHANGED
@@ -2,6 +2,7 @@ require 'batali'
|
|
2
2
|
|
3
3
|
class Chef
|
4
4
|
class Knife
|
5
|
+
# Batali manifest to chef server sync
|
5
6
|
class BataliSync < Knife
|
6
7
|
|
7
8
|
banner 'knife batali sync'
|
@@ -63,7 +64,7 @@ class Chef
|
|
63
64
|
)
|
64
65
|
end
|
65
66
|
if(to_add.empty? && to_remove.empty?)
|
66
|
-
ui.info "#{ui.color('[Batali]', :green, :bold)}: Chef Server Batali Manifest Sync - #{ui.color('No Changes Detected!', :green, :bold)}"
|
67
|
+
ui.info "#{ui.color('[Batali]', :green, :bold)}: Chef Server Batali Manifest Sync - #{ui.color('No Changes Detected!', :green, :bold)}" # rubocop:disable Metrics/LineLength
|
67
68
|
else
|
68
69
|
display_sync_info(
|
69
70
|
:additions => to_add,
|
@@ -74,7 +75,7 @@ class Chef
|
|
74
75
|
ui.confirm 'Sync remote cookbooks with Batali manifest'
|
75
76
|
remove_cookbooks(to_remove) unless to_remove.empty?
|
76
77
|
add_cookbooks(to_add) unless to_add.empty?
|
77
|
-
ui.info "#{ui.color('[Batali]', :green, :bold)}: Chef Server Batali Manifest Sync - #{ui.color('Sync Complete!', :green, :bold)}"
|
78
|
+
ui.info "#{ui.color('[Batali]', :green, :bold)}: Chef Server Batali Manifest Sync - #{ui.color('Sync Complete!', :green, :bold)}" # rubocop:disable Metrics/LineLength
|
78
79
|
else
|
79
80
|
ui.warn 'Dry run requested. No action taken.'
|
80
81
|
end
|
@@ -143,7 +144,7 @@ class Chef
|
|
143
144
|
end
|
144
145
|
end
|
145
146
|
if(Chef::Config[:knife][:batali_show_remaining])
|
146
|
-
ui.info "#{ui.color('[Batali]', :green, :bold)}: Final list of cookbooks to be available on the chef server:"
|
147
|
+
ui.info "#{ui.color('[Batali]', :green, :bold)}: Final list of cookbooks to be available on the chef server:" # rubocop:disable Metrics/LineLength
|
147
148
|
opts[:manifest].sort.each do |name, versions|
|
148
149
|
vers = versions.map do |v|
|
149
150
|
Gem::Version.new(v)
|
@@ -178,7 +179,7 @@ class Chef
|
|
178
179
|
|
179
180
|
def generate_manifest_cookbooks
|
180
181
|
path = File.join(Dir.pwd, 'batali.manifest')
|
181
|
-
unless(File.
|
182
|
+
unless(File.exist?(path))
|
182
183
|
raise "Failed to locate batali manifest at: #{path}"
|
183
184
|
end
|
184
185
|
manifest = Batali::Manifest.build(path)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: batali
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Roberts
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-12-
|
11
|
+
date: 2015-12-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: attribute_struct
|
@@ -128,6 +128,34 @@ dependencies:
|
|
128
128
|
- - ">="
|
129
129
|
- !ruby/object:Gem::Version
|
130
130
|
version: '0'
|
131
|
+
- !ruby/object:Gem::Dependency
|
132
|
+
name: rake
|
133
|
+
requirement: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0'
|
138
|
+
type: :development
|
139
|
+
prerelease: false
|
140
|
+
version_requirements: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
- !ruby/object:Gem::Dependency
|
146
|
+
name: rubocop
|
147
|
+
requirement: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - ">="
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: '0'
|
152
|
+
type: :development
|
153
|
+
prerelease: false
|
154
|
+
version_requirements: !ruby/object:Gem::Requirement
|
155
|
+
requirements:
|
156
|
+
- - ">="
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: '0'
|
131
159
|
- !ruby/object:Gem::Dependency
|
132
160
|
name: minitest
|
133
161
|
requirement: !ruby/object:Gem::Requirement
|