Skip to content
Snippets Groups Projects

Draft: Add a tool that generates a Lua table

Closed Miro Hrončok requested to merge hroncok/fedora-license-data:lua into master

Merge request reports

Approval is optional

Closed by David CantrellDavid Cantrell 2 years ago (Jul 27, 2022 5:05pm UTC)

Merge details

  • The changes were not merged into master.

Activity

Filter activity
  • Approvals
  • Assignees & reviewers
  • Comments (from bots)
  • Comments (from users)
  • Commits & branches
  • Edits
  • Labels
  • Lock status
  • Mentions
  • Merge request status
  • Tracking
  • 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 standalone Artistic-1.0-Perl, so I've hacked around that in the macro, but we could add Artistic-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čok
  • I 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 only GPL-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 that Artistic-1.0-Perl was Artistic is important. I believe this conflict of purpose can be solved by simply including the partial abbreviation in the data file that defines Artistic-1.0-Perl as status = [ "not-allowed" ].

  • This can be closed (I cannot do that). The Change has been approved and SPDX can be used in old branches. Therefore no need to use this. Thank you Miro for the contribution anyway.

  • Closing per most recent comment.

Please register or sign in to reply
Loading