Skip to content

Commit

Permalink
Accept arbitrary version formats in overrides. (#1329)
Browse files Browse the repository at this point in the history
* Accept arbitrary version formats in overrides.

We accidentally implemented the overrides deserializer to reject non-relaxed-versions in "overrides", despite the original intent that overrides are scheme-less. Note how the original schema:

#1209

, and original documentation:

microsoft/vcpkg-docs#159

said everything should be accepted here.

Also fix our example printing when we're asking users to add overrides to ensure it is valid JSON.

* Implement preferring putting the port-version into the version text.

* Rename GenericVersionDeserializer to BaselineVersionTagDeserializer.
  • Loading branch information
BillyONeal authored Mar 1, 2024
1 parent 96bf7ef commit c05f470
Show file tree
Hide file tree
Showing 15 changed files with 449 additions and 251 deletions.
11 changes: 6 additions & 5 deletions docs/vcpkg-schema-definitions.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -763,26 +763,27 @@
"$ref": "#/definitions/identifier"
},
"version-string": {
"description": "Text used to identify an arbitrary version",
"description": "Deprecated in favor of 'version' in overrides. Text used to identify an arbitrary version",
"type": "string",
"pattern": "^[^#]+(#\\d+)?$"
},
"version": {
"description": "A relaxed version string (1.2.3.4...)",
"description": "Text used to identify the overridden version.",
"type": "string",
"pattern": "^\\d+(\\.\\d+)*(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?(#\\d+)?$"
"pattern": "^[^#]+(#\\d+)?$"
},
"version-date": {
"description": "A date version string (e.g. 2020-01-20)",
"description": "Deprecated in favor of 'version' in overrides. A date version string (e.g. 2020-01-20).",
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}(\\.\\d+)*(#\\d+)?$"
},
"version-semver": {
"description": "A semantic version string. See https://semver.org/",
"description": "Deprecated in favor of 'version' in overrides. A semantic version string. See https://semver.org/",
"type": "string",
"pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?(#\\d+)?$"
},
"port-version": {
"description": "Deprecated in favor of being a part of 'version' in overrides. Specifies the port-version portion of the version. Overrides the value in one of the other version fields.",
"$ref": "#/definitions/port-version"
}
},
Expand Down
2 changes: 1 addition & 1 deletion include/vcpkg-test/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,5 +199,5 @@ namespace vcpkg::Test
#define REQUIRE_LINES(a, b) \
do \
{ \
if (auto delta = ::vcpkg::Test::diff_lines((a), (b))) FAIL(*delta.get()); \
if (auto delta = ::vcpkg::Test::diff_lines((b), (a))) FAIL(*delta.get()); \
} while (0)
5 changes: 5 additions & 0 deletions include/vcpkg/base/json.h
Original file line number Diff line number Diff line change
Expand Up @@ -339,5 +339,10 @@ namespace vcpkg::Json
std::string stringify(const Array&);
std::string stringify(const Array&, JsonStyle style);

std::string stringify_object_member(StringLiteral member_name,
const Array& arr,
JsonStyle style,
int initial_indent);

uint64_t get_json_parsing_stats();
}
6 changes: 5 additions & 1 deletion include/vcpkg/sourceparagraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <vcpkg/base/json.h>
#include <vcpkg/base/path.h>
#include <vcpkg/base/stringview.h>

#include <vcpkg/paragraphparser.h>
#include <vcpkg/platform-expression.h>
Expand Down Expand Up @@ -70,14 +71,15 @@ namespace vcpkg
{
std::string name;
Version version;
VersionScheme scheme;

Json::Object extra_info;

friend bool operator==(const DependencyOverride& lhs, const DependencyOverride& rhs);
friend bool operator!=(const DependencyOverride& lhs, const DependencyOverride& rhs) { return !(lhs == rhs); }
};

void serialize_dependency_override(Json::Array& arr, const DependencyOverride& dep);

std::vector<FullPackageSpec> filter_dependencies(const std::vector<Dependency>& deps,
Triplet t,
Triplet host,
Expand Down Expand Up @@ -224,4 +226,6 @@ namespace vcpkg
ExpectedL<std::vector<Dependency>> parse_dependencies_list(const std::string& str,
StringView origin,
TextRowCol textrowcol = {});

constexpr StringLiteral OVERRIDES = "overrides";
}
35 changes: 21 additions & 14 deletions include/vcpkg/versiondeserializers.h
Original file line number Diff line number Diff line change
@@ -1,33 +1,40 @@
#pragma once

#include <vcpkg/base/fwd/messages.h>
#include <vcpkg/base/fwd/stringview.h>

#include <vcpkg/fwd/versions.h>

#include <vcpkg/base/jsonreader.h>
#include <vcpkg/base/stringview.h>

