license-acceptance 0.2.10 → 1.0.5
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.lock +2 -2
- data/config/product_info.toml +19 -10
- data/lib/license_acceptance/acceptor.rb +76 -36
- data/lib/license_acceptance/product.rb +10 -5
- data/lib/license_acceptance/product_reader.rb +22 -11
- data/lib/license_acceptance/strategy/argument.rb +44 -0
- data/lib/license_acceptance/strategy/base.rb +7 -0
- data/lib/license_acceptance/strategy/environment.rb +38 -0
- data/lib/license_acceptance/strategy/file.rb +103 -0
- data/lib/license_acceptance/strategy/prompt.rb +111 -0
- data/lib/license_acceptance/strategy/provided_value.rb +28 -0
- data/lib/license_acceptance/version.rb +1 -1
- data/spec/license_acceptance/acceptor_spec.rb +115 -94
- data/spec/license_acceptance/product_reader_spec.rb +21 -5
- data/spec/license_acceptance/product_spec.rb +4 -2
- data/spec/license_acceptance/strategy/argument_spec.rb +82 -0
- data/spec/license_acceptance/strategy/environment_spec.rb +76 -0
- data/spec/license_acceptance/{file_acceptance_spec.rb → strategy/file_spec.rb} +21 -15
- data/spec/license_acceptance/{prompt_acceptance_spec.rb → strategy/prompt_spec.rb} +6 -6
- data/spec/license_acceptance/strategy/provided_value_spec.rb +55 -0
- metadata +14 -11
- 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/arg_acceptance_spec.rb +0 -57
- data/spec/license_acceptance/env_acceptance_spec.rb +0 -65
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e892e857adb140ddab6c76d173116f248180ced44a2e2ceeeecd9919b1a91b09
|
|
4
|
+
data.tar.gz: ce171bdadb89755fa39e0bd9ce5c5c63901d7949958a0de9a4883a823a35ae9f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0a6c4bb643dc44b5ca0ca0e0f48f6ac22ef590bc7645eea104aa584259d29a911054030749689d2be4424daed5d5a6fd2ace9554a2c7ee9989502d7f63e69d79
|
|
7
|
+
data.tar.gz: c5508cb4655eb0a02ba5c1067b9c58a8c03a08d9ff9eeed7bf0c864df31749ab649901db64c5fc3db6da1fee22f66c81e0bc27d32b02a0fc4899648033c2f408
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
license-acceptance (0.
|
|
4
|
+
license-acceptance (1.0.5)
|
|
5
5
|
pastel (~> 0.7)
|
|
6
6
|
tomlrb (~> 1.2)
|
|
7
7
|
tty-box (~> 0.3)
|
|
@@ -40,7 +40,7 @@ GEM
|
|
|
40
40
|
rspec-mocks (~> 3.8.0)
|
|
41
41
|
rspec-core (3.8.0)
|
|
42
42
|
rspec-support (~> 3.8.0)
|
|
43
|
-
rspec-expectations (3.8.
|
|
43
|
+
rspec-expectations (3.8.3)
|
|
44
44
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
45
45
|
rspec-support (~> 3.8.0)
|
|
46
46
|
rspec-mocks (3.8.0)
|
data/config/product_info.toml
CHANGED
|
@@ -2,27 +2,36 @@
|
|
|
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"
|
|
26
33
|
|
|
27
34
|
[relationships]
|
|
28
|
-
"
|
|
35
|
+
"infra-client" = ["inspec"]
|
|
36
|
+
"infra-server" = ["infra-client"]
|
|
37
|
+
"push-jobs-server" = ["infra-client", "infra-server"]
|
|
@@ -3,26 +3,35 @@ 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"
|
|
15
|
+
ACCEPT_SILENT = "accept-silent"
|
|
16
|
+
ACCEPT_NO_PERSIST = "accept-no-persist"
|
|
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
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,73 +39,102 @@ 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
|
-
elsif config.output.isatty &&
|
|
78
|
+
elsif config.output.isatty && prompt_strategy.request(missing_licenses) do
|
|
79
|
+
# We have to infer the acceptance value if they use the prompt to accept
|
|
68
80
|
if config.persist
|
|
69
|
-
|
|
81
|
+
@acceptance_value = ACCEPT
|
|
82
|
+
file_strategy.persist(product_relationship, missing_licenses)
|
|
70
83
|
else
|
|
84
|
+
@acceptance_value = ACCEPT_NO_PERSIST
|
|
71
85
|
[]
|
|
72
86
|
end
|
|
73
87
|
end
|
|
74
88
|
return true
|
|
75
89
|
else
|
|
76
|
-
raise LicenseNotAcceptedError.new(missing_licenses)
|
|
90
|
+
raise LicenseNotAcceptedError.new(product_relationship.parent, missing_licenses)
|
|
77
91
|
end
|
|
78
92
|
end
|
|
79
93
|
|
|
80
|
-
def self.check_and_persist!(
|
|
81
|
-
new(opts).check_and_persist!(
|
|
94
|
+
def self.check_and_persist!(product_id, version, opts={})
|
|
95
|
+
new(opts).check_and_persist!(product_id, version)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def self.check_and_persist(product_id, version, opts={})
|
|
99
|
+
new(opts).check_and_persist(product_id, version)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Check whether the specified product requires license acceptance for the given version.
|
|
103
|
+
def license_required?(mixlib_name, version)
|
|
104
|
+
product = product_reader.lookup_by_mixlib(mixlib_name)
|
|
105
|
+
return false if product.nil?
|
|
106
|
+
# If they don't pass a version we assume they want latest
|
|
107
|
+
return true if version == :latest || version.nil?
|
|
108
|
+
Gem::Version.new(version) >= Gem::Version.new(product.license_required_version)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Some callers only know about mixlib names so we need a way for them to get the product
|
|
112
|
+
# id as this library knows it.
|
|
113
|
+
def id_from_mixlib(mixlib_name)
|
|
114
|
+
product = product_reader.lookup_by_mixlib(mixlib_name)
|
|
115
|
+
return nil if product.nil?
|
|
116
|
+
product.id
|
|
82
117
|
end
|
|
83
118
|
|
|
84
|
-
|
|
85
|
-
|
|
119
|
+
# Return the value that was matched ("accept", "accept-no-persist", etc.). Used by callers so they do not
|
|
120
|
+
# have to know the precedence order between provided/environment/argument. Can just get back the value
|
|
121
|
+
# that was used. Value is only guaranteed to be set after calling check_and_persist.
|
|
122
|
+
def acceptance_value
|
|
123
|
+
@acceptance_value
|
|
86
124
|
end
|
|
87
125
|
|
|
88
126
|
def accepted?
|
|
89
|
-
|
|
127
|
+
provided_strategy.accepted? || env_strategy.accepted? || arg_strategy.accepted?
|
|
90
128
|
end
|
|
91
129
|
|
|
92
130
|
# no-persist is silent too
|
|
93
131
|
def accepted_no_persist?
|
|
94
|
-
|
|
132
|
+
provided_strategy.no_persist? || env_strategy.no_persist? || arg_strategy.no_persist?
|
|
95
133
|
end
|
|
96
134
|
|
|
97
135
|
# persist but be silent like no-persist
|
|
98
136
|
def accepted_silent?
|
|
99
|
-
|
|
137
|
+
provided_strategy.silent? || env_strategy.silent? || arg_strategy.silent?
|
|
100
138
|
end
|
|
101
139
|
|
|
102
140
|
# In the case where users accept with a command line argument or environment variable
|
|
@@ -104,26 +142,28 @@ module LicenseAcceptance
|
|
|
104
142
|
def output_num_persisted(count)
|
|
105
143
|
s = count > 1 ? "s": ""
|
|
106
144
|
output.puts <<~EOM
|
|
107
|
-
#{
|
|
108
|
-
#{
|
|
109
|
-
#{
|
|
145
|
+
#{Strategy::Prompt::BORDER}
|
|
146
|
+
#{Strategy::Prompt::CHECK} #{count} product license#{s} accepted.
|
|
147
|
+
#{Strategy::Prompt::BORDER}
|
|
110
148
|
EOM
|
|
111
149
|
end
|
|
112
150
|
|
|
113
151
|
def output_persist_failed(errs)
|
|
114
152
|
output.puts <<~EOM
|
|
115
|
-
#{
|
|
116
|
-
#{
|
|
153
|
+
#{Strategy::Prompt::BORDER}
|
|
154
|
+
#{Strategy::Prompt::CHECK} Product license accepted.
|
|
117
155
|
Could not persist acceptance:\n\t* #{errs.map(&:message).join("\n\t* ")}
|
|
118
|
-
#{
|
|
156
|
+
#{Strategy::Prompt::BORDER}
|
|
119
157
|
EOM
|
|
120
158
|
end
|
|
121
159
|
|
|
122
160
|
end
|
|
123
161
|
|
|
124
162
|
class LicenseNotAcceptedError < RuntimeError
|
|
125
|
-
|
|
126
|
-
|
|
163
|
+
attr_reader :product
|
|
164
|
+
def initialize(product, missing_licenses)
|
|
165
|
+
@product = product
|
|
166
|
+
msg = "Missing licenses for the following:\n* " + missing_licenses.map(&:id).join("\n* ")
|
|
127
167
|
super(msg)
|
|
128
168
|
end
|
|
129
169
|
end
|
|
@@ -1,19 +1,24 @@
|
|
|
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
|
-
if other.
|
|
17
|
+
if other.id == id &&
|
|
15
18
|
other.pretty_name == pretty_name &&
|
|
16
|
-
other.filename == filename
|
|
19
|
+
other.filename == filename &&
|
|
20
|
+
other.mixlib_name == mixlib_name
|
|
21
|
+
other.license_required_version == license_required_version
|
|
17
22
|
return true
|
|
18
23
|
end
|
|
19
24
|
return false
|
|
@@ -19,20 +19,24 @@ module LicenseAcceptance
|
|
|
19
19
|
raise InvalidProductInfo.new(location) if toml.empty? || toml["products"].nil? || toml["relationships"].nil?
|
|
20
20
|
|
|
21
21
|
for product in toml["products"]
|
|
22
|
-
products[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
|
-
for
|
|
26
|
-
parent = products[
|
|
27
|
-
raise UnknownParent.new(
|
|
29
|
+
for parent_id, children in toml["relationships"]
|
|
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
|
-
children.map! do |
|
|
34
|
-
child = products[
|
|
35
|
-
raise UnknownChild.new(
|
|
37
|
+
children.map! do |child_id|
|
|
38
|
+
child = products[child_id]
|
|
39
|
+
raise UnknownChild.new(child_id) if child.nil?
|
|
36
40
|
child
|
|
37
41
|
end
|
|
38
42
|
relationships[parent] = children
|
|
@@ -51,9 +55,9 @@ module LicenseAcceptance
|
|
|
51
55
|
File.absolute_path(File.join(__FILE__, "../../../config/product_info.toml"))
|
|
52
56
|
end
|
|
53
57
|
|
|
54
|
-
def lookup(
|
|
55
|
-
parent_product = products.fetch(
|
|
56
|
-
raise UnknownProduct.new(
|
|
58
|
+
def lookup(parent_id, parent_version)
|
|
59
|
+
parent_product = products.fetch(parent_id) do
|
|
60
|
+
raise UnknownProduct.new(parent_id)
|
|
57
61
|
end
|
|
58
62
|
children = relationships.fetch(parent_product, [])
|
|
59
63
|
if !parent_version.is_a? String
|
|
@@ -62,6 +66,13 @@ module LicenseAcceptance
|
|
|
62
66
|
ProductRelationship.new(parent_product, children, parent_version)
|
|
63
67
|
end
|
|
64
68
|
|
|
69
|
+
def lookup_by_mixlib(mixlib_name)
|
|
70
|
+
found_product = products.values.find(nil) do |p|
|
|
71
|
+
p.mixlib_name == mixlib_name
|
|
72
|
+
end
|
|
73
|
+
found_product
|
|
74
|
+
end
|
|
75
|
+
|
|
65
76
|
end
|
|
66
77
|
|
|
67
78
|
class UnknownProduct < RuntimeError
|
|
@@ -94,7 +105,7 @@ module LicenseAcceptance
|
|
|
94
105
|
|
|
95
106
|
class NoChildRelationships < RuntimeError
|
|
96
107
|
def initialize(product)
|
|
97
|
-
msg = "No child relationships for #{product.
|
|
108
|
+
msg = "No child relationships for #{product.id}, should be removed from product info or fixed"
|
|
98
109
|
super(msg)
|
|
99
110
|
end
|
|
100
111
|
end
|
|
@@ -0,0 +1,44 @@
|
|
|
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
|
+
attr_reader :argv
|
|
10
|
+
|
|
11
|
+
def initialize(argv)
|
|
12
|
+
@argv = argv
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def accepted?
|
|
16
|
+
look_for_value(ACCEPT)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def silent?
|
|
20
|
+
look_for_value(ACCEPT_SILENT)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def no_persist?
|
|
24
|
+
look_for_value(ACCEPT_NO_PERSIST)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def look_for_value(sought)
|
|
30
|
+
if argv.include?("--chef-license=#{sought}")
|
|
31
|
+
return true
|
|
32
|
+
end
|
|
33
|
+
i = argv.index("--chef-license")
|
|
34
|
+
unless i.nil?
|
|
35
|
+
val = argv[i+1]
|
|
36
|
+
if val != nil && val.downcase == sought
|
|
37
|
+
return true
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
return false
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
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
|
+
attr_reader :env
|
|
10
|
+
|
|
11
|
+
def initialize(env)
|
|
12
|
+
@env = env
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def accepted?
|
|
16
|
+
look_for_value(ACCEPT)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def silent?
|
|
20
|
+
look_for_value(ACCEPT_SILENT)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def no_persist?
|
|
24
|
+
look_for_value(ACCEPT_NO_PERSIST)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def look_for_value(sought)
|
|
30
|
+
if env['CHEF_LICENSE'] && env['CHEF_LICENSE'].downcase == sought
|
|
31
|
+
return true
|
|
32
|
+
end
|
|
33
|
+
return false
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
require 'date'
|
|
2
|
+
require 'yaml'
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
require 'etc'
|
|
5
|
+
require "license_acceptance/logger"
|
|
6
|
+
require "license_acceptance/strategy/base"
|
|
7
|
+
|
|
8
|
+
module LicenseAcceptance
|
|
9
|
+
module Strategy
|
|
10
|
+
|
|
11
|
+
# Read and write marker files that show acceptance.
|
|
12
|
+
class File < Base
|
|
13
|
+
include Logger
|
|
14
|
+
|
|
15
|
+
attr_reader :config
|
|
16
|
+
|
|
17
|
+
def initialize(config)
|
|
18
|
+
@config = config
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
INVOCATION_TIME = DateTime.now.freeze
|
|
22
|
+
|
|
23
|
+
# For all the given products in the product set, search all possible locations for the
|
|
24
|
+
# license acceptance files.
|
|
25
|
+
def accepted?(product_relationship)
|
|
26
|
+
searching = [product_relationship.parent] + product_relationship.children
|
|
27
|
+
missing_licenses = searching.clone
|
|
28
|
+
logger.debug("Searching for the following licenses: #{missing_licenses.map(&:id)}")
|
|
29
|
+
|
|
30
|
+
searching.each do |product|
|
|
31
|
+
found = false
|
|
32
|
+
config.license_locations.each do |loc|
|
|
33
|
+
f = ::File.join(loc, product.filename)
|
|
34
|
+
if ::File.exist?(f)
|
|
35
|
+
found = true
|
|
36
|
+
logger.debug("Found license #{product.filename} at #{f}")
|
|
37
|
+
missing_licenses.delete(product)
|
|
38
|
+
break
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
break if missing_licenses.empty?
|
|
42
|
+
end
|
|
43
|
+
logger.debug("Missing licenses remaining: #{missing_licenses.map(&:id)}")
|
|
44
|
+
missing_licenses
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def persist(product_relationship, missing_licenses)
|
|
48
|
+
parent = product_relationship.parent
|
|
49
|
+
parent_version = product_relationship.parent_version
|
|
50
|
+
root_dir = config.persist_location
|
|
51
|
+
|
|
52
|
+
if !Dir.exist?(root_dir)
|
|
53
|
+
begin
|
|
54
|
+
FileUtils.mkdir_p(root_dir)
|
|
55
|
+
rescue StandardError => e
|
|
56
|
+
msg = "Could not create license directory #{root_dir}"
|
|
57
|
+
logger.info "#{msg}\n\t#{e.message}\n\t#{e.backtrace.join("\n\t")}"
|
|
58
|
+
return [e]
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
errs = []
|
|
63
|
+
if missing_licenses.include?(parent)
|
|
64
|
+
err = persist_license(root_dir, parent, parent, parent_version)
|
|
65
|
+
errs << err unless err.nil?
|
|
66
|
+
end
|
|
67
|
+
product_relationship.children.each do |child|
|
|
68
|
+
if missing_licenses.include?(child)
|
|
69
|
+
err = persist_license(root_dir, child, parent, parent_version)
|
|
70
|
+
errs << err unless err.nil?
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
return errs
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def persist_license(folder_path, product, parent, parent_version)
|
|
79
|
+
path = ::File.join(folder_path, product.filename)
|
|
80
|
+
logger.info("Persisting a license for #{product.pretty_name} at path #{path}")
|
|
81
|
+
::File.open(path, ::File::WRONLY | ::File::CREAT | ::File::EXCL) do |license_file|
|
|
82
|
+
contents = {
|
|
83
|
+
id: product.id,
|
|
84
|
+
name: product.pretty_name,
|
|
85
|
+
date_accepted: INVOCATION_TIME.iso8601,
|
|
86
|
+
accepting_product: parent.id,
|
|
87
|
+
accepting_product_version: parent_version,
|
|
88
|
+
user: Etc.getlogin,
|
|
89
|
+
file_format: 1,
|
|
90
|
+
}
|
|
91
|
+
contents = Hash[contents.map { |k, v| [k.to_s, v] }]
|
|
92
|
+
license_file << YAML.dump(contents)
|
|
93
|
+
end
|
|
94
|
+
return nil
|
|
95
|
+
rescue StandardError => e
|
|
96
|
+
msg = "Could not persist license to #{path}"
|
|
97
|
+
logger.info "#{msg}\n\t#{e.message}\n\t#{e.backtrace.join("\n\t")}"
|
|
98
|
+
return e
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|