From afc5c1e6e9f4f54e7cc06035b97d2bf73e57527b Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Wed, 13 Sep 2017 14:59:08 -0700 Subject: [PATCH] appendix-IV: Refactor the license expression appendix This is a large diff, but I aimed for restructuring/polishing without changing the end result (much). I did make a few intentional changes: * Extended license-id to include appendix I.3 (deprecated licenses). We don't want folks using these in license expressions (because they're deprecated), but they are valid (or we would have removed them instead of just deprecating them). That means that in some cases the nature of a string is unclear. For example 'GPL-1.0+' could be the depreacted license-id, or it could be a simple-expression using the more-recently-deprecated GPL-1.0 license-id and the + operator. I don't think that's a problem though, because I can't think of a case where the ambiguity would matter. * I've allowed + for license-ref (it used to be only for license-id). There could be external licenses which offer a choice between only-this-version and or-later grants, and allowing + for license-ref makes it easier to support those licenses as they transition into the SPDX License List. This isn't a big deal, but it avoids needing separate license-refs for the only-this-version and or-later grants if you need both. * I've added explicit whitespace handling, vs. the previous version which just discussed it in the text. That way the ABNF is the sole source of normative syntax information. * I've added a paragraph addressing casing, based on discussion in [1]. * I've added enclosed-license-expression, so consumers like the tag:value format can suggest/require it. This allows for more precision in consumers (e.g. appendix V should be updated to require enclosed-license-expression), but I've left those other sections alone for this commit. Ideally the tag:value line would be moved to a separate section that defined the tag-value format, but we don't have such a section yet [2]. * I've added Gary's documentation for spdx:OrLaterOperator [3]; previously there was no way to represent the + operator in RDF/XML. * I've added Gary's documentation for spdx:WithExceptionOperator [4]. I think it's a bit odd that the XML operator represetation are using URLs instead of the SPDX IDs that the license expression syntax calls for. That means you cannot convert between the two representations without an ID <-> URL map. But we can address that later. * I've removed spdx:LicenseException, because we currently provide no other way for authors to define license exceptions. We do define a way for them to define their own licenses [5], and currently authors have to use that to give a LicenseRef to a license+exception pair if their exception is not in our list. Gary feels like we may return to this later (and I'd be happy giving users a way to define their own exceptions), but we're removing it for now [6]. * I've fleshed out the documentation for the + operator to explain how it works with the AGPL-1.0. Without this explaination, I think there's a risk that folks misinterpret ${ROOT}-${BASE_VERSION}+ as "allows ${ROOT}-${VERSION} for any ${VERSION} >= ${BASE_VERSION}", but that's not true. Instead the proper interpretation is "allows ${ROOT}-${VERSION} and any other licenses allowed by ${ROOT-VERSION} which are based on 'any later version' grant". For example, if the AGPL-2.0 had not been released, you could distribute AGPL-1.0-or-later code under the GPL-3.0-or-later, but *not* under the AGPL-3.0-or-later. The HTML comment avoids the ambiguous four-space indent after the list. Without the comment, it could be parsed as a code block (which is what we want) [7] or a second paragraph of the final list entry [8] (which is not what we want). The HTML comment closes the list to resolve the ambiguity. [1]: https://github.com/spdx/spdx-spec/issues/63 [2]: https://github.com/spdx/spdx-spec/issues/22#issuecomment-327253273 [3]: https://github.com/spdx/spdx-spec/pull/37#discussion_r145835414 [4]: https://github.com/spdx/spdx-spec/pull/37#discussion_r145836880 [5]: https://github.com/spdx/spdx-spec/blob/cfa1b9d08903befdf03e669da6472707b7b60cb9/chapters/6-other-licensing-information-detected.md#6.1 [6]: https://github.com/spdx/spdx-spec/pull/37#discussion_r146060446 [7]: https://daringfireball.net/projects/markdown/syntax#precode "To produce a code block in Markdown, simply indent every line of the block by at least 4 spaces or 1 tab" [8]: https://daringfireball.net/projects/markdown/syntax#list "Each subsequent paragraph in a list item must be indented by either 4 spaces or one tab" --- .../appendix-IV-SPDX-license-expressions.md | 198 +++++++++--------- 1 file changed, 101 insertions(+), 97 deletions(-) diff --git a/chapters/appendix-IV-SPDX-license-expressions.md b/chapters/appendix-IV-SPDX-license-expressions.md index b5e96f9d98..8d70ecfbe8 100644 --- a/chapters/appendix-IV-SPDX-license-expressions.md +++ b/chapters/appendix-IV-SPDX-license-expressions.md @@ -1,142 +1,159 @@ -# SPDX License Expressions +# Appendix IV: SPDX License Expressions -## Overview +## IV.1 Overview -Often a single license can be used to represent the licensing terms of a source code or binary file, but there are situations where a single license identifier is not sufficient. A common example is when software is offered under a choice of one or more licenses (e.g., GPL-2.0 OR BSD-3-Clause). Another example is when a set of licenses is needed to represent a binary program constructed by compiling and linking two (or more) different source files each governed by different licenses (e.g., LGPL-2.1 AND BSD-3-Clause). +Often a single license can be used to represent the licensing terms of a source code or binary file, but there are situations where a single license identifier is not sufficient. A common example is when software is offered under a choice of one or more licenses (e.g., `GPL-2.0 OR BSD-3-Clause`). Another example is when a set of licenses is needed to represent a binary program constructed by compiling and linking two (or more) different source files each governed by different licenses (e.g., `LGPL-2.1 AND BSD-3-Clause`). -SPDX License Expressions provides a way for one to construct expressions that more accurately represent the licensing terms typically found in open source software source code. A license expression could be a single license identifier found on the SPDX License List; a user defined license reference denoted by the LicenseRef-`[idString]`; a license identifier combined with an SPDX exception; or some combination of license identifiers, license references and exceptions constructed using a small set of defined operators (e.g., `AND`, `OR`, `WITH` and `+`). We provide the definition of what constitutes a valid an SPDX License Expression in this section. +SPDX License Expressions allow accurate representations of the licensing terms typically found in open source software. A license expression could be a single license identifier found on the [SPDX License List](appendix-I-SPDX-license-list.md); a user defined license reference denoted by the `LicenseRef-[idString]`; a license identifier combined with an SPDX exception; or some combination of license identifiers, license references and exceptions constructed using a small set of defined operators (`AND`, `OR`, `WITH` and `+`). We provide the definition of what constitutes a valid an SPDX License Expression in this section. -The exact syntax of license expressions is described below in [ABNF](http://tools.ietf.org/html/rfc5234). +## IV.2 Syntax -idstring = 1*(ALPHA / DIGIT / "-" / "." ) +The exact syntax of license expressions is described below in [ABNF][rfc5234]. `ALPHA`, `DIGIT`, and `WSP` are from the [ABNF core rules][rfc5234-aB]. -license-id = \ +``` +idstring = 1*(ALPHA / DIGIT / "-" / "." ) +license-id = +license-exception-id = +license-ref = ["DocumentRef-" idstring ":"] "LicenseRef-" idstring +license = license-id / license-ref +space = 1*WSP +simple-expression = license ["+"] [space "WITH" space license-exception-id] +binary-expression-operator = "AND" / "OR" +license-expression = simple-expression + / license-expression space binary-expression-operator space license-expression + / "(" license-expression ")" + / space license-expression + / license-expression space +enclosed-license-expression = [space] simple-expression [space] + / [space] "(" [space] license-expression [space] ")" [space] +``` -license-exception-id = \ +Where: -license-ref = ["DocumentRef-"1\*(idstring)":"]"LicenseRef-"1*(idstring) +* Short form license identifiers are drawn from sections [I.1](appendix-I-SPDX-license-list.md#I.1) and [I.3](appendix-I-SPDX-license-list.md#I.3). +* Short form license exception identifiers are drawn from [section I.2](appendix-I-SPDX-license-list.md#I.2). -simple-expression = license-id / license-id"+" / license-ref +License expressions are case sensitive, and license expressions must use the canonical case for all components. +However, the SPDX Licence List commits to [never contain identifiers which differ only in case but have different semantics][list-case-commitment]. +Similarly, SPDX License Expressions will never contain operators or other local components which differ only in case but have different semantics. +Tools are encouraged, but not required, to take advantage of those commitments and support parsing license expressions which alter the canonical casing of any expression components. -compound-expression = 1*1(simple-expression / +When a particular rule is not referenced, “SPDX License Expressions” means the more general `license-expression`. +Consumers that need the more limited `enclosed-license-expression` (which may be easier to parse depending on the surrounding context) SHOULD say so explicitly. +Tag:value authors SHOULD use `enclosed-license-expression` instead of the more general `license-expression`. -simple-expression "WITH" license-exception-id / +### IV.2.1 The `+` Operator - compound-expression "AND" compound-expression / +The unary `+` suffix operator represents the given version of the license or any later version. - compound-expression "OR" compound-expression ) / +For example, a grant like: - "(" compound-expression ")" ) +> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. -license-expression = 1*1(simple-expression / compound-expression) +could be be represented as `GPL-2.0+`, although that form has been deprecated in favor of `GPL-2.0-or-later`. -In the following sections we describe in more detail `` construct, a licensing expression string that enables a more accurate representation of the licensing terms of modern day software. +The set of alternatives may depend on the specific license text. For example, `AGPL-1.0+` (and its successor `AGPL-1.0-or-later`) invokes the “any later version” condition from §9 of the [`AGPL-1.0`][AGPL-1.0], allowing you to redistribute and/or modify it under the terms of the [AGPL-2.0][] (a later version published by Affero) or under the terms of the [`GPL-3.0-or-later`][GPL-3.0-or-later] (specifically allowed via the AGPL-1.0's §9). -A valid `` string consists of either: +### IV.2.2 Exception `WITH` Operator -(i) a simple license expression, such as a single license identifier; or +Sometimes a set of license terms apply except under special circumstances. In this case, use the binary `WITH` operator to construct a new simple expression to represent the exception situation. A valid `simple-expression` is where the left operand is a `license` value (with an optional `+` suffix) and the right operand is a `license-exception-id` that represents the exception terms. -(ii) a more complex expression constructed by combining smaller valid expressions using Boolean license operators. +For example, when the Bison exception is applied to `GPL-2.0-or-later`, the `simple-expression` would be: -There MUST NOT be whitespace between a license-id and any following `+`. This supports easy parsing and backwards compatibility. There MUST be whitespace on either side of the operator "WITH". There MUST be whitespace and/or parentheses on either side of the operators `AND` and `OR`. + GPL-2.0-or-later WITH Bison-exception-2.2 -## Simple License Expressions +The current set of valid exceptions can be found in [Appendix I, section 2](appendix-I-SPDX-license-list.md#I.2). For the most up to date set of exceptions please see [spdx.org/licenses](https://spdx.org/licenses). If the applicable exception is not found on the SPDX License Exception List, then use a single `license-ref` to represent the entire license terms (including the exception). -A simple `` is composed one of the following: +### IV.2.3 Conjunctive `AND` Operator -* An SPDX License List Short Form Identifier. For example: GPL-2.0 -* An SPDX License List Short Form Identifier with a unary"+" operator suffix to represent the current version of the license or any later version. For example: GPL-2.0+ -* A SPDX user defined license reference: ["DocumentRef-"1\*(idstring)":"]"LicenseRef-"1*(idstring) +If required to simultaneously comply with two or more licenses, use the conjunctive binary `AND` operator to construct a new license expression, where both the left and right operands are valid `license-expression` values. -Some examples: +For example, when one is required to comply with both the `LGPL-2.1` or `MIT` licenses, a valid `license-expression` would be: - LicenseRef-23 + LGPL-2.1 AND MIT - LicenseRef-MIT-Style-1 - - DocumentRef-spdx-tool-1.2:LicenseRef-MIT-Style-2 - -## Composite License Expressions +An example where all three different licenses apply would be: -More expressive composite license expressions can be constructed using "OR", "AND", and "WITH" operators similar to constructing mathematical expressions using arithmetic operators. For the `tag:value` format, any license expression that consists of more than one license identifier and/or LicenseRef, should be encapsulated by parentheses: "( )". This has been specified to facilitate expression parsing. Nested parentheses can also be used to specify an order of precedence which is discussed in more detail in subsection (4). + LGPL-2.1 AND MIT AND BSD-2-Clause -### 1) Disjunctive "OR" Operator +### IV.2.4 Disjunctive `OR` Operator -If presented with a choice between two or more licenses, use the disjunctive binary "OR" operator to construct a new lincense expression, where both the left and right operands are valid license expression values. +If presented with a choice between two or more licenses, use the disjunctive binary `OR` license operator to construct a new license expression, where both the left and right operands are valid `license-expression` values. -For example, when given a choice between the LGPL-2.1 or MIT licenses, a valid expression would be: +For example, when given a choice between the `LGPL-2.1` or `MIT` licenses, a valid `license-expression` would be: - (LGPL-2.1 OR MIT) + LGPL-2.1 OR MIT An example representing a choice between three different licenses would be: -(LGPL-2.1 OR MIT OR BSD-3-Clause) - -### 2) Conjunctive "AND" Operator + LGPL-2.1 OR MIT OR BSD-3-Clause -If required to simultaneously comply with two or more licenses, use the conjunctive binary "AND" operator to construct a new license expression, where both the left and right operands are a valid license expression values. +### IV.2.5 Grouping -For example, when one is required to comply with both the LGPL-2.1 or MIT licenses, a valid expression would be: - - (LGPL-2.1 AND MIT) - -An example where all three different licenses apply would be: +Parentheses (`()`) can be used to specify an explicit grouping to override [operator precedence](#IV.2.6). This is similar to the use of parentheses in algebraic expressions like `(5+7)/2`. - (LGPL-2.1 AND MIT AND BSD-2-Clause) - -### 3) Exception "WITH" Operator - -Sometimes a set of license terms apply except under special circumstances. In this case, use the binary "WITH" operator to construct a new license expression to represent the special exception situation. A valid `` is where the left operand is a `` value and the right operand is a `` that represents the special exception terms. - -For example, when the Bison exception is to be applied to GPL-2.0+, the expression would be: +For instance, the following expression: - (GPL-2.0+ WITH Bison-exception-2.2) + MIT AND (LGPL-2.1-or-later OR BSD-3-Clause) -The current set of valid exceptions can be found in [Appendix I, section 2](appendix-I-SPDX-license-list.md#I.2). For the most up to date set of exceptions please see [spdx.org/licenses](https://spdx.org/licenses). If the applicable exception is not found on the SPDX License Exception List, then use a single `` to represent the entire license terms (including the exception). +represents a license requring both `MIT` and the expression `LGPL-2.1-or-later OR BSD-3-Clause`, because the parenthesis require the enclosed expression take precedence over (is applied before) the `AND` operator. -### 4) Order of Precedence and Parentheses +### IV.2.6 Operator Precedence -The order of application of the operators in an expression matters (similar to mathematical operators). The default operator order of precedence of a `` a is: +The operators described above have the following precedence, from highest (binding tightest) at the top, to lowest (loosest) at the bottom: + Grouping + WITH AND OR -where a lower order operator is applied before a higher order operator. - For example, the following expression: LGPL-2.1 OR BSD-3-Clause AND MIT -represents a license choice between either LGPL-2.1 and the expression BSD-3-Clause AND MIT because the AND operator takes precedence over (is applied before) the OR operator. +represents a license choice between either `LGPL-2.1` and the expression `BSD-3-Clause AND MIT` because the `AND` operator takes precedence over (is applied before) the `OR` operator. -When required to express an order of precedence that is different from the default order a `` can be encapsulated in pairs of parentheses: ( ), to indicate that the operators found inside the parentheses takes precedence over operators outside. This is also similar to the use of parentheses in an algebraic expression e.g., (5+7)/2. +## IV.3 License Expressions in XML -For instance, the following expression: +### IV.3.1 The `+` Operator - (MIT AND (LGPL-2.1+ OR BSD-3-Clause)) +The [`+` operator](#IV.2.1) can be expressed in XML via an `` element, with a single ` child for the license preceeding the `+` operator. -states the OR operator should be applied before the AND operator. That is, one should first select between the LGPL-2.1+ or the BSD-3-Clause license before applying the MIT license. + + + + +### IV.3.2 Exception `WITH` Operator -### 5) License Expressions in RDF +The [`WITH` operator](#IV.2.2) can be expressed in XML via a `` element, with an `` property for the license and an `` property for the exception. + + + + + -A conjunctive license can be expressed in RDF via a `` element, with an spdx:member property for each element in the conjunctive license. Two or more members are required. +### IV.3.3 Conjunctive `AND` Operator + +A [conjunctive license](#IV.2.3) can be expressed in XML via an `` element, with an `` child for each element in the conjunctive license. Two or more members are required. - - - In exchange for using this software, you agree to give its author all your worldly possessions. - You will not hold the author liable for all the damage this software will inevitably cause not only - to your person and property, but to the entire fabric of the cosmos. - - LicenseRef-EternalSurrender - + + + In exchange for using this software, you agree to give its author all your worldly possessions. + You will not hold the author liable for all the damage this software will inevitably cause not only + to your person and property, but to the entire fabric of the cosmos. + + LicenseRef-EternalSurrender + + -A disjunctive license can be expressed in RDF via a `` element, with an spdx:member property for each element in the disjunctive license. Two or more members are required. +### IV.3.4 Disjunctive `OR` Operator + +A [disjunctive license](#IV.2.4) can be expressed in XML via an `` element, with an `` child for each element in the disjunctive license. Two or more members are required. @@ -152,24 +169,11 @@ A disjunctive license can be expressed in RDF via a ` -A License Exception can be expressed in RDF via a `` element. This element has the following attributes: - -* Comment - An `rdfs:comment` element describing the nature of the exception. -* See Also (optional)- An `rdfs:seeAlso` element referencing external sources of information on the exception. -* Example - Text describing examples of this exception. -* Name - The full human readable name of the item. -* License Exception ID: The identifier of an exception in the SPDX License List to which the exception applies. -* License Exception Text: Full text of the license exception. - - - This exception may be invalid in some jurisdictions. - http://dilbert.com/strip/1997-01-15 - So this one time, I had a license exception… - - A user of this software may decline to follow any subset of the terms of this license upon - finding any or all such terms unfavorable. - - "But I Don't Want To" Exception - SPDXRef-ButIdDontWantToException - - \ No newline at end of file +[AGPL-1.0]: https://spdx.org/licenses/AGPL-1.0.html +[AGPL-2.0]: http://www.affero.org/agpl2.html +[GPL-3.0]: https://spdx.org/licenses/GPL-3.0-or-later.html +[list-case-commitment]: https://github.com/spdx/license-list-XML/pull/651#FIXME:get-this-released +[rdfs:comment]: https://www.w3.org/TR/2014/REC-rdf-schema-20140225/#ch_comment +[rdfs:seeAlso]: https://www.w3.org/TR/2014/REC-rdf-schema-20140225/#ch_seealso +[rfc5234]: http://tools.ietf.org/html/rfc5234 +[rfc5234-aB]: https://tools.ietf.org/html/rfc5234#appendix-B