batali 0.3.10 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bc79c37709d9a82123b18ff7f3708d3ab3090747
4
- data.tar.gz: d71675d5533528818ffdafe8a2b7727ae7d20566
3
+ metadata.gz: 011f26a3e8a17db988eb207d7fc79cbdc51e1306
4
+ data.tar.gz: e0bd881f9cf5be081f73c315e6be9ee50a206ff7
5
5
  SHA512:
6
- metadata.gz: e745bf572287f0c86144b03a55493f0de0f8954762664d5165e2cce579bffb80742af7f22c4ac9881fe06519a459b619f922cb7f8c7390cb3d59f62ca7dfc042
7
- data.tar.gz: 6dcb427899adfbc5c7d9e7c9b5b2cb1900a52e98e27511c357f4287b53c94a2698c26ffad5d44efab9cf7df2d66d2f74286ebaac93c0e1d74bc75128de531b96
6
+ metadata.gz: dc6e7955b3163d94389ee1b71b61ce63651ea760f39e4061682f8fbb91505642129159252e95d851e3ae6cae6b6600d1bebf9f580adad9613e358ed1ef082abb
7
+ data.tar.gz: fa4b45f0b1c202a9ada821e6d64456c78316b21b52e969281f7ef6fbc07a9395aec2209dea78b724035430445f9b9498ea0c39ec657a0805d389be7af31811d3
@@ -1,3 +1,7 @@
1
+ # v0.3.12
2
+ * [feature] Support multiple sources for single cookbook in infra-mode
3
+ * [fix] Make cache directory usage consistent in all commands
4
+
1
5
  # v0.3.10
2
6
  * [feature] Chef server manifest sync knife plugin
3
7
 
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
@@ -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'
@@ -2,6 +2,7 @@ require 'bogo-cli'
2
2
  require 'grimoire'
3
3
  require 'batali/monkey'
4
4
 
5
+ # Batali namespace
5
6
  module Batali
6
7
 
7
8
  autoload :BFile, 'batali/b_file'
@@ -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
@@ -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)
@@ -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 "No cookbooks defined within manifest! Try resolving first. (`batali resolve`)"
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?(:cache))
25
- unit.source.cache = cache_directory(
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}" , :yellow)
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
@@ -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(cache, Base64.urlsafe_encode64(url))
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(cache, ref)
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
- self.path
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
 
@@ -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.exists?(path))
20
- self.new(Bogo::Config.new(path).data.merge(:path => path))
19
+ if(File.exist?(path))
20
+ new(Bogo::Config.new(path).data.merge(:path => path))
21
21
  else
22
- self.new(:path => path)
22
+ new(:path => path)
23
23
  end
24
24
  end
25
25
 
@@ -1,11 +1,15 @@
1
1
  require 'batali'
2
2
  require 'bogo/http_proxy'
3
3
 
4
+ # Batali namespace
4
5
  module Batali
5
- # Simple stubs mostly for naming
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,
@@ -10,6 +10,7 @@ module Batali
10
10
  autoload :Path, 'batali/origin/path'
11
11
 
12
12
  attribute :name, String, :required => true
13
+ attribute :cache_path, String, :required => true
13
14
  attribute :identifier, String
14
15
 
15
16
  # @return [Array<Unit>] all units
@@ -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 = self.identifier
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
@@ -18,7 +18,7 @@ module Batali
18
18
  :subdirectory => subdirectory
19
19
  ).checksum
20
20
  unless(name?)
21
- self.name = self.identifier
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
@@ -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 = self.identifier
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.exists?(json = File.join(path, 'metadata.json')))
78
+ if(File.exist?(json = File.join(path, 'metadata.json')))
77
79
  MultiJson.load(json).to_smash
78
- elsif(File.exists?(rb = File.join(path, 'metadata.rb')))
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 = self.identifier
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(cache, identifier)
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.exists?(universe_path))
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 :requirements, [Batali::UnitDependency, Grimoire::DEPENDENCY_CLASS], :multiple => true, :default => [], :coerce => lambda{|v| Batali::UnitDependency.new(val.first, *val.last)}
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
@@ -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 = 10000000
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 = 10000000 if new_world_unit
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 = 1000000
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
- pos = UnitRequirement.new("~> #{manifest_unit.version.segments.slice(0,2).join('.')}").satisfied_by?(unit.version) ? 1 : 0
49
- multi_val = pos == 1 ? 1000 : 100
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 = 10000000 if new_world_unit
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, pos|
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.push (2 - (1.0 / val)) * ((pos + 1)**10)
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
@@ -9,7 +9,15 @@ module Batali
9
9
  autoload :Git, 'batali/source/git'
10
10
  autoload :ChefServer, 'batali/source/chef_server'
11
11
 
12
- attribute :type, String, :required => true, :default => lambda{ self.name }
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(self.respond_to?(:cache))
32
- false
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
- if(File.exists?(asset_path))
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 = [self.name, Bogo::Utility.camel(type)].join('::')
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
- unless(@cache)
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.has_key?(segment))
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))
@@ -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.exists?(c_path)
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
@@ -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
- unless(@cache)
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
@@ -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
- "I got 99 problems but a policyfile ain't one",
7
- "Solve the way you want, not the way you're told",
8
- "Build environments, not applications",
9
- "DRY should be the rule, not the exception",
10
- "Solve for the forest, not just a tree"
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
@@ -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 :dependencies, [Batali::UnitDependency, Grimoire::DEPENDENCY_CLASS], :multiple => true, :default => [], :coerce => lambda{|val| Batali::UnitDependency.new(val.first, *val.last)}
8
- attribute :version, [Batali::UnitVersion, Grimoire::VERSION_CLASS], :required => true, :coerce => lambda{|val| Batali::UnitVersion.new(val)}
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(self.send(k) == u.send(k))
25
- _diff[k] = [self.send(k), u.send(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)
@@ -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
- :cache => cache
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.path)
57
- rest[ckbk.name] = Smash.new(:path => ckbk.path).checksum
58
- elsif(ckbk.git)
59
- rest[ckbk.name] = Smash.new(
60
- :url => ckbk.git,
61
- :ref => ckbk.ref
62
- ).checksum
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
@@ -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
@@ -1,4 +1,5 @@
1
+ # Batali namespace
1
2
  module Batali
2
3
  # Current version
3
- VERSION = Gem::Version.new('0.3.10')
4
+ VERSION = Gem::Version.new('0.3.12')
4
5
  end
@@ -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.exists?(path))
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.10
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-19 00:00:00.000000000 Z
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