license-acceptance 0.2.10 → 2.1.2
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/Gemfile +23 -1
- data/config/product_info.toml +41 -10
- data/lib/license_acceptance/acceptor.rb +103 -46
- data/lib/license_acceptance/cli_flags/mixlib_cli.rb +2 -2
- data/lib/license_acceptance/cli_flags/thor.rb +3 -3
- data/lib/license_acceptance/config.rb +6 -4
- data/lib/license_acceptance/product.rb +15 -8
- data/lib/license_acceptance/product_reader.rb +29 -14
- data/lib/license_acceptance/strategy/argument.rb +45 -0
- data/lib/license_acceptance/strategy/base.rb +7 -0
- data/lib/license_acceptance/strategy/environment.rb +39 -0
- data/lib/license_acceptance/strategy/file.rb +101 -0
- data/lib/license_acceptance/strategy/prompt.rb +111 -0
- data/lib/license_acceptance/strategy/provided_value.rb +31 -0
- data/lib/license_acceptance/version.rb +1 -1
- metadata +12 -135
- data/Gemfile.lock +0 -94
- data/Rakefile +0 -6
- data/lib/license_acceptance/arg_acceptance.rb +0 -32
- data/lib/license_acceptance/env_acceptance.rb +0 -26
- data/lib/license_acceptance/file_acceptance.rb +0 -97
- data/lib/license_acceptance/prompt_acceptance.rb +0 -106
- data/spec/license_acceptance/acceptor_spec.rb +0 -272
- data/spec/license_acceptance/arg_acceptance_spec.rb +0 -57
- data/spec/license_acceptance/cli_flags/mixlib_cli_spec.rb +0 -14
- data/spec/license_acceptance/cli_flags/thor_spec.rb +0 -14
- data/spec/license_acceptance/config_spec.rb +0 -111
- data/spec/license_acceptance/env_acceptance_spec.rb +0 -65
- data/spec/license_acceptance/file_acceptance_spec.rb +0 -121
- data/spec/license_acceptance/product_reader_spec.rb +0 -139
- data/spec/license_acceptance/product_spec.rb +0 -13
- data/spec/license_acceptance/prompt_acceptance_spec.rb +0 -100
- data/spec/spec_helper.rb +0 -25
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d82f01f1176a863816de18e547817c501d796873019601fc84a6c01a2e97c713
|
|
4
|
+
data.tar.gz: eab594e87a7613d6126e124757f63f2acc35fcbf24485a50d84e96f2609c6f51
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c9ed6dd65f3fb274f110157fab725a9b2cc0b341aff313f38a4a30809fd19aaef0dd52d9eabeb95a8f1738c45fff0f3efdf39a9d681fb4b9ed3118b0eeb0090e
|
|
7
|
+
data.tar.gz: 3fe1ba49289e95c77ffc863deea1221bd418cb5a111262904349d4c92e3dc2a5a760e5c562175d0a167916c3f028bcf8d0a346e038e8b935a69aadc6d147f3f6
|
data/Gemfile
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
source "https://rubygems.org"
|
|
2
2
|
|
|
3
|
-
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
|
3
|
+
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
|
4
4
|
|
|
5
5
|
# Specify your gem's dependencies in license-acceptance.gemspec
|
|
6
6
|
gemspec
|
|
7
|
+
|
|
8
|
+
group :development do
|
|
9
|
+
gem "chefstyle", "1.3.2"
|
|
10
|
+
gem "climate_control", "~> 0.2"
|
|
11
|
+
gem "mixlib-cli", "~> 2.1"
|
|
12
|
+
gem "rake", ">= 10.1.0"
|
|
13
|
+
gem "rspec", "~> 3.0"
|
|
14
|
+
gem "thor", ">= 0.20", "< 2.0" # validate 2.0 when it ships
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
group :docs do
|
|
18
|
+
gem "yard"
|
|
19
|
+
gem "redcarpet"
|
|
20
|
+
gem "github-markup"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
group :debug do
|
|
24
|
+
gem "pry"
|
|
25
|
+
gem "pry-byebug"
|
|
26
|
+
gem "pry-stack_explorer", "~> 0.4.0" # pin until we drop ruby < 2.6
|
|
27
|
+
gem "rb-readline"
|
|
28
|
+
end
|
data/config/product_info.toml
CHANGED
|
@@ -2,27 +2,58 @@
|
|
|
2
2
|
title = "All known products that require license acceptance, and the mapping of parent to child relationships"
|
|
3
3
|
|
|
4
4
|
[[products]]
|
|
5
|
-
|
|
6
|
-
pretty_name = "Chef Client"
|
|
5
|
+
id = "infra-client"
|
|
6
|
+
pretty_name = "Chef Infra Client"
|
|
7
7
|
hab_pkg_id = "chef/chef-client"
|
|
8
|
-
filename = "
|
|
8
|
+
filename = "chef_infra_client"
|
|
9
|
+
mixlib_name = "chef"
|
|
10
|
+
license_required_version = "15"
|
|
9
11
|
|
|
10
12
|
[[products]]
|
|
11
|
-
|
|
12
|
-
pretty_name = "InSpec"
|
|
13
|
+
id = "inspec"
|
|
14
|
+
pretty_name = "Chef InSpec"
|
|
13
15
|
hab_pkg_id = "chef/inspec"
|
|
14
16
|
filename = "inspec"
|
|
15
17
|
|
|
16
18
|
[[products]]
|
|
17
|
-
|
|
19
|
+
id = "supermarket"
|
|
18
20
|
pretty_name = "Supermarket"
|
|
19
21
|
filename = "supermarket"
|
|
20
22
|
|
|
21
23
|
[[products]]
|
|
22
|
-
|
|
23
|
-
pretty_name = "Chef Server"
|
|
24
|
+
id = "infra-server"
|
|
25
|
+
pretty_name = "Chef Infra Server"
|
|
24
26
|
hab_pkg_id = "chef/oc_erchef"
|
|
25
|
-
filename = "
|
|
27
|
+
filename = "chef_infra_server"
|
|
28
|
+
|
|
29
|
+
[[products]]
|
|
30
|
+
id = "push-jobs-server"
|
|
31
|
+
pretty_name = "Chef Push Jobs Server"
|
|
32
|
+
filename = "push_jobs_server"
|
|
33
|
+
|
|
34
|
+
[[products]]
|
|
35
|
+
id = "push-jobs-client"
|
|
36
|
+
pretty_name = "Chef Push Jobs Client"
|
|
37
|
+
filename = "push_jobs_client"
|
|
38
|
+
|
|
39
|
+
[[products]]
|
|
40
|
+
id = "chef-dk"
|
|
41
|
+
pretty_name = "Chef Development Kit"
|
|
42
|
+
filename = "chef_dk"
|
|
43
|
+
mixlib_name = "chefdk"
|
|
44
|
+
license_required_version = "4"
|
|
45
|
+
|
|
46
|
+
[[products]]
|
|
47
|
+
id = "chef-workstation"
|
|
48
|
+
pretty_name = "Chef Workstation"
|
|
49
|
+
filename = "chef_workstation"
|
|
50
|
+
mixlib_name = "chef-workstation"
|
|
51
|
+
license_required_version = "0.4"
|
|
26
52
|
|
|
27
53
|
[relationships]
|
|
28
|
-
"
|
|
54
|
+
"infra-client" = ["inspec"]
|
|
55
|
+
"infra-server" = ["infra-client", "inspec"]
|
|
56
|
+
"push-jobs-server" = ["infra-client", "infra-server"]
|
|
57
|
+
"push-jobs-client" = ["infra-client"]
|
|
58
|
+
"chef-dk" = ["infra-client", "inspec"]
|
|
59
|
+
"chef-workstation" = ["infra-client", "inspec"]
|
|
@@ -1,28 +1,37 @@
|
|
|
1
|
-
require "forwardable"
|
|
1
|
+
require "forwardable" unless defined?(Forwardable)
|
|
2
2
|
require "license_acceptance/config"
|
|
3
3
|
require "license_acceptance/logger"
|
|
4
4
|
require "license_acceptance/product_reader"
|
|
5
5
|
require "license_acceptance/product_relationship"
|
|
6
|
-
require "license_acceptance/
|
|
7
|
-
require "license_acceptance/
|
|
8
|
-
require "license_acceptance/
|
|
9
|
-
require "license_acceptance/
|
|
6
|
+
require "license_acceptance/strategy/environment"
|
|
7
|
+
require "license_acceptance/strategy/file"
|
|
8
|
+
require "license_acceptance/strategy/argument"
|
|
9
|
+
require "license_acceptance/strategy/prompt"
|
|
10
|
+
require "license_acceptance/strategy/provided_value"
|
|
10
11
|
|
|
11
12
|
module LicenseAcceptance
|
|
13
|
+
|
|
14
|
+
ACCEPT = "accept".freeze
|
|
15
|
+
ACCEPT_SILENT = "accept-silent".freeze
|
|
16
|
+
ACCEPT_NO_PERSIST = "accept-no-persist".freeze
|
|
17
|
+
|
|
12
18
|
class Acceptor
|
|
13
19
|
extend Forwardable
|
|
14
20
|
include Logger
|
|
15
21
|
|
|
16
|
-
attr_reader :config, :product_reader, :
|
|
22
|
+
attr_reader :config, :product_reader, :env_strategy, :file_strategy, :arg_strategy, :prompt_strategy, :provided_strategy
|
|
17
23
|
|
|
18
|
-
def initialize(opts={})
|
|
24
|
+
def initialize(opts = {})
|
|
19
25
|
@config = Config.new(opts)
|
|
20
26
|
Logger.initialize(config.logger)
|
|
21
27
|
@product_reader = ProductReader.new
|
|
22
|
-
|
|
23
|
-
@
|
|
24
|
-
@
|
|
25
|
-
@
|
|
28
|
+
product_reader.read
|
|
29
|
+
@env_strategy = Strategy::Environment.new(ENV)
|
|
30
|
+
@file_strategy = Strategy::File.new(config)
|
|
31
|
+
@arg_strategy = Strategy::Argument.new(ARGV)
|
|
32
|
+
@prompt_strategy = Strategy::Prompt.new(config)
|
|
33
|
+
@provided_strategy = Strategy::ProvidedValue.new(opts.fetch(:provided, nil))
|
|
34
|
+
@acceptance_value = nil
|
|
26
35
|
end
|
|
27
36
|
|
|
28
37
|
def_delegator :@config, :output
|
|
@@ -30,100 +39,148 @@ module LicenseAcceptance
|
|
|
30
39
|
# For applications that just need simple logic to handle a failed license acceptance flow we include this small
|
|
31
40
|
# wrapper. Apps with more complex logic (like logging to a logging engine) should call the non-bang version and
|
|
32
41
|
# handle the exception.
|
|
33
|
-
def check_and_persist!(
|
|
34
|
-
check_and_persist(
|
|
35
|
-
rescue LicenseNotAcceptedError
|
|
36
|
-
output.puts "#{
|
|
42
|
+
def check_and_persist!(product_id, version)
|
|
43
|
+
check_and_persist(product_id, version)
|
|
44
|
+
rescue LicenseNotAcceptedError => e
|
|
45
|
+
output.puts "#{e.product.pretty_name} cannot execute without accepting the license"
|
|
37
46
|
exit 172
|
|
38
47
|
end
|
|
39
48
|
|
|
40
|
-
def check_and_persist(
|
|
49
|
+
def check_and_persist(product_id, version)
|
|
41
50
|
if accepted_no_persist?
|
|
42
51
|
logger.debug("Chef License accepted with no persistence")
|
|
52
|
+
@acceptance_value = ACCEPT_NO_PERSIST
|
|
43
53
|
return true
|
|
44
54
|
end
|
|
45
55
|
|
|
46
|
-
product_reader.
|
|
47
|
-
product_relationship = product_reader.lookup(product_name, version)
|
|
56
|
+
product_relationship = product_reader.lookup(product_id, version)
|
|
48
57
|
|
|
49
|
-
missing_licenses =
|
|
58
|
+
missing_licenses = file_strategy.accepted?(product_relationship)
|
|
50
59
|
|
|
51
60
|
# They have already accepted all licenses and stored their acceptance in the persistent files
|
|
52
61
|
if missing_licenses.empty?
|
|
53
62
|
logger.debug("All licenses present")
|
|
63
|
+
@acceptance_value = ACCEPT
|
|
54
64
|
return true
|
|
55
65
|
end
|
|
56
66
|
|
|
57
67
|
if accepted? || accepted_silent?
|
|
58
68
|
if config.persist
|
|
59
|
-
errs =
|
|
69
|
+
errs = file_strategy.persist(product_relationship, missing_licenses)
|
|
60
70
|
if errs.empty?
|
|
61
71
|
output_num_persisted(missing_licenses.size) unless accepted_silent?
|
|
62
72
|
else
|
|
63
73
|
output_persist_failed(errs)
|
|
64
74
|
end
|
|
65
75
|
end
|
|
76
|
+
@acceptance_value = accepted_silent? ? ACCEPT_SILENT : ACCEPT
|
|
66
77
|
return true
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
if acceptance_value_provided?
|
|
81
|
+
value = provided_strategy.value || env_strategy.value || arg_strategy.value
|
|
82
|
+
output.puts("Unrecognized license acceptance value '#{value}', expected one of: '#{ACCEPT}', '#{ACCEPT_SILENT}', '#{ACCEPT_NO_PERSIST}'")
|
|
83
|
+
raise LicenseNotAcceptedError.new(product_relationship.parent, missing_licenses)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
return true if output.isatty && accepted_license_prompt?(product_relationship, missing_licenses)
|
|
87
|
+
|
|
88
|
+
raise LicenseNotAcceptedError.new(product_relationship.parent, missing_licenses)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def self.check_and_persist!(product_id, version, opts = {})
|
|
92
|
+
new(opts).check_and_persist!(product_id, version)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def self.check_and_persist(product_id, version, opts = {})
|
|
96
|
+
new(opts).check_and_persist(product_id, version)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def accepted_license_prompt?(product_relationship, missing_licenses)
|
|
100
|
+
prompt_strategy.request(missing_licenses) do
|
|
101
|
+
# We have to infer the acceptance value if they use the prompt to accept
|
|
102
|
+
if config.persist
|
|
103
|
+
@acceptance_value = ACCEPT
|
|
104
|
+
file_strategy.persist(product_relationship, missing_licenses)
|
|
105
|
+
else
|
|
106
|
+
@acceptance_value = ACCEPT_NO_PERSIST
|
|
107
|
+
[]
|
|
73
108
|
end
|
|
74
|
-
return true
|
|
75
|
-
else
|
|
76
|
-
raise LicenseNotAcceptedError.new(missing_licenses)
|
|
77
109
|
end
|
|
78
110
|
end
|
|
79
111
|
|
|
80
|
-
|
|
81
|
-
|
|
112
|
+
# Check whether the specified product requires license acceptance for the given version.
|
|
113
|
+
def license_required?(mixlib_name, version)
|
|
114
|
+
product = product_reader.lookup_by_mixlib(mixlib_name)
|
|
115
|
+
return false if product.nil?
|
|
116
|
+
# If they don't pass a version we assume they want latest
|
|
117
|
+
# All versions in all channels require license acceptance
|
|
118
|
+
return true if %w{latest unstable current stable}.include?(version.to_s) || version.nil?
|
|
119
|
+
|
|
120
|
+
Gem::Version.new(version) >= Gem::Version.new(product.license_required_version)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Some callers only know about mixlib names so we need a way for them to get the product
|
|
124
|
+
# id as this library knows it.
|
|
125
|
+
def id_from_mixlib(mixlib_name)
|
|
126
|
+
product = product_reader.lookup_by_mixlib(mixlib_name)
|
|
127
|
+
return nil if product.nil?
|
|
128
|
+
|
|
129
|
+
product.id
|
|
82
130
|
end
|
|
83
131
|
|
|
84
|
-
|
|
85
|
-
|
|
132
|
+
# Return the value that was matched ("accept", "accept-no-persist", etc.). Used by callers so they do not
|
|
133
|
+
# have to know the precedence order between provided/environment/argument. Can just get back the value
|
|
134
|
+
# that was used. Value is only guaranteed to be set after calling check_and_persist.
|
|
135
|
+
def acceptance_value
|
|
136
|
+
@acceptance_value
|
|
86
137
|
end
|
|
87
138
|
|
|
88
139
|
def accepted?
|
|
89
|
-
|
|
140
|
+
provided_strategy.accepted? || env_strategy.accepted? || arg_strategy.accepted?
|
|
90
141
|
end
|
|
91
142
|
|
|
92
143
|
# no-persist is silent too
|
|
93
144
|
def accepted_no_persist?
|
|
94
|
-
|
|
145
|
+
provided_strategy.no_persist? || env_strategy.no_persist? || arg_strategy.no_persist?
|
|
95
146
|
end
|
|
96
147
|
|
|
97
148
|
# persist but be silent like no-persist
|
|
98
149
|
def accepted_silent?
|
|
99
|
-
|
|
150
|
+
provided_strategy.silent? || env_strategy.silent? || arg_strategy.silent?
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def acceptance_value_provided?
|
|
154
|
+
provided_strategy.value? || env_strategy.value? || arg_strategy.value?
|
|
100
155
|
end
|
|
101
156
|
|
|
102
157
|
# In the case where users accept with a command line argument or environment variable
|
|
103
158
|
# we still want to output the fact that the filesystem was changed.
|
|
104
159
|
def output_num_persisted(count)
|
|
105
|
-
s = count > 1 ? "s": ""
|
|
160
|
+
s = count > 1 ? "s" : ""
|
|
106
161
|
output.puts <<~EOM
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
162
|
+
#{Strategy::Prompt::BORDER}
|
|
163
|
+
#{Strategy::Prompt::CHECK} #{count} product license#{s} accepted.
|
|
164
|
+
#{Strategy::Prompt::BORDER}
|
|
110
165
|
EOM
|
|
111
166
|
end
|
|
112
167
|
|
|
113
168
|
def output_persist_failed(errs)
|
|
114
169
|
output.puts <<~EOM
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
170
|
+
#{Strategy::Prompt::BORDER}
|
|
171
|
+
#{Strategy::Prompt::CHECK} Product license accepted.
|
|
172
|
+
Could not persist acceptance:\n\t* #{errs.map(&:message).join("\n\t* ")}
|
|
173
|
+
#{Strategy::Prompt::BORDER}
|
|
119
174
|
EOM
|
|
120
175
|
end
|
|
121
176
|
|
|
122
177
|
end
|
|
123
178
|
|
|
124
179
|
class LicenseNotAcceptedError < RuntimeError
|
|
125
|
-
|
|
126
|
-
|
|
180
|
+
attr_reader :product
|
|
181
|
+
def initialize(product, missing_licenses)
|
|
182
|
+
@product = product
|
|
183
|
+
msg = "Missing licenses for the following:\n* " + missing_licenses.map(&:id).join("\n* ")
|
|
127
184
|
super(msg)
|
|
128
185
|
end
|
|
129
186
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
begin
|
|
2
|
-
require
|
|
3
|
-
rescue
|
|
2
|
+
require "thor" unless defined?(Thor)
|
|
3
|
+
rescue
|
|
4
4
|
raise "Must have thor gem installed to use this mixin"
|
|
5
5
|
end
|
|
6
6
|
|
|
@@ -12,7 +12,7 @@ module LicenseAcceptance
|
|
|
12
12
|
def self.included(klass)
|
|
13
13
|
klass.class_option :chef_license,
|
|
14
14
|
type: :string,
|
|
15
|
-
desc:
|
|
15
|
+
desc: "Accept the license for this product and any contained products: accept, accept-no-persist, accept-silent"
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
end
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "logger"
|
|
2
2
|
|
|
3
3
|
module LicenseAcceptance
|
|
4
4
|
class Config
|
|
5
5
|
attr_accessor :output, :logger, :license_locations, :persist_location, :persist
|
|
6
6
|
|
|
7
|
-
def initialize(opts={})
|
|
7
|
+
def initialize(opts = {})
|
|
8
8
|
@output = opts.fetch(:output, $stdout)
|
|
9
9
|
@logger = opts.fetch(:logger, ::Logger.new(IO::NULL))
|
|
10
10
|
@license_locations = opts.fetch(:license_locations, default_license_locations)
|
|
@@ -21,7 +21,8 @@ module LicenseAcceptance
|
|
|
21
21
|
|
|
22
22
|
def default_license_locations
|
|
23
23
|
if windows?
|
|
24
|
-
|
|
24
|
+
root = ENV.fetch("SYSTEMDRIVE", "C:")
|
|
25
|
+
l = [ File.join(root, "chef/accepted_licenses/") ]
|
|
25
26
|
unless is_root?
|
|
26
27
|
# Look through a list of possible user locations and pick the first one that exists
|
|
27
28
|
# copied from path_helper.rb in chef-config gem
|
|
@@ -31,6 +32,7 @@ module LicenseAcceptance
|
|
|
31
32
|
possible_dirs << ENV["HOMESHARE"] + ENV["HOMEPATH"] if ENV["HOMESHARE"] && ENV["HOMEPATH"]
|
|
32
33
|
possible_dirs << ENV["USERPROFILE"] if ENV["USERPROFILE"]
|
|
33
34
|
raise NoValidEnvironmentVar if possible_dirs.empty?
|
|
35
|
+
|
|
34
36
|
possible_dirs.each do |possible_dir|
|
|
35
37
|
if Dir.exist?(possible_dir)
|
|
36
38
|
full_possible_dir = File.join(possible_dir, ".chef/accepted_licenses/")
|
|
@@ -41,7 +43,7 @@ module LicenseAcceptance
|
|
|
41
43
|
end
|
|
42
44
|
else
|
|
43
45
|
l = [ "/etc/chef/accepted_licenses/" ]
|
|
44
|
-
l << File.join(ENV[
|
|
46
|
+
l << File.join(ENV["HOME"], ".chef/accepted_licenses/") unless is_root?
|
|
45
47
|
end
|
|
46
48
|
l
|
|
47
49
|
end
|
|
@@ -1,22 +1,29 @@
|
|
|
1
1
|
module LicenseAcceptance
|
|
2
2
|
class Product
|
|
3
3
|
|
|
4
|
-
attr_reader :
|
|
4
|
+
attr_reader :id, :pretty_name, :filename, :mixlib_name, :license_required_version
|
|
5
5
|
|
|
6
|
-
def initialize(
|
|
7
|
-
|
|
6
|
+
def initialize(id, pretty_name, filename, mixlib_name, license_required_version)
|
|
7
|
+
# id is the internal representation of this product as license-acceptance knows it
|
|
8
|
+
@id = id
|
|
8
9
|
@pretty_name = pretty_name
|
|
9
10
|
@filename = filename
|
|
11
|
+
@mixlib_name = mixlib_name
|
|
12
|
+
@license_required_version = license_required_version
|
|
10
13
|
end
|
|
11
14
|
|
|
12
15
|
def ==(other)
|
|
13
16
|
return false if other.class != Product
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
|
|
18
|
+
if other.id == id &&
|
|
19
|
+
other.pretty_name == pretty_name &&
|
|
20
|
+
other.filename == filename &&
|
|
21
|
+
other.mixlib_name == mixlib_name &&
|
|
22
|
+
other.license_required_version == license_required_version
|
|
23
|
+
return true
|
|
18
24
|
end
|
|
19
|
-
|
|
25
|
+
|
|
26
|
+
false
|
|
20
27
|
end
|
|
21
28
|
|
|
22
29
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
autoload :Tomlrb, "tomlrb"
|
|
2
2
|
require "license_acceptance/logger"
|
|
3
3
|
require "license_acceptance/product"
|
|
4
4
|
require "license_acceptance/product_relationship"
|
|
@@ -18,21 +18,27 @@ module LicenseAcceptance
|
|
|
18
18
|
toml = Tomlrb.load_file(location, symbolize_keys: false)
|
|
19
19
|
raise InvalidProductInfo.new(location) if toml.empty? || toml["products"].nil? || toml["relationships"].nil?
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
products[product["
|
|
21
|
+
toml["products"].each do |product|
|
|
22
|
+
products[product["id"]] = Product.new(
|
|
23
|
+
product["id"], product["pretty_name"],
|
|
24
|
+
product["filename"], product["mixlib_name"],
|
|
25
|
+
product["license_required_version"]
|
|
26
|
+
)
|
|
23
27
|
end
|
|
24
28
|
|
|
25
|
-
|
|
26
|
-
parent = products[
|
|
27
|
-
raise UnknownParent.new(
|
|
29
|
+
toml["relationships"].each do |parent_id, children|
|
|
30
|
+
parent = products[parent_id]
|
|
31
|
+
raise UnknownParent.new(parent_id) if parent.nil?
|
|
28
32
|
# Its fine to not have a relationship entry, but not fine to have
|
|
29
33
|
# a relationship where the children are nil or empty.
|
|
30
34
|
if children.nil? || children.empty? || !children.is_a?(Array)
|
|
31
35
|
raise NoChildRelationships.new(parent)
|
|
32
36
|
end
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
|
|
38
|
+
children.map! do |child_id|
|
|
39
|
+
child = products[child_id]
|
|
40
|
+
raise UnknownChild.new(child_id) if child.nil?
|
|
41
|
+
|
|
36
42
|
child
|
|
37
43
|
end
|
|
38
44
|
relationships[parent] = children
|
|
@@ -48,20 +54,29 @@ module LicenseAcceptance
|
|
|
48
54
|
if ENV["CHEF_LICENSE_PRODUCT_INFO"]
|
|
49
55
|
return ENV["CHEF_LICENSE_PRODUCT_INFO"]
|
|
50
56
|
end
|
|
57
|
+
|
|
51
58
|
File.absolute_path(File.join(__FILE__, "../../../config/product_info.toml"))
|
|
52
59
|
end
|
|
53
60
|
|
|
54
|
-
def lookup(
|
|
55
|
-
parent_product = products.fetch(
|
|
56
|
-
raise UnknownProduct.new(
|
|
61
|
+
def lookup(parent_id, parent_version)
|
|
62
|
+
parent_product = products.fetch(parent_id) do
|
|
63
|
+
raise UnknownProduct.new(parent_id)
|
|
57
64
|
end
|
|
58
65
|
children = relationships.fetch(parent_product, [])
|
|
59
|
-
|
|
66
|
+
unless parent_version.is_a? String
|
|
60
67
|
raise ProductVersionTypeError.new(parent_version)
|
|
61
68
|
end
|
|
69
|
+
|
|
62
70
|
ProductRelationship.new(parent_product, children, parent_version)
|
|
63
71
|
end
|
|
64
72
|
|
|
73
|
+
def lookup_by_mixlib(mixlib_name)
|
|
74
|
+
found_product = products.values.find(nil) do |p|
|
|
75
|
+
p.mixlib_name == mixlib_name
|
|
76
|
+
end
|
|
77
|
+
found_product
|
|
78
|
+
end
|
|
79
|
+
|
|
65
80
|
end
|
|
66
81
|
|
|
67
82
|
class UnknownProduct < RuntimeError
|
|
@@ -94,7 +109,7 @@ module LicenseAcceptance
|
|
|
94
109
|
|
|
95
110
|
class NoChildRelationships < RuntimeError
|
|
96
111
|
def initialize(product)
|
|
97
|
-
msg = "No child relationships for #{product.
|
|
112
|
+
msg = "No child relationships for #{product.id}, should be removed from product info or fixed"
|
|
98
113
|
super(msg)
|
|
99
114
|
end
|
|
100
115
|
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require "license_acceptance/strategy/base"
|
|
2
|
+
|
|
3
|
+
module LicenseAcceptance
|
|
4
|
+
module Strategy
|
|
5
|
+
|
|
6
|
+
# Look for acceptance values in the ARGV
|
|
7
|
+
class Argument < Base
|
|
8
|
+
|
|
9
|
+
FLAG = "--chef-license".freeze
|
|
10
|
+
|
|
11
|
+
attr_reader :argv
|
|
12
|
+
|
|
13
|
+
def initialize(argv)
|
|
14
|
+
@argv = argv
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def accepted?
|
|
18
|
+
String(value).downcase == ACCEPT
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def silent?
|
|
22
|
+
String(value).downcase == ACCEPT_SILENT
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def no_persist?
|
|
26
|
+
String(value).downcase == ACCEPT_NO_PERSIST
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def value?
|
|
30
|
+
argv.any? { |s| s == FLAG || s.start_with?("#{FLAG}=") }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def value
|
|
34
|
+
match = argv.detect { |s| s.start_with?("#{FLAG}=") }
|
|
35
|
+
return match.split("=").last if match
|
|
36
|
+
|
|
37
|
+
argv.each_cons(2) do |arg, value|
|
|
38
|
+
return value if arg == FLAG
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
nil
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require "license_acceptance/strategy/base"
|
|
2
|
+
|
|
3
|
+
module LicenseAcceptance
|
|
4
|
+
module Strategy
|
|
5
|
+
|
|
6
|
+
# Look for acceptance values in the environment
|
|
7
|
+
class Environment < Base
|
|
8
|
+
|
|
9
|
+
ENV_KEY = "CHEF_LICENSE".freeze
|
|
10
|
+
|
|
11
|
+
attr_reader :env
|
|
12
|
+
|
|
13
|
+
def initialize(env)
|
|
14
|
+
@env = env
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def accepted?
|
|
18
|
+
String(value).downcase == ACCEPT
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def silent?
|
|
22
|
+
String(value).downcase == ACCEPT_SILENT
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def no_persist?
|
|
26
|
+
String(value).downcase == ACCEPT_NO_PERSIST
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def value?
|
|
30
|
+
env.key?(ENV_KEY)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def value
|
|
34
|
+
env[ENV_KEY]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|