[manifest license] fully implement SPDX, plus general parsing stuff (#334)
* [ParserBase] get ready for parsing SPDX license expressions * parse SPDX license expressions * add error message tests * more tests, plus minor error change * format Co-authored-by: nicole mazzuca <mazzucan@outlook.com>
This commit is contained in:
Родитель
c76e0def14
Коммит
457b0309ce
|
@ -37,16 +37,15 @@ function Transform-JsonFile {
|
|||
|
||||
$fileContent = @(
|
||||
"// Data downloaded from $Uri",
|
||||
"// Generated by scripts/Generate-SpdxLicenseList.ps1",
|
||||
"{")
|
||||
"// Generated by Generate-SpdxLicenseList.ps1")
|
||||
$json.$OuterName |
|
||||
Sort-Object -Property $Id -Culture '' |
|
||||
ForEach-Object {
|
||||
$fileContent += " `"$($_.$Id)`","
|
||||
$fileContent += "`"$($_.$Id)`","
|
||||
}
|
||||
$fileContent += "}"
|
||||
|
||||
$fileContent -join "`n" | Out-File -FilePath $OutFile -Encoding 'utf8'
|
||||
($fileContent -join "`n") + "`n" `
|
||||
| Out-File -FilePath $OutFile -Encoding 'utf8' -NoNewline
|
||||
}
|
||||
|
||||
$baseUrl = "https://raw.githubusercontent.com/$GithubRepository/$Commit/json"
|
||||
|
|
|
@ -55,6 +55,7 @@ namespace vcpkg::msg
|
|||
LocalizedString() = default;
|
||||
operator StringView() const { return m_data; }
|
||||
const std::string& data() const { return m_data; }
|
||||
std::string extract_data() { return std::exchange(m_data, ""); }
|
||||
|
||||
static LocalizedString from_string_unchecked(std::string&& s)
|
||||
{
|
||||
|
@ -87,6 +88,8 @@ namespace vcpkg::msg
|
|||
}
|
||||
};
|
||||
|
||||
inline const char* to_printf_arg(const msg::LocalizedString& s) { return s.data().c_str(); }
|
||||
|
||||
struct LocalizedStringMapLess
|
||||
{
|
||||
using is_transparent = void;
|
||||
|
@ -110,6 +113,16 @@ namespace vcpkg::msg
|
|||
|
||||
inline void print(Color c, const LocalizedString& s) { write_unlocalized_text_to_stdout(c, s); }
|
||||
inline void print(const LocalizedString& s) { write_unlocalized_text_to_stdout(Color::none, s); }
|
||||
inline void println(Color c, const LocalizedString& s)
|
||||
{
|
||||
write_unlocalized_text_to_stdout(c, s);
|
||||
write_unlocalized_text_to_stdout(Color::none, "\n");
|
||||
}
|
||||
inline void println(const LocalizedString& s)
|
||||
{
|
||||
write_unlocalized_text_to_stdout(Color::none, s);
|
||||
write_unlocalized_text_to_stdout(Color::none, "\n");
|
||||
}
|
||||
|
||||
template<class Message, class... Ts>
|
||||
void print(Message m, Ts... args)
|
||||
|
@ -157,6 +170,8 @@ namespace vcpkg::msg
|
|||
DECLARE_MSG_ARG(version);
|
||||
DECLARE_MSG_ARG(list);
|
||||
DECLARE_MSG_ARG(output);
|
||||
DECLARE_MSG_ARG(row);
|
||||
DECLARE_MSG_ARG(column);
|
||||
#undef DECLARE_MSG_ARG
|
||||
|
||||
// These are `...` instead of
|
||||
|
|
|
@ -400,6 +400,7 @@ namespace vcpkg
|
|||
|
||||
return !rhs.m_base.has_value();
|
||||
}
|
||||
friend bool operator!=(const Optional& lhs, const Optional& rhs) noexcept { return !(lhs == rhs); }
|
||||
|
||||
private:
|
||||
details::OptionalStorage<T> m_base;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <vcpkg/base/cstringview.h>
|
||||
#include <vcpkg/base/messages.h>
|
||||
#include <vcpkg/base/optional.h>
|
||||
#include <vcpkg/base/stringview.h>
|
||||
#include <vcpkg/base/unicode.h>
|
||||
|
@ -42,16 +43,36 @@ namespace vcpkg::Parse
|
|||
virtual const std::string& get_message() const override;
|
||||
};
|
||||
|
||||
struct SourceLoc
|
||||
{
|
||||
Unicode::Utf8Decoder it;
|
||||
Unicode::Utf8Decoder start_of_line;
|
||||
int row;
|
||||
int column;
|
||||
};
|
||||
|
||||
enum class MessageKind
|
||||
{
|
||||
Warning,
|
||||
Error,
|
||||
};
|
||||
|
||||
struct ParseMessage
|
||||
{
|
||||
SourceLoc location = {};
|
||||
msg::LocalizedString message;
|
||||
|
||||
msg::LocalizedString format(StringView origin, MessageKind kind) const;
|
||||
};
|
||||
|
||||
struct ParseMessages
|
||||
{
|
||||
std::unique_ptr<ParseError> error;
|
||||
std::vector<ParseMessage> warnings;
|
||||
};
|
||||
|
||||
struct ParserBase
|
||||
{
|
||||
struct SourceLoc
|
||||
{
|
||||
Unicode::Utf8Decoder it;
|
||||
Unicode::Utf8Decoder start_of_line;
|
||||
int row;
|
||||
int column;
|
||||
};
|
||||
|
||||
ParserBase(StringView text, StringView origin, TextRowCol init_rowcol = {});
|
||||
|
||||
static constexpr bool is_whitespace(char32_t ch) { return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'; }
|
||||
|
@ -110,9 +131,17 @@ namespace vcpkg::Parse
|
|||
|
||||
void add_error(std::string message) { add_error(std::move(message), cur_loc()); }
|
||||
void add_error(std::string message, const SourceLoc& loc);
|
||||
void add_error(msg::LocalizedString&& message) { add_error(message.extract_data(), cur_loc()); }
|
||||
void add_error(msg::LocalizedString&& message, const SourceLoc& loc) { add_error(message.extract_data(), loc); }
|
||||
|
||||
const Parse::IParseError* get_error() const { return m_err.get(); }
|
||||
std::unique_ptr<Parse::IParseError> extract_error() { return std::move(m_err); }
|
||||
void add_warning(msg::LocalizedString&& message) { add_warning(std::move(message), cur_loc()); }
|
||||
void add_warning(msg::LocalizedString&& message, const SourceLoc& loc);
|
||||
|
||||
const IParseError* get_error() const { return m_messages.error.get(); }
|
||||
std::unique_ptr<IParseError> extract_error() { return std::move(m_messages.error); }
|
||||
|
||||
const ParseMessages& messages() const { return m_messages; }
|
||||
ParseMessages extract_messages() { return std::move(m_messages); }
|
||||
|
||||
private:
|
||||
Unicode::Utf8Decoder m_it;
|
||||
|
@ -123,6 +152,6 @@ namespace vcpkg::Parse
|
|||
StringView m_text;
|
||||
StringView m_origin;
|
||||
|
||||
std::unique_ptr<IParseError> m_err;
|
||||
ParseMessages m_messages;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -14,12 +14,37 @@ namespace vcpkg::Unicode
|
|||
StartFour = 4,
|
||||
};
|
||||
|
||||
constexpr static char32_t end_of_file = 0xFFFF'FFFF;
|
||||
|
||||
enum class utf8_errc
|
||||
{
|
||||
NoError = 0,
|
||||
InvalidCodeUnit = 1,
|
||||
InvalidCodePoint = 2,
|
||||
PairedSurrogates = 3,
|
||||
UnexpectedContinue = 4,
|
||||
UnexpectedStart = 5,
|
||||
UnexpectedEof = 6,
|
||||
};
|
||||
|
||||
const std::error_category& utf8_category() noexcept;
|
||||
|
||||
Utf8CodeUnitKind utf8_code_unit_kind(unsigned char code_unit) noexcept;
|
||||
int utf8_code_unit_count(Utf8CodeUnitKind kind) noexcept;
|
||||
int utf8_code_unit_count(char code_unit) noexcept;
|
||||
|
||||
int utf8_encode_code_point(char (&array)[4], char32_t code_point) noexcept;
|
||||
|
||||
// returns {after-current-code-point, error},
|
||||
// and if error = NoError, then out = parsed code point.
|
||||
// else, out = end_of_file.
|
||||
std::pair<const char*, utf8_errc> utf8_decode_code_point(const char* first,
|
||||
const char* last,
|
||||
char32_t& out) noexcept;
|
||||
|
||||
// uses the C++20 definition
|
||||
bool is_double_width_code_point(char32_t ch) noexcept;
|
||||
|
||||
inline std::string& utf8_append_code_point(std::string& str, char32_t code_point)
|
||||
{
|
||||
if (static_cast<uint32_t>(code_point) < 0x80)
|
||||
|
@ -52,21 +77,6 @@ namespace vcpkg::Unicode
|
|||
|
||||
char32_t utf16_surrogates_to_code_point(char32_t leading, char32_t trailing);
|
||||
|
||||
constexpr static char32_t end_of_file = 0xFFFF'FFFF;
|
||||
|
||||
enum class utf8_errc
|
||||
{
|
||||
NoError = 0,
|
||||
InvalidCodeUnit = 1,
|
||||
InvalidCodePoint = 2,
|
||||
PairedSurrogates = 3,
|
||||
UnexpectedContinue = 4,
|
||||
UnexpectedStart = 5,
|
||||
UnexpectedEof = 6,
|
||||
};
|
||||
|
||||
const std::error_category& utf8_category() noexcept;
|
||||
|
||||
inline std::error_code make_error_code(utf8_errc err) noexcept
|
||||
{
|
||||
return std::error_code(static_cast<int>(err), utf8_category());
|
||||
|
@ -89,6 +99,7 @@ namespace vcpkg::Unicode
|
|||
struct Utf8Decoder
|
||||
{
|
||||
Utf8Decoder() noexcept;
|
||||
explicit Utf8Decoder(StringView sv) : Utf8Decoder(sv.begin(), sv.end()) { }
|
||||
Utf8Decoder(const char* first, const char* last) noexcept;
|
||||
|
||||
struct sentinel
|
||||
|
|
|
@ -147,7 +147,17 @@ namespace vcpkg::Util
|
|||
{
|
||||
using std::begin;
|
||||
using std::end;
|
||||
return std::find_if(begin(cont), end(cont), pred);
|
||||
// allow cont.begin() to not have the same type as cont.end()
|
||||
auto it = begin(cont);
|
||||
auto last = end(cont);
|
||||
for (; it != last; ++it)
|
||||
{
|
||||
if (pred(*it))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
template<class Container, class Pred>
|
||||
|
|
|
@ -4,4 +4,5 @@ namespace vcpkg
|
|||
{
|
||||
struct Configuration;
|
||||
struct RegistryConfig;
|
||||
struct ManifestConfiguration;
|
||||
}
|
||||
|
|
|
@ -77,6 +77,6 @@ namespace vcpkg::PlatformExpression
|
|||
};
|
||||
|
||||
// platform expression parses a platform expression; the EBNF of such is defined in
|
||||
// /docs/maintainers/manifest-files.md#supports
|
||||
// https://github.com/microsoft/vcpkg/blob/master/docs/maintainers/manifest-files.md#supports
|
||||
ExpectedS<Expr> parse_platform_expression(StringView expression, MultipleBinaryOperators multiple_binary_operators);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <vcpkg/base/fwd/json.h>
|
||||
|
||||
#include <vcpkg/fwd/configuration.h>
|
||||
#include <vcpkg/fwd/vcpkgcmdarguments.h>
|
||||
|
||||
#include <vcpkg/base/expected.h>
|
||||
|
@ -71,7 +72,12 @@ namespace vcpkg
|
|||
std::vector<Dependency> dependencies;
|
||||
std::vector<DependencyOverride> overrides;
|
||||
std::vector<std::string> default_features;
|
||||
std::string license; // SPDX license expression
|
||||
|
||||
// there are two distinct "empty" states here
|
||||
// "user did not provide a license" -> nullopt
|
||||
// "user provided license = null" -> {""}
|
||||
Optional<std::string> license; // SPDX license expression
|
||||
|
||||
Optional<std::string> builtin_baseline;
|
||||
Optional<Json::Object> vcpkg_configuration;
|
||||
// Currently contacts is only a Json::Object but it will eventually be unified with maintainers
|
||||
|
@ -127,8 +133,7 @@ namespace vcpkg
|
|||
Json::Object serialize_manifest(const SourceControlFile& scf);
|
||||
Json::Object serialize_debug_manifest(const SourceControlFile& scf);
|
||||
|
||||
ExpectedS<struct ManifestConfiguration> parse_manifest_configuration(StringView origin,
|
||||
const Json::Object& manifest);
|
||||
ExpectedS<ManifestConfiguration> parse_manifest_configuration(StringView origin, const Json::Object& manifest);
|
||||
|
||||
/// <summary>
|
||||
/// Named pair of a SourceControlFile and the location of this file
|
||||
|
@ -146,4 +151,6 @@ namespace vcpkg
|
|||
{
|
||||
return print_error_message({&error_info_list, 1});
|
||||
}
|
||||
|
||||
std::string parse_spdx_license_expression(StringView sv, Parse::ParseMessages& messages);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
"AwsFailedToDownload": "aws failed to download with exit code: {value}\n{output}",
|
||||
"AwsRestoredPackages": "Restored {value} packages from AWS servers in {elapsed}s",
|
||||
"AwsUploadedPackages": "Uploaded binaries to {value} AWS servers",
|
||||
"EmptyLicenseExpression": "SPDX license expression was empty.",
|
||||
"ErrorIndividualPackagesUnsupported": "Error: In manifest mode, `vcpkg install` does not support individual package arguments.\nTo install additional packages, edit vcpkg.json and then run `vcpkg install` without any package arguments.",
|
||||
"ErrorInvalidClassicModeOption": "Error: The option {value} is not supported in classic mode and no manifest was found.",
|
||||
"ErrorInvalidManifestModeOption": "Error: The option {value} is not supported in manifest mode.",
|
||||
|
@ -21,8 +22,30 @@
|
|||
"ErrorRequirePackagesToInstall": "Error: No packages were listed for installation and no manifest was found.",
|
||||
"ErrorVcvarsUnsupported": "Error: in triplet {triplet}: Use of Visual Studio's Developer Prompt is unsupported on non-Windows hosts.\nDefine 'VCPKG_CMAKE_SYSTEM_NAME' or 'VCPKG_CHAINLOAD_TOOLCHAIN_FILE' in the triplet file.",
|
||||
"ForceSystemBinariesOnWeirdPlatforms": "Environment variable VCPKG_FORCE_SYSTEM_BINARIES must be set on arm, s390x, and ppc64le platforms.",
|
||||
"FormattedParseError": "error: {value}",
|
||||
"FormattedParseMessageExpression": " on expression: {value}",
|
||||
"FormattedParseMessageLocation": "{path}:{row}:{column}: ",
|
||||
"_FormattedParseMessageLocation.comment": "{LOCKED}",
|
||||
"FormattedParseWarning": "warning: {value}",
|
||||
"IllegalFeatures": "Error: List of features is not allowed in this contect",
|
||||
"IllegalPlatformSpec": "Error: Platform qualifier is not allowed in this context",
|
||||
"LicenseExpressionContainsExtraPlus": "SPDX license expression contains an extra '+'. These are only allowed directly after a license identifier.",
|
||||
"LicenseExpressionContainsInvalidCharacter": "SPDX license expression contains an invalid character (0x{value:02x} '{value}').",
|
||||
"LicenseExpressionContainsUnicode": "SPDX license expression contains a unicode character (U+{value:04x} '{pretty_value}'), but these expressions are ASCII-only.",
|
||||
"LicenseExpressionDocumentRefUnsupported": "The current implementation does not support DocumentRef- SPDX references.",
|
||||
"LicenseExpressionExpectCompoundFoundParen": "Expected a compound or the end of the string, found a parenthesis.",
|
||||
"LicenseExpressionExpectCompoundFoundWith": "Expected either AND or OR, found WITH (WITH is only allowed after license names, not parenthesized expressions).",
|
||||
"LicenseExpressionExpectCompoundFoundWord": "Expected either AND or OR, found a license or exception name: '{value}'.",
|
||||
"LicenseExpressionExpectCompoundOrWithFoundWord": "Expected either AND, OR, or WITH, found a license or exception name: '{value}'.",
|
||||
"LicenseExpressionExpectExceptionFoundCompound": "Expected an exception name, found the compound {value}.",
|
||||
"LicenseExpressionExpectExceptionFoundEof": "Expected an exception name, found the end of the string.",
|
||||
"LicenseExpressionExpectExceptionFoundParen": "Expected an exception name, found a parenthesis.",
|
||||
"LicenseExpressionExpectLicenseFoundCompound": "Expected a license name, found the compound {value}.",
|
||||
"LicenseExpressionExpectLicenseFoundEof": "Expected a license name, found the end of the string.",
|
||||
"LicenseExpressionExpectLicenseFoundParen": "Expected a license name, found a parenthesis.",
|
||||
"LicenseExpressionImbalancedParens": "There was a close parenthesis without an opening parenthesis.",
|
||||
"LicenseExpressionUnknownException": "Unknown license exception identifier '{value}'. Known values are listed at https://spdx.org/licenses/exceptions-index.html",
|
||||
"LicenseExpressionUnknownLicense": "Unknown license identifier '{value}'. Known values are listed at https://spdx.org/licenses/",
|
||||
"NoLocalizationForMessages": "No localization for the following messages:",
|
||||
"ProcessorArchitectureMalformed": "Failed to parse %PROCESSOR_ARCHITECTURE% ({value}) as a valid CPU architecture.",
|
||||
"ProcessorArchitectureMissing": "The required environment variable %PROCESSOR_ARCHITECTURE% is missing.",
|
||||
|
|
|
@ -236,8 +236,8 @@ TEST_CASE ("JSON track newlines", "[json]")
|
|||
REQUIRE(!res);
|
||||
REQUIRE(res.error()->format() ==
|
||||
R"(filename:2:1: error: Unexpected character; expected property name
|
||||
on expression: ,
|
||||
^
|
||||
on expression: ,
|
||||
^
|
||||
)");
|
||||
}
|
||||
|
||||
|
@ -247,7 +247,39 @@ TEST_CASE ("JSON duplicated object keys", "[json]")
|
|||
REQUIRE(!res);
|
||||
REQUIRE(res.error()->format() ==
|
||||
R"(filename:1:13: error: Duplicated key "name" in an object
|
||||
on expression: {"name": 1, "name": 2}
|
||||
^
|
||||
on expression: {"name": 1, "name": 2}
|
||||
^
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_CASE ("JSON support unicode characters in errors", "[json]")
|
||||
{
|
||||
// unicode characters w/ bytes >1
|
||||
auto res = Json::parse(R"json("Δx/Δt" "")json", "filename");
|
||||
REQUIRE(!res);
|
||||
CHECK(res.error()->format() ==
|
||||
R"(filename:1:9: error: Unexpected character; expected EOF
|
||||
on expression: "Δx/Δt" ""
|
||||
^
|
||||
)");
|
||||
|
||||
// full width unicode characters
|
||||
// note that the A is full width
|
||||
res = Json::parse(R"json("姐姐aA" "")json", "filename");
|
||||
REQUIRE(!res);
|
||||
CHECK(res.error()->format() ==
|
||||
R"(filename:1:8: error: Unexpected character; expected EOF
|
||||
on expression: "姐姐aA" ""
|
||||
^
|
||||
)");
|
||||
|
||||
// incorrect errors in the face of combining characters
|
||||
// (this test should be fixed once the underlying bug is fixed)
|
||||
res = Json::parse(R"json("é" "")json", "filename");
|
||||
REQUIRE(!res);
|
||||
CHECK(res.error()->format() ==
|
||||
R"(filename:1:6: error: Unexpected character; expected EOF
|
||||
on expression: "é" ""
|
||||
^
|
||||
)");
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <vcpkg/base/json.h>
|
||||
#include <vcpkg/base/system.print.h>
|
||||
#include <vcpkg/base/util.h>
|
||||
|
||||
#include <vcpkg/paragraphs.h>
|
||||
|
@ -28,21 +29,40 @@ static Json::Object parse_json_object(StringView sv)
|
|||
}
|
||||
else
|
||||
{
|
||||
vcpkg::print2("Error found while parsing JSON document:\n", sv, '\n');
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO, json.error()->format());
|
||||
}
|
||||
}
|
||||
|
||||
static Parse::ParseExpected<SourceControlFile> test_parse_manifest(StringView sv, bool expect_fail = false)
|
||||
enum class PrintErrors : bool
|
||||
{
|
||||
auto object = parse_json_object(sv);
|
||||
auto res = SourceControlFile::parse_manifest_object("<test manifest>", object);
|
||||
if (!res.has_value() && !expect_fail)
|
||||
No,
|
||||
Yes,
|
||||
};
|
||||
|
||||
static Parse::ParseExpected<SourceControlFile> test_parse_manifest(const Json::Object& obj,
|
||||
PrintErrors print = PrintErrors::Yes)
|
||||
{
|
||||
auto res = SourceControlFile::parse_manifest_object("<test manifest>", obj);
|
||||
if (!res.has_value() && print == PrintErrors::Yes)
|
||||
{
|
||||
print_error_message(res.error());
|
||||
}
|
||||
REQUIRE(res.has_value() == !expect_fail);
|
||||
return res;
|
||||
}
|
||||
static Parse::ParseExpected<SourceControlFile> test_parse_manifest(StringView obj, PrintErrors print = PrintErrors::Yes)
|
||||
{
|
||||
return test_parse_manifest(parse_json_object(obj), print);
|
||||
}
|
||||
|
||||
static bool manifest_is_parseable(const Json::Object& obj)
|
||||
{
|
||||
return test_parse_manifest(obj, PrintErrors::No).has_value();
|
||||
}
|
||||
static bool manifest_is_parseable(StringView obj)
|
||||
{
|
||||
return test_parse_manifest(parse_json_object(obj), PrintErrors::No).has_value();
|
||||
}
|
||||
|
||||
static const FeatureFlagSettings feature_flags_with_versioning{false, false, false, true};
|
||||
static const FeatureFlagSettings feature_flags_without_versioning{false, false, false, false};
|
||||
|
@ -113,57 +133,49 @@ TEST_CASE ("manifest versioning", "[manifests]")
|
|||
CHECK(pgh.core_paragraph->port_version == 0);
|
||||
}
|
||||
|
||||
test_parse_manifest(R"json({
|
||||
REQUIRE_FALSE(manifest_is_parseable(R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "abcd",
|
||||
"version-semver": "1.2.3-rc3"
|
||||
})json",
|
||||
true);
|
||||
})json"));
|
||||
|
||||
test_parse_manifest(R"json({
|
||||
REQUIRE_FALSE(manifest_is_parseable(R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "abcd#1"
|
||||
})json",
|
||||
true);
|
||||
test_parse_manifest(R"json({
|
||||
})json"));
|
||||
REQUIRE_FALSE(manifest_is_parseable(R"json({
|
||||
"name": "zlib",
|
||||
"version": "abcd#1"
|
||||
})json",
|
||||
true);
|
||||
test_parse_manifest(R"json({
|
||||
})json"));
|
||||
REQUIRE_FALSE(manifest_is_parseable(R"json({
|
||||
"name": "zlib",
|
||||
"version-date": "abcd#1"
|
||||
})json",
|
||||
true);
|
||||
test_parse_manifest(R"json({
|
||||
})json"));
|
||||
REQUIRE_FALSE(manifest_is_parseable(R"json({
|
||||
"name": "zlib",
|
||||
"version-semver": "abcd#1"
|
||||
})json",
|
||||
true);
|
||||
})json"));
|
||||
|
||||
SECTION ("version syntax")
|
||||
{
|
||||
test_parse_manifest(R"json({
|
||||
REQUIRE_FALSE(manifest_is_parseable(R"json({
|
||||
"name": "zlib",
|
||||
"version-semver": "2020-01-01"
|
||||
})json",
|
||||
true);
|
||||
test_parse_manifest(R"json({
|
||||
})json"));
|
||||
REQUIRE_FALSE(manifest_is_parseable(R"json({
|
||||
"name": "zlib",
|
||||
"version-date": "1.1.1"
|
||||
})json",
|
||||
true);
|
||||
test_parse_manifest(R"json({
|
||||
})json"));
|
||||
REQUIRE(manifest_is_parseable(R"json({
|
||||
"name": "zlib",
|
||||
"version": "1.2.3-rc3"
|
||||
})json",
|
||||
false);
|
||||
})json"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE ("manifest constraints hash", "[manifests]")
|
||||
{
|
||||
auto p = unwrap(test_parse_manifest(R"json({
|
||||
auto m_pgh = test_parse_manifest(R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "abcd",
|
||||
"dependencies": [
|
||||
|
@ -172,11 +184,13 @@ TEST_CASE ("manifest constraints hash", "[manifests]")
|
|||
"version>=": "2018-09-01#1"
|
||||
}
|
||||
]
|
||||
})json"));
|
||||
})json");
|
||||
REQUIRE(m_pgh.has_value());
|
||||
const auto& p = *m_pgh.get();
|
||||
REQUIRE(p->core_paragraph->dependencies.at(0).constraint.value == "2018-09-01");
|
||||
REQUIRE(p->core_paragraph->dependencies.at(0).constraint.port_version == 1);
|
||||
|
||||
test_parse_manifest(R"json({
|
||||
REQUIRE_FALSE(manifest_is_parseable(R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "abcd",
|
||||
"dependencies": [
|
||||
|
@ -185,10 +199,9 @@ TEST_CASE ("manifest constraints hash", "[manifests]")
|
|||
"version>=": "2018-09-01#0"
|
||||
}
|
||||
]
|
||||
})json",
|
||||
true);
|
||||
})json"));
|
||||
|
||||
test_parse_manifest(R"json({
|
||||
REQUIRE_FALSE(manifest_is_parseable(R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "abcd",
|
||||
"dependencies": [
|
||||
|
@ -197,10 +210,9 @@ TEST_CASE ("manifest constraints hash", "[manifests]")
|
|||
"version>=": "2018-09-01#-1"
|
||||
}
|
||||
]
|
||||
})json",
|
||||
true);
|
||||
})json"));
|
||||
|
||||
test_parse_manifest(R"json({
|
||||
REQUIRE_FALSE(manifest_is_parseable(R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "abcd",
|
||||
"dependencies": [
|
||||
|
@ -210,13 +222,12 @@ TEST_CASE ("manifest constraints hash", "[manifests]")
|
|||
"port-version": 1
|
||||
}
|
||||
]
|
||||
})json",
|
||||
true);
|
||||
})json"));
|
||||
}
|
||||
|
||||
TEST_CASE ("manifest overrides embedded port version", "[manifests]")
|
||||
{
|
||||
test_parse_manifest(R"json({
|
||||
REQUIRE_FALSE(manifest_is_parseable(R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "abcd",
|
||||
"overrides": [
|
||||
|
@ -226,9 +237,8 @@ TEST_CASE ("manifest overrides embedded port version", "[manifests]")
|
|||
"port-version": 1
|
||||
}
|
||||
]
|
||||
})json",
|
||||
true);
|
||||
test_parse_manifest(R"json({
|
||||
})json"));
|
||||
REQUIRE_FALSE(manifest_is_parseable(R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "abcd",
|
||||
"overrides": [
|
||||
|
@ -238,9 +248,8 @@ TEST_CASE ("manifest overrides embedded port version", "[manifests]")
|
|||
"port-version": 1
|
||||
}
|
||||
]
|
||||
})json",
|
||||
true);
|
||||
test_parse_manifest(R"json({
|
||||
})json"));
|
||||
REQUIRE_FALSE(manifest_is_parseable(R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "abcd",
|
||||
"overrides": [
|
||||
|
@ -250,9 +259,8 @@ TEST_CASE ("manifest overrides embedded port version", "[manifests]")
|
|||
"port-version": 1
|
||||
}
|
||||
]
|
||||
})json",
|
||||
true);
|
||||
test_parse_manifest(R"json({
|
||||
})json"));
|
||||
REQUIRE_FALSE(manifest_is_parseable(R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "abcd",
|
||||
"overrides": [
|
||||
|
@ -262,10 +270,9 @@ TEST_CASE ("manifest overrides embedded port version", "[manifests]")
|
|||
"port-version": 1
|
||||
}
|
||||
]
|
||||
})json",
|
||||
true);
|
||||
})json"));
|
||||
|
||||
CHECK(unwrap(test_parse_manifest(R"json({
|
||||
auto parsed = test_parse_manifest(R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "abcd",
|
||||
"overrides": [
|
||||
|
@ -274,11 +281,11 @@ TEST_CASE ("manifest overrides embedded port version", "[manifests]")
|
|||
"version-string": "abcd#1"
|
||||
}
|
||||
]
|
||||
})json",
|
||||
false))
|
||||
->core_paragraph->overrides.at(0)
|
||||
.port_version == 1);
|
||||
CHECK(unwrap(test_parse_manifest(R"json({
|
||||
})json");
|
||||
REQUIRE(parsed.has_value());
|
||||
CHECK((*parsed.get())->core_paragraph->overrides.at(0).port_version == 1);
|
||||
|
||||
parsed = test_parse_manifest(R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "abcd",
|
||||
"overrides": [
|
||||
|
@ -287,11 +294,11 @@ TEST_CASE ("manifest overrides embedded port version", "[manifests]")
|
|||
"version-date": "2018-01-01#1"
|
||||
}
|
||||
]
|
||||
})json",
|
||||
false))
|
||||
->core_paragraph->overrides.at(0)
|
||||
.port_version == 1);
|
||||
CHECK(unwrap(test_parse_manifest(R"json({
|
||||
})json");
|
||||
REQUIRE(parsed.has_value());
|
||||
CHECK((*parsed.get())->core_paragraph->overrides.at(0).port_version == 1);
|
||||
|
||||
parsed = test_parse_manifest(R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "abcd",
|
||||
"overrides": [
|
||||
|
@ -300,11 +307,11 @@ TEST_CASE ("manifest overrides embedded port version", "[manifests]")
|
|||
"version": "1.2#1"
|
||||
}
|
||||
]
|
||||
})json",
|
||||
false))
|
||||
->core_paragraph->overrides.at(0)
|
||||
.port_version == 1);
|
||||
CHECK(unwrap(test_parse_manifest(R"json({
|
||||
})json");
|
||||
REQUIRE(parsed.has_value());
|
||||
CHECK((*parsed.get())->core_paragraph->overrides.at(0).port_version == 1);
|
||||
|
||||
parsed = test_parse_manifest(R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "abcd",
|
||||
"overrides": [
|
||||
|
@ -313,10 +320,9 @@ TEST_CASE ("manifest overrides embedded port version", "[manifests]")
|
|||
"version-semver": "1.2.0#1"
|
||||
}
|
||||
]
|
||||
})json",
|
||||
false))
|
||||
->core_paragraph->overrides.at(0)
|
||||
.port_version == 1);
|
||||
})json");
|
||||
REQUIRE(parsed.has_value());
|
||||
CHECK((*parsed.get())->core_paragraph->overrides.at(0).port_version == 1);
|
||||
}
|
||||
|
||||
TEST_CASE ("manifest constraints", "[manifests]")
|
||||
|
@ -355,7 +361,7 @@ TEST_CASE ("manifest constraints", "[manifests]")
|
|||
DependencyConstraint{VersionConstraintKind::Minimum, "2018-09-01", 0});
|
||||
REQUIRE(pgh.core_paragraph->builtin_baseline == "089fa4de7dca22c67dcab631f618d5cd0697c8d4");
|
||||
|
||||
test_parse_manifest(R"json({
|
||||
REQUIRE_FALSE(manifest_is_parseable(R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "abcd",
|
||||
"dependencies": [
|
||||
|
@ -364,8 +370,7 @@ TEST_CASE ("manifest constraints", "[manifests]")
|
|||
"port-version": 5
|
||||
}
|
||||
]
|
||||
})json",
|
||||
true);
|
||||
})json"));
|
||||
}
|
||||
|
||||
TEST_CASE ("manifest builtin-baseline", "[manifests]")
|
||||
|
@ -555,7 +560,7 @@ TEST_CASE ("manifest overrides", "[manifests]")
|
|||
REQUIRE(!pgh.check_against_feature_flags({}, feature_flags_with_versioning));
|
||||
}
|
||||
|
||||
test_parse_manifest(R"json({
|
||||
REQUIRE_FALSE(manifest_is_parseable(R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "abcd",
|
||||
"builtin-baseline": "089fa4de7dca22c67dcab631f618d5cd0697c8d4",
|
||||
|
@ -565,10 +570,9 @@ TEST_CASE ("manifest overrides", "[manifests]")
|
|||
"version-semver": "1.2.3-rc3",
|
||||
"version-string": "1.2.3-rc3"
|
||||
}
|
||||
]})json",
|
||||
true);
|
||||
]})json"));
|
||||
|
||||
test_parse_manifest(R"json({
|
||||
REQUIRE_FALSE(manifest_is_parseable(R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "abcd",
|
||||
"builtin-baseline": "089fa4de7dca22c67dcab631f618d5cd0697c8d4",
|
||||
|
@ -577,8 +581,7 @@ TEST_CASE ("manifest overrides", "[manifests]")
|
|||
"name": "abc",
|
||||
"port-version": 5
|
||||
}
|
||||
]})json",
|
||||
true);
|
||||
]})json"));
|
||||
|
||||
std::string raw = R"json({
|
||||
"name": "zlib",
|
||||
|
@ -946,22 +949,146 @@ TEST_CASE ("SourceParagraph manifest supports", "[manifests]")
|
|||
|
||||
TEST_CASE ("SourceParagraph manifest empty supports", "[manifests]")
|
||||
{
|
||||
auto m_pgh = test_parse_manifest(R"json({
|
||||
REQUIRE_FALSE(manifest_is_parseable(R"json({
|
||||
"name": "a",
|
||||
"version-string": "1.0",
|
||||
"supports": ""
|
||||
})json",
|
||||
true);
|
||||
REQUIRE_FALSE(m_pgh.has_value());
|
||||
})json"));
|
||||
}
|
||||
|
||||
TEST_CASE ("SourceParagraph manifest non-string supports", "[manifests]")
|
||||
{
|
||||
auto m_pgh = test_parse_manifest(R"json({
|
||||
REQUIRE_FALSE(manifest_is_parseable(R"json({
|
||||
"name": "a",
|
||||
"version-string": "1.0",
|
||||
"supports": true
|
||||
})json",
|
||||
true);
|
||||
REQUIRE_FALSE(m_pgh.has_value());
|
||||
})json"));
|
||||
}
|
||||
|
||||
static Json::Object manifest_with_license(Json::Value&& license)
|
||||
{
|
||||
Json::Object res;
|
||||
res.insert("name", Json::Value::string("foo"));
|
||||
res.insert("version", Json::Value::string("0"));
|
||||
res.insert("license", std::move(license));
|
||||
return res;
|
||||
}
|
||||
static Json::Object manifest_with_license(StringView license)
|
||||
{
|
||||
return manifest_with_license(Json::Value::string(license.to_string()));
|
||||
}
|
||||
static std::string test_serialized_license(StringView license)
|
||||
{
|
||||
auto m_pgh = test_parse_manifest(manifest_with_license(license));
|
||||
REQUIRE(m_pgh.has_value());
|
||||
|
||||
return serialize_manifest(**m_pgh.get())["license"].string().to_string();
|
||||
}
|
||||
|
||||
static bool license_is_parseable(StringView license)
|
||||
{
|
||||
Parse::ParseMessages messages;
|
||||
parse_spdx_license_expression(license, messages);
|
||||
return messages.error == nullptr;
|
||||
}
|
||||
static bool license_is_strict(StringView license)
|
||||
{
|
||||
Parse::ParseMessages messages;
|
||||
parse_spdx_license_expression(license, messages);
|
||||
return messages.error == nullptr && messages.warnings.empty();
|
||||
}
|
||||
|
||||
static std::string test_format_parse_warning(const Parse::ParseMessage& msg)
|
||||
{
|
||||
return msg.format("<license string>", Parse::MessageKind::Warning).extract_data();
|
||||
}
|
||||
|
||||
TEST_CASE ("simple license in manifest", "[manifests][license]")
|
||||
{
|
||||
CHECK(manifest_is_parseable(manifest_with_license(Json::Value::null(nullptr))));
|
||||
CHECK_FALSE(manifest_is_parseable(manifest_with_license("")));
|
||||
CHECK(manifest_is_parseable(manifest_with_license("MIT")));
|
||||
}
|
||||
|
||||
TEST_CASE ("valid and invalid licenses", "[manifests][license]")
|
||||
{
|
||||
CHECK(license_is_strict("mIt"));
|
||||
CHECK(license_is_strict("Apache-2.0"));
|
||||
CHECK(license_is_strict("GPL-2.0+"));
|
||||
CHECK_FALSE(license_is_parseable("GPL-2.0++"));
|
||||
CHECK(license_is_strict("LicenseRef-blah"));
|
||||
CHECK_FALSE(license_is_strict("unknownlicense"));
|
||||
CHECK(license_is_parseable("unknownlicense"));
|
||||
}
|
||||
|
||||
TEST_CASE ("licenses with compounds", "[manifests][license]")
|
||||
{
|
||||
CHECK(license_is_strict("GPL-3.0+ WITH GCC-exception-3.1"));
|
||||
CHECK(license_is_strict("Apache-2.0 WITH LLVM-exception"));
|
||||
CHECK_FALSE(license_is_parseable("(Apache-2.0) WITH LLVM-exception"));
|
||||
CHECK(license_is_strict("(Apache-2.0 OR MIT) AND GPL-3.0+ WITH GCC-exception-3.1"));
|
||||
CHECK_FALSE(license_is_parseable("Apache-2.0 WITH"));
|
||||
CHECK_FALSE(license_is_parseable("GPL-3.0+ AND"));
|
||||
CHECK_FALSE(license_is_parseable("MIT and Apache-2.0"));
|
||||
CHECK_FALSE(license_is_parseable("GPL-3.0 WITH GCC-exception+"));
|
||||
CHECK_FALSE(license_is_parseable("(GPL-3.0 WITH GCC-exception)+"));
|
||||
}
|
||||
|
||||
TEST_CASE ("license serialization", "[manifests][license]")
|
||||
{
|
||||
auto m_pgh = test_parse_manifest(manifest_with_license(Json::Value::null(nullptr)));
|
||||
REQUIRE(m_pgh);
|
||||
auto manifest = serialize_manifest(**m_pgh.get());
|
||||
REQUIRE(manifest.contains("license"));
|
||||
CHECK(manifest["license"].is_null());
|
||||
|
||||
CHECK(test_serialized_license("MIT") == "MIT");
|
||||
CHECK(test_serialized_license("mit") == "MIT");
|
||||
CHECK(test_serialized_license("MiT AND (aPACHe-2.0 \tOR \n gpl-2.0+)") == "MIT AND (Apache-2.0 OR GPL-2.0+)");
|
||||
CHECK(test_serialized_license("uNkNoWnLiCeNsE") == "uNkNoWnLiCeNsE");
|
||||
}
|
||||
|
||||
TEST_CASE ("license error messages", "[manifests][license]")
|
||||
{
|
||||
Parse::ParseMessages messages;
|
||||
parse_spdx_license_expression("", messages);
|
||||
REQUIRE(messages.error);
|
||||
CHECK(messages.error->format() == R"(<license string>:1:1: error: SPDX license expression was empty.
|
||||
on expression:
|
||||
^
|
||||
)");
|
||||
|
||||
parse_spdx_license_expression("MIT ()", messages);
|
||||
REQUIRE(messages.error);
|
||||
CHECK(messages.error->format() ==
|
||||
R"(<license string>:1:5: error: Expected a compound or the end of the string, found a parenthesis.
|
||||
on expression: MIT ()
|
||||
^
|
||||
)");
|
||||
|
||||
parse_spdx_license_expression("MIT +", messages);
|
||||
REQUIRE(messages.error);
|
||||
CHECK(
|
||||
messages.error->format() ==
|
||||
R"(<license string>:1:5: error: SPDX license expression contains an extra '+'. These are only allowed directly after a license identifier.
|
||||
on expression: MIT +
|
||||
^
|
||||
)");
|
||||
|
||||
parse_spdx_license_expression("MIT AND", messages);
|
||||
REQUIRE(messages.error);
|
||||
CHECK(messages.error->format() ==
|
||||
R"(<license string>:1:8: error: Expected a license name, found the end of the string.
|
||||
on expression: MIT AND
|
||||
^
|
||||
)");
|
||||
|
||||
parse_spdx_license_expression("MIT AND unknownlicense", messages);
|
||||
CHECK(!messages.error);
|
||||
REQUIRE(messages.warnings.size() == 1);
|
||||
CHECK(
|
||||
test_format_parse_warning(messages.warnings[0]) ==
|
||||
R"(<license string>:1:9: warning: Unknown license identifier 'unknownlicense'. Known values are listed at https://spdx.org/licenses/
|
||||
on expression: MIT AND unknownlicense
|
||||
^)");
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#include <vcpkg/base/messages.h>
|
||||
#include <vcpkg/base/parse.h>
|
||||
#include <vcpkg/base/system.print.h>
|
||||
#include <vcpkg/base/util.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
using namespace vcpkg;
|
||||
|
@ -25,28 +27,67 @@ namespace vcpkg::Parse
|
|||
|
||||
std::string ParseError::format() const
|
||||
{
|
||||
auto caret_spacing = std::string(18, ' ');
|
||||
auto decoder = Unicode::Utf8Decoder(line.data(), line.data() + line.size());
|
||||
for (int i = 0; i < caret_col; ++i, ++decoder)
|
||||
{
|
||||
const char32_t cp = *decoder;
|
||||
// this may eventually want to check for full-width characters and grapheme clusters as well
|
||||
caret_spacing.push_back(cp == '\t' ? '\t' : ' ');
|
||||
}
|
||||
ParseMessage as_message;
|
||||
as_message.location = SourceLoc{std::next(decoder, caret_col), decoder, row, column};
|
||||
as_message.message = msg::LocalizedString::from_string_unchecked(std::string(message));
|
||||
|
||||
return Strings::concat(origin,
|
||||
":",
|
||||
row,
|
||||
":",
|
||||
column,
|
||||
": error: ",
|
||||
message,
|
||||
"\n"
|
||||
" on expression: ", // 18 columns
|
||||
line,
|
||||
"\n",
|
||||
caret_spacing,
|
||||
"^\n");
|
||||
auto res = as_message.format(origin, MessageKind::Error).extract_data();
|
||||
res.push_back('\n');
|
||||
return res;
|
||||
}
|
||||
|
||||
DECLARE_AND_REGISTER_MESSAGE(FormattedParseMessageLocation,
|
||||
(msg::path, msg::row, msg::column),
|
||||
"{LOCKED}",
|
||||
"{path}:{row}:{column}: ");
|
||||
DECLARE_AND_REGISTER_MESSAGE(FormattedParseError, (msg::value), "", "error: {value}");
|
||||
DECLARE_AND_REGISTER_MESSAGE(FormattedParseWarning, (msg::value), "", "warning: {value}");
|
||||
DECLARE_AND_REGISTER_MESSAGE(FormattedParseMessageExpression, (msg::value), "", " on expression: {value}");
|
||||
|
||||
msg::LocalizedString ParseMessage::format(StringView origin, MessageKind kind) const
|
||||
{
|
||||
msg::LocalizedString res = msg::format(msgFormattedParseMessageLocation,
|
||||
msg::path = origin,
|
||||
msg::row = location.row,
|
||||
msg::column = location.column);
|
||||
if (kind == MessageKind::Warning)
|
||||
{
|
||||
res.append(msg::format(msgFormattedParseWarning, msg::value = message));
|
||||
}
|
||||
else
|
||||
{
|
||||
res.append(msg::format(msgFormattedParseError, msg::value = message));
|
||||
}
|
||||
res.appendnl();
|
||||
|
||||
auto line_end = Util::find_if(location.it, Parse::ParserBase::is_lineend);
|
||||
StringView line = StringView{
|
||||
location.start_of_line.pointer_to_current(),
|
||||
line_end.pointer_to_current(),
|
||||
};
|
||||
res.append(msg::format(msgFormattedParseMessageExpression, msg::value = line));
|
||||
res.appendnl();
|
||||
|
||||
auto caret_point = StringView{location.start_of_line.pointer_to_current(), location.it.pointer_to_current()};
|
||||
auto formatted_caret_point = msg::format(msgFormattedParseMessageExpression, msg::value = caret_point);
|
||||
|
||||
std::string caret_string;
|
||||
caret_string.reserve(formatted_caret_point.data().size());
|
||||
for (char32_t ch : Unicode::Utf8Decoder(formatted_caret_point))
|
||||
{
|
||||
if (ch == '\t')
|
||||
caret_string.push_back('\t');
|
||||
else if (Unicode::is_double_width_code_point(ch))
|
||||
caret_string.append(" ");
|
||||
else
|
||||
caret_string.push_back(' ');
|
||||
}
|
||||
caret_string.push_back('^');
|
||||
|
||||
res.append(msg::LocalizedString::from_string_unchecked(std::move(caret_string)));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
const std::string& ParseError::get_message() const { return this->message; }
|
||||
|
@ -84,10 +125,15 @@ namespace vcpkg::Parse
|
|||
return cur();
|
||||
}
|
||||
|
||||
void ParserBase::add_warning(msg::LocalizedString&& message, const SourceLoc& loc)
|
||||
{
|
||||
m_messages.warnings.push_back(ParseMessage{loc, std::move(message)});
|
||||
}
|
||||
|
||||
void ParserBase::add_error(std::string message, const SourceLoc& loc)
|
||||
{
|
||||
// avoid cascading errors by only saving the first
|
||||
if (!m_err)
|
||||
if (!m_messages.error)
|
||||
{
|
||||
// find end of line
|
||||
auto line_end = loc.it;
|
||||
|
@ -95,7 +141,7 @@ namespace vcpkg::Parse
|
|||
{
|
||||
++line_end;
|
||||
}
|
||||
m_err = std::make_unique<ParseError>(
|
||||
m_messages.error = std::make_unique<ParseError>(
|
||||
m_origin.to_string(),
|
||||
loc.row,
|
||||
loc.column,
|
||||
|
|
|
@ -92,6 +92,103 @@ namespace vcpkg::Unicode
|
|||
return count;
|
||||
}
|
||||
|
||||
std::pair<const char*, utf8_errc> utf8_decode_code_point(const char* first,
|
||||
const char* last,
|
||||
char32_t& out) noexcept
|
||||
{
|
||||
out = end_of_file;
|
||||
if (first == last)
|
||||
{
|
||||
return {last, utf8_errc::NoError};
|
||||
}
|
||||
|
||||
auto code_unit = *first;
|
||||
auto kind = utf8_code_unit_kind(code_unit);
|
||||
const int count = utf8_code_unit_count(kind);
|
||||
|
||||
const char* it = first + 1;
|
||||
|
||||
if (kind == Utf8CodeUnitKind::Invalid)
|
||||
{
|
||||
return {it, utf8_errc::InvalidCodeUnit};
|
||||
}
|
||||
else if (kind == Utf8CodeUnitKind::Continue)
|
||||
{
|
||||
return {it, utf8_errc::UnexpectedContinue};
|
||||
}
|
||||
else if (count > last - first)
|
||||
{
|
||||
return {last, utf8_errc::UnexpectedEof};
|
||||
}
|
||||
|
||||
if (count == 1)
|
||||
{
|
||||
out = static_cast<char32_t>(code_unit);
|
||||
return {it, utf8_errc::NoError};
|
||||
}
|
||||
|
||||
// 2 -> 0b0001'1111, 6
|
||||
// 3 -> 0b0000'1111, 12
|
||||
// 4 -> 0b0000'0111, 18
|
||||
const auto start_mask = static_cast<unsigned char>(0xFF >> (count + 1));
|
||||
const int start_shift = 6 * (count - 1);
|
||||
char32_t code_point = static_cast<char32_t>(code_unit & start_mask) << start_shift;
|
||||
|
||||
constexpr unsigned char continue_mask = 0b0011'1111;
|
||||
for (int byte = 1; byte < count; ++byte)
|
||||
{
|
||||
code_unit = static_cast<unsigned char>(*it++);
|
||||
|
||||
kind = utf8_code_unit_kind(code_unit);
|
||||
if (kind == Utf8CodeUnitKind::Invalid)
|
||||
{
|
||||
return {it, utf8_errc::InvalidCodeUnit};
|
||||
}
|
||||
else if (kind != Utf8CodeUnitKind::Continue)
|
||||
{
|
||||
return {it, utf8_errc::UnexpectedStart};
|
||||
}
|
||||
|
||||
const int shift = 6 * (count - byte - 1);
|
||||
code_point |= (code_unit & continue_mask) << shift;
|
||||
}
|
||||
|
||||
if (code_point > 0x10'FFFF)
|
||||
{
|
||||
return {it, utf8_errc::InvalidCodePoint};
|
||||
}
|
||||
|
||||
out = code_point;
|
||||
return {it, utf8_errc::NoError};
|
||||
}
|
||||
|
||||
// uses the C++20 definition
|
||||
/*
|
||||
[format.string.std]
|
||||
* U+1100 - U+115F
|
||||
* U+2329 - U+232A
|
||||
* U+2E80 - U+303E
|
||||
* U+3040 - U+A4CF
|
||||
* U+AC00 - U+D7A3
|
||||
* U+F900 - U+FAFF
|
||||
* U+FE10 - U+FE19
|
||||
* U+FE30 - U+FE6F
|
||||
* U+FF00 - U+FF60
|
||||
* U+FFE0 - U+FFE6
|
||||
* U+1F300 - U+1F64F
|
||||
* U+1F900 - U+1F9FF
|
||||
* U+20000 - U+2FFFD
|
||||
* U+30000 - U+3FFFD
|
||||
*/
|
||||
bool is_double_width_code_point(char32_t ch) noexcept
|
||||
{
|
||||
return (ch >= 0x1100 && ch <= 0x115F) || (ch >= 0x2329 && ch <= 0x232A) || (ch >= 0x2E80 && ch <= 0x303E) ||
|
||||
(ch >= 0x3040 && ch <= 0xA4CF) || (ch >= 0xAC00 && ch <= 0xD7A3) || (ch >= 0xF900 && ch <= 0xFAFF) ||
|
||||
(ch >= 0xFE10 && ch <= 0xFE19) || (ch >= 0xFE30 && ch <= 0xFE6F) || (ch >= 0xFF00 && ch <= 0xFF60) ||
|
||||
(ch >= 0xFFE0 && ch <= 0xFFE6) || (ch >= 0x1F300 && ch <= 0x1F64F) || (ch >= 0x1F900 && ch <= 0x1F9FF) ||
|
||||
(ch >= 0x20000 && ch <= 0x2FFFD) || (ch >= 0x30000 && ch <= 0x3FFFD);
|
||||
}
|
||||
|
||||
bool utf8_is_valid_string(const char* first, const char* last) noexcept
|
||||
{
|
||||
utf8_errc err = utf8_errc::NoError;
|
||||
|
@ -179,76 +276,22 @@ namespace vcpkg::Unicode
|
|||
return utf8_errc::NoError;
|
||||
}
|
||||
|
||||
unsigned char code_unit = static_cast<unsigned char>(*next_++);
|
||||
|
||||
auto kind = utf8_code_unit_kind(code_unit);
|
||||
if (kind == Utf8CodeUnitKind::Invalid)
|
||||
char32_t code_point;
|
||||
auto new_next = utf8_decode_code_point(next_, last_, code_point);
|
||||
if (new_next.second != utf8_errc::NoError)
|
||||
{
|
||||
*this = sentinel();
|
||||
return utf8_errc::InvalidCodeUnit;
|
||||
return new_next.second;
|
||||
}
|
||||
else if (kind == Utf8CodeUnitKind::Continue)
|
||||
|
||||
if (utf16_is_trailing_surrogate_code_point(code_point) && utf16_is_leading_surrogate_code_point(current_))
|
||||
{
|
||||
*this = sentinel();
|
||||
return utf8_errc::UnexpectedContinue;
|
||||
return utf8_errc::PairedSurrogates;
|
||||
}
|
||||
|
||||
const int count = utf8_code_unit_count(kind);
|
||||
if (count == 1)
|
||||
{
|
||||
current_ = static_cast<char32_t>(code_unit);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 2 -> 0b0001'1111, 6
|
||||
// 3 -> 0b0000'1111, 12
|
||||
// 4 -> 0b0000'0111, 18
|
||||
const auto start_mask = static_cast<unsigned char>(0xFF >> (count + 1));
|
||||
const int start_shift = 6 * (count - 1);
|
||||
auto code_point = static_cast<char32_t>(code_unit & start_mask) << start_shift;
|
||||
|
||||
constexpr unsigned char continue_mask = 0b0011'1111;
|
||||
for (int byte = 1; byte < count; ++byte)
|
||||
{
|
||||
if (next_ == last_)
|
||||
{
|
||||
*this = sentinel();
|
||||
return utf8_errc::UnexpectedContinue;
|
||||
}
|
||||
code_unit = static_cast<unsigned char>(*next_++);
|
||||
|
||||
kind = utf8_code_unit_kind(code_unit);
|
||||
if (kind == Utf8CodeUnitKind::Invalid)
|
||||
{
|
||||
*this = sentinel();
|
||||
return utf8_errc::InvalidCodeUnit;
|
||||
}
|
||||
else if (kind != Utf8CodeUnitKind::Continue)
|
||||
{
|
||||
*this = sentinel();
|
||||
return utf8_errc::UnexpectedStart;
|
||||
}
|
||||
|
||||
const int shift = 6 * (count - byte - 1);
|
||||
code_point |= (code_unit & continue_mask) << shift;
|
||||
}
|
||||
|
||||
if (code_point > 0x10'FFFF)
|
||||
{
|
||||
*this = sentinel();
|
||||
return utf8_errc::InvalidCodePoint;
|
||||
}
|
||||
else if (utf16_is_trailing_surrogate_code_point(code_point) &&
|
||||
utf16_is_leading_surrogate_code_point(current_))
|
||||
{
|
||||
*this = sentinel();
|
||||
return utf8_errc::PairedSurrogates;
|
||||
}
|
||||
else
|
||||
{
|
||||
current_ = code_point;
|
||||
}
|
||||
}
|
||||
next_ = new_next.first;
|
||||
current_ = code_point;
|
||||
return utf8_errc::NoError;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,8 @@ namespace
|
|||
"Restored {value} packages from AWS servers in {elapsed}s");
|
||||
DECLARE_AND_REGISTER_MESSAGE(AwsUploadedPackages, (msg::value), "", "Uploaded binaries to {value} AWS servers");
|
||||
|
||||
using Parse::SourceLoc;
|
||||
|
||||
struct ConfigSegmentsParser : Parse::ParserBase
|
||||
{
|
||||
using Parse::ParserBase::ParserBase;
|
||||
|
@ -134,10 +136,9 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<std::vector<std::pair<Parse::ParserBase::SourceLoc, std::string>>> ConfigSegmentsParser::
|
||||
parse_all_segments()
|
||||
std::vector<std::vector<std::pair<SourceLoc, std::string>>> ConfigSegmentsParser::parse_all_segments()
|
||||
{
|
||||
std::vector<std::vector<std::pair<Parse::ParserBase::SourceLoc, std::string>>> ret;
|
||||
std::vector<std::vector<std::pair<SourceLoc, std::string>>> ret;
|
||||
while (!at_eof())
|
||||
{
|
||||
std::vector<std::pair<SourceLoc, std::string>> segments;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <vcpkg/base/expected.h>
|
||||
#include <vcpkg/base/jsonreader.h>
|
||||
#include <vcpkg/base/span.h>
|
||||
#include <vcpkg/base/stringliteral.h>
|
||||
#include <vcpkg/base/system.debug.h>
|
||||
#include <vcpkg/base/system.print.h>
|
||||
#include <vcpkg/base/util.h>
|
||||
|
@ -16,6 +17,85 @@
|
|||
#include <vcpkg/vcpkgcmdarguments.h>
|
||||
#include <vcpkg/versiondeserializers.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace msg = vcpkg::msg;
|
||||
DECLARE_AND_REGISTER_MESSAGE(EmptyLicenseExpression, (), "", "SPDX license expression was empty.");
|
||||
DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionContainsUnicode,
|
||||
(msg::value, msg::pretty_value),
|
||||
"",
|
||||
"SPDX license expression contains a unicode character (U+{value:04x} "
|
||||
"'{pretty_value}'), but these expressions are ASCII-only.");
|
||||
DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionContainsInvalidCharacter,
|
||||
(msg::value),
|
||||
"",
|
||||
"SPDX license expression contains an invalid character (0x{value:02x} '{value}').");
|
||||
DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionContainsExtraPlus,
|
||||
(),
|
||||
"",
|
||||
"SPDX license expression contains an extra '+'. These are only allowed directly "
|
||||
"after a license identifier.");
|
||||
DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionDocumentRefUnsupported,
|
||||
(),
|
||||
"",
|
||||
"The current implementation does not support DocumentRef- SPDX references.");
|
||||
DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionExpectLicenseFoundEof,
|
||||
(),
|
||||
"",
|
||||
"Expected a license name, found the end of the string.");
|
||||
DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionExpectExceptionFoundEof,
|
||||
(),
|
||||
"",
|
||||
"Expected an exception name, found the end of the string.");
|
||||
DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionExpectCompoundFoundParen,
|
||||
(),
|
||||
"",
|
||||
"Expected a compound or the end of the string, found a parenthesis.");
|
||||
DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionExpectLicenseFoundParen,
|
||||
(),
|
||||
"",
|
||||
"Expected a license name, found a parenthesis.");
|
||||
DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionExpectExceptionFoundParen,
|
||||
(),
|
||||
"",
|
||||
"Expected an exception name, found a parenthesis.");
|
||||
DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionImbalancedParens,
|
||||
(),
|
||||
"",
|
||||
"There was a close parenthesis without an opening parenthesis.");
|
||||
DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionExpectLicenseFoundCompound,
|
||||
(msg::value),
|
||||
"",
|
||||
"Expected a license name, found the compound {value}.");
|
||||
DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionExpectExceptionFoundCompound,
|
||||
(msg::value),
|
||||
"",
|
||||
"Expected an exception name, found the compound {value}.");
|
||||
DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionExpectCompoundFoundWith,
|
||||
(),
|
||||
"",
|
||||
"Expected either AND or OR, found WITH (WITH is only allowed after license names, not "
|
||||
"parenthesized expressions).");
|
||||
DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionExpectCompoundOrWithFoundWord,
|
||||
(msg::value),
|
||||
"",
|
||||
"Expected either AND, OR, or WITH, found a license or exception name: '{value}'.");
|
||||
DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionExpectCompoundFoundWord,
|
||||
(msg::value),
|
||||
"",
|
||||
"Expected either AND or OR, found a license or exception name: '{value}'.");
|
||||
DECLARE_AND_REGISTER_MESSAGE(
|
||||
LicenseExpressionUnknownLicense,
|
||||
(msg::value),
|
||||
"",
|
||||
"Unknown license identifier '{value}'. Known values are listed at https://spdx.org/licenses/");
|
||||
DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionUnknownException,
|
||||
(msg::value),
|
||||
"",
|
||||
"Unknown license exception identifier '{value}'. Known values are listed at "
|
||||
"https://spdx.org/licenses/exceptions-index.html");
|
||||
} // anonymous namespace
|
||||
|
||||
namespace vcpkg
|
||||
{
|
||||
using namespace vcpkg::Parse;
|
||||
|
@ -708,143 +788,253 @@ namespace vcpkg
|
|||
};
|
||||
ContactsDeserializer ContactsDeserializer::instance;
|
||||
|
||||
static constexpr StringLiteral EXPRESSION_WORDS[] = {
|
||||
"WITH",
|
||||
"AND",
|
||||
"OR",
|
||||
static constexpr StringLiteral VALID_LICENSES[] = {
|
||||
#include "spdx-licenses.inc"
|
||||
};
|
||||
static constexpr StringLiteral VALID_EXCEPTIONS[] = {
|
||||
#include "spdx-exceptions.inc"
|
||||
};
|
||||
static constexpr StringLiteral VALID_LICENSES[] =
|
||||
#include "spdx-licenses.inc"
|
||||
;
|
||||
static constexpr StringLiteral VALID_EXCEPTIONS[] =
|
||||
#include "spdx-licenses.inc"
|
||||
;
|
||||
|
||||
// We "parse" this so that we can add actual license parsing at some point in the future
|
||||
// without breaking anyone
|
||||
// The "license" field; either:
|
||||
// * a string, which must be an SPDX license expression.
|
||||
// EBNF located at: https://github.com/microsoft/vcpkg/blob/master/docs/maintainers/manifest-files.md#license
|
||||
// * `null`, for when the license of the package cannot be described by an SPDX expression
|
||||
struct SpdxLicenseExpressionParser : Parse::ParserBase
|
||||
{
|
||||
SpdxLicenseExpressionParser(StringView sv, StringView origin) : Parse::ParserBase(sv, origin) { }
|
||||
|
||||
static const StringLiteral* case_insensitive_find(View<StringLiteral> lst, StringView id)
|
||||
{
|
||||
return Util::find_if(lst,
|
||||
[id](StringLiteral el) { return Strings::case_insensitive_ascii_equals(id, el); });
|
||||
}
|
||||
static constexpr bool is_idstring_element(char32_t ch) { return is_alphanumdash(ch) || ch == '.'; }
|
||||
|
||||
enum class Expecting
|
||||
{
|
||||
License, // at the beginning, or after a compound (AND, OR)
|
||||
Exception, // after a WITH
|
||||
CompoundOrWith, // after a license
|
||||
Compound, // after an exception (only one WITH is allowed), or after a close paren
|
||||
};
|
||||
|
||||
void eat_idstring(std::string& result, Expecting& expecting)
|
||||
{
|
||||
auto loc = cur_loc();
|
||||
auto token = match_zero_or_more(is_idstring_element);
|
||||
|
||||
if (Strings::starts_with(token, "DocumentRef-"))
|
||||
{
|
||||
add_error(msg::format(msgLicenseExpressionDocumentRefUnsupported), loc);
|
||||
if (cur() == ':')
|
||||
{
|
||||
next();
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (token == "AND" || token == "OR" || token == "WITH")
|
||||
{
|
||||
if (expecting == Expecting::License)
|
||||
{
|
||||
add_error(msg::format(msgLicenseExpressionExpectLicenseFoundCompound, msg::value = token), loc);
|
||||
}
|
||||
if (expecting == Expecting::Exception)
|
||||
{
|
||||
add_error(msg::format(msgLicenseExpressionExpectExceptionFoundCompound, msg::value = token), loc);
|
||||
}
|
||||
|
||||
if (token == "WITH")
|
||||
{
|
||||
if (expecting == Expecting::Compound)
|
||||
{
|
||||
add_error(msg::format(msgLicenseExpressionExpectCompoundFoundWith), loc);
|
||||
}
|
||||
expecting = Expecting::Exception;
|
||||
}
|
||||
else
|
||||
{
|
||||
expecting = Expecting::License;
|
||||
}
|
||||
|
||||
result.push_back(' ');
|
||||
result.append(token.begin(), token.end());
|
||||
result.push_back(' ');
|
||||
return;
|
||||
}
|
||||
|
||||
switch (expecting)
|
||||
{
|
||||
case Expecting::Compound:
|
||||
add_error(msg::format(msgLicenseExpressionExpectCompoundFoundWord, msg::value = token), loc);
|
||||
break;
|
||||
case Expecting::CompoundOrWith:
|
||||
add_error(msg::format(msgLicenseExpressionExpectCompoundOrWithFoundWord, msg::value = token), loc);
|
||||
break;
|
||||
case Expecting::License:
|
||||
if (Strings::starts_with(token, "LicenseRef-"))
|
||||
{
|
||||
result.append(token.begin(), token.end());
|
||||
}
|
||||
else
|
||||
{
|
||||
auto it = case_insensitive_find(VALID_LICENSES, token);
|
||||
if (it != std::end(VALID_LICENSES))
|
||||
{
|
||||
result.append(it->begin(), it->end());
|
||||
}
|
||||
else
|
||||
{
|
||||
add_warning(msg::format(msgLicenseExpressionUnknownLicense, msg::value = token), loc);
|
||||
result.append(token.begin(), token.end());
|
||||
}
|
||||
|
||||
if (cur() == '+')
|
||||
{
|
||||
next();
|
||||
result.push_back('+');
|
||||
}
|
||||
}
|
||||
expecting = Expecting::CompoundOrWith;
|
||||
break;
|
||||
case Expecting::Exception:
|
||||
auto it = case_insensitive_find(VALID_EXCEPTIONS, token);
|
||||
if (it != std::end(VALID_EXCEPTIONS))
|
||||
{
|
||||
// case normalization
|
||||
result.append(it->begin(), it->end());
|
||||
}
|
||||
else
|
||||
{
|
||||
add_warning(msg::format(msgLicenseExpressionUnknownException, msg::value = token), loc);
|
||||
result.append(token.begin(), token.end());
|
||||
}
|
||||
expecting = Expecting::Compound;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::string parse()
|
||||
{
|
||||
if (cur() == Unicode::end_of_file)
|
||||
{
|
||||
add_error(msg::format(msgEmptyLicenseExpression));
|
||||
return "";
|
||||
}
|
||||
|
||||
Expecting expecting = Expecting::License;
|
||||
std::string result;
|
||||
|
||||
size_t open_parens = 0;
|
||||
while (!at_eof())
|
||||
{
|
||||
skip_whitespace();
|
||||
switch (cur())
|
||||
{
|
||||
case '(':
|
||||
if (expecting == Expecting::Compound || expecting == Expecting::CompoundOrWith)
|
||||
{
|
||||
add_error(msg::format(msgLicenseExpressionExpectCompoundFoundParen));
|
||||
}
|
||||
if (expecting == Expecting::Exception)
|
||||
{
|
||||
add_error(msg::format(msgLicenseExpressionExpectExceptionFoundParen));
|
||||
}
|
||||
result.push_back('(');
|
||||
expecting = Expecting::License;
|
||||
++open_parens;
|
||||
next();
|
||||
break;
|
||||
case ')':
|
||||
if (expecting == Expecting::License)
|
||||
{
|
||||
add_error(msg::format(msgLicenseExpressionExpectLicenseFoundParen));
|
||||
}
|
||||
else if (expecting == Expecting::Exception)
|
||||
{
|
||||
add_error(msg::format(msgLicenseExpressionExpectExceptionFoundParen));
|
||||
}
|
||||
if (open_parens == 0)
|
||||
{
|
||||
add_error(msg::format(msgLicenseExpressionImbalancedParens));
|
||||
}
|
||||
result.push_back(')');
|
||||
expecting = Expecting::Compound;
|
||||
--open_parens;
|
||||
next();
|
||||
break;
|
||||
case '+':
|
||||
add_error(msg::format(msgLicenseExpressionContainsExtraPlus));
|
||||
next();
|
||||
break;
|
||||
default:
|
||||
if (cur() > 0x7F)
|
||||
{
|
||||
auto ch = cur();
|
||||
auto first = it().pointer_to_current();
|
||||
next();
|
||||
auto last = it().pointer_to_current();
|
||||
add_error(msg::format(msgLicenseExpressionContainsUnicode,
|
||||
msg::value = ch,
|
||||
msg::pretty_value = StringView{first, last}));
|
||||
break;
|
||||
}
|
||||
if (!is_idstring_element(cur()))
|
||||
{
|
||||
add_error(msg::format(msgLicenseExpressionContainsInvalidCharacter,
|
||||
msg::value = static_cast<char>(cur())));
|
||||
next();
|
||||
break;
|
||||
}
|
||||
eat_idstring(result, expecting);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (expecting == Expecting::License)
|
||||
{
|
||||
add_error(msg::format(msgLicenseExpressionExpectLicenseFoundEof));
|
||||
}
|
||||
if (expecting == Expecting::Exception)
|
||||
{
|
||||
add_error(msg::format(msgLicenseExpressionExpectExceptionFoundEof));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
std::string parse_spdx_license_expression(StringView sv, Parse::ParseMessages& messages)
|
||||
{
|
||||
auto parser = SpdxLicenseExpressionParser(sv, "<license string>");
|
||||
auto result = parser.parse();
|
||||
messages = parser.extract_messages();
|
||||
return result;
|
||||
}
|
||||
|
||||
struct LicenseExpressionDeserializer : Json::IDeserializer<std::string>
|
||||
{
|
||||
virtual StringView type_name() const override { return "an SPDX license expression"; }
|
||||
|
||||
enum class Mode
|
||||
virtual Optional<std::string> visit_null(Json::Reader&) override { return {std::string()}; }
|
||||
|
||||
// if `sv` is a valid SPDX license expression, returns sv,
|
||||
// but with whitespace normalized
|
||||
virtual Optional<std::string> visit_string(Json::Reader& r, StringView sv) override
|
||||
{
|
||||
ExpectExpression,
|
||||
ExpectContinue,
|
||||
ExpectException,
|
||||
};
|
||||
auto parser = SpdxLicenseExpressionParser(sv, "<manifest>");
|
||||
auto res = parser.parse();
|
||||
|
||||
virtual Optional<std::string> visit_string(Json::Reader&, StringView sv) override
|
||||
{
|
||||
Mode mode = Mode::ExpectExpression;
|
||||
size_t open_parens = 0;
|
||||
std::string current_word;
|
||||
|
||||
const auto check_current_word = [¤t_word, &mode] {
|
||||
if (current_word.empty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Span<const StringLiteral> valid_ids;
|
||||
bool case_sensitive = false;
|
||||
switch (mode)
|
||||
{
|
||||
case Mode::ExpectExpression:
|
||||
valid_ids = VALID_LICENSES;
|
||||
mode = Mode::ExpectContinue;
|
||||
// a single + is allowed on the end of licenses
|
||||
if (current_word.back() == '+')
|
||||
{
|
||||
current_word.pop_back();
|
||||
}
|
||||
break;
|
||||
case Mode::ExpectContinue:
|
||||
valid_ids = EXPRESSION_WORDS;
|
||||
mode = Mode::ExpectExpression;
|
||||
case_sensitive = true;
|
||||
break;
|
||||
case Mode::ExpectException:
|
||||
valid_ids = VALID_EXCEPTIONS;
|
||||
mode = Mode::ExpectContinue;
|
||||
break;
|
||||
}
|
||||
|
||||
const auto equal = [&](StringView sv) {
|
||||
if (case_sensitive)
|
||||
{
|
||||
return sv == current_word;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Strings::case_insensitive_ascii_equals(sv, current_word);
|
||||
}
|
||||
};
|
||||
|
||||
if (std::find_if(valid_ids.begin(), valid_ids.end(), equal) == valid_ids.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (current_word == "WITH")
|
||||
{
|
||||
mode = Mode::ExpectException;
|
||||
}
|
||||
|
||||
current_word.clear();
|
||||
return true;
|
||||
};
|
||||
|
||||
for (const auto& ch : sv)
|
||||
for (const auto& warning : parser.messages().warnings)
|
||||
{
|
||||
if (ch == ' ' || ch == '\t')
|
||||
{
|
||||
if (!check_current_word())
|
||||
{
|
||||
return nullopt;
|
||||
}
|
||||
}
|
||||
else if (ch == '(')
|
||||
{
|
||||
if (!check_current_word())
|
||||
{
|
||||
return nullopt;
|
||||
}
|
||||
if (mode != Mode::ExpectExpression)
|
||||
{
|
||||
return nullopt;
|
||||
}
|
||||
++open_parens;
|
||||
}
|
||||
else if (ch == ')')
|
||||
{
|
||||
if (!check_current_word())
|
||||
{
|
||||
return nullopt;
|
||||
}
|
||||
if (mode != Mode::ExpectContinue)
|
||||
{
|
||||
return nullopt;
|
||||
}
|
||||
if (open_parens == 0)
|
||||
{
|
||||
return nullopt;
|
||||
}
|
||||
--open_parens;
|
||||
}
|
||||
else
|
||||
{
|
||||
current_word.push_back(ch);
|
||||
}
|
||||
msg::println(Color::warning, warning.format("<manifest>", Parse::MessageKind::Warning));
|
||||
}
|
||||
if (auto err = parser.get_error())
|
||||
{
|
||||
r.add_generic_error(type_name(), err->format());
|
||||
return std::string();
|
||||
}
|
||||
|
||||
if (!check_current_word())
|
||||
{
|
||||
return nullopt;
|
||||
}
|
||||
else
|
||||
{
|
||||
return sv.to_string();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static LicenseExpressionDeserializer instance;
|
||||
|
@ -941,7 +1131,13 @@ namespace vcpkg
|
|||
r.optional_object_field(obj, DESCRIPTION, spgh->description, Json::ParagraphDeserializer::instance);
|
||||
r.optional_object_field(obj, HOMEPAGE, spgh->homepage, url_deserializer);
|
||||
r.optional_object_field(obj, DOCUMENTATION, spgh->documentation, url_deserializer);
|
||||
r.optional_object_field(obj, LICENSE, spgh->license, LicenseExpressionDeserializer::instance);
|
||||
|
||||
std::string license;
|
||||
if (r.optional_object_field(obj, LICENSE, license, LicenseExpressionDeserializer::instance))
|
||||
{
|
||||
spgh->license = {std::move(license)};
|
||||
}
|
||||
|
||||
r.optional_object_field(obj, DEPENDENCIES, spgh->dependencies, DependencyArrayDeserializer::instance);
|
||||
static Json::ArrayDeserializer<DependencyOverrideDeserializer> overrides_deserializer{
|
||||
"an array of overrides"};
|
||||
|
@ -1464,7 +1660,21 @@ namespace vcpkg
|
|||
|
||||
serialize_optional_string(obj, ManifestDeserializer::HOMEPAGE, scf.core_paragraph->homepage);
|
||||
serialize_optional_string(obj, ManifestDeserializer::DOCUMENTATION, scf.core_paragraph->documentation);
|
||||
serialize_optional_string(obj, ManifestDeserializer::LICENSE, scf.core_paragraph->license);
|
||||
if (auto license = scf.core_paragraph->license.get())
|
||||
{
|
||||
if (license->empty())
|
||||
{
|
||||
obj.insert(ManifestDeserializer::LICENSE, Json::Value::null(nullptr));
|
||||
}
|
||||
else
|
||||
{
|
||||
obj.insert(ManifestDeserializer::LICENSE, Json::Value::string(*license));
|
||||
}
|
||||
}
|
||||
else if (debug)
|
||||
{
|
||||
obj.insert(ManifestDeserializer::LICENSE, Json::Value::string(""));
|
||||
}
|
||||
serialize_optional_string(
|
||||
obj, ManifestDeserializer::SUPPORTS, to_string(scf.core_paragraph->supports_expression));
|
||||
if (scf.core_paragraph->builtin_baseline.has_value())
|
||||
|
|
|
@ -1,45 +1,43 @@
|
|||
// Data downloaded from https://raw.githubusercontent.com/spdx/license-list-data/0af22f869f8b0906097cfac90ee0516992e8939f/json/exceptions.json
|
||||
// Generated by scripts/Generate-SpdxLicenseList.ps1
|
||||
{
|
||||
"389-exception",
|
||||
"Autoconf-exception-2.0",
|
||||
"Autoconf-exception-3.0",
|
||||
"Bison-exception-2.2",
|
||||
"Bootloader-exception",
|
||||
"Classpath-exception-2.0",
|
||||
"CLISP-exception-2.0",
|
||||
"DigiRule-FOSS-exception",
|
||||
"eCos-exception-2.0",
|
||||
"Fawkes-Runtime-exception",
|
||||
"FLTK-exception",
|
||||
"Font-exception-2.0",
|
||||
"freertos-exception-2.0",
|
||||
"GCC-exception-2.0",
|
||||
"GCC-exception-3.1",
|
||||
"gnu-javamail-exception",
|
||||
"GPL-3.0-linking-exception",
|
||||
"GPL-3.0-linking-source-exception",
|
||||
"GPL-CC-1.0",
|
||||
"i2p-gpl-java-exception",
|
||||
"LGPL-3.0-linking-exception",
|
||||
"Libtool-exception",
|
||||
"Linux-syscall-note",
|
||||
"LLVM-exception",
|
||||
"LZMA-exception",
|
||||
"mif-exception",
|
||||
"Nokia-Qt-exception-1.1",
|
||||
"OCaml-LGPL-linking-exception",
|
||||
"OCCT-exception-1.0",
|
||||
"OpenJDK-assembly-exception-1.0",
|
||||
"openvpn-openssl-exception",
|
||||
"PS-or-PDF-font-exception-20170817",
|
||||
"Qt-GPL-exception-1.0",
|
||||
"Qt-LGPL-exception-1.1",
|
||||
"Qwt-exception-1.0",
|
||||
"SHL-2.0",
|
||||
"SHL-2.1",
|
||||
"Swift-exception",
|
||||
"u-boot-exception-2.0",
|
||||
"Universal-FOSS-exception-1.0",
|
||||
"WxWindows-exception-3.1",
|
||||
}
|
||||
// Generated by Generate-SpdxLicenseList.ps1
|
||||
"389-exception",
|
||||
"Autoconf-exception-2.0",
|
||||
"Autoconf-exception-3.0",
|
||||
"Bison-exception-2.2",
|
||||
"Bootloader-exception",
|
||||
"Classpath-exception-2.0",
|
||||
"CLISP-exception-2.0",
|
||||
"DigiRule-FOSS-exception",
|
||||
"eCos-exception-2.0",
|
||||
"Fawkes-Runtime-exception",
|
||||
"FLTK-exception",
|
||||
"Font-exception-2.0",
|
||||
"freertos-exception-2.0",
|
||||
"GCC-exception-2.0",
|
||||
"GCC-exception-3.1",
|
||||
"gnu-javamail-exception",
|
||||
"GPL-3.0-linking-exception",
|
||||
"GPL-3.0-linking-source-exception",
|
||||
"GPL-CC-1.0",
|
||||
"i2p-gpl-java-exception",
|
||||
"LGPL-3.0-linking-exception",
|
||||
"Libtool-exception",
|
||||
"Linux-syscall-note",
|
||||
"LLVM-exception",
|
||||
"LZMA-exception",
|
||||
"mif-exception",
|
||||
"Nokia-Qt-exception-1.1",
|
||||
"OCaml-LGPL-linking-exception",
|
||||
"OCCT-exception-1.0",
|
||||
"OpenJDK-assembly-exception-1.0",
|
||||
"openvpn-openssl-exception",
|
||||
"PS-or-PDF-font-exception-20170817",
|
||||
"Qt-GPL-exception-1.0",
|
||||
"Qt-LGPL-exception-1.1",
|
||||
"Qwt-exception-1.0",
|
||||
"SHL-2.0",
|
||||
"SHL-2.1",
|
||||
"Swift-exception",
|
||||
"u-boot-exception-2.0",
|
||||
"Universal-FOSS-exception-1.0",
|
||||
"WxWindows-exception-3.1",
|
||||
|
|
|
@ -1,479 +1,477 @@
|
|||
// Data downloaded from https://raw.githubusercontent.com/spdx/license-list-data/0af22f869f8b0906097cfac90ee0516992e8939f/json/licenses.json
|
||||
// Generated by scripts/Generate-SpdxLicenseList.ps1
|
||||
{
|
||||
"0BSD",
|
||||
"AAL",
|
||||
"Abstyles",
|
||||
"Adobe-2006",
|
||||
"Adobe-Glyph",
|
||||
"ADSL",
|
||||
"AFL-1.1",
|
||||
"AFL-1.2",
|
||||
"AFL-2.0",
|
||||
"AFL-2.1",
|
||||
"AFL-3.0",
|
||||
"Afmparse",
|
||||
"AGPL-1.0",
|
||||
"AGPL-1.0-only",
|
||||
"AGPL-1.0-or-later",
|
||||
"AGPL-3.0",
|
||||
"AGPL-3.0-only",
|
||||
"AGPL-3.0-or-later",
|
||||
"Aladdin",
|
||||
"AMDPLPA",
|
||||
"AML",
|
||||
"AMPAS",
|
||||
"ANTLR-PD",
|
||||
"ANTLR-PD-fallback",
|
||||
"Apache-1.0",
|
||||
"Apache-1.1",
|
||||
"Apache-2.0",
|
||||
"APAFML",
|
||||
"APL-1.0",
|
||||
"APSL-1.0",
|
||||
"APSL-1.1",
|
||||
"APSL-1.2",
|
||||
"APSL-2.0",
|
||||
"Artistic-1.0",
|
||||
"Artistic-1.0-cl8",
|
||||
"Artistic-1.0-Perl",
|
||||
"Artistic-2.0",
|
||||
"Bahyph",
|
||||
"Barr",
|
||||
"Beerware",
|
||||
"BitTorrent-1.0",
|
||||
"BitTorrent-1.1",
|
||||
"blessing",
|
||||
"BlueOak-1.0.0",
|
||||
"Borceux",
|
||||
"BSD-1-Clause",
|
||||
"BSD-2-Clause",
|
||||
"BSD-2-Clause-FreeBSD",
|
||||
"BSD-2-Clause-NetBSD",
|
||||
"BSD-2-Clause-Patent",
|
||||
"BSD-2-Clause-Views",
|
||||
"BSD-3-Clause",
|
||||
"BSD-3-Clause-Attribution",
|
||||
"BSD-3-Clause-Clear",
|
||||
"BSD-3-Clause-LBNL",
|
||||
"BSD-3-Clause-Modification",
|
||||
"BSD-3-Clause-No-Military-License",
|
||||
"BSD-3-Clause-No-Nuclear-License",
|
||||
"BSD-3-Clause-No-Nuclear-License-2014",
|
||||
"BSD-3-Clause-No-Nuclear-Warranty",
|
||||
"BSD-3-Clause-Open-MPI",
|
||||
"BSD-4-Clause",
|
||||
"BSD-4-Clause-Shortened",
|
||||
"BSD-4-Clause-UC",
|
||||
"BSD-Protection",
|
||||
"BSD-Source-Code",
|
||||
"BSL-1.0",
|
||||
"BUSL-1.1",
|
||||
"bzip2-1.0.5",
|
||||
"bzip2-1.0.6",
|
||||
"C-UDA-1.0",
|
||||
"CAL-1.0",
|
||||
"CAL-1.0-Combined-Work-Exception",
|
||||
"Caldera",
|
||||
"CATOSL-1.1",
|
||||
"CC-BY-1.0",
|
||||
"CC-BY-2.0",
|
||||
"CC-BY-2.5",
|
||||
"CC-BY-2.5-AU",
|
||||
"CC-BY-3.0",
|
||||
"CC-BY-3.0-AT",
|
||||
"CC-BY-3.0-DE",
|
||||
"CC-BY-3.0-NL",
|
||||
"CC-BY-3.0-US",
|
||||
"CC-BY-4.0",
|
||||
"CC-BY-NC-1.0",
|
||||
"CC-BY-NC-2.0",
|
||||
"CC-BY-NC-2.5",
|
||||
"CC-BY-NC-3.0",
|
||||
"CC-BY-NC-3.0-DE",
|
||||
"CC-BY-NC-4.0",
|
||||
"CC-BY-NC-ND-1.0",
|
||||
"CC-BY-NC-ND-2.0",
|
||||
"CC-BY-NC-ND-2.5",
|
||||
"CC-BY-NC-ND-3.0",
|
||||
"CC-BY-NC-ND-3.0-DE",
|
||||
"CC-BY-NC-ND-3.0-IGO",
|
||||
"CC-BY-NC-ND-4.0",
|
||||
"CC-BY-NC-SA-1.0",
|
||||
"CC-BY-NC-SA-2.0",
|
||||
"CC-BY-NC-SA-2.0-FR",
|
||||
"CC-BY-NC-SA-2.0-UK",
|
||||
"CC-BY-NC-SA-2.5",
|
||||
"CC-BY-NC-SA-3.0",
|
||||
"CC-BY-NC-SA-3.0-DE",
|
||||
"CC-BY-NC-SA-3.0-IGO",
|
||||
"CC-BY-NC-SA-4.0",
|
||||
"CC-BY-ND-1.0",
|
||||
"CC-BY-ND-2.0",
|
||||
"CC-BY-ND-2.5",
|
||||
"CC-BY-ND-3.0",
|
||||
"CC-BY-ND-3.0-DE",
|
||||
"CC-BY-ND-4.0",
|
||||
"CC-BY-SA-1.0",
|
||||
"CC-BY-SA-2.0",
|
||||
"CC-BY-SA-2.0-UK",
|
||||
"CC-BY-SA-2.1-JP",
|
||||
"CC-BY-SA-2.5",
|
||||
"CC-BY-SA-3.0",
|
||||
"CC-BY-SA-3.0-AT",
|
||||
"CC-BY-SA-3.0-DE",
|
||||
"CC-BY-SA-4.0",
|
||||
"CC-PDDC",
|
||||
"CC0-1.0",
|
||||
"CDDL-1.0",
|
||||
"CDDL-1.1",
|
||||
"CDL-1.0",
|
||||
"CDLA-Permissive-1.0",
|
||||
"CDLA-Permissive-2.0",
|
||||
"CDLA-Sharing-1.0",
|
||||
"CECILL-1.0",
|
||||
"CECILL-1.1",
|
||||
"CECILL-2.0",
|
||||
"CECILL-2.1",
|
||||
"CECILL-B",
|
||||
"CECILL-C",
|
||||
"CERN-OHL-1.1",
|
||||
"CERN-OHL-1.2",
|
||||
"CERN-OHL-P-2.0",
|
||||
"CERN-OHL-S-2.0",
|
||||
"CERN-OHL-W-2.0",
|
||||
"ClArtistic",
|
||||
"CNRI-Jython",
|
||||
"CNRI-Python",
|
||||
"CNRI-Python-GPL-Compatible",
|
||||
"Condor-1.1",
|
||||
"copyleft-next-0.3.0",
|
||||
"copyleft-next-0.3.1",
|
||||
"CPAL-1.0",
|
||||
"CPL-1.0",
|
||||
"CPOL-1.02",
|
||||
"Crossword",
|
||||
"CrystalStacker",
|
||||
"CUA-OPL-1.0",
|
||||
"Cube",
|
||||
"curl",
|
||||
"D-FSL-1.0",
|
||||
"diffmark",
|
||||
"DOC",
|
||||
"Dotseqn",
|
||||
"DRL-1.0",
|
||||
"DSDP",
|
||||
"dvipdfm",
|
||||
"ECL-1.0",
|
||||
"ECL-2.0",
|
||||
"eCos-2.0",
|
||||
"EFL-1.0",
|
||||
"EFL-2.0",
|
||||
"eGenix",
|
||||
"Entessa",
|
||||
"EPICS",
|
||||
"EPL-1.0",
|
||||
"EPL-2.0",
|
||||
"ErlPL-1.1",
|
||||
"etalab-2.0",
|
||||
"EUDatagrid",
|
||||
"EUPL-1.0",
|
||||
"EUPL-1.1",
|
||||
"EUPL-1.2",
|
||||
"Eurosym",
|
||||
"Fair",
|
||||
"Frameworx-1.0",
|
||||
"FreeBSD-DOC",
|
||||
"FreeImage",
|
||||
"FSFAP",
|
||||
"FSFUL",
|
||||
"FSFULLR",
|
||||
"FTL",
|
||||
"GD",
|
||||
"GFDL-1.1",
|
||||
"GFDL-1.1-invariants-only",
|
||||
"GFDL-1.1-invariants-or-later",
|
||||
"GFDL-1.1-no-invariants-only",
|
||||
"GFDL-1.1-no-invariants-or-later",
|
||||
"GFDL-1.1-only",
|
||||
"GFDL-1.1-or-later",
|
||||
"GFDL-1.2",
|
||||
"GFDL-1.2-invariants-only",
|
||||
"GFDL-1.2-invariants-or-later",
|
||||
"GFDL-1.2-no-invariants-only",
|
||||
"GFDL-1.2-no-invariants-or-later",
|
||||
"GFDL-1.2-only",
|
||||
"GFDL-1.2-or-later",
|
||||
"GFDL-1.3",
|
||||
"GFDL-1.3-invariants-only",
|
||||
"GFDL-1.3-invariants-or-later",
|
||||
"GFDL-1.3-no-invariants-only",
|
||||
"GFDL-1.3-no-invariants-or-later",
|
||||
"GFDL-1.3-only",
|
||||
"GFDL-1.3-or-later",
|
||||
"Giftware",
|
||||
"GL2PS",
|
||||
"Glide",
|
||||
"Glulxe",
|
||||
"GLWTPL",
|
||||
"gnuplot",
|
||||
"GPL-1.0",
|
||||
"GPL-1.0-only",
|
||||
"GPL-1.0-or-later",
|
||||
"GPL-1.0+",
|
||||
"GPL-2.0",
|
||||
"GPL-2.0-only",
|
||||
"GPL-2.0-or-later",
|
||||
"GPL-2.0-with-autoconf-exception",
|
||||
"GPL-2.0-with-bison-exception",
|
||||
"GPL-2.0-with-classpath-exception",
|
||||
"GPL-2.0-with-font-exception",
|
||||
"GPL-2.0-with-GCC-exception",
|
||||
"GPL-2.0+",
|
||||
"GPL-3.0",
|
||||
"GPL-3.0-only",
|
||||
"GPL-3.0-or-later",
|
||||
"GPL-3.0-with-autoconf-exception",
|
||||
"GPL-3.0-with-GCC-exception",
|
||||
"GPL-3.0+",
|
||||
"gSOAP-1.3b",
|
||||
"HaskellReport",
|
||||
"Hippocratic-2.1",
|
||||
"HPND",
|
||||
"HPND-sell-variant",
|
||||
"HTMLTIDY",
|
||||
"IBM-pibs",
|
||||
"ICU",
|
||||
"IJG",
|
||||
"ImageMagick",
|
||||
"iMatix",
|
||||
"Imlib2",
|
||||
"Info-ZIP",
|
||||
"Intel",
|
||||
"Intel-ACPI",
|
||||
"Interbase-1.0",
|
||||
"IPA",
|
||||
"IPL-1.0",
|
||||
"ISC",
|
||||
"JasPer-2.0",
|
||||
"JPNIC",
|
||||
"JSON",
|
||||
"LAL-1.2",
|
||||
"LAL-1.3",
|
||||
"Latex2e",
|
||||
"Leptonica",
|
||||
"LGPL-2.0",
|
||||
"LGPL-2.0-only",
|
||||
"LGPL-2.0-or-later",
|
||||
"LGPL-2.0+",
|
||||
"LGPL-2.1",
|
||||
"LGPL-2.1-only",
|
||||
"LGPL-2.1-or-later",
|
||||
"LGPL-2.1+",
|
||||
"LGPL-3.0",
|
||||
"LGPL-3.0-only",
|
||||
"LGPL-3.0-or-later",
|
||||
"LGPL-3.0+",
|
||||
"LGPLLR",
|
||||
"Libpng",
|
||||
"libpng-2.0",
|
||||
"libselinux-1.0",
|
||||
"libtiff",
|
||||
"LiLiQ-P-1.1",
|
||||
"LiLiQ-R-1.1",
|
||||
"LiLiQ-Rplus-1.1",
|
||||
"Linux-OpenIB",
|
||||
"LPL-1.0",
|
||||
"LPL-1.02",
|
||||
"LPPL-1.0",
|
||||
"LPPL-1.1",
|
||||
"LPPL-1.2",
|
||||
"LPPL-1.3a",
|
||||
"LPPL-1.3c",
|
||||
"MakeIndex",
|
||||
"MirOS",
|
||||
"MIT",
|
||||
"MIT-0",
|
||||
"MIT-advertising",
|
||||
"MIT-CMU",
|
||||
"MIT-enna",
|
||||
"MIT-feh",
|
||||
"MIT-Modern-Variant",
|
||||
"MIT-open-group",
|
||||
"MITNFA",
|
||||
"Motosoto",
|
||||
"mpich2",
|
||||
"MPL-1.0",
|
||||
"MPL-1.1",
|
||||
"MPL-2.0",
|
||||
"MPL-2.0-no-copyleft-exception",
|
||||
"MS-PL",
|
||||
"MS-RL",
|
||||
"MTLL",
|
||||
"MulanPSL-1.0",
|
||||
"MulanPSL-2.0",
|
||||
"Multics",
|
||||
"Mup",
|
||||
"NAIST-2003",
|
||||
"NASA-1.3",
|
||||
"Naumen",
|
||||
"NBPL-1.0",
|
||||
"NCGL-UK-2.0",
|
||||
"NCSA",
|
||||
"Net-SNMP",
|
||||
"NetCDF",
|
||||
"Newsletr",
|
||||
"NGPL",
|
||||
"NIST-PD",
|
||||
"NIST-PD-fallback",
|
||||
"NLOD-1.0",
|
||||
"NLOD-2.0",
|
||||
"NLPL",
|
||||
"Nokia",
|
||||
"NOSL",
|
||||
"Noweb",
|
||||
"NPL-1.0",
|
||||
"NPL-1.1",
|
||||
"NPOSL-3.0",
|
||||
"NRL",
|
||||
"NTP",
|
||||
"NTP-0",
|
||||
"Nunit",
|
||||
"O-UDA-1.0",
|
||||
"OCCT-PL",
|
||||
"OCLC-2.0",
|
||||
"ODbL-1.0",
|
||||
"ODC-By-1.0",
|
||||
"OFL-1.0",
|
||||
"OFL-1.0-no-RFN",
|
||||
"OFL-1.0-RFN",
|
||||
"OFL-1.1",
|
||||
"OFL-1.1-no-RFN",
|
||||
"OFL-1.1-RFN",
|
||||
"OGC-1.0",
|
||||
"OGDL-Taiwan-1.0",
|
||||
"OGL-Canada-2.0",
|
||||
"OGL-UK-1.0",
|
||||
"OGL-UK-2.0",
|
||||
"OGL-UK-3.0",
|
||||
"OGTSL",
|
||||
"OLDAP-1.1",
|
||||
"OLDAP-1.2",
|
||||
"OLDAP-1.3",
|
||||
"OLDAP-1.4",
|
||||
"OLDAP-2.0",
|
||||
"OLDAP-2.0.1",
|
||||
"OLDAP-2.1",
|
||||
"OLDAP-2.2",
|
||||
"OLDAP-2.2.1",
|
||||
"OLDAP-2.2.2",
|
||||
"OLDAP-2.3",
|
||||
"OLDAP-2.4",
|
||||
"OLDAP-2.5",
|
||||
"OLDAP-2.6",
|
||||
"OLDAP-2.7",
|
||||
"OLDAP-2.8",
|
||||
"OML",
|
||||
"OpenSSL",
|
||||
"OPL-1.0",
|
||||
"OPUBL-1.0",
|
||||
"OSET-PL-2.1",
|
||||
"OSL-1.0",
|
||||
"OSL-1.1",
|
||||
"OSL-2.0",
|
||||
"OSL-2.1",
|
||||
"OSL-3.0",
|
||||
"Parity-6.0.0",
|
||||
"Parity-7.0.0",
|
||||
"PDDL-1.0",
|
||||
"PHP-3.0",
|
||||
"PHP-3.01",
|
||||
"Plexus",
|
||||
"PolyForm-Noncommercial-1.0.0",
|
||||
"PolyForm-Small-Business-1.0.0",
|
||||
"PostgreSQL",
|
||||
"PSF-2.0",
|
||||
"psfrag",
|
||||
"psutils",
|
||||
"Python-2.0",
|
||||
"Qhull",
|
||||
"QPL-1.0",
|
||||
"Rdisc",
|
||||
"RHeCos-1.1",
|
||||
"RPL-1.1",
|
||||
"RPL-1.5",
|
||||
"RPSL-1.0",
|
||||
"RSA-MD",
|
||||
"RSCPL",
|
||||
"Ruby",
|
||||
"SAX-PD",
|
||||
"Saxpath",
|
||||
"SCEA",
|
||||
"Sendmail",
|
||||
"Sendmail-8.23",
|
||||
"SGI-B-1.0",
|
||||
"SGI-B-1.1",
|
||||
"SGI-B-2.0",
|
||||
"SHL-0.5",
|
||||
"SHL-0.51",
|
||||
"SimPL-2.0",
|
||||
"SISSL",
|
||||
"SISSL-1.2",
|
||||
"Sleepycat",
|
||||
"SMLNJ",
|
||||
"SMPPL",
|
||||
"SNIA",
|
||||
"Spencer-86",
|
||||
"Spencer-94",
|
||||
"Spencer-99",
|
||||
"SPL-1.0",
|
||||
"SSH-OpenSSH",
|
||||
"SSH-short",
|
||||
"SSPL-1.0",
|
||||
"StandardML-NJ",
|
||||
"SugarCRM-1.1.3",
|
||||
"SWL",
|
||||
"TAPR-OHL-1.0",
|
||||
"TCL",
|
||||
"TCP-wrappers",
|
||||
"TMate",
|
||||
"TORQUE-1.1",
|
||||
"TOSL",
|
||||
"TU-Berlin-1.0",
|
||||
"TU-Berlin-2.0",
|
||||
"UCL-1.0",
|
||||
"Unicode-DFS-2015",
|
||||
"Unicode-DFS-2016",
|
||||
"Unicode-TOU",
|
||||
"Unlicense",
|
||||
"UPL-1.0",
|
||||
"Verbatim-man-pages",
|
||||
"Vim",
|
||||
"VOSTROM",
|
||||
"VSL-1.0",
|
||||
"W3C",
|
||||
"W3C-19980720",
|
||||
"W3C-20150513",
|
||||
"Watcom-1.0",
|
||||
"Wsuipa",
|
||||
"WTFPL",
|
||||
"wxWindows",
|
||||
"X11",
|
||||
"Xerox",
|
||||
"XFree86-1.1",
|
||||
"xinetd",
|
||||
"Xnet",
|
||||
"xpp",
|
||||
"XSkat",
|
||||
"YPL-1.0",
|
||||
"YPL-1.1",
|
||||
"Zed",
|
||||
"Zend-2.0",
|
||||
"Zimbra-1.3",
|
||||
"Zimbra-1.4",
|
||||
"Zlib",
|
||||
"zlib-acknowledgement",
|
||||
"ZPL-1.1",
|
||||
"ZPL-2.0",
|
||||
"ZPL-2.1",
|
||||
}
|
||||
// Generated by Generate-SpdxLicenseList.ps1
|
||||
"0BSD",
|
||||
"AAL",
|
||||
"Abstyles",
|
||||
"Adobe-2006",
|
||||
"Adobe-Glyph",
|
||||
"ADSL",
|
||||
"AFL-1.1",
|
||||
"AFL-1.2",
|
||||
"AFL-2.0",
|
||||
"AFL-2.1",
|
||||
"AFL-3.0",
|
||||
"Afmparse",
|
||||
"AGPL-1.0",
|
||||
"AGPL-1.0-only",
|
||||
"AGPL-1.0-or-later",
|
||||
"AGPL-3.0",
|
||||
"AGPL-3.0-only",
|
||||
"AGPL-3.0-or-later",
|
||||
"Aladdin",
|
||||
"AMDPLPA",
|
||||
"AML",
|
||||
"AMPAS",
|
||||
"ANTLR-PD",
|
||||
"ANTLR-PD-fallback",
|
||||
"Apache-1.0",
|
||||
"Apache-1.1",
|
||||
"Apache-2.0",
|
||||
"APAFML",
|
||||
"APL-1.0",
|
||||
"APSL-1.0",
|
||||
"APSL-1.1",
|
||||
"APSL-1.2",
|
||||
"APSL-2.0",
|
||||
"Artistic-1.0",
|
||||
"Artistic-1.0-cl8",
|
||||
"Artistic-1.0-Perl",
|
||||
"Artistic-2.0",
|
||||
"Bahyph",
|
||||
"Barr",
|
||||
"Beerware",
|
||||
"BitTorrent-1.0",
|
||||
"BitTorrent-1.1",
|
||||
"blessing",
|
||||
"BlueOak-1.0.0",
|
||||
"Borceux",
|
||||
"BSD-1-Clause",
|
||||
"BSD-2-Clause",
|
||||
"BSD-2-Clause-FreeBSD",
|
||||
"BSD-2-Clause-NetBSD",
|
||||
"BSD-2-Clause-Patent",
|
||||
"BSD-2-Clause-Views",
|
||||
"BSD-3-Clause",
|
||||
"BSD-3-Clause-Attribution",
|
||||
"BSD-3-Clause-Clear",
|
||||
"BSD-3-Clause-LBNL",
|
||||
"BSD-3-Clause-Modification",
|
||||
"BSD-3-Clause-No-Military-License",
|
||||
"BSD-3-Clause-No-Nuclear-License",
|
||||
"BSD-3-Clause-No-Nuclear-License-2014",
|
||||
"BSD-3-Clause-No-Nuclear-Warranty",
|
||||
"BSD-3-Clause-Open-MPI",
|
||||
"BSD-4-Clause",
|
||||
"BSD-4-Clause-Shortened",
|
||||
"BSD-4-Clause-UC",
|
||||
"BSD-Protection",
|
||||
"BSD-Source-Code",
|
||||
"BSL-1.0",
|
||||
"BUSL-1.1",
|
||||
"bzip2-1.0.5",
|
||||
"bzip2-1.0.6",
|
||||
"C-UDA-1.0",
|
||||
"CAL-1.0",
|
||||
"CAL-1.0-Combined-Work-Exception",
|
||||
"Caldera",
|
||||
"CATOSL-1.1",
|
||||
"CC-BY-1.0",
|
||||
"CC-BY-2.0",
|
||||
"CC-BY-2.5",
|
||||
"CC-BY-2.5-AU",
|
||||
"CC-BY-3.0",
|
||||
"CC-BY-3.0-AT",
|
||||
"CC-BY-3.0-DE",
|
||||
"CC-BY-3.0-NL",
|
||||
"CC-BY-3.0-US",
|
||||
"CC-BY-4.0",
|
||||
"CC-BY-NC-1.0",
|
||||
"CC-BY-NC-2.0",
|
||||
"CC-BY-NC-2.5",
|
||||
"CC-BY-NC-3.0",
|
||||
"CC-BY-NC-3.0-DE",
|
||||
"CC-BY-NC-4.0",
|
||||
"CC-BY-NC-ND-1.0",
|
||||
"CC-BY-NC-ND-2.0",
|
||||
"CC-BY-NC-ND-2.5",
|
||||
"CC-BY-NC-ND-3.0",
|
||||
"CC-BY-NC-ND-3.0-DE",
|
||||
"CC-BY-NC-ND-3.0-IGO",
|
||||
"CC-BY-NC-ND-4.0",
|
||||
"CC-BY-NC-SA-1.0",
|
||||
"CC-BY-NC-SA-2.0",
|
||||
"CC-BY-NC-SA-2.0-FR",
|
||||
"CC-BY-NC-SA-2.0-UK",
|
||||
"CC-BY-NC-SA-2.5",
|
||||
"CC-BY-NC-SA-3.0",
|
||||
"CC-BY-NC-SA-3.0-DE",
|
||||
"CC-BY-NC-SA-3.0-IGO",
|
||||
"CC-BY-NC-SA-4.0",
|
||||
"CC-BY-ND-1.0",
|
||||
"CC-BY-ND-2.0",
|
||||
"CC-BY-ND-2.5",
|
||||
"CC-BY-ND-3.0",
|
||||
"CC-BY-ND-3.0-DE",
|
||||
"CC-BY-ND-4.0",
|
||||
"CC-BY-SA-1.0",
|
||||
"CC-BY-SA-2.0",
|
||||
"CC-BY-SA-2.0-UK",
|
||||
"CC-BY-SA-2.1-JP",
|
||||
"CC-BY-SA-2.5",
|
||||
"CC-BY-SA-3.0",
|
||||
"CC-BY-SA-3.0-AT",
|
||||
"CC-BY-SA-3.0-DE",
|
||||
"CC-BY-SA-4.0",
|
||||
"CC-PDDC",
|
||||
"CC0-1.0",
|
||||
"CDDL-1.0",
|
||||
"CDDL-1.1",
|
||||
"CDL-1.0",
|
||||
"CDLA-Permissive-1.0",
|
||||
"CDLA-Permissive-2.0",
|
||||
"CDLA-Sharing-1.0",
|
||||
"CECILL-1.0",
|
||||
"CECILL-1.1",
|
||||
"CECILL-2.0",
|
||||
"CECILL-2.1",
|
||||
"CECILL-B",
|
||||
"CECILL-C",
|
||||
"CERN-OHL-1.1",
|
||||
"CERN-OHL-1.2",
|
||||
"CERN-OHL-P-2.0",
|
||||
"CERN-OHL-S-2.0",
|
||||
"CERN-OHL-W-2.0",
|
||||
"ClArtistic",
|
||||
"CNRI-Jython",
|
||||
"CNRI-Python",
|
||||
"CNRI-Python-GPL-Compatible",
|
||||
"Condor-1.1",
|
||||
"copyleft-next-0.3.0",
|
||||
"copyleft-next-0.3.1",
|
||||
"CPAL-1.0",
|
||||
"CPL-1.0",
|
||||
"CPOL-1.02",
|
||||
"Crossword",
|
||||
"CrystalStacker",
|
||||
"CUA-OPL-1.0",
|
||||
"Cube",
|
||||
"curl",
|
||||
"D-FSL-1.0",
|
||||
"diffmark",
|
||||
"DOC",
|
||||
"Dotseqn",
|
||||
"DRL-1.0",
|
||||
"DSDP",
|
||||
"dvipdfm",
|
||||
"ECL-1.0",
|
||||
"ECL-2.0",
|
||||
"eCos-2.0",
|
||||
"EFL-1.0",
|
||||
"EFL-2.0",
|
||||
"eGenix",
|
||||
"Entessa",
|
||||
"EPICS",
|
||||
"EPL-1.0",
|
||||
"EPL-2.0",
|
||||
"ErlPL-1.1",
|
||||
"etalab-2.0",
|
||||
"EUDatagrid",
|
||||
"EUPL-1.0",
|
||||
"EUPL-1.1",
|
||||
"EUPL-1.2",
|
||||
"Eurosym",
|
||||
"Fair",
|
||||
"Frameworx-1.0",
|
||||
"FreeBSD-DOC",
|
||||
"FreeImage",
|
||||
"FSFAP",
|
||||
"FSFUL",
|
||||
"FSFULLR",
|
||||
"FTL",
|
||||
"GD",
|
||||
"GFDL-1.1",
|
||||
"GFDL-1.1-invariants-only",
|
||||
"GFDL-1.1-invariants-or-later",
|
||||
"GFDL-1.1-no-invariants-only",
|
||||
"GFDL-1.1-no-invariants-or-later",
|
||||
"GFDL-1.1-only",
|
||||
"GFDL-1.1-or-later",
|
||||
"GFDL-1.2",
|
||||
"GFDL-1.2-invariants-only",
|
||||
"GFDL-1.2-invariants-or-later",
|
||||
"GFDL-1.2-no-invariants-only",
|
||||
"GFDL-1.2-no-invariants-or-later",
|
||||
"GFDL-1.2-only",
|
||||
"GFDL-1.2-or-later",
|
||||
"GFDL-1.3",
|
||||
"GFDL-1.3-invariants-only",
|
||||
"GFDL-1.3-invariants-or-later",
|
||||
"GFDL-1.3-no-invariants-only",
|
||||
"GFDL-1.3-no-invariants-or-later",
|
||||
"GFDL-1.3-only",
|
||||
"GFDL-1.3-or-later",
|
||||
"Giftware",
|
||||
"GL2PS",
|
||||
"Glide",
|
||||
"Glulxe",
|
||||
"GLWTPL",
|
||||
"gnuplot",
|
||||
"GPL-1.0",
|
||||
"GPL-1.0-only",
|
||||
"GPL-1.0-or-later",
|
||||
"GPL-1.0+",
|
||||
"GPL-2.0",
|
||||
"GPL-2.0-only",
|
||||
"GPL-2.0-or-later",
|
||||
"GPL-2.0-with-autoconf-exception",
|
||||
"GPL-2.0-with-bison-exception",
|
||||
"GPL-2.0-with-classpath-exception",
|
||||
"GPL-2.0-with-font-exception",
|
||||
"GPL-2.0-with-GCC-exception",
|
||||
"GPL-2.0+",
|
||||
"GPL-3.0",
|
||||
"GPL-3.0-only",
|
||||
"GPL-3.0-or-later",
|
||||
"GPL-3.0-with-autoconf-exception",
|
||||
"GPL-3.0-with-GCC-exception",
|
||||
"GPL-3.0+",
|
||||
"gSOAP-1.3b",
|
||||
"HaskellReport",
|
||||
"Hippocratic-2.1",
|
||||
"HPND",
|
||||
"HPND-sell-variant",
|
||||
"HTMLTIDY",
|
||||
"IBM-pibs",
|
||||
"ICU",
|
||||
"IJG",
|
||||
"ImageMagick",
|
||||
"iMatix",
|
||||
"Imlib2",
|
||||
"Info-ZIP",
|
||||
"Intel",
|
||||
"Intel-ACPI",
|
||||
"Interbase-1.0",
|
||||
"IPA",
|
||||
"IPL-1.0",
|
||||
"ISC",
|
||||
"JasPer-2.0",
|
||||
"JPNIC",
|
||||
"JSON",
|
||||
"LAL-1.2",
|
||||
"LAL-1.3",
|
||||
"Latex2e",
|
||||
"Leptonica",
|
||||
"LGPL-2.0",
|
||||
"LGPL-2.0-only",
|
||||
"LGPL-2.0-or-later",
|
||||
"LGPL-2.0+",
|
||||
"LGPL-2.1",
|
||||
"LGPL-2.1-only",
|
||||
"LGPL-2.1-or-later",
|
||||
"LGPL-2.1+",
|
||||
"LGPL-3.0",
|
||||
"LGPL-3.0-only",
|
||||
"LGPL-3.0-or-later",
|
||||
"LGPL-3.0+",
|
||||
"LGPLLR",
|
||||
"Libpng",
|
||||
"libpng-2.0",
|
||||
"libselinux-1.0",
|
||||
"libtiff",
|
||||
"LiLiQ-P-1.1",
|
||||
"LiLiQ-R-1.1",
|
||||
"LiLiQ-Rplus-1.1",
|
||||
"Linux-OpenIB",
|
||||
"LPL-1.0",
|
||||
"LPL-1.02",
|
||||
"LPPL-1.0",
|
||||
"LPPL-1.1",
|
||||
"LPPL-1.2",
|
||||
"LPPL-1.3a",
|
||||
"LPPL-1.3c",
|
||||
"MakeIndex",
|
||||
"MirOS",
|
||||
"MIT",
|
||||
"MIT-0",
|
||||
"MIT-advertising",
|
||||
"MIT-CMU",
|
||||
"MIT-enna",
|
||||
"MIT-feh",
|
||||
"MIT-Modern-Variant",
|
||||
"MIT-open-group",
|
||||
"MITNFA",
|
||||
"Motosoto",
|
||||
"mpich2",
|
||||
"MPL-1.0",
|
||||
"MPL-1.1",
|
||||
"MPL-2.0",
|
||||
"MPL-2.0-no-copyleft-exception",
|
||||
"MS-PL",
|
||||
"MS-RL",
|
||||
"MTLL",
|
||||
"MulanPSL-1.0",
|
||||
"MulanPSL-2.0",
|
||||
"Multics",
|
||||
"Mup",
|
||||
"NAIST-2003",
|
||||
"NASA-1.3",
|
||||
"Naumen",
|
||||
"NBPL-1.0",
|
||||
"NCGL-UK-2.0",
|
||||
"NCSA",
|
||||
"Net-SNMP",
|
||||
"NetCDF",
|
||||
"Newsletr",
|
||||
"NGPL",
|
||||
"NIST-PD",
|
||||
"NIST-PD-fallback",
|
||||
"NLOD-1.0",
|
||||
"NLOD-2.0",
|
||||
"NLPL",
|
||||
"Nokia",
|
||||
"NOSL",
|
||||
"Noweb",
|
||||
"NPL-1.0",
|
||||
"NPL-1.1",
|
||||
"NPOSL-3.0",
|
||||
"NRL",
|
||||
"NTP",
|
||||
"NTP-0",
|
||||
"Nunit",
|
||||
"O-UDA-1.0",
|
||||
"OCCT-PL",
|
||||
"OCLC-2.0",
|
||||
"ODbL-1.0",
|
||||
"ODC-By-1.0",
|
||||
"OFL-1.0",
|
||||
"OFL-1.0-no-RFN",
|
||||
"OFL-1.0-RFN",
|
||||
"OFL-1.1",
|
||||
"OFL-1.1-no-RFN",
|
||||
"OFL-1.1-RFN",
|
||||
"OGC-1.0",
|
||||
"OGDL-Taiwan-1.0",
|
||||
"OGL-Canada-2.0",
|
||||
"OGL-UK-1.0",
|
||||
"OGL-UK-2.0",
|
||||
"OGL-UK-3.0",
|
||||
"OGTSL",
|
||||
"OLDAP-1.1",
|
||||
"OLDAP-1.2",
|
||||
"OLDAP-1.3",
|
||||
"OLDAP-1.4",
|
||||
"OLDAP-2.0",
|
||||
"OLDAP-2.0.1",
|
||||
"OLDAP-2.1",
|
||||
"OLDAP-2.2",
|
||||
"OLDAP-2.2.1",
|
||||
"OLDAP-2.2.2",
|
||||
"OLDAP-2.3",
|
||||
"OLDAP-2.4",
|
||||
"OLDAP-2.5",
|
||||
"OLDAP-2.6",
|
||||
"OLDAP-2.7",
|
||||
"OLDAP-2.8",
|
||||
"OML",
|
||||
"OpenSSL",
|
||||
"OPL-1.0",
|
||||
"OPUBL-1.0",
|
||||
"OSET-PL-2.1",
|
||||
"OSL-1.0",
|
||||
"OSL-1.1",
|
||||
"OSL-2.0",
|
||||
"OSL-2.1",
|
||||
"OSL-3.0",
|
||||
"Parity-6.0.0",
|
||||
"Parity-7.0.0",
|
||||
"PDDL-1.0",
|
||||
"PHP-3.0",
|
||||
"PHP-3.01",
|
||||
"Plexus",
|
||||
"PolyForm-Noncommercial-1.0.0",
|
||||
"PolyForm-Small-Business-1.0.0",
|
||||
"PostgreSQL",
|
||||
"PSF-2.0",
|
||||
"psfrag",
|
||||
"psutils",
|
||||
"Python-2.0",
|
||||
"Qhull",
|
||||
"QPL-1.0",
|
||||
"Rdisc",
|
||||
"RHeCos-1.1",
|
||||
"RPL-1.1",
|
||||
"RPL-1.5",
|
||||
"RPSL-1.0",
|
||||
"RSA-MD",
|
||||
"RSCPL",
|
||||
"Ruby",
|
||||
"SAX-PD",
|
||||
"Saxpath",
|
||||
"SCEA",
|
||||
"Sendmail",
|
||||
"Sendmail-8.23",
|
||||
"SGI-B-1.0",
|
||||
"SGI-B-1.1",
|
||||
"SGI-B-2.0",
|
||||
"SHL-0.5",
|
||||
"SHL-0.51",
|
||||
"SimPL-2.0",
|
||||
"SISSL",
|
||||
"SISSL-1.2",
|
||||
"Sleepycat",
|
||||
"SMLNJ",
|
||||
"SMPPL",
|
||||
"SNIA",
|
||||
"Spencer-86",
|
||||
"Spencer-94",
|
||||
"Spencer-99",
|
||||
"SPL-1.0",
|
||||
"SSH-OpenSSH",
|
||||
"SSH-short",
|
||||
"SSPL-1.0",
|
||||
"StandardML-NJ",
|
||||
"SugarCRM-1.1.3",
|
||||
"SWL",
|
||||
"TAPR-OHL-1.0",
|
||||
"TCL",
|
||||
"TCP-wrappers",
|
||||
"TMate",
|
||||
"TORQUE-1.1",
|
||||
"TOSL",
|
||||
"TU-Berlin-1.0",
|
||||
"TU-Berlin-2.0",
|
||||
"UCL-1.0",
|
||||
"Unicode-DFS-2015",
|
||||
"Unicode-DFS-2016",
|
||||
"Unicode-TOU",
|
||||
"Unlicense",
|
||||
"UPL-1.0",
|
||||
"Verbatim-man-pages",
|
||||
"Vim",
|
||||
"VOSTROM",
|
||||
"VSL-1.0",
|
||||
"W3C",
|
||||
"W3C-19980720",
|
||||
"W3C-20150513",
|
||||
"Watcom-1.0",
|
||||
"Wsuipa",
|
||||
"WTFPL",
|
||||
"wxWindows",
|
||||
"X11",
|
||||
"Xerox",
|
||||
"XFree86-1.1",
|
||||
"xinetd",
|
||||
"Xnet",
|
||||
"xpp",
|
||||
"XSkat",
|
||||
"YPL-1.0",
|
||||
"YPL-1.1",
|
||||
"Zed",
|
||||
"Zend-2.0",
|
||||
"Zimbra-1.3",
|
||||
"Zimbra-1.4",
|
||||
"Zlib",
|
||||
"zlib-acknowledgement",
|
||||
"ZPL-1.1",
|
||||
"ZPL-2.0",
|
||||
"ZPL-2.1",
|
||||
|
|
Загрузка…
Ссылка в новой задаче