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/chefspec.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
1
|
+
require "batali"
|
2
|
+
require "stringio"
|
3
|
+
require "fileutils"
|
4
|
+
require "tmpdir"
|
5
5
|
|
6
6
|
# ChefSpec namespace
|
7
7
|
module ChefSpec
|
8
8
|
# Batali integration class
|
9
9
|
class Batali
|
10
|
-
|
11
10
|
class << self
|
12
11
|
extend Forwardable
|
13
12
|
def_delegators :instance, :setup!, :teardown!
|
@@ -17,24 +16,24 @@ module ChefSpec
|
|
17
16
|
|
18
17
|
# Create new instance
|
19
18
|
def initialize
|
20
|
-
@vendor_path = Dir.mktmpdir
|
19
|
+
@vendor_path = Utility.clean_path(Dir.mktmpdir)
|
21
20
|
end
|
22
21
|
|
23
22
|
# Setup the environment (load cookbooks)
|
24
23
|
def setup!
|
25
|
-
output =
|
24
|
+
output = ""
|
26
25
|
begin
|
27
26
|
::Batali::Command::Update.new(
|
28
27
|
Smash.new(
|
29
|
-
:file =>
|
28
|
+
:file => Utility.join_path(Dir.pwd, "Batali"),
|
30
29
|
:path => @vendor_path,
|
31
30
|
:update => {
|
32
|
-
:install => true
|
31
|
+
:install => true,
|
33
32
|
},
|
34
33
|
:ui => Bogo::Ui.new(
|
35
|
-
:app_name =>
|
36
|
-
:output_to => StringIO.new(output)
|
37
|
-
)
|
34
|
+
:app_name => "Batali",
|
35
|
+
:output_to => StringIO.new(output),
|
36
|
+
),
|
38
37
|
),
|
39
38
|
[]
|
40
39
|
).execute!
|
@@ -50,15 +49,14 @@ module ChefSpec
|
|
50
49
|
|
51
50
|
# Clean up after complete
|
52
51
|
def teardown!
|
53
|
-
if
|
52
|
+
if File.directory?(@vendor_path)
|
54
53
|
FileUtils.rm_rf(@vendor_path)
|
55
54
|
end
|
56
55
|
end
|
57
|
-
|
58
56
|
end
|
59
57
|
end
|
60
58
|
|
61
59
|
RSpec.configure do |config|
|
62
|
-
config.before(:suite){ ChefSpec::Batali.setup! }
|
63
|
-
config.after(:suite){ ChefSpec::Batali.teardown! }
|
60
|
+
config.before(:suite) { ChefSpec::Batali.setup! }
|
61
|
+
config.after(:suite) { ChefSpec::Batali.teardown! }
|
64
62
|
end
|
data/lib/batali/command.rb
CHANGED
@@ -1,21 +1,20 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "batali"
|
2
|
+
require "fileutils"
|
3
3
|
|
4
4
|
module Batali
|
5
5
|
# Customized command base for Batali
|
6
6
|
class Command < Bogo::Cli::Command
|
7
|
-
|
8
|
-
DEFAULT_CONFIGURATION_FILES = ['.batali']
|
7
|
+
DEFAULT_CONFIGURATION_FILES = [".batali"]
|
9
8
|
|
10
9
|
include Bogo::Memoization
|
11
10
|
|
12
|
-
autoload :Cache,
|
13
|
-
autoload :Configure,
|
14
|
-
autoload :Display,
|
15
|
-
autoload :Install,
|
16
|
-
autoload :Resolve,
|
17
|
-
autoload :Supermarket,
|
18
|
-
autoload :Update,
|
11
|
+
autoload :Cache, "batali/command/cache"
|
12
|
+
autoload :Configure, "batali/command/configure"
|
13
|
+
autoload :Display, "batali/command/display"
|
14
|
+
autoload :Install, "batali/command/install"
|
15
|
+
autoload :Resolve, "batali/command/resolve"
|
16
|
+
autoload :Supermarket, "batali/command/supermarket"
|
17
|
+
autoload :Update, "batali/command/update"
|
19
18
|
|
20
19
|
# Set UI when loading via command
|
21
20
|
def initialize(*_)
|
@@ -27,14 +26,14 @@ module Batali
|
|
27
26
|
def batali_file
|
28
27
|
memoize(:batali_file) do
|
29
28
|
# TODO: Add directory traverse searching
|
30
|
-
path = config.fetch(:file, File.join(Dir.pwd,
|
29
|
+
path = Utility.clean_path(config.fetch(:file, File.join(Dir.pwd, "Batali")))
|
31
30
|
ui.verbose "Loading Batali file from: #{path}"
|
32
31
|
bfile = BFile.new(path, cache_directory)
|
33
|
-
if
|
32
|
+
if bfile.discover
|
34
33
|
bfile.auto_discover!(config[:environment])
|
35
34
|
end
|
36
35
|
bfile.data.keys.each do |key|
|
37
|
-
unless
|
36
|
+
unless bfile.respond_to?(key)
|
38
37
|
ui.warn "Unknown keyword used within Batali file: #{key.inspect}"
|
39
38
|
end
|
40
39
|
end
|
@@ -45,23 +44,32 @@ module Batali
|
|
45
44
|
# @return [Manifest]
|
46
45
|
def manifest
|
47
46
|
memoize(:manifest) do
|
48
|
-
path =
|
47
|
+
path = Utility.join_path(
|
49
48
|
File.dirname(
|
50
|
-
config.fetch(:file, File.join(Dir.pwd,
|
51
|
-
),
|
49
|
+
config.fetch(:file, File.join(Dir.pwd, "batali.manifest"))
|
50
|
+
), "batali.manifest"
|
52
51
|
)
|
53
52
|
ui.verbose "Loading manifest file from: #{path}"
|
54
53
|
Manifest.build(path)
|
55
54
|
end
|
56
55
|
end
|
57
56
|
|
57
|
+
# @return [String] correct user home location for platform
|
58
|
+
def user_home
|
59
|
+
if (RUBY_PLATFORM =~ /mswin|mingw|windows/)
|
60
|
+
Utility.clean_path(ENV.fetch("LOCALAPPDATA", Dir.home))
|
61
|
+
else
|
62
|
+
Utility.clean_path(Dir.home)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
58
66
|
# @return [String] path to local cache
|
59
67
|
def cache_directory(*args)
|
60
|
-
memoize([
|
61
|
-
directory = config.fetch(:cache_directory, File.join(
|
68
|
+
memoize(["cache_directory", *args].join("_")) do
|
69
|
+
directory = Utility.clean_path(config.fetch(:cache_directory, File.join(user_home, ".batali", "cache")))
|
62
70
|
ui.debug "Cache directory to persist cookbooks: #{directory}"
|
63
|
-
unless
|
64
|
-
directory =
|
71
|
+
unless args.empty?
|
72
|
+
directory = Utility.join_path(directory, *args.map(&:to_s))
|
65
73
|
end
|
66
74
|
FileUtils.mkdir_p(directory)
|
67
75
|
directory
|
@@ -73,7 +81,7 @@ module Batali
|
|
73
81
|
# @param action [String] action to be performed
|
74
82
|
# @yield block to execute
|
75
83
|
def dry_run(action)
|
76
|
-
if
|
84
|
+
if config[:dry_run]
|
77
85
|
ui.warn "Dry run disabled: #{action}"
|
78
86
|
else
|
79
87
|
yield
|
@@ -82,11 +90,8 @@ module Batali
|
|
82
90
|
|
83
91
|
# @return [TrueClass, FalseClass] infrastructure mode
|
84
92
|
def infrastructure?
|
85
|
-
config[:infrastructure] || (
|
86
|
-
|
87
|
-
manifest.infrastructure
|
88
|
-
)
|
93
|
+
config[:infrastructure] || (config[:infrastructure].nil? &&
|
94
|
+
manifest.infrastructure)
|
89
95
|
end
|
90
|
-
|
91
96
|
end
|
92
97
|
end
|
data/lib/batali/command/cache.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "batali"
|
2
2
|
|
3
3
|
module Batali
|
4
4
|
class Command
|
@@ -8,17 +8,17 @@ module Batali
|
|
8
8
|
|
9
9
|
# Display information from manifest
|
10
10
|
def execute!
|
11
|
-
if
|
11
|
+
if opts[:scrub]
|
12
12
|
scrub!
|
13
13
|
end
|
14
|
-
ui.puts ui.color(
|
14
|
+
ui.puts ui.color("Batali cache information:", :bold) + "\n"
|
15
15
|
display
|
16
16
|
end
|
17
17
|
|
18
18
|
# Remove all contents from local cache
|
19
19
|
def scrub!
|
20
|
-
ui.confirm "Remove all contents from local cache (#{cache_directory})"
|
21
|
-
run_action
|
20
|
+
ui.confirm "Remove all contents from local cache (#{cache_directory})" unless opts[:yes]
|
21
|
+
run_action "Scrubbing local cache" do
|
22
22
|
FileUtils.rm_rf(cache_directory)
|
23
23
|
nil
|
24
24
|
end
|
@@ -26,19 +26,17 @@ module Batali
|
|
26
26
|
|
27
27
|
# Display local cache information
|
28
28
|
def display
|
29
|
-
cache_size = Dir.glob(
|
29
|
+
cache_size = Dir.glob(Utility.join_path(cache_directory, "**", "**", "*")).map do |path|
|
30
30
|
File.size(path) if File.file?(path)
|
31
31
|
end.compact.inject(&:+).to_i
|
32
|
-
cache_size = "#{sprintf(
|
32
|
+
cache_size = "#{sprintf("%.2f", ((cache_size / 1024.to_f) / 1024))}M"
|
33
33
|
[
|
34
|
-
"#{ui.color(
|
35
|
-
"#{ui.color(
|
34
|
+
"#{ui.color("Path:", :bold)} #{cache_directory}",
|
35
|
+
"#{ui.color("Size:", :bold)} #{cache_size}",
|
36
36
|
].each do |line|
|
37
37
|
ui.puts " #{line}"
|
38
38
|
end
|
39
39
|
end
|
40
|
-
|
41
40
|
end
|
42
|
-
|
43
41
|
end
|
44
42
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "batali"
|
2
2
|
|
3
3
|
module Batali
|
4
4
|
class Command
|
@@ -8,7 +8,7 @@ module Batali
|
|
8
8
|
|
9
9
|
# Display information from manifest
|
10
10
|
def execute!
|
11
|
-
ui.puts ui.color(
|
11
|
+
ui.puts ui.color("Batali manifest information:", :bold) + "\n"
|
12
12
|
display(arguments)
|
13
13
|
end
|
14
14
|
|
@@ -40,8 +40,6 @@ module Batali
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
43
|
-
|
44
43
|
end
|
45
|
-
|
46
44
|
end
|
47
45
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "batali"
|
2
|
+
require "fileutils"
|
3
3
|
|
4
4
|
module Batali
|
5
5
|
class Command
|
@@ -9,34 +9,34 @@ module Batali
|
|
9
9
|
|
10
10
|
# Install cookbooks
|
11
11
|
def execute!
|
12
|
-
dry_run(
|
13
|
-
install_path = config.fetch(:path,
|
14
|
-
run_action(
|
12
|
+
dry_run("Cookbook installation") do
|
13
|
+
install_path = Utility.clean_path(config.fetch(:path, "cookbooks"))
|
14
|
+
run_action("Readying installation destination") do
|
15
15
|
FileUtils.rm_rf(install_path)
|
16
16
|
FileUtils.mkdir_p(install_path)
|
17
17
|
nil
|
18
18
|
end
|
19
|
-
if
|
20
|
-
ui.error
|
19
|
+
if manifest.cookbook.nil? || manifest.cookbook.empty?
|
20
|
+
ui.error "No cookbooks defined within manifest! Try resolving first. (`batali resolve`)"
|
21
21
|
else
|
22
|
-
run_action(
|
22
|
+
run_action("Installing cookbooks") do
|
23
23
|
manifest.cookbook.each_slice(100) do |units_slice|
|
24
24
|
units_slice.map do |unit|
|
25
25
|
Thread.new do
|
26
26
|
ui.debug "Starting unit install for: #{unit.name}<#{unit.version}>"
|
27
|
-
if
|
27
|
+
if unit.source.respond_to?(:cache_path)
|
28
28
|
unit.source.cache_path = cache_directory(
|
29
|
-
Bogo::Utility.snake(unit.source.class.name.split(
|
29
|
+
Bogo::Utility.snake(unit.source.class.name.split("::").last)
|
30
30
|
)
|
31
31
|
end
|
32
32
|
asset_path = unit.source.asset
|
33
|
-
final_path =
|
34
|
-
if
|
33
|
+
final_path = Utility.join_path(install_path, unit.name)
|
34
|
+
if infrastructure?
|
35
35
|
final_path << "-#{unit.version}"
|
36
36
|
end
|
37
37
|
begin
|
38
38
|
FileUtils.cp_r(
|
39
|
-
|
39
|
+
Utility.join_path(asset_path, "."),
|
40
40
|
final_path
|
41
41
|
)
|
42
42
|
ui.debug "Completed unit install for: #{unit.name}<#{unit.version}>"
|
@@ -54,8 +54,6 @@ module Batali
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
end
|
57
|
-
|
58
57
|
end
|
59
|
-
|
60
58
|
end
|
61
59
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "batali"
|
2
2
|
|
3
3
|
module Batali
|
4
4
|
class Command
|
@@ -10,27 +10,27 @@ module Batali
|
|
10
10
|
# and dump serialized manifest
|
11
11
|
def execute!
|
12
12
|
system = Grimoire::System.new
|
13
|
-
run_action
|
13
|
+
run_action "Loading sources" do
|
14
14
|
UnitLoader.new(
|
15
15
|
:file => batali_file,
|
16
16
|
:system => system,
|
17
17
|
:cache => cache_directory(:git),
|
18
|
-
:auto_path_restrict => !infrastructure
|
18
|
+
:auto_path_restrict => !infrastructure?,
|
19
19
|
).populate!
|
20
20
|
nil
|
21
21
|
end
|
22
22
|
requirements = Grimoire::RequirementList.new(
|
23
23
|
:name => :batali_resolv,
|
24
|
-
:requirements => batali_file.cookbook.map{ |ckbk|
|
25
|
-
[ckbk.name, (ckbk.constraint.nil? || ckbk.constraint.empty? ? [
|
26
|
-
}
|
24
|
+
:requirements => batali_file.cookbook.map { |ckbk|
|
25
|
+
[ckbk.name, (ckbk.constraint.nil? || ckbk.constraint.empty? ? ["> 0"] : ckbk.constraint)]
|
26
|
+
},
|
27
27
|
)
|
28
28
|
solv = Grimoire::Solver.new(
|
29
29
|
:requirements => requirements,
|
30
30
|
:system => system,
|
31
|
-
:score_keeper => score_keeper
|
31
|
+
:score_keeper => score_keeper,
|
32
32
|
)
|
33
|
-
if
|
33
|
+
if infrastructure?
|
34
34
|
infrastructure_resolution(solv)
|
35
35
|
else
|
36
36
|
single_path_resolution(solv)
|
@@ -41,7 +41,7 @@ module Batali
|
|
41
41
|
def score_keeper
|
42
42
|
memoize(:score_keeper) do
|
43
43
|
sk_manifest = Manifest.new(:cookbook => manifest.cookbook)
|
44
|
-
unless
|
44
|
+
unless config[:least_impact]
|
45
45
|
sk_manifest.cookbook.clear
|
46
46
|
end
|
47
47
|
sk_manifest.cookbook.delete_if do |unit|
|
@@ -61,50 +61,50 @@ module Batali
|
|
61
61
|
[unit.name, unit.version]
|
62
62
|
end
|
63
63
|
]
|
64
|
-
ui.info
|
65
|
-
if
|
66
|
-
ui.confirm
|
64
|
+
ui.info "Performing single path resolution."
|
65
|
+
if manifest.infrastructure
|
66
|
+
ui.confirm "Current manifest is resolved for infrastucture. Convert to single path?"
|
67
67
|
end
|
68
68
|
results = []
|
69
|
-
run_action
|
69
|
+
run_action "Resolving dependency constraints" do
|
70
70
|
results = solv.generate!
|
71
71
|
nil
|
72
72
|
end
|
73
|
-
if
|
74
|
-
ui.error
|
73
|
+
if results.empty?
|
74
|
+
ui.error "No solutions found defined requirements!"
|
75
75
|
else
|
76
76
|
ideal_solution = results.pop
|
77
|
-
ui.debug
|
77
|
+
ui.debug "Full solution raw contents:"
|
78
78
|
ideal_solution.units.each do |unit|
|
79
|
-
ui.debug [unit.name, unit.version].join(
|
79
|
+
ui.debug [unit.name, unit.version].join(" -> ")
|
80
80
|
end
|
81
|
-
dry_run(
|
82
|
-
run_action
|
81
|
+
dry_run("manifest file write") do
|
82
|
+
run_action "Writing manifest" do
|
83
83
|
manifest = Manifest.new(
|
84
84
|
:cookbook => ideal_solution.units,
|
85
|
-
:infrastructure => false
|
85
|
+
:infrastructure => false,
|
86
86
|
)
|
87
|
-
File.open(
|
87
|
+
File.open("batali.manifest", "w") do |file|
|
88
88
|
file.write MultiJson.dump(manifest, :pretty => true)
|
89
89
|
end
|
90
90
|
nil
|
91
91
|
end
|
92
92
|
end
|
93
93
|
# ui.info "Number of solutions collected for defined requirements: #{results.size + 1}"
|
94
|
-
ui.info
|
95
|
-
solution_units = Smash[ideal_solution.units.map{|unit| [unit.name, unit]}]
|
96
|
-
manifest_units = Smash[manifest.cookbook.map{|unit| [unit.name, unit]}]
|
94
|
+
ui.info "Ideal solution:"
|
95
|
+
solution_units = Smash[ideal_solution.units.map { |unit| [unit.name, unit] }]
|
96
|
+
manifest_units = Smash[manifest.cookbook.map { |unit| [unit.name, unit] }]
|
97
97
|
(solution_units.keys + manifest_units.keys).compact.uniq.sort.each do |unit_name|
|
98
|
-
if
|
99
|
-
if
|
100
|
-
if
|
98
|
+
if manifest_units[unit_name]
|
99
|
+
if solution_units[unit_name]
|
100
|
+
if solution_units[unit_name].same?(manifest_units[unit_name])
|
101
101
|
ui.puts "#{unit_name} <#{solution_units[unit_name].version}>"
|
102
102
|
else
|
103
103
|
u_diff = manifest_units[unit_name].diff(solution_units[unit_name])
|
104
|
-
version_output = u_diff[:version] ? u_diff[:version].join(
|
104
|
+
version_output = u_diff[:version] ? u_diff[:version].join(" -> ") : solution_units[unit_name].version
|
105
105
|
u_diff.delete(:version)
|
106
|
-
unless
|
107
|
-
diff_output = "[#{u_diff.values.map{|v| v.join(
|
106
|
+
unless u_diff.empty?
|
107
|
+
diff_output = "[#{u_diff.values.map { |v| v.join(" -> ") }.join(" | ")}]"
|
108
108
|
end
|
109
109
|
ui.puts ui.color("#{unit_name} <#{version_output}> #{diff_output}", :yellow)
|
110
110
|
end
|
@@ -123,27 +123,27 @@ module Batali
|
|
123
123
|
# @param solv [Grimoire::Solver]
|
124
124
|
# @return [TrueClass]
|
125
125
|
def infrastructure_resolution(solv)
|
126
|
-
ui.info
|
127
|
-
if
|
128
|
-
ui.ask
|
126
|
+
ui.info "Performing infrastructure path resolution."
|
127
|
+
if manifest.infrastructure == false
|
128
|
+
ui.ask "Current manifest is resolved single path. Convert to infrastructure?"
|
129
129
|
end
|
130
|
-
run_action
|
130
|
+
run_action "Resolving dependency constraints" do
|
131
131
|
solv.prune_world!
|
132
132
|
nil
|
133
133
|
end
|
134
|
-
dry_run(
|
135
|
-
run_action
|
136
|
-
File.open(manifest.path,
|
134
|
+
dry_run("manifest file write") do
|
135
|
+
run_action "Writing infrastructure manifest file" do
|
136
|
+
File.open(manifest.path, "w") do |file|
|
137
137
|
manifest = Manifest.new(
|
138
138
|
:cookbook => solv.world.units.values.flatten,
|
139
|
-
:infrastructure => true
|
139
|
+
:infrastructure => true,
|
140
140
|
)
|
141
141
|
file.write MultiJson.dump(manifest, :pretty => true)
|
142
142
|
nil
|
143
143
|
end
|
144
144
|
end
|
145
145
|
end
|
146
|
-
ui.info
|
146
|
+
ui.info "Infrastructure manifest solution:"
|
147
147
|
|
148
148
|
solution_units = solv.world.units
|
149
149
|
manifest_units = Smash.new.tap do |mu|
|
@@ -153,41 +153,39 @@ module Batali
|
|
153
153
|
end
|
154
154
|
end
|
155
155
|
(solution_units.keys + manifest_units.keys).compact.uniq.sort.each do |unit_name|
|
156
|
-
if
|
157
|
-
if
|
156
|
+
if manifest_units[unit_name]
|
157
|
+
if solution_units[unit_name]
|
158
158
|
removed = manifest_units[unit_name].find_all do |m_unit|
|
159
159
|
solution_units[unit_name].none? do |s_unit|
|
160
160
|
m_unit.same?(s_unit)
|
161
161
|
end
|
162
|
-
end.map{|u| [u.version, :red] }
|
162
|
+
end.map { |u| [u.version, :red] }
|
163
163
|
added = solution_units[unit_name].find_all do |s_unit|
|
164
164
|
manifest_units[unit_name].none? do |m_unit|
|
165
165
|
s_unit.same?(m_unit)
|
166
166
|
end
|
167
|
-
end.map{|u| [u.version, :green]}
|
167
|
+
end.map { |u| [u.version, :green] }
|
168
168
|
persisted = solution_units[unit_name].find_all do |s_unit|
|
169
169
|
manifest_units[unit_name].any? do |m_unit|
|
170
170
|
s_unit.same?(m_unit)
|
171
171
|
end
|
172
|
-
end.map{|u| [u.version, nil]}
|
172
|
+
end.map { |u| [u.version, nil] }
|
173
173
|
unit_versions = (removed + added + persisted).sort_by(&:first).map do |uv|
|
174
174
|
uv.last ? ui.color(uv.first.to_s, uv.last) : uv.first.to_s
|
175
175
|
end
|
176
|
-
unless
|
177
|
-
ui.puts "#{ui.color(unit_name, :yellow)} #{ui.color(
|
176
|
+
unless added.empty? && removed.empty?
|
177
|
+
ui.puts "#{ui.color(unit_name, :yellow)} #{ui.color("<", :yellow)}#{unit_versions.join(ui.color(", ", :yellow))}#{ui.color(">", :yellow)}" # rubocop:disable Metrics/LineLength
|
178
178
|
else
|
179
|
-
ui.puts "#{unit_name} <#{unit_versions.join(
|
179
|
+
ui.puts "#{unit_name} <#{unit_versions.join(", ")}>"
|
180
180
|
end
|
181
181
|
else
|
182
|
-
ui.puts ui.color("#{unit_name} <#{manifest_units[unit_name].map(&:version).sort.map(&:to_s).join(
|
182
|
+
ui.puts ui.color("#{unit_name} <#{manifest_units[unit_name].map(&:version).sort.map(&:to_s).join(", ")}>", :red) # rubocop:disable Metrics/LineLength
|
183
183
|
end
|
184
184
|
else
|
185
|
-
ui.puts ui.color("#{unit_name} <#{solution_units[unit_name].map(&:version).sort.map(&:to_s).join(
|
185
|
+
ui.puts ui.color("#{unit_name} <#{solution_units[unit_name].map(&:version).sort.map(&:to_s).join(", ")}>", :green) # rubocop:disable Metrics/LineLength
|
186
186
|
end
|
187
187
|
end
|
188
188
|
end
|
189
|
-
|
190
189
|
end
|
191
|
-
|
192
190
|
end
|
193
191
|
end
|