Implement pseudo-lockfiles (#69)
* Initial implementation of pseudo-lockfiles * Migrate e2e test collateral * Add git registry parsing unit tests * Increase lockfile value validation (40 hex) * Fix MSVC Analyze * Introduce vcpkg-lock.json e2e testing Add redirection for the registries cache directory via X_VCPKG_REGISTRIES_CACHE * Fix unit tests * Handle JSON escaping in lock file test * Rename VTPResult to VersionsTreePathResult * Format all version-files collateral Co-authored-by: Robert Schumacher <ras0219@outlook.com>
This commit is contained in:
Родитель
b2c742187d
Коммит
ee93e8f487
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"name": "default-baseline-test",
|
||||
"version-string": "0",
|
||||
"builtin-baseline": "fca18ba3572f8aebe3b8158c359db62a7e26134e",
|
||||
"dependencies": [
|
||||
"zlib"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"name": "default-baseline-test-2",
|
||||
"version-string": "0",
|
||||
"builtin-baseline": "d5cd6b8c74ee548cfc9ff83cefdac4843cc1503f",
|
||||
"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 @@
|
|||
set(VCPKG_POLICY_EMPTY_PACKAGE enabled)
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "cat",
|
||||
"version": "1.0"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
set(VCPKG_POLICY_EMPTY_PACKAGE enabled)
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "dog",
|
||||
"version-date": "2001-01-01"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
set(VCPKG_POLICY_EMPTY_PACKAGE enabled)
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "duck",
|
||||
"version-string": "mallard"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
set(VCPKG_POLICY_EMPTY_PACKAGE enabled)
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "mouse",
|
||||
"version-semver": "1.0.0"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
set(VCPKG_POLICY_EMPTY_PACKAGE enabled)
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "cat",
|
||||
"version": "1.0"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
set(VCPKG_POLICY_EMPTY_PACKAGE enabled)
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"name": "dog",
|
||||
"version-date": "2001-01-01",
|
||||
"port-version": 1
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
set(VCPKG_POLICY_EMPTY_PACKAGE enabled)
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "duck",
|
||||
"version-string": "mallard"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
set(VCPKG_POLICY_EMPTY_PACKAGE enabled)
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "ferret",
|
||||
"version": "1"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
set(VCPKG_POLICY_EMPTY_PACKAGE enabled)
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"name": "fish",
|
||||
"version-string": "1.0.0",
|
||||
"description": "This description causes an intentional discrepancy between the local SHA and the SHA in fish.json for version 1.0.0"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
set(VCPKG_POLICY_EMPTY_PACKAGE enabled)
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "mouse",
|
||||
"version-semver": "1.0.0"
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"default": {
|
||||
"cat": {
|
||||
"baseline": "1.0",
|
||||
"port-version": 0
|
||||
},
|
||||
"dog": {
|
||||
"baseline": "2001-01-01",
|
||||
"port-version": 0
|
||||
},
|
||||
"duck": {
|
||||
"baseline": "mallard",
|
||||
"port-version": 0
|
||||
},
|
||||
"mouse": {
|
||||
"baseline": "1.0.0",
|
||||
"port-version": 0
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"versions": [
|
||||
{
|
||||
"git-tree": "e635ee8b3277303dfc7231d526e04f1102b56605",
|
||||
"version": "1.0",
|
||||
"port-version": 0
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"versions": [
|
||||
{
|
||||
"git-tree": "d6c3e716b6fbd5f8a0690376b6fdadf8a69204d8",
|
||||
"version-date": "2001-01-01",
|
||||
"port-version": 0
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"versions": [
|
||||
{
|
||||
"git-tree": "e2974a551846257708d1e0dbdf81cfd76abf8e97",
|
||||
"version-string": "mallard",
|
||||
"port-version": 0
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"versions": [
|
||||
{
|
||||
"git-tree": "f8882feb032d2aacd83340decb0966c2dacc3fd6",
|
||||
"version-semver": "1.0.0",
|
||||
"port-version": 0
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"default": {
|
||||
"cat": {
|
||||
"baseline": "1.0",
|
||||
"port-version": 0
|
||||
},
|
||||
"dog": {
|
||||
"baseline": "2001-01-01",
|
||||
"port-version": 0
|
||||
},
|
||||
"duck": {
|
||||
"baseline": "mallard",
|
||||
"port-version": 0
|
||||
},
|
||||
"fish": {
|
||||
"baseline": "1.0.0",
|
||||
"port-version": 0
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"versions": [
|
||||
{
|
||||
"git-tree": "e635ee8b3277303dfc7231d526e04f1102b56605",
|
||||
"version": "1.0",
|
||||
"port-version": 0
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"versions": [
|
||||
{
|
||||
"git-tree": "e170a2ed0da7ba5d434c4a0a98ffd7a3159e3200",
|
||||
"version-date": "2001-01-01",
|
||||
"port-version": 0
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"versions": [
|
||||
{
|
||||
"git-tree": "cf3be634f203c1b4152b65ec7700d5695a1fca5c",
|
||||
"version-string": "1.0.0",
|
||||
"port-version": 0
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"versions": [
|
||||
{
|
||||
"git-tree": "f8882feb032d2aacd83340decb0966c2dacc3fd6",
|
||||
"version-semver": "1.0.0",
|
||||
"port-version": 0
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"name": "without-default-baseline-test-2",
|
||||
"version-string": "0",
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
# Test vcpkg create
|
||||
$Script:CurrentTest = "create zlib"
|
||||
Write-Host $Script:CurrentTest
|
||||
./vcpkg --x-builtin-ports-root=$TestingRoot/ports create zlib https://github.com/madler/zlib/archive/v1.2.11.tar.gz zlib-1.2.11.tar.gz
|
||||
Run-Vcpkg --x-builtin-ports-root=$TestingRoot/ports create zlib https://github.com/madler/zlib/archive/v1.2.11.tar.gz zlib-1.2.11.tar.gz
|
||||
Throw-IfFailed
|
||||
|
||||
Require-FileExists "$TestingRoot/ports/zlib/portfile.cmake"
|
||||
|
|
|
@ -107,6 +107,9 @@ try
|
|||
$CurrentTest = 'git commit'
|
||||
git @gitConfigOptions commit --amend --no-edit
|
||||
Throw-IfFailed
|
||||
|
||||
$gitBaselineCommit = git rev-parse HEAD
|
||||
$gitRefVersionsObject = git rev-parse HEAD:versions
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -176,6 +179,7 @@ try
|
|||
@{
|
||||
"kind" = "git";
|
||||
"repository" = $gitRegistryUpstream;
|
||||
"baseline" = $gitBaselineCommit;
|
||||
"packages" = @( "vcpkg-internal-e2e-test-port" )
|
||||
}
|
||||
)
|
||||
|
@ -183,6 +187,37 @@ try
|
|||
New-Item -Path 'vcpkg-configuration.json' -ItemType File `
|
||||
-Value (ConvertTo-Json -Depth 5 -InputObject $vcpkgConfigurationJson)
|
||||
|
||||
Run-Vcpkg install @builtinRegistryArgs '--feature-flags=registries,manifests' --dry-run
|
||||
Throw-IfFailed
|
||||
Require-FileExists $env:X_VCPKG_REGISTRIES_CACHE/git-trees/$vcpkgInternalE2eTestPortGitTree
|
||||
# This is both the selected baseline as well as the current HEAD
|
||||
Require-FileExists $env:X_VCPKG_REGISTRIES_CACHE/git-trees/$gitRefVersionsObject
|
||||
# Dry run does not create a lockfile
|
||||
Require-FileNotExists $installRoot/vcpkg/vcpkg-lock.json
|
||||
|
||||
Run-Vcpkg install @builtinRegistryArgs '--feature-flags=registries,manifests'
|
||||
Throw-IfFailed
|
||||
Require-FileEquals $installRoot/vcpkg/vcpkg-lock.json "{`n $(ConvertTo-Json $gitRegistryUpstream): `"$gitBaselineCommit`"`n}`n"
|
||||
|
||||
# Using the lock file means we can reinstall without pulling from the upstream registry
|
||||
$vcpkgConfigurationJson = @{
|
||||
"default-registry" = $null;
|
||||
"registries" = @(
|
||||
@{
|
||||
"kind" = "git";
|
||||
"repository" = "/"; # An invalid repository
|
||||
"baseline" = $gitBaselineCommit;
|
||||
"packages" = @( "vcpkg-internal-e2e-test-port" )
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Remove-Item -Recurse -Force $installRoot -ErrorAction SilentlyContinue
|
||||
Require-FileNotExists $installRoot
|
||||
New-Item -Path $installRoot/vcpkg -ItemType Directory
|
||||
# We pre-seed the install root with a lockfile for the invalid repository, so it isn't actually fetched from
|
||||
New-Item -Path $installRoot/vcpkg/vcpkg-lock.json -ItemType File `
|
||||
-Value "{`n `"/`": `"$gitBaselineCommit`"`n}`n"
|
||||
Run-Vcpkg install @builtinRegistryArgs '--feature-flags=registries,manifests'
|
||||
Throw-IfFailed
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
##### Test spaces in the path
|
||||
$Script:CurrentTest = "zlib with spaces in path"
|
||||
Write-Host $Script:CurrentTest
|
||||
./vcpkg install zlib "--triplet" $Triplet `
|
||||
Run-Vcpkg install zlib "--triplet" $Triplet `
|
||||
"--no-binarycaching" `
|
||||
"--x-buildtrees-root=$TestingRoot/build Trees" `
|
||||
"--x-install-root=$TestingRoot/instalL ed" `
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
. $PSScriptRoot/../end-to-end-tests-prelude.ps1
|
||||
|
||||
$versionFilesPath = "$env:VCPKG_ROOT/scripts/testing/version-files"
|
||||
$versionFilesPath = "$PSScriptRoot/../e2e_ports/version-files"
|
||||
|
||||
# Test verify versions
|
||||
mkdir $VersionFilesRoot
|
||||
mkdir $VersionFilesRoot | Out-Null
|
||||
Copy-Item -Recurse "$versionFilesPath/versions_incomplete" $VersionFilesRoot
|
||||
$portsRedirectArgsOK = @(
|
||||
"--feature-flags=versions",
|
||||
|
@ -17,51 +17,51 @@ $portsRedirectArgsIncomplete = @(
|
|||
)
|
||||
$CurrentTest = "x-verify-ci-versions (All files OK)"
|
||||
Write-Host $CurrentTest
|
||||
./vcpkg $portsRedirectArgsOK x-ci-verify-versions --verbose
|
||||
Run-Vcpkg @portsRedirectArgsOK x-ci-verify-versions --verbose --debug
|
||||
Throw-IfFailed
|
||||
|
||||
$CurrentTest = "x-verify-ci-versions (Incomplete)"
|
||||
./vcpkg $portsRedirectArgsIncomplete x-ci-verify-versions --verbose
|
||||
Run-Vcpkg @portsRedirectArgsIncomplete x-ci-verify-versions --verbose
|
||||
Throw-IfNotFailed
|
||||
|
||||
$CurrentTest = "x-add-version cat"
|
||||
# Do not fail if there's nothing to update
|
||||
./vcpkg $portsRedirectArgsIncomplete x-add-version cat --skip-formatting-check
|
||||
Run-Vcpkg @portsRedirectArgsIncomplete x-add-version cat
|
||||
Throw-IfFailed
|
||||
|
||||
$CurrentTest = "x-add-version dog"
|
||||
# Local version is not in baseline and versions file
|
||||
./vcpkg $portsRedirectArgsIncomplete x-add-version dog --skip-formatting-check
|
||||
Run-Vcpkg @portsRedirectArgsIncomplete x-add-version dog
|
||||
Throw-IfFailed
|
||||
|
||||
$CurrentTest = "x-add-version duck"
|
||||
# Missing versions file
|
||||
./vcpkg $portsRedirectArgsIncomplete x-add-version duck --skip-formatting-check
|
||||
Run-Vcpkg @portsRedirectArgsIncomplete x-add-version duck
|
||||
Throw-IfFailed
|
||||
|
||||
$CurrentTest = "x-add-version ferret"
|
||||
# Missing versions file and missing baseline entry
|
||||
./vcpkg $portsRedirectArgsIncomplete x-add-version ferret --skip-formatting-check
|
||||
Run-Vcpkg @portsRedirectArgsIncomplete x-add-version ferret
|
||||
Throw-IfFailed
|
||||
|
||||
$CurrentTest = "x-add-version fish (must fail)"
|
||||
# Discrepancy between local SHA and SHA in fish.json. Requires --overwrite-version.
|
||||
$out = ./vcpkg $portsRedirectArgsIncomplete x-add-version fish --skip-formatting-check
|
||||
$out = Run-Vcpkg @portsRedirectArgsIncomplete x-add-version fish
|
||||
Throw-IfNotFailed
|
||||
$CurrentTest = "x-add-version fish --overwrite-version"
|
||||
./vcpkg $portsRedirectArgsIncomplete x-add-version fish --overwrite-version --skip-formatting-check
|
||||
Run-Vcpkg @portsRedirectArgsIncomplete x-add-version fish --overwrite-version
|
||||
Throw-IfFailed
|
||||
|
||||
$CurrentTest = "x-add-version mouse"
|
||||
# Missing baseline entry
|
||||
./vcpkg $portsRedirectArgsIncomplete x-add-version mouse --skip-formatting-check
|
||||
Run-Vcpkg @portsRedirectArgsIncomplete x-add-version mouse
|
||||
Throw-IfFailed
|
||||
# Validate changes
|
||||
./vcpkg $portsRedirectArgsIncomplete x-ci-verify-versions --verbose
|
||||
Run-Vcpkg @portsRedirectArgsIncomplete x-ci-verify-versions --verbose
|
||||
Throw-IfFailed
|
||||
|
||||
$CurrentTest = "default baseline"
|
||||
$out = ./vcpkg $commonArgs "--feature-flags=versions" install --x-manifest-root=$versionFilesPath/default-baseline-1 2>&1 | Out-String
|
||||
$out = Run-Vcpkg @commonArgs "--feature-flags=versions" install --x-manifest-root=$versionFilesPath/default-baseline-1 2>&1 | Out-String
|
||||
Throw-IfNotFailed
|
||||
if ($out -notmatch ".*Error: while checking out baseline.*")
|
||||
{
|
||||
|
@ -76,7 +76,7 @@ foreach ($opt_registries in @("",",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 `
|
||||
Run-Vcpkg @commonArgs "--feature-flags=versions$opt_registries" install `
|
||||
"--dry-run" `
|
||||
"--x-manifest-root=$versionFilesPath/without-default-baseline-2" `
|
||||
"--x-builtin-registry-versions-dir=$versionFilesPath/default-baseline-2/versions"
|
||||
|
@ -84,7 +84,7 @@ foreach ($opt_registries in @("",",registries"))
|
|||
Require-FileNotExists $buildtreesRoot/versioning
|
||||
|
||||
$CurrentTest = "default baseline 2"
|
||||
./vcpkg $commonArgs "--feature-flags=versions$opt_registries" install `
|
||||
Run-Vcpkg @commonArgs "--feature-flags=versions$opt_registries" install `
|
||||
"--dry-run" `
|
||||
"--x-manifest-root=$versionFilesPath/default-baseline-2" `
|
||||
"--x-builtin-registry-versions-dir=$versionFilesPath/default-baseline-2/versions"
|
||||
|
@ -92,7 +92,7 @@ foreach ($opt_registries in @("",",registries"))
|
|||
Require-FileExists $buildtreesRoot/versioning
|
||||
|
||||
$CurrentTest = "using version features fails without flag"
|
||||
./vcpkg $commonArgs "--feature-flags=-versions$opt_registries" install `
|
||||
Run-Vcpkg @commonArgs "--feature-flags=-versions$opt_registries" install `
|
||||
"--dry-run" `
|
||||
"--x-manifest-root=$versionFilesPath/default-baseline-2" `
|
||||
"--x-builtin-registry-versions-dir=$versionFilesPath/default-baseline-2/versions"
|
||||
|
|
|
@ -5,7 +5,7 @@ $packagesRoot = Join-Path $TestingRoot 'packages'
|
|||
$NuGetRoot = Join-Path $TestingRoot 'nuget'
|
||||
$NuGetRoot2 = Join-Path $TestingRoot 'nuget2'
|
||||
$ArchiveRoot = Join-Path $TestingRoot 'archives'
|
||||
$VersionFilesRoot = Join-Path $env:VCPKG_ROOT 'version-test'
|
||||
$VersionFilesRoot = Join-Path $TestingRoot 'version-test'
|
||||
$commonArgs = @(
|
||||
"--triplet",
|
||||
$Triplet,
|
||||
|
@ -16,41 +16,66 @@ $commonArgs = @(
|
|||
"--overlay-triplets=$PSScriptRoot/e2e_ports/triplets"
|
||||
)
|
||||
$Script:CurrentTest = 'unassigned'
|
||||
$env:X_VCPKG_REGISTRIES_CACHE = Join-Path $TestingRoot 'registries'
|
||||
|
||||
function Refresh-TestRoot {
|
||||
Remove-Item -Recurse -Force $TestingRoot -ErrorAction SilentlyContinue
|
||||
mkdir $TestingRoot | Out-Null
|
||||
mkdir $env:X_VCPKG_REGISTRIES_CACHE | Out-Null
|
||||
mkdir $NuGetRoot | Out-Null
|
||||
}
|
||||
|
||||
function Write-Stack {
|
||||
Get-PSCallStack | % {
|
||||
Write-Host "$($_.ScriptName):$($_.ScriptLineNumber): $($_.FunctionName)"
|
||||
}
|
||||
}
|
||||
|
||||
function Require-FileExists {
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
[string]$File
|
||||
)
|
||||
if (-Not (Test-Path $File)) {
|
||||
Write-Stack
|
||||
throw "'$Script:CurrentTest' failed to create file '$File'"
|
||||
}
|
||||
}
|
||||
|
||||
function Require-FileEquals {
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
[string]$File,
|
||||
[string]$Content
|
||||
)
|
||||
Require-FileExists $File
|
||||
if ((Get-Content $File -Raw) -ne $Content) {
|
||||
Write-Stack
|
||||
throw "'$Script:CurrentTest' file '$File' did not have the correct contents"
|
||||
}
|
||||
}
|
||||
|
||||
function Require-FileNotExists {
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
[string]$File
|
||||
)
|
||||
if (Test-Path $File) {
|
||||
Write-Stack
|
||||
throw "'$Script:CurrentTest' should not have created file '$File'"
|
||||
}
|
||||
}
|
||||
|
||||
function Throw-IfFailed {
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Stack
|
||||
throw "'$Script:CurrentTest' had a step with a nonzero exit code"
|
||||
}
|
||||
}
|
||||
|
||||
function Throw-IfNotFailed {
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Stack
|
||||
throw "'$Script:CurrentTest' had a step with an unexpectedly zero exit code"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,7 +71,8 @@ $envvars_clear = @(
|
|||
"VCPKG_KEEP_ENV_VARS",
|
||||
"VCPKG_ROOT",
|
||||
"VCPKG_FEATURE_FLAGS",
|
||||
"VCPKG_DISABLE_METRICS"
|
||||
"VCPKG_DISABLE_METRICS",
|
||||
"X_VCPKG_REGISTRIES_CACHE"
|
||||
)
|
||||
$envvars = $envvars_clear + @("VCPKG_DOWNLOADS")
|
||||
|
||||
|
|
|
@ -182,6 +182,10 @@ namespace vcpkg::Files
|
|||
std::error_code& ec) = 0;
|
||||
void write_contents(const fs::path& path, const std::string& data, LineInfo linfo);
|
||||
virtual void write_contents(const fs::path& file_path, const std::string& data, std::error_code& ec) = 0;
|
||||
void write_rename_contents(const fs::path& path,
|
||||
const fs::path& tmpext,
|
||||
const std::string& data,
|
||||
LineInfo linfo);
|
||||
void write_contents_and_dirs(const fs::path& path, const std::string& data, LineInfo linfo);
|
||||
virtual void write_contents_and_dirs(const fs::path& file_path,
|
||||
const std::string& data,
|
||||
|
|
|
@ -6,4 +6,5 @@ namespace vcpkg
|
|||
struct RegistryImplementation;
|
||||
struct Registry;
|
||||
struct RegistrySet;
|
||||
struct LockFile;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,31 @@
|
|||
|
||||
namespace vcpkg
|
||||
{
|
||||
struct LockFile
|
||||
{
|
||||
struct EntryData
|
||||
{
|
||||
std::string value;
|
||||
bool stale;
|
||||
};
|
||||
struct Entry
|
||||
{
|
||||
LockFile* lockfile;
|
||||
std::map<std::string, EntryData, std::less<>>::iterator data;
|
||||
|
||||
const std::string& value() const { return data->second.value; }
|
||||
bool stale() const { return data->second.stale; }
|
||||
const std::string& uri() const { return data->first; }
|
||||
|
||||
void ensure_up_to_date(const VcpkgPaths& paths) const;
|
||||
};
|
||||
|
||||
Entry get_or_fetch(const VcpkgPaths& paths, StringView key);
|
||||
|
||||
std::map<std::string, EntryData, std::less<>> lockdata;
|
||||
bool modified = false;
|
||||
};
|
||||
|
||||
struct RegistryEntry
|
||||
{
|
||||
virtual View<VersionT> get_port_versions() const = 0;
|
||||
|
@ -109,4 +134,6 @@ namespace vcpkg
|
|||
StringView port_name);
|
||||
|
||||
ExpectedS<std::map<std::string, VersionT, std::less<>>> get_builtin_baseline(const VcpkgPaths& paths);
|
||||
|
||||
bool is_git_commit_sha(StringView sv);
|
||||
}
|
||||
|
|
|
@ -86,6 +86,9 @@ namespace vcpkg
|
|||
StringView get_ports_cmake_hash() const;
|
||||
const fs::path get_triplet_file_path(Triplet triplet) const;
|
||||
|
||||
LockFile& get_installed_lockfile() const;
|
||||
void flush_lockfile() const;
|
||||
|
||||
fs::path original_cwd;
|
||||
fs::path root;
|
||||
fs::path manifest_root_dir;
|
||||
|
@ -141,8 +144,10 @@ namespace vcpkg
|
|||
|
||||
// Git manipulation for remote registries
|
||||
// runs `git fetch {uri} {treeish}`, and returns the hash of FETCH_HEAD.
|
||||
// If `treeish` is empty, then just runs `git fetch {uri}`
|
||||
ExpectedS<std::string> git_fetch_from_remote_registry(StringView uri, StringView treeish = {}) const;
|
||||
// Use {treeish} of "HEAD" for the default branch
|
||||
ExpectedS<std::string> git_fetch_from_remote_registry(StringView uri, StringView treeish) const;
|
||||
// runs `git fetch {uri} {treeish}`
|
||||
Optional<std::string> git_fetch(StringView uri, StringView treeish) const;
|
||||
ExpectedS<std::string> git_show_from_remote_registry(StringView hash,
|
||||
const fs::path& relative_path_to_file) const;
|
||||
ExpectedS<std::string> git_find_object_id_for_remote_registry_path(StringView hash,
|
||||
|
@ -177,13 +182,5 @@ namespace vcpkg
|
|||
|
||||
private:
|
||||
std::unique_ptr<details::VcpkgPathsImpl> m_pimpl;
|
||||
|
||||
static void git_checkout_subpath(const VcpkgPaths& paths,
|
||||
StringView commit_sha,
|
||||
const fs::path& subpath,
|
||||
const fs::path& local_repo,
|
||||
const fs::path& destination,
|
||||
const fs::path& dot_git_dir,
|
||||
const fs::path& work_tree);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -76,59 +76,109 @@ TEST_CASE ("registry_set_selects_registry", "[registries]")
|
|||
|
||||
TEST_CASE ("registry_parsing", "[registries]")
|
||||
{
|
||||
Json::Reader r;
|
||||
auto registry_impl_des = get_registry_implementation_deserializer({});
|
||||
{
|
||||
Json::Reader r;
|
||||
|
||||
auto test_json = parse_json(R"json(
|
||||
auto test_json = parse_json(R"json(
|
||||
{
|
||||
"kind": "builtin"
|
||||
}
|
||||
)json");
|
||||
auto registry_impl = r.visit(test_json, *registry_impl_des);
|
||||
REQUIRE(registry_impl);
|
||||
CHECK(*registry_impl.get());
|
||||
CHECK(r.errors().empty());
|
||||
auto registry_impl = r.visit(test_json, *registry_impl_des);
|
||||
REQUIRE(registry_impl);
|
||||
CHECK(*registry_impl.get());
|
||||
CHECK(r.errors().empty());
|
||||
|
||||
test_json = parse_json(R"json(
|
||||
test_json = parse_json(R"json(
|
||||
{
|
||||
"kind": "builtin",
|
||||
"baseline": "hi"
|
||||
}
|
||||
)json");
|
||||
registry_impl = r.visit(test_json, *registry_impl_des);
|
||||
REQUIRE(registry_impl);
|
||||
CHECK(*registry_impl.get());
|
||||
CHECK(r.errors().empty());
|
||||
registry_impl = r.visit(test_json, *registry_impl_des);
|
||||
REQUIRE(registry_impl);
|
||||
CHECK(*registry_impl.get());
|
||||
CHECK(r.errors().empty());
|
||||
|
||||
test_json = parse_json(R"json(
|
||||
test_json = parse_json(R"json(
|
||||
{
|
||||
"kind": "builtin",
|
||||
"path": "a/b"
|
||||
}
|
||||
)json");
|
||||
registry_impl = r.visit(test_json, *registry_impl_des);
|
||||
CHECK_FALSE(r.errors().empty());
|
||||
r.errors().clear();
|
||||
registry_impl = r.visit(test_json, *registry_impl_des);
|
||||
CHECK_FALSE(r.errors().empty());
|
||||
r.errors().clear();
|
||||
|
||||
test_json = parse_json(R"json(
|
||||
test_json = parse_json(R"json(
|
||||
{
|
||||
"kind": "filesystem",
|
||||
"path": "a/b/c"
|
||||
}
|
||||
)json");
|
||||
registry_impl = r.visit(test_json, *registry_impl_des);
|
||||
REQUIRE(registry_impl);
|
||||
CHECK(*registry_impl.get());
|
||||
CHECK(r.errors().empty());
|
||||
registry_impl = r.visit(test_json, *registry_impl_des);
|
||||
REQUIRE(registry_impl);
|
||||
CHECK(*registry_impl.get());
|
||||
CHECK(r.errors().empty());
|
||||
|
||||
test_json = parse_json(R"json(
|
||||
test_json = parse_json(R"json(
|
||||
{
|
||||
"kind": "filesystem",
|
||||
"path": "/a/b/c"
|
||||
}
|
||||
)json");
|
||||
registry_impl = r.visit(test_json, *registry_impl_des);
|
||||
registry_impl = r.visit(test_json, *registry_impl_des);
|
||||
REQUIRE(registry_impl);
|
||||
CHECK(*registry_impl.get());
|
||||
CHECK(r.errors().empty());
|
||||
}
|
||||
|
||||
auto test_json = parse_json(R"json(
|
||||
{
|
||||
"kind": "git"
|
||||
}
|
||||
)json");
|
||||
{
|
||||
Json::Reader r;
|
||||
r.visit(test_json, *registry_impl_des);
|
||||
CHECK(!r.errors().empty());
|
||||
}
|
||||
test_json = parse_json(R"json(
|
||||
{
|
||||
"kind": "git",
|
||||
"repository": "abc"
|
||||
}
|
||||
)json");
|
||||
{
|
||||
Json::Reader r;
|
||||
r.visit(test_json, *registry_impl_des);
|
||||
CHECK(!r.errors().empty());
|
||||
}
|
||||
|
||||
test_json = parse_json(R"json(
|
||||
{
|
||||
"kind": "git",
|
||||
"baseline": "123"
|
||||
}
|
||||
)json");
|
||||
{
|
||||
Json::Reader r;
|
||||
r.visit(test_json, *registry_impl_des);
|
||||
CHECK(!r.errors().empty());
|
||||
}
|
||||
|
||||
test_json = parse_json(R"json(
|
||||
{
|
||||
"kind": "git",
|
||||
"repository": "abc",
|
||||
"baseline": "123"
|
||||
}
|
||||
)json");
|
||||
Json::Reader r;
|
||||
auto registry_impl = r.visit(test_json, *registry_impl_des);
|
||||
REQUIRE(registry_impl);
|
||||
CHECK(*registry_impl.get());
|
||||
INFO(Strings::join("\n", r.errors()));
|
||||
CHECK(r.errors().empty());
|
||||
}
|
||||
|
|
|
@ -487,6 +487,16 @@ namespace vcpkg::Files
|
|||
Checks::exit_with_message(linfo, "error writing file: %s: %s", fs::u8string(path), ec.message());
|
||||
}
|
||||
}
|
||||
void Filesystem::write_rename_contents(const fs::path& path,
|
||||
const fs::path& tmpname,
|
||||
const std::string& data,
|
||||
LineInfo linfo)
|
||||
{
|
||||
auto tmp_path = path;
|
||||
tmp_path.replace_filename(tmpname);
|
||||
this->write_contents(tmp_path, data, linfo);
|
||||
this->rename(tmp_path, path, linfo);
|
||||
}
|
||||
void Filesystem::write_contents_and_dirs(const fs::path& path, const std::string& data, LineInfo linfo)
|
||||
{
|
||||
std::error_code ec;
|
||||
|
|
|
@ -236,8 +236,8 @@ namespace vcpkg::Commands::CIVerifyVersions
|
|||
port_name,
|
||||
fs::u8string(versions_file_path),
|
||||
top_entry.first.versiont,
|
||||
local_git_tree,
|
||||
top_entry.second,
|
||||
local_git_tree,
|
||||
port_name),
|
||||
expected_right_tag,
|
||||
};
|
||||
|
|
|
@ -104,6 +104,8 @@ namespace vcpkg::Commands::SetInstalled
|
|||
Checks::exit_success(VCPKG_LINE_INFO);
|
||||
}
|
||||
|
||||
paths.flush_lockfile();
|
||||
|
||||
Install::track_install_plan(action_plan);
|
||||
|
||||
const auto summary = Install::perform(args,
|
||||
|
|
|
@ -1043,6 +1043,8 @@ namespace vcpkg::Install
|
|||
Checks::exit_success(VCPKG_LINE_INFO);
|
||||
}
|
||||
|
||||
paths.flush_lockfile();
|
||||
|
||||
track_install_plan(action_plan);
|
||||
|
||||
const InstallSummary summary =
|
||||
|
|
|
@ -22,21 +22,29 @@ namespace
|
|||
|
||||
static const fs::path registry_versions_dir_name = fs::u8path("versions");
|
||||
|
||||
// this class is an implementation detail of `BuiltinRegistryEntry`;
|
||||
// when `BuiltinRegistryEntry` is using a port versions file for a port,
|
||||
// it uses this as it's underlying type;
|
||||
// when `BuiltinRegistryEntry` is using a port tree, it uses the scfl
|
||||
struct GitRegistry;
|
||||
|
||||
struct GitRegistryEntry final : RegistryEntry
|
||||
{
|
||||
View<VersionT> get_port_versions() const override { return port_versions; }
|
||||
GitRegistryEntry(const GitRegistry& reg, StringView name);
|
||||
|
||||
View<VersionT> get_port_versions() const override;
|
||||
ExpectedS<fs::path> get_path_to_version(const VcpkgPaths&, const VersionT& version) const override;
|
||||
|
||||
private:
|
||||
void fill_data_from_path(const Files::Filesystem& fs, const fs::path& port_versions_path) const;
|
||||
|
||||
std::string port_name;
|
||||
|
||||
const GitRegistry& parent;
|
||||
|
||||
// Indicates whether port_versions and git_trees were filled in with stale (i.e. lock) data.
|
||||
mutable bool stale;
|
||||
|
||||
// these two map port versions to git trees
|
||||
// these shall have the same size, and git_trees[i] shall be the git tree for port_versions[i]
|
||||
std::vector<VersionT> port_versions;
|
||||
std::vector<std::string> git_trees;
|
||||
mutable std::vector<VersionT> port_versions;
|
||||
mutable std::vector<std::string> git_trees;
|
||||
};
|
||||
|
||||
struct GitRegistry final : RegistryImplementation
|
||||
|
@ -54,26 +62,22 @@ namespace
|
|||
|
||||
Optional<VersionT> get_baseline_version(const VcpkgPaths&, StringView) const override;
|
||||
|
||||
StringView get_commit_of_repo(const VcpkgPaths& paths) const
|
||||
private:
|
||||
friend struct GitRegistryEntry;
|
||||
|
||||
LockFile::Entry get_lock_entry(const VcpkgPaths& paths) const
|
||||
{
|
||||
return m_commit.get([this, &paths]() -> std::string {
|
||||
auto maybe_hash = paths.git_fetch_from_remote_registry(m_repo);
|
||||
if (!maybe_hash.has_value())
|
||||
{
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO,
|
||||
"Error: Failed to fetch from remote registry `%s`: %s",
|
||||
m_repo,
|
||||
maybe_hash.error());
|
||||
}
|
||||
return std::move(*maybe_hash.get());
|
||||
});
|
||||
return m_lock_entry.get(
|
||||
[this, &paths]() { return paths.get_installed_lockfile().get_or_fetch(paths, m_repo); });
|
||||
}
|
||||
|
||||
fs::path get_versions_tree_path(const VcpkgPaths& paths) const
|
||||
{
|
||||
return m_versions_tree.get([this, &paths]() -> fs::path {
|
||||
auto maybe_tree = paths.git_find_object_id_for_remote_registry_path(get_commit_of_repo(paths),
|
||||
registry_versions_dir_name);
|
||||
auto e = get_lock_entry(paths);
|
||||
e.ensure_up_to_date(paths);
|
||||
auto maybe_tree =
|
||||
paths.git_find_object_id_for_remote_registry_path(e.value(), registry_versions_dir_name);
|
||||
if (!maybe_tree)
|
||||
{
|
||||
Metrics::g_metrics.lock()->track_property("registries-error-no-versions-at-commit", "defined");
|
||||
|
@ -81,7 +85,7 @@ namespace
|
|||
VCPKG_LINE_INFO,
|
||||
"Error: could not find the git tree for `versions` in repo `%s` at commit `%s`: %s",
|
||||
m_repo,
|
||||
get_commit_of_repo(paths),
|
||||
e.value(),
|
||||
maybe_tree.error());
|
||||
}
|
||||
auto maybe_path = paths.git_checkout_object_from_remote_registry(*maybe_tree.get());
|
||||
|
@ -96,11 +100,48 @@ namespace
|
|||
});
|
||||
}
|
||||
|
||||
struct VersionsTreePathResult
|
||||
{
|
||||
fs::path path;
|
||||
bool stale;
|
||||
};
|
||||
|
||||
VersionsTreePathResult get_stale_versions_tree_path(const VcpkgPaths& paths) const
|
||||
{
|
||||
auto e = get_lock_entry(paths);
|
||||
if (!e.stale())
|
||||
{
|
||||
return {get_versions_tree_path(paths), false};
|
||||
}
|
||||
if (!m_stale_versions_tree.has_value())
|
||||
{
|
||||
auto maybe_tree =
|
||||
paths.git_find_object_id_for_remote_registry_path(e.value(), registry_versions_dir_name);
|
||||
if (!maybe_tree)
|
||||
{
|
||||
// This could be caused by git gc or otherwise -- fall back to full fetch
|
||||
return {get_versions_tree_path(paths), false};
|
||||
}
|
||||
auto maybe_path = paths.git_checkout_object_from_remote_registry(*maybe_tree.get());
|
||||
if (!maybe_path)
|
||||
{
|
||||
// This could be caused by git gc or otherwise -- fall back to full fetch
|
||||
return {get_versions_tree_path(paths), false};
|
||||
}
|
||||
m_stale_versions_tree = std::move(*maybe_path.get());
|
||||
}
|
||||
return {*m_stale_versions_tree.get(), true};
|
||||
}
|
||||
|
||||
std::string m_repo;
|
||||
DelayedInit<std::string> m_commit; // TODO: eventually this should end up in the vcpkg-lock.json file
|
||||
DelayedInit<fs::path> m_versions_tree;
|
||||
std::string m_baseline_identifier;
|
||||
DelayedInit<LockFile::Entry> m_lock_entry;
|
||||
mutable Optional<fs::path> m_stale_versions_tree;
|
||||
DelayedInit<fs::path> m_versions_tree;
|
||||
DelayedInit<Baseline> m_baseline;
|
||||
|
||||
// Shared by all child GitRegistryEntry's
|
||||
mutable const VcpkgPaths* m_paths = nullptr;
|
||||
};
|
||||
|
||||
struct BuiltinPortTreeRegistryEntry final : RegistryEntry
|
||||
|
@ -491,101 +532,95 @@ namespace
|
|||
// { GitRegistry::RegistryImplementation
|
||||
std::unique_ptr<RegistryEntry> GitRegistry::get_port_entry(const VcpkgPaths& paths, StringView port_name) const
|
||||
{
|
||||
auto port_versions = get_versions_tree_path(paths);
|
||||
auto maybe_version_entries =
|
||||
load_versions_file(paths.get_filesystem(), VersionDbType::Git, port_versions, port_name);
|
||||
Checks::check_maybe_upgrade(
|
||||
VCPKG_LINE_INFO, maybe_version_entries.has_value(), "Error: " + maybe_version_entries.error());
|
||||
auto version_entries = std::move(maybe_version_entries).value_or_exit(VCPKG_LINE_INFO);
|
||||
if (!m_paths) m_paths = &paths;
|
||||
return std::make_unique<GitRegistryEntry>(*this, port_name);
|
||||
}
|
||||
|
||||
auto res = std::make_unique<GitRegistryEntry>();
|
||||
res->port_name = port_name.to_string();
|
||||
for (auto&& version_entry : version_entries)
|
||||
{
|
||||
res->port_versions.push_back(version_entry.version);
|
||||
res->git_trees.push_back(version_entry.git_tree);
|
||||
}
|
||||
return res;
|
||||
GitRegistryEntry::GitRegistryEntry(const GitRegistry& reg, StringView name)
|
||||
: port_name(name.to_string()), parent(reg)
|
||||
{
|
||||
// This guarantees that parent.m_paths has been filled before any entries are constructed.
|
||||
// The entries may then rely on (bool)parent.m_paths during their operation
|
||||
Checks::check_exit(VCPKG_LINE_INFO, parent.m_paths);
|
||||
#if defined(_MSC_VER)
|
||||
__assume(parent.m_paths);
|
||||
#endif
|
||||
auto vtp = parent.get_stale_versions_tree_path(*parent.m_paths);
|
||||
stale = vtp.stale;
|
||||
fill_data_from_path(parent.m_paths->get_filesystem(), vtp.path);
|
||||
}
|
||||
|
||||
Optional<VersionT> GitRegistry::get_baseline_version(const VcpkgPaths& paths, StringView port_name) const
|
||||
{
|
||||
const auto& baseline = m_baseline.get([this, &paths]() -> Baseline {
|
||||
auto baseline_file = get_versions_tree_path(paths) / fs::u8path("baseline.json");
|
||||
|
||||
auto res_baseline = load_baseline_versions(paths, baseline_file, m_baseline_identifier);
|
||||
|
||||
if (!res_baseline.has_value())
|
||||
// We delay baseline validation until here to give better error messages and suggestions
|
||||
if (!is_git_commit_sha(m_baseline_identifier))
|
||||
{
|
||||
Checks::exit_maybe_upgrade(VCPKG_LINE_INFO, res_baseline.error());
|
||||
}
|
||||
auto opt_baseline = res_baseline.get();
|
||||
if (auto p = opt_baseline->get())
|
||||
{
|
||||
return std::move(*p);
|
||||
}
|
||||
|
||||
if (m_baseline_identifier.empty())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
if (m_baseline_identifier == "default")
|
||||
{
|
||||
Metrics::g_metrics.lock()->track_property("registries-error-could-not-find-baseline", "defined");
|
||||
Checks::exit_with_message(
|
||||
auto e = get_lock_entry(paths);
|
||||
e.ensure_up_to_date(paths);
|
||||
Checks::exit_maybe_upgrade(
|
||||
VCPKG_LINE_INFO,
|
||||
"Couldn't find explicitly specified baseline `\"default\"` in the baseline file.",
|
||||
m_baseline_identifier);
|
||||
}
|
||||
|
||||
// attempt to check out the baseline:
|
||||
auto explicit_hash = paths.git_fetch_from_remote_registry(m_repo, m_baseline_identifier);
|
||||
if (!explicit_hash.has_value())
|
||||
{
|
||||
Metrics::g_metrics.lock()->track_property("registries-error-could-not-find-baseline", "defined");
|
||||
Checks::exit_with_message(
|
||||
VCPKG_LINE_INFO,
|
||||
"Error: Couldn't find explicitly specified baseline `\"%s\"` in the baseline file for repo %s, "
|
||||
"and that commit doesn't exist.\n%s",
|
||||
m_baseline_identifier,
|
||||
"Error: the git registry entry for \"%s\" must have a \"baseline\" field that is a valid git "
|
||||
"commit SHA (40 lowercase hexadecimal characters).\n"
|
||||
"The current HEAD of that repo is \"%s\".\n",
|
||||
m_repo,
|
||||
explicit_hash.error());
|
||||
e.value());
|
||||
}
|
||||
|
||||
auto path_to_baseline = registry_versions_dir_name / fs::u8path("baseline.json");
|
||||
auto maybe_contents = paths.git_show_from_remote_registry(*explicit_hash.get(), path_to_baseline);
|
||||
auto maybe_contents = paths.git_show_from_remote_registry(m_baseline_identifier, path_to_baseline);
|
||||
if (!maybe_contents.has_value())
|
||||
{
|
||||
if (auto err = paths.git_fetch(m_repo, m_baseline_identifier))
|
||||
{
|
||||
Metrics::g_metrics.lock()->track_property("registries-error-could-not-find-baseline", "defined");
|
||||
Checks::exit_with_message(
|
||||
VCPKG_LINE_INFO,
|
||||
"Error: Couldn't find baseline `\"%s\"` for repo %s:\n%s\nError: Failed to fetch %s:\n%s",
|
||||
m_baseline_identifier,
|
||||
m_repo,
|
||||
maybe_contents.error(),
|
||||
m_repo,
|
||||
*err.get());
|
||||
}
|
||||
maybe_contents = paths.git_show_from_remote_registry(m_baseline_identifier, path_to_baseline);
|
||||
}
|
||||
|
||||
if (!maybe_contents.has_value())
|
||||
{
|
||||
Metrics::g_metrics.lock()->track_property("registries-error-could-not-find-baseline", "defined");
|
||||
Checks::exit_with_message(
|
||||
VCPKG_LINE_INFO,
|
||||
"Error: Couldn't find explicitly specified baseline `\"%s\"` in the baseline file for repo %s, "
|
||||
"and the baseline file doesn't exist at that commit.\n%s\n",
|
||||
m_baseline_identifier,
|
||||
m_repo,
|
||||
maybe_contents.error());
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO,
|
||||
"Error: Couldn't find baseline in commit `\"%s\"` from repo %s:\n%s\n",
|
||||
m_baseline_identifier,
|
||||
m_repo,
|
||||
maybe_contents.error());
|
||||
}
|
||||
|
||||
auto contents = maybe_contents.get();
|
||||
res_baseline = parse_baseline_versions(*contents, "default", fs::u8string(path_to_baseline));
|
||||
if (!res_baseline.has_value())
|
||||
auto res_baseline = parse_baseline_versions(*contents, "default", fs::u8string(path_to_baseline));
|
||||
if (auto opt_baseline = res_baseline.get())
|
||||
{
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO, res_baseline.error());
|
||||
}
|
||||
opt_baseline = res_baseline.get();
|
||||
if (auto p = opt_baseline->get())
|
||||
{
|
||||
return std::move(*p);
|
||||
if (auto p = opt_baseline->get())
|
||||
{
|
||||
return std::move(*p);
|
||||
}
|
||||
else
|
||||
{
|
||||
Metrics::g_metrics.lock()->track_property("registries-error-could-not-find-baseline", "defined");
|
||||
Checks::exit_maybe_upgrade(
|
||||
VCPKG_LINE_INFO,
|
||||
"The baseline.json from commit `\"%s\"` in the repo %s did not contain a \"default\" field.",
|
||||
m_baseline_identifier,
|
||||
m_repo);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Metrics::g_metrics.lock()->track_property("registries-error-could-not-find-baseline", "defined");
|
||||
Checks::exit_maybe_upgrade(
|
||||
VCPKG_LINE_INFO,
|
||||
"Couldn't find explicitly specified baseline `\"%s\"` in the baseline file for repo %s, "
|
||||
"and the `\"default\"` baseline does not exist at that commit.",
|
||||
m_baseline_identifier,
|
||||
m_repo);
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO,
|
||||
"Error while fetching baseline `\"%s\"` from repo %s:\n%s",
|
||||
m_baseline_identifier,
|
||||
m_repo,
|
||||
res_baseline.error());
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -647,19 +682,31 @@ namespace
|
|||
// } FilesystemRegistryEntry::RegistryEntry
|
||||
|
||||
// { GitRegistryEntry::RegistryEntry
|
||||
View<VersionT> GitRegistryEntry::get_port_versions() const
|
||||
{
|
||||
if (stale)
|
||||
{
|
||||
fill_data_from_path(parent.m_paths->get_filesystem(), parent.get_versions_tree_path(*parent.m_paths));
|
||||
stale = false;
|
||||
}
|
||||
return port_versions;
|
||||
}
|
||||
ExpectedS<fs::path> GitRegistryEntry::get_path_to_version(const VcpkgPaths& paths, const VersionT& version) const
|
||||
{
|
||||
auto it = std::find(port_versions.begin(), port_versions.end(), version);
|
||||
if (it == port_versions.end() && stale)
|
||||
{
|
||||
fill_data_from_path(parent.m_paths->get_filesystem(), parent.get_versions_tree_path(*parent.m_paths));
|
||||
stale = false;
|
||||
it = std::find(port_versions.begin(), port_versions.end(), version);
|
||||
}
|
||||
if (it == port_versions.end())
|
||||
{
|
||||
// This message suggests that the user updates vcpkg -- this is appropriate for the builtin registry for now
|
||||
// but needs tweaking for external git registries
|
||||
return {Strings::concat("Error: No version entry for ",
|
||||
port_name,
|
||||
" at version ",
|
||||
version,
|
||||
". This may be fixed by updating vcpkg to the latest master via `git "
|
||||
"pull`.\nAvailable versions:\n",
|
||||
".\nAvailable versions:\n",
|
||||
Strings::join("",
|
||||
port_versions,
|
||||
[](const VersionT& v) { return Strings::concat(" ", v, "\n"); }),
|
||||
|
@ -670,6 +717,21 @@ namespace
|
|||
const auto& git_tree = git_trees[it - port_versions.begin()];
|
||||
return paths.git_checkout_object_from_remote_registry(git_tree);
|
||||
}
|
||||
|
||||
void GitRegistryEntry::fill_data_from_path(const Files::Filesystem& fs, const fs::path& port_versions_path) const
|
||||
{
|
||||
auto maybe_version_entries = load_versions_file(fs, VersionDbType::Git, port_versions_path, port_name);
|
||||
Checks::check_maybe_upgrade(
|
||||
VCPKG_LINE_INFO, maybe_version_entries.has_value(), "Error: " + maybe_version_entries.error());
|
||||
auto version_entries = std::move(maybe_version_entries).value_or_exit(VCPKG_LINE_INFO);
|
||||
|
||||
for (auto&& version_entry : version_entries)
|
||||
{
|
||||
port_versions.push_back(version_entry.version);
|
||||
git_trees.push_back(version_entry.git_tree);
|
||||
}
|
||||
}
|
||||
|
||||
// } GitRegistryEntry::RegistryEntry
|
||||
|
||||
// } RegistryEntry
|
||||
|
@ -896,20 +958,22 @@ namespace
|
|||
static Json::StringDeserializer kind_deserializer{"a registry implementation kind"};
|
||||
static Json::StringDeserializer baseline_deserializer{"a baseline"};
|
||||
std::string kind;
|
||||
std::string baseline;
|
||||
|
||||
r.required_object_field(type_name(), obj, KIND, kind, kind_deserializer);
|
||||
r.optional_object_field(obj, BASELINE, baseline, baseline_deserializer);
|
||||
|
||||
std::unique_ptr<RegistryImplementation> res;
|
||||
|
||||
if (kind == KIND_BUILTIN)
|
||||
{
|
||||
std::string baseline;
|
||||
r.optional_object_field(obj, BASELINE, baseline, baseline_deserializer);
|
||||
r.check_for_unexpected_fields(obj, valid_builtin_fields(), "a builtin registry");
|
||||
res = std::make_unique<BuiltinRegistry>(std::move(baseline));
|
||||
}
|
||||
else if (kind == KIND_FILESYSTEM)
|
||||
{
|
||||
std::string baseline;
|
||||
r.optional_object_field(obj, BASELINE, baseline, baseline_deserializer);
|
||||
r.check_for_unexpected_fields(obj, valid_filesystem_fields(), "a filesystem registry");
|
||||
|
||||
fs::path path;
|
||||
|
@ -925,6 +989,9 @@ namespace
|
|||
Json::StringDeserializer repo_des{"a git repository URL"};
|
||||
r.required_object_field("a git registry", obj, REPO, repo, repo_des);
|
||||
|
||||
std::string baseline;
|
||||
r.required_object_field("a git registry", obj, BASELINE, baseline, baseline_deserializer);
|
||||
|
||||
res = std::make_unique<GitRegistry>(std::move(repo), std::move(baseline));
|
||||
}
|
||||
else
|
||||
|
@ -1100,6 +1167,28 @@ namespace
|
|||
|
||||
namespace vcpkg
|
||||
{
|
||||
LockFile::Entry LockFile::get_or_fetch(const VcpkgPaths& paths, StringView key)
|
||||
{
|
||||
auto it = lockdata.find(key);
|
||||
if (it == lockdata.end())
|
||||
{
|
||||
auto x = paths.git_fetch_from_remote_registry(key, "HEAD");
|
||||
it = lockdata.emplace(key.to_string(), EntryData{x.value_or_exit(VCPKG_LINE_INFO), false}).first;
|
||||
modified = true;
|
||||
}
|
||||
return {this, it};
|
||||
}
|
||||
void LockFile::Entry::ensure_up_to_date(const VcpkgPaths& paths) const
|
||||
{
|
||||
if (data->second.stale)
|
||||
{
|
||||
data->second.value =
|
||||
paths.git_fetch_from_remote_registry(data->first, "HEAD").value_or_exit(VCPKG_LINE_INFO);
|
||||
data->second.stale = false;
|
||||
lockfile->modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Json::IDeserializer<std::unique_ptr<RegistryImplementation>>>
|
||||
get_registry_implementation_deserializer(const fs::path& configuration_directory)
|
||||
{
|
||||
|
@ -1217,4 +1306,14 @@ namespace vcpkg
|
|||
{
|
||||
return try_parse_builtin_baseline(paths, "default");
|
||||
}
|
||||
|
||||
bool is_git_commit_sha(StringView sv)
|
||||
{
|
||||
static constexpr struct
|
||||
{
|
||||
bool operator()(char ch) { return ('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'f'); }
|
||||
} is_lcase_ascii_hex;
|
||||
|
||||
return sv.size() == 40 && std::all_of(sv.begin(), sv.end(), is_lcase_ascii_hex);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -186,6 +186,55 @@ namespace vcpkg
|
|||
|
||||
namespace details
|
||||
{
|
||||
namespace
|
||||
{
|
||||
const ExpectedS<fs::path>& default_registries_cache_path()
|
||||
{
|
||||
static auto cachepath = System::get_platform_cache_home().then([](fs::path p) -> ExpectedS<fs::path> {
|
||||
auto maybe_cachepath = System::get_environment_variable("X_VCPKG_REGISTRIES_CACHE");
|
||||
if (auto p_str = maybe_cachepath.get())
|
||||
{
|
||||
Metrics::g_metrics.lock()->track_property("X_VCPKG_REGISTRIES_CACHE", "defined");
|
||||
auto path = fs::u8path(*p_str);
|
||||
path.make_preferred();
|
||||
const auto status = fs::stdfs::status(path);
|
||||
if (!fs::stdfs::exists(status))
|
||||
{
|
||||
return {"Path to X_VCPKG_REGISTRIES_CACHE does not exist: " + fs::u8string(path),
|
||||
expected_right_tag};
|
||||
}
|
||||
|
||||
if (!fs::stdfs::is_directory(status))
|
||||
{
|
||||
return {"Value of environment variable X_VCPKG_REGISTRIES_CACHE is not a directory: " +
|
||||
fs::u8string(path),
|
||||
expected_right_tag};
|
||||
}
|
||||
|
||||
if (!path.is_absolute())
|
||||
{
|
||||
return {"Value of environment variable X_VCPKG_REGISTRIES_CACHE is not absolute: " +
|
||||
fs::u8string(path),
|
||||
expected_right_tag};
|
||||
}
|
||||
|
||||
return {std::move(path), expected_left_tag};
|
||||
}
|
||||
p /= fs::u8path("vcpkg/registries");
|
||||
p.make_preferred();
|
||||
if (p.is_absolute())
|
||||
{
|
||||
return {std::move(p), expected_left_tag};
|
||||
}
|
||||
else
|
||||
{
|
||||
return {"default path was not absolute: " + fs::u8string(p), expected_right_tag};
|
||||
}
|
||||
});
|
||||
return cachepath;
|
||||
}
|
||||
}
|
||||
|
||||
struct VcpkgPathsImpl
|
||||
{
|
||||
VcpkgPathsImpl(Files::Filesystem& fs, FeatureFlagSettings ff_settings)
|
||||
|
@ -194,11 +243,10 @@ namespace vcpkg
|
|||
, m_env_cache(ff_settings.compiler_tracking)
|
||||
, m_ff_settings(ff_settings)
|
||||
{
|
||||
const auto& cache_root =
|
||||
System::get_platform_cache_home().value_or_exit(VCPKG_LINE_INFO) / fs::u8path("vcpkg");
|
||||
registries_work_tree_dir = cache_root / fs::u8path("registries") / fs::u8path("git");
|
||||
const auto& cache_root = default_registries_cache_path().value_or_exit(VCPKG_LINE_INFO);
|
||||
registries_work_tree_dir = cache_root / fs::u8path("git");
|
||||
registries_dot_git_dir = registries_work_tree_dir / fs::u8path(".git");
|
||||
registries_git_trees = cache_root / fs::u8path("registries") / fs::u8path("git-trees");
|
||||
registries_git_trees = cache_root / fs::u8path("git-trees");
|
||||
}
|
||||
|
||||
Lazy<std::vector<VcpkgPaths::TripletFile>> available_triplets;
|
||||
|
@ -228,9 +276,13 @@ namespace vcpkg
|
|||
fs::path registries_work_tree_dir;
|
||||
fs::path registries_dot_git_dir;
|
||||
fs::path registries_git_trees;
|
||||
|
||||
Optional<LockFile> m_installed_lock;
|
||||
};
|
||||
}
|
||||
|
||||
static fs::path lockfile_path(const VcpkgPaths& p) { return p.vcpkg_dir / fs::u8path("vcpkg-lock.json"); }
|
||||
|
||||
VcpkgPaths::VcpkgPaths(Files::Filesystem& filesystem, const VcpkgCmdArguments& args)
|
||||
: m_pimpl(std::make_unique<details::VcpkgPathsImpl>(filesystem, args.feature_flag_settings()))
|
||||
{
|
||||
|
@ -494,6 +546,72 @@ If you wish to silence this error and use classic mode, you can:
|
|||
});
|
||||
}
|
||||
|
||||
static LockFile load_lockfile(const Files::Filesystem& fs, const fs::path& p)
|
||||
{
|
||||
LockFile ret;
|
||||
std::error_code ec;
|
||||
auto maybe_lock_contents = Json::parse_file(fs, p, ec);
|
||||
if (ec)
|
||||
{
|
||||
Debug::print("Failed to load lockfile: ", ec.message(), "\n");
|
||||
return ret;
|
||||
}
|
||||
else if (auto lock_contents = maybe_lock_contents.get())
|
||||
{
|
||||
auto& doc = lock_contents->first;
|
||||
if (doc.is_object())
|
||||
{
|
||||
for (auto&& x : doc.object())
|
||||
{
|
||||
if (!x.second.is_string())
|
||||
{
|
||||
Debug::print("Lockfile value for key '", x.first, "' was not a string\n");
|
||||
return ret;
|
||||
}
|
||||
auto sv = x.second.string();
|
||||
if (!is_git_commit_sha(sv))
|
||||
{
|
||||
Debug::print("Lockfile value for key '", x.first, "' was not a git commit sha\n");
|
||||
return ret;
|
||||
}
|
||||
ret.lockdata.emplace(x.first.to_string(), LockFile::EntryData{sv.to_string(), true});
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
Debug::print("Lockfile was not an object\n");
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug::print("Failed to load lockfile:\n", maybe_lock_contents.error()->format());
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
LockFile& VcpkgPaths::get_installed_lockfile() const
|
||||
{
|
||||
if (!m_pimpl->m_installed_lock.has_value())
|
||||
{
|
||||
m_pimpl->m_installed_lock = load_lockfile(get_filesystem(), lockfile_path(*this));
|
||||
}
|
||||
return *m_pimpl->m_installed_lock.get();
|
||||
}
|
||||
void VcpkgPaths::flush_lockfile() const
|
||||
{
|
||||
// If the lock file was not loaded, no need to flush it.
|
||||
if (!m_pimpl->m_installed_lock.has_value()) return;
|
||||
// lockfile was not modified, no need to write anything to disk.
|
||||
const auto& lockfile = *m_pimpl->m_installed_lock.get();
|
||||
if (!lockfile.modified) return;
|
||||
Json::Object obj;
|
||||
for (auto&& data : lockfile.lockdata)
|
||||
{
|
||||
obj.insert(data.first, Json::Value::string(data.second.value));
|
||||
}
|
||||
get_filesystem().write_rename_contents(
|
||||
lockfile_path(*this), fs::u8path("vcpkg-lock.json.tmp"), Json::stringify(obj, {}), VCPKG_LINE_INFO);
|
||||
}
|
||||
|
||||
const fs::path VcpkgPaths::get_triplet_file_path(Triplet triplet) const
|
||||
{
|
||||
return m_pimpl->m_triplets_cache.get_lazy(
|
||||
|
@ -523,75 +641,17 @@ If you wish to silence this error and use classic mode, you can:
|
|||
|
||||
System::Command VcpkgPaths::git_cmd_builder(const fs::path& dot_git_dir, const fs::path& work_tree) const
|
||||
{
|
||||
return System::Command(get_tool_exe(Tools::GIT))
|
||||
.string_arg(Strings::concat("--git-dir=", fs::u8string(dot_git_dir)))
|
||||
.string_arg(Strings::concat("--work-tree=", fs::u8string(work_tree)))
|
||||
.string_arg("-c")
|
||||
.string_arg("core.autocrlf=false");
|
||||
}
|
||||
|
||||
void VcpkgPaths::git_checkout_subpath(const VcpkgPaths& paths,
|
||||
StringView commit_sha,
|
||||
const fs::path& subpath,
|
||||
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);
|
||||
fs.remove_all(dot_git_dir, VCPKG_LINE_INFO);
|
||||
|
||||
// All git commands are run with: --git-dir={dot_git_dir} --work-tree={work_tree_temp}
|
||||
// git clone --no-checkout --local --no-hardlinks {vcpkg_root} {dot_git_dir}
|
||||
// note that `--no-hardlinks` is added because otherwise, git fails to clone in some cases
|
||||
System::Command clone_cmd_builder = paths.git_cmd_builder(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);
|
||||
|
||||
// git checkout {commit-sha} -- {subpath}
|
||||
System::Command checkout_cmd_builder = paths.git_cmd_builder(dot_git_dir, work_tree)
|
||||
.string_arg("checkout")
|
||||
.string_arg(commit_sha)
|
||||
.string_arg("--")
|
||||
.path_arg(subpath);
|
||||
const auto checkout_output = System::cmd_execute_and_capture_output(checkout_cmd_builder);
|
||||
Checks::check_exit(VCPKG_LINE_INFO,
|
||||
checkout_output.exit_code == 0,
|
||||
"Error: Failed to checkout %s:%s\n%s\n",
|
||||
commit_sha,
|
||||
fs::u8string(subpath),
|
||||
checkout_output.output);
|
||||
|
||||
const fs::path checked_out_path = work_tree / subpath;
|
||||
const auto& containing_folder = destination.parent_path();
|
||||
if (!fs.exists(containing_folder))
|
||||
System::Command ret(get_tool_exe(Tools::GIT));
|
||||
if (!dot_git_dir.empty())
|
||||
{
|
||||
fs.create_directories(containing_folder, VCPKG_LINE_INFO);
|
||||
ret.string_arg(Strings::concat("--git-dir=", fs::u8string(dot_git_dir)));
|
||||
}
|
||||
|
||||
std::error_code ec;
|
||||
fs.rename_or_copy(checked_out_path, destination, ".tmp", ec);
|
||||
fs.remove_all(work_tree, VCPKG_LINE_INFO);
|
||||
fs.remove_all(dot_git_dir, VCPKG_LINE_INFO);
|
||||
if (ec)
|
||||
if (!work_tree.empty())
|
||||
{
|
||||
System::printf(System::Color::error,
|
||||
"Error: Couldn't move checked out files from %s to destination %s",
|
||||
fs::u8string(checked_out_path),
|
||||
fs::u8string(destination));
|
||||
Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
ret.string_arg(Strings::concat("--work-tree=", fs::u8string(work_tree)));
|
||||
}
|
||||
ret.string_arg("-c").string_arg("core.autocrlf=false");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ExpectedS<std::string> VcpkgPaths::get_current_git_sha() const
|
||||
|
@ -641,14 +701,13 @@ If you wish to silence this error and use classic mode, you can:
|
|||
ExpectedS<std::map<std::string, std::string, std::less<>>> VcpkgPaths::git_get_local_port_treeish_map() const
|
||||
{
|
||||
const auto local_repo = this->root / fs::u8path(".git");
|
||||
const auto path_with_separator =
|
||||
Strings::concat(fs::u8string(this->builtin_ports_directory()), Files::preferred_separator);
|
||||
const auto git_cmd = git_cmd_builder(local_repo, this->root)
|
||||
const auto git_cmd = git_cmd_builder({}, {})
|
||||
.string_arg("-C")
|
||||
.path_arg(this->builtin_ports_directory())
|
||||
.string_arg("ls-tree")
|
||||
.string_arg("-d")
|
||||
.string_arg("HEAD")
|
||||
.string_arg("--")
|
||||
.path_arg(path_with_separator);
|
||||
.string_arg("--");
|
||||
|
||||
auto output = System::cmd_execute_and_capture_output(git_cmd);
|
||||
if (output.exit_code != 0)
|
||||
|
@ -673,15 +732,7 @@ If you wish to silence this error and use classic mode, you can:
|
|||
git_cmd.command_line(),
|
||||
line);
|
||||
|
||||
const auto index = split_line[1].find_last_of('/');
|
||||
if (index == std::string::npos)
|
||||
{
|
||||
return Strings::format("Error: Unexpected output from command `%s`. Couldn't split by `/`.\n%s",
|
||||
git_cmd.command_line(),
|
||||
line);
|
||||
}
|
||||
|
||||
ret.emplace(split_line[1].substr(index + 1), file_info_section.back());
|
||||
ret.emplace(split_line[1], file_info_section.back());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -856,20 +907,14 @@ If you wish to silence this error and use classic mode, you can:
|
|||
.string_arg("fetch")
|
||||
.string_arg("--update-shallow")
|
||||
.string_arg("--")
|
||||
.string_arg(repo);
|
||||
if (treeish.size() != 0)
|
||||
{
|
||||
fetch_git_ref.string_arg(treeish);
|
||||
}
|
||||
.string_arg(repo)
|
||||
.string_arg(treeish);
|
||||
|
||||
auto fetch_output = System::cmd_execute_and_capture_output(fetch_git_ref);
|
||||
if (fetch_output.exit_code != 0)
|
||||
{
|
||||
return {Strings::format("Error: Failed to fetch %s%s from repository %s.\n%s\n",
|
||||
treeish.size() != 0 ? "ref " : "",
|
||||
treeish,
|
||||
repo,
|
||||
fetch_output.output),
|
||||
return {Strings::format(
|
||||
"Error: Failed to fetch ref %s from repository %s.\n%s\n", treeish, repo, fetch_output.output),
|
||||
expected_right_tag};
|
||||
}
|
||||
|
||||
|
@ -883,6 +928,44 @@ If you wish to silence this error and use classic mode, you can:
|
|||
}
|
||||
return {Strings::trim(fetch_head_output.output).to_string(), expected_left_tag};
|
||||
}
|
||||
|
||||
Optional<std::string> VcpkgPaths::git_fetch(StringView repo, StringView treeish) const
|
||||
{
|
||||
auto& fs = get_filesystem();
|
||||
|
||||
auto work_tree = m_pimpl->registries_work_tree_dir;
|
||||
fs.create_directories(work_tree, VCPKG_LINE_INFO);
|
||||
|
||||
auto lock_file = work_tree / fs::u8path(".vcpkg-lock");
|
||||
|
||||
std::error_code ec;
|
||||
Files::ExclusiveFileLock guard(Files::ExclusiveFileLock::Wait::Yes, fs, lock_file, ec);
|
||||
|
||||
auto dot_git_dir = m_pimpl->registries_dot_git_dir;
|
||||
|
||||
System::Command init_registries_git_dir = git_cmd_builder(dot_git_dir, work_tree).string_arg("init");
|
||||
auto init_output = System::cmd_execute_and_capture_output(init_registries_git_dir);
|
||||
if (init_output.exit_code != 0)
|
||||
{
|
||||
return Strings::format(
|
||||
"Error: Failed to initialize local repository %s.\n%s\n", fs::u8string(work_tree), init_output.output);
|
||||
}
|
||||
System::Command fetch_git_ref = git_cmd_builder(dot_git_dir, work_tree)
|
||||
.string_arg("fetch")
|
||||
.string_arg("--update-shallow")
|
||||
.string_arg("--")
|
||||
.string_arg(repo)
|
||||
.string_arg(treeish);
|
||||
|
||||
auto fetch_output = System::cmd_execute_and_capture_output(fetch_git_ref);
|
||||
if (fetch_output.exit_code != 0)
|
||||
{
|
||||
return Strings::format(
|
||||
"Error: Failed to fetch ref %s from repository %s.\n%s\n", treeish, repo, fetch_output.output);
|
||||
}
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
// returns an error if there was an unexpected error; returns nullopt if the file doesn't exist at the specified
|
||||
// hash
|
||||
ExpectedS<std::string> VcpkgPaths::git_show_from_remote_registry(StringView hash,
|
||||
|
@ -954,6 +1037,8 @@ If you wish to silence this error and use classic mode, you can:
|
|||
git_tree_temp_tar);
|
||||
|
||||
auto untar_output = System::cmd_execute_and_capture_output(untar, System::InWorkingDirectory{git_tree_temp});
|
||||
// Attempt to remove temporary files, though non-critical.
|
||||
fs.remove(git_tree_temp_tar, ignore_errors);
|
||||
if (untar_output.exit_code != 0)
|
||||
{
|
||||
return {Strings::format("cmake's untar failed with message:\n%s", untar_output.output), expected_right_tag};
|
||||
|
|
Загрузка…
Ссылка в новой задаче