license-acceptance 0.0.1 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/Gemfile.lock +97 -0
- data/config/product_info.toml +1 -0
- data/lib/license_acceptance/acceptor.rb +117 -0
- data/lib/license_acceptance/arg_acceptance.rb +33 -0
- data/lib/license_acceptance/cli_flags/mixlib_cli.rb +22 -0
- data/lib/license_acceptance/cli_flags/thor.rb +21 -0
- data/lib/license_acceptance/config.rb +65 -0
- data/lib/license_acceptance/env_acceptance.rb +19 -0
- data/lib/license_acceptance/file_acceptance.rb +97 -0
- data/lib/license_acceptance/logger.rb +19 -0
- data/lib/license_acceptance/product.rb +23 -0
- data/lib/license_acceptance/product_reader.rb +108 -0
- data/lib/license_acceptance/product_relationship.rb +13 -0
- data/lib/license_acceptance/prompt_acceptance.rb +104 -0
- data/lib/license_acceptance/version.rb +3 -0
- data/spec/license_acceptance/acceptor_spec.rb +222 -0
- data/spec/license_acceptance/arg_acceptance_spec.rb +37 -0
- data/spec/license_acceptance/cli_flags/mixlib_cli_spec.rb +14 -0
- data/spec/license_acceptance/cli_flags/thor_spec.rb +14 -0
- data/spec/license_acceptance/config_spec.rb +113 -0
- data/spec/license_acceptance/env_acceptance_spec.rb +43 -0
- data/spec/license_acceptance/file_acceptance_spec.rb +121 -0
- data/spec/license_acceptance/product_reader_spec.rb +139 -0
- data/spec/license_acceptance/product_spec.rb +13 -0
- data/spec/license_acceptance/prompt_acceptance_spec.rb +100 -0
- data/spec/spec_helper.rb +25 -0
- metadata +184 -22
- data/.gitignore +0 -11
- data/.rspec +0 -3
- data/.travis.yml +0 -7
- data/LICENSE +0 -1
- data/README.md +0 -35
- data/lib/license/acceptance/version.rb +0 -5
- data/lib/license/acceptance.rb +0 -8
- data/license-acceptance.gemspec +0 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5ae4a25ff89f94b78498d69d0d5805a243e065cc2e622e4ec08f2acf8294345d
|
4
|
+
data.tar.gz: b994a62576a2e0c24694f916d3e4672f556077d8882bb52aa853706ef1e4e9c3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c6d8d023638ba548846b92b27e166a7ff2683b96b59eb5513b71c28ebbd46792dfd755e46893409e02dfbf4ce83dcee28e60e4c26716078fbe122b465553d399
|
7
|
+
data.tar.gz: d4501d2b154e6fcf8dabdc1a40c689d2bb575ea09f0f61b1f3ccbb5775609808ac6543fc6f9ed9bbee262fc085ddc634ecc4f3732a01cc17e951422162fdcded
|
data/Gemfile
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
license-acceptance (0.1.0)
|
5
|
+
pastel (>= 0.7)
|
6
|
+
tomlrb (~> 1.2)
|
7
|
+
tty-box (>= 0.3)
|
8
|
+
tty-platform (>= 0.2)
|
9
|
+
tty-prompt (>= 0.18)
|
10
|
+
|
11
|
+
GEM
|
12
|
+
remote: https://rubygems.org/
|
13
|
+
specs:
|
14
|
+
binding_of_caller (0.8.0)
|
15
|
+
debug_inspector (>= 0.0.1)
|
16
|
+
byebug (11.0.1)
|
17
|
+
climate_control (0.2.0)
|
18
|
+
coderay (1.1.2)
|
19
|
+
debug_inspector (0.0.3)
|
20
|
+
diff-lcs (1.3)
|
21
|
+
equatable (0.5.0)
|
22
|
+
method_source (0.9.2)
|
23
|
+
mixlib-cli (2.0.3)
|
24
|
+
necromancer (0.4.0)
|
25
|
+
pastel (0.7.2)
|
26
|
+
equatable (~> 0.5.0)
|
27
|
+
tty-color (~> 0.4.0)
|
28
|
+
pry (0.12.2)
|
29
|
+
coderay (~> 1.1.0)
|
30
|
+
method_source (~> 0.9.0)
|
31
|
+
pry-byebug (3.7.0)
|
32
|
+
byebug (~> 11.0)
|
33
|
+
pry (~> 0.10)
|
34
|
+
pry-stack_explorer (0.4.9.3)
|
35
|
+
binding_of_caller (>= 0.7)
|
36
|
+
pry (>= 0.9.11)
|
37
|
+
rake (12.3.2)
|
38
|
+
rspec (3.8.0)
|
39
|
+
rspec-core (~> 3.8.0)
|
40
|
+
rspec-expectations (~> 3.8.0)
|
41
|
+
rspec-mocks (~> 3.8.0)
|
42
|
+
rspec-core (3.8.0)
|
43
|
+
rspec-support (~> 3.8.0)
|
44
|
+
rspec-expectations (3.8.2)
|
45
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
46
|
+
rspec-support (~> 3.8.0)
|
47
|
+
rspec-mocks (3.8.0)
|
48
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
49
|
+
rspec-support (~> 3.8.0)
|
50
|
+
rspec-support (3.8.0)
|
51
|
+
strings (0.1.4)
|
52
|
+
strings-ansi (~> 0.1.0)
|
53
|
+
unicode-display_width (~> 1.4.0)
|
54
|
+
unicode_utils (~> 1.4.0)
|
55
|
+
strings-ansi (0.1.0)
|
56
|
+
thor (0.20.3)
|
57
|
+
timers (4.3.0)
|
58
|
+
tomlrb (1.2.8)
|
59
|
+
tty-box (0.3.0)
|
60
|
+
pastel (~> 0.7.2)
|
61
|
+
strings (~> 0.1.4)
|
62
|
+
tty-cursor (~> 0.6.0)
|
63
|
+
tty-color (0.4.3)
|
64
|
+
tty-cursor (0.6.1)
|
65
|
+
tty-platform (0.2.0)
|
66
|
+
tty-prompt (0.18.1)
|
67
|
+
necromancer (~> 0.4.0)
|
68
|
+
pastel (~> 0.7.0)
|
69
|
+
timers (~> 4.0)
|
70
|
+
tty-cursor (~> 0.6.0)
|
71
|
+
tty-reader (~> 0.5.0)
|
72
|
+
tty-reader (0.5.0)
|
73
|
+
tty-cursor (~> 0.6.0)
|
74
|
+
tty-screen (~> 0.6.4)
|
75
|
+
wisper (~> 2.0.0)
|
76
|
+
tty-screen (0.6.5)
|
77
|
+
unicode-display_width (1.4.1)
|
78
|
+
unicode_utils (1.4.0)
|
79
|
+
wisper (2.0.0)
|
80
|
+
|
81
|
+
PLATFORMS
|
82
|
+
ruby
|
83
|
+
|
84
|
+
DEPENDENCIES
|
85
|
+
bundler (>= 1.17)
|
86
|
+
climate_control (>= 0.2)
|
87
|
+
license-acceptance!
|
88
|
+
mixlib-cli (>= 1.7)
|
89
|
+
pry (>= 0.12)
|
90
|
+
pry-byebug (>= 3.6)
|
91
|
+
pry-stack_explorer (>= 0.4)
|
92
|
+
rake (>= 10.0)
|
93
|
+
rspec (>= 3.0)
|
94
|
+
thor (>= 0.20)
|
95
|
+
|
96
|
+
BUNDLED WITH
|
97
|
+
1.17.3
|
@@ -0,0 +1 @@
|
|
1
|
+
# DO NOT CHANGE - overwritten by expeditor at build time
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
require "license_acceptance/config"
|
3
|
+
require "license_acceptance/logger"
|
4
|
+
require "license_acceptance/product_reader"
|
5
|
+
require "license_acceptance/product_relationship"
|
6
|
+
require "license_acceptance/file_acceptance"
|
7
|
+
require "license_acceptance/arg_acceptance"
|
8
|
+
require "license_acceptance/prompt_acceptance"
|
9
|
+
require "license_acceptance/env_acceptance"
|
10
|
+
|
11
|
+
module LicenseAcceptance
|
12
|
+
class Acceptor
|
13
|
+
extend Forwardable
|
14
|
+
include Logger
|
15
|
+
|
16
|
+
attr_reader :config, :product_reader, :env_acceptance, :file_acceptance, :arg_acceptance, :prompt_acceptance
|
17
|
+
|
18
|
+
def initialize(opts={})
|
19
|
+
@config = Config.new(opts)
|
20
|
+
Logger.initialize(config.logger)
|
21
|
+
@product_reader = ProductReader.new
|
22
|
+
@env_acceptance = EnvAcceptance.new
|
23
|
+
@file_acceptance = FileAcceptance.new(config)
|
24
|
+
@arg_acceptance = ArgAcceptance.new
|
25
|
+
@prompt_acceptance = PromptAcceptance.new(config)
|
26
|
+
end
|
27
|
+
|
28
|
+
def_delegator :@config, :output
|
29
|
+
|
30
|
+
# For applications that just need simple logic to handle a failed license acceptance flow we include this small
|
31
|
+
# wrapper. Apps with more complex logic (like logging to a logging engine) should call the non-bang version and
|
32
|
+
# handle the exception.
|
33
|
+
def check_and_persist!(product_name, version)
|
34
|
+
check_and_persist(product_name, version)
|
35
|
+
rescue LicenseNotAcceptedError
|
36
|
+
output.puts "#{product_name} cannot execute without accepting the license"
|
37
|
+
exit 172
|
38
|
+
end
|
39
|
+
|
40
|
+
def check_and_persist(product_name, version)
|
41
|
+
if env_acceptance.check_no_persist(ENV) || arg_acceptance.check_no_persist(ARGV)
|
42
|
+
logger.debug("Chef License accepted with no persistence")
|
43
|
+
return true
|
44
|
+
end
|
45
|
+
|
46
|
+
product_reader.read
|
47
|
+
product_relationship = product_reader.lookup(product_name, version)
|
48
|
+
|
49
|
+
missing_licenses = file_acceptance.check(product_relationship)
|
50
|
+
|
51
|
+
# They have already accepted all licenses and stored their acceptance in the persistent files
|
52
|
+
if missing_licenses.empty?
|
53
|
+
logger.debug("All licenses present")
|
54
|
+
return true
|
55
|
+
end
|
56
|
+
|
57
|
+
if env_acceptance.check(ENV) || arg_acceptance.check(ARGV)
|
58
|
+
if config.persist
|
59
|
+
errs = file_acceptance.persist(product_relationship, missing_licenses)
|
60
|
+
if errs.empty?
|
61
|
+
output_num_persisted(missing_licenses.size)
|
62
|
+
else
|
63
|
+
output_persist_failed(errs)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
return true
|
67
|
+
elsif config.output.isatty && prompt_acceptance.request(missing_licenses) do
|
68
|
+
if config.persist
|
69
|
+
file_acceptance.persist(product_relationship, missing_licenses)
|
70
|
+
else
|
71
|
+
[]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
return true
|
75
|
+
else
|
76
|
+
raise LicenseNotAcceptedError.new(missing_licenses)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.check_and_persist!(product_name, version, opts={})
|
81
|
+
new(opts).check_and_persist!(product_name, version)
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.check_and_persist(product_name, version, opts={})
|
85
|
+
new(opts).check_and_persist(product_name, version)
|
86
|
+
end
|
87
|
+
|
88
|
+
# In the case where users accept with a command line argument or environment variable
|
89
|
+
# we still want to output the fact that the filesystem was changed.
|
90
|
+
def output_num_persisted(count)
|
91
|
+
s = count > 1 ? "s": ""
|
92
|
+
output.puts <<~EOM
|
93
|
+
#{PromptAcceptance::BORDER}
|
94
|
+
#{PromptAcceptance::CHECK} #{count} product license#{s} accepted.
|
95
|
+
#{PromptAcceptance::BORDER}
|
96
|
+
EOM
|
97
|
+
end
|
98
|
+
|
99
|
+
def output_persist_failed(errs)
|
100
|
+
output.puts <<~EOM
|
101
|
+
#{PromptAcceptance::BORDER}
|
102
|
+
#{PromptAcceptance::CHECK} Product license accepted.
|
103
|
+
Could not persist acceptance:\n\t* #{errs.map(&:message).join("\n\t* ")}
|
104
|
+
#{PromptAcceptance::BORDER}
|
105
|
+
EOM
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
class LicenseNotAcceptedError < RuntimeError
|
111
|
+
def initialize(missing_licenses)
|
112
|
+
msg = "Missing licenses for the following:\n* " + missing_licenses.join("\n* ")
|
113
|
+
super(msg)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module LicenseAcceptance
|
2
|
+
class ArgAcceptance
|
3
|
+
|
4
|
+
def check(argv)
|
5
|
+
if argv.include?("--chef-license=accept")
|
6
|
+
return true
|
7
|
+
end
|
8
|
+
i = argv.index("--chef-license")
|
9
|
+
unless i.nil?
|
10
|
+
val = argv[i+1]
|
11
|
+
if val != nil && val.downcase == "accept"
|
12
|
+
return true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
return false
|
16
|
+
end
|
17
|
+
|
18
|
+
def check_no_persist(argv)
|
19
|
+
if argv.include?("--chef-license=accept-no-persist")
|
20
|
+
return true
|
21
|
+
end
|
22
|
+
i = argv.index("--chef-license")
|
23
|
+
unless i.nil?
|
24
|
+
val = argv[i+1]
|
25
|
+
if val != nil && val.downcase == "accept-no-persist"
|
26
|
+
return true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
return false
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
begin
|
2
|
+
require 'mixlib/cli'
|
3
|
+
rescue => exception
|
4
|
+
raise "Must have mixlib-cli gem installed to use this mixin"
|
5
|
+
end
|
6
|
+
|
7
|
+
module LicenseAcceptance
|
8
|
+
module CLIFlags
|
9
|
+
|
10
|
+
module MixlibCLI
|
11
|
+
|
12
|
+
def self.included(klass)
|
13
|
+
klass.option :chef_license,
|
14
|
+
long: "--chef-license ACCEPTANCE",
|
15
|
+
description: "Accept the license for this product and any contained products ('accept' or 'accept-no-persist')",
|
16
|
+
required: false
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
begin
|
2
|
+
require 'thor'
|
3
|
+
rescue => exception
|
4
|
+
raise "Must have thor gem installed to use this mixin"
|
5
|
+
end
|
6
|
+
|
7
|
+
module LicenseAcceptance
|
8
|
+
module CLIFlags
|
9
|
+
|
10
|
+
module Thor
|
11
|
+
|
12
|
+
def self.included(klass)
|
13
|
+
klass.class_option :chef_license,
|
14
|
+
type: :string,
|
15
|
+
desc: 'Accept the license for this product and any contained products: accept, accept-no-persist'
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'tty-platform'
|
3
|
+
|
4
|
+
module LicenseAcceptance
|
5
|
+
class Config
|
6
|
+
attr_accessor :output, :logger, :license_locations, :persist_location, :persist
|
7
|
+
|
8
|
+
def initialize(opts={})
|
9
|
+
@output = opts.fetch(:output, $stdout)
|
10
|
+
@logger = opts.fetch(:logger, ::Logger.new(IO::NULL))
|
11
|
+
@license_locations = opts.fetch(:license_locations, default_license_locations)
|
12
|
+
@license_locations = [ @license_locations ].flatten
|
13
|
+
@persist_location = opts.fetch(:persist_location, default_persist_location)
|
14
|
+
@persist = opts.fetch(:persist, true)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def platform
|
20
|
+
@platform ||= TTY::Platform.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def is_root?
|
24
|
+
Process.uid == 0
|
25
|
+
end
|
26
|
+
|
27
|
+
def default_license_locations
|
28
|
+
if platform.windows?
|
29
|
+
l = [ File.join(ENV["HOMEDRIVE"], "chef/accepted_licenses/") ]
|
30
|
+
unless is_root?
|
31
|
+
# Look through a list of possible user locations and pick the first one that exists
|
32
|
+
# copied from path_helper.rb in chef-config gem
|
33
|
+
possible_dirs = []
|
34
|
+
possible_dirs << ENV["HOME"] if ENV["HOME"]
|
35
|
+
possible_dirs << ENV["HOMEDRIVE"] + ENV["HOMEPATH"] if ENV["HOMEDRIVE"] && ENV["HOMEPATH"]
|
36
|
+
possible_dirs << ENV["HOMESHARE"] + ENV["HOMEPATH"] if ENV["HOMESHARE"] && ENV["HOMEPATH"]
|
37
|
+
possible_dirs << ENV["USERPROFILE"] if ENV["USERPROFILE"]
|
38
|
+
raise NoValidEnvironmentVar if possible_dirs.empty?
|
39
|
+
possible_dirs.each do |possible_dir|
|
40
|
+
if Dir.exist?(possible_dir)
|
41
|
+
full_possible_dir = File.join(possible_dir, ".chef/accepted_licenses/")
|
42
|
+
l << full_possible_dir
|
43
|
+
break
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
else
|
48
|
+
l = [ "/etc/chef/accepted_licenses/" ]
|
49
|
+
l << File.join(ENV['HOME'], ".chef/accepted_licenses/") unless is_root?
|
50
|
+
end
|
51
|
+
l
|
52
|
+
end
|
53
|
+
|
54
|
+
def default_persist_location
|
55
|
+
license_locations[-1]
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
class NoValidEnvironmentVar < StandardError
|
61
|
+
def initialize
|
62
|
+
super("no valid environment variables set on Windows")
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module LicenseAcceptance
|
2
|
+
class EnvAcceptance
|
3
|
+
|
4
|
+
def check(env)
|
5
|
+
if env['CHEF_LICENSE'] && env['CHEF_LICENSE'].downcase == 'accept'
|
6
|
+
return true
|
7
|
+
end
|
8
|
+
return false
|
9
|
+
end
|
10
|
+
|
11
|
+
def check_no_persist(env)
|
12
|
+
if env['CHEF_LICENSE'] && env['CHEF_LICENSE'].downcase == 'accept-no-persist'
|
13
|
+
return true
|
14
|
+
end
|
15
|
+
return false
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'yaml'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'etc'
|
5
|
+
require "license_acceptance/logger"
|
6
|
+
|
7
|
+
module LicenseAcceptance
|
8
|
+
class FileAcceptance
|
9
|
+
include Logger
|
10
|
+
|
11
|
+
attr_reader :config
|
12
|
+
|
13
|
+
def initialize(config)
|
14
|
+
@config = config
|
15
|
+
end
|
16
|
+
|
17
|
+
INVOCATION_TIME = DateTime.now.freeze
|
18
|
+
|
19
|
+
# For all the given products in the product set, search all possible locations for the
|
20
|
+
# license acceptance files.
|
21
|
+
def check(product_relationship)
|
22
|
+
searching = [product_relationship.parent] + product_relationship.children
|
23
|
+
missing_licenses = searching.clone
|
24
|
+
logger.debug("Searching for the following licenses: #{missing_licenses.map(&:name)}")
|
25
|
+
|
26
|
+
searching.each do |product|
|
27
|
+
found = false
|
28
|
+
config.license_locations.each do |loc|
|
29
|
+
f = File.join(loc, product.filename)
|
30
|
+
if File.exist?(f)
|
31
|
+
found = true
|
32
|
+
logger.debug("Found license #{product.filename} at #{f}")
|
33
|
+
missing_licenses.delete(product)
|
34
|
+
break
|
35
|
+
end
|
36
|
+
end
|
37
|
+
break if missing_licenses.empty?
|
38
|
+
end
|
39
|
+
logger.debug("Missing licenses remaining: #{missing_licenses.map(&:name)}")
|
40
|
+
missing_licenses
|
41
|
+
end
|
42
|
+
|
43
|
+
def persist(product_relationship, missing_licenses)
|
44
|
+
parent = product_relationship.parent
|
45
|
+
parent_version = product_relationship.parent_version
|
46
|
+
root_dir = config.persist_location
|
47
|
+
|
48
|
+
if !Dir.exist?(root_dir)
|
49
|
+
begin
|
50
|
+
FileUtils.mkdir_p(root_dir)
|
51
|
+
rescue StandardError => e
|
52
|
+
msg = "Could not create license directory #{root_dir}"
|
53
|
+
logger.info "#{msg}\n\t#{e.message}\n\t#{e.backtrace.join("\n\t")}"
|
54
|
+
return [e]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
errs = []
|
59
|
+
if missing_licenses.include?(parent)
|
60
|
+
err = persist_license(root_dir, parent, parent, parent_version)
|
61
|
+
errs << err unless err.nil?
|
62
|
+
end
|
63
|
+
product_relationship.children.each do |child|
|
64
|
+
if missing_licenses.include?(child)
|
65
|
+
err = persist_license(root_dir, child, parent, parent_version)
|
66
|
+
errs << err unless err.nil?
|
67
|
+
end
|
68
|
+
end
|
69
|
+
return errs
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def persist_license(folder_path, product, parent, parent_version)
|
75
|
+
path = File.join(folder_path, product.filename)
|
76
|
+
logger.info("Persisting a license for #{product.name} at path #{path}")
|
77
|
+
File.open(path, File::WRONLY | File::CREAT | File::EXCL) do |license_file|
|
78
|
+
contents = {
|
79
|
+
name: product.name,
|
80
|
+
date_accepted: INVOCATION_TIME.iso8601,
|
81
|
+
accepting_product: parent.name,
|
82
|
+
accepting_product_version: parent_version,
|
83
|
+
user: Etc.getlogin,
|
84
|
+
file_format: 1,
|
85
|
+
}
|
86
|
+
contents = Hash[contents.map { |k, v| [k.to_s, v] }]
|
87
|
+
license_file << YAML.dump(contents)
|
88
|
+
end
|
89
|
+
return nil
|
90
|
+
rescue StandardError => e
|
91
|
+
msg = "Could not persist license to #{path}"
|
92
|
+
logger.info "#{msg}\n\t#{e.message}\n\t#{e.backtrace.join("\n\t")}"
|
93
|
+
return e
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|