namespace vcpkg
{
const Json::IDeserializer<Version>& get_version_deserializer_instance();
const Json::IDeserializer<Version>& get_versiontag_deserializer_instance();

Optional<SchemedVersion> visit_optional_schemed_deserializer(const LocalizedString& parent_type,
Json::Reader& r,
const Json::Object& obj,
bool allow_hash_portversion);

SchemedVersion visit_required_schemed_deserializer(const LocalizedString& parent_type,
Json::Reader& r,
const Json::Object& obj,
bool allow_hash_portversion = false);
extern const StringLiteral VERSION_RELAXED;
extern const StringLiteral VERSION_SEMVER;
extern const StringLiteral VERSION_STRING;
extern const StringLiteral VERSION_DATE;

extern const Json::IDeserializer<Version>& baseline_version_tag_deserializer;

Optional<SchemedVersion> visit_optional_schemed_version(const LocalizedString& parent_type,
Json::Reader& r,
const Json::Object& obj);

SchemedVersion visit_required_schemed_version(const LocalizedString& parent_type,
Json::Reader& r,
const Json::Object& obj);

Version visit_version_override_version(const LocalizedString& parent_type,
Json::Reader& r,
const Json::Object& obj);

View<StringView> schemed_deserializer_fields();

void serialize_schemed_version(Json::Object& out_obj, VersionScheme scheme, const Version& version);

struct VersionConstraintStringDeserializer : Json::StringDeserializer
{
LocalizedString type_name() const;
virtual LocalizedString type_name() const override;

static const VersionConstraintStringDeserializer instance;
};
Expand Down
6 changes: 6 additions & 0 deletions include/vcpkg/versions.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ namespace vcpkg
VersionScheme scheme;
Version version;

SchemedVersion() noexcept;
SchemedVersion(VersionScheme scheme, Version&& version) noexcept;
SchemedVersion(VersionScheme scheme, const Version& version);
SchemedVersion(VersionScheme scheme, std::string&& value, int port_version) noexcept;
SchemedVersion(VersionScheme scheme, StringView value, int port_version);

friend bool operator==(const SchemedVersion& lhs, const SchemedVersion& rhs);
friend bool operator!=(const SchemedVersion& lhs, const SchemedVersion& rhs);
};
Expand Down
77 changes: 40 additions & 37 deletions src/vcpkg-test/dependencies.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -441,11 +441,11 @@ TEST_CASE ("version string baseline agree", "[versionplan]")
TEST_CASE ("version install scheme baseline conflict", "[versionplan]")
{
MockBaselineProvider bp;
bp.v["a"] = {"2", 0};
bp.v["a"] = {"2with\"quotes", 0};

MockVersionedPortfileProvider vp;
vp.emplace("a", {"1", 0});
vp.emplace("a", {"2", 0});
vp.emplace("a", {"2with\"quotes", 0});
vp.emplace("a", {"3", 0});

MockCMakeVarProvider var_provider;
Expand All @@ -463,16 +463,17 @@ TEST_CASE ("version install scheme baseline conflict", "[versionplan]")
REQUIRE(!install_plan.has_value());
REQUIRE_LINES(
install_plan.error(),
R"(error: version conflict on a:x86-windows: toplevel-spec required 3, which cannot be compared with the baseline version 2.
R"(error: version conflict on a:x86-windows: toplevel-spec required 3, which cannot be compared with the baseline version 2with"quotes.
Both versions have scheme string but different primary text.
This can be resolved by adding an explicit override to the preferred version. For example:
"overrides": [
{ "name": "a", "version": "2" }
{
"name": "a",
"version": "2with\"quotes"
}
]
See `vcpkg help versioning` or https://learn.microsoft.com/vcpkg/users/versioning for more information.)");
}

Expand Down Expand Up @@ -1106,11 +1107,12 @@ The versions have incomparable schemes:
[email protected] has scheme string
This can be resolved by adding an explicit override to the preferred version. For example:
"overrides": [
{ "name": "a", "version": "1.0.0" }
{
"name": "a",
"version": "1.0.0"
}
]
See `vcpkg help versioning` or https://learn.microsoft.com/vcpkg/users/versioning for more information.)");
}
SECTION ("higher baseline")
Expand All @@ -1136,11 +1138,12 @@ The versions have incomparable schemes:
[email protected] has scheme string
This can be resolved by adding an explicit override to the preferred version. For example:
"overrides": [
{ "name": "a", "version": "1.0.2" }
{
"name": "a",
"version": "1.0.2"
}
]
See `vcpkg help versioning` or https://learn.microsoft.com/vcpkg/users/versioning for more information.)");
}
}
Expand Down Expand Up @@ -1228,11 +1231,12 @@ The versions have incomparable schemes:
b@1#1 has scheme relaxed
This can be resolved by adding an explicit override to the preferred version. For example:
"overrides": [
{ "name": "b", "version": "1" }
{
"name": "b",
"version": "1"
}
]
See `vcpkg help versioning` or https://learn.microsoft.com/vcpkg/users/versioning for more information.)");
}
SECTION ("lower baseline")
Expand Down Expand Up @@ -1553,8 +1557,8 @@ TEST_CASE ("version install overrides", "[versionplan]")
bp.v["b"] = {"2", 0};
bp.v["c"] = {"2", 0};

DependencyOverride bdo{"b", Version{"1", 0}, VersionScheme::String};
DependencyOverride cdo{"c", Version{"1", 0}, VersionScheme::String};
DependencyOverride bdo{"b", Version{"1", 0}};
DependencyOverride cdo{"c", Version{"1", 0}};
SECTION ("string")
{
auto install_plan =
Expand Down Expand Up @@ -1593,8 +1597,8 @@ TEST_CASE ("version install transitive overrides", "[versionplan]")
bp.v["b"] = {"2", 0};
bp.v["c"] = {"2", 1};

DependencyOverride bdo{"b", Version{"1", 0}, VersionScheme::String};
DependencyOverride cdo{"c", Version{"1", 0}, VersionScheme::String};
DependencyOverride bdo{"b", Version{"1", 0}};
DependencyOverride cdo{"c", Version{"1", 0}};
WITH_EXPECTED(install_plan,
create_versioned_install_plan(vp, bp, var_provider, {Dependency{"b"}}, {bdo, cdo}, toplevel_spec()));

Expand Down Expand Up @@ -2143,7 +2147,7 @@ TEST_CASE ("version overlay ports", "[versionplan]")
Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, Version{"1", 1}}},
},
{
DependencyOverride{"a", Version{"2", 0}, VersionScheme::String},
DependencyOverride{"a", Version{"2", 0}},
},
toplevel_spec())
.value_or_exit(VCPKG_LINE_INFO);
Expand All @@ -2153,19 +2157,18 @@ TEST_CASE ("version overlay ports", "[versionplan]")
}
SECTION ("override")
{
auto install_plan =
create_versioned_install_plan(vp,
bp,
oprovider,
var_provider,
{
Dependency{"a"},
},
{
DependencyOverride{"a", Version{"2", 0}, VersionScheme::String},
},
toplevel_spec())
.value_or_exit(VCPKG_LINE_INFO);
auto install_plan = create_versioned_install_plan(vp,
bp,
oprovider,
var_provider,
{
Dependency{"a"},
},
{
DependencyOverride{"a", Version{"2", 0}},
},
toplevel_spec())
.value_or_exit(VCPKG_LINE_INFO);

REQUIRE(install_plan.size() == 1);
check_name_and_version(install_plan.install_actions[0], "a", {"overlay", 0});
Expand Down Expand Up @@ -2199,7 +2202,7 @@ TEST_CASE ("respect supports expression", "[versionplan]")
oprovider,
var_provider,
{Dependency{"a"}},
{DependencyOverride{"a", Version{"1", 1}, VersionScheme::String}},
{DependencyOverride{"a", Version{"1", 1}}},
toplevel_spec());
CHECK(install_plan.has_value());
// override from supported to non supported version
Expand All @@ -2209,7 +2212,7 @@ TEST_CASE ("respect supports expression", "[versionplan]")
oprovider,
var_provider,
{Dependency{"a"}},
{DependencyOverride{"a", Version{"1", 0}, VersionScheme::String}},
{DependencyOverride{"a", Version{"1", 0}}},
toplevel_spec());
CHECK_FALSE(install_plan.has_value());
}
Expand Down Expand Up @@ -2247,7 +2250,7 @@ TEST_CASE ("respect supports expressions of features", "[versionplan]")
oprovider,
var_provider,
{Dependency{"a", {{"x"}}}},
{DependencyOverride{"a", Version{"1", 1}, VersionScheme::String}},
{DependencyOverride{"a", Version{"1", 1}}},
toplevel_spec());
CHECK(install_plan.has_value());
// override from supported to non supported version
Expand All @@ -2257,7 +2260,7 @@ TEST_CASE ("respect supports expressions of features", "[versionplan]")
oprovider,
var_provider,
{Dependency{"a", {{"x"}}}},
{DependencyOverride{"a", Version{"1", 0}, VersionScheme::String}},
{DependencyOverride{"a", Version{"1", 0}}},
toplevel_spec());
CHECK_FALSE(install_plan.has_value());
}
Expand Down
Loading

0 comments on commit c05f470

Please sign in to comment.