gitlab-license_finder 6.14.2.1

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.
Files changed (180) hide show
  1. checksums.yaml +7 -0
  2. data/.force-build +0 -0
  3. data/.gitignore +13 -0
  4. data/.rspec +1 -0
  5. data/.rubocop.yml +70 -0
  6. data/CHANGELOG.md +981 -0
  7. data/CONTRIBUTING.md +121 -0
  8. data/Dockerfile +249 -0
  9. data/Gemfile +2 -0
  10. data/LICENSE +22 -0
  11. data/README.md +555 -0
  12. data/Rakefile +77 -0
  13. data/TODO.md +12 -0
  14. data/VERSION +1 -0
  15. data/appveyor.yml +21 -0
  16. data/bin/license_finder +6 -0
  17. data/bin/license_finder_pip.py +43 -0
  18. data/ci/pipelines/pull-request.yml.erb +141 -0
  19. data/ci/pipelines/release.yml.erb +200 -0
  20. data/ci/scripts/containerize-tests.sh +14 -0
  21. data/ci/scripts/pushscript.sh +32 -0
  22. data/ci/scripts/run-rubocop.sh +15 -0
  23. data/ci/scripts/run-tests.sh +24 -0
  24. data/ci/scripts/test.ps1 +81 -0
  25. data/ci/scripts/updateChangelog.sh +84 -0
  26. data/ci/tasks/build-and-push-gem.yml +10 -0
  27. data/ci/tasks/build-windows.yml +6 -0
  28. data/ci/tasks/build.yml +16 -0
  29. data/ci/tasks/rubocop.yml +15 -0
  30. data/ci/tasks/run-tests.yml +10 -0
  31. data/ci/tasks/update-changelog.yml +18 -0
  32. data/dlf +12 -0
  33. data/examples/Gemfile +4 -0
  34. data/examples/custom_erb_template.rb +24 -0
  35. data/examples/extract_license_data.rb +63 -0
  36. data/examples/sample_template.erb +7 -0
  37. data/lib/license_finder/cli/approvals.rb +28 -0
  38. data/lib/license_finder/cli/base.rb +107 -0
  39. data/lib/license_finder/cli/dependencies.rb +44 -0
  40. data/lib/license_finder/cli/ignored_dependencies.rb +32 -0
  41. data/lib/license_finder/cli/ignored_groups.rb +32 -0
  42. data/lib/license_finder/cli/inherited_decisions.rb +50 -0
  43. data/lib/license_finder/cli/licenses.rb +26 -0
  44. data/lib/license_finder/cli/main.rb +221 -0
  45. data/lib/license_finder/cli/makes_decisions.rb +38 -0
  46. data/lib/license_finder/cli/patched_thor.rb +33 -0
  47. data/lib/license_finder/cli/permitted_licenses.rb +32 -0
  48. data/lib/license_finder/cli/project_name.rb +32 -0
  49. data/lib/license_finder/cli/restricted_licenses.rb +32 -0
  50. data/lib/license_finder/cli.rb +20 -0
  51. data/lib/license_finder/configuration.rb +186 -0
  52. data/lib/license_finder/core.rb +118 -0
  53. data/lib/license_finder/decision_applier.rb +70 -0
  54. data/lib/license_finder/decisions.rb +312 -0
  55. data/lib/license_finder/decisions_factory.rb +13 -0
  56. data/lib/license_finder/diff.rb +51 -0
  57. data/lib/license_finder/license/any_matcher.rb +15 -0
  58. data/lib/license_finder/license/definitions.rb +366 -0
  59. data/lib/license_finder/license/header_matcher.rb +17 -0
  60. data/lib/license_finder/license/matcher.rb +24 -0
  61. data/lib/license_finder/license/none_matcher.rb +11 -0
  62. data/lib/license_finder/license/template.rb +19 -0
  63. data/lib/license_finder/license/templates/0BSD.txt +10 -0
  64. data/lib/license_finder/license/templates/Apache1_1.txt +16 -0
  65. data/lib/license_finder/license/templates/Apache2.txt +172 -0
  66. data/lib/license_finder/license/templates/BSD.txt +24 -0
  67. data/lib/license_finder/license/templates/CC01.txt +30 -0
  68. data/lib/license_finder/license/templates/CDDL1.txt +131 -0
  69. data/lib/license_finder/license/templates/EPL1.txt +86 -0
  70. data/lib/license_finder/license/templates/GPLv2.txt +339 -0
  71. data/lib/license_finder/license/templates/GPLv3.txt +674 -0
  72. data/lib/license_finder/license/templates/ISC.txt +2 -0
  73. data/lib/license_finder/license/templates/LGPL.txt +165 -0
  74. data/lib/license_finder/license/templates/LGPL2_1.txt +169 -0
  75. data/lib/license_finder/license/templates/MIT.txt +9 -0
  76. data/lib/license_finder/license/templates/MPL1_1.txt +469 -0
  77. data/lib/license_finder/license/templates/MPL2.txt +373 -0
  78. data/lib/license_finder/license/templates/NewBSD.txt +21 -0
  79. data/lib/license_finder/license/templates/OFL.txt +91 -0
  80. data/lib/license_finder/license/templates/Python.txt +47 -0
  81. data/lib/license_finder/license/templates/Ruby.txt +52 -0
  82. data/lib/license_finder/license/templates/SimplifiedBSD.txt +19 -0
  83. data/lib/license_finder/license/templates/WTFPL.txt +14 -0
  84. data/lib/license_finder/license/templates/Zlib.txt +17 -0
  85. data/lib/license_finder/license/text.rb +45 -0
  86. data/lib/license_finder/license.rb +117 -0
  87. data/lib/license_finder/license_aggregator.rb +59 -0
  88. data/lib/license_finder/logger.rb +69 -0
  89. data/lib/license_finder/package.rb +202 -0
  90. data/lib/license_finder/package_delta.rb +61 -0
  91. data/lib/license_finder/package_manager.rb +181 -0
  92. data/lib/license_finder/package_managers/bower.rb +37 -0
  93. data/lib/license_finder/package_managers/bundler.rb +110 -0
  94. data/lib/license_finder/package_managers/cargo.rb +38 -0
  95. data/lib/license_finder/package_managers/carthage.rb +68 -0
  96. data/lib/license_finder/package_managers/cocoa_pods.rb +61 -0
  97. data/lib/license_finder/package_managers/composer.rb +63 -0
  98. data/lib/license_finder/package_managers/conan.rb +28 -0
  99. data/lib/license_finder/package_managers/conda.rb +131 -0
  100. data/lib/license_finder/package_managers/dep.rb +43 -0
  101. data/lib/license_finder/package_managers/dotnet.rb +83 -0
  102. data/lib/license_finder/package_managers/erlangmk.rb +50 -0
  103. data/lib/license_finder/package_managers/glide.rb +36 -0
  104. data/lib/license_finder/package_managers/go_15vendorexperiment.rb +87 -0
  105. data/lib/license_finder/package_managers/go_dep.rb +80 -0
  106. data/lib/license_finder/package_managers/go_modules.rb +93 -0
  107. data/lib/license_finder/package_managers/go_workspace.rb +116 -0
  108. data/lib/license_finder/package_managers/govendor.rb +73 -0
  109. data/lib/license_finder/package_managers/gradle.rb +99 -0
  110. data/lib/license_finder/package_managers/gvt.rb +69 -0
  111. data/lib/license_finder/package_managers/maven.rb +65 -0
  112. data/lib/license_finder/package_managers/mix.rb +131 -0
  113. data/lib/license_finder/package_managers/npm.rb +57 -0
  114. data/lib/license_finder/package_managers/nuget.rb +154 -0
  115. data/lib/license_finder/package_managers/pip.rb +70 -0
  116. data/lib/license_finder/package_managers/pipenv.rb +63 -0
  117. data/lib/license_finder/package_managers/rebar.rb +65 -0
  118. data/lib/license_finder/package_managers/sbt.rb +50 -0
  119. data/lib/license_finder/package_managers/spm.rb +93 -0
  120. data/lib/license_finder/package_managers/trash.rb +43 -0
  121. data/lib/license_finder/package_managers/yarn.rb +107 -0
  122. data/lib/license_finder/package_utils/activation.rb +40 -0
  123. data/lib/license_finder/package_utils/conan_info_parser.rb +77 -0
  124. data/lib/license_finder/package_utils/gradle_dependency_finder.rb +15 -0
  125. data/lib/license_finder/package_utils/license_files.rb +41 -0
  126. data/lib/license_finder/package_utils/licensing.rb +39 -0
  127. data/lib/license_finder/package_utils/maven_dependency_finder.rb +15 -0
  128. data/lib/license_finder/package_utils/notice_files.rb +40 -0
  129. data/lib/license_finder/package_utils/possible_license_file.rb +27 -0
  130. data/lib/license_finder/package_utils/pypi.rb +41 -0
  131. data/lib/license_finder/package_utils/sbt_dependency_finder.rb +15 -0
  132. data/lib/license_finder/packages/bower_package.rb +42 -0
  133. data/lib/license_finder/packages/bundler_package.rb +33 -0
  134. data/lib/license_finder/packages/cargo_package.rb +28 -0
  135. data/lib/license_finder/packages/carthage_package.rb +18 -0
  136. data/lib/license_finder/packages/cocoa_pods_package.rb +22 -0
  137. data/lib/license_finder/packages/composer_package.rb +13 -0
  138. data/lib/license_finder/packages/conan_package.rb +23 -0
  139. data/lib/license_finder/packages/conda_package.rb +74 -0
  140. data/lib/license_finder/packages/erlangmk_package.rb +114 -0
  141. data/lib/license_finder/packages/go_package.rb +32 -0
  142. data/lib/license_finder/packages/gradle_package.rb +30 -0
  143. data/lib/license_finder/packages/manual_package.rb +27 -0
  144. data/lib/license_finder/packages/maven_package.rb +27 -0
  145. data/lib/license_finder/packages/merged_package.rb +44 -0
  146. data/lib/license_finder/packages/mix_package.rb +13 -0
  147. data/lib/license_finder/packages/npm_package.rb +171 -0
  148. data/lib/license_finder/packages/nuget_package.rb +13 -0
  149. data/lib/license_finder/packages/pip_package.rb +50 -0
  150. data/lib/license_finder/packages/rebar_package.rb +13 -0
  151. data/lib/license_finder/packages/sbt_package.rb +22 -0
  152. data/lib/license_finder/packages/spm_package.rb +18 -0
  153. data/lib/license_finder/packages/yarn_package.rb +13 -0
  154. data/lib/license_finder/platform.rb +15 -0
  155. data/lib/license_finder/project_finder.rb +62 -0
  156. data/lib/license_finder/report.rb +33 -0
  157. data/lib/license_finder/reports/csv_report.rb +99 -0
  158. data/lib/license_finder/reports/diff_report.rb +29 -0
  159. data/lib/license_finder/reports/erb_report.rb +58 -0
  160. data/lib/license_finder/reports/html_report.rb +13 -0
  161. data/lib/license_finder/reports/json_report.rb +30 -0
  162. data/lib/license_finder/reports/junit_report.rb +19 -0
  163. data/lib/license_finder/reports/markdown_report.rb +9 -0
  164. data/lib/license_finder/reports/merged_report.rb +16 -0
  165. data/lib/license_finder/reports/templates/bootstrap.css +9 -0
  166. data/lib/license_finder/reports/templates/html_report.erb +113 -0
  167. data/lib/license_finder/reports/templates/junit_report.erb +41 -0
  168. data/lib/license_finder/reports/templates/markdown_report.erb +49 -0
  169. data/lib/license_finder/reports/templates/xml_report.erb +19 -0
  170. data/lib/license_finder/reports/text_report.rb +12 -0
  171. data/lib/license_finder/reports/xml_report.rb +19 -0
  172. data/lib/license_finder/scanner.rb +83 -0
  173. data/lib/license_finder/shared_helpers/cmd.rb +13 -0
  174. data/lib/license_finder/shared_helpers/common_path.rb +29 -0
  175. data/lib/license_finder/version.rb +6 -0
  176. data/lib/license_finder.rb +14 -0
  177. data/license_finder.gemspec +72 -0
  178. data/release/instructions.md +8 -0
  179. data/swift-all-keys.asc +240 -0
  180. metadata +544 -0
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ require 'license_finder/logger'
6
+ require 'license_finder/license'
7
+
8
+ require 'license_finder/configuration'
9
+ require 'license_finder/package_manager'
10
+ require 'license_finder/decisions'
11
+ require 'license_finder/decisions_factory'
12
+ require 'license_finder/decision_applier'
13
+ require 'license_finder/scanner'
14
+
15
+ module LicenseFinder
16
+ # Coordinates setup
17
+ class Core
18
+ attr_reader :config
19
+
20
+ def self.default_logger
21
+ Logger.new
22
+ end
23
+
24
+ # Default +options+:
25
+ # {
26
+ # project_path: Pathname.pwd
27
+ # logger: nil, # can be :quiet or :debug
28
+ # decisions_file: "doc/dependency_decisions.yml",
29
+ # gradle_command: "gradle",
30
+ # rebar_command: "rebar",
31
+ # rebar_deps_dir: "deps",
32
+ # }
33
+ def initialize(configuration)
34
+ @logger = Logger.new(configuration.logger_mode)
35
+ @config = configuration
36
+ @scanner = Scanner.new(options)
37
+ end
38
+
39
+ def modifying
40
+ yield
41
+ decisions.save!(config.decisions_file_path)
42
+ end
43
+
44
+ extend Forwardable
45
+ def_delegators :decision_applier, :acknowledged, :unapproved, :restricted, :any_packages?
46
+
47
+ def project_name
48
+ decisions.project_name || config.project_path.basename.to_s
49
+ end
50
+
51
+ def project_path
52
+ config.project_path
53
+ end
54
+
55
+ def decisions
56
+ @decisions ||= DecisionsFactory.decisions(config.decisions_file_path)
57
+ end
58
+
59
+ def prepare_projects
60
+ clear_logs
61
+ package_managers = @scanner.active_package_managers
62
+ package_managers.each do |manager|
63
+ logger.debug manager.class, 'Running prepare on project'
64
+ manager.prepare
65
+ logger.debug manager.class, 'Finished prepare on project', color: :green
66
+ end
67
+ end
68
+
69
+ private
70
+
71
+ attr_reader :logger
72
+
73
+ # The core of the system. The saved decisions are applied to the current
74
+ # packages.
75
+ def decision_applier
76
+ # lazy, do not move to `initialize`
77
+ # Needs to be lazy loaded to prvent multiple decision appliers being created each time
78
+ @decision_applier ||= DecisionApplier.new(decisions: decisions, packages: current_packages)
79
+ end
80
+
81
+ def current_packages
82
+ # lazy, do not move to `initialize`
83
+ @scanner.active_packages
84
+ end
85
+
86
+ def clear_logs
87
+ FileUtils.rmtree config.log_directory, secure: true if File.directory? config.log_directory
88
+ end
89
+
90
+ def options # rubocop:disable Metrics/AbcSize
91
+ {
92
+ logger: logger,
93
+ project_path: config.project_path,
94
+ log_directory: File.join(config.log_directory, project_name),
95
+ ignored_groups: decisions.ignored_groups,
96
+ enabled_package_manager_ids: config.enabled_package_manager_ids,
97
+ go_full_version: config.go_full_version,
98
+ gradle_command: config.gradle_command,
99
+ gradle_include_groups: config.gradle_include_groups,
100
+ maven_include_groups: config.maven_include_groups,
101
+ maven_options: config.maven_options,
102
+ npm_options: config.npm_options,
103
+ pip_requirements_path: config.pip_requirements_path,
104
+ python_version: config.python_version,
105
+ rebar_command: config.rebar_command,
106
+ rebar_deps_dir: config.rebar_deps_dir,
107
+ elixir_command: config.elixir_command,
108
+ mix_command: config.mix_command,
109
+ mix_deps_dir: config.mix_deps_dir,
110
+ prepare: config.prepare,
111
+ prepare_no_fail: config.prepare_no_fail,
112
+ sbt_include_groups: config.sbt_include_groups,
113
+ conda_bash_setup_script: config.conda_bash_setup_script,
114
+ composer_check_require_only: config.composer_check_require_only
115
+ }
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class DecisionApplier
5
+ def initialize(options)
6
+ @decisions = options.fetch(:decisions)
7
+ @all_packages = options.fetch(:packages).to_set + @decisions.packages.to_set
8
+ @acknowledged = apply_decisions
9
+ end
10
+
11
+ attr_reader :acknowledged
12
+
13
+ def unapproved
14
+ acknowledged.reject(&:approved?)
15
+ end
16
+
17
+ def restricted
18
+ acknowledged.select(&:restricted?)
19
+ end
20
+
21
+ def any_packages?
22
+ all_packages.any?
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :decisions, :all_packages
28
+
29
+ def apply_decisions
30
+ all_packages
31
+ .reject { |package| ignored?(package) }
32
+ .map do |package|
33
+ with_homepage(
34
+ with_approval(
35
+ with_decided_licenses(package)
36
+ )
37
+ )
38
+ end
39
+ end
40
+
41
+ def ignored?(package)
42
+ decisions.ignored?(package.name) ||
43
+ (package.groups.any? && package.groups.all? { |group| decisions.ignored_group?(group) })
44
+ end
45
+
46
+ def with_decided_licenses(package)
47
+ decisions.licenses_of(package.name).each do |license|
48
+ package.decide_on_license license
49
+ end
50
+ package
51
+ end
52
+
53
+ def with_homepage(package)
54
+ homepage = decisions.homepage_of(package.name)
55
+ package.homepage = homepage if homepage
56
+ package
57
+ end
58
+
59
+ def with_approval(package)
60
+ if package.licenses.all? { |license| decisions.restricted?(license) }
61
+ package.restricted!
62
+ elsif decisions.approved?(package.name, package.version)
63
+ package.approved_manually!(decisions.approval_of(package.name, package.version))
64
+ elsif package.licenses.any? { |license| decisions.permitted?(license) }
65
+ package.permitted!
66
+ end
67
+ package
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,312 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open-uri'
4
+ require 'license_finder/license'
5
+
6
+ module LicenseFinder
7
+ class Decisions
8
+ ######
9
+ # READ
10
+ ######
11
+
12
+ attr_reader :packages, :permitted, :restricted, :ignored, :ignored_groups, :project_name, :inherited_decisions
13
+
14
+ def licenses_of(name)
15
+ @licenses[name]
16
+ end
17
+
18
+ def homepage_of(name)
19
+ @homepages[name]
20
+ end
21
+
22
+ def approval_of(name, version = nil)
23
+ if !@approvals.key?(name)
24
+ nil
25
+ elsif !version.nil?
26
+ @approvals[name] if @approvals[name][:safe_versions].empty? || @approvals[name][:safe_versions].include?(version)
27
+ elsif @approvals[name][:safe_versions].empty?
28
+ @approvals[name]
29
+ end
30
+ end
31
+
32
+ def approved?(name, version = nil)
33
+ if !@approvals.key?(name)
34
+ nil
35
+ elsif !version.nil?
36
+ @approvals.key?(name) && @approvals[name][:safe_versions].empty? || @approvals[name][:safe_versions].include?(version)
37
+ else
38
+ @approvals.key?(name)
39
+ end
40
+ end
41
+
42
+ def permitted?(lic)
43
+ if @permitted.include?(lic)
44
+ true
45
+ elsif lic.is_a?(OrLicense)
46
+ lic.sub_licenses.any? { |sub_lic| @permitted.include?(sub_lic) }
47
+ elsif lic.is_a?(AndLicense)
48
+ lic.sub_licenses.all? { |sub_lic| @permitted.include?(sub_lic) }
49
+ else
50
+ false
51
+ end
52
+ end
53
+
54
+ def restricted?(lic)
55
+ @restricted.include?(lic)
56
+ end
57
+
58
+ def ignored?(name)
59
+ @ignored.include?(name)
60
+ end
61
+
62
+ def ignored_group?(name)
63
+ @ignored_groups.include?(name)
64
+ end
65
+
66
+ #######
67
+ # WRITE
68
+ #######
69
+
70
+ TXN = Struct.new(:who, :why, :safe_when, :safe_versions) do
71
+ def self.from_hash(txn, versions)
72
+ new(txn[:who], txn[:why], txn[:when], versions || [])
73
+ end
74
+ end
75
+
76
+ def initialize
77
+ @decisions = []
78
+ @packages = Set.new
79
+ @licenses = Hash.new { |h, k| h[k] = Set.new }
80
+ @homepages = {}
81
+ @approvals = {}
82
+ @permitted = Set.new
83
+ @restricted = Set.new
84
+ @ignored = Set.new
85
+ @ignored_groups = Set.new
86
+ @inherited_decisions = Set.new
87
+ end
88
+
89
+ def add_package(name, version, txn = {})
90
+ add_decision [:add_package, name, version, txn]
91
+ @packages << ManualPackage.new(name, version)
92
+ self
93
+ end
94
+
95
+ def remove_package(name, txn = {})
96
+ add_decision [:remove_package, name, txn]
97
+ @packages.delete(ManualPackage.new(name))
98
+ self
99
+ end
100
+
101
+ def license(name, lic, txn = {})
102
+ add_decision [:license, name, lic, txn]
103
+ @licenses[name] << License.find_by_name(lic)
104
+ self
105
+ end
106
+
107
+ def unlicense(name, lic, txn = {})
108
+ add_decision [:unlicense, name, lic, txn]
109
+ @licenses[name].delete(License.find_by_name(lic))
110
+ self
111
+ end
112
+
113
+ def homepage(name, homepage, txn = {})
114
+ add_decision [:homepage, name, homepage, txn]
115
+ @homepages[name] = homepage
116
+ self
117
+ end
118
+
119
+ def approve(name, txn = {})
120
+ add_decision [:approve, name, txn]
121
+
122
+ versions = []
123
+ versions = @approvals[name][:safe_versions] if @approvals.key?(name)
124
+ @approvals[name] = TXN.from_hash(txn, versions)
125
+ @approvals[name][:safe_versions].concat(txn[:versions]) unless txn[:versions].nil?
126
+ self
127
+ end
128
+
129
+ def unapprove(name, txn = {})
130
+ add_decision [:unapprove, name, txn]
131
+ @approvals.delete(name)
132
+ self
133
+ end
134
+
135
+ def permit(lic, txn = {})
136
+ add_decision [:permit, lic, txn]
137
+ @permitted << License.find_by_name(lic)
138
+ self
139
+ end
140
+
141
+ def unpermit(lic, txn = {})
142
+ add_decision [:unpermit, lic, txn]
143
+ @permitted.delete(License.find_by_name(lic))
144
+ self
145
+ end
146
+
147
+ def restrict(lic, txn = {})
148
+ add_decision [:restrict, lic, txn]
149
+ @restricted << License.find_by_name(lic)
150
+ self
151
+ end
152
+
153
+ def unrestrict(lic, txn = {})
154
+ add_decision [:unrestrict, lic, txn]
155
+ @restricted.delete(License.find_by_name(lic))
156
+ self
157
+ end
158
+
159
+ def ignore(name, txn = {})
160
+ add_decision [:ignore, name, txn]
161
+ @ignored << name
162
+ self
163
+ end
164
+
165
+ def heed(name, txn = {})
166
+ add_decision [:heed, name, txn]
167
+ @ignored.delete(name)
168
+ self
169
+ end
170
+
171
+ def ignore_group(name, txn = {})
172
+ add_decision [:ignore_group, name, txn]
173
+ @ignored_groups << name
174
+ self
175
+ end
176
+
177
+ def heed_group(name, txn = {})
178
+ add_decision [:heed_group, name, txn]
179
+ @ignored_groups.delete(name)
180
+ self
181
+ end
182
+
183
+ def name_project(name, txn = {})
184
+ add_decision [:name_project, name, txn]
185
+ @project_name = name
186
+ self
187
+ end
188
+
189
+ def unname_project(txn = {})
190
+ add_decision [:unname_project, txn]
191
+ @project_name = nil
192
+ self
193
+ end
194
+
195
+ def inherit_from(filepath_info)
196
+ decisions =
197
+ if filepath_info.is_a?(Hash)
198
+ resolve_inheritance(filepath_info)
199
+ elsif filepath_info =~ %r{^https?://}
200
+ open_uri(filepath_info).read
201
+ else
202
+ Pathname(filepath_info).read
203
+ end
204
+
205
+ add_decision [:inherit_from, filepath_info]
206
+ @inherited_decisions << filepath_info
207
+ restore_inheritance(decisions)
208
+ end
209
+
210
+ def resolve_inheritance(filepath_info)
211
+ if (gem_name = filepath_info['gem'])
212
+ Pathname(gem_config_path(gem_name, filepath_info['path'])).read
213
+ else
214
+ open_uri(filepath_info['url'], filepath_info['authorization']).read
215
+ end
216
+ end
217
+
218
+ def gem_config_path(gem_name, relative_config_path)
219
+ spec = Gem::Specification.find_by_name(gem_name)
220
+ File.join(spec.gem_dir, relative_config_path)
221
+ rescue Gem::LoadError => e
222
+ raise Gem::LoadError,
223
+ "Unable to find gem #{gem_name}; is the gem installed? #{e}"
224
+ end
225
+
226
+ def remove_inheritance(filepath)
227
+ @decisions -= [[:inherit_from, filepath]]
228
+ @inherited_decisions.delete(filepath)
229
+ self
230
+ end
231
+
232
+ def add_decision(decision)
233
+ @decisions << decision unless @inherited
234
+ end
235
+
236
+ def restore_inheritance(decisions)
237
+ @inherited = true
238
+ self.class.restore(decisions, self)
239
+ @inherited = false
240
+ self
241
+ end
242
+
243
+ def open_uri(uri, auth = nil)
244
+ header = {}
245
+ auth_header = resolve_authorization(auth)
246
+ header['Authorization'] = auth_header if auth_header
247
+
248
+ # ruby < 2.5.0 URI.open is private
249
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.5.0')
250
+ # rubocop:disable Security/Open
251
+ open(uri, header)
252
+ # rubocop:enable Security/Open
253
+ else
254
+ URI.open(uri, header)
255
+ end
256
+ end
257
+
258
+ def resolve_authorization(auth)
259
+ return unless auth
260
+
261
+ token_env = auth.match(/\$(\S.*)/)
262
+ return auth unless token_env
263
+
264
+ token = ENV[token_env[1]]
265
+ auth.sub(token_env[0], token)
266
+ end
267
+
268
+ #########
269
+ # PERSIST
270
+ #########
271
+
272
+ def self.fetch_saved(file)
273
+ restore(read!(file))
274
+ end
275
+
276
+ def save!(file)
277
+ write!(persist, file)
278
+ end
279
+
280
+ def self.restore(persisted, result = new)
281
+ return result unless persisted
282
+
283
+ actions = YAML.load(persisted)
284
+
285
+ list_of_actions = (actions || []).map(&:first)
286
+
287
+ if (list_of_actions & %i[whitelist blacklist]).any?
288
+ raise 'The decisions file seems to have whitelist/blacklist keys which are deprecated. Please replace them with permit/restrict respectively and try again! More info - https://github.com/pivotal/LicenseFinder/commit/a40b22fda11b3a0efbb3c0a021381534bc998dd9'
289
+ end
290
+
291
+ (actions || []).each do |action, *args|
292
+ result.send(action, *args)
293
+ end
294
+ result
295
+ end
296
+
297
+ def persist
298
+ YAML.dump(@decisions)
299
+ end
300
+
301
+ def self.read!(file)
302
+ file.read if file.exist?
303
+ end
304
+
305
+ def write!(value, file)
306
+ file.dirname.mkpath
307
+ file.open('w+') do |f|
308
+ f.print value
309
+ end
310
+ end
311
+ end
312
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class DecisionsFactory
5
+ @decisions = {}
6
+ class << self
7
+ def decisions(decisions_file_path)
8
+ @decisions[decisions_file_path] = Decisions.fetch_saved(decisions_file_path) if @decisions[decisions_file_path].nil?
9
+ @decisions[decisions_file_path]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class Diff
5
+ class << self
6
+ def compare(file1, file2)
7
+ p1 = Set.new(build_packages(file1))
8
+ p2 = Set.new(build_packages(file2))
9
+
10
+ added = p2.difference(p1).to_a
11
+ removed = p1.difference(p2).to_a
12
+ unchanged = p1.intersection(p2).to_a
13
+
14
+ [].tap do |packages|
15
+ unchanged.each do |package|
16
+ package_previous = find_package(p1, package)
17
+ package_current = find_package(p2, package)
18
+
19
+ if package_current.licenses == package_previous.licenses
20
+ packages << PackageDelta.unchanged(package_current, package_previous)
21
+ else
22
+ packages << PackageDelta.removed(package_previous)
23
+ packages << PackageDelta.added(package_current)
24
+ end
25
+ end
26
+
27
+ added.each { |package| packages << PackageDelta.added(package) }
28
+ removed.each { |package| packages << PackageDelta.removed(package) }
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def build_packages(content)
35
+ CSV.parse(content).map do |row|
36
+ row.map!(&:strip)
37
+ package = Package.new(row[0], row[1], spec_licenses: [row[2]])
38
+ if row.count == 4
39
+ MergedPackage.new(package, row[3].split(','))
40
+ else
41
+ package
42
+ end
43
+ end
44
+ end
45
+
46
+ def find_package(set, package)
47
+ set.find { |p| p.eql? package }
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class License
5
+ class AnyMatcher
6
+ def initialize(*matchers)
7
+ @matchers = matchers
8
+ end
9
+
10
+ def matches_text?(text)
11
+ @matchers.any? { |m| m.matches_text? text }
12
+ end
13
+ end
14
+ end
15
+ end