omnibus 5.4.0 → 5.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (155) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -3
  3. data/CHANGELOG.md +21 -0
  4. data/Gemfile +8 -5
  5. data/README.md +3 -1
  6. data/Rakefile +20 -13
  7. data/appveyor.yml +4 -3
  8. data/bin/omnibus +3 -3
  9. data/features/commands/manifest.feature +19 -5
  10. data/features/step_definitions/generator_steps.rb +5 -6
  11. data/features/support/env.rb +4 -4
  12. data/lib/omnibus/build_version.rb +14 -14
  13. data/lib/omnibus/build_version_dsl.rb +3 -3
  14. data/lib/omnibus/builder.rb +50 -61
  15. data/lib/omnibus/changelog.rb +2 -2
  16. data/lib/omnibus/changelog_printer.rb +4 -4
  17. data/lib/omnibus/cleaner.rb +4 -4
  18. data/lib/omnibus/cli/base.rb +15 -15
  19. data/lib/omnibus/cli/cache.rb +13 -13
  20. data/lib/omnibus/cli/changelog.rb +8 -9
  21. data/lib/omnibus/cli/publish.rb +12 -13
  22. data/lib/omnibus/cli.rb +26 -27
  23. data/lib/omnibus/compressor.rb +6 -6
  24. data/lib/omnibus/compressors/base.rb +7 -2
  25. data/lib/omnibus/compressors/dmg.rb +12 -12
  26. data/lib/omnibus/compressors/null.rb +1 -1
  27. data/lib/omnibus/compressors/tgz.rb +8 -8
  28. data/lib/omnibus/config.rb +37 -26
  29. data/lib/omnibus/core_extensions/open_uri.rb +3 -3
  30. data/lib/omnibus/core_extensions.rb +1 -1
  31. data/lib/omnibus/digestable.rb +5 -4
  32. data/lib/omnibus/download_helpers.rb +7 -6
  33. data/lib/omnibus/exceptions.rb +29 -13
  34. data/lib/omnibus/fetcher.rb +0 -1
  35. data/lib/omnibus/fetchers/git_fetcher.rb +7 -7
  36. data/lib/omnibus/fetchers/net_fetcher.rb +19 -19
  37. data/lib/omnibus/fetchers/path_fetcher.rb +1 -1
  38. data/lib/omnibus/file_syncer.rb +3 -3
  39. data/lib/omnibus/generator.rb +60 -47
  40. data/lib/omnibus/git_cache.rb +33 -22
  41. data/lib/omnibus/git_repository.rb +5 -5
  42. data/lib/omnibus/health_check.rb +122 -119
  43. data/lib/omnibus/instrumentation.rb +1 -1
  44. data/lib/omnibus/licensing.rb +348 -60
  45. data/lib/omnibus/logger.rb +12 -9
  46. data/lib/omnibus/logging.rb +1 -1
  47. data/lib/omnibus/manifest.rb +4 -4
  48. data/lib/omnibus/manifest_diff.rb +6 -7
  49. data/lib/omnibus/manifest_entry.rb +1 -1
  50. data/lib/omnibus/metadata.rb +36 -36
  51. data/lib/omnibus/ohai.rb +6 -7
  52. data/lib/omnibus/package.rb +1 -1
  53. data/lib/omnibus/packager.rb +37 -28
  54. data/lib/omnibus/packagers/appx.rb +86 -0
  55. data/lib/omnibus/packagers/base.rb +21 -18
  56. data/lib/omnibus/packagers/bff.rb +22 -24
  57. data/lib/omnibus/packagers/deb.rb +20 -20
  58. data/lib/omnibus/packagers/ips.rb +18 -17
  59. data/lib/omnibus/packagers/makeself.rb +7 -7
  60. data/lib/omnibus/packagers/msi.rb +38 -193
  61. data/lib/omnibus/packagers/pkg.rb +16 -16
  62. data/lib/omnibus/packagers/rpm.rb +53 -54
  63. data/lib/omnibus/packagers/solaris.rb +14 -14
  64. data/lib/omnibus/packagers/windows_base.rb +192 -0
  65. data/lib/omnibus/project.rb +45 -43
  66. data/lib/omnibus/publisher.rb +3 -3
  67. data/lib/omnibus/publishers/artifactory_publisher.rb +39 -39
  68. data/lib/omnibus/publishers/s3_publisher.rb +7 -7
  69. data/lib/omnibus/reports.rb +10 -10
  70. data/lib/omnibus/s3_cache.rb +7 -7
  71. data/lib/omnibus/s3_helpers.rb +8 -7
  72. data/lib/omnibus/semantic_version.rb +1 -1
  73. data/lib/omnibus/software.rb +131 -81
  74. data/lib/omnibus/sugarable.rb +10 -10
  75. data/lib/omnibus/templating.rb +5 -5
  76. data/lib/omnibus/thread_pool.rb +1 -1
  77. data/lib/omnibus/util.rb +5 -5
  78. data/lib/omnibus/version.rb +1 -1
  79. data/lib/omnibus.rb +65 -65
  80. data/omnibus.gemspec +34 -32
  81. data/resources/appx/AppxManifest.xml.erb +18 -0
  82. data/resources/appx/assets/clear.png +0 -0
  83. data/spec/fixtures/licensing/license_scout/snoopy/ruby_bundler-bundler-audit-0.5.0-COPYING.txt +674 -0
  84. data/spec/fixtures/licensing/license_scout/snoopy/ruby_bundler-inifile-3.0.0-README.md +215 -0
  85. data/spec/fixtures/licensing/license_scout/snoopy/snoopy-dependency-licenses.json +24 -0
  86. data/spec/fixtures/licensing/license_scout/zlib/ruby_bundler-inifile-3.0.0-README.md +215 -0
  87. data/spec/fixtures/licensing/license_scout/zlib/ruby_bundler-mime-types-3.1-Licence.rdoc +25 -0
  88. data/spec/fixtures/licensing/license_scout/zlib/ruby_bundler-mini_portile2-2.1.0-LICENSE.txt +20 -0
  89. data/spec/fixtures/licensing/license_scout/zlib/zlib-dependency-licenses.json +32 -0
  90. data/spec/functional/builder_spec.rb +149 -150
  91. data/spec/functional/fetchers/git_fetcher_spec.rb +69 -71
  92. data/spec/functional/fetchers/net_fetcher_spec.rb +79 -79
  93. data/spec/functional/fetchers/path_fetcher_spec.rb +19 -20
  94. data/spec/functional/file_syncer_spec.rb +74 -74
  95. data/spec/functional/licensing_spec.rb +344 -35
  96. data/spec/functional/templating_spec.rb +17 -17
  97. data/spec/spec_helper.rb +20 -20
  98. data/spec/support/examples.rb +21 -15
  99. data/spec/support/file_helpers.rb +1 -1
  100. data/spec/support/git_helpers.rb +37 -37
  101. data/spec/support/matchers.rb +3 -3
  102. data/spec/support/ohai_helpers.rb +4 -4
  103. data/spec/support/path_helpers.rb +2 -2
  104. data/spec/support/shell_helpers.rb +2 -2
  105. data/spec/unit/build_version_dsl_spec.rb +5 -5
  106. data/spec/unit/build_version_spec.rb +63 -63
  107. data/spec/unit/builder_spec.rb +86 -70
  108. data/spec/unit/changelog_spec.rb +4 -4
  109. data/spec/unit/changelogprinter_spec.rb +130 -0
  110. data/spec/unit/cleanroom_spec.rb +11 -11
  111. data/spec/unit/compressor_spec.rb +16 -16
  112. data/spec/unit/compressors/base_spec.rb +6 -6
  113. data/spec/unit/compressors/dmg_spec.rb +76 -76
  114. data/spec/unit/compressors/null_spec.rb +4 -4
  115. data/spec/unit/compressors/tgz_spec.rb +20 -20
  116. data/spec/unit/config_spec.rb +44 -43
  117. data/spec/unit/digestable_spec.rb +13 -13
  118. data/spec/unit/fetcher_spec.rb +11 -12
  119. data/spec/unit/fetchers/git_fetcher_spec.rb +31 -31
  120. data/spec/unit/fetchers/net_fetcher_spec.rb +172 -173
  121. data/spec/unit/fetchers/path_fetcher_spec.rb +18 -18
  122. data/spec/unit/generator_spec.rb +38 -38
  123. data/spec/unit/git_cache_spec.rb +56 -54
  124. data/spec/unit/git_repository_spec.rb +2 -2
  125. data/spec/unit/health_check_spec.rb +40 -40
  126. data/spec/unit/library_spec.rb +35 -35
  127. data/spec/unit/manifest_diff_spec.rb +10 -11
  128. data/spec/unit/manifest_spec.rb +17 -17
  129. data/spec/unit/metadata_spec.rb +152 -152
  130. data/spec/unit/ohai_spec.rb +5 -5
  131. data/spec/unit/omnibus_spec.rb +31 -31
  132. data/spec/unit/package_spec.rb +20 -20
  133. data/spec/unit/packager_spec.rb +48 -42
  134. data/spec/unit/packagers/appx_spec.rb +165 -0
  135. data/spec/unit/packagers/base_spec.rb +34 -34
  136. data/spec/unit/packagers/bff_spec.rb +60 -60
  137. data/spec/unit/packagers/deb_spec.rb +71 -71
  138. data/spec/unit/packagers/ips_spec.rb +45 -45
  139. data/spec/unit/packagers/makeself_spec.rb +22 -22
  140. data/spec/unit/packagers/msi_spec.rb +141 -147
  141. data/spec/unit/packagers/pkg_spec.rb +59 -60
  142. data/spec/unit/packagers/rpm_spec.rb +125 -126
  143. data/spec/unit/packagers/solaris_spec.rb +52 -52
  144. data/spec/unit/project_spec.rb +137 -135
  145. data/spec/unit/publisher_spec.rb +70 -70
  146. data/spec/unit/publishers/artifactory_publisher_spec.rb +85 -85
  147. data/spec/unit/publishers/s3_publisher_spec.rb +36 -36
  148. data/spec/unit/s3_cacher_spec.rb +34 -34
  149. data/spec/unit/s3_helpers_spec.rb +6 -6
  150. data/spec/unit/semantic_version_spec.rb +2 -2
  151. data/spec/unit/software_spec.rb +346 -384
  152. data/spec/unit/sugarable_spec.rb +10 -10
  153. data/spec/unit/util_spec.rb +60 -60
  154. metadata +54 -6
  155. data/.rubocop.yml +0 -48
