Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix license handling for API formulae #14518

Merged
merged 1 commit into from Feb 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion Library/Homebrew/formulary.rb
Expand Up @@ -151,7 +151,7 @@ def self.load_formula_from_api(name, flags:)
klass = Class.new(::Formula) do
desc json_formula["desc"]
homepage json_formula["homepage"]
license json_formula["license"]
license SPDX.string_to_license_expression(json_formula["license"])
revision json_formula["revision"]
version_scheme json_formula["version_scheme"]

Expand Down
25 changes: 25 additions & 0 deletions Library/Homebrew/test/utils/spdx_spec.rb
Expand Up @@ -217,6 +217,31 @@
end
end

describe ".string_to_license_expression" do
it "returns the correct result for 'and', 'or' and 'with'" do
expr_string = "Apache-2.0 and (Apache-2.0 with LLVM-exception) and (MIT or NCSA)"
expect(described_class.string_to_license_expression(expr_string)).to eq({
all_of: [
"Apache-2.0",
{ "Apache-2.0" => { with: "LLVM-exception" } },
{ any_of: ["MIT", "NCSA"] },
],
})
end

it "handles nested brackets" do
expect(described_class.string_to_license_expression("A and (B or (C and D))")).to eq({
all_of: [
"A",
any_of: [
"B",
all_of: ["C", "D"],
],
],
})
end
end

describe ".license_version_info" do
it "returns license without version" do
expect(described_class.license_version_info("MIT")).to eq ["MIT"]
Expand Down
34 changes: 34 additions & 0 deletions Library/Homebrew/utils/spdx.rb
Expand Up @@ -129,6 +129,40 @@ def license_expression_to_string(license_expression, bracket: false, hash_type:
end
end

def string_to_license_expression(string)
return if string.blank?

result = string
result_type = nil

and_parts = string.split(/ and (?![^(]*\))/)
if and_parts.length > 1
result = and_parts
result_type = :all_of
else
or_parts = string.split(/ or (?![^(]*\))/)
if or_parts.length > 1
result = or_parts
result_type = :any_of
end
end

if result_type
result.map! do |part|
part = part[1..-2] if part[0] == "(" && part[-1] == ")"
string_to_license_expression(part)
end
{ result_type => result }
else
with_parts = string.split(" with ", 2)
if with_parts.length > 1
{ with_parts.first => { with: with_parts.second } }
else
result
end
end
end

def license_version_info(license)
return [license] if ALLOWED_LICENSE_SYMBOLS.include? license

Expand Down