mirror of
https://github.com/microsoft/vcpkg.git
synced 2024-12-27 02:11:58 +08:00
[vcpkg] Add initial versioning documentation (#15565)
* [vcpkg] Improve efficiency and tests of versioning * [vcpkg] Add initial versioning documentation and rename x-default-baseline to builtin-baseline * [vcpkg] Enable metrics for builtin-baseline & overrides * [vcpkg] Address PR comments * [vcpkg] Add support for syntax in version>= * [vcpkg] Remove port-version from dependency syntax * [vcpkg] Address CR comment * [vcpkg] Minor docs fixup
This commit is contained in:
parent
a8e97d4a4b
commit
4f8fb510ba
@ -64,6 +64,12 @@ Additionally, the `"port-version"` field is used by registries of packages,
|
||||
as a way to version "the package gotten from `vcpkg install`" differently from the upstream package version.
|
||||
You shouldn't need to worry about this at all.
|
||||
|
||||
#### Additional version fields
|
||||
|
||||
**Experimental behind the `versions` feature flag**
|
||||
|
||||
See [versioning.md](versioning.md#version%20schemes) for additional version types.
|
||||
|
||||
### `"description"`
|
||||
|
||||
This is where you describe your project. Give it a good description to help in searching for it!
|
||||
@ -71,6 +77,14 @@ This can be a single string, or it can be an array of strings;
|
||||
in the latter case, the first string is treated as a summary,
|
||||
while the remaining strings are treated as the full description.
|
||||
|
||||
### `"builtin-baseline"`
|
||||
|
||||
**Experimental behind the `versions` feature flag**
|
||||
|
||||
This field indicates the commit of vcpkg which provides global minimum version information for your manifest. It is required for top-level manifest files using versioning.
|
||||
|
||||
See also [versioning](versioning.md#builtin-baseline) for more semantic details.
|
||||
|
||||
### `"dependencies"`
|
||||
|
||||
This field lists all the dependencies you'll need to build your library (as well as any your dependents might need,
|
||||
@ -131,6 +145,16 @@ The common identifiers are:
|
||||
|
||||
although one can define their own.
|
||||
|
||||
#### `"version>="`
|
||||
|
||||
**Experimental behind the `versions` feature flag**
|
||||
|
||||
A minimum version constraint on the dependency.
|
||||
|
||||
This field specifies the minimum version of the dependency using a '#' suffix to denote port-version if non-zero.
|
||||
|
||||
See also [versioning](versioning.md#constraints) for more semantic details.
|
||||
|
||||
#### Example:
|
||||
|
||||
```json
|
||||
@ -151,6 +175,26 @@ although one can define their own.
|
||||
}
|
||||
```
|
||||
|
||||
### `"overrides"`
|
||||
|
||||
**Experimental behind the `versions` feature flag**
|
||||
|
||||
This field enables version resolution to be ignored for certain dependencies and to use specific versions instead.
|
||||
|
||||
See also [versioning](versioning.md#overrides) for more semantic details.
|
||||
|
||||
#### Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"overrides": [
|
||||
{
|
||||
"name": "arrow", "version": "1.2.3", "port-version": 7
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `"supports"`
|
||||
|
||||
If your project doesn't support common platforms, you can tell your users this with the `"supports"` field.
|
||||
@ -180,8 +224,9 @@ and that's the `"default-features"` field, which is an array of feature names.
|
||||
"name": "libdb",
|
||||
"description": [
|
||||
"An example database library.",
|
||||
"Optionally uses one of CBOR, JSON, or CSV as a backend."
|
||||
"Optionally can build with CBOR, JSON, or CSV as backends."
|
||||
],
|
||||
"$default-features-explanation": "Users using this library transitively will get all backends automatically",
|
||||
"default-features": [ "cbor", "csv", "json" ],
|
||||
"features": {
|
||||
"cbor": {
|
||||
@ -189,8 +234,7 @@ and that's the `"default-features"` field, which is an array of feature names.
|
||||
"dependencies": [
|
||||
{
|
||||
"$explanation": [
|
||||
"This is currently how you tell vcpkg that the cbor feature depends on the json feature of this package",
|
||||
"We're looking into making this easier"
|
||||
"This is how you tell vcpkg that the cbor feature depends on the json feature of this package"
|
||||
],
|
||||
"name": "libdb",
|
||||
"default-features": false,
|
||||
|
85
docs/users/versioning.md
Normal file
85
docs/users/versioning.md
Normal file
@ -0,0 +1,85 @@
|
||||
# Versioning
|
||||
|
||||
**This feature is experimental and requires `--feature-flags=versions`**
|
||||
|
||||
Versioning allows you to deterministically control the precise revisions of dependencies used by
|
||||
your project from within your manifest file.
|
||||
|
||||
## Version schemes
|
||||
|
||||
### Schemes
|
||||
Versions in vcpkg come in four primary flavors:
|
||||
|
||||
#### version
|
||||
A dot-separated sequence of numbers (1.2.3.4)
|
||||
|
||||
#### version-date
|
||||
A date (2021-01-01.5)
|
||||
|
||||
#### version-semver
|
||||
A Semantic Version 2.0 (2.1.0-rc2)
|
||||
|
||||
See https://semver.org/ for a full specification.
|
||||
|
||||
#### version-string
|
||||
An exact, incomparable version (Vista)
|
||||
|
||||
### Port Versions
|
||||
Each version additionally has a "port-version" which is a nonnegative integer. When rendered as text, the
|
||||
port version (if nonzero) is added as a suffix to the primary version text separated by a hash (#).
|
||||
Port-versions are sorted lexographically after the primary version text, for example:
|
||||
|
||||
1.0.0 < 1.0.0#1 < 1.0.1 < 1.0.1#5 < 2.0.0
|
||||
|
||||
## Constraints
|
||||
|
||||
Manifests can place three kinds of constraints upon the versions used:
|
||||
|
||||
### builtin-baseline
|
||||
The baseline references a commit within the vcpkg repository that
|
||||
establishes a minimum version on every dependency in the graph. If
|
||||
no other constraints are specified (directly or transitively),
|
||||
then the version from the baseline of the top level manifest will
|
||||
be used.
|
||||
|
||||
You can get the current commit of your vcpkg instance either by adding an empty `"builtin-baseline"` field, installing, and examining the error message or by running `git rev-parse HEAD` in the root of the vcpkg instance.
|
||||
|
||||
Baselines provide stability and ease of development for top-level manifest files. They are not considered from ports consumed as a dependency. If a minimum version constraint is required during transitive version resolution, the port should use `version>=`.
|
||||
|
||||
### version>=
|
||||
Within the "dependencies" field, each dependency can have a
|
||||
minimum constraint listed. These minimum constraints will be used
|
||||
when transitively depending upon this library. A minimum
|
||||
port-version can additionally be specified with a '#' suffix.
|
||||
|
||||
This constraint must refer to an existing, valid version (including port-version).
|
||||
|
||||
### overrides
|
||||
When used as the top-level manifest (such as when running `vcpkg
|
||||
install` in the directory), overrides allow a manifest to
|
||||
short-circuit dependency resolution and specify exactly the
|
||||
version to use. These can be used to handle version conflicts,
|
||||
such as with `version-string` dependencies.
|
||||
|
||||
Overrides are not considered from ports consumed as a dependency.
|
||||
|
||||
## Example top-level manifest:
|
||||
```json
|
||||
{
|
||||
"name": "example",
|
||||
"version": "1.0",
|
||||
"builtin-baseline": "a14a6bcb27287e3ec138dba1b948a0cdbc337a3a",
|
||||
"dependencies": [
|
||||
{ "name": "zlib", "version>=": "1.2.11#8" },
|
||||
"rapidjson"
|
||||
],
|
||||
"overrides": [
|
||||
{ "name": "rapidjson", "version": "2020-09-14" }
|
||||
]
|
||||
}
|
||||
```
|
||||
See also the [manifest documentation](manifests.md) for more syntax information.
|
||||
|
||||
## Original Specification
|
||||
|
||||
See also the [original specification](https://github.com/vicroms/vcpkg/blob/versioning-spec/docs/specifications/versioning.md)
|
@ -14,12 +14,13 @@ Throw-IfNotFailed
|
||||
Run-Vcpkg install @builtinRegistryArgs --feature-flags=registries 'zlib'
|
||||
Throw-IfFailed
|
||||
|
||||
# Test git and filesystem registries
|
||||
Write-Trace "Test git and filesystem registries"
|
||||
Refresh-TestRoot
|
||||
$filesystemRegistry = "$TestingRoot/filesystem-registry"
|
||||
$gitRegistryUpstream = "$TestingRoot/git-registry-upstream"
|
||||
|
||||
# build a filesystem registry
|
||||
Write-Trace "build a filesystem registry"
|
||||
New-Item -Path $filesystemRegistry -ItemType Directory
|
||||
$filesystemRegistry = (Get-Item $filesystemRegistry).FullName
|
||||
|
||||
@ -51,6 +52,7 @@ New-Item `
|
||||
|
||||
|
||||
# build a git registry
|
||||
Write-Trace "build a git registry"
|
||||
New-Item -Path $gitRegistryUpstream -ItemType Directory
|
||||
$gitRegistryUpstream = (Get-Item $gitRegistryUpstream).FullName
|
||||
|
||||
@ -82,6 +84,7 @@ finally
|
||||
}
|
||||
|
||||
# actually test the registries
|
||||
Write-Trace "actually test the registries"
|
||||
$vcpkgJson = @{
|
||||
"name" = "manifest-test";
|
||||
"version-string" = "1.0.0";
|
||||
@ -90,37 +93,8 @@ $vcpkgJson = @{
|
||||
)
|
||||
}
|
||||
|
||||
$manifestDir = "$TestingRoot/builtin-registry-test-manifest-dir"
|
||||
|
||||
New-Item -Path $manifestDir -ItemType Directory
|
||||
$manifestDir = (Get-Item $manifestDir).FullName
|
||||
|
||||
Push-Location $manifestDir
|
||||
|
||||
try
|
||||
{
|
||||
$vcpkgJsonWithBaseline = $vcpkgJson.Clone()
|
||||
$vcpkgJsonWithBaseline['$x-default-baseline'] = 'default'
|
||||
|
||||
New-Item -Path 'vcpkg.json' -ItemType File `
|
||||
-Value (ConvertTo-Json -Depth 5 -InputObject $vcpkgJson)
|
||||
|
||||
Run-Vcpkg install @builtinRegistryArgs '--feature-flags=registries,manifests'
|
||||
Throw-IfNotFailed
|
||||
|
||||
New-Item -Path 'vcpkg.json' -ItemType File -Force `
|
||||
-Value (ConvertTo-Json -Depth 5 -InputObject $vcpkgJsonWithBaseline)
|
||||
|
||||
Run-Vcpkg install @builtinRegistryArgs '--feature-flags=registries,manifests'
|
||||
Throw-IfFailed
|
||||
}
|
||||
finally
|
||||
{
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
|
||||
# test the filesystem registry
|
||||
Write-Trace "test the filesystem registry"
|
||||
$manifestDir = "$TestingRoot/filesystem-registry-test-manifest-dir"
|
||||
|
||||
New-Item -Path $manifestDir -ItemType Directory
|
||||
@ -154,6 +128,7 @@ finally
|
||||
}
|
||||
|
||||
# test the git registry
|
||||
Write-Trace "test the git registry"
|
||||
$manifestDir = "$TestingRoot/git-registry-test-manifest-dir"
|
||||
|
||||
New-Item -Path $manifestDir -ItemType Directory
|
||||
|
@ -59,17 +59,40 @@ Throw-IfFailed
|
||||
Throw-IfFailed
|
||||
|
||||
$CurrentTest = "default baseline"
|
||||
$out = ./vcpkg $commonArgs "--feature-flags=versions" install --x-manifest-root=scripts/testing/version-files/default-baseline-1
|
||||
$out = ./vcpkg $commonArgs "--feature-flags=versions" install --x-manifest-root=scripts/testing/version-files/default-baseline-1 2>&1 | Out-String
|
||||
Throw-IfNotFailed
|
||||
# if ($out -notmatch "Error: while checking out baseline" -or $out -notmatch " does not exist in ")
|
||||
# {
|
||||
# $out
|
||||
# throw "Expected to fail due to missing baseline"
|
||||
# }
|
||||
if ($out -notmatch ".*Error: while checking out baseline.*")
|
||||
{
|
||||
$out
|
||||
throw "Expected to fail due to missing baseline"
|
||||
}
|
||||
|
||||
git fetch https://github.com/vicroms/test-registries
|
||||
$CurrentTest = "default baseline"
|
||||
./vcpkg $commonArgs --debug "--feature-flags=versions" install `
|
||||
"--x-manifest-root=scripts/testing/version-files/default-baseline-2" `
|
||||
"--x-builtin-port-versions-dir=scripts/testing/version-files/default-baseline-2/port_versions"
|
||||
Throw-IfFailed
|
||||
foreach ($opt_registries in @("",",registries"))
|
||||
{
|
||||
Write-Trace "testing baselines: $opt_registries"
|
||||
Refresh-TestRoot
|
||||
$CurrentTest = "without default baseline 2 -- enabling versions should not change behavior"
|
||||
Remove-Item -Recurse $buildtreesRoot/versioning -ErrorAction SilentlyContinue
|
||||
./vcpkg $commonArgs "--feature-flags=versions$opt_registries" install `
|
||||
"--dry-run" `
|
||||
"--x-manifest-root=scripts/testing/version-files/without-default-baseline-2" `
|
||||
"--x-builtin-port-versions-dir=scripts/testing/version-files/default-baseline-2/port_versions"
|
||||
Throw-IfFailed
|
||||
Require-FileNotExists $buildtreesRoot/versioning
|
||||
|
||||
$CurrentTest = "default baseline 2"
|
||||
./vcpkg $commonArgs "--feature-flags=versions$opt_registries" install `
|
||||
"--dry-run" `
|
||||
"--x-manifest-root=scripts/testing/version-files/default-baseline-2" `
|
||||
"--x-builtin-port-versions-dir=scripts/testing/version-files/default-baseline-2/port_versions"
|
||||
Throw-IfFailed
|
||||
Require-FileExists $buildtreesRoot/versioning
|
||||
|
||||
$CurrentTest = "using version features fails without flag"
|
||||
./vcpkg $commonArgs "--feature-flags=-versions$opt_registries" install `
|
||||
"--dry-run" `
|
||||
"--x-manifest-root=scripts/testing/version-files/default-baseline-2" `
|
||||
"--x-builtin-port-versions-dir=scripts/testing/version-files/default-baseline-2/port_versions"
|
||||
Throw-IfNotFailed
|
||||
}
|
@ -63,6 +63,10 @@ function Throw-IfNotFailed {
|
||||
}
|
||||
}
|
||||
|
||||
function Write-Trace ([string]$text) {
|
||||
Write-Host (@($MyInvocation.ScriptName, ":", $MyInvocation.ScriptLineNumber, ": ", $text) -join "")
|
||||
}
|
||||
|
||||
function Run-Vcpkg {
|
||||
Param(
|
||||
[Parameter(ValueFromRemainingArguments)]
|
||||
|
@ -35,7 +35,7 @@ def generate_port_versions_file(port_name):
|
||||
env = os.environ.copy()
|
||||
env['GIT_OPTIONAL_LOCKS'] = '0'
|
||||
output = subprocess.run(
|
||||
[os.path.join(SCRIPT_DIRECTORY, '../vcpkg.exe'),
|
||||
[os.path.join(SCRIPT_DIRECTORY, '../vcpkg'),
|
||||
'x-history', port_name, '--x-json', f'--output={output_file_path}'],
|
||||
capture_output=True, encoding='utf-8', env=env)
|
||||
if output.returncode != 0:
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "default-baseline-test",
|
||||
"version-string": "0",
|
||||
"$x-default-baseline": "fca18ba3572f8aebe3b8158c359db62a7e26134e",
|
||||
"builtin-baseline": "fca18ba3572f8aebe3b8158c359db62a7e26134e",
|
||||
"dependencies": [
|
||||
"zlib"
|
||||
]
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "default-baseline-test",
|
||||
"name": "default-baseline-test-2",
|
||||
"version-string": "0",
|
||||
"$x-default-baseline": "16002d9c2318dec4c69e02d9af8c0e11dca0d4c6",
|
||||
"builtin-baseline": "16002d9c2318dec4c69e02d9af8c0e11dca0d4c6",
|
||||
"dependencies": [
|
||||
"zlib"
|
||||
]
|
||||
|
@ -0,0 +1,14 @@
|
||||
{
|
||||
"versions": [
|
||||
{
|
||||
"git-tree": "7bb2b2f3783303a4dd41163553fe4cc103dc9262",
|
||||
"version-string": "1.2.11",
|
||||
"port-version": 9
|
||||
},
|
||||
{
|
||||
"git-tree": "4927735fa9baca564ebddf6e6880de344b20d7a8",
|
||||
"version-string": "1.2.11",
|
||||
"port-version": 8
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "without-default-baseline-test-2",
|
||||
"version-string": "0",
|
||||
"dependencies": [
|
||||
"zlib"
|
||||
]
|
||||
}
|
@ -136,12 +136,9 @@
|
||||
"$ref": "#/definitions/platform-expression"
|
||||
},
|
||||
"version>=": {
|
||||
"description": "Minimum required port version",
|
||||
"$ref": "#/definitions/version-text"
|
||||
},
|
||||
"port-version": {
|
||||
"description": "Minimum port revision (defaults to 0)",
|
||||
"$ref": "#/definitions/port-version"
|
||||
"description": "Minimum required version",
|
||||
"type": "string",
|
||||
"pattern": "^[^#]+(#\\d+)?$"
|
||||
}
|
||||
},
|
||||
"patternProperties": {
|
||||
@ -256,6 +253,10 @@
|
||||
"description": "An SPDX license expression at version 3.9.",
|
||||
"type": "string"
|
||||
},
|
||||
"builtin-baseline": {
|
||||
"description": "A vcpkg repository commit for version control.",
|
||||
"type": "string"
|
||||
},
|
||||
"dependencies": {
|
||||
"description": "Dependencies that are always required.",
|
||||
"type": "array",
|
||||
|
@ -226,11 +226,10 @@ namespace vcpkg
|
||||
void exit_if_error(const LineInfo& line_info) const
|
||||
{
|
||||
// This is used for quick value_or_exit() calls, so always put line_info in the error message.
|
||||
Checks::check_exit(line_info,
|
||||
!m_s.has_error(),
|
||||
"Failed at [%s] with message:\n%s",
|
||||
line_info.to_string(),
|
||||
m_s.to_string());
|
||||
if (m_s.has_error())
|
||||
{
|
||||
Checks::exit_with_message(line_info, "Failed at [%s] with message:\n%s", line_info, m_s.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
ErrorHolder<S> m_s;
|
||||
|
@ -282,45 +282,34 @@ namespace vcpkg::Files
|
||||
};
|
||||
|
||||
ExclusiveFileLock() = default;
|
||||
ExclusiveFileLock(ExclusiveFileLock&& other)
|
||||
: fs_(other.fs_), handle_(std::exchange(handle_, fs::SystemHandle{}))
|
||||
{
|
||||
}
|
||||
ExclusiveFileLock& operator=(ExclusiveFileLock&& other)
|
||||
{
|
||||
if (this == &other) return *this;
|
||||
ExclusiveFileLock(ExclusiveFileLock&&) = delete;
|
||||
ExclusiveFileLock& operator=(ExclusiveFileLock&&) = delete;
|
||||
|
||||
clear();
|
||||
fs_ = other.fs_;
|
||||
handle_ = std::exchange(other.handle_, fs::SystemHandle{});
|
||||
return *this;
|
||||
}
|
||||
|
||||
ExclusiveFileLock(Wait wait, Filesystem& fs, const fs::path& path_, std::error_code& ec) : fs_(&fs)
|
||||
ExclusiveFileLock(Wait wait, Filesystem& fs, const fs::path& path_, std::error_code& ec) : m_fs(&fs)
|
||||
{
|
||||
switch (wait)
|
||||
{
|
||||
case Wait::Yes: handle_ = fs_->take_exclusive_file_lock(path_, ec); break;
|
||||
case Wait::No: handle_ = fs_->try_take_exclusive_file_lock(path_, ec); break;
|
||||
case Wait::Yes: m_handle = m_fs->take_exclusive_file_lock(path_, ec); break;
|
||||
case Wait::No: m_handle = m_fs->try_take_exclusive_file_lock(path_, ec); break;
|
||||
}
|
||||
}
|
||||
~ExclusiveFileLock() { clear(); }
|
||||
|
||||
explicit operator bool() const { return handle_.is_valid(); }
|
||||
bool has_lock() const { return handle_.is_valid(); }
|
||||
explicit operator bool() const { return m_handle.is_valid(); }
|
||||
bool has_lock() const { return m_handle.is_valid(); }
|
||||
|
||||
void clear()
|
||||
{
|
||||
if (fs_ && handle_.is_valid())
|
||||
if (m_fs && m_handle.is_valid())
|
||||
{
|
||||
std::error_code ignore;
|
||||
fs_->unlock_file_lock(std::exchange(handle_, fs::SystemHandle{}), ignore);
|
||||
m_fs->unlock_file_lock(std::exchange(m_handle, fs::SystemHandle{}), ignore);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
fs::SystemHandle handle_;
|
||||
Filesystem* fs_;
|
||||
Filesystem* m_fs;
|
||||
fs::SystemHandle m_handle;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -291,7 +291,9 @@ namespace vcpkg::Json
|
||||
ExpectedT<std::pair<Value, JsonStyle>, std::unique_ptr<Parse::IParseError>> parse_file(
|
||||
const Files::Filesystem&, const fs::path&, std::error_code& ec) noexcept;
|
||||
ExpectedT<std::pair<Value, JsonStyle>, std::unique_ptr<Parse::IParseError>> parse(
|
||||
StringView text, const fs::path& filepath = {}) noexcept;
|
||||
StringView text, const fs::path& filepath) noexcept;
|
||||
ExpectedT<std::pair<Value, JsonStyle>, std::unique_ptr<Parse::IParseError>> parse(StringView text,
|
||||
StringView origin = {}) noexcept;
|
||||
std::pair<Value, JsonStyle> parse_file(vcpkg::LineInfo linfo, const Files::Filesystem&, const fs::path&) noexcept;
|
||||
|
||||
std::string stringify(const Value&, JsonStyle style);
|
||||
|
@ -278,7 +278,7 @@ namespace vcpkg::Json
|
||||
|
||||
struct NaturalNumberDeserializer final : IDeserializer<int>
|
||||
{
|
||||
virtual StringView type_name() const override { return "a natural number"; }
|
||||
virtual StringView type_name() const override { return "a nonnegative integer"; }
|
||||
|
||||
virtual Optional<int> visit_integer(Reader&, int64_t value) override
|
||||
{
|
||||
|
@ -69,6 +69,7 @@ namespace vcpkg
|
||||
std::vector<DependencyOverride> overrides;
|
||||
std::vector<std::string> default_features;
|
||||
std::string license; // SPDX license expression
|
||||
Optional<std::string> builtin_baseline;
|
||||
|
||||
Type type;
|
||||
PlatformExpression::Expr supports_expression;
|
||||
|
@ -118,8 +118,12 @@ namespace vcpkg
|
||||
const std::string& get_tool_version(const std::string& tool) const;
|
||||
|
||||
// Git manipulation in the vcpkg directory
|
||||
fs::path git_checkout_baseline(Files::Filesystem& filesystem, StringView commit_sha) const;
|
||||
fs::path git_checkout_port(Files::Filesystem& filesystem, StringView port_name, StringView git_tree) const;
|
||||
ExpectedS<std::string> get_current_git_sha() const;
|
||||
std::string get_current_git_sha_message() const;
|
||||
ExpectedS<fs::path> git_checkout_baseline(StringView commit_sha) const;
|
||||
ExpectedS<fs::path> git_checkout_port(StringView port_name,
|
||||
StringView git_tree,
|
||||
const fs::path& dot_git_dir) const;
|
||||
ExpectedS<std::string> git_show(const std::string& treeish, const fs::path& dot_git_dir) const;
|
||||
|
||||
ExpectedS<std::map<std::string, std::string, std::less<>>> git_get_local_port_treeish_map() const;
|
||||
@ -168,12 +172,5 @@ namespace vcpkg
|
||||
const fs::path& destination,
|
||||
const fs::path& dot_git_dir,
|
||||
const fs::path& work_tree);
|
||||
|
||||
static void git_checkout_object(const VcpkgPaths& paths,
|
||||
StringView git_object,
|
||||
const fs::path& local_repo,
|
||||
const fs::path& destination,
|
||||
const fs::path& dot_git_dir,
|
||||
const fs::path& work_tree);
|
||||
};
|
||||
}
|
||||
|
@ -81,8 +81,7 @@ namespace vcpkg::Versions
|
||||
enum class Type
|
||||
{
|
||||
None,
|
||||
Minimum,
|
||||
Exact
|
||||
Minimum
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ private:
|
||||
|
||||
static const MockOverlayProvider s_empty_mock_overlay;
|
||||
|
||||
ExpectedS<Dependencies::ActionPlan> create_versioned_install_plan(
|
||||
static ExpectedS<Dependencies::ActionPlan> create_versioned_install_plan(
|
||||
const PortFileProvider::IVersionedPortfileProvider& provider,
|
||||
const PortFileProvider::IBaselineProvider& bprovider,
|
||||
const CMakeVars::CMakeVarProvider& var_provider,
|
||||
@ -335,7 +335,7 @@ TEST_CASE ("basic version install scheme baseline missing success", "[versionpla
|
||||
bp,
|
||||
var_provider,
|
||||
{
|
||||
Dependency{"a", {}, {}, {Constraint::Type::Exact, "2"}},
|
||||
Dependency{"a", {}, {}, {Constraint::Type::Minimum, "2"}},
|
||||
},
|
||||
{},
|
||||
toplevel_spec()));
|
||||
@ -375,7 +375,7 @@ TEST_CASE ("version string baseline agree", "[versionplan]")
|
||||
MockCMakeVarProvider var_provider;
|
||||
|
||||
auto install_plan = create_versioned_install_plan(
|
||||
vp, bp, var_provider, {Dependency{"a", {}, {}, {Constraint::Type::Exact, "2"}}}, {}, toplevel_spec());
|
||||
vp, bp, var_provider, {Dependency{"a", {}, {}, {Constraint::Type::Minimum, "2"}}}, {}, toplevel_spec());
|
||||
|
||||
REQUIRE(install_plan.has_value());
|
||||
}
|
||||
@ -396,7 +396,7 @@ TEST_CASE ("version install scheme baseline conflict", "[versionplan]")
|
||||
bp,
|
||||
var_provider,
|
||||
{
|
||||
Dependency{"a", {}, {}, {Constraint::Type::Exact, "3"}},
|
||||
Dependency{"a", {}, {}, {Constraint::Type::Minimum, "3"}},
|
||||
},
|
||||
{},
|
||||
toplevel_spec());
|
||||
@ -421,7 +421,7 @@ TEST_CASE ("version install string port version", "[versionplan]")
|
||||
bp,
|
||||
var_provider,
|
||||
{
|
||||
Dependency{"a", {}, {}, {Constraint::Type::Exact, "2", 1}},
|
||||
Dependency{"a", {}, {}, {Constraint::Type::Minimum, "2", 1}},
|
||||
},
|
||||
{},
|
||||
toplevel_spec()));
|
||||
@ -447,7 +447,7 @@ TEST_CASE ("version install string port version 2", "[versionplan]")
|
||||
bp,
|
||||
var_provider,
|
||||
{
|
||||
Dependency{"a", {}, {}, {Constraint::Type::Exact, "2", 0}},
|
||||
Dependency{"a", {}, {}, {Constraint::Type::Minimum, "2", 0}},
|
||||
},
|
||||
{},
|
||||
toplevel_spec()));
|
||||
@ -463,10 +463,10 @@ TEST_CASE ("version install transitive string", "[versionplan]")
|
||||
|
||||
MockVersionedPortfileProvider vp;
|
||||
vp.emplace("a", {"2", 0}).source_control_file->core_paragraph->dependencies = {
|
||||
Dependency{"b", {}, {}, DependencyConstraint{Constraint::Type::Exact, "1"}},
|
||||
Dependency{"b", {}, {}, DependencyConstraint{Constraint::Type::Minimum, "1"}},
|
||||
};
|
||||
vp.emplace("a", {"2", 1}).source_control_file->core_paragraph->dependencies = {
|
||||
Dependency{"b", {}, {}, DependencyConstraint{Constraint::Type::Exact, "2"}},
|
||||
Dependency{"b", {}, {}, DependencyConstraint{Constraint::Type::Minimum, "2"}},
|
||||
};
|
||||
vp.emplace("b", {"1", 0});
|
||||
vp.emplace("b", {"2", 0});
|
||||
@ -478,7 +478,7 @@ TEST_CASE ("version install transitive string", "[versionplan]")
|
||||
bp,
|
||||
var_provider,
|
||||
{
|
||||
Dependency{"a", {}, {}, {Constraint::Type::Exact, "2", 1}},
|
||||
Dependency{"a", {}, {}, {Constraint::Type::Minimum, "2", 1}},
|
||||
},
|
||||
{},
|
||||
toplevel_spec()));
|
||||
@ -1006,7 +1006,7 @@ TEST_CASE ("version install scheme change in port version", "[versionplan]")
|
||||
{
|
||||
MockVersionedPortfileProvider vp;
|
||||
vp.emplace("a", {"2", 0}).source_control_file->core_paragraph->dependencies = {
|
||||
Dependency{"b", {}, {}, DependencyConstraint{Constraint::Type::Exact, "1"}},
|
||||
Dependency{"b", {}, {}, DependencyConstraint{Constraint::Type::Minimum, "1"}},
|
||||
};
|
||||
vp.emplace("a", {"2", 1}).source_control_file->core_paragraph->dependencies = {
|
||||
Dependency{"b", {}, {}, DependencyConstraint{Constraint::Type::Minimum, "1", 1}},
|
||||
@ -1026,7 +1026,7 @@ TEST_CASE ("version install scheme change in port version", "[versionplan]")
|
||||
bp,
|
||||
var_provider,
|
||||
{
|
||||
Dependency{"a", {}, {}, {Constraint::Type::Exact, "2", 1}},
|
||||
Dependency{"a", {}, {}, {Constraint::Type::Minimum, "2", 1}},
|
||||
},
|
||||
{},
|
||||
toplevel_spec()));
|
||||
@ -1045,7 +1045,7 @@ TEST_CASE ("version install scheme change in port version", "[versionplan]")
|
||||
bp,
|
||||
var_provider,
|
||||
{
|
||||
Dependency{"a", {}, {}, {Constraint::Type::Exact, "2", 0}},
|
||||
Dependency{"a", {}, {}, {Constraint::Type::Minimum, "2", 0}},
|
||||
},
|
||||
{},
|
||||
toplevel_spec()));
|
||||
@ -1305,7 +1305,8 @@ TEST_CASE ("version install transitive overrides", "[versionplan]")
|
||||
MockVersionedPortfileProvider vp;
|
||||
|
||||
vp.emplace("b", {"1", 0}, Scheme::Relaxed)
|
||||
.source_control_file->core_paragraph->dependencies.push_back({"c", {}, {}, {Constraint::Type::Exact, "2", 1}});
|
||||
.source_control_file->core_paragraph->dependencies.push_back(
|
||||
{"c", {}, {}, {Constraint::Type::Minimum, "2", 1}});
|
||||
vp.emplace("b", {"2", 0}, Scheme::Relaxed);
|
||||
vp.emplace("c", {"1", 0}, Scheme::String);
|
||||
vp.emplace("c", {"2", 1}, Scheme::String);
|
||||
|
@ -62,6 +62,7 @@ TEST_CASE ("manifest construct minimum", "[manifests]")
|
||||
REQUIRE(pgh.core_paragraph->maintainers.empty());
|
||||
REQUIRE(pgh.core_paragraph->description.empty());
|
||||
REQUIRE(pgh.core_paragraph->dependencies.empty());
|
||||
REQUIRE(!pgh.core_paragraph->builtin_baseline.has_value());
|
||||
|
||||
REQUIRE(!pgh.check_against_feature_flags({}, feature_flags_without_versioning));
|
||||
}
|
||||
@ -157,19 +158,31 @@ TEST_CASE ("manifest versioning", "[manifests]")
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE ("manifest constraints error hash", "[manifests]")
|
||||
TEST_CASE ("manifest constraints hash", "[manifests]")
|
||||
{
|
||||
auto p = unwrap(test_parse_manifest(R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "abcd",
|
||||
"dependencies": [
|
||||
{
|
||||
"name": "d",
|
||||
"version>=": "2018-09-01#1"
|
||||
}
|
||||
]
|
||||
})json"));
|
||||
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({
|
||||
"name": "zlib",
|
||||
"version-string": "abcd",
|
||||
"dependencies": [
|
||||
{
|
||||
"name": "b",
|
||||
"version=": "5#1"
|
||||
"name": "d",
|
||||
"version>=": "2018-09-01#0"
|
||||
}
|
||||
]
|
||||
}
|
||||
)json",
|
||||
})json",
|
||||
true);
|
||||
|
||||
test_parse_manifest(R"json({
|
||||
@ -178,7 +191,20 @@ TEST_CASE ("manifest constraints error hash", "[manifests]")
|
||||
"dependencies": [
|
||||
{
|
||||
"name": "d",
|
||||
"version>=": "2018-09-01#1"
|
||||
"version>=": "2018-09-01#-1"
|
||||
}
|
||||
]
|
||||
})json",
|
||||
true);
|
||||
|
||||
test_parse_manifest(R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "abcd",
|
||||
"dependencies": [
|
||||
{
|
||||
"name": "d",
|
||||
"version>=": "2018-09-01",
|
||||
"port-version": 1
|
||||
}
|
||||
]
|
||||
})json",
|
||||
@ -238,13 +264,9 @@ TEST_CASE ("manifest constraints", "[manifests]")
|
||||
std::string raw = R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "abcd",
|
||||
"builtin-baseline": "089fa4de7dca22c67dcab631f618d5cd0697c8d4",
|
||||
"dependencies": [
|
||||
"a",
|
||||
{
|
||||
"name": "b",
|
||||
"port-version": 12,
|
||||
"version=": "5"
|
||||
},
|
||||
{
|
||||
"$extra": null,
|
||||
"name": "c"
|
||||
@ -263,32 +285,17 @@ TEST_CASE ("manifest constraints", "[manifests]")
|
||||
REQUIRE(pgh.check_against_feature_flags({}, feature_flags_without_versioning));
|
||||
REQUIRE(!pgh.check_against_feature_flags({}, feature_flags_with_versioning));
|
||||
REQUIRE(Json::stringify(serialize_manifest(pgh), Json::JsonStyle::with_spaces(4)) == raw);
|
||||
REQUIRE(pgh.core_paragraph->dependencies.size() == 4);
|
||||
REQUIRE(pgh.core_paragraph->dependencies.size() == 3);
|
||||
REQUIRE(pgh.core_paragraph->dependencies[0].name == "a");
|
||||
REQUIRE(pgh.core_paragraph->dependencies[0].constraint ==
|
||||
DependencyConstraint{Versions::Constraint::Type::None, "", 0});
|
||||
REQUIRE(pgh.core_paragraph->dependencies[1].name == "b");
|
||||
REQUIRE(pgh.core_paragraph->dependencies[1].name == "c");
|
||||
REQUIRE(pgh.core_paragraph->dependencies[1].constraint ==
|
||||
DependencyConstraint{Versions::Constraint::Type::Exact, "5", 12});
|
||||
REQUIRE(pgh.core_paragraph->dependencies[2].name == "c");
|
||||
REQUIRE(pgh.core_paragraph->dependencies[2].constraint ==
|
||||
DependencyConstraint{Versions::Constraint::Type::None, "", 0});
|
||||
REQUIRE(pgh.core_paragraph->dependencies[3].name == "d");
|
||||
REQUIRE(pgh.core_paragraph->dependencies[3].constraint ==
|
||||
REQUIRE(pgh.core_paragraph->dependencies[2].name == "d");
|
||||
REQUIRE(pgh.core_paragraph->dependencies[2].constraint ==
|
||||
DependencyConstraint{Versions::Constraint::Type::Minimum, "2018-09-01", 0});
|
||||
|
||||
test_parse_manifest(R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "abcd",
|
||||
"dependencies": [
|
||||
{
|
||||
"name": "d",
|
||||
"version=": "2018-09-01",
|
||||
"version>=": "2018-09-01"
|
||||
}
|
||||
]
|
||||
})json",
|
||||
true);
|
||||
REQUIRE(pgh.core_paragraph->builtin_baseline == "089fa4de7dca22c67dcab631f618d5cd0697c8d4");
|
||||
|
||||
test_parse_manifest(R"json({
|
||||
"name": "zlib",
|
||||
@ -303,6 +310,45 @@ TEST_CASE ("manifest constraints", "[manifests]")
|
||||
true);
|
||||
}
|
||||
|
||||
TEST_CASE ("manifest builtin-baseline", "[manifests]")
|
||||
{
|
||||
SECTION ("valid baseline")
|
||||
{
|
||||
std::string raw = R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "abcd",
|
||||
"builtin-baseline": "089fa4de7dca22c67dcab631f618d5cd0697c8d4"
|
||||
}
|
||||
)json";
|
||||
auto m_pgh = test_parse_manifest(raw);
|
||||
|
||||
REQUIRE(m_pgh.has_value());
|
||||
auto& pgh = **m_pgh.get();
|
||||
REQUIRE(pgh.check_against_feature_flags({}, feature_flags_without_versioning));
|
||||
REQUIRE(!pgh.check_against_feature_flags({}, feature_flags_with_versioning));
|
||||
REQUIRE(pgh.core_paragraph->builtin_baseline.value_or("does not have a value") ==
|
||||
"089fa4de7dca22c67dcab631f618d5cd0697c8d4");
|
||||
}
|
||||
|
||||
SECTION ("empty baseline")
|
||||
{
|
||||
std::string raw = R"json({
|
||||
"name": "zlib",
|
||||
"version-string": "abcd",
|
||||
"builtin-baseline": ""
|
||||
}
|
||||
)json";
|
||||
|
||||
auto m_pgh = test_parse_manifest(raw);
|
||||
|
||||
REQUIRE(m_pgh.has_value());
|
||||
auto& pgh = **m_pgh.get();
|
||||
REQUIRE(pgh.check_against_feature_flags({}, feature_flags_without_versioning));
|
||||
REQUIRE(!pgh.check_against_feature_flags({}, feature_flags_with_versioning));
|
||||
REQUIRE(pgh.core_paragraph->builtin_baseline.value_or("does not have a value") == "");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE ("manifest overrides", "[manifests]")
|
||||
{
|
||||
std::tuple<StringLiteral, Versions::Scheme, StringLiteral> data[] = {
|
||||
|
@ -1064,6 +1064,11 @@ namespace vcpkg::Json
|
||||
{
|
||||
return Parser::parse(json, fs::generic_u8string(filepath));
|
||||
}
|
||||
ExpectedT<std::pair<Value, JsonStyle>, std::unique_ptr<Parse::IParseError>> parse(StringView json,
|
||||
StringView origin) noexcept
|
||||
{
|
||||
return Parser::parse(json, origin);
|
||||
}
|
||||
// } auto parse()
|
||||
|
||||
namespace
|
||||
|
@ -404,7 +404,7 @@ namespace vcpkg::Commands::CIVerifyVersions
|
||||
System::printf(System::Color::error, "%s\n", error);
|
||||
}
|
||||
System::print2(System::Color::error,
|
||||
"\nTo attempt to resolve all erros at once, run:\n\n"
|
||||
"\nTo attempt to resolve all errors at once, run:\n\n"
|
||||
" vcpkg x-add-version --all\n\n");
|
||||
Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
}
|
||||
|
@ -47,7 +47,69 @@ namespace vcpkg::Help
|
||||
nullptr,
|
||||
};
|
||||
|
||||
static constexpr std::array<Topic, 15> topics = {{
|
||||
static void help_topic_versioning(const VcpkgPaths&)
|
||||
{
|
||||
HelpTableFormatter tbl;
|
||||
tbl.text("Versioning allows you to deterministically control the precise revisions of dependencies used by "
|
||||
"your project from within your manifest file.");
|
||||
tbl.blank();
|
||||
tbl.blank();
|
||||
tbl.text("** This feature is experimental and requires `--feature-flags=versions` **");
|
||||
tbl.blank();
|
||||
tbl.blank();
|
||||
tbl.header("Versions in vcpkg come in four primary flavors");
|
||||
tbl.format("version", "A dot-separated sequence of numbers (1.2.3.4)");
|
||||
tbl.format("version-date", "A date (2021-01-01.5)");
|
||||
tbl.format("version-semver", "A Semantic Version 2.0 (2.1.0-rc2)");
|
||||
tbl.format("version-string", "An exact, incomparable version (Vista)");
|
||||
tbl.blank();
|
||||
tbl.text("Each version additionally has a \"port-version\" which is a nonnegative integer. When rendered as "
|
||||
"text, the port version (if nonzero) is added as a suffix to the primary version text separated by a "
|
||||
"hash (#). Port-versions are sorted lexographically after the primary version text, for example:");
|
||||
tbl.blank();
|
||||
tbl.blank();
|
||||
tbl.text(" 1.0.0 < 1.0.0#1 < 1.0.1 < 1.0.1#5 < 2.0.0");
|
||||
tbl.blank();
|
||||
tbl.blank();
|
||||
tbl.header("Manifests can place three kinds of constraints upon the versions used");
|
||||
tbl.format("builtin-baseline",
|
||||
"The baseline references a commit within the vcpkg repository that establishes a minimum version on "
|
||||
"every dependency in the graph. If no other constraints are specified (directly or transitively), "
|
||||
"then the version from the baseline of the top level manifest will be used. Baselines of transitive "
|
||||
"dependencies are ignored.");
|
||||
tbl.blank();
|
||||
tbl.format("version>=",
|
||||
"Within the \"dependencies\" field, each dependency can have a minimum constraint listed. These "
|
||||
"minimum constraints will be used when transitively depending upon this library. A minimum "
|
||||
"port-version can additionally be specified with a '#' suffix.");
|
||||
tbl.blank();
|
||||
tbl.format(
|
||||
"overrides",
|
||||
"When used as the top-level manifest (such as when running `vcpkg install` in the directory), overrides "
|
||||
"allow a manifest to short-circuit dependency resolution and specify exactly the version to use. These can "
|
||||
"be used to handle version conflicts, such as with `version-string` dependencies. They will not be "
|
||||
"considered when transitively depended upon.");
|
||||
tbl.blank();
|
||||
tbl.text("Example manifest:");
|
||||
tbl.blank();
|
||||
tbl.text(R"({
|
||||
"name": "example",
|
||||
"version": "1.0",
|
||||
"builtin-baseline": "a14a6bcb27287e3ec138dba1b948a0cdbc337a3a",
|
||||
"dependencies": [
|
||||
{ "name": "zlib", "version>=": "1.2.11#8" },
|
||||
"rapidjson"
|
||||
],
|
||||
"overrides": [
|
||||
{ "name": "rapidjson", "version": "2020-09-14" }
|
||||
]
|
||||
})");
|
||||
System::print2(tbl.m_str,
|
||||
"\nExtended documentation is available at "
|
||||
"https://github.com/Microsoft/vcpkg/tree/master/docs/users/versioning.md\n");
|
||||
}
|
||||
|
||||
static constexpr std::array<Topic, 16> topics = {{
|
||||
{"binarycaching", help_topic_binary_caching},
|
||||
{"create", command_topic_fn<Commands::Create::COMMAND_STRUCTURE>},
|
||||
{"depend-info", command_topic_fn<Commands::DependInfo::COMMAND_STRUCTURE>},
|
||||
@ -63,6 +125,7 @@ namespace vcpkg::Help
|
||||
{"search", command_topic_fn<Commands::Search::COMMAND_STRUCTURE>},
|
||||
{"topics", help_topics},
|
||||
{"triplet", help_topic_valid_triplet},
|
||||
{"versioning", help_topic_versioning},
|
||||
}};
|
||||
|
||||
static void help_topics(const VcpkgPaths&)
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <vcpkg/metrics.h>
|
||||
#include <vcpkg/paragraphs.h>
|
||||
#include <vcpkg/remove.h>
|
||||
#include <vcpkg/tools.h>
|
||||
#include <vcpkg/vcpkglib.h>
|
||||
#include <vcpkg/vcpkgpaths.h>
|
||||
|
||||
@ -847,10 +848,25 @@ namespace vcpkg::Install
|
||||
|
||||
if (args.versions_enabled() || args.registries_enabled())
|
||||
{
|
||||
if (auto p_baseline = manifest_scf.core_paragraph->extra_info.get("$x-default-baseline"))
|
||||
if (!manifest_scf.core_paragraph->overrides.empty())
|
||||
{
|
||||
paths.get_configuration().registry_set.experimental_set_builtin_registry_baseline(
|
||||
p_baseline->string());
|
||||
Metrics::g_metrics.lock()->track_property("manifest_overrides", "defined");
|
||||
}
|
||||
if (auto p_baseline = manifest_scf.core_paragraph->builtin_baseline.get())
|
||||
{
|
||||
Metrics::g_metrics.lock()->track_property("manifest_baseline", "defined");
|
||||
if (p_baseline->size() != 40 || !std::all_of(p_baseline->begin(), p_baseline->end(), [](char ch) {
|
||||
return (ch >= 'a' || ch <= 'f') || Parse::ParserBase::is_ascii_digit(ch);
|
||||
}))
|
||||
{
|
||||
Checks::exit_with_message(
|
||||
VCPKG_LINE_INFO,
|
||||
"Error: the top-level builtin-baseline (%s) was not a valid commit sha: "
|
||||
"expected 40 lowercase hexadecimal characters.\n%s\n",
|
||||
*p_baseline,
|
||||
paths.get_current_git_sha_message());
|
||||
}
|
||||
paths.get_configuration().registry_set.experimental_set_builtin_registry_baseline(*p_baseline);
|
||||
}
|
||||
}
|
||||
if (args.versions_enabled())
|
||||
|
@ -373,7 +373,14 @@ namespace vcpkg::Paragraphs
|
||||
|
||||
auto error_info = std::make_unique<ParseControlErrorInfo>();
|
||||
error_info->name = fs::u8string(path.filename());
|
||||
error_info->error = "Failed to find either a CONTROL file or vcpkg.json file.";
|
||||
if (fs.exists(path))
|
||||
{
|
||||
error_info->error = "Failed to find either a CONTROL file or vcpkg.json file.";
|
||||
}
|
||||
else
|
||||
{
|
||||
error_info->error = "The port directory (" + fs::u8string(path) + ") does not exist";
|
||||
}
|
||||
return error_info;
|
||||
}
|
||||
|
||||
|
@ -186,17 +186,6 @@ namespace
|
||||
DelayedInit<Baseline> m_baseline;
|
||||
};
|
||||
|
||||
ExpectedS<fs::path> get_git_baseline_json_path(const VcpkgPaths& paths, StringView baseline_commit_sha)
|
||||
{
|
||||
auto baseline_path = paths.git_checkout_baseline(paths.get_filesystem(), baseline_commit_sha);
|
||||
if (paths.get_filesystem().exists(baseline_path))
|
||||
{
|
||||
return std::move(baseline_path);
|
||||
}
|
||||
return {Strings::concat("Error: Baseline database file does not exist: ", fs::u8string(baseline_path)),
|
||||
expected_right_tag};
|
||||
}
|
||||
|
||||
struct VersionDbEntry
|
||||
{
|
||||
VersionT version;
|
||||
@ -224,7 +213,7 @@ namespace
|
||||
|
||||
// returns nullopt if the baseline is valid, but doesn't contain the specified baseline,
|
||||
// or (equivalently) if the baseline does not exist.
|
||||
ExpectedS<Optional<Baseline>> parse_baseline_versions(StringView contents, StringView baseline);
|
||||
ExpectedS<Optional<Baseline>> parse_baseline_versions(StringView contents, StringView baseline, StringView origin);
|
||||
ExpectedS<Optional<Baseline>> load_baseline_versions(const VcpkgPaths& paths,
|
||||
const fs::path& path_to_baseline,
|
||||
StringView identifier = {});
|
||||
@ -327,18 +316,20 @@ namespace
|
||||
|
||||
if (baseline_identifier == "default")
|
||||
{
|
||||
return Strings::format("Couldn't find explicitly specified baseline `\"default\"` in baseline file: %s",
|
||||
fs::u8string(path_to_baseline));
|
||||
return Strings::format(
|
||||
"Error: Couldn't find explicitly specified baseline `\"default\"` in baseline file: %s",
|
||||
fs::u8string(path_to_baseline));
|
||||
}
|
||||
|
||||
// attempt to check out the baseline:
|
||||
auto maybe_path = get_git_baseline_json_path(paths, baseline_identifier);
|
||||
auto maybe_path = paths.git_checkout_baseline(baseline_identifier);
|
||||
if (!maybe_path.has_value())
|
||||
{
|
||||
return Strings::format("Couldn't find explicitly specified baseline `\"%s\"` in the baseline file, "
|
||||
"and there was no baseline at that commit or the commit didn't exist.\n%s",
|
||||
return Strings::format("Error: Couldn't find explicitly specified baseline `\"%s\"` in the baseline file, "
|
||||
"and there was no baseline at that commit or the commit didn't exist.\n%s\n%s",
|
||||
baseline_identifier,
|
||||
maybe_path.error());
|
||||
maybe_path.error(),
|
||||
paths.get_current_git_sha_message());
|
||||
}
|
||||
|
||||
res_baseline = load_baseline_versions(paths, *maybe_path.get());
|
||||
@ -352,7 +343,7 @@ namespace
|
||||
return std::move(*p);
|
||||
}
|
||||
|
||||
return Strings::format("Couldn't find explicitly specified baseline `\"%s\"` in the baseline "
|
||||
return Strings::format("Error: Couldn't find explicitly specified baseline `\"%s\"` in the baseline "
|
||||
"file, and the `\"default\"` baseline does not exist at that commit.",
|
||||
baseline_identifier);
|
||||
}
|
||||
@ -549,7 +540,7 @@ namespace
|
||||
}
|
||||
|
||||
auto contents = maybe_contents.get();
|
||||
res_baseline = parse_baseline_versions(*contents, {});
|
||||
res_baseline = parse_baseline_versions(*contents, "default", fs::u8string(path_to_baseline));
|
||||
if (!res_baseline.has_value())
|
||||
{
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO, res_baseline.error());
|
||||
@ -599,12 +590,22 @@ namespace
|
||||
auto it = std::find(git_entry->port_versions.begin(), git_entry->port_versions.end(), version);
|
||||
if (it == git_entry->port_versions.end())
|
||||
{
|
||||
return Strings::concat(
|
||||
"Error: No version entry for ", git_entry->port_name, " at version ", version, ".");
|
||||
return {
|
||||
Strings::concat("Error: No version entry for ",
|
||||
git_entry->port_name,
|
||||
" at version ",
|
||||
version,
|
||||
". This may be fixed by updating vcpkg to the latest master via `git "
|
||||
"pull`.\nAvailable versions:\n",
|
||||
Strings::join("",
|
||||
git_entry->port_versions,
|
||||
[](const VersionT& v) { return Strings::concat(" ", v, "\n"); }),
|
||||
"\nSee `vcpkg help versioning` for more information."),
|
||||
expected_right_tag};
|
||||
}
|
||||
|
||||
const auto& git_tree = git_entry->git_trees[it - git_entry->port_versions.begin()];
|
||||
return paths.git_checkout_port(paths.get_filesystem(), git_entry->port_name, git_tree);
|
||||
return paths.git_checkout_port(git_entry->port_name, git_tree, paths.root / fs::u8path(".git"));
|
||||
}
|
||||
|
||||
if (scfl_version == version)
|
||||
@ -1014,19 +1015,20 @@ namespace
|
||||
return db_entries;
|
||||
}
|
||||
|
||||
ExpectedS<Optional<Baseline>> parse_baseline_versions(StringView contents, StringView baseline)
|
||||
ExpectedS<Optional<Baseline>> parse_baseline_versions(StringView contents, StringView baseline, StringView origin)
|
||||
{
|
||||
auto maybe_value = Json::parse(contents);
|
||||
auto maybe_value = Json::parse(contents, origin);
|
||||
if (!maybe_value.has_value())
|
||||
{
|
||||
return Strings::format("Error: failed to parse baseline file: %s", maybe_value.error()->format());
|
||||
return Strings::format(
|
||||
"Error: failed to parse baseline file: %s\n%s", origin, maybe_value.error()->format());
|
||||
}
|
||||
|
||||
auto& value = *maybe_value.get();
|
||||
|
||||
if (!value.first.is_object())
|
||||
{
|
||||
return std::string("Error: baseline does not have a top-level object.");
|
||||
return Strings::concat("Error: baseline does not have a top-level object: ", origin);
|
||||
}
|
||||
|
||||
auto real_baseline = baseline.size() == 0 ? "default" : baseline;
|
||||
@ -1047,8 +1049,7 @@ namespace
|
||||
}
|
||||
else
|
||||
{
|
||||
Checks::exit_with_message(
|
||||
VCPKG_LINE_INFO, "Error: failed to parse baseline:\n%s", Strings::join("\n", r.errors()));
|
||||
return Strings::format("Error: failed to parse baseline: %s\n%s", origin, Strings::join("\n", r.errors()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1059,7 +1060,7 @@ namespace
|
||||
auto maybe_contents = paths.get_filesystem().read_contents(path_to_baseline);
|
||||
if (auto contents = maybe_contents.get())
|
||||
{
|
||||
return parse_baseline_versions(*contents, baseline);
|
||||
return parse_baseline_versions(*contents, baseline, fs::u8string(path_to_baseline));
|
||||
}
|
||||
else if (maybe_contents.error() == std::errc::no_such_file_or_directory)
|
||||
{
|
||||
@ -1143,7 +1144,7 @@ namespace vcpkg
|
||||
if (!default_registry_is_builtin || registries_.size() != 0)
|
||||
{
|
||||
System::print2(System::Color::warning,
|
||||
"Warning: when using the registries feature, one should not use `\"$x-default-baseline\"` "
|
||||
"Warning: when using the registries feature, one should not use `\"builtin-baseline\"` "
|
||||
"to set the baseline.\n",
|
||||
" Instead, use the \"baseline\" field of the registry.\n");
|
||||
}
|
||||
|
@ -430,8 +430,6 @@ namespace vcpkg
|
||||
constexpr static StringLiteral FEATURES = "features";
|
||||
constexpr static StringLiteral DEFAULT_FEATURES = "default-features";
|
||||
constexpr static StringLiteral PLATFORM = "platform";
|
||||
constexpr static StringLiteral PORT_VERSION = "port-version";
|
||||
constexpr static StringLiteral VERSION_EQ = "version=";
|
||||
constexpr static StringLiteral VERSION_GE = "version>=";
|
||||
|
||||
virtual Span<const StringView> valid_fields() const override
|
||||
@ -441,8 +439,6 @@ namespace vcpkg
|
||||
FEATURES,
|
||||
DEFAULT_FEATURES,
|
||||
PLATFORM,
|
||||
PORT_VERSION,
|
||||
VERSION_EQ,
|
||||
VERSION_GE,
|
||||
};
|
||||
|
||||
@ -488,32 +484,33 @@ namespace vcpkg
|
||||
|
||||
r.optional_object_field(obj, PLATFORM, dep.platform, PlatformExprDeserializer::instance);
|
||||
|
||||
static auto version_deserializer = make_version_deserializer("a version");
|
||||
static Json::StringDeserializer version_deserializer("a version");
|
||||
|
||||
auto has_eq_constraint =
|
||||
r.optional_object_field(obj, VERSION_EQ, dep.constraint.value, *version_deserializer);
|
||||
auto has_ge_constraint =
|
||||
r.optional_object_field(obj, VERSION_GE, dep.constraint.value, *version_deserializer);
|
||||
auto has_port_ver = r.optional_object_field(
|
||||
obj, PORT_VERSION, dep.constraint.port_version, Json::NaturalNumberDeserializer::instance);
|
||||
r.optional_object_field(obj, VERSION_GE, dep.constraint.value, version_deserializer);
|
||||
|
||||
if (has_eq_constraint)
|
||||
{
|
||||
dep.constraint.type = Versions::Constraint::Type::Exact;
|
||||
if (has_ge_constraint)
|
||||
{
|
||||
r.add_generic_error(type_name(), "cannot have both exact and minimum constraints simultaneously");
|
||||
}
|
||||
}
|
||||
else if (has_ge_constraint)
|
||||
if (has_ge_constraint)
|
||||
{
|
||||
dep.constraint.type = Versions::Constraint::Type::Minimum;
|
||||
}
|
||||
else if (has_port_ver) // does not have a primary constraint
|
||||
{
|
||||
r.add_generic_error(
|
||||
type_name(),
|
||||
"\"port-version\" cannot be used without a primary constraint (\"version=\" or \"version>=\")");
|
||||
auto h = dep.constraint.value.find('#');
|
||||
if (h != std::string::npos)
|
||||
{
|
||||
auto opt = Strings::strto<int>(dep.constraint.value.c_str() + h + 1);
|
||||
auto v = opt.get();
|
||||
if (v && *v > 0)
|
||||
{
|
||||
dep.constraint.port_version = *v;
|
||||
}
|
||||
else
|
||||
{
|
||||
r.add_generic_error(type_name(),
|
||||
"embedded port-version ('#') in the primary "
|
||||
"constraint (\"",
|
||||
VERSION_GE,
|
||||
"\") must be a positive integer");
|
||||
}
|
||||
dep.constraint.value.erase(h);
|
||||
}
|
||||
}
|
||||
|
||||
return dep;
|
||||
@ -540,9 +537,7 @@ namespace vcpkg
|
||||
constexpr StringLiteral DependencyDeserializer::FEATURES;
|
||||
constexpr StringLiteral DependencyDeserializer::DEFAULT_FEATURES;
|
||||
constexpr StringLiteral DependencyDeserializer::PLATFORM;
|
||||
constexpr StringLiteral DependencyDeserializer::VERSION_EQ;
|
||||
constexpr StringLiteral DependencyDeserializer::VERSION_GE;
|
||||
constexpr StringLiteral DependencyDeserializer::PORT_VERSION;
|
||||
|
||||
struct DependencyOverrideDeserializer : Json::IDeserializer<DependencyOverride>
|
||||
{
|
||||
@ -860,6 +855,21 @@ namespace vcpkg
|
||||
};
|
||||
LicenseExpressionDeserializer LicenseExpressionDeserializer::instance;
|
||||
|
||||
struct BaselineCommitDeserializer final : Json::IDeserializer<std::string>
|
||||
{
|
||||
virtual StringView type_name() const override { return "a vcpkg repository commit"; }
|
||||
|
||||
virtual Optional<std::string> visit_string(Json::Reader&, StringView s) override
|
||||
{
|
||||
// We allow non-sha strings here to allow the core vcpkg code to provide better error
|
||||
// messages including the current git commit
|
||||
return s.to_string();
|
||||
}
|
||||
|
||||
static BaselineCommitDeserializer instance;
|
||||
};
|
||||
BaselineCommitDeserializer BaselineCommitDeserializer::instance;
|
||||
|
||||
struct ManifestDeserializer : Json::IDeserializer<std::unique_ptr<SourceControlFile>>
|
||||
{
|
||||
virtual StringView type_name() const override { return "a manifest"; }
|
||||
@ -876,6 +886,7 @@ namespace vcpkg
|
||||
constexpr static StringLiteral DEFAULT_FEATURES = "default-features";
|
||||
constexpr static StringLiteral SUPPORTS = "supports";
|
||||
constexpr static StringLiteral OVERRIDES = "overrides";
|
||||
constexpr static StringLiteral BUILTIN_BASELINE = "builtin-baseline";
|
||||
|
||||
virtual Span<const StringView> valid_fields() const override
|
||||
{
|
||||
@ -892,6 +903,7 @@ namespace vcpkg
|
||||
DEFAULT_FEATURES,
|
||||
SUPPORTS,
|
||||
OVERRIDES,
|
||||
BUILTIN_BASELINE,
|
||||
};
|
||||
static const auto t = Util::Vectors::concat<StringView>(schemed_deserializer_fields(), u);
|
||||
|
||||
@ -917,9 +929,9 @@ namespace vcpkg
|
||||
|
||||
static Json::StringDeserializer url_deserializer{"a url"};
|
||||
|
||||
constexpr static StringView type_name = "vcpkg.json";
|
||||
constexpr static StringView inner_type_name = "vcpkg.json";
|
||||
DependencyOverrideDeserializer::visit_impl(
|
||||
type_name, r, obj, spgh->name, spgh->version, spgh->version_scheme, spgh->port_version);
|
||||
inner_type_name, r, obj, spgh->name, spgh->version, spgh->version_scheme, spgh->port_version);
|
||||
|
||||
r.optional_object_field(obj, MAINTAINERS, spgh->maintainers, Json::ParagraphDeserializer::instance);
|
||||
r.optional_object_field(obj, DESCRIPTION, spgh->description, Json::ParagraphDeserializer::instance);
|
||||
@ -933,8 +945,12 @@ namespace vcpkg
|
||||
|
||||
if (obj.contains(DEV_DEPENDENCIES))
|
||||
{
|
||||
System::print2(System::Color::error, DEV_DEPENDENCIES, " are not yet supported");
|
||||
Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
r.add_generic_error(type_name(), DEV_DEPENDENCIES, " are not yet supported");
|
||||
}
|
||||
std::string baseline;
|
||||
if (r.optional_object_field(obj, BUILTIN_BASELINE, baseline, BaselineCommitDeserializer::instance))
|
||||
{
|
||||
spgh->builtin_baseline = std::move(baseline);
|
||||
}
|
||||
|
||||
r.optional_object_field(obj, SUPPORTS, spgh->supports_expression, PlatformExprDeserializer::instance);
|
||||
@ -1007,6 +1023,7 @@ namespace vcpkg
|
||||
Optional<std::string> SourceControlFile::check_against_feature_flags(const fs::path& origin,
|
||||
const FeatureFlagSettings& flags) const
|
||||
{
|
||||
static constexpr StringLiteral s_extended_help = "See `vcpkg help versioning` for more information.";
|
||||
if (!flags.versions)
|
||||
{
|
||||
auto check_deps = [&](View<Dependency> deps) -> Optional<std::string> {
|
||||
@ -1014,11 +1031,12 @@ namespace vcpkg
|
||||
{
|
||||
if (dep.constraint.type != Versions::Constraint::Type::None)
|
||||
{
|
||||
return Strings::concat(fs::u8string(origin),
|
||||
" was rejected because it uses constraints and the `",
|
||||
VcpkgCmdArguments::VERSIONS_FEATURE,
|
||||
"` feature flag is disabled.\nThis can be fixed by removing uses of "
|
||||
"\"version>=\" and \"version=\".");
|
||||
return Strings::concat(
|
||||
fs::u8string(origin),
|
||||
" was rejected because it uses constraints and the `",
|
||||
VcpkgCmdArguments::VERSIONS_FEATURE,
|
||||
"` feature flag is disabled.\nThis can be fixed by removing uses of \"version>=\".\n",
|
||||
s_extended_help);
|
||||
}
|
||||
}
|
||||
return nullopt;
|
||||
@ -1036,7 +1054,18 @@ namespace vcpkg
|
||||
return Strings::concat(fs::u8string(origin),
|
||||
" was rejected because it uses overrides and the `",
|
||||
VcpkgCmdArguments::VERSIONS_FEATURE,
|
||||
"` feature flag is disabled.\nThis can be fixed by removing \"overrides\".");
|
||||
"` feature flag is disabled.\nThis can be fixed by removing \"overrides\".\n",
|
||||
s_extended_help);
|
||||
}
|
||||
|
||||
if (core_paragraph->builtin_baseline.has_value())
|
||||
{
|
||||
return Strings::concat(
|
||||
fs::u8string(origin),
|
||||
" was rejected because it uses builtin-baseline and the `",
|
||||
VcpkgCmdArguments::VERSIONS_FEATURE,
|
||||
"` feature flag is disabled.\nThis can be fixed by removing \"builtin-baseline\".\n",
|
||||
s_extended_help);
|
||||
}
|
||||
}
|
||||
return nullopt;
|
||||
@ -1242,19 +1271,14 @@ namespace vcpkg
|
||||
|
||||
serialize_optional_array(dep_obj, DependencyDeserializer::FEATURES, features_copy);
|
||||
serialize_optional_string(dep_obj, DependencyDeserializer::PLATFORM, to_string(dep.platform));
|
||||
if (dep.constraint.port_version != 0)
|
||||
if (dep.constraint.type == Versions::Constraint::Type::Minimum)
|
||||
{
|
||||
dep_obj.insert(DependencyDeserializer::PORT_VERSION,
|
||||
Json::Value::integer(dep.constraint.port_version));
|
||||
}
|
||||
|
||||
if (dep.constraint.type == Versions::Constraint::Type::Exact)
|
||||
{
|
||||
dep_obj.insert(DependencyDeserializer::VERSION_EQ, Json::Value::string(dep.constraint.value));
|
||||
}
|
||||
else if (dep.constraint.type == Versions::Constraint::Type::Minimum)
|
||||
{
|
||||
dep_obj.insert(DependencyDeserializer::VERSION_GE, Json::Value::string(dep.constraint.value));
|
||||
auto s = dep.constraint.value;
|
||||
if (dep.constraint.port_version != 0)
|
||||
{
|
||||
Strings::append(s, '#', dep.constraint.port_version);
|
||||
}
|
||||
dep_obj.insert(DependencyDeserializer::VERSION_GE, Json::Value::string(std::move(s)));
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -1294,6 +1318,11 @@ namespace vcpkg
|
||||
serialize_optional_string(obj, ManifestDeserializer::LICENSE, scf.core_paragraph->license);
|
||||
serialize_optional_string(
|
||||
obj, ManifestDeserializer::SUPPORTS, to_string(scf.core_paragraph->supports_expression));
|
||||
if (scf.core_paragraph->builtin_baseline.has_value())
|
||||
{
|
||||
obj.insert(ManifestDeserializer::BUILTIN_BASELINE,
|
||||
Json::Value::string(scf.core_paragraph->builtin_baseline.value_or_exit(VCPKG_LINE_INFO)));
|
||||
}
|
||||
|
||||
if (!scf.core_paragraph->dependencies.empty() || debug)
|
||||
{
|
||||
|
@ -554,6 +554,33 @@ If you wish to silence this error and use classic mode, you can:
|
||||
}
|
||||
}
|
||||
|
||||
ExpectedS<std::string> VcpkgPaths::get_current_git_sha() const
|
||||
{
|
||||
auto cmd = git_cmd_builder(*this, this->root / fs::u8path(".git"), this->root);
|
||||
cmd.string_arg("rev-parse").string_arg("HEAD");
|
||||
auto output = System::cmd_execute_and_capture_output(cmd);
|
||||
if (output.exit_code != 0)
|
||||
{
|
||||
return {std::move(output.output), expected_right_tag};
|
||||
}
|
||||
else
|
||||
{
|
||||
return {Strings::trim(std::move(output.output)), expected_left_tag};
|
||||
}
|
||||
}
|
||||
std::string VcpkgPaths::get_current_git_sha_message() const
|
||||
{
|
||||
auto maybe_cur_sha = get_current_git_sha();
|
||||
if (auto p_sha = maybe_cur_sha.get())
|
||||
{
|
||||
return Strings::concat("The current commit is \"", *p_sha, '"');
|
||||
}
|
||||
else
|
||||
{
|
||||
return Strings::concat("Failed to determine the current commit:\n", maybe_cur_sha.error());
|
||||
}
|
||||
}
|
||||
|
||||
ExpectedS<std::string> VcpkgPaths::git_show(const std::string& treeish, const fs::path& dot_git_dir) const
|
||||
{
|
||||
// All git commands are run with: --git-dir={dot_git_dir} --work-tree={work_tree_temp}
|
||||
@ -620,119 +647,148 @@ If you wish to silence this error and use classic mode, you can:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void VcpkgPaths::git_checkout_object(const VcpkgPaths& paths,
|
||||
StringView git_object,
|
||||
const fs::path& local_repo,
|
||||
const fs::path& destination,
|
||||
const fs::path& dot_git_dir,
|
||||
const fs::path& work_tree)
|
||||
{
|
||||
Files::Filesystem& fs = paths.get_filesystem();
|
||||
fs.remove_all(work_tree, VCPKG_LINE_INFO);
|
||||
fs.remove_all(destination, VCPKG_LINE_INFO);
|
||||
|
||||
if (!fs.exists(dot_git_dir))
|
||||
{
|
||||
// All git commands are run with: --git-dir={dot_git_dir} --work-tree={work_tree_temp}
|
||||
// git clone --no-checkout --local {vcpkg_root} {dot_git_dir}
|
||||
System::CmdLineBuilder clone_cmd_builder = git_cmd_builder(paths, dot_git_dir, work_tree)
|
||||
.string_arg("clone")
|
||||
.string_arg("--no-checkout")
|
||||
.string_arg("--local")
|
||||
.string_arg("--no-hardlinks")
|
||||
.path_arg(local_repo)
|
||||
.path_arg(dot_git_dir);
|
||||
const auto clone_output = System::cmd_execute_and_capture_output(clone_cmd_builder);
|
||||
Checks::check_exit(VCPKG_LINE_INFO,
|
||||
clone_output.exit_code == 0,
|
||||
"Failed to clone temporary vcpkg instance.\n%s\n",
|
||||
clone_output.output);
|
||||
}
|
||||
else
|
||||
{
|
||||
System::CmdLineBuilder fetch_cmd_builder =
|
||||
git_cmd_builder(paths, dot_git_dir, work_tree).string_arg("fetch");
|
||||
const auto fetch_output = System::cmd_execute_and_capture_output(fetch_cmd_builder);
|
||||
Checks::check_exit(VCPKG_LINE_INFO,
|
||||
fetch_output.exit_code == 0,
|
||||
"Failed to update refs on temporary vcpkg repository.\n%s\n",
|
||||
fetch_output.output);
|
||||
}
|
||||
|
||||
if (!fs.exists(work_tree))
|
||||
{
|
||||
fs.create_directories(work_tree, VCPKG_LINE_INFO);
|
||||
}
|
||||
|
||||
// git checkout {tree_object} .
|
||||
System::CmdLineBuilder checkout_cmd_builder = git_cmd_builder(paths, dot_git_dir, work_tree)
|
||||
.string_arg("checkout")
|
||||
.string_arg(git_object)
|
||||
.string_arg(".");
|
||||
const auto checkout_output = System::cmd_execute_and_capture_output(checkout_cmd_builder);
|
||||
Checks::check_exit(VCPKG_LINE_INFO, checkout_output.exit_code == 0, "Failed to checkout %s", git_object);
|
||||
|
||||
const auto& containing_folder = destination.parent_path();
|
||||
if (!fs.exists(containing_folder))
|
||||
{
|
||||
fs.create_directories(containing_folder, VCPKG_LINE_INFO);
|
||||
}
|
||||
|
||||
std::error_code ec;
|
||||
fs.rename_or_copy(work_tree, destination, ".tmp", ec);
|
||||
fs.remove_all(work_tree, VCPKG_LINE_INFO);
|
||||
if (ec)
|
||||
{
|
||||
System::printf(System::Color::error,
|
||||
"Error: Couldn't move checked out files from %s to destination %s",
|
||||
fs::u8string(work_tree),
|
||||
fs::u8string(destination));
|
||||
Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
fs::path VcpkgPaths::git_checkout_baseline(Files::Filesystem& fs, StringView commit_sha) const
|
||||
ExpectedS<fs::path> VcpkgPaths::git_checkout_baseline(StringView commit_sha) const
|
||||
{
|
||||
Files::Filesystem& fs = get_filesystem();
|
||||
const fs::path destination_parent = this->baselines_output / fs::u8path(commit_sha);
|
||||
const fs::path destination = destination_parent / fs::u8path("baseline.json");
|
||||
fs::path destination = destination_parent / fs::u8path("baseline.json");
|
||||
|
||||
if (!fs.exists(destination))
|
||||
{
|
||||
const fs::path destination_tmp = destination_parent / fs::u8path("baseline.json.tmp");
|
||||
auto treeish = Strings::concat(commit_sha, ":port_versions/baseline.json");
|
||||
auto maybe_contents = git_show(treeish, this->root / fs::u8path(".git"));
|
||||
if (auto contents = maybe_contents.get())
|
||||
{
|
||||
fs.create_directories(destination_parent, VCPKG_LINE_INFO);
|
||||
fs.write_contents(destination, *contents, VCPKG_LINE_INFO);
|
||||
std::error_code ec;
|
||||
fs.create_directories(destination_parent, ec);
|
||||
if (ec)
|
||||
{
|
||||
return {Strings::format(
|
||||
"Error: while checking out baseline %s\nError: while creating directories %s: %s",
|
||||
commit_sha,
|
||||
fs::u8string(destination_parent),
|
||||
ec.message()),
|
||||
expected_right_tag};
|
||||
}
|
||||
fs.write_contents(destination_tmp, *contents, ec);
|
||||
if (ec)
|
||||
{
|
||||
return {Strings::format("Error: while checking out baseline %s\nError: while writing %s: %s",
|
||||
commit_sha,
|
||||
fs::u8string(destination_tmp),
|
||||
ec.message()),
|
||||
expected_right_tag};
|
||||
}
|
||||
fs.rename(destination_tmp, destination, ec);
|
||||
if (ec)
|
||||
{
|
||||
return {Strings::format("Error: while checking out baseline %s\nError: while renaming %s to %s: %s",
|
||||
commit_sha,
|
||||
fs::u8string(destination_tmp),
|
||||
fs::u8string(destination),
|
||||
ec.message()),
|
||||
expected_right_tag};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Checks::exit_with_message(
|
||||
VCPKG_LINE_INFO, "Error: while checking out baseline '%s':\n%s", treeish, maybe_contents.error());
|
||||
return {Strings::format("Error: while checking out baseline '%s':\n%s\nThis may be fixed by updating "
|
||||
"vcpkg to the latest master via `git pull`.",
|
||||
treeish,
|
||||
maybe_contents.error()),
|
||||
expected_right_tag};
|
||||
}
|
||||
}
|
||||
return destination;
|
||||
}
|
||||
|
||||
fs::path VcpkgPaths::git_checkout_port(Files::Filesystem& fs, StringView port_name, StringView git_tree) const
|
||||
ExpectedS<fs::path> VcpkgPaths::git_checkout_port(StringView port_name,
|
||||
StringView git_tree,
|
||||
const fs::path& dot_git_dir) const
|
||||
{
|
||||
/* Clone a new vcpkg repository instance using the local instance as base.
|
||||
*
|
||||
* The `--git-dir` directory will store all the Git metadata files,
|
||||
* and the `--work-tree` is the directory where files will be checked out.
|
||||
/* Check out a git tree into the versioned port recipes folder
|
||||
*
|
||||
* Since we are checking a git tree object, all files will be checked out to the root of `work-tree`.
|
||||
* Because of that, it makes sense to use the git hash as the name for the directory.
|
||||
*/
|
||||
const fs::path& local_repo = this->root;
|
||||
fs::path destination = this->versions_output / fs::u8path(git_tree) / fs::u8path(port_name);
|
||||
|
||||
if (!fs.exists(destination / "CONTROL") && !fs.exists(destination / "vcpkg.json"))
|
||||
Files::Filesystem& fs = get_filesystem();
|
||||
fs::path destination = this->versions_output / fs::u8path(port_name) / fs::u8path(git_tree);
|
||||
if (fs.exists(destination))
|
||||
{
|
||||
git_checkout_object(
|
||||
*this, git_tree, local_repo, destination, this->versions_dot_git_dir, this->versions_work_tree);
|
||||
return destination;
|
||||
}
|
||||
|
||||
const fs::path destination_tmp =
|
||||
this->versions_output / fs::u8path(port_name) / fs::u8path(Strings::concat(git_tree, ".tmp"));
|
||||
const fs::path destination_tar =
|
||||
this->versions_output / fs::u8path(port_name) / fs::u8path(Strings::concat(git_tree, ".tar"));
|
||||
#define PRELUDE "Error: while checking out port ", port_name, " with git tree ", git_tree, "\n"
|
||||
std::error_code ec;
|
||||
fs::path failure_point;
|
||||
fs.remove_all(destination_tmp, ec, failure_point);
|
||||
if (ec)
|
||||
{
|
||||
return {Strings::concat(PRELUDE, "Error: while removing ", fs::u8string(failure_point), ": ", ec.message()),
|
||||
expected_right_tag};
|
||||
}
|
||||
fs.create_directories(destination_tmp, ec);
|
||||
if (ec)
|
||||
{
|
||||
return {
|
||||
Strings::concat(
|
||||
PRELUDE, "Error: while creating directories ", fs::u8string(destination_tmp), ": ", ec.message()),
|
||||
expected_right_tag};
|
||||
}
|
||||
|
||||
System::CmdLineBuilder tar_cmd_builder = git_cmd_builder(*this, dot_git_dir, dot_git_dir)
|
||||
.string_arg("archive")
|
||||
.string_arg(git_tree)
|
||||
.string_arg("-o")
|
||||
.path_arg(destination_tar);
|
||||
const auto tar_output = System::cmd_execute_and_capture_output(tar_cmd_builder);
|
||||
if (tar_output.exit_code != 0)
|
||||
{
|
||||
return {Strings::concat(PRELUDE, "Error: Failed to tar port directory\n", tar_output.output),
|
||||
expected_right_tag};
|
||||
}
|
||||
|
||||
System::CmdLineBuilder extract_cmd_builder;
|
||||
extract_cmd_builder.path_arg(this->get_tool_exe(Tools::CMAKE))
|
||||
.string_arg("-E")
|
||||
.string_arg("tar")
|
||||
.string_arg("xf")
|
||||
.path_arg(destination_tar);
|
||||
|
||||
const auto extract_output =
|
||||
System::cmd_execute_and_capture_output(extract_cmd_builder, System::InWorkingDirectory{destination_tmp});
|
||||
if (extract_output.exit_code != 0)
|
||||
{
|
||||
return {Strings::concat(PRELUDE, "Error: Failed to extract port directory\n", extract_output.output),
|
||||
expected_right_tag};
|
||||
}
|
||||
fs.remove(destination_tar, ec);
|
||||
if (ec)
|
||||
{
|
||||
return {
|
||||
Strings::concat(PRELUDE, "Error: while removing ", fs::u8string(destination_tar), ": ", ec.message()),
|
||||
expected_right_tag};
|
||||
}
|
||||
fs.rename(destination_tmp, destination, ec);
|
||||
if (ec)
|
||||
{
|
||||
return {Strings::concat(PRELUDE,
|
||||
"Error: while renaming ",
|
||||
fs::u8string(destination_tmp),
|
||||
" to ",
|
||||
fs::u8string(destination),
|
||||
": ",
|
||||
ec.message()),
|
||||
expected_right_tag};
|
||||
}
|
||||
|
||||
return destination;
|
||||
#undef PRELUDE
|
||||
}
|
||||
|
||||
ExpectedS<std::string> VcpkgPaths::git_fetch_from_remote_registry(StringView repo, StringView treeish) const
|
||||
@ -757,7 +813,7 @@ If you wish to silence this error and use classic mode, you can:
|
||||
auto lock_file = work_tree / fs::u8path(".vcpkg-lock");
|
||||
|
||||
std::error_code ec;
|
||||
auto guard = Files::ExclusiveFileLock(Files::ExclusiveFileLock::Wait::Yes, fs, lock_file, ec);
|
||||
Files::ExclusiveFileLock guard(Files::ExclusiveFileLock::Wait::Yes, fs, lock_file, ec);
|
||||
|
||||
System::CmdLineBuilder fetch_git_ref =
|
||||
git_cmd_builder(*this, dot_git_dir, work_tree).string_arg("fetch").string_arg("--").string_arg(repo);
|
||||
|
Loading…
x
Reference in New Issue
Block a user