@@ -14,21 +14,56 @@
14
14
  # limitations under the License.
15
15
  #
16
16
 
17
- require 'uri'
18
- require 'fileutils'
19
- require 'omnibus/download_helpers'
17
+ require "uri"
18
+ require "fileutils"
19
+ require "omnibus/download_helpers"
20
+ require "license_scout/collector"
21
+ require "license_scout/options"
20
22
 
21
23
  module Omnibus
22
24
  class Licensing
23
25
  include Logging
24
26
  include DownloadHelpers
27
+ include Sugarable
25
28
 
26
29
  OUTPUT_DIRECTORY = "LICENSES".freeze
30
+ CACHE_DIRECTORY = "license-cache".freeze
27
31
 
28
32
  class << self
29
- # @see (Licensing#create!)
30
- def create!(project)
31
- new(project).create!
33
+
34
+ # Creates a new instance of Licensing, executes preparation steps, then
35
+ # yields control to a given block, and then creates a summary of the
36
+ # included licenses.
37
+ #
38
+ # @example Building a project:
39
+ #
40
+ # Licensing.create_incrementally(self) do |license_collector|
41
+ # softwares.each do |software|
42
+ # software.build_me([license_collector])
43
+ # end
44
+ # end
45
+ #
46
+ # @param [Project] project
47
+ # The project being built.
48
+ #
49
+ # @yieldparam [Licensing] license_collector
50
+ # Yields an instance of Licensing. Call #execute_post_build to copy the
51
+ # license files for a Software definition.
52
+ #
53
+ # @return [Licensing]
54
+ #
55
+ def create_incrementally(project)
56
+ new(project).tap do |license_collector|
57
+
58
+ license_collector.prepare
59
+ license_collector.validate_license_info
60
+
61
+ yield license_collector
62
+
63
+ license_collector.process_transitive_dependency_licensing_info
64
+ license_collector.create_project_license_file
65
+ license_collector.raise_if_warnings_fatal!
66
+ end
32
67
  end
33
68
  end
34
69
 
@@ -39,35 +74,80 @@ module Omnibus
39
74
  #
40
75
  attr_reader :project
41
76
 
77
+ #
78
+ # The warnings encountered while preparing the licensing information
79
+ #
80
+ # @return [Array<String>]
81
+ #
82
+ attr_reader :licensing_warnings
83
+
84
+ #
85
+ # The warnings encountered while preparing the licensing information for
86
+ # transitive dependencies.
87
+ #
88
+ # @return [Array<String>]
89
+ #
90
+ attr_reader :transitive_dependency_licensing_warnings
91
+
92
+ #
93
+ # Manifest data of transitive dependency licensing information
94
+ #
95
+ # @return Hash
96
+ #
97
+ attr_reader :dep_license_map
98
+
42
99
  #
43
100
  # @param [Project] project
44
101
  # the project to create licenses for.
45
102
  #
46
103
  def initialize(project)
47
104
  @project = project
105
+ @licensing_warnings = []
106
+ @transitive_dependency_licensing_warnings = []
107
+ @dep_license_map = {}
48
108
  end
49
109
 
50
110
  #
51
- # Creates the license files for given project.
52
- # It is assumed that the project has already been built.
111
+ # Creates the required directories for licenses.
53
112
  #
54
113
  # @return [void]
55
114
  #
56
- def create!
57
- prepare
58
- validate_license_info
59
- create_software_license_files
60
- create_project_license_file
115
+ def prepare
116
+ FileUtils.rm_rf(output_dir)
117
+ FileUtils.mkdir_p(output_dir)
118
+ FileUtils.touch(output_dir_gitkeep_file)
119
+ FileUtils.rm_rf(cache_dir)
120
+ FileUtils.mkdir_p(cache_dir)
121
+ FileUtils.touch(cache_dir_gitkeep_file)
61
122
  end
62
123
 
124
+ # Required callback to use instances of this class as a build wrapper for
125
+ # Software#build_me. Licensing doesn't need to do anything pre-build, so
126
+ # this does nothing.
63
127
  #
64
- # Creates the required directories for licenses.
128
+ # @param [Software] software
65
129
  #
66
130
  # @return [void]
67
131
  #
68
- def prepare
69
- FileUtils.rm_rf(output_dir)
70
- FileUtils.mkdir_p(output_dir)
132
+ def execute_pre_build(software)
133
+ end
134
+
135
+ # Callback that gets called by Software#build_me after the build is done.
136
+ # Invokes license copying for the given software. This ensures that
137
+ # licenses are copied before a git cache snapshot is taken, so that the
138
+ # license files are correctly restored when a build is skipped due to a
139
+ # cache hit.
140
+ #
141
+ # @param [Software] software
142
+ #
143
+ # @return [void]
144
+ #
145
+ def execute_post_build(software)
146
+ collect_licenses_for(software)
147
+
148
+ unless software.skip_transitive_dependency_licensing
149
+ collect_transitive_dependency_licenses_for(software)
150
+ end
71
151
  end
72
152
 
73
153
  #
@@ -91,7 +171,7 @@ module Omnibus
91
171
 
92
172
  # Check used license is a standard license
93
173
  if project.license != "Unspecified" && !STANDARD_LICENSES.include?(project.license)
94
- licensing_warning("Project '#{project.name}' is using '#{project.license}' which is not one of the standard licenses identified in https://opensource.org/licenses/alphabetical. Consider using one of the standard licenses.")
174
+ licensing_info("Project '#{project.name}' is using '#{project.license}' which is not one of the standard licenses identified in https://opensource.org/licenses/alphabetical. Consider using one of the standard licenses.")
95
175
  end
96
176
 
97
177
  # Now let's check the licensing info for software components
@@ -108,7 +188,7 @@ module Omnibus
108
188
 
109
189
  # Check if the software license is one of the standard licenses
110
190
  if license_info[:license] != "Unspecified" && !STANDARD_LICENSES.include?(license_info[:license])
111
- licensing_warning("Software '#{software_name}' uses license '#{license_info[:license]}' which is not one of the standard licenses identified in https://opensource.org/licenses/alphabetical. Consider using one of the standard licenses.")
191
+ licensing_info("Software '#{software_name}' uses license '#{license_info[:license]}' which is not one of the standard licenses identified in https://opensource.org/licenses/alphabetical. Consider using one of the standard licenses.")
112
192
  end
113
193
  end
114
194
  end
@@ -123,50 +203,14 @@ module Omnibus
123
203
  # @return [void]
124
204
  #
125
205
  def create_project_license_file
126
- File.open(project.license_file_path, 'w') do |f|
206
+ File.open(project.license_file_path, "w") do |f|
127
207
  f.puts "#{project.name} #{project.build_version} license: \"#{project.license}\""
128
208
  f.puts ""
129
209
  f.puts project_license_content
130
210
  f.puts ""
131
211
  f.puts components_license_summary
132
- end
133
- end
134
-
135
- #
136
- # Copies the license files specified by the software components into the
137
- # output directory.
138
- #
139
- # @return [void]
140
- #
141
- def create_software_license_files
142
- license_map.each do |name, values|
143
- license_files = values[:license_files]
144
-
145
- license_files.each do |license_file|
146
- if license_file
147
- output_file = license_package_location(name, license_file)
148
-
149
- if local?(license_file)
150
- input_file = File.expand_path(license_file, values[:project_dir])
151
- if File.exist?(input_file)
152
- FileUtils.cp(input_file, output_file)
153
- else
154
- licensing_warning("License file '#{input_file}' does not exist for software '#{name}'.")
155
- end
156
- else
157
- begin
158
- download_file!(license_file, output_file, enable_progress_bar: false)
159
- rescue SocketError,
160
- Errno::ECONNREFUSED,
161
- Errno::ECONNRESET,
162
- Errno::ENETUNREACH,
163
- Timeout::Error,
164
- OpenURI::HTTPError
165
- licensing_warning("Can not download license file '#{license_file}' for software '#{name}'.")
166
- end
167
- end
168
- end
169
- end
212
+ f.puts ""
213
+ f.puts dependencies_license_summary
170
214
  end
171
215
  end
172
216
 
@@ -176,7 +220,7 @@ module Omnibus
176
220
  # @return [String]
177
221
  #
178
222
  def project_license_content
179
- project.license_file.nil? ? "" : IO.read(File.join(Config.project_root,project.license_file))
223
+ project.license_file.nil? ? "" : IO.read(File.join(Config.project_root, project.license_file))
180
224
  end
181
225
 
182
226
  #
@@ -213,6 +257,41 @@ module Omnibus
213
257
  out
214
258
  end
215
259
 
260
+ #
261
+ # Summary of the licenses of the transitive dependencies of the project.
262
+ # It is in the form of:
263
+ # ...
264
+ # This product includes inifile 3.0.0
265
+ # which is a 'ruby_bundler' dependency of 'chef',
266
+ # and which is available under a 'MIT' License.
267
+ # For details, see:
268
+ # /opt/opscode/LICENSES/ruby_bundler-inifile-3.0.0-README.md
269
+ # ...
270
+ #
271
+ # @return [String]
272
+ #
273
+ def dependencies_license_summary
274
+ out = "\n\n"
275
+
276
+ dep_license_map.each do |dep_mgr_name, data|
277
+ data.each do |dep_name, data|
278
+ data.each do |dep_version, dep_data|
279
+ projects = dep_data["dependency_of"].sort.map { |p| "'#{p}'" }.join(", ")
280
+ files = dep_data["license_files"].map { |f| File.join(output_dir, f) }
281
+
282
+ out << "This product includes #{dep_name} #{dep_version}\n"
283
+ out << "which is a '#{dep_mgr_name}' dependency of #{projects},\n"
284
+ out << "and which is available under a '#{dep_data["license"]}' License.\n"
285
+ out << "For details, see:\n"
286
+ out << files.join("\n")
287
+ out << "\n\n"
288
+ end
289
+ end
290
+ end
291
+
292
+ out
293
+ end
294
+
216
295
  #
217
296
  # Map that collects information about the licenses of the softwares
218
297
  # included in the project.
@@ -279,6 +358,34 @@ module Omnibus
279
358
  File.expand_path(OUTPUT_DIRECTORY, project.install_dir)
280
359
  end
281
360
 
361
+ #
362
+ # Path to a .gitkeep file we create in the output dir so git caching
363
+ # doesn't delete the directory.
364
+ #
365
+ # @return [String]
366
+ #
367
+ def output_dir_gitkeep_file
368
+ File.join(output_dir, ".gitkeep")
369
+ end
370
+
371
+ # Cache directory where transitive dependency licenses will be collected in.
372
+ #
373
+ # @return [String]
374
+ #
375
+ def cache_dir
376
+ File.expand_path(CACHE_DIRECTORY, project.install_dir)
377
+ end
378
+
379
+ #
380
+ # Path to a .gitkeep file we create in the cache dir so git caching
381
+ # doesn't delete the directory.
382
+ #
383
+ # @return [String]
384
+ #
385
+ def cache_dir_gitkeep_file
386
+ File.join(cache_dir, ".gitkeep")
387
+ end
388
+
282
389
  #
283
390
  # Returns if the given path to a license is local or a remote url.
284
391
  #
@@ -290,14 +397,194 @@ module Omnibus
290
397
  end
291
398
 
292
399
  #
293
- # Logs the given message as warning.
400
+ # Logs the given message as info.
401
+ #
402
+ # This method should only be used for detecting in a license is known or not.
403
+ # In the future, we will introduce a configurable way to whitelist or blacklist
404
+ # the allowed licenses. Once we implement that we need to stop using this method.
405
+ #
406
+ # @param [String] message
407
+ # message to log as warning
408
+ def licensing_info(message)
409
+ log.info(log_key) { message }
410
+ end
411
+
412
+ #
413
+ # Logs the given message as warning or fails the build depending on the
414
+ # :fatal_licensing_warnings configuration setting.
294
415
  #
295
416
  # @param [String] message
296
417
  # message to log as warning
297
418
  def licensing_warning(message)
419
+ licensing_warnings << message
420
+ log.warn(log_key) { message }
421
+ end
422
+
423
+ #
424
+ # Logs the given message as warning or fails the build depending on the
425
+ # :fatal_transitive_dependency_licensing_warnings configuration setting.
426
+ #
427
+ # @param [String] message
428
+ # message to log as warning
429
+ def transitive_dependency_licensing_warning(message)
430
+ transitive_dependency_licensing_warnings << message
298
431
  log.warn(log_key) { message }
299
432
  end
300
433
 
434
+ def raise_if_warnings_fatal!
435
+ warnings_to_raise = []
436
+ if Config.fatal_licensing_warnings && !licensing_warnings.empty?
437
+ warnings_to_raise << licensing_warnings
438
+ end
439
+
440
+ if Config.fatal_transitive_dependency_licensing_warnings && !transitive_dependency_licensing_warnings.empty?
441
+ warnings_to_raise << transitive_dependency_licensing_warnings
442
+ end
443
+
444
+ warnings_to_raise.flatten!
445
+ raise LicensingError.new(warnings_to_raise) unless warnings_to_raise.empty?
446
+ end
447
+
448
+ # 1. Parse all the licensing information for all software from 'cache_dir'
449
+ # 2. Merge and drop the duplicates
450
+ # 3. Add these licenses to the main manifest, to be merged with the main
451
+ # licensing information from software definitions.
452
+ def process_transitive_dependency_licensing_info
453
+ Dir.glob("#{cache_dir}/*/*-dependency-licenses.json").each do |license_manifest_path|
454
+ license_manifest_data = FFI_Yajl::Parser.parse(File.read(license_manifest_path))
455
+ project_name = license_manifest_data["project_name"]
456
+ dependency_license_dir = File.dirname(license_manifest_path)
457
+
458
+ license_manifest_data["dependency_managers"].each do |dep_mgr_name, dependencies|
459
+ dep_license_map[dep_mgr_name] ||= {}
460
+
461
+ dependencies.each do |dependency|
462
+ # Copy dependency files
463
+ dependency["license_files"].each do |f|
464
+ license_path = File.join(dependency_license_dir, f)
465
+ output_path = File.join(output_dir, f)
466
+ FileUtils.cp(license_path, output_path)
467
+ end
468
+
469
+ dep_name = dependency["name"]
470
+ dep_version = dependency["version"]
471
+
472
+ # If we already have this dependency we do not need to add it again.
473
+ if dep_license_map[dep_mgr_name][dep_name] && dep_license_map[dep_mgr_name][dep_name][dep_version]
474
+ dep_license_map[dep_mgr_name][dep_name][dep_version]["dependency_of"] << project_name
475
+ else
476
+ dep_license_map[dep_mgr_name][dep_name] ||= {}
477
+ dep_license_map[dep_mgr_name][dep_name][dep_version] = {
478
+ "license" => dependency["license"],
479
+ "license_files" => dependency["license_files"],
480
+ "dependency_of" => [ project_name ],
481
+ }
482
+ end
483
+ end
484
+ end
485
+ end
486
+
487
+ FileUtils.rm_rf(cache_dir)
488
+ end
489
+
490
+ private
491
+
492
+ # Uses license_scout to collect the licenses for transitive dependencies
493
+ # into #{output_dir}/license-cache/#{software.name}
494
+ def collect_transitive_dependency_licenses_for(software)
495
+ # We collect the licenses of the transitive dependencies of this software
496
+ # with LicenseScout. We place these files under
497
+ # /opt/project-name/license-cache for them to be cached in git_cache. Once
498
+ # the build completes we will process these license files but we need to
499
+ # perform this step after build, before git_cache to be able to operate
500
+ # correctly with the git_cache.
501
+ license_output_dir = File.join(cache_dir, software.name)
502
+
503
+ collector = LicenseScout::Collector.new(
504
+ software.project.name,
505
+ software.project_dir,
506
+ license_output_dir,
507
+ LicenseScout::Options.new(
508
+ environment: software.with_embedded_path,
509
+ ruby_bin: software.embedded_bin("ruby")
510
+ )
511
+ )
512
+
513
+ begin
514
+ collector.run
515
+ collector.issue_report.each { |i| transitive_dependency_licensing_warning(i) }
516
+ rescue LicenseScout::Exceptions::UnsupportedProjectType => e
517
+ # Looks like this project is not supported by LicenseScout. Either the
518
+ # language and the dependency manager used by the project is not
519
+ # supported, or the software definition does not have any transitive
520
+ # dependencies. In the latter case software definition should set
521
+ # 'skip_transitive_dependency_licensing' to 'true' to correct this
522
+ # error.
523
+ transitive_dependency_licensing_warning(<<-EOH)
524
+ Software '#{software.name}' is not supported project type for transitive \
525
+ dependency license collection. See https://github.com/chef/license_scout for \
526
+ the list of supported languages and dependency managers. If this project does \
527
+ not have any transitive dependencies, consider setting \
528
+ 'skip_transitive_dependency_licensing' to 'true' in order to correct this error.
529
+ EOH
530
+ rescue LicenseScout::Exceptions::Error => e
531
+ transitive_dependency_licensing_warning(<<-EOH)
532
+ Can not automatically detect licensing information for '#{software.name}' using \
533
+ license_scout. Error is: '#{e}'
534
+ EOH
535
+ rescue Exception => e
536
+ transitive_dependency_licensing_warning(<<-EOH)
537
+ Unexpected error while running license_scout for '#{software.name}': '#{e}'
538
+ EOH
539
+ end
540
+ end
541
+
542
+ # Collect the license files for the software.
543
+ def collect_licenses_for(software)
544
+ return nil if software.license == :project_license
545
+
546
+ software_name = software.name
547
+ license_data = license_map[software_name]
548
+ license_files = license_data[:license_files]
549
+
550
+ license_files.each do |license_file|
551
+ if license_file
552
+ output_file = license_package_location(software_name, license_file)
553
+
554
+ if local?(license_file)
555
+ input_file = File.expand_path(license_file, license_data[:project_dir])
556
+ if File.exist?(input_file)
557
+ FileUtils.cp(input_file, output_file)
558
+ File.chmod 0644, output_file unless windows?
559
+ else
560
+ licensing_warning("License file '#{input_file}' does not exist for software '#{software_name}'.")
561
+ # If we got here, we need to fail now so we don't take a git
562
+ # cache snapshot, or else the software build could be restored
563
+ # from cache without fixing the license issue.
564
+ raise_if_warnings_fatal!
565
+ end
566
+ else
567
+ begin
568
+ download_file!(license_file, output_file, enable_progress_bar: false)
569
+ File.chmod 0644, output_file unless windows?
570
+ rescue SocketError,
571
+ Errno::ECONNREFUSED,
572
+ Errno::ECONNRESET,
573
+ Errno::ENETUNREACH,
574
+ Timeout::Error,
575
+ OpenURI::HTTPError,
576
+ OpenSSL::SSL::SSLError
577
+ licensing_warning("Can not download license file '#{license_file}' for software '#{software_name}'.")
578
+ # If we got here, we need to fail now so we don't take a git
579
+ # cache snapshot, or else the software build could be restored
580
+ # from cache without fixing the license issue.
581
+ raise_if_warnings_fatal!
582
+ end
583
+ end
584
+ end
585
+ end
586
+ end
587
+
301
588
  STANDARD_LICENSES = [
302
589
  #
303
590
  # Below licenses are compiled based on https://opensource.org/licenses/alphabetical
@@ -392,4 +679,5 @@ module Omnibus
392
679
  "Chef-MLSA", # https://www.chef.io/online-master-agreement/
393
680
  ].freeze
394
681
  end
682
+
395
683
  end
@@ -16,19 +16,22 @@
16
16
 
17
17
  module Omnibus
18
18
  class Logger
19
+
20
+ require "time"
21
+
19
22
  #
20
23
  # The amount of padding on the left column.
21
24
  #
22
25
  # @return [Fixnum]
23
26
  #
24
- LEFT = 40
27
+ LEFT = 30
25
28
 
26
29
  #
27
30
  # Our custom log levels, in order of severity
28
31
  #
29
32
  # @return [Array]
30
33
  #
31
- LEVELS = %w(UNKNOWN INTERNAL DEBUG INFO WARN ERROR FATAL NOTHING).freeze
34
+ LEVELS = %w{UNKNOWN INTERNAL DEBUG INFO WARN ERROR FATAL NOTHING}.freeze
32
35
 
33
36
  #
34
37
  # The mutex lock for synchronizing IO writing.
@@ -48,7 +51,7 @@ module Omnibus
48
51
  #
49
52
  def initialize(io = $stdout)
50
53
  @io = io
51
- @level = LEVELS.index('WARN')
54
+ @level = LEVELS.index("WARN")
52
55
  end
53
56
 
54
57
  LEVELS.each.with_index do |level, index|
@@ -66,8 +69,8 @@ module Omnibus
66
69
  # @see (Logger#add)
67
70
  #
68
71
  def deprecated(progname, &block)
69
- meta = Proc.new { "DEPRECATED: #{block.call}" }
70
- add(LEVELS.index('WARN'), progname, &meta)
72
+ meta = Proc.new { "DEPRECATED: #{yield}" }
73
+ add(LEVELS.index("WARN"), progname, &meta)
71
74
  end
72
75
 
73
76
  #
@@ -135,7 +138,7 @@ module Omnibus
135
138
  else
136
139
  left = "#{format_severity(severity)} | "
137
140
  end
138
- "#{left.rjust(LEFT)}#{message}\n"
141
+ "#{left.rjust(LEFT)}#{Time.now.iso8601()} | #{message}\n"
139
142
  end
140
143
 
141
144
  #
@@ -145,9 +148,9 @@ module Omnibus
145
148
  #
146
149
  def format_severity(severity)
147
150
  if severity == 0
148
- '_'
151
+ "_"
149
152
  else
150
- (LEVELS[severity] || '?')[0]
153
+ (LEVELS[severity] || "?")[0]
151
154
  end
152
155
  end
153
156
 
@@ -167,7 +170,7 @@ module Omnibus
167
170
  def initialize(log, level = :debug)
168
171
  @log = log
169
172
  @level = level
170
- @buffer = ''
173
+ @buffer = ""
171
174
  end
172
175
 
173
176
  #
@@ -39,7 +39,7 @@ module Omnibus
39
39
  # @return [String]
40
40
  #
41
41
  def log_key
42
- @log_key ||= (name || '(Anonymous)').split('::')[1..-1].join('::')
42
+ @log_key ||= (name || "(Anonymous)").split("::")[1..-1].join("::")
43
43
  end
44
44
  end
45
45
 
@@ -14,7 +14,7 @@
14
14
  # limitations under the License.
15
15
  #
16
16
 
17
- require 'ffi_yajl'
17
+ require "ffi_yajl"
18
18
 
19
19
  module Omnibus
20
20
  class Manifest
@@ -27,7 +27,7 @@ module Omnibus
27
27
  LATEST_MANIFEST_FORMAT = 2
28
28
 
29
29
  attr_reader :build_version, :build_git_revision, :license
30
- def initialize(version=nil, git_rev=nil, license="Unspecified")
30
+ def initialize(version = nil, git_rev = nil, license = "Unspecified")
31
31
  @data = {}
32
32
  @build_version = version
33
33
  @build_git_revision = git_rev
@@ -68,13 +68,13 @@ module Omnibus
68
68
  end
69
69
 
70
70
  def to_hash
71
- software_hash = @data.inject({}) do |memo, (k,v)|
71
+ software_hash = @data.inject({}) do |memo, (k, v)|
72
72
  memo[k] = v.to_hash
73
73
  memo
74
74
  end
75
75
  ret = {
76
76
  manifest_format: LATEST_MANIFEST_FORMAT,
77
- software: software_hash
77
+ software: software_hash,
78
78
  }
79
79
  ret[:build_version] = build_version if build_version
80
80
  ret[:build_git_revision] = build_git_revision if build_git_revision
@@ -27,8 +27,8 @@ module Omnibus
27
27
  @updated ||=
28
28
  begin
29
29
  (first.entry_names & second.entry_names).collect do |name|
30
- diff(first.entry_for(name), second.entry_for(name))
31
- end.compact
30
+ diff(first.entry_for(name), second.entry_for(name))
31
+ end.compact
32
32
  end
33
33
  end
34
34
 
@@ -36,8 +36,8 @@ module Omnibus
36
36
  @removed ||=
37
37
  begin
38
38
  (first.entry_names - second.entry_names).collect do |name|
39
- removed_entry(first.entry_for(name))
40
- end
39
+ removed_entry(first.entry_for(name))
40
+ end
41
41
  end
42
42
  end
43
43
 
@@ -45,8 +45,8 @@ module Omnibus
45
45
  @added ||=
46
46
  begin
47
47
  (second.entry_names - first.entry_names).collect do |name|
48
- new_entry(second.entry_for(name))
49
- end
48
+ new_entry(second.entry_for(name))
49
+ end
50
50
  end
51
51
  end
52
52
 
@@ -65,7 +65,6 @@ module Omnibus
65
65
  source: entry.locked_source }
66
66
  end
67
67
 
68
-
69
68
  def removed_entry(entry)
70
69
  { name: entry.name,
71
70
  old_version: entry.locked_version,
@@ -32,7 +32,7 @@ module Omnibus
32
32
  locked_source: @locked_source,
33
33
  source_type: @source_type,
34
34
  described_version: @described_version,
35
- license: @license
35
+ license: @license,
36
36
  }
37
37
  end
38
38