summaryrefslogtreecommitdiffstats
path: root/lib/licenses/helpers.nix
blob: 37721489f77a2f833dc5fbfa59c3ed89eebfefec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
{ lib }:

let
  inherit (lib) all any elem;
  handleComplexProperty =
    evaluateSubProperty: AND: OR: license:
    if license.licenseType == "compound" then
      if license.operator == "OR" then
        OR evaluateSubProperty license.licenses
      else if license.operator == "AND" then
        AND evaluateSubProperty license.licenses
      else
        throw "Unknown license operator"
    else if license.licenseType == "exception" then
      evaluateSubProperty license.license && evaluateSubProperty license.exception
    else if license.licenseType == "plus" then
      evaluateSubProperty license.license
    else
      throw "Unknown license type or legacy license";
in
rec {
  /**
    Evaluate a license expression for a given predicate.

    # Example

    ```nix
    evaluateProperty (x: x.free) true (with lib.licenses; AND [ ncsa (WITH asl20 llvm-exception) ])
    ```
    # Type

    ```
    evaluateProperty :: Function -> Bool -> AttrSet -> Bool
    ```

    # Arguments

    - [predicate] checks for each license included in the license expression
    - [permissive] whether to apply checks permissive or reciprocal
    - [license] license expression to check
  */
  evaluateProperty =
    predicate: permissive:
    let
      OR = if permissive then any else all;
      AND = if permissive then all else any;
      evaluateComplexProperty = handleComplexProperty (evaluateProperty predicate permissive) AND OR;
    in
    license:
    if license.licenseType == "simple" then predicate license else evaluateComplexProperty license;

  /**
    Evaluate a license expression for a given property name. The property must
    be defined as a boolean attribute of all licenses passed.

    # Example

    ```nix
    evaluateNamedProperty "deprecated" true (with lib.licenses; AND [ ncsa (WITH asl20 llvm-exception) ])
    ```
    # Type

    ```
    evaluateProperty :: String -> Bool -> AttrSet -> Bool
    ```

    # Arguments

    - [name] name of the attribute to check
    - [permissive] whether to apply checks permissive or reciprocal
    - [license] license expression to check
  */
  evaluateNamedProperty =
    name: permissive:
    let
      OR = if permissive then any else all;
      AND = if permissive then all else any;
      evaluateComplexProperty = handleComplexProperty (evaluateNamedProperty name permissive) AND OR;
    in
    license:
    if license.licenseType == "simple" then license.${name} else evaluateComplexProperty license;

  /**
    Check whether a license expression is free.

    # Example

    ```nix
    isFree (with lib.licenses; (AND [ ncsa (WITH asl20 llvm-exception) ]))
    => true
    ```

    # Type

    ```
    isFree :: AttrSet -> Bool
    ```

    # Arguments

    - [license] License expression to check if free
  */
  isFree = evaluateNamedProperty "free" true;

  /**
    Check whether a license expression is redistributable.

    # Example

    ```nix
    isRedistributable (with lib.licenses; (AND [ ncsa (WITH asl20 llvm-exception) ]))
    => true
    ```

    # Type

    ```
    isRedistributable :: AttrSet -> Bool
    ```

    # Arguments

    - [license] License expression to check if redistributable
  */
  isRedistributable = evaluateNamedProperty "redistributable" true;

  /**
    Check whether any of the given licenses is required in the license expression.

    # Example

    ```nix
    containsLicenses [ lib.licenses.asl20 ] (with lib.licenses; (AND [ ncsa (WITH asl20 llvm-exception) ]))
    => true
    ```

    # Type

    ```
    containsLicenses :: List -> AttrSet -> Bool
    ```

    # Arguments

    - [licenses] List of licenses to look
    - [license] License expression to check
  */
  containsLicenses = licenses: evaluateProperty (x: elem x licenses) false;

  /**
    Convert a license expression to an SPDX license expression string.

    # Example

    ```nix
    toSPDX (with lib.licenses; AND [ ncsa (WITH asl20 llvm-exception) ])
    => "NCSA AND (Apache-2.0 WITH LLVM-exception)"
    ```

    # Type

    ```
    toSPDX :: AttrSet -> String
    ```

    # Arguments

    - [license] License expression which to convert to spdx expression
  */
  toSPDX =
    license:
    let
      mkBracket =
        x:
        if x.licenseType == "compound" || x.licenseType == "exception" then "(${toSPDX x})" else toSPDX x;
    in
    if license.licenseType == "simple" then
      license.spdxId or "LicenseRef-nixos-${license.shortName}"
    else if license.licenseType == "compound" then
      lib.concatMapStringsSep " ${license.operator} " (x: mkBracket x) license.licenses
    else if license.licenseType == "exception" then
      "${mkBracket license.license} ${license.operator} ${mkBracket license.exception}"
    else if license.licenseType == "plus" then
      "${mkBracket license.license}${license.operator}"
    else
      throw "Unknown license type";
}