batali 0.2.10 → 0.2.12
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +22 -0
- data/batali.gemspec +1 -1
- data/lib/batali/b_file.rb +151 -0
- data/lib/batali/command/install.rb +1 -1
- data/lib/batali/command/resolve.rb +1 -1
- data/lib/batali/command/update.rb +4 -2
- data/lib/batali/command.rb +6 -2
- data/lib/batali/git.rb +1 -1
- data/lib/batali/origin/remote_site.rb +1 -1
- data/lib/batali/source/path.rb +23 -1
- data/lib/batali/source/site.rb +1 -1
- data/lib/batali/version.rb +1 -1
- metadata +4 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa18c8e69b93424e57b8317616ce7724cb9978ef
|
4
|
+
data.tar.gz: 7f1399c6617d115a1d80150e955872c90ea7bcce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab46ecf666ecb4e50e8a235cfb67eb5b6288d4e0b0292854eb6ca6252b5abc54ca3ed1bcc1091962f9d96d53768bc51812fdef57e10e5ab2996c8803f7d4196b
|
7
|
+
data.tar.gz: ab32f312eade8efe395430641ae97539fe05e21b255b8a27149a19e946a4b7c00ae04c58615f17f1e8e81b29125aa771e211e88d68fdcb4f808eba66875f51e8
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
# v0.2.12
|
2
|
+
* Update home directory path generation to use `Dir.home`
|
3
|
+
* Detect resolution type from manifest files
|
4
|
+
* Add support for chefignore file (also allows `.chefignore`)
|
5
|
+
* Introduce automatic cookbook constraint detection
|
6
|
+
|
1
7
|
# v0.2.10
|
2
8
|
* Parse full metadata file on path sources to properly discover all deps (#26)
|
3
9
|
* Allow source to be optionally defined for Units
|
data/README.md
CHANGED
@@ -235,6 +235,28 @@ the dry run option to see what upgrades are available without actually changing
|
|
235
235
|
$ batali resolve --no-least-impact --dry-run
|
236
236
|
```
|
237
237
|
|
238
|
+
### Automatic cookbook discovery
|
239
|
+
|
240
|
+
Tired of tracking constraints in multiple places when using Chef Environment `cookbook_versions`
|
241
|
+
for environment specific constraints? Let Batali manage it for you! Define your `Batali` file
|
242
|
+
to enable automatic discovery:
|
243
|
+
|
244
|
+
```ruby
|
245
|
+
Batali.define do
|
246
|
+
source 'https://example.com'
|
247
|
+
discover true
|
248
|
+
end
|
249
|
+
```
|
250
|
+
|
251
|
+
That's it! Now you can resolve for the infrastructure:
|
252
|
+
|
253
|
+
```
|
254
|
+
$ batali resolve --infrastructure
|
255
|
+
```
|
256
|
+
|
257
|
+
which will generate a resulting manifest that includes all required cookbook versions to
|
258
|
+
satisfiy constraints defined by all environments.
|
259
|
+
|
238
260
|
## Configuration
|
239
261
|
|
240
262
|
Batali can be configured via the `.batali` file. The contents of the file can be in YAML,
|
data/batali.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.require_path = 'lib'
|
12
12
|
s.license = 'Apache 2.0'
|
13
13
|
s.add_runtime_dependency 'attribute_struct', '~> 0.2.14'
|
14
|
-
s.add_runtime_dependency 'grimoire', '~> 0.2.
|
14
|
+
s.add_runtime_dependency 'grimoire', '~> 0.2.6'
|
15
15
|
s.add_runtime_dependency 'bogo', '~> 0.1.20'
|
16
16
|
s.add_runtime_dependency 'bogo-cli', '~> 0.1.18'
|
17
17
|
s.add_runtime_dependency 'bogo-config', '~> 0.1.10'
|
data/lib/batali/b_file.rb
CHANGED
@@ -84,6 +84,7 @@ module Batali
|
|
84
84
|
attribute :cookbook, Cookbook, :multiple => true, :required => true, :coerce => BFile.cookbook_coerce
|
85
85
|
end
|
86
86
|
|
87
|
+
attribute :discover, [TrueClass, FalseClass], :required => true, :default => false
|
87
88
|
attribute :restrict, Restriction, :multiple => true, :coerce => lambda{|v|
|
88
89
|
Restriction.new(:cookbook => v.first, :source => v.last.to_smash[:source])
|
89
90
|
}
|
@@ -104,6 +105,156 @@ module Batali
|
|
104
105
|
ckbk
|
105
106
|
}
|
106
107
|
|
108
|
+
# Search environments for cookbooks and restraints
|
109
|
+
#
|
110
|
+
# @return [TrueClass]
|
111
|
+
def auto_discover!(environment=nil)
|
112
|
+
debug 'Starting cookbook auto-discovery'
|
113
|
+
unless(discover)
|
114
|
+
raise 'Attempting to perform auto-discovery but auto-discovery is not enabled!'
|
115
|
+
end
|
116
|
+
environment_items = Dir.glob(File.join(File.dirname(path), 'environments', '*.{json,rb}')).map do |e_path|
|
117
|
+
result = parse_environment(e_path)
|
118
|
+
if(result[:name] && result[:cookbooks])
|
119
|
+
Smash.new(
|
120
|
+
result[:name] => result[:cookbooks]
|
121
|
+
)
|
122
|
+
end
|
123
|
+
end.compact.inject(Smash.new){|m,n| m.merge(n)}
|
124
|
+
environment_items.each do |e_name, items|
|
125
|
+
next if environment && e_name != environment
|
126
|
+
debug "Discovery processing of environment: #{e_name}"
|
127
|
+
items.each do |ckbk_name, constraints|
|
128
|
+
ckbk = cookbook.detect do |c|
|
129
|
+
c.name == ckbk_name
|
130
|
+
end
|
131
|
+
if(ckbk)
|
132
|
+
new_constraints = ckbk.constraint.dup
|
133
|
+
new_constraints += constraints
|
134
|
+
requirement = UnitRequirement.new(*new_constraints)
|
135
|
+
new_constraints = flatten_constraints(requirement.requirements)
|
136
|
+
debug "Discovery merged constraints for #{ckbk.name}: #{new_constraints.inspect}"
|
137
|
+
ckbk.constraint.replace(new_constraints)
|
138
|
+
else
|
139
|
+
debug "Discovery added cookbook #{ckbk_name}: #{constraints.inspect}"
|
140
|
+
cookbook.push(
|
141
|
+
Cookbook.new(
|
142
|
+
:name => ckbk_name,
|
143
|
+
:constraint => constraints
|
144
|
+
)
|
145
|
+
)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
debug 'Completed cookbook auto-discovery'
|
150
|
+
true
|
151
|
+
end
|
152
|
+
|
153
|
+
protected
|
154
|
+
|
155
|
+
# Convert constraint for merging
|
156
|
+
#
|
157
|
+
# @param constraint [String]
|
158
|
+
# @param [Array<String>]
|
159
|
+
def convert_constraint(constraint)
|
160
|
+
comp, ver = constraint.split(' ', 2).map(&:strip)
|
161
|
+
if(comp == '~>')
|
162
|
+
ver = UnitVersion.new(ver)
|
163
|
+
[">= #{ver}", "< #{ver.bump}"]
|
164
|
+
else
|
165
|
+
[constraint]
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# Consume list of constraints and generate compressed list that
|
170
|
+
# satisfies all defined constraints.
|
171
|
+
#
|
172
|
+
# @param constraints [Array<Array<String, UnitVersion>>]
|
173
|
+
# @return [Array<Array<String, UnitVersion>>]
|
174
|
+
# @note if an explict constraint is provided, only it will be
|
175
|
+
# returned
|
176
|
+
def flatten_constraints(constraints)
|
177
|
+
grouped = constraints.group_by(&:first)
|
178
|
+
grouped = Smash[
|
179
|
+
grouped.map do |comp, items|
|
180
|
+
versions = items.map(&:last)
|
181
|
+
if(comp.start_with?('>'))
|
182
|
+
[comp, [versions.min]]
|
183
|
+
elsif(comp.start_with?('<'))
|
184
|
+
[comp, [versions.max]]
|
185
|
+
else
|
186
|
+
[comp, versions]
|
187
|
+
end
|
188
|
+
end
|
189
|
+
]
|
190
|
+
if(grouped['='])
|
191
|
+
grouped['>='] ||= []
|
192
|
+
grouped['<='] ||= []
|
193
|
+
grouped['='].each do |ver|
|
194
|
+
grouped['>='] << ver
|
195
|
+
grouped['<='] << ver
|
196
|
+
end
|
197
|
+
grouped.delete('=')
|
198
|
+
end
|
199
|
+
if(grouped['>'] || grouped['>='])
|
200
|
+
if(grouped['>='] && (grouped['>'].nil? || grouped['>='].min <= grouped['>'].min))
|
201
|
+
grouped['>='] = [grouped['>='].min]
|
202
|
+
grouped.delete('>')
|
203
|
+
else
|
204
|
+
grouped['>'] = [grouped['>'].min]
|
205
|
+
grouped.delete('>=')
|
206
|
+
end
|
207
|
+
end
|
208
|
+
if(grouped['<'] || grouped['<='])
|
209
|
+
if(grouped['<='] && (grouped['<'].nil? || grouped['<='].max >= grouped['<'].max))
|
210
|
+
grouped['<='] = [grouped['<='].max]
|
211
|
+
grouped.delete('<')
|
212
|
+
else
|
213
|
+
grouped['<'] = [grouped['<'].max]
|
214
|
+
grouped.delete('<=')
|
215
|
+
end
|
216
|
+
end
|
217
|
+
grouped.map do |comp, vers|
|
218
|
+
vers.map do |version|
|
219
|
+
"#{comp} #{version}"
|
220
|
+
end
|
221
|
+
end.flatten
|
222
|
+
end
|
223
|
+
|
224
|
+
# Read environment file and return defined cookbook constraints
|
225
|
+
#
|
226
|
+
# @param path [String] path to environment
|
227
|
+
# @return [Smash]
|
228
|
+
def parse_environment(path)
|
229
|
+
case File.extname(path)
|
230
|
+
when '.json'
|
231
|
+
env = MultiJson.load(
|
232
|
+
File.read(path)
|
233
|
+
).to_smash
|
234
|
+
when '.rb'
|
235
|
+
struct = Struct.new
|
236
|
+
struct.set_state!(:value_collapse => true)
|
237
|
+
struct.instance_eval(File.read(path), path, 1)
|
238
|
+
env = struct._dump.to_smash
|
239
|
+
else
|
240
|
+
raise "Unexpected file format encountered! (#{File.extname(path)})"
|
241
|
+
end
|
242
|
+
Smash.new(
|
243
|
+
:name => env[:name],
|
244
|
+
:cookbooks => Smash[
|
245
|
+
env.fetch(
|
246
|
+
:cookbook_versions,
|
247
|
+
Smash.new
|
248
|
+
).map{|k,v| [k, v.to_s.split(',')]}
|
249
|
+
]
|
250
|
+
)
|
251
|
+
end
|
252
|
+
|
253
|
+
# Proxy debug output
|
254
|
+
def debug(s)
|
255
|
+
Batali.debug(s)
|
256
|
+
end
|
257
|
+
|
107
258
|
end
|
108
259
|
|
109
260
|
end
|
@@ -28,7 +28,7 @@ module Batali
|
|
28
28
|
end
|
29
29
|
asset_path = unit.source.asset
|
30
30
|
final_path = File.join(install_path, unit.name)
|
31
|
-
if(config[:infrastructure])
|
31
|
+
if(config[:infrastructure] || (config[:infrastructure].nil? && manifest.infrastructure))
|
32
32
|
final_path << "-#{unit.version}"
|
33
33
|
end
|
34
34
|
begin
|
@@ -29,7 +29,7 @@ module Batali
|
|
29
29
|
:system => system,
|
30
30
|
:score_keeper => score_keeper
|
31
31
|
)
|
32
|
-
if(config[:infrastructure])
|
32
|
+
if(config[:infrastructure] || (config[:infrastructure].nil? && manifest.infrastructure))
|
33
33
|
infrastructure_resolution(solv)
|
34
34
|
else
|
35
35
|
single_path_resolution(solv)
|
@@ -7,8 +7,10 @@ module Batali
|
|
7
7
|
class Update < Batali::Command
|
8
8
|
|
9
9
|
def execute!
|
10
|
-
Resolve.new(
|
11
|
-
|
10
|
+
Resolve.new(opts.merge(:ui => ui), arguments).execute!
|
11
|
+
if(opts[:install])
|
12
|
+
Install.new(opts.merge(:ui => ui, :install => {}), arguments).execute!
|
13
|
+
end
|
12
14
|
end
|
13
15
|
|
14
16
|
end
|
data/lib/batali/command.rb
CHANGED
@@ -26,7 +26,11 @@ module Batali
|
|
26
26
|
# TODO: Add directory traverse searching
|
27
27
|
path = config.fetch(:file, File.join(Dir.pwd, 'Batali'))
|
28
28
|
ui.verbose "Loading Batali file from: #{path}"
|
29
|
-
BFile.new(path)
|
29
|
+
bfile = BFile.new(path)
|
30
|
+
if(bfile.discover)
|
31
|
+
bfile.auto_discover!
|
32
|
+
end
|
33
|
+
bfile
|
30
34
|
end
|
31
35
|
end
|
32
36
|
|
@@ -46,7 +50,7 @@ module Batali
|
|
46
50
|
# @return [String] path to local cache
|
47
51
|
def cache_directory(*args)
|
48
52
|
memoize(['cache_directory', *args].join('_')) do
|
49
|
-
directory = config.fetch(:cache_directory, File.
|
53
|
+
directory = config.fetch(:cache_directory, File.join(Dir.home, '.batali/cache'))
|
50
54
|
ui.debug "Cache directory to persist cookbooks: #{directory}"
|
51
55
|
unless(args.empty?)
|
52
56
|
directory = File.join(directory, *args.map(&:to_s))
|
data/lib/batali/git.rb
CHANGED
@@ -47,7 +47,7 @@ module Batali
|
|
47
47
|
klass.class_eval do
|
48
48
|
attribute :url, String, :required => true, :equivalent => true
|
49
49
|
attribute :ref, String, :required => true, :equivalent => true
|
50
|
-
attribute :cache, String, :default => File.
|
50
|
+
attribute :cache, String, :default => File.join(Dir.home, '.batali/cache/git')
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
@@ -19,7 +19,7 @@ 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.
|
22
|
+
attribute :cache, String, :default => File.join(Dir.home, '.batali/cache/remote_site'), :required => true
|
23
23
|
|
24
24
|
def initialize(*_)
|
25
25
|
super
|
data/lib/batali/source/path.rb
CHANGED
@@ -8,6 +8,11 @@ module Batali
|
|
8
8
|
# Path based source
|
9
9
|
class Path < Source
|
10
10
|
|
11
|
+
# @return [Array<String>] default ignore globs
|
12
|
+
DEFAULT_IGNORE = ['.git*']
|
13
|
+
# @return [Array<String>] valid ignore file names
|
14
|
+
IGNORE_FILE = ['chefignore', '.chefignore']
|
15
|
+
|
11
16
|
include Bogo::Memoization
|
12
17
|
|
13
18
|
attribute :path, String, :required => true, :equivalent => true
|
@@ -16,7 +21,24 @@ module Batali
|
|
16
21
|
def asset
|
17
22
|
memoize(:asset) do
|
18
23
|
dir = Dir.mktmpdir
|
19
|
-
|
24
|
+
chefignore = IGNORE_FILE.map do |c_name|
|
25
|
+
c_path = File.join(path, c_name)
|
26
|
+
c_path if File.exists?(c_path)
|
27
|
+
end.compact.first
|
28
|
+
chefignore = chefignore ? File.readlines(chefignore) : []
|
29
|
+
chefignore += DEFAULT_IGNORE
|
30
|
+
chefignore.uniq!
|
31
|
+
files_to_copy = Dir.glob(File.join(path, '{.[^.]*,**}', '**', '{*,*.*,.*}'))
|
32
|
+
files_to_copy = files_to_copy.map do |file_path|
|
33
|
+
next unless File.file?(file_path)
|
34
|
+
relative_path = file_path.sub("#{path}/", '')
|
35
|
+
relative_path unless chefignore.detect{|ig| File.fnmatch(ig, relative_path)}
|
36
|
+
end.compact
|
37
|
+
files_to_copy.each do |relative_path|
|
38
|
+
new_path = File.join(dir, relative_path)
|
39
|
+
FileUtils.mkdir_p(File.dirname(new_path))
|
40
|
+
FileUtils.cp(File.join(path, relative_path), new_path)
|
41
|
+
end
|
20
42
|
dir
|
21
43
|
end
|
22
44
|
end
|
data/lib/batali/source/site.rb
CHANGED
@@ -44,7 +44,7 @@ module Batali
|
|
44
44
|
def cache_directory
|
45
45
|
memoize(:cache_directory) do
|
46
46
|
unless(@cache)
|
47
|
-
@cache = File.
|
47
|
+
@cache = File.join(Dir.home, '.batali/cache/remote_site')
|
48
48
|
end
|
49
49
|
['entitystore', 'metastore'].each do |leaf|
|
50
50
|
FileUtils.mkdir_p(File.join(cache, leaf))
|
data/lib/batali/version.rb
CHANGED
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.2.
|
4
|
+
version: 0.2.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-
|
11
|
+
date: 2015-06-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: attribute_struct
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.2.
|
33
|
+
version: 0.2.6
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.2.
|
40
|
+
version: 0.2.6
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: bogo
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -228,4 +228,3 @@ signing_key:
|
|
228
228
|
specification_version: 4
|
229
229
|
summary: Magic
|
230
230
|
test_files: []
|
231
|
-
has_rdoc:
|