Draft: Add a tool that generates a Lua table
Merge request reports
Activity
Here is an absolutely naïve proof of concept of a macro that uses it. It does not really validate and it does not deduplicate.
%spdx() %{lua: local licenses = require 'fedora.licenses' local expr = rpm.expand('%*') local function convert(spdx) if spdx == '' then return '' end local fedoras = licenses.spdx2fedora[spdx] if fedoras == nil then if spdx == 'Artistic-1.0-Perl' then -- this is a hack that could be fixed in the data return 'Artistic' end rpm.expand('%{warn:%%spdx: Unknown SPDX license "' .. spdx .. '", using literally}') return spdx end if #fedoras > 1 then rpm.expand('%{warn:%%spdx: Multiple options for SPDX license "' .. spdx .. '", using the first option: "' .. fedoras[1] .. '"}') end return fedoras[1] end local idx = 1 local out = '' local current = '' local depth = 0 while idx <= #expr do if expr:sub(idx, idx+4) == ' AND ' then out = out .. convert(current) .. ' and ' current = '' idx = idx+4 elseif expr:sub(idx, idx+3) == ' OR ' then out = out .. convert(current) .. ' or ' current = '' idx = idx+3 elseif expr:sub(idx, idx) == '(' then out = out .. '(' current = '' depth = depth+1 elseif expr:sub(idx, idx) == ')' then out = out .. convert(current) .. ')' current = '' depth = depth-1 if depth < 0 then rpm.expand('%{warn:%%spdx: Redundant closing parenthesis at position ' .. idx .. '.}') end else current = current .. expr:sub(idx, idx) end idx = idx+1 end if depth > 0 then rpm.expand('%{warn:%%spdx: Opening and closing parenthesis count mismatch.}') end print(out .. convert(current)) }
I've realized some of the SPDX abbrevs here contain
... OR Artistic-1.0-Perl
and there is no standaloneArtistic-1.0-Perl
, so I've hacked around that in the macro, but we could addArtistic-1.0-Perl
->Artistic
to the data instead. I prefer to fix the data but can keep the workaround in the code if needed.I could also make the macro more strict and error when the SPDX identifier is not found. Possibly allowing an option to relax that to a warning.
It is also not very robust wrt input with multiple spaces in it (e.g.
%{spdx:BSD-3-Clause AND MIT}
searches for"BSD-3-Clause "
and" MIT"
in the table), but that can be quite easily changed by passing the entire input trough a pattern substitution that converts%S+
to a single space and strips spaces at the beginning and end if desired.And as a working demo, the macro would be defined like this on newer Fedoras:
%spdx() %*
Once validation exists, we could replace that with a version that validates only. Alternatively, the implementation could remain almost the same with uppercase AND/OR and always return the input in
convert()
(with or without the warning), like this:@@ -7,16 +7,9 @@ end local fedoras = licenses.spdx2fedora[spdx] if fedoras == nil then - if spdx == 'Artistic-1.0-Perl' then -- this is a hack that could be fixed in the data - return 'Artistic' - end - rpm.expand('%{warn:%%spdx: Unknown SPDX license "' .. spdx .. '", using literally}') - return spdx + rpm.expand('%{warn:%%spdx: Unknown SPDX license "' .. spdx .. '"}') end - if #fedoras > 1 then - rpm.expand('%{warn:%%spdx: Multiple options for SPDX license "' .. spdx .. '", using the first option: "' .. fedoras[1] .. '"}') - end - return fedoras[1] + return spdx end local idx = 1 local out = '' @@ -24,11 +17,11 @@ local depth = 0 while idx <= #expr do if expr:sub(idx, idx+4) == ' AND ' then - out = out .. convert(current) .. ' and ' + out = out .. convert(current) .. ' AND ' current = '' idx = idx+4 elseif expr:sub(idx, idx+3) == ' OR ' then - out = out .. convert(current) .. ' or ' + out = out .. convert(current) .. ' OR ' current = '' idx = idx+3 elseif expr:sub(idx, idx) == '(' then
Here are some examples of usage:
%{spdx MIT} MIT %{spdx BSD-2-Clause} BSD %{spdx GPL-1.0-or-later OR Artistic-1.0-Perl} GPL+ or Artistic %{spdx MIT AND (LGPL-2.1-or-later OR BSD-3-Clause) AND GPL-1.0-or-later} warning: %spdx: Multiple options for SPDX license "BSD-3-Clause", using the first option: "BSD" MIT and (LGPLv2+ or BSD) and GPL+ %{spdx ((MIT))} ((MIT)) %{spdx ((MIT)} warning: %spdx: Opening and closing parenthesis count mismatch. ((MIT) %{spdx (MIT))} warning: %spdx: Redundant closing parenthesis at position 6. (MIT)) %{spdx:GPL-2.0-or-later WITH Classpath-exception-2.0 OR LGPL-2.0-or-later WITH WxWindows-exception-3.1} GPLv2+ with exceptions or wxWindows %{spdx:BSD AND MIT} warning: %spdx: Unknown SPDX license "BSD", using literally BSD and MIT
BTW I am not sure what is the actual semantic difference between
%{spdx:foo}
and%{spdx foo}
but this seems to work both ways.Edited by Miro HrončokI like the way this is going. One thing regarding the Fedora license list is that even though we are using SPDX syntax, we need to check for approved expressions first and then work backwards from that.
For example, in Fedora we may approve something like "BSD-3-Clause OR MIT0" but we may not approved BSD-3-Clause or MIT0 by themselves. What we have to do for validation is check for the entire expression first and then failing that falling back on checking the individual tokens.
Sure. For the purposes of validation,
Artistic-1.0-Perl
is not valid and onlyGPL-2.0-or-later OR Artistic-1.0-Perl
or similar is. But for the purposes of pure conversion (which is the main goal of this macro, validation is a nice to have next thing), knowing thatArtistic-1.0-Perl
wasArtistic
is important. I believe this conflict of purpose can be solved by simply including the partial abbreviation in the data file that definesArtistic-1.0-Perl
asstatus = [ "not-allowed" ]
.