batali 0.4.10 → 0.5.0
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 +5 -5
- data/CHANGELOG.md +5 -0
- data/CONTRIBUTING.md +2 -2
- data/LICENSE +1 -1
- data/README.md +6 -5
- data/batali.gemspec +26 -25
- data/bin/batali +1 -0
- data/lib/batali.rb +23 -26
- data/lib/batali/b_file.rb +116 -98
- data/lib/batali/chefspec.rb +14 -16
- data/lib/batali/command.rb +32 -27
- data/lib/batali/command/cache.rb +9 -11
- data/lib/batali/command/configure.rb +1 -3
- data/lib/batali/command/display.rb +2 -4
- data/lib/batali/command/install.rb +13 -15
- data/lib/batali/command/resolve.rb +49 -51
- data/lib/batali/command/supermarket.rb +42 -45
- data/lib/batali/command/update.rb +2 -5
- data/lib/batali/config.rb +1 -2
- data/lib/batali/git.rb +10 -11
- data/lib/batali/manifest.rb +5 -6
- data/lib/batali/monkey.rb +6 -4
- data/lib/batali/origin.rb +12 -9
- data/lib/batali/origin/chef_server.rb +12 -14
- data/lib/batali/origin/git.rb +7 -9
- data/lib/batali/origin/path.rb +14 -15
- data/lib/batali/origin/remote_site.rb +17 -18
- data/lib/batali/requirement_list.rb +6 -7
- data/lib/batali/score_keeper.rb +12 -13
- data/lib/batali/source.rb +19 -21
- data/lib/batali/source/chef_server.rb +8 -10
- data/lib/batali/source/git.rb +11 -7
- data/lib/batali/source/path.rb +16 -12
- data/lib/batali/source/site.rb +23 -25
- data/lib/batali/tag_lines.rb +4 -5
- data/lib/batali/unit.rb +13 -16
- data/lib/batali/unit_loader.rb +12 -15
- data/lib/batali/utility.rb +42 -14
- data/lib/batali/version.rb +1 -1
- data/lib/chef/knife/batali_sync.rb +66 -72
- metadata +29 -16
data/lib/batali/origin/path.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "batali"
|
2
2
|
|
3
3
|
module Batali
|
4
4
|
class Origin
|
@@ -13,7 +13,7 @@ module Batali
|
|
13
13
|
# @return [Constant]
|
14
14
|
def self.const_missing(const)
|
15
15
|
[::Object, ::ObjectSpace].map do |root|
|
16
|
-
if
|
16
|
+
if root.const_defined?(const)
|
17
17
|
root.const_get(const)
|
18
18
|
end
|
19
19
|
end.compact.first || super
|
@@ -23,7 +23,6 @@ module Batali
|
|
23
23
|
set!(:depends, args)
|
24
24
|
self
|
25
25
|
end
|
26
|
-
|
27
26
|
end
|
28
27
|
|
29
28
|
include Bogo::Memoization
|
@@ -32,8 +31,9 @@ module Batali
|
|
32
31
|
|
33
32
|
def initialize(*_)
|
34
33
|
super
|
34
|
+
self.path = Utility.clean_path(path)
|
35
35
|
self.identifier = Smash.new(:path => path).checksum
|
36
|
-
unless
|
36
|
+
unless name?
|
37
37
|
self.name = identifier
|
38
38
|
end
|
39
39
|
end
|
@@ -42,16 +42,16 @@ module Batali
|
|
42
42
|
def units
|
43
43
|
memoize(:units) do
|
44
44
|
info = load_metadata
|
45
|
-
if
|
46
|
-
unless
|
45
|
+
if info[:depends]
|
46
|
+
unless info[:depends].first.is_a?(Array)
|
47
47
|
info[:depends] = [info[:depends]]
|
48
48
|
end
|
49
49
|
info[:depends] = info[:depends].map do |dep|
|
50
50
|
case dep
|
51
51
|
when String
|
52
|
-
[dep,
|
52
|
+
[dep, "> 0"]
|
53
53
|
else
|
54
|
-
dep.size == 1 ? dep.push(
|
54
|
+
dep.size == 1 ? dep.push("> 0") : dep
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
@@ -65,9 +65,9 @@ module Batali
|
|
65
65
|
:version => info[:version],
|
66
66
|
:path => path,
|
67
67
|
:dependencies => info.fetch(:depends, []),
|
68
|
-
:cache_path => cache_path
|
69
|
-
)
|
70
|
-
)
|
68
|
+
:cache_path => cache_path,
|
69
|
+
),
|
70
|
+
),
|
71
71
|
]
|
72
72
|
end
|
73
73
|
end
|
@@ -75,9 +75,9 @@ module Batali
|
|
75
75
|
# @return [Smash] metadata information
|
76
76
|
def load_metadata
|
77
77
|
memoize(:metadata) do
|
78
|
-
if
|
79
|
-
MultiJson.load(json).to_smash
|
80
|
-
elsif
|
78
|
+
if File.exist?(json = File.join(path, "metadata.json"))
|
79
|
+
MultiJson.load(File.read(json)).to_smash
|
80
|
+
elsif File.exist?(rb = File.join(path, "metadata.rb"))
|
81
81
|
struct = Metadata.new
|
82
82
|
struct.set_state!(:value_collapse => true)
|
83
83
|
struct.instance_eval(File.read(rb), rb, 1)
|
@@ -87,7 +87,6 @@ module Batali
|
|
87
87
|
end
|
88
88
|
end
|
89
89
|
end
|
90
|
-
|
91
90
|
end
|
92
91
|
end
|
93
92
|
end
|
@@ -1,8 +1,8 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
1
|
+
require "batali"
|
2
|
+
require "digest/sha2"
|
3
|
+
require "securerandom"
|
4
|
+
require "http"
|
5
|
+
require "fileutils"
|
6
6
|
|
7
7
|
module Batali
|
8
8
|
class Origin
|
@@ -10,7 +10,7 @@ module Batali
|
|
10
10
|
class RemoteSite < Origin
|
11
11
|
|
12
12
|
# Site suffix for API endpoint
|
13
|
-
API_SUFFIX =
|
13
|
+
API_SUFFIX = "api/v1/"
|
14
14
|
|
15
15
|
include Bogo::Memoization
|
16
16
|
|
@@ -25,7 +25,7 @@ module Batali
|
|
25
25
|
# NOTE: We currently don't require API_SUFFIX information
|
26
26
|
# self.endpoint = URI.join(endpoint, API_SUFFIX).to_s
|
27
27
|
self.identifier = Digest::SHA256.hexdigest(endpoint)
|
28
|
-
unless
|
28
|
+
unless name?
|
29
29
|
self.name = identifier
|
30
30
|
end
|
31
31
|
end
|
@@ -33,7 +33,7 @@ module Batali
|
|
33
33
|
# @return [String] cache directory path
|
34
34
|
def cache_directory
|
35
35
|
memoize(:cache_directory) do
|
36
|
-
c_path =
|
36
|
+
c_path = Utility.join_path(cache_path, "remote_site", identifier)
|
37
37
|
FileUtils.mkdir_p(c_path)
|
38
38
|
c_path
|
39
39
|
end
|
@@ -53,8 +53,8 @@ module Batali
|
|
53
53
|
:url => info[:download_url],
|
54
54
|
:version => version,
|
55
55
|
:dependencies => info[:dependencies],
|
56
|
-
:cache_path => cache_path
|
57
|
-
)
|
56
|
+
:cache_path => cache_path,
|
57
|
+
),
|
58
58
|
)
|
59
59
|
end
|
60
60
|
end.flatten
|
@@ -76,17 +76,17 @@ module Batali
|
|
76
76
|
def fetch
|
77
77
|
do_fetch = true
|
78
78
|
cache_directory # init directory creation
|
79
|
-
if
|
79
|
+
if File.exist?(universe_path)
|
80
80
|
age = Time.now - File.mtime(universe_path)
|
81
|
-
if
|
81
|
+
if age < update_interval
|
82
82
|
do_fetch = false
|
83
83
|
end
|
84
84
|
end
|
85
|
-
if
|
85
|
+
if do_fetch
|
86
86
|
t_uni = "#{universe_path}.#{SecureRandom.urlsafe_base64}"
|
87
|
-
result = HTTP.get(URI.join(endpoint,
|
88
|
-
File.open(t_uni,
|
89
|
-
while
|
87
|
+
result = HTTP.get(URI.join(endpoint, "universe"))
|
88
|
+
File.open(t_uni, "w") do |file|
|
89
|
+
while content = result.body.readpartial(2048)
|
90
90
|
file.write content
|
91
91
|
end
|
92
92
|
end
|
@@ -97,9 +97,8 @@ module Batali
|
|
97
97
|
|
98
98
|
# @return [String] path to universe file
|
99
99
|
def universe_path
|
100
|
-
|
100
|
+
Utility.join_path(cache_directory, "universe.json")
|
101
101
|
end
|
102
|
-
|
103
102
|
end
|
104
103
|
end
|
105
104
|
end
|
@@ -1,15 +1,14 @@
|
|
1
|
-
require
|
1
|
+
require "batali"
|
2
2
|
|
3
3
|
# Batali namespace
|
4
4
|
module Batali
|
5
5
|
# Customized Unit
|
6
6
|
class RequirementList < Grimoire::RequirementList
|
7
7
|
attribute(:requirements, [Batali::UnitDependency, Grimoire::DEPENDENCY_CLASS],
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
)
|
8
|
+
:multiple => true,
|
9
|
+
:default => [],
|
10
|
+
:coerce => lambda { |v|
|
11
|
+
Batali::UnitDependency.new(val.first, *val.last)
|
12
|
+
})
|
14
13
|
end
|
15
14
|
end
|
data/lib/batali/score_keeper.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "batali"
|
2
2
|
|
3
3
|
module Batali
|
4
4
|
# Provide scores for units
|
@@ -9,7 +9,7 @@ module Batali
|
|
9
9
|
:preferred => 10_000_000,
|
10
10
|
:patch => 1_000_000,
|
11
11
|
:minor => 1_000,
|
12
|
-
:major => 100
|
12
|
+
:major => 100,
|
13
13
|
}
|
14
14
|
|
15
15
|
attribute :manifest, Manifest, :required => true
|
@@ -27,17 +27,17 @@ module Batali
|
|
27
27
|
# @param idx [Integer] current index location
|
28
28
|
# @return [Numeric, NilClass]
|
29
29
|
def score_for(unit, *args)
|
30
|
-
opts = args.detect{|a| a.is_a?(Hash)} || {}
|
30
|
+
opts = args.detect { |a| a.is_a?(Hash) } || {}
|
31
31
|
multiplier = 1
|
32
32
|
manifest_unit = manifest.cookbook.detect do |m_unit|
|
33
33
|
m_unit.name == unit.name
|
34
34
|
end
|
35
|
-
if
|
35
|
+
if manifest_unit
|
36
36
|
# If the unit version matches the manifest version, this
|
37
37
|
# should be _the_ preferred version
|
38
|
-
if
|
38
|
+
if manifest_unit.version == unit.version
|
39
39
|
multiplier = MULTIPLIERS[:preferred]
|
40
|
-
elsif
|
40
|
+
elsif opts[:solver] && opts[:solver].new_world
|
41
41
|
new_world_unit = opts[:solver].new_world.units.detect do |n_unit|
|
42
42
|
n_unit.name == unit.name &&
|
43
43
|
n_unit.version == unit.version
|
@@ -46,7 +46,7 @@ module Batali
|
|
46
46
|
else
|
47
47
|
# If the unit version satisfies within the patch segment of
|
48
48
|
# the manifest version score those versions highest for upgrade
|
49
|
-
if
|
49
|
+
if UnitRequirement.new("~> #{manifest_unit.version}").satisfied_by?(unit.version)
|
50
50
|
multiplier = MULTIPLIERS[:patch]
|
51
51
|
else
|
52
52
|
# If the unit version satisfies within the minor or major
|
@@ -54,12 +54,12 @@ module Batali
|
|
54
54
|
# value up (with satisfaction within minor segment being
|
55
55
|
# worth more than satisfaction within major segment)
|
56
56
|
satisfied = UnitRequirement.new(
|
57
|
-
"~> #{manifest_unit.version.segments.slice(0, 2).join(
|
57
|
+
"~> #{manifest_unit.version.segments.slice(0, 2).join(".")}"
|
58
58
|
).satisfied_by?(unit.version)
|
59
59
|
pos = satisfied ? 1 : 0
|
60
60
|
multi_val = pos == 1 ? MULTIPLIERS[:minor] : MULTIPLIERS[:major]
|
61
61
|
distance = (manifest_unit.version.segments[pos] - unit.version.segments[pos])
|
62
|
-
if
|
62
|
+
if distance > 0
|
63
63
|
distance = 1.0 / distance
|
64
64
|
else
|
65
65
|
distance = 0
|
@@ -68,7 +68,7 @@ module Batali
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
else
|
71
|
-
if
|
71
|
+
if opts[:solver] && opts[:solver].new_world
|
72
72
|
new_world_unit = opts[:solver].new_world.units.detect do |n_unit|
|
73
73
|
n_unit.name == unit.name &&
|
74
74
|
n_unit.version == unit.version
|
@@ -80,10 +80,10 @@ module Batali
|
|
80
80
|
# Generate a "value" for each segment of the version with
|
81
81
|
# growing importance (major > minor > patch)
|
82
82
|
unit.version.segments.reverse.each_with_index.map do |val, v_pos|
|
83
|
-
if
|
83
|
+
if val == 0
|
84
84
|
score.push 0
|
85
85
|
else
|
86
|
-
score << (2 - (1.0 / val)) * ((v_pos + 1)**10)
|
86
|
+
score << (2 - (1.0 / val)) * ((v_pos + 1) ** 10)
|
87
87
|
end
|
88
88
|
end
|
89
89
|
# Sum the score for each segment to provide the score for the
|
@@ -94,6 +94,5 @@ module Batali
|
|
94
94
|
debug "Score <#{unit.name}:#{unit.version}>: #{score}"
|
95
95
|
score
|
96
96
|
end
|
97
|
-
|
98
97
|
end
|
99
98
|
end
|
data/lib/batali/source.rb
CHANGED
@@ -1,42 +1,41 @@
|
|
1
|
-
require
|
1
|
+
require "batali"
|
2
2
|
|
3
3
|
module Batali
|
4
4
|
# Source of asset
|
5
5
|
class Source < Utility
|
6
|
-
|
7
|
-
autoload :
|
8
|
-
autoload :
|
9
|
-
autoload :
|
10
|
-
autoload :ChefServer, 'batali/source/chef_server'
|
6
|
+
autoload :Path, "batali/source/path"
|
7
|
+
autoload :Site, "batali/source/site"
|
8
|
+
autoload :Git, "batali/source/git"
|
9
|
+
autoload :ChefServer, "batali/source/chef_server"
|
11
10
|
|
12
11
|
# @return [String] path to local cache
|
13
12
|
attr_accessor :cache_path
|
14
13
|
|
15
|
-
attribute :type, String, :required => true, :default => lambda{ self.name } # rubocop:disable Style/RedundantSelf
|
14
|
+
attribute :type, String, :required => true, :default => lambda { self.name } # rubocop:disable Style/RedundantSelf
|
16
15
|
|
17
|
-
def initialize(args={})
|
18
|
-
@cache_path = args.delete(:cache_path)
|
16
|
+
def initialize(args = {})
|
17
|
+
@cache_path = Utility.clean_path(args.delete(:cache_path))
|
19
18
|
super
|
20
19
|
end
|
21
20
|
|
22
21
|
# @return [String]
|
23
22
|
def unit_version
|
24
|
-
raise NotImplementedError.new
|
23
|
+
raise NotImplementedError.new "Abstract class"
|
25
24
|
end
|
26
25
|
|
27
26
|
# @return [Array<Array<name, constraints>>]
|
28
27
|
def unit_dependencies
|
29
|
-
raise NotImplementedError.new
|
28
|
+
raise NotImplementedError.new "Abstract class"
|
30
29
|
end
|
31
30
|
|
32
31
|
# @return [String] directory containing contents
|
33
32
|
def asset
|
34
|
-
raise NotImplementedError.new
|
33
|
+
raise NotImplementedError.new "Abstract class"
|
35
34
|
end
|
36
35
|
|
37
36
|
# @return [TrueClass, FalseClass]
|
38
37
|
def clean_asset(asset_path)
|
39
|
-
if
|
38
|
+
if cache_path && asset_path.include?(cache_path) && File.exist?(asset_path)
|
40
39
|
FileUtils.rm_rf(asset_path)
|
41
40
|
true
|
42
41
|
else
|
@@ -60,9 +59,9 @@ module Batali
|
|
60
59
|
def diff(s)
|
61
60
|
Smash.new.tap do |_diff|
|
62
61
|
self.class.attributes.each do |k, v|
|
63
|
-
if
|
62
|
+
if v[:equivalent]
|
64
63
|
s_attrs = s.respond_to?(:attributes) ? s.attributes : {}
|
65
|
-
unless
|
64
|
+
unless attributes[k] == s_attrs[k]
|
66
65
|
_diff[k] = [attributes[k], s_attrs[k]]
|
67
66
|
end
|
68
67
|
end
|
@@ -77,19 +76,18 @@ module Batali
|
|
77
76
|
# @note uses `:type` to build concrete source
|
78
77
|
def self.build(args)
|
79
78
|
type = args.delete(:type)
|
80
|
-
unless
|
81
|
-
raise ArgumentError.new
|
79
|
+
unless type
|
80
|
+
raise ArgumentError.new "Missing required option `:type`!"
|
82
81
|
end
|
83
|
-
unless
|
84
|
-
type = [name, Bogo::Utility.camel(type)].join(
|
82
|
+
unless type.to_s.include?("::")
|
83
|
+
type = [name, Bogo::Utility.camel(type)].join("::")
|
85
84
|
end
|
86
85
|
klass = Bogo::Utility.constantize(type)
|
87
|
-
unless
|
86
|
+
unless klass
|
88
87
|
raise TypeError.new "Unknown source type provided `#{type}`!"
|
89
88
|
else
|
90
89
|
klass.new(args.merge(:type => type))
|
91
90
|
end
|
92
91
|
end
|
93
|
-
|
94
92
|
end
|
95
93
|
end
|
@@ -1,11 +1,10 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "batali"
|
2
|
+
require "tmpdir"
|
3
3
|
|
4
4
|
module Batali
|
5
5
|
class Source
|
6
6
|
# Chef Server based source
|
7
7
|
class ChefServer < Source
|
8
|
-
|
9
8
|
include Bogo::Memoization
|
10
9
|
include Utility::Chef
|
11
10
|
|
@@ -22,7 +21,7 @@ module Batali
|
|
22
21
|
#
|
23
22
|
# @param args [Hash]
|
24
23
|
# @return [self]
|
25
|
-
def initialize(args={})
|
24
|
+
def initialize(args = {})
|
26
25
|
@deps = args.delete(:dependencies) || {}
|
27
26
|
super
|
28
27
|
init_chef!
|
@@ -48,25 +47,25 @@ module Batali
|
|
48
47
|
# @return [String] path to cache
|
49
48
|
def cache_directory
|
50
49
|
memoize(:cache_directory) do
|
51
|
-
@cache ||=
|
50
|
+
@cache ||= Utility.join_path(cache_path, "chef_server", endpoint)
|
52
51
|
cache
|
53
52
|
end
|
54
53
|
end
|
55
54
|
|
56
55
|
# @return [String] directory
|
57
56
|
def asset
|
58
|
-
path =
|
57
|
+
path = Utility.join_path(cache_directory, name, version)
|
59
58
|
begin
|
60
59
|
FileUtils.mkdir_p(path)
|
61
60
|
cookbook = rest.get_rest("cookbooks/#{name}/#{version}")
|
62
61
|
manifest = cookbook.manifest
|
63
62
|
Chef::CookbookVersion::COOKBOOK_SEGMENTS.each do |segement|
|
64
|
-
if
|
63
|
+
if manifest.key?(segment)
|
65
64
|
manifest[segement].each do |s_file|
|
66
|
-
new_path =
|
65
|
+
new_path = Utility.join_path(path, s_file["path"].gsub("/", File::SEPARATOR))
|
67
66
|
FileUtils.mkdir_p(File.dirname(new_path))
|
68
67
|
api_service.sign_on_redirect = false
|
69
|
-
t_file = api_service.get_rest(s_file[
|
68
|
+
t_file = api_service.get_rest(s_file["url"], true)
|
70
69
|
FilUtils.mv(t_file.path, new_path)
|
71
70
|
end
|
72
71
|
end
|
@@ -78,7 +77,6 @@ module Batali
|
|
78
77
|
end
|
79
78
|
path
|
80
79
|
end
|
81
|
-
|
82
80
|
end
|
83
81
|
end
|
84
82
|
end
|
data/lib/batali/source/git.rb
CHANGED
@@ -1,24 +1,29 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "batali"
|
2
|
+
require "fileutils"
|
3
|
+
require "tmpdir"
|
4
4
|
|
5
5
|
module Batali
|
6
6
|
# Source of asset
|
7
7
|
class Source
|
8
8
|
# Path based source
|
9
9
|
class Git < Path
|
10
|
-
|
11
10
|
include Bogo::Memoization
|
12
11
|
include Batali::Git
|
13
12
|
|
14
13
|
attribute :subdirectory, String, :equivalent => true
|
15
14
|
attribute :path, String
|
16
15
|
|
16
|
+
def initialize(*_, &block)
|
17
|
+
super
|
18
|
+
self.subdirectory = Utility.clean_path(subdirectory)
|
19
|
+
self.path = Utility.clean_path(path)
|
20
|
+
end
|
21
|
+
|
17
22
|
# @return [String] directory containing contents
|
18
23
|
def asset
|
19
24
|
clone_repository
|
20
25
|
clone_path = ref_dup
|
21
|
-
self.path =
|
26
|
+
self.path = Utility.join_path(*[ref_dup, subdirectory].compact)
|
22
27
|
result = super
|
23
28
|
self.path = clone_path
|
24
29
|
result
|
@@ -31,11 +36,10 @@ module Batali
|
|
31
36
|
:url => url,
|
32
37
|
:ref => ref,
|
33
38
|
:type => self.class.name,
|
34
|
-
:subdirectory => subdirectory
|
39
|
+
:subdirectory => subdirectory,
|
35
40
|
), *args
|
36
41
|
)
|
37
42
|
end
|
38
|
-
|
39
43
|
end
|
40
44
|
end
|
41
45
|
end
|