diff --git a/Generate-SpdxLicenseList.ps1 b/Generate-SpdxLicenseList.ps1 index 92542bd418..2e8892c3ed 100644 --- a/Generate-SpdxLicenseList.ps1 +++ b/Generate-SpdxLicenseList.ps1 @@ -37,16 +37,15 @@ function Transform-JsonFile { $fileContent = @( "// Data downloaded from $Uri", - "// Generated by scripts/Generate-SpdxLicenseList.ps1", - "{") + "// Generated by Generate-SpdxLicenseList.ps1") $json.$OuterName | Sort-Object -Property $Id -Culture '' | ForEach-Object { - $fileContent += " `"$($_.$Id)`"," + $fileContent += "`"$($_.$Id)`"," } - $fileContent += "}" - $fileContent -join "`n" | Out-File -FilePath $OutFile -Encoding 'utf8' + ($fileContent -join "`n") + "`n" ` + | Out-File -FilePath $OutFile -Encoding 'utf8' -NoNewline } $baseUrl = "https://raw.githubusercontent.com/$GithubRepository/$Commit/json" diff --git a/LocProject.json b/LocProject.json index 0967ef424b..7b11a04750 100644 --- a/LocProject.json +++ b/LocProject.json @@ -1 +1,15 @@ -{} +{ + "Projects": [ + { + "LanguageSet": "VS_Main_Languages", + "LocItems": [ + { + "SourceFile": "locales/messages.json", + "CopyOption": "LangIDOnName", + "LclFile": "src/localization-team/{Lang}/messages.json.lcl", + "OutputPath": "locales" + } + ] + } + ] +} diff --git a/azure-pipelines/Format-CxxCode.ps1 b/azure-pipelines/Format-CxxCode.ps1 index 8826699aa4..2041ef0580 100755 --- a/azure-pipelines/Format-CxxCode.ps1 +++ b/azure-pipelines/Format-CxxCode.ps1 @@ -16,6 +16,10 @@ if ($null -ne $clangFormat) if ($IsWindows) { + if ([String]::IsNullOrEmpty($clangFormat) -or -not (Test-Path $clangFormat)) + { + $clangFormat = 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\Llvm\x64\bin\clang-format.exe' + } if ([String]::IsNullOrEmpty($clangFormat) -or -not (Test-Path $clangFormat)) { $clangFormat = 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\Llvm\x64\bin\clang-format.exe' diff --git a/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg-configuration.json b/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg-configuration.json new file mode 100644 index 0000000000..7122b60c21 --- /dev/null +++ b/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg-configuration.json @@ -0,0 +1,13 @@ +{ + "default-registry": null, + "registries": [ + { + "kind": "filesystem", + "path": "./vcpkg_registry", + "packages": [ + "arrow", + "bloom-filter" + ] + } + ] +} diff --git a/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg.json b/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg.json new file mode 100644 index 0000000000..34622305c2 --- /dev/null +++ b/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg.json @@ -0,0 +1,15 @@ +{ + "name": "cycle-detected", + "version": "0.1.0", + "dependencies": [ + "arrow", + "bloom-filter" + ], + "overrides": [ + { + "name": "arrow", + "version": "6.0.0.20210925", + "port-version": 4 + } + ] +} diff --git a/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg_registry/ports/arrow/portfile.cmake b/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg_registry/ports/arrow/portfile.cmake new file mode 100644 index 0000000000..d11c69f812 --- /dev/null +++ b/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg_registry/ports/arrow/portfile.cmake @@ -0,0 +1 @@ +// intentionally empty diff --git a/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg_registry/ports/arrow/vcpkg.json b/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg_registry/ports/arrow/vcpkg.json new file mode 100644 index 0000000000..b8a79d3847 --- /dev/null +++ b/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg_registry/ports/arrow/vcpkg.json @@ -0,0 +1,5 @@ +{ + "name": "arrow", + "version": "6.0.0.20210925", + "description": "Cross-language development platform for in-memory analytics" +} diff --git a/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg_registry/ports/bloom-filter/portfile.cmake b/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg_registry/ports/bloom-filter/portfile.cmake new file mode 100644 index 0000000000..d11c69f812 --- /dev/null +++ b/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg_registry/ports/bloom-filter/portfile.cmake @@ -0,0 +1 @@ +// intentionally empty diff --git a/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg_registry/ports/bloom-filter/vcpkg.json b/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg_registry/ports/bloom-filter/vcpkg.json new file mode 100644 index 0000000000..2025d15a5d --- /dev/null +++ b/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg_registry/ports/bloom-filter/vcpkg.json @@ -0,0 +1,7 @@ +{ + "name": "bloom-filter", + "version": "0.2.0", + "port-version": 1, + "description": "bloom filter", + "dependencies": ["arrow"] +} diff --git a/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg_registry/versions/a-/arrow.json b/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg_registry/versions/a-/arrow.json new file mode 100644 index 0000000000..8728f8917f --- /dev/null +++ b/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg_registry/versions/a-/arrow.json @@ -0,0 +1,9 @@ +{ + "versions": [ + { + "version": "6.0.0.20210925", + "port-version": 4, + "path": "$/ports/arrow" + } + ] +} \ No newline at end of file diff --git a/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg_registry/versions/b-/bloom-filter.json b/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg_registry/versions/b-/bloom-filter.json new file mode 100644 index 0000000000..8a4079a4a7 --- /dev/null +++ b/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg_registry/versions/b-/bloom-filter.json @@ -0,0 +1,9 @@ +{ + "versions": [ + { + "version": "0.2.0", + "port-version": 1, + "path": "$/ports/bloom-filter" + } + ] +} \ No newline at end of file diff --git a/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg_registry/versions/baseline.json b/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg_registry/versions/baseline.json new file mode 100644 index 0000000000..f15584ae08 --- /dev/null +++ b/azure-pipelines/e2e_ports/mismatched-version-database/vcpkg_registry/versions/baseline.json @@ -0,0 +1,13 @@ +{ + "$doc": "https://github.com/microsoft/vcpkg/blob/master/docs/maintainers/registries.md#filesystem-registries", + "default": { + "arrow": { + "baseline": "6.0.0.20210925", + "port-version": 4 + }, + "bloom-filter": { + "baseline": "0.2.0", + "port-version": 1 + } + } +} \ No newline at end of file diff --git a/azure-pipelines/end-to-end-tests-dir/manifest-reserialize.ps1 b/azure-pipelines/end-to-end-tests-dir/manifest-reserialize.ps1 new file mode 100644 index 0000000000..283f2ef9e3 --- /dev/null +++ b/azure-pipelines/end-to-end-tests-dir/manifest-reserialize.ps1 @@ -0,0 +1,20 @@ +. "$PSScriptRoot/../end-to-end-tests-prelude.ps1" + +Write-Trace "test re-serializing every manifest" +$manifestDir = "$TestingRoot/manifest-dir" +New-Item -Path $manifestDir -ItemType Directory | Out-Null + +$ports = Get-ChildItem "$env:VCPKG_ROOT/ports" + +$ports | % { + if (Test-Path "$_/vcpkg.json") { + Copy-Item "$_/vcpkg.json" "$manifestDir" | Out-Null + $x = Get-Content "$manifestDir/vcpkg.json" -Raw + Run-Vcpkg -EndToEndTestSilent format-manifest "$manifestDir/vcpkg.json" | Out-Null + Throw-IfFailed "$_/vcpkg.json" + $y = Get-Content "$manifestDir/vcpkg.json" -Raw + if ($x -ne $y) { + throw "Expected formatting manifest $_/vcpkg.json to cause no modifications" + } + } +} \ No newline at end of file diff --git a/azure-pipelines/end-to-end-tests-dir/versions.ps1 b/azure-pipelines/end-to-end-tests-dir/versions.ps1 index 3ba90770b9..69a6bde41c 100644 --- a/azure-pipelines/end-to-end-tests-dir/versions.ps1 +++ b/azure-pipelines/end-to-end-tests-dir/versions.ps1 @@ -71,12 +71,23 @@ Throw-IfFailed $CurrentTest = "default baseline" $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.*") +if ($out -notmatch ".*Error: while checking out baseline\.*") { $out throw "Expected to fail due to missing baseline" } +$CurrentTest = "mismatched version database" +$out = Run-Vcpkg @commonArgs "--feature-flags=versions" install --x-manifest-root="$PSScriptRoot/../e2e_ports/mismatched-version-database" 2>&1 | Out-String +Throw-IfNotFailed +if (($out -notmatch ".*Error: Failed to load port because version specs did not match*") -or + ($out -notmatch ".*Expected: arrow@6.0.0.20210925#4.*") -or + ($out -notmatch ".*Actual: arrow@6.0.0.20210925.*")) +{ + $out + throw "Expected to fail due to mismatched versions between portfile and the version database" +} + git -C "$env:VCPKG_ROOT" fetch https://github.com/vicroms/test-registries foreach ($opt_registries in @("",",registries")) { diff --git a/azure-pipelines/end-to-end-tests-prelude.ps1 b/azure-pipelines/end-to-end-tests-prelude.ps1 index 0d9a9baf23..9da97499df 100644 --- a/azure-pipelines/end-to-end-tests-prelude.ps1 +++ b/azure-pipelines/end-to-end-tests-prelude.ps1 @@ -70,9 +70,13 @@ function Require-FileNotExists { } function Throw-IfFailed { + [CmdletBinding()] + Param( + [string]$Message = "" + ) if ($LASTEXITCODE -ne 0) { Write-Stack - throw "'$Script:CurrentTest' had a step with a nonzero exit code" + throw "'$Script:CurrentTest' had a step with a nonzero exit code: $Message" } } @@ -89,11 +93,14 @@ function Write-Trace ([string]$text) { function Run-Vcpkg { Param( + [Parameter(Mandatory = $false)] + [Switch]$EndToEndTestSilent, + [Parameter(ValueFromRemainingArguments)] [string[]]$TestArgs ) $Script:CurrentTest = "$VcpkgExe $($testArgs -join ' ')" - Write-Host $Script:CurrentTest + if (!$EndToEndTestSilent) { Write-Host $Script:CurrentTest } & $VcpkgExe @testArgs } diff --git a/azure-pipelines/pipelines.yml b/azure-pipelines/pipelines.yml index 8d62fd7a61..17ad0015b9 100644 --- a/azure-pipelines/pipelines.yml +++ b/azure-pipelines/pipelines.yml @@ -19,6 +19,8 @@ jobs: failOnStderr: true - bash: build.amd64.debug/vcpkg-test displayName: 'Run vcpkg tests' + env: + VCPKG_ROOT: UNIT_TESTS_SHOULD_NOT_USE_VCPKG_ROOT - task: PowerShell@2 displayName: 'Run vcpkg end-to-end tests' inputs: @@ -93,7 +95,7 @@ jobs: git clone https://github.com/microsoft/vcpkg $env:VCPKG_ROOT -n git -C "$env:VCPKG_ROOT" checkout $sha - task: CmdLine@2 - displayName: "Build vcpkg with CMake, and Run Tests" + displayName: "Build vcpkg with CMake" inputs: script: | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=x86 -host_arch=x86 @@ -102,6 +104,11 @@ jobs: ninja.exe -C build.x86.debug build.x86.debug\vcpkg-test.exe failOnStderr: true + - script: build.x86.debug\vcpkg-test.exe + displayName: "Run vcpkg tests" + failOnStderr: true + env: + VCPKG_ROOT: UNIT_TESTS_SHOULD_NOT_USE_VCPKG_ROOT - task: PowerShell@2 displayName: 'Run vcpkg end-to-end tests' inputs: @@ -118,7 +125,7 @@ jobs: displayName: 'Generate the Messages File' inputs: script: | - build.x86.debug\vcpkg.exe x-generate-default-message-map >locales/en.json + build.x86.debug\vcpkg.exe x-generate-default-message-map locales/messages.json - task: Powershell@2 displayName: 'Create Diff' inputs: diff --git a/azure-pipelines/signing.yml b/azure-pipelines/signing.yml index b73a2940dc..b72a9f9361 100644 --- a/azure-pipelines/signing.yml +++ b/azure-pipelines/signing.yml @@ -19,12 +19,6 @@ parameters: default: variables: - - ${{ if eq(parameters.VcpkgBaseVersionOverride, '') }}: - - name: VCPKG_BASE_VERSION - value: $[format('{0:yyyy}-{0:MM}-{0:dd}', pipeline.startTime)] - - ${{ if ne(parameters.VcpkgBaseVersionOverride, '') }}: - - name: VCPKG_BASE_VERSION - value: ${{parameters.VcpkgBaseVersionOverride}} - name: TeamName value: vcpkg - group: vcpkg-dependency-source-blobs @@ -47,15 +41,34 @@ variables: jobs: - job: arch_independent displayName: 'Build and Sign Arch-Independent Scripts and vcpkg-ce' + # The first job records VCPKG_INITIAL_BASE_VERSION as VCPKG_BASE_VERSION so that all subsequent stages agree + # on the value; AzureDevOps appears to repeat evaluation of variables such that crossing UTC's day start + # would make subsequent pipeline stages use a different day producing a broken build. + # Note that pipeline.startTime seems to refer to the start of the *job*, not the overall pipeline run. + variables: + - ${{ if eq(parameters.VcpkgBaseVersionOverride, '') }}: + - name: VCPKG_INITIAL_BASE_VERSION + value: $[format('{0:yyyy}-{0:MM}-{0:dd}', pipeline.startTime)] + - ${{ if ne(parameters.VcpkgBaseVersionOverride, '') }}: + - name: VCPKG_INITIAL_BASE_VERSION + value: ${{parameters.VcpkgBaseVersionOverride}} pool: name: 'VSEngSS-MicroBuild2022-1ES' steps: + - task: Powershell@2 + displayName: 'Lock VCPKG_BASE_VERSION' + name: versions + inputs: + pwsh: true + targetType: 'inline' + script: | + Write-Host "##vso[task.setvariable variable=VCPKG_BASE_VERSION;isOutput=true]$env:VCPKG_INITIAL_BASE_VERSION" - task: Powershell@2 displayName: 'Lock Installer Scripts Versions' inputs: pwsh: true filePath: vcpkg-init/lock-versions.ps1 - arguments: '-Destination "$(Build.BinariesDirectory)" -VcpkgBaseVersion $(VCPKG_BASE_VERSION)' + arguments: '-Destination "$(Build.BinariesDirectory)" -VcpkgBaseVersion $(VCPKG_INITIAL_BASE_VERSION)' # Build and test vcpkg-ce - task: PowerShell@2 displayName: 'Download vcpkg-ce sources' @@ -174,6 +187,7 @@ jobs: variables: VCPKG_STANDALONE_BUNDLE_SHA: $[ dependencies.arch_independent.outputs['shas.VCPKG_STANDALONE_BUNDLE_SHA'] ] VCPKG_CE_SHA: $[ dependencies.arch_independent.outputs['shas.VCPKG_CE_SHA'] ] + VCPKG_BASE_VERSION: $[ dependencies.arch_independent.outputs['versions.VCPKG_BASE_VERSION'] ] steps: - task: CmdLine@2 displayName: "Download fmt library" @@ -207,6 +221,7 @@ jobs: variables: VCPKG_STANDALONE_BUNDLE_SHA: $[ dependencies.arch_independent.outputs['shas.VCPKG_STANDALONE_BUNDLE_SHA'] ] VCPKG_CE_SHA: $[ dependencies.arch_independent.outputs['shas.VCPKG_CE_SHA'] ] + VCPKG_BASE_VERSION: $[ dependencies.arch_independent.outputs['versions.VCPKG_BASE_VERSION'] ] steps: - task: CmdLine@2 displayName: "Download fmt library" @@ -241,6 +256,7 @@ jobs: variables: VCPKG_STANDALONE_BUNDLE_SHA: $[ dependencies.arch_independent.outputs['shas.VCPKG_STANDALONE_BUNDLE_SHA'] ] VCPKG_CE_SHA: $[ dependencies.arch_independent.outputs['shas.VCPKG_CE_SHA'] ] + VCPKG_BASE_VERSION: $[ dependencies.arch_independent.outputs['versions.VCPKG_BASE_VERSION'] ] steps: - task: CmdLine@2 displayName: "Download fmt library" @@ -280,6 +296,7 @@ jobs: variables: VCPKG_STANDALONE_BUNDLE_SHA: $[ dependencies.arch_independent.outputs['shas.VCPKG_STANDALONE_BUNDLE_SHA'] ] VCPKG_CE_SHA: $[ dependencies.arch_independent.outputs['shas.VCPKG_CE_SHA'] ] + VCPKG_BASE_VERSION: $[ dependencies.arch_independent.outputs['versions.VCPKG_BASE_VERSION'] ] steps: - task: PowerShell@2 displayName: "Download fmt library" diff --git a/include/vcpkg/archives.h b/include/vcpkg/archives.h index 92d264613e..d531562b20 100644 --- a/include/vcpkg/archives.h +++ b/include/vcpkg/archives.h @@ -1,9 +1,11 @@ #pragma once +#include +#include + #include #include -#include namespace vcpkg { @@ -17,6 +19,11 @@ namespace vcpkg View files, const Path& destination_dir); + // Compress the source directory into the destination file. + int compress_directory_to_zip(const VcpkgPaths& paths, const Path& source, const Path& destination); + + Command decompress_zip_archive_cmd(const VcpkgPaths& paths, const Path& dst, const Path& archive_path); + std::vector decompress_in_parallel(View jobs); void decompress_in_parallel(LineInfo, View jobs); } diff --git a/include/vcpkg/base/basic_checks.h b/include/vcpkg/base/basic_checks.h index 2ea7145993..a5e8d5056e 100644 --- a/include/vcpkg/base/basic_checks.h +++ b/include/vcpkg/base/basic_checks.h @@ -25,6 +25,9 @@ namespace vcpkg::Checks // Display an error message to the user and exit the tool. [[noreturn]] void exit_with_message(const LineInfo& line_info, StringView error_message); + // Display an error message and the line to the user and exit the tool. + [[noreturn]] void exit_with_message_and_line(const LineInfo& line_info, StringView error_message); + // If expression is false, call exit_fail. void check_exit(const LineInfo& line_info, bool expression); diff --git a/include/vcpkg/base/cofffilereader.h b/include/vcpkg/base/cofffilereader.h index d80963605c..72e88d620a 100644 --- a/include/vcpkg/base/cofffilereader.h +++ b/include/vcpkg/base/cofffilereader.h @@ -15,6 +15,7 @@ namespace vcpkg AMD64 = 0x8664, // x64 ARM = 0x1c0, // ARM little endian ARM64 = 0xaa64, // ARM64 little endian + ARM64EC = 0xa641, // ARM64 "emulation compatible" ARMNT = 0x1c4, // ARM Thumb-2 little endian EBC = 0xebc, // EFI byte code I386 = 0x14c, // Intel 386 or later processors and compatible processors diff --git a/include/vcpkg/base/expected.h b/include/vcpkg/base/expected.h index 913cc09c72..3814a6d35f 100644 --- a/include/vcpkg/base/expected.h +++ b/include/vcpkg/base/expected.h @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -131,12 +132,24 @@ namespace vcpkg explicit constexpr operator bool() const noexcept { return !m_s.has_error(); } constexpr bool has_value() const noexcept { return !m_s.has_error(); } + const T&& value_or_exit(const LineInfo& line_info) const&& + { + exit_if_error(line_info); + return std::move(*this->m_t.get()); + } + T&& value_or_exit(const LineInfo& line_info) && { exit_if_error(line_info); return std::move(*this->m_t.get()); } + T& value_or_exit(const LineInfo& line_info) & + { + exit_if_error(line_info); + return *this->m_t.get(); + } + const T& value_or_exit(const LineInfo& line_info) const& { exit_if_error(line_info); diff --git a/include/vcpkg/base/files.h b/include/vcpkg/base/files.h index ad7eb6a770..61d0081fcf 100644 --- a/include/vcpkg/base/files.h +++ b/include/vcpkg/base/files.h @@ -237,6 +237,10 @@ namespace vcpkg virtual std::vector get_regular_files_recursive(const Path& dir, std::error_code& ec) const = 0; std::vector get_regular_files_recursive(const Path& dir, LineInfo li) const; + virtual std::vector get_regular_files_recursive_lexically_proximate(const Path& dir, + std::error_code& ec) const = 0; + std::vector get_regular_files_recursive_lexically_proximate(const Path& dir, LineInfo li) const; + virtual std::vector get_regular_files_non_recursive(const Path& dir, std::error_code& ec) const = 0; std::vector get_regular_files_non_recursive(const Path& dir, LineInfo li) const; diff --git a/include/vcpkg/base/fwd/format.h b/include/vcpkg/base/fwd/format.h index 431d726e00..3afbdbec74 100644 --- a/include/vcpkg/base/fwd/format.h +++ b/include/vcpkg/base/fwd/format.h @@ -19,3 +19,14 @@ namespace fmt return fmt::formatter::format(static_cast(val), ctx); \ } \ } + +#define VCPKG_FORMAT_WITH_TO_STRING(Type) \ + template \ + struct fmt::formatter : fmt::formatter \ + { \ + template \ + auto format(Type const& val, FormatContext& ctx) const -> decltype(ctx.out()) \ + { \ + return fmt::formatter::format(val.to_string(), ctx); \ + } \ + } diff --git a/include/vcpkg/base/fwd/system.process.h b/include/vcpkg/base/fwd/system.process.h index 74f051c051..bf2f4625f2 100644 --- a/include/vcpkg/base/fwd/system.process.h +++ b/include/vcpkg/base/fwd/system.process.h @@ -5,4 +5,5 @@ namespace vcpkg struct CMakeVariable; struct Command; struct CommandLess; + struct ExitCodeAndOutput; } diff --git a/include/vcpkg/base/graphs.h b/include/vcpkg/base/graphs.h index ef8a1c6572..cc790c0fce 100644 --- a/include/vcpkg/base/graphs.h +++ b/include/vcpkg/base/graphs.h @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include @@ -10,6 +10,9 @@ namespace vcpkg::Graphs { + DECLARE_MESSAGE(GraphCycleDetected, (msg::value), "", "Cycle detected within graph at {value}:"); + DECLARE_MESSAGE(GraphCycleDetectedElement, (msg::value), "{LOCKED}", " {value}"); + enum class ExplorationStatus { // We have not visited this vertex @@ -67,12 +70,12 @@ namespace vcpkg::Graphs case ExplorationStatus::FULLY_EXPLORED: return; case ExplorationStatus::PARTIALLY_EXPLORED: { - print2("Cycle detected within graph at ", f.to_string(vertex), ":\n"); + msg::println(msgGraphCycleDetected, msg::value = vertex); for (auto&& node : exploration_status) { if (node.second == ExplorationStatus::PARTIALLY_EXPLORED) { - print2(" ", f.to_string(node.first), '\n'); + msg::println(msgGraphCycleDetectedElement, msg::value = node.first); } } Checks::exit_fail(VCPKG_LINE_INFO); diff --git a/include/vcpkg/base/messages.h b/include/vcpkg/base/messages.h index 8d37651bf8..56606d58b8 100644 --- a/include/vcpkg/base/messages.h +++ b/include/vcpkg/base/messages.h @@ -12,8 +12,6 @@ namespace vcpkg::msg { - struct LocalizedString; - namespace detail { template @@ -47,7 +45,7 @@ namespace vcpkg::msg StringView get_localization_comment(::size_t index); } - // load from "locale_base/${language}.json" + // load from "locale_base/messages.${language}.json" void threadunsafe_initialize_context(const Filesystem& fs, StringView language, const Path& locale_base); // initialize without any localized messages (use default messages only) void threadunsafe_initialize_context(); @@ -57,6 +55,7 @@ namespace vcpkg::msg LocalizedString() = default; operator StringView() const { return m_data; } const std::string& data() const { return m_data; } + std::string extract_data() { return std::exchange(m_data, ""); } static LocalizedString from_string_unchecked(std::string&& s) { @@ -89,6 +88,8 @@ namespace vcpkg::msg } }; + inline const char* to_printf_arg(const msg::LocalizedString& s) { return s.data().c_str(); } + struct LocalizedStringMapLess { using is_transparent = void; @@ -112,6 +113,16 @@ namespace vcpkg::msg inline void print(Color c, const LocalizedString& s) { write_unlocalized_text_to_stdout(c, s); } inline void print(const LocalizedString& s) { write_unlocalized_text_to_stdout(Color::none, s); } + inline void println(Color c, const LocalizedString& s) + { + write_unlocalized_text_to_stdout(c, s); + write_unlocalized_text_to_stdout(Color::none, "\n"); + } + inline void println(const LocalizedString& s) + { + write_unlocalized_text_to_stdout(Color::none, s); + write_unlocalized_text_to_stdout(Color::none, "\n"); + } template void print(Message m, Ts... args) @@ -155,10 +166,14 @@ namespace vcpkg::msg DECLARE_MSG_ARG(triplet); DECLARE_MSG_ARG(url); DECLARE_MSG_ARG(value); + DECLARE_MSG_ARG(expected); + DECLARE_MSG_ARG(actual); DECLARE_MSG_ARG(elapsed); DECLARE_MSG_ARG(version); DECLARE_MSG_ARG(list); DECLARE_MSG_ARG(output); + DECLARE_MSG_ARG(row); + DECLARE_MSG_ARG(column); #undef DECLARE_MSG_ARG // These are `...` instead of diff --git a/include/vcpkg/base/optional.h b/include/vcpkg/base/optional.h index d998f684f8..be49907b9d 100644 --- a/include/vcpkg/base/optional.h +++ b/include/vcpkg/base/optional.h @@ -400,6 +400,7 @@ namespace vcpkg return !rhs.m_base.has_value(); } + friend bool operator!=(const Optional& lhs, const Optional& rhs) noexcept { return !(lhs == rhs); } private: details::OptionalStorage m_base; diff --git a/include/vcpkg/base/parse.h b/include/vcpkg/base/parse.h index 9cb24680e2..9cbd890b7e 100644 --- a/include/vcpkg/base/parse.h +++ b/include/vcpkg/base/parse.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -42,16 +43,36 @@ namespace vcpkg::Parse virtual const std::string& get_message() const override; }; - struct ParserBase + struct SourceLoc { - struct SourceLoc - { - Unicode::Utf8Decoder it; - Unicode::Utf8Decoder start_of_line; - int row; - int column; - }; + Unicode::Utf8Decoder it; + Unicode::Utf8Decoder start_of_line; + int row; + int column; + }; + enum class MessageKind + { + Warning, + Error, + }; + + struct ParseMessage + { + SourceLoc location = {}; + msg::LocalizedString message; + + msg::LocalizedString format(StringView origin, MessageKind kind) const; + }; + + struct ParseMessages + { + std::unique_ptr error; + std::vector warnings; + }; + + struct ParserBase + { ParserBase(StringView text, StringView origin, TextRowCol init_rowcol = {}); static constexpr bool is_whitespace(char32_t ch) { return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'; } @@ -110,9 +131,17 @@ namespace vcpkg::Parse void add_error(std::string message) { add_error(std::move(message), cur_loc()); } void add_error(std::string message, const SourceLoc& loc); + void add_error(msg::LocalizedString&& message) { add_error(message.extract_data(), cur_loc()); } + void add_error(msg::LocalizedString&& message, const SourceLoc& loc) { add_error(message.extract_data(), loc); } + + void add_warning(msg::LocalizedString&& message) { add_warning(std::move(message), cur_loc()); } + void add_warning(msg::LocalizedString&& message, const SourceLoc& loc); + + const IParseError* get_error() const { return m_messages.error.get(); } + std::unique_ptr extract_error() { return std::move(m_messages.error); } - const Parse::IParseError* get_error() const { return m_err.get(); } - std::unique_ptr extract_error() { return std::move(m_err); } + const ParseMessages& messages() const { return m_messages; } + ParseMessages extract_messages() { return std::move(m_messages); } private: Unicode::Utf8Decoder m_it; @@ -123,6 +152,6 @@ namespace vcpkg::Parse StringView m_text; StringView m_origin; - std::unique_ptr m_err; + ParseMessages m_messages; }; } diff --git a/include/vcpkg/base/system.h b/include/vcpkg/base/system.h index b2e67bf84a..d5fcc92ca7 100644 --- a/include/vcpkg/base/system.h +++ b/include/vcpkg/base/system.h @@ -2,6 +2,7 @@ #include #include +#include #include #include #include diff --git a/include/vcpkg/base/unicode.h b/include/vcpkg/base/unicode.h index bfde0bcf07..80a4a507d3 100644 --- a/include/vcpkg/base/unicode.h +++ b/include/vcpkg/base/unicode.h @@ -14,12 +14,37 @@ namespace vcpkg::Unicode StartFour = 4, }; + constexpr static char32_t end_of_file = 0xFFFF'FFFF; + + enum class utf8_errc + { + NoError = 0, + InvalidCodeUnit = 1, + InvalidCodePoint = 2, + PairedSurrogates = 3, + UnexpectedContinue = 4, + UnexpectedStart = 5, + UnexpectedEof = 6, + }; + + const std::error_category& utf8_category() noexcept; + Utf8CodeUnitKind utf8_code_unit_kind(unsigned char code_unit) noexcept; int utf8_code_unit_count(Utf8CodeUnitKind kind) noexcept; int utf8_code_unit_count(char code_unit) noexcept; int utf8_encode_code_point(char (&array)[4], char32_t code_point) noexcept; + // returns {after-current-code-point, error}, + // and if error = NoError, then out = parsed code point. + // else, out = end_of_file. + std::pair utf8_decode_code_point(const char* first, + const char* last, + char32_t& out) noexcept; + + // uses the C++20 definition + bool is_double_width_code_point(char32_t ch) noexcept; + inline std::string& utf8_append_code_point(std::string& str, char32_t code_point) { if (static_cast(code_point) < 0x80) @@ -52,21 +77,6 @@ namespace vcpkg::Unicode char32_t utf16_surrogates_to_code_point(char32_t leading, char32_t trailing); - constexpr static char32_t end_of_file = 0xFFFF'FFFF; - - enum class utf8_errc - { - NoError = 0, - InvalidCodeUnit = 1, - InvalidCodePoint = 2, - PairedSurrogates = 3, - UnexpectedContinue = 4, - UnexpectedStart = 5, - UnexpectedEof = 6, - }; - - const std::error_category& utf8_category() noexcept; - inline std::error_code make_error_code(utf8_errc err) noexcept { return std::error_code(static_cast(err), utf8_category()); @@ -89,6 +99,7 @@ namespace vcpkg::Unicode struct Utf8Decoder { Utf8Decoder() noexcept; + explicit Utf8Decoder(StringView sv) : Utf8Decoder(sv.begin(), sv.end()) { } Utf8Decoder(const char* first, const char* last) noexcept; struct sentinel diff --git a/include/vcpkg/base/util.h b/include/vcpkg/base/util.h index 9c522910f8..88fd16b025 100644 --- a/include/vcpkg/base/util.h +++ b/include/vcpkg/base/util.h @@ -147,7 +147,17 @@ namespace vcpkg::Util { using std::begin; using std::end; - return std::find_if(begin(cont), end(cont), pred); + // allow cont.begin() to not have the same type as cont.end() + auto it = begin(cont); + auto last = end(cont); + for (; it != last; ++it) + { + if (pred(*it)) + { + break; + } + } + return it; } template diff --git a/include/vcpkg/binarycaching.h b/include/vcpkg/binarycaching.h index 8c89821c95..750d605a9c 100644 --- a/include/vcpkg/binarycaching.h +++ b/include/vcpkg/binarycaching.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -16,27 +17,6 @@ namespace vcpkg { - enum class RestoreResult - { - unavailable, - restored, - }; - - enum class CacheAvailability - { - unavailable, - available, - }; - - enum class CacheStatusState - { - unknown, // the cache status of the indicated package ABI is unknown - available, // the cache is known to contain the package ABI, but it has not been restored - restored, // the cache contains the ABI and it has been restored to the packages tree - }; - - struct IBinaryProvider; - struct CacheStatus { bool should_attempt_precheck(const IBinaryProvider* sender) const noexcept; @@ -67,57 +47,84 @@ namespace vcpkg /// Attempts to restore the package referenced by `action` into the packages directory. /// Prerequisite: action has a package_abi() - virtual RestoreResult try_restore(const VcpkgPaths& paths, - const Dependencies::InstallPlanAction& action) const = 0; + virtual RestoreResult try_restore(const Dependencies::InstallPlanAction& action) const = 0; /// Called upon a successful build of `action` to store those contents in the binary cache. /// Prerequisite: action has a package_abi() - virtual void push_success(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action) const = 0; + virtual void push_success(const Dependencies::InstallPlanAction& action) const = 0; /// Gives the IBinaryProvider an opportunity to batch any downloading or server communication for /// executing `actions`. /// `cache_status` is a vector with the same number of entries of actions, where each index corresponds /// to the action at the same index in `actions`. The provider must mark the cache status as appropriate. - virtual void prefetch(const VcpkgPaths& paths, - View actions, - View cache_status) const = 0; + /// Note: `actions` *might not* have package ABIs (for example, a --head package)! + /// Prerequisite: if `actions[i]` has no package ABI, `cache_status[i]` is nullptr. + virtual void prefetch(View actions, View cache_status) const = 0; /// Checks whether the `actions` are present in the cache, without restoring them. Used by CI to determine /// missing packages. /// `cache_status` is a view with the same number of entries of actions, where each index corresponds /// to the action at the same index in `actions`. The provider must mark the cache status as appropriate. - virtual void precheck(const VcpkgPaths& paths, - View actions, - View cache_status) const = 0; + /// Prerequisite: `actions` have package ABIs. + virtual void precheck(View actions, View cache_status) const = 0; + }; + + struct BinaryConfigParserState + { + bool m_cleared = false; + bool interactive = false; + std::string nugettimeout = "100"; + + std::vector archives_to_read; + std::vector archives_to_write; + + std::vector url_templates_to_get; + std::vector azblob_templates_to_put; + + std::vector gcs_read_prefixes; + std::vector gcs_write_prefixes; + + std::vector aws_read_prefixes; + std::vector aws_write_prefixes; + + std::vector sources_to_read; + std::vector sources_to_write; + + std::vector configs_to_read; + std::vector configs_to_write; + + std::vector secrets; + + void clear(); }; + ExpectedS create_binary_providers_from_configs_pure(const std::string& env_string, + View args); ExpectedS>> create_binary_providers_from_configs( - View args); - ExpectedS>> create_binary_providers_from_configs_pure( - const std::string& env_string, View args); + const VcpkgPaths& paths, View args); struct BinaryCache { BinaryCache() = default; - explicit BinaryCache(const VcpkgCmdArguments& args); + explicit BinaryCache(const VcpkgCmdArguments& args, const VcpkgPaths& paths); void install_providers(std::vector>&& providers); - void install_providers_for(const VcpkgCmdArguments& args); + void install_providers_for(const VcpkgCmdArguments& args, const VcpkgPaths& paths); /// Attempts to restore the package referenced by `action` into the packages directory. - RestoreResult try_restore(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action); + RestoreResult try_restore(const Dependencies::InstallPlanAction& action); /// Called upon a successful build of `action` to store those contents in the binary cache. - void push_success(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action); + void push_success(const Dependencies::InstallPlanAction& action); /// Gives the IBinaryProvider an opportunity to batch any downloading or server communication for /// executing `actions`. - void prefetch(const VcpkgPaths& paths, View actions); + void prefetch(View actions); /// Checks whether the `actions` are present in the cache, without restoring them. Used by CI to determine /// missing packages. /// Returns a vector where each index corresponds to the matching index in `actions`. - std::vector precheck(const VcpkgPaths& paths, View actions); + std::vector precheck(View actions); private: std::unordered_map m_status; diff --git a/include/vcpkg/binarycaching.private.h b/include/vcpkg/binarycaching.private.h index cf17787d3c..c1387cd6bf 100644 --- a/include/vcpkg/binarycaching.private.h +++ b/include/vcpkg/binarycaching.private.h @@ -32,7 +32,7 @@ namespace vcpkg { return make_nugetref(action.spec, action.source_control_file_and_location.value_or_exit(VCPKG_LINE_INFO) - .source_control_file->core_paragraph->version, + .source_control_file->core_paragraph->raw_version, action.abi_info.value_or_exit(VCPKG_LINE_INFO).package_abi, prefix); } diff --git a/include/vcpkg/fwd/binarycaching.h b/include/vcpkg/fwd/binarycaching.h new file mode 100644 index 0000000000..de46295d3f --- /dev/null +++ b/include/vcpkg/fwd/binarycaching.h @@ -0,0 +1,28 @@ +#pragma once + +namespace vcpkg +{ + enum class RestoreResult + { + unavailable, + restored, + }; + + enum class CacheAvailability + { + unavailable, + available, + }; + + enum class CacheStatusState + { + unknown, // the cache status of the indicated package ABI is unknown + available, // the cache is known to contain the package ABI, but it has not been restored + restored, // the cache contains the ABI and it has been restored to the packages tree + }; + + struct CacheStatus; + struct IBinaryProvider; + struct BinaryCache; + struct BinaryConfigParserState; +} diff --git a/include/vcpkg/fwd/configuration.h b/include/vcpkg/fwd/configuration.h index cddbbf024a..6be58b363c 100644 --- a/include/vcpkg/fwd/configuration.h +++ b/include/vcpkg/fwd/configuration.h @@ -4,4 +4,5 @@ namespace vcpkg { struct Configuration; struct RegistryConfig; + struct ManifestConfiguration; } diff --git a/include/vcpkg/packagespec.h b/include/vcpkg/packagespec.h index a5f3213a00..a9b9ee6cbf 100644 --- a/include/vcpkg/packagespec.h +++ b/include/vcpkg/packagespec.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -27,8 +28,6 @@ namespace vcpkg PackageSpec() = default; PackageSpec(std::string name, Triplet triplet) : m_name(std::move(name)), m_triplet(triplet) { } - static std::vector to_package_specs(const std::vector& ports, Triplet triplet); - const std::string& name() const; Triplet triplet() const; @@ -128,7 +127,7 @@ namespace vcpkg struct DependencyConstraint { - Versions::Constraint::Type type = Versions::Constraint::Type::None; + VersionConstraintKind type = VersionConstraintKind::None; std::string value; int port_version = 0; @@ -137,6 +136,8 @@ namespace vcpkg { return !(lhs == rhs); } + + Optional try_get_minimum_version() const; }; enum class ImplicitDefault : bool @@ -167,7 +168,7 @@ namespace vcpkg std::string name; std::string version; int port_version = 0; - Versions::Scheme version_scheme = Versions::Scheme::String; + VersionScheme version_scheme = VersionScheme::String; Json::Object extra_info; @@ -195,28 +196,39 @@ namespace vcpkg Optional parse_qualified_specifier(Parse::ParserBase& parser); } -namespace std +template +struct fmt::formatter { - template<> - struct hash + constexpr auto parse(format_parse_context& ctx) const -> decltype(ctx.begin()) { - size_t operator()(const vcpkg::PackageSpec& value) const - { - size_t hash = 17; - hash = hash * 31 + std::hash()(value.name()); - hash = hash * 31 + std::hash()(value.triplet()); - return hash; - } - }; + return vcpkg::basic_format_parse_impl(ctx); + } + template + auto format(const vcpkg::PackageSpec& spec, FormatContext& ctx) const -> decltype(ctx.out()) + { + return fmt::formatter{}.format(spec.to_string(), ctx); + } +}; - template<> - struct hash +template<> +struct std::hash +{ + size_t operator()(const vcpkg::PackageSpec& value) const { - size_t operator()(const vcpkg::FeatureSpec& value) const - { - size_t hash = std::hash()(value.spec()); - hash = hash * 31 + std::hash()(value.feature()); - return hash; - } - }; -} + size_t hash = 17; + hash = hash * 31 + std::hash()(value.name()); + hash = hash * 31 + std::hash()(value.triplet()); + return hash; + } +}; + +template<> +struct std::hash +{ + size_t operator()(const vcpkg::FeatureSpec& value) const + { + size_t hash = std::hash()(value.spec()); + hash = hash * 31 + std::hash()(value.feature()); + return hash; + } +}; diff --git a/include/vcpkg/platform-expression.h b/include/vcpkg/platform-expression.h index 5de13b7a24..423b60f4b1 100644 --- a/include/vcpkg/platform-expression.h +++ b/include/vcpkg/platform-expression.h @@ -77,6 +77,6 @@ namespace vcpkg::PlatformExpression }; // platform expression parses a platform expression; the EBNF of such is defined in - // /docs/maintainers/manifest-files.md#supports + // https://github.com/microsoft/vcpkg/blob/master/docs/maintainers/manifest-files.md#supports ExpectedS parse_platform_expression(StringView expression, MultipleBinaryOperators multiple_binary_operators); } diff --git a/include/vcpkg/portfileprovider.h b/include/vcpkg/portfileprovider.h index 71b9860918..c58a277971 100644 --- a/include/vcpkg/portfileprovider.h +++ b/include/vcpkg/portfileprovider.h @@ -32,17 +32,17 @@ namespace vcpkg::PortFileProvider struct IVersionedPortfileProvider { - virtual View get_port_versions(StringView port_name) const = 0; + virtual View get_port_versions(StringView port_name) const = 0; virtual ~IVersionedPortfileProvider() = default; virtual ExpectedS get_control_file( - const Versions::VersionSpec& version_spec) const = 0; + const VersionSpec& version_spec) const = 0; virtual void load_all_control_files(std::map& out) const = 0; }; struct IBaselineProvider { - virtual Optional get_baseline_version(StringView port_name) const = 0; + virtual Optional get_baseline_version(StringView port_name) const = 0; virtual ~IBaselineProvider() = default; }; diff --git a/include/vcpkg/registries.h b/include/vcpkg/registries.h index f903baa7ab..f94531af44 100644 --- a/include/vcpkg/registries.h +++ b/include/vcpkg/registries.h @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include @@ -51,9 +51,9 @@ namespace vcpkg struct RegistryEntry { - virtual View get_port_versions() const = 0; + virtual View get_port_versions() const = 0; - virtual ExpectedS get_path_to_version(const VersionT& version) const = 0; + virtual ExpectedS get_path_to_version(const Version& version) const = 0; virtual ~RegistryEntry() = default; }; @@ -69,7 +69,7 @@ namespace vcpkg // may result in duplicated port names; make sure to Util::sort_unique_erase at the end virtual void get_all_port_names(std::vector& port_names) const = 0; - virtual Optional get_baseline_version(StringView port_name) const = 0; + virtual Optional get_baseline_version(StringView port_name) const = 0; virtual Optional get_path_to_baseline_version(StringView port_name) const; @@ -110,7 +110,7 @@ namespace vcpkg // finds the correct registry for the port name // Returns the null pointer if there is no registry set up for that name const RegistryImplementation* registry_for_port(StringView port_name) const; - Optional baseline_for_port(StringView port_name) const; + Optional baseline_for_port(StringView port_name) const; View registries() const { return registries_; } @@ -141,14 +141,14 @@ namespace vcpkg ExpectedS>> get_builtin_versions(const VcpkgPaths& paths, StringView port_name); - ExpectedS>> get_builtin_baseline(const VcpkgPaths& paths); + ExpectedS>> get_builtin_baseline(const VcpkgPaths& paths); bool is_git_commit_sha(StringView sv); struct VersionDbEntry { - VersionT version; - Versions::Scheme scheme = Versions::Scheme::String; + Version version; + VersionScheme scheme = VersionScheme::String; // only one of these may be non-empty std::string git_tree; diff --git a/include/vcpkg/sourceparagraph.h b/include/vcpkg/sourceparagraph.h index 4338dcb706..5c541bd1b1 100644 --- a/include/vcpkg/sourceparagraph.h +++ b/include/vcpkg/sourceparagraph.h @@ -2,6 +2,7 @@ #include +#include #include #include @@ -60,8 +61,8 @@ namespace vcpkg struct SourceParagraph { std::string name; - Versions::Scheme version_scheme = Versions::Scheme::String; - std::string version; + VersionScheme version_scheme = VersionScheme::String; + std::string raw_version; int port_version = 0; std::vector description; std::vector summary; @@ -71,7 +72,12 @@ namespace vcpkg std::vector dependencies; std::vector overrides; std::vector default_features; - std::string license; // SPDX license expression + + // there are two distinct "empty" states here + // "user did not provide a license" -> nullopt + // "user provided license = null" -> {""} + Optional license; // SPDX license expression + Optional builtin_baseline; Optional vcpkg_configuration; // Currently contacts is only a Json::Object but it will eventually be unified with maintainers @@ -82,7 +88,7 @@ namespace vcpkg Json::Object extra_info; - VersionT to_versiont() const { return VersionT{version, port_version}; } + Version to_version() const { return Version{raw_version, port_version}; } friend bool operator==(const SourceParagraph& lhs, const SourceParagraph& rhs); friend bool operator!=(const SourceParagraph& lhs, const SourceParagraph& rhs) { return !(lhs == rhs); } @@ -114,11 +120,12 @@ namespace vcpkg const FeatureFlagSettings& flags, bool is_default_builtin_registry = true) const; - VersionT to_versiont() const { return core_paragraph->to_versiont(); } + Version to_version() const { return core_paragraph->to_version(); } SchemedVersion to_schemed_version() const { - return SchemedVersion{core_paragraph->version_scheme, core_paragraph->to_versiont()}; + return SchemedVersion{core_paragraph->version_scheme, core_paragraph->to_version()}; } + VersionSpec to_version_spec() const { return {core_paragraph->name, core_paragraph->to_version()}; } friend bool operator==(const SourceControlFile& lhs, const SourceControlFile& rhs); friend bool operator!=(const SourceControlFile& lhs, const SourceControlFile& rhs) { return !(lhs == rhs); } @@ -127,15 +134,14 @@ namespace vcpkg Json::Object serialize_manifest(const SourceControlFile& scf); Json::Object serialize_debug_manifest(const SourceControlFile& scf); - ExpectedS parse_manifest_configuration(StringView origin, - const Json::Object& manifest); + ExpectedS parse_manifest_configuration(StringView origin, const Json::Object& manifest); /// /// Named pair of a SourceControlFile and the location of this file /// struct SourceControlFileAndLocation { - VersionT to_versiont() const { return source_control_file->to_versiont(); } + Version to_version() const { return source_control_file->to_version(); } std::unique_ptr source_control_file; Path source_location; @@ -146,4 +152,6 @@ namespace vcpkg { return print_error_message({&error_info_list, 1}); } + + std::string parse_spdx_license_expression(StringView sv, Parse::ParseMessages& messages); } diff --git a/include/vcpkg/update.h b/include/vcpkg/update.h index 063e16997f..59cb939edd 100644 --- a/include/vcpkg/update.h +++ b/include/vcpkg/update.h @@ -6,7 +6,7 @@ #include #include -#include +#include namespace vcpkg { diff --git a/include/vcpkg/vcpkgpaths.h b/include/vcpkg/vcpkgpaths.h index 74785db6fe..680cda147e 100644 --- a/include/vcpkg/vcpkgpaths.h +++ b/include/vcpkg/vcpkgpaths.h @@ -102,25 +102,21 @@ namespace vcpkg const Path original_cwd; const Path root; - Path manifest_root_dir; - Path downloads; - Path triplets; - Path community_triplets; - Path scripts; - Path prefab; - private: - Path builtin_ports; + const std::unique_ptr m_pimpl; public: - Path builtin_registry_versions; - - Path tools; - Path buildsystems; - Path buildsystems_msbuild_targets; - Path buildsystems_msbuild_props; - - Path ports_cmake; + const Path builtin_registry_versions; + const Path scripts; + const Path prefab; + const Path buildsystems; + const Path buildsystems_msbuild_targets; + const Path buildsystems_msbuild_props; + const Path downloads; + const Path tools; + const Path ports_cmake; + const Path triplets; + const Path community_triplets; std::string get_toolver_diagnostics() const; @@ -169,15 +165,8 @@ namespace vcpkg // the directory of the builtin ports // this should be used only for helper commands, not core commands like `install`. - Path builtin_ports_directory() const { return this->builtin_ports; } + const Path& builtin_ports_directory() const; bool use_git_default_registry() const; - - private: - Optional maybe_get_tmp_path(const std::string* arg_path, - StringLiteral root_subpath, - StringLiteral readonly_subpath, - LineInfo li) const; - std::unique_ptr m_pimpl; }; } diff --git a/include/vcpkg/versiondeserializers.h b/include/vcpkg/versiondeserializers.h index 158fb2eaea..26db99d01e 100644 --- a/include/vcpkg/versiondeserializers.h +++ b/include/vcpkg/versiondeserializers.h @@ -6,22 +6,16 @@ #include #include -#include namespace vcpkg { - Json::IDeserializer& get_versiont_deserializer_instance(); - Json::IDeserializer& get_versiontag_deserializer_instance(); + Json::IDeserializer& get_version_deserializer_instance(); + Json::IDeserializer& get_versiontag_deserializer_instance(); struct SchemedVersion { - SchemedVersion() = default; - SchemedVersion(Versions::Scheme scheme_, VersionT versiont_) : scheme(scheme_), versiont(std::move(versiont_)) - { - } - - Versions::Scheme scheme = Versions::Scheme::String; - VersionT versiont; + VersionScheme scheme; + Version version; }; SchemedVersion visit_required_schemed_deserializer(StringView parent_type, @@ -31,7 +25,7 @@ namespace vcpkg View schemed_deserializer_fields(); void serialize_schemed_version(Json::Object& out_obj, - Versions::Scheme scheme, + VersionScheme scheme, const std::string& version, int port_version, bool always_emit_port_version = false); diff --git a/include/vcpkg/versions.h b/include/vcpkg/versions.h index 3d5451325b..90475beda8 100644 --- a/include/vcpkg/versions.h +++ b/include/vcpkg/versions.h @@ -1,22 +1,63 @@ #pragma once -#include +#include -#include +#include -namespace vcpkg::Versions +namespace vcpkg { - using Version = VersionT; + struct Version + { + Version() noexcept; + Version(std::string&& value, int port_version); + Version(const std::string& value, int port_version); + + std::string to_string() const; + void to_string(std::string& out) const; + + friend bool operator==(const Version& left, const Version& right); + friend bool operator!=(const Version& left, const Version& right); + + // Version has no operator< because without a scheme it is not necessarily semantically comparable; + // VersionMapLess is provided as a less than comparison for use in std::map. + friend struct VersionMapLess; + + const std::string text() const { return m_text; } + int port_version() const { return m_port_version; } + + private: + std::string m_text; + int m_port_version = 0; + }; + + struct VersionDiff + { + Version left; + Version right; + + VersionDiff() noexcept; + VersionDiff(const Version& left, const Version& right); + + std::string to_string() const; + }; + + struct VersionMapLess + { + bool operator()(const Version& left, const Version& right) const; + }; enum class VerComp { - unk, - lt, - eq, - gt, + unk = -2, + lt = -1, // these values are chosen to align with traditional -1/0/1 for less/equal/greater + eq = 0, + gt = 1, }; - enum class Scheme + // converts a strcmp <0/0/>0 style integer into a VerComp + VerComp int_to_vercomp(int comparison_result); + + enum class VersionScheme { Relaxed, Semver, @@ -24,17 +65,19 @@ namespace vcpkg::Versions String }; - void to_string(std::string& out, Scheme scheme); + void to_string(std::string& out, VersionScheme scheme); struct VersionSpec { std::string port_name; - VersionT version; + Version version; - VersionSpec(const std::string& port_name, const VersionT& version); + VersionSpec(const std::string& port_name, const Version& version); VersionSpec(const std::string& port_name, const std::string& version_string, int port_version); + std::string to_string() const; + friend bool operator==(const VersionSpec& lhs, const VersionSpec& rhs); friend bool operator!=(const VersionSpec& lhs, const VersionSpec& rhs); }; @@ -52,30 +95,44 @@ namespace vcpkg::Versions std::vector version; std::vector identifiers; + + friend bool operator==(const DotVersion& lhs, const DotVersion& rhs); + friend bool operator!=(const DotVersion& lhs, const DotVersion& rhs) { return !(lhs == rhs); } + friend bool operator<(const DotVersion& lhs, const DotVersion& rhs); + friend bool operator>(const DotVersion& lhs, const DotVersion& rhs) { return rhs < lhs; } + friend bool operator>=(const DotVersion& lhs, const DotVersion& rhs) { return !(lhs < rhs); } + friend bool operator<=(const DotVersion& lhs, const DotVersion& rhs) { return !(rhs < lhs); } + + static ExpectedS try_parse(const std::string& str, VersionScheme target_scheme); + static ExpectedS try_parse_relaxed(const std::string& str); + static ExpectedS try_parse_semver(const std::string& str); }; + VerComp compare(const DotVersion& a, const DotVersion& b); + struct DateVersion { std::string original_string; std::string version_string; std::vector identifiers; - static ExpectedS from_string(const std::string& str); - }; + friend bool operator==(const DateVersion& lhs, const DateVersion& rhs); + friend bool operator!=(const DateVersion& lhs, const DateVersion& rhs) { return !(lhs == rhs); } + friend bool operator<(const DateVersion& lhs, const DateVersion& rhs); + friend bool operator>(const DateVersion& lhs, const DateVersion& rhs) { return rhs < lhs; } + friend bool operator>=(const DateVersion& lhs, const DateVersion& rhs) { return !(lhs < rhs); } + friend bool operator<=(const DateVersion& lhs, const DateVersion& rhs) { return !(rhs < lhs); } - ExpectedS relaxed_from_string(const std::string& str); - ExpectedS semver_from_string(const std::string& str); + static ExpectedS try_parse(const std::string& str); + }; - VerComp compare(const std::string& a, const std::string& b, Scheme scheme); - VerComp compare(const DotVersion& a, const DotVersion& b); VerComp compare(const DateVersion& a, const DateVersion& b); - struct Constraint + enum class VersionConstraintKind { - enum class Type - { - None, - Minimum - }; + None, + Minimum }; } + +VCPKG_FORMAT_WITH_TO_STRING(vcpkg::VersionSpec); diff --git a/include/vcpkg/versiont.h b/include/vcpkg/versiont.h deleted file mode 100644 index 910183b9d4..0000000000 --- a/include/vcpkg/versiont.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include - -namespace vcpkg -{ - struct VersionT - { - VersionT() noexcept; - VersionT(std::string&& value, int port_version); - VersionT(const std::string& value, int port_version); - - std::string to_string() const; - void to_string(std::string& out) const; - - friend bool operator==(const VersionT& left, const VersionT& right); - friend bool operator!=(const VersionT& left, const VersionT& right); - - friend struct VersionTMapLess; - - const std::string text() const { return m_text; } - int port_version() const { return m_port_version; } - - private: - std::string m_text; - int m_port_version = 0; - }; - - struct VersionDiff - { - VersionT left; - VersionT right; - - VersionDiff() noexcept; - VersionDiff(const VersionT& left, const VersionT& right); - - std::string to_string() const; - }; - - struct VersionTMapLess - { - bool operator()(const VersionT& left, const VersionT& right) const; - }; -} diff --git a/locales/en.json b/locales/messages.json similarity index 54% rename from locales/en.json rename to locales/messages.json index 87182db2cd..3d0a404e1d 100644 --- a/locales/en.json +++ b/locales/messages.json @@ -5,9 +5,11 @@ "AwsFailedToDownload": "aws failed to download with exit code: {value}\n{output}", "AwsRestoredPackages": "Restored {value} packages from AWS servers in {elapsed}s", "AwsUploadedPackages": "Uploaded binaries to {value} AWS servers", + "EmptyLicenseExpression": "SPDX license expression was empty.", "ErrorIndividualPackagesUnsupported": "Error: In manifest mode, `vcpkg install` does not support individual package arguments.\nTo install additional packages, edit vcpkg.json and then run `vcpkg install` without any package arguments.", "ErrorInvalidClassicModeOption": "Error: The option {value} is not supported in classic mode and no manifest was found.", "ErrorInvalidManifestModeOption": "Error: The option {value} is not supported in manifest mode.", + "ErrorMissingVcpkgRoot": "Error: Could not detect vcpkg-root. If you are trying to use a copy of vcpkg that you've built, you must define the VCPKG_ROOT environment variable to point to a cloned copy of {url}.", "ErrorNoVSInstance": "Error: in triplet {triplet}: Unable to find a valid Visual Studio instance", "ErrorNoVSInstanceAt": " at \"{path}\"", "_ErrorNoVSInstanceAt.comment": "Printed after ErrorNoVSInstance on a separate line", @@ -20,21 +22,49 @@ "ErrorRequirePackagesToInstall": "Error: No packages were listed for installation and no manifest was found.", "ErrorVcvarsUnsupported": "Error: in triplet {triplet}: Use of Visual Studio's Developer Prompt is unsupported on non-Windows hosts.\nDefine 'VCPKG_CMAKE_SYSTEM_NAME' or 'VCPKG_CHAINLOAD_TOOLCHAIN_FILE' in the triplet file.", "ForceSystemBinariesOnWeirdPlatforms": "Environment variable VCPKG_FORCE_SYSTEM_BINARIES must be set on arm, s390x, and ppc64le platforms.", + "FormattedParseError": "error: {value}", + "FormattedParseMessageExpression": " on expression: {value}", + "FormattedParseMessageLocation": "{path}:{row}:{column}: ", + "_FormattedParseMessageLocation.comment": "{LOCKED}", + "FormattedParseWarning": "warning: {value}", + "GraphCycleDetected": "Cycle detected within graph at {value}:", + "GraphCycleDetectedElement": " {value}", + "_GraphCycleDetectedElement.comment": "{LOCKED}", "IllegalFeatures": "Error: List of features is not allowed in this contect", "IllegalPlatformSpec": "Error: Platform qualifier is not allowed in this context", + "LicenseExpressionContainsExtraPlus": "SPDX license expression contains an extra '+'. These are only allowed directly after a license identifier.", + "LicenseExpressionContainsInvalidCharacter": "SPDX license expression contains an invalid character (0x{value:02x} '{value}').", + "LicenseExpressionContainsUnicode": "SPDX license expression contains a unicode character (U+{value:04x} '{pretty_value}'), but these expressions are ASCII-only.", + "LicenseExpressionDocumentRefUnsupported": "The current implementation does not support DocumentRef- SPDX references.", + "LicenseExpressionExpectCompoundFoundParen": "Expected a compound or the end of the string, found a parenthesis.", + "LicenseExpressionExpectCompoundFoundWith": "Expected either AND or OR, found WITH (WITH is only allowed after license names, not parenthesized expressions).", + "LicenseExpressionExpectCompoundFoundWord": "Expected either AND or OR, found a license or exception name: '{value}'.", + "LicenseExpressionExpectCompoundOrWithFoundWord": "Expected either AND, OR, or WITH, found a license or exception name: '{value}'.", + "LicenseExpressionExpectExceptionFoundCompound": "Expected an exception name, found the compound {value}.", + "LicenseExpressionExpectExceptionFoundEof": "Expected an exception name, found the end of the string.", + "LicenseExpressionExpectExceptionFoundParen": "Expected an exception name, found a parenthesis.", + "LicenseExpressionExpectLicenseFoundCompound": "Expected a license name, found the compound {value}.", + "LicenseExpressionExpectLicenseFoundEof": "Expected a license name, found the end of the string.", + "LicenseExpressionExpectLicenseFoundParen": "Expected a license name, found a parenthesis.", + "LicenseExpressionImbalancedParens": "There was a close parenthesis without an opening parenthesis.", + "LicenseExpressionUnknownException": "Unknown license exception identifier '{value}'. Known values are listed at https://spdx.org/licenses/exceptions-index.html", + "LicenseExpressionUnknownLicense": "Unknown license identifier '{value}'. Known values are listed at https://spdx.org/licenses/", "NoLocalizationForMessages": "No localization for the following messages:", + "ProcessorArchitectureMalformed": "Failed to parse %PROCESSOR_ARCHITECTURE% ({value}) as a valid CPU architecture.", + "ProcessorArchitectureMissing": "The required environment variable %PROCESSOR_ARCHITECTURE% is missing.", + "ProcessorArchitectureW6432Malformed": "Failed to parse %PROCESSOR_ARCHITEW6432% ({value}) as a valid CPU architecture. Falling back to %PROCESSOR_ARCHITECTURE%.", "SeeURL": "See {url} for more information.", "UnsupportedSystemName": "Error: Could not map VCPKG_CMAKE_SYSTEM_NAME '{value}' to a vcvarsall platform. Supported system names are '', 'Windows' and 'WindowsStore'.", "UnsupportedToolchain": "Error: in triplet {triplet}: Unable to find a valid toolchain combination.\n The requested target architecture was {value}\n The selected Visual Studio instance is at {path}\n The available toolchain combinations are {list}\n", "UsingManifestAt": "Using manifest file at {path}.", "VSExaminedInstances": "The following Visual Studio instances were considered:", "VSExaminedPaths": "The following paths were examined for Visual Studio instances:", - "VSExcludedByLanguagePack": "The following VS instances were excluded because the English language pack is unavailable:", "VSNoInstances": "Could not locate a complete Visual Studio instance", "VcpkgDisallowedClassicMode": "Error: Could not locate a manifest (vcpkg.json) above the current working directory.\nThis vcpkg distribution does not have a classic mode instance.", "VcpkgHasCrashed": "vcpkg.exe has crashed.\nPlease send an email to:\n {email}\ncontaining a brief summary of what you were trying to do and the following data blob:\n\nVersion={version}\nEXCEPTION='{error}'\nCMD=", "VcpkgHasCrashedArgument": "{value}|", "_VcpkgHasCrashedArgument.comment": "{LOCKED}", "VcpkgInvalidCommand": "invalid command: {value}", - "VcpkgSendMetricsButDisabled": "Warning: passed --sendmetrics, but metrics are disabled." + "VcpkgSendMetricsButDisabled": "Warning: passed --sendmetrics, but metrics are disabled.", + "VersionSpecMismatch": "Error: Failed to load port because version specs did not match\n Path: {path}\n Expected: {expected}\n Actual: {actual}" } diff --git a/src/vcpkg-test/binarycaching.cpp b/src/vcpkg-test/binarycaching.cpp index 2239f323c1..6da6ba9915 100644 --- a/src/vcpkg-test/binarycaching.cpp +++ b/src/vcpkg-test/binarycaching.cpp @@ -18,27 +18,34 @@ using namespace vcpkg; struct KnowNothingBinaryProvider : IBinaryProvider { - RestoreResult try_restore(const VcpkgPaths&, const Dependencies::InstallPlanAction&) const override + RestoreResult try_restore(const Dependencies::InstallPlanAction& action) const override { + CHECK(action.has_package_abi()); return RestoreResult::unavailable; } - virtual void push_success(const VcpkgPaths&, const Dependencies::InstallPlanAction&) const override { } - virtual void prefetch(const VcpkgPaths&, - View, - View) const override + virtual void push_success(const Dependencies::InstallPlanAction& action) const override { + CHECK(action.has_package_abi()); } - virtual void precheck(const VcpkgPaths&, - View, + + virtual void prefetch(View actions, View cache_status) const override { + REQUIRE(actions.size() == cache_status.size()); + for (size_t idx = 0; idx < cache_status.size(); ++idx) + { + CHECK(actions[idx].has_package_abi() == (cache_status[idx] != nullptr)); + } + } + virtual void precheck(View actions, + View cache_status) const override + { + REQUIRE(actions.size() == cache_status.size()); for (const auto c : cache_status) { - if (c) - { - c->mark_unavailable(this); - } + CHECK(c); + c->mark_unavailable(this); } } }; @@ -359,6 +366,39 @@ Features: a, b } } +TEST_CASE ("Provider nullptr checks", "[BinaryCache]") +{ + // create a binary cache to test + BinaryCache uut; + std::vector> providers; + providers.emplace_back(std::make_unique()); + uut.install_providers(std::move(providers)); + + // create an action plan with an action without a package ABI set + auto pghs = Paragraphs::parse_paragraphs(R"( +Source: someheadpackage +Version: 1.5 +Description: +)", + ""); + REQUIRE(pghs.has_value()); + auto maybe_scf = SourceControlFile::parse_control_file("", std::move(*pghs.get())); + REQUIRE(maybe_scf.has_value()); + SourceControlFileAndLocation scfl{std::move(*maybe_scf.get()), Path()}; + std::vector install_plan; + install_plan.emplace_back(PackageSpec{"someheadpackage", Test::X64_WINDOWS}, + scfl, + Dependencies::RequestType::USER_REQUESTED, + Test::ARM_UWP, + std::map>{}); + Dependencies::InstallPlanAction& ipa_without_abi = install_plan.back(); + + // test that the binary cache does the right thing. See also CHECKs etc. in KnowNothingBinaryProvider + uut.push_success(ipa_without_abi); // should have no effects + CHECK(uut.try_restore(ipa_without_abi) == RestoreResult::unavailable); + uut.prefetch(install_plan); // should have no effects +} + TEST_CASE ("XmlSerializer", "[XmlSerializer]") { XmlSerializer xml; diff --git a/src/vcpkg-test/catch.cpp b/src/vcpkg-test/catch.cpp index ca13c34d3c..092c323848 100644 --- a/src/vcpkg-test/catch.cpp +++ b/src/vcpkg-test/catch.cpp @@ -1,12 +1,16 @@ #define CATCH_CONFIG_RUNNER #include +#include #include #include int main(int argc, char** argv) { + vcpkg::msg::threadunsafe_initialize_context(); if (vcpkg::get_environment_variable("VCPKG_DEBUG").value_or("") == "1") vcpkg::Debug::g_debugging = true; + // We set VCPKG_ROOT to an invalid value to ensure unit tests do not attempt to instantiate VcpkgRoot + vcpkg::set_environment_variable("VCPKG_ROOT", "VCPKG_TESTS_SHOULD_NOT_USE_VCPKG_ROOT"); return Catch::Session().run(argc, argv); } diff --git a/src/vcpkg-test/dependencies.cpp b/src/vcpkg-test/dependencies.cpp index c8b1c90f24..e9db3d293f 100644 --- a/src/vcpkg-test/dependencies.cpp +++ b/src/vcpkg-test/dependencies.cpp @@ -24,9 +24,9 @@ using Test::PackageSpecMap; struct MockBaselineProvider : PortFileProvider::IBaselineProvider { - mutable std::map> v; + mutable std::map> v; - Optional get_baseline_version(StringView name) const override + Optional get_baseline_version(StringView name) const override { auto it = v.find(name); if (it == v.end()) return nullopt; @@ -36,16 +36,16 @@ struct MockBaselineProvider : PortFileProvider::IBaselineProvider struct MockVersionedPortfileProvider : PortFileProvider::IVersionedPortfileProvider { - mutable std::map> v; + mutable std::map> v; ExpectedS get_control_file( - const vcpkg::Versions::VersionSpec& versionspec) const override + const vcpkg::VersionSpec& versionspec) const override { return get_control_file(versionspec.port_name, versionspec.version); } ExpectedS get_control_file(const std::string& name, - const vcpkg::Versions::Version& version) const + const vcpkg::Version& version) const { auto it = v.find(name); if (it == v.end()) return std::string("Unknown port name"); @@ -54,15 +54,21 @@ struct MockVersionedPortfileProvider : PortFileProvider::IVersionedPortfileProvi return it2->second; } - virtual View get_port_versions(StringView) const override { Checks::unreachable(VCPKG_LINE_INFO); } + virtual View get_port_versions(StringView) const override { Checks::unreachable(VCPKG_LINE_INFO); } SourceControlFileAndLocation& emplace(std::string&& name, - Versions::Version&& version, - Versions::Scheme scheme = Versions::Scheme::String) + Version&& version, + VersionScheme scheme = VersionScheme::String) { +#if defined(__cpp_lib_map_try_emplace) && __cpp_lib_map_try_emplace >= 201411 + auto it = v.try_emplace(name).first; +#else // ^^^ has try_emplace / no try_emplace vvv auto it = v.find(name); if (it == v.end()) - it = v.emplace(name, std::map{}).first; + { + it = v.emplace(std::piecewise_construct, std::forward_as_tuple(name), std::forward_as_tuple()).first; + } +#endif auto it2 = it->second.find(version); if (it2 == it->second.end()) @@ -70,12 +76,13 @@ struct MockVersionedPortfileProvider : PortFileProvider::IVersionedPortfileProvi auto scf = std::make_unique(); auto core = std::make_unique(); core->name = name; - core->version = version.text(); + core->raw_version = version.text(); core->port_version = version.port_version(); core->version_scheme = scheme; scf->core_paragraph = std::move(core); it2 = it->second.emplace(version, SourceControlFileAndLocation{std::move(scf), name}).first; } + return it2->second; } @@ -85,9 +92,6 @@ struct MockVersionedPortfileProvider : PortFileProvider::IVersionedPortfileProvi } }; -using Versions::Constraint; -using Versions::Scheme; - template T unwrap(ExpectedS e) { @@ -120,18 +124,18 @@ static void check_name_and_features(const Dependencies::InstallPlanAction& ipa, static void check_name_and_version(const Dependencies::InstallPlanAction& ipa, StringLiteral name, - Versions::Version v, + Version v, std::initializer_list features = {}) { check_name_and_features(ipa, name, features); if (auto scfl = ipa.source_control_file_and_location.get()) { - CHECK(scfl->source_control_file->core_paragraph->version == v.text()); + CHECK(scfl->source_control_file->core_paragraph->raw_version == v.text()); CHECK(scfl->source_control_file->core_paragraph->port_version == v.port_version()); } } -static void check_semver_version(const ExpectedS& maybe_version, +static void check_semver_version(const ExpectedS& maybe_version, const std::string& version_string, const std::string& prerelease_string, uint64_t major, @@ -149,7 +153,7 @@ static void check_semver_version(const ExpectedS& maybe_ve CHECK(actual_version.identifiers == identifiers); } -static void check_relaxed_version(const ExpectedS& maybe_version, +static void check_relaxed_version(const ExpectedS& maybe_version, const std::vector& version, const std::vector& identifiers = {}) { @@ -158,7 +162,7 @@ static void check_relaxed_version(const ExpectedS& maybe_v CHECK(actual_version.identifiers == identifiers); } -static void check_date_version(const ExpectedS& maybe_version, +static void check_date_version(const ExpectedS& maybe_version, const std::string& version_string, const std::vector& identifiers) { @@ -191,8 +195,8 @@ struct MockOverlayProvider : PortFileProvider::IOverlayProvider } SourceControlFileAndLocation& emplace(const std::string& name, - Versions::Version&& version, - Versions::Scheme scheme = Versions::Scheme::String) + Version&& version, + VersionScheme scheme = VersionScheme::String) { auto it = mappings.find(name); if (it == mappings.end()) @@ -200,7 +204,7 @@ struct MockOverlayProvider : PortFileProvider::IOverlayProvider auto scf = std::make_unique(); auto core = std::make_unique(); core->name = name; - core->version = version.text(); + core->raw_version = version.text(); core->port_version = version.port_version(); core->version_scheme = scheme; scf->core_paragraph = std::move(core); @@ -388,7 +392,7 @@ TEST_CASE ("basic version install scheme baseline missing success", "[versionpla bp, var_provider, { - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "2"}}, + Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "2"}}, }, {}, toplevel_spec())); @@ -428,7 +432,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::Minimum, "2"}}}, {}, toplevel_spec()); + vp, bp, var_provider, {Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "2"}}}, {}, toplevel_spec()); REQUIRE(install_plan.has_value()); } @@ -445,14 +449,15 @@ TEST_CASE ("version install scheme baseline conflict", "[versionplan]") MockCMakeVarProvider var_provider; - auto install_plan = create_versioned_install_plan(vp, - bp, - var_provider, - { - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "3"}}, - }, - {}, - toplevel_spec()); + auto install_plan = + create_versioned_install_plan(vp, + bp, + var_provider, + { + Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "3"}}, + }, + {}, + toplevel_spec()); REQUIRE(!install_plan.has_value()); } @@ -474,7 +479,7 @@ TEST_CASE ("version install string port version", "[versionplan]") bp, var_provider, { - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "2", 1}}, + Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "2", 1}}, }, {}, toplevel_spec())); @@ -500,7 +505,7 @@ TEST_CASE ("version install string port version 2", "[versionplan]") bp, var_provider, { - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "2", 0}}, + Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "2", 0}}, }, {}, toplevel_spec())); @@ -517,10 +522,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::Minimum, "1"}}, + Dependency{"b", {}, {}, DependencyConstraint{VersionConstraintKind::Minimum, "1"}}, }; vp.emplace("a", {"2", 1}).source_control_file->core_paragraph->dependencies = { - Dependency{"b", {}, {}, DependencyConstraint{Constraint::Type::Minimum, "2"}}, + Dependency{"b", {}, {}, DependencyConstraint{VersionConstraintKind::Minimum, "2"}}, }; vp.emplace("b", {"1", 0}); vp.emplace("b", {"2", 0}); @@ -532,7 +537,7 @@ TEST_CASE ("version install transitive string", "[versionplan]") bp, var_provider, { - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "2", 1}}, + Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "2", 1}}, }, {}, toplevel_spec())); @@ -550,8 +555,8 @@ TEST_CASE ("version install simple relaxed", "[versionplan]") bp.v["a"] = {"2", 0}; MockVersionedPortfileProvider vp; - vp.emplace("a", {"2", 0}, Scheme::Relaxed); - vp.emplace("a", {"3", 0}, Scheme::Relaxed); + vp.emplace("a", {"2", 0}, VersionScheme::Relaxed); + vp.emplace("a", {"3", 0}, VersionScheme::Relaxed); MockCMakeVarProvider var_provider; @@ -560,7 +565,7 @@ TEST_CASE ("version install simple relaxed", "[versionplan]") bp, var_provider, { - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "3", 0}}, + Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "3", 0}}, }, {}, toplevel_spec())); @@ -576,12 +581,12 @@ TEST_CASE ("version install transitive relaxed", "[versionplan]") bp.v["b"] = {"2", 0}; MockVersionedPortfileProvider vp; - vp.emplace("a", {"2", 0}, Scheme::Relaxed); - vp.emplace("a", {"3", 0}, Scheme::Relaxed).source_control_file->core_paragraph->dependencies = { - Dependency{"b", {}, {}, DependencyConstraint{Constraint::Type::Minimum, "3"}}, + vp.emplace("a", {"2", 0}, VersionScheme::Relaxed); + vp.emplace("a", {"3", 0}, VersionScheme::Relaxed).source_control_file->core_paragraph->dependencies = { + Dependency{"b", {}, {}, DependencyConstraint{VersionConstraintKind::Minimum, "3"}}, }; - vp.emplace("b", {"2", 0}, Scheme::Relaxed); - vp.emplace("b", {"3", 0}, Scheme::Relaxed); + vp.emplace("b", {"2", 0}, VersionScheme::Relaxed); + vp.emplace("b", {"3", 0}, VersionScheme::Relaxed); MockCMakeVarProvider var_provider; @@ -590,7 +595,7 @@ TEST_CASE ("version install transitive relaxed", "[versionplan]") bp, var_provider, { - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "3", 0}}, + Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "3", 0}}, }, {}, toplevel_spec())); @@ -607,17 +612,17 @@ TEST_CASE ("version install diamond relaxed", "[versionplan]") bp.v["b"] = {"3", 0}; MockVersionedPortfileProvider vp; - vp.emplace("a", {"2", 0}, Scheme::Relaxed); - vp.emplace("a", {"3", 0}, Scheme::Relaxed).source_control_file->core_paragraph->dependencies = { - Dependency{"b", {}, {}, DependencyConstraint{Constraint::Type::Minimum, "2", 1}}, - Dependency{"c", {}, {}, DependencyConstraint{Constraint::Type::Minimum, "5", 1}}, + vp.emplace("a", {"2", 0}, VersionScheme::Relaxed); + vp.emplace("a", {"3", 0}, VersionScheme::Relaxed).source_control_file->core_paragraph->dependencies = { + Dependency{"b", {}, {}, DependencyConstraint{VersionConstraintKind::Minimum, "2", 1}}, + Dependency{"c", {}, {}, DependencyConstraint{VersionConstraintKind::Minimum, "5", 1}}, }; - vp.emplace("b", {"2", 1}, Scheme::Relaxed); - vp.emplace("b", {"3", 0}, Scheme::Relaxed).source_control_file->core_paragraph->dependencies = { - Dependency{"c", {}, {}, DependencyConstraint{Constraint::Type::Minimum, "9", 2}}, + vp.emplace("b", {"2", 1}, VersionScheme::Relaxed); + vp.emplace("b", {"3", 0}, VersionScheme::Relaxed).source_control_file->core_paragraph->dependencies = { + Dependency{"c", {}, {}, DependencyConstraint{VersionConstraintKind::Minimum, "9", 2}}, }; - vp.emplace("c", {"5", 1}, Scheme::Relaxed); - vp.emplace("c", {"9", 2}, Scheme::Relaxed); + vp.emplace("c", {"5", 1}, VersionScheme::Relaxed); + vp.emplace("c", {"9", 2}, VersionScheme::Relaxed); MockCMakeVarProvider var_provider; @@ -626,8 +631,8 @@ TEST_CASE ("version install diamond relaxed", "[versionplan]") bp, var_provider, { - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "3", 0}}, - Dependency{"b", {}, {}, {Constraint::Type::Minimum, "2", 1}}, + Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "3", 0}}, + Dependency{"b", {}, {}, {VersionConstraintKind::Minimum, "2", 1}}, }, {}, toplevel_spec())); @@ -640,93 +645,91 @@ TEST_CASE ("version install diamond relaxed", "[versionplan]") TEST_CASE ("version parse semver", "[versionplan]") { - check_semver_version(Versions::semver_from_string("1.2.3"), "1.2.3", "", 1, 2, 3, {}); - check_semver_version(Versions::semver_from_string("1.0.0-alpha"), "1.0.0", "alpha", 1, 0, 0, {"alpha"}); - check_semver_version(Versions::semver_from_string("1.0.0-0alpha0"), "1.0.0", "0alpha0", 1, 0, 0, {"0alpha0"}); + check_semver_version(DotVersion::try_parse_semver("1.2.3"), "1.2.3", "", 1, 2, 3, {}); + check_semver_version(DotVersion::try_parse_semver("1.0.0-alpha"), "1.0.0", "alpha", 1, 0, 0, {"alpha"}); + check_semver_version(DotVersion::try_parse_semver("1.0.0-0alpha0"), "1.0.0", "0alpha0", 1, 0, 0, {"0alpha0"}); check_semver_version( - Versions::semver_from_string("1.0.0-alpha.1.0.0"), "1.0.0", "alpha.1.0.0", 1, 0, 0, {"alpha", "1", "0", "0"}); - check_semver_version(Versions::semver_from_string("1.0.0-alpha.1.x.y.z.0-alpha.0-beta.l-a-s-t"), + DotVersion::try_parse_semver("1.0.0-alpha.1.0.0"), "1.0.0", "alpha.1.0.0", 1, 0, 0, {"alpha", "1", "0", "0"}); + check_semver_version(DotVersion::try_parse_semver("1.0.0-alpha.1.x.y.z.0-alpha.0-beta.l-a-s-t"), "1.0.0", "alpha.1.x.y.z.0-alpha.0-beta.l-a-s-t", 1, 0, 0, {"alpha", "1", "x", "y", "z", "0-alpha", "0-beta", "l-a-s-t"}); - check_semver_version(Versions::semver_from_string("1.0.0----------------------------------"), + check_semver_version(DotVersion::try_parse_semver("1.0.0----------------------------------"), "1.0.0", "---------------------------------", 1, 0, 0, {"---------------------------------"}); - check_semver_version(Versions::semver_from_string("1.0.0+build"), "1.0.0", "", 1, 0, 0, {}); - check_semver_version(Versions::semver_from_string("1.0.0-alpha+build"), "1.0.0", "alpha", 1, 0, 0, {"alpha"}); - check_semver_version(Versions::semver_from_string("1.0.0-alpha+build.ok"), "1.0.0", "alpha", 1, 0, 0, {"alpha"}); + check_semver_version(DotVersion::try_parse_semver("1.0.0+build"), "1.0.0", "", 1, 0, 0, {}); + check_semver_version(DotVersion::try_parse_semver("1.0.0-alpha+build"), "1.0.0", "alpha", 1, 0, 0, {"alpha"}); + check_semver_version(DotVersion::try_parse_semver("1.0.0-alpha+build.ok"), "1.0.0", "alpha", 1, 0, 0, {"alpha"}); check_semver_version( - Versions::semver_from_string("1.0.0-alpha+build.ok-too"), "1.0.0", "alpha", 1, 0, 0, {"alpha"}); + DotVersion::try_parse_semver("1.0.0-alpha+build.ok-too"), "1.0.0", "alpha", 1, 0, 0, {"alpha"}); - CHECK(!Versions::semver_from_string("1.0").has_value()); - CHECK(!Versions::semver_from_string("1.0-alpha").has_value()); - CHECK(!Versions::semver_from_string("1.0.0.0").has_value()); - CHECK(!Versions::semver_from_string("1.02.03").has_value()); - CHECK(!Versions::semver_from_string("1.0.0-").has_value()); - CHECK(!Versions::semver_from_string("1.0.0-01").has_value()); - CHECK(!Versions::semver_from_string("1.0.0-alpha#2").has_value()); - CHECK(!Versions::semver_from_string("1.0.0-alpha+build+notok").has_value()); + CHECK(!DotVersion::try_parse_semver("1.0").has_value()); + CHECK(!DotVersion::try_parse_semver("1.0-alpha").has_value()); + CHECK(!DotVersion::try_parse_semver("1.0.0.0").has_value()); + CHECK(!DotVersion::try_parse_semver("1.02.03").has_value()); + CHECK(!DotVersion::try_parse_semver("1.0.0-").has_value()); + CHECK(!DotVersion::try_parse_semver("1.0.0-01").has_value()); + CHECK(!DotVersion::try_parse_semver("1.0.0-alpha#2").has_value()); + CHECK(!DotVersion::try_parse_semver("1.0.0-alpha+build+notok").has_value()); } TEST_CASE ("version parse relaxed", "[versionplan]") { - check_relaxed_version(Versions::relaxed_from_string("1.2.3"), {1, 2, 3}); - check_relaxed_version(Versions::relaxed_from_string("1"), {1}); + check_relaxed_version(DotVersion::try_parse_relaxed("1.2.3"), {1, 2, 3}); + check_relaxed_version(DotVersion::try_parse_relaxed("1"), {1}); check_relaxed_version( - Versions::relaxed_from_string("1.20.300.4000.50000.6000000.70000000.80000000.18446744073709551610"), + DotVersion::try_parse_relaxed("1.20.300.4000.50000.6000000.70000000.80000000.18446744073709551610"), {1, 20, 300, 4000, 50000, 6000000, 70000000, 80000000, 18446744073709551610u}); - check_relaxed_version(Versions::relaxed_from_string("1.0.0.0-alpha"), {1, 0, 0, 0}, {"alpha"}); - check_relaxed_version(Versions::relaxed_from_string("1.0.0.0-alpha-0.1"), {1, 0, 0, 0}, {"alpha-0", "1"}); - check_relaxed_version(Versions::relaxed_from_string("1.0.0.0-alpha+build-ok"), {1, 0, 0, 0}, {"alpha"}); + check_relaxed_version(DotVersion::try_parse_relaxed("1.0.0.0-alpha"), {1, 0, 0, 0}, {"alpha"}); + check_relaxed_version(DotVersion::try_parse_relaxed("1.0.0.0-alpha-0.1"), {1, 0, 0, 0}, {"alpha-0", "1"}); + check_relaxed_version(DotVersion::try_parse_relaxed("1.0.0.0-alpha+build-ok"), {1, 0, 0, 0}, {"alpha"}); - CHECK(!Versions::relaxed_from_string("1.1a.2").has_value()); - CHECK(!Versions::relaxed_from_string("01.002.003").has_value()); - CHECK(!Versions::relaxed_from_string("1.0.0-").has_value()); - CHECK(!Versions::relaxed_from_string("1.0.0+extra+other").has_value()); + CHECK(!DotVersion::try_parse_relaxed("1.1a.2").has_value()); + CHECK(!DotVersion::try_parse_relaxed("01.002.003").has_value()); + CHECK(!DotVersion::try_parse_relaxed("1.0.0-").has_value()); + CHECK(!DotVersion::try_parse_relaxed("1.0.0+extra+other").has_value()); } TEST_CASE ("version parse date", "[versionplan]") { - check_date_version(Versions::DateVersion::from_string("2020-12-25"), "2020-12-25", {}); - check_date_version(Versions::DateVersion::from_string("2020-12-25.1.2.3"), "2020-12-25", {1, 2, 3}); + check_date_version(DateVersion::try_parse("2020-12-25"), "2020-12-25", {}); + check_date_version(DateVersion::try_parse("2020-12-25.1.2.3"), "2020-12-25", {1, 2, 3}); - CHECK(!Versions::DateVersion::from_string("2020-1-1").has_value()); - CHECK(!Versions::DateVersion::from_string("2020-01-01.alpha").has_value()); - CHECK(!Versions::DateVersion::from_string("2020-01-01.2a").has_value()); - CHECK(!Versions::DateVersion::from_string("2020-01-01.01").has_value()); + CHECK(!DateVersion::try_parse("2020-1-1").has_value()); + CHECK(!DateVersion::try_parse("2020-01-01.alpha").has_value()); + CHECK(!DateVersion::try_parse("2020-01-01.2a").has_value()); + CHECK(!DateVersion::try_parse("2020-01-01.01").has_value()); } TEST_CASE ("version sort semver", "[versionplan]") { - std::vector versions{ - unwrap(Versions::semver_from_string("1.0.0")), - unwrap(Versions::semver_from_string("0.0.0")), - unwrap(Versions::semver_from_string("1.1.0")), - unwrap(Versions::semver_from_string("2.0.0")), - unwrap(Versions::semver_from_string("1.1.1")), - unwrap(Versions::semver_from_string("1.0.1")), - unwrap(Versions::semver_from_string("1.0.0-alpha.1")), - unwrap(Versions::semver_from_string("1.0.0-beta")), - unwrap(Versions::semver_from_string("1.0.0-alpha")), - unwrap(Versions::semver_from_string("1.0.0-alpha.beta")), - unwrap(Versions::semver_from_string("1.0.0-rc")), - unwrap(Versions::semver_from_string("1.0.0-beta.2")), - unwrap(Versions::semver_from_string("1.0.0-beta.20")), - unwrap(Versions::semver_from_string("1.0.0-beta.3")), - unwrap(Versions::semver_from_string("1.0.0-1")), - unwrap(Versions::semver_from_string("1.0.0-0alpha")), + std::vector versions{ + unwrap(DotVersion::try_parse_semver("1.0.0")), + unwrap(DotVersion::try_parse_semver("0.0.0")), + unwrap(DotVersion::try_parse_semver("1.1.0")), + unwrap(DotVersion::try_parse_semver("2.0.0")), + unwrap(DotVersion::try_parse_semver("1.1.1")), + unwrap(DotVersion::try_parse_semver("1.0.1")), + unwrap(DotVersion::try_parse_semver("1.0.0-alpha.1")), + unwrap(DotVersion::try_parse_semver("1.0.0-beta")), + unwrap(DotVersion::try_parse_semver("1.0.0-alpha")), + unwrap(DotVersion::try_parse_semver("1.0.0-alpha.beta")), + unwrap(DotVersion::try_parse_semver("1.0.0-rc")), + unwrap(DotVersion::try_parse_semver("1.0.0-beta.2")), + unwrap(DotVersion::try_parse_semver("1.0.0-beta.20")), + unwrap(DotVersion::try_parse_semver("1.0.0-beta.3")), + unwrap(DotVersion::try_parse_semver("1.0.0-1")), + unwrap(DotVersion::try_parse_semver("1.0.0-0alpha")), }; - std::sort(std::begin(versions), std::end(versions), [](const auto& lhs, const auto& rhs) -> bool { - return Versions::compare(lhs, rhs) == Versions::VerComp::lt; - }); + std::sort(std::begin(versions), std::end(versions)); CHECK(versions[0].original_string == "0.0.0"); CHECK(versions[1].original_string == "1.0.0-1"); @@ -748,28 +751,26 @@ TEST_CASE ("version sort semver", "[versionplan]") TEST_CASE ("version sort relaxed", "[versionplan]") { - std::vector versions{ - unwrap(Versions::relaxed_from_string("2.1-alpha.alpha")), - unwrap(Versions::relaxed_from_string("1.0.0")), - unwrap(Versions::relaxed_from_string("2.0-1")), - unwrap(Versions::relaxed_from_string("1.0")), - unwrap(Versions::relaxed_from_string("1")), - unwrap(Versions::relaxed_from_string("2.1-alpha")), - unwrap(Versions::relaxed_from_string("2")), - unwrap(Versions::relaxed_from_string("1.1")), - unwrap(Versions::relaxed_from_string("1.10.1")), - unwrap(Versions::relaxed_from_string("2.0-0")), - unwrap(Versions::relaxed_from_string("1.0.1")), - unwrap(Versions::relaxed_from_string("2.1-beta")), - unwrap(Versions::relaxed_from_string("1.0.0.1")), - unwrap(Versions::relaxed_from_string("1.0.0.2")), - unwrap(Versions::relaxed_from_string("2.0")), - unwrap(Versions::relaxed_from_string("2.0-rc")), + std::vector versions{ + unwrap(DotVersion::try_parse_relaxed("2.1-alpha.alpha")), + unwrap(DotVersion::try_parse_relaxed("1.0.0")), + unwrap(DotVersion::try_parse_relaxed("2.0-1")), + unwrap(DotVersion::try_parse_relaxed("1.0")), + unwrap(DotVersion::try_parse_relaxed("1")), + unwrap(DotVersion::try_parse_relaxed("2.1-alpha")), + unwrap(DotVersion::try_parse_relaxed("2")), + unwrap(DotVersion::try_parse_relaxed("1.1")), + unwrap(DotVersion::try_parse_relaxed("1.10.1")), + unwrap(DotVersion::try_parse_relaxed("2.0-0")), + unwrap(DotVersion::try_parse_relaxed("1.0.1")), + unwrap(DotVersion::try_parse_relaxed("2.1-beta")), + unwrap(DotVersion::try_parse_relaxed("1.0.0.1")), + unwrap(DotVersion::try_parse_relaxed("1.0.0.2")), + unwrap(DotVersion::try_parse_relaxed("2.0")), + unwrap(DotVersion::try_parse_relaxed("2.0-rc")), }; - std::sort(std::begin(versions), std::end(versions), [](const auto& lhs, const auto& rhs) -> bool { - return Versions::compare(lhs, rhs) == Versions::VerComp::lt; - }); + std::sort(std::begin(versions), std::end(versions)); CHECK(versions[0].original_string == "1"); CHECK(versions[1].original_string == "1.0"); @@ -791,21 +792,19 @@ TEST_CASE ("version sort relaxed", "[versionplan]") TEST_CASE ("version sort date", "[versionplan]") { - std::vector versions{ - unwrap(Versions::DateVersion::from_string("2021-01-01.2")), - unwrap(Versions::DateVersion::from_string("2021-01-01.1")), - unwrap(Versions::DateVersion::from_string("2021-01-01.1.1")), - unwrap(Versions::DateVersion::from_string("2021-01-01.1.0")), - unwrap(Versions::DateVersion::from_string("2021-01-01")), - unwrap(Versions::DateVersion::from_string("2021-01-01")), - unwrap(Versions::DateVersion::from_string("2020-12-25")), - unwrap(Versions::DateVersion::from_string("2020-12-31")), - unwrap(Versions::DateVersion::from_string("2021-01-01.10")), + std::vector versions{ + unwrap(DateVersion::try_parse("2021-01-01.2")), + unwrap(DateVersion::try_parse("2021-01-01.1")), + unwrap(DateVersion::try_parse("2021-01-01.1.1")), + unwrap(DateVersion::try_parse("2021-01-01.1.0")), + unwrap(DateVersion::try_parse("2021-01-01")), + unwrap(DateVersion::try_parse("2021-01-01")), + unwrap(DateVersion::try_parse("2020-12-25")), + unwrap(DateVersion::try_parse("2020-12-31")), + unwrap(DateVersion::try_parse("2021-01-01.10")), }; - std::sort(std::begin(versions), std::end(versions), [](const auto& lhs, const auto& rhs) -> bool { - return Versions::compare(lhs, rhs) == Versions::VerComp::lt; - }); + std::sort(std::begin(versions), std::end(versions)); CHECK(versions[0].original_string == "2020-12-25"); CHECK(versions[1].original_string == "2020-12-31"); @@ -818,22 +817,14 @@ TEST_CASE ("version sort date", "[versionplan]") CHECK(versions[8].original_string == "2021-01-01.10"); } -TEST_CASE ("version compare string", "[versionplan]") -{ - CHECK(Versions::compare("1.0.0", "1.0.0", Versions::Scheme::String) == Versions::VerComp::eq); - CHECK(Versions::compare("1.0.0", "0.0.0", Versions::Scheme::String) == Versions::VerComp::unk); - CHECK(Versions::compare("0.0.0", "1.0.0", Versions::Scheme::String) == Versions::VerComp::unk); - CHECK(Versions::compare("apple", "orange", Versions::Scheme::String) == Versions::VerComp::unk); -} - TEST_CASE ("version install simple semver", "[versionplan]") { MockBaselineProvider bp; bp.v["a"] = {"2.0.0", 0}; MockVersionedPortfileProvider vp; - vp.emplace("a", {"2.0.0", 0}, Scheme::Semver); - vp.emplace("a", {"3.0.0", 0}, Scheme::Semver); + vp.emplace("a", {"2.0.0", 0}, VersionScheme::Semver); + vp.emplace("a", {"3.0.0", 0}, VersionScheme::Semver); MockCMakeVarProvider var_provider; @@ -842,7 +833,7 @@ TEST_CASE ("version install simple semver", "[versionplan]") bp, var_provider, { - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "3.0.0", 0}}, + Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "3.0.0", 0}}, }, {}, toplevel_spec())); @@ -858,12 +849,12 @@ TEST_CASE ("version install transitive semver", "[versionplan]") bp.v["b"] = {"2.0.0", 0}; MockVersionedPortfileProvider vp; - vp.emplace("a", {"2.0.0", 0}, Scheme::Semver); - vp.emplace("a", {"3.0.0", 0}, Scheme::Semver).source_control_file->core_paragraph->dependencies = { - Dependency{"b", {}, {}, DependencyConstraint{Constraint::Type::Minimum, "3.0.0"}}, + vp.emplace("a", {"2.0.0", 0}, VersionScheme::Semver); + vp.emplace("a", {"3.0.0", 0}, VersionScheme::Semver).source_control_file->core_paragraph->dependencies = { + Dependency{"b", {}, {}, DependencyConstraint{VersionConstraintKind::Minimum, "3.0.0"}}, }; - vp.emplace("b", {"2.0.0", 0}, Scheme::Semver); - vp.emplace("b", {"3.0.0", 0}, Scheme::Semver); + vp.emplace("b", {"2.0.0", 0}, VersionScheme::Semver); + vp.emplace("b", {"3.0.0", 0}, VersionScheme::Semver); MockCMakeVarProvider var_provider; @@ -872,7 +863,7 @@ TEST_CASE ("version install transitive semver", "[versionplan]") bp, var_provider, { - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "3.0.0", 0}}, + Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "3.0.0", 0}}, }, {}, toplevel_spec())); @@ -889,17 +880,17 @@ TEST_CASE ("version install diamond semver", "[versionplan]") bp.v["b"] = {"3.0.0", 0}; MockVersionedPortfileProvider vp; - vp.emplace("a", {"2.0.0", 0}, Scheme::Semver); - vp.emplace("a", {"3.0.0", 0}, Scheme::Semver).source_control_file->core_paragraph->dependencies = { - Dependency{"b", {}, {}, DependencyConstraint{Constraint::Type::Minimum, "2.0.0", 1}}, - Dependency{"c", {}, {}, DependencyConstraint{Constraint::Type::Minimum, "5.0.0", 1}}, + vp.emplace("a", {"2.0.0", 0}, VersionScheme::Semver); + vp.emplace("a", {"3.0.0", 0}, VersionScheme::Semver).source_control_file->core_paragraph->dependencies = { + Dependency{"b", {}, {}, DependencyConstraint{VersionConstraintKind::Minimum, "2.0.0", 1}}, + Dependency{"c", {}, {}, DependencyConstraint{VersionConstraintKind::Minimum, "5.0.0", 1}}, }; - vp.emplace("b", {"2.0.0", 1}, Scheme::Semver); - vp.emplace("b", {"3.0.0", 0}, Scheme::Semver).source_control_file->core_paragraph->dependencies = { - Dependency{"c", {}, {}, DependencyConstraint{Constraint::Type::Minimum, "9.0.0", 2}}, + vp.emplace("b", {"2.0.0", 1}, VersionScheme::Semver); + vp.emplace("b", {"3.0.0", 0}, VersionScheme::Semver).source_control_file->core_paragraph->dependencies = { + Dependency{"c", {}, {}, DependencyConstraint{VersionConstraintKind::Minimum, "9.0.0", 2}}, }; - vp.emplace("c", {"5.0.0", 1}, Scheme::Semver); - vp.emplace("c", {"9.0.0", 2}, Scheme::Semver); + vp.emplace("c", {"5.0.0", 1}, VersionScheme::Semver); + vp.emplace("c", {"9.0.0", 2}, VersionScheme::Semver); MockCMakeVarProvider var_provider; @@ -908,8 +899,8 @@ TEST_CASE ("version install diamond semver", "[versionplan]") bp, var_provider, { - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "3.0.0", 0}}, - Dependency{"b", {}, {}, {Constraint::Type::Minimum, "2.0.0", 1}}, + Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "3.0.0", 0}}, + Dependency{"b", {}, {}, {VersionConstraintKind::Minimum, "2.0.0", 1}}, }, {}, toplevel_spec())); @@ -926,20 +917,20 @@ TEST_CASE ("version install simple date", "[versionplan]") bp.v["a"] = {"2020-02-01", 0}; MockVersionedPortfileProvider vp; - vp.emplace("a", {"2020-02-01", 0}, Scheme::Date); - vp.emplace("a", {"2020-03-01", 0}, Scheme::Date); + vp.emplace("a", {"2020-02-01", 0}, VersionScheme::Date); + vp.emplace("a", {"2020-03-01", 0}, VersionScheme::Date); MockCMakeVarProvider var_provider; - auto install_plan = - unwrap(create_versioned_install_plan(vp, - bp, - var_provider, - { - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "2020-03-01", 0}}, - }, - {}, - toplevel_spec())); + auto install_plan = unwrap( + create_versioned_install_plan(vp, + bp, + var_provider, + { + Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "2020-03-01", 0}}, + }, + {}, + toplevel_spec())); REQUIRE(install_plan.size() == 1); check_name_and_version(install_plan.install_actions[0], "a", {"2020-03-01", 0}); @@ -952,12 +943,12 @@ TEST_CASE ("version install transitive date", "[versionplan]") bp.v["b"] = {"2020-01-01.3", 0}; MockVersionedPortfileProvider vp; - vp.emplace("a", {"2020-01-01.2", 0}, Scheme::Date); - vp.emplace("a", {"2020-01-01.3", 0}, Scheme::Date).source_control_file->core_paragraph->dependencies = { - Dependency{"b", {}, {}, DependencyConstraint{Constraint::Type::Minimum, "2020-01-01.3"}}, + vp.emplace("a", {"2020-01-01.2", 0}, VersionScheme::Date); + vp.emplace("a", {"2020-01-01.3", 0}, VersionScheme::Date).source_control_file->core_paragraph->dependencies = { + Dependency{"b", {}, {}, DependencyConstraint{VersionConstraintKind::Minimum, "2020-01-01.3"}}, }; - vp.emplace("b", {"2020-01-01.2", 0}, Scheme::Date); - vp.emplace("b", {"2020-01-01.3", 0}, Scheme::Date); + vp.emplace("b", {"2020-01-01.2", 0}, VersionScheme::Date); + vp.emplace("b", {"2020-01-01.3", 0}, VersionScheme::Date); MockCMakeVarProvider var_provider; @@ -966,7 +957,7 @@ TEST_CASE ("version install transitive date", "[versionplan]") bp, var_provider, { - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "2020-01-01.3", 0}}, + Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "2020-01-01.3", 0}}, }, {}, toplevel_spec())); @@ -983,30 +974,30 @@ TEST_CASE ("version install diamond date", "[versionplan]") bp.v["b"] = {"2020-01-03", 0}; MockVersionedPortfileProvider vp; - vp.emplace("a", {"2020-01-02", 0}, Scheme::Date); - vp.emplace("a", {"2020-01-03", 0}, Scheme::Date).source_control_file->core_paragraph->dependencies = { - Dependency{"b", {}, {}, DependencyConstraint{Constraint::Type::Minimum, "2020-01-02", 1}}, - Dependency{"c", {}, {}, DependencyConstraint{Constraint::Type::Minimum, "2020-01-05", 1}}, + vp.emplace("a", {"2020-01-02", 0}, VersionScheme::Date); + vp.emplace("a", {"2020-01-03", 0}, VersionScheme::Date).source_control_file->core_paragraph->dependencies = { + Dependency{"b", {}, {}, DependencyConstraint{VersionConstraintKind::Minimum, "2020-01-02", 1}}, + Dependency{"c", {}, {}, DependencyConstraint{VersionConstraintKind::Minimum, "2020-01-05", 1}}, }; - vp.emplace("b", {"2020-01-02", 1}, Scheme::Date); - vp.emplace("b", {"2020-01-03", 0}, Scheme::Date).source_control_file->core_paragraph->dependencies = { - Dependency{"c", {}, {}, DependencyConstraint{Constraint::Type::Minimum, "2020-01-09", 2}}, + vp.emplace("b", {"2020-01-02", 1}, VersionScheme::Date); + vp.emplace("b", {"2020-01-03", 0}, VersionScheme::Date).source_control_file->core_paragraph->dependencies = { + Dependency{"c", {}, {}, DependencyConstraint{VersionConstraintKind::Minimum, "2020-01-09", 2}}, }; - vp.emplace("c", {"2020-01-05", 1}, Scheme::Date); - vp.emplace("c", {"2020-01-09", 2}, Scheme::Date); + vp.emplace("c", {"2020-01-05", 1}, VersionScheme::Date); + vp.emplace("c", {"2020-01-09", 2}, VersionScheme::Date); MockCMakeVarProvider var_provider; - auto install_plan = - unwrap(create_versioned_install_plan(vp, - bp, - var_provider, - { - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "2020-01-03", 0}}, - Dependency{"b", {}, {}, {Constraint::Type::Minimum, "2020-01-02", 1}}, - }, - {}, - toplevel_spec())); + auto install_plan = unwrap( + create_versioned_install_plan(vp, + bp, + var_provider, + { + Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "2020-01-03", 0}}, + Dependency{"b", {}, {}, {VersionConstraintKind::Minimum, "2020-01-02", 1}}, + }, + {}, + toplevel_spec())); REQUIRE(install_plan.size() == 3); check_name_and_version(install_plan.install_actions[0], "c", {"2020-01-09", 2}); @@ -1029,9 +1020,9 @@ static void CHECK_LINES(const std::string& a, const std::string& b) TEST_CASE ("version install scheme failure", "[versionplan]") { MockVersionedPortfileProvider vp; - vp.emplace("a", {"1.0.0", 0}, Scheme::Semver); - vp.emplace("a", {"1.0.1", 0}, Scheme::Relaxed); - vp.emplace("a", {"1.0.2", 0}, Scheme::Semver); + vp.emplace("a", {"1.0.0", 0}, VersionScheme::Semver); + vp.emplace("a", {"1.0.1", 0}, VersionScheme::String); + vp.emplace("a", {"1.0.2", 0}, VersionScheme::Semver); MockCMakeVarProvider var_provider; @@ -1044,7 +1035,7 @@ TEST_CASE ("version install scheme failure", "[versionplan]") create_versioned_install_plan(vp, bp, var_provider, - {Dependency{"a", {}, {}, {Constraint::Type::Minimum, "1.0.1", 0}}}, + {Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "1.0.1", 0}}}, {}, toplevel_spec()); @@ -1054,7 +1045,7 @@ TEST_CASE ("version install scheme failure", "[versionplan]") R"(Error: Version conflict on a:x86-windows: baseline required 1.0.0 but vcpkg could not compare it to 1.0.1 The two versions used incomparable schemes: - "1.0.1" was of scheme relaxed + "1.0.1" was of scheme string "1.0.0" was of scheme semver This can be resolved by adding an explicit override to the preferred version, for example: @@ -1074,7 +1065,7 @@ See `vcpkg help versioning` for more information.)"); create_versioned_install_plan(vp, bp, var_provider, - {Dependency{"a", {}, {}, {Constraint::Type::Minimum, "1.0.1", 0}}}, + {Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "1.0.1", 0}}}, {}, toplevel_spec()); @@ -1084,7 +1075,7 @@ See `vcpkg help versioning` for more information.)"); R"(Error: Version conflict on a:x86-windows: baseline required 1.0.2 but vcpkg could not compare it to 1.0.1 The two versions used incomparable schemes: - "1.0.1" was of scheme relaxed + "1.0.1" was of scheme string "1.0.2" was of scheme semver This can be resolved by adding an explicit override to the preferred version, for example: @@ -1097,17 +1088,58 @@ See `vcpkg help versioning` for more information.)"); } } +TEST_CASE ("version install relaxed cross with semver success", "[versionplan]") +{ + MockVersionedPortfileProvider vp; + vp.emplace("a", {"1.0.0", 0}, VersionScheme::Semver); + vp.emplace("a", {"1.0.1", 0}, VersionScheme::Relaxed); + vp.emplace("a", {"1.0.2", 0}, VersionScheme::Semver); + + MockCMakeVarProvider var_provider; + + SECTION ("lower baseline") + { + MockBaselineProvider bp; + bp.v["a"] = {"1.0.0", 0}; + + auto install_plan = unwrap( + create_versioned_install_plan(vp, + bp, + var_provider, + {Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "1.0.1", 0}}}, + {}, + toplevel_spec())); + + check_name_and_version(install_plan.install_actions[0], "a", {"1.0.1", 0}); + } + SECTION ("higher baseline") + { + MockBaselineProvider bp; + bp.v["a"] = {"1.0.2", 0}; + + auto install_plan = unwrap( + create_versioned_install_plan(vp, + bp, + var_provider, + {Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "1.0.1", 0}}}, + {}, + toplevel_spec())); + + check_name_and_version(install_plan.install_actions[0], "a", {"1.0.2", 0}); + } +} + 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::Minimum, "1"}}, + Dependency{"b", {}, {}, DependencyConstraint{VersionConstraintKind::Minimum, "1"}}, }; vp.emplace("a", {"2", 1}).source_control_file->core_paragraph->dependencies = { - Dependency{"b", {}, {}, DependencyConstraint{Constraint::Type::Minimum, "1", 1}}, + Dependency{"b", {}, {}, DependencyConstraint{VersionConstraintKind::Minimum, "1", 1}}, }; - vp.emplace("b", {"1", 0}, Scheme::String); - vp.emplace("b", {"1", 1}, Scheme::Relaxed); + vp.emplace("b", {"1", 0}, VersionScheme::String); + vp.emplace("b", {"1", 1}, VersionScheme::Relaxed); MockCMakeVarProvider var_provider; @@ -1121,7 +1153,7 @@ TEST_CASE ("version install scheme change in port version", "[versionplan]") bp, var_provider, { - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "2", 1}}, + Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "2", 1}}, }, {}, toplevel_spec())); @@ -1140,7 +1172,7 @@ TEST_CASE ("version install scheme change in port version", "[versionplan]") bp, var_provider, { - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "2", 0}}, + Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "2", 0}}, }, {}, toplevel_spec())); @@ -1157,18 +1189,19 @@ TEST_CASE ("version install simple feature", "[versionplan]") { auto a_x = std::make_unique(); a_x->name = "x"; - vp.emplace("a", {"1", 0}, Scheme::Relaxed).source_control_file->feature_paragraphs.push_back(std::move(a_x)); + vp.emplace("a", {"1", 0}, VersionScheme::Relaxed) + .source_control_file->feature_paragraphs.push_back(std::move(a_x)); } { auto a_x = std::make_unique(); a_x->name = "x"; - vp.emplace("semver", {"1.0.0", 0}, Scheme::Semver) + vp.emplace("semver", {"1.0.0", 0}, VersionScheme::Semver) .source_control_file->feature_paragraphs.push_back(std::move(a_x)); } { auto a_x = std::make_unique(); a_x->name = "x"; - vp.emplace("date", {"2020-01-01", 0}, Scheme::Date) + vp.emplace("date", {"2020-01-01", 0}, VersionScheme::Date) .source_control_file->feature_paragraphs.push_back(std::move(a_x)); } @@ -1229,15 +1262,15 @@ TEST_CASE ("version install simple feature", "[versionplan]") { MockBaselineProvider bp; - auto install_plan = - unwrap(create_versioned_install_plan(vp, - bp, - var_provider, - { - Dependency{"a", {"x"}, {}, {Constraint::Type::Minimum, "1", 0}}, - }, - {}, - toplevel_spec())); + auto install_plan = unwrap( + create_versioned_install_plan(vp, + bp, + var_provider, + { + Dependency{"a", {"x"}, {}, {VersionConstraintKind::Minimum, "1", 0}}, + }, + {}, + toplevel_spec())); REQUIRE(install_plan.size() == 1); check_name_and_version(install_plan.install_actions[0], "a", {"1", 0}, {"x"}); @@ -1257,10 +1290,10 @@ TEST_CASE ("version install transitive features", "[versionplan]") auto a_x = make_fpgh("x"); a_x->dependencies.push_back(Dependency{"b", {"y"}}); - vp.emplace("a", {"1", 0}, Scheme::Relaxed).source_control_file->feature_paragraphs.push_back(std::move(a_x)); + vp.emplace("a", {"1", 0}, VersionScheme::Relaxed).source_control_file->feature_paragraphs.push_back(std::move(a_x)); auto b_y = make_fpgh("y"); - vp.emplace("b", {"1", 0}, Scheme::Relaxed).source_control_file->feature_paragraphs.push_back(std::move(b_y)); + vp.emplace("b", {"1", 0}, VersionScheme::Relaxed).source_control_file->feature_paragraphs.push_back(std::move(b_y)); MockCMakeVarProvider var_provider; @@ -1287,20 +1320,22 @@ TEST_CASE ("version install transitive feature versioned", "[versionplan]") MockVersionedPortfileProvider vp; auto a_x = make_fpgh("x"); - a_x->dependencies.push_back(Dependency{"b", {"y"}, {}, {Constraint::Type::Minimum, "2", 0}}); - vp.emplace("a", {"1", 0}, Scheme::Relaxed).source_control_file->feature_paragraphs.push_back(std::move(a_x)); + a_x->dependencies.push_back(Dependency{"b", {"y"}, {}, {VersionConstraintKind::Minimum, "2", 0}}); + vp.emplace("a", {"1", 0}, VersionScheme::Relaxed).source_control_file->feature_paragraphs.push_back(std::move(a_x)); { auto b_y = make_fpgh("y"); - vp.emplace("b", {"1", 0}, Scheme::Relaxed).source_control_file->feature_paragraphs.push_back(std::move(b_y)); + vp.emplace("b", {"1", 0}, VersionScheme::Relaxed) + .source_control_file->feature_paragraphs.push_back(std::move(b_y)); } { auto b_y = make_fpgh("y"); b_y->dependencies.push_back(Dependency{"c"}); - vp.emplace("b", {"2", 0}, Scheme::Relaxed).source_control_file->feature_paragraphs.push_back(std::move(b_y)); + vp.emplace("b", {"2", 0}, VersionScheme::Relaxed) + .source_control_file->feature_paragraphs.push_back(std::move(b_y)); } - vp.emplace("c", {"1", 0}, Scheme::Relaxed); + vp.emplace("c", {"1", 0}, VersionScheme::Relaxed); MockCMakeVarProvider var_provider; @@ -1334,16 +1369,16 @@ TEST_CASE ("version install constraint-reduction", "[versionplan]") { MockVersionedPortfileProvider vp; - vp.emplace("b", {"1", 0}, Scheme::Relaxed).source_control_file->core_paragraph->dependencies = { - Dependency{"c", {}, {}, {Constraint::Type::Minimum, "2"}}, + vp.emplace("b", {"1", 0}, VersionScheme::Relaxed).source_control_file->core_paragraph->dependencies = { + Dependency{"c", {}, {}, {VersionConstraintKind::Minimum, "2"}}, }; - vp.emplace("b", {"2", 0}, Scheme::Relaxed).source_control_file->core_paragraph->dependencies = { - Dependency{"c", {}, {}, {Constraint::Type::Minimum, "1"}}, + vp.emplace("b", {"2", 0}, VersionScheme::Relaxed).source_control_file->core_paragraph->dependencies = { + Dependency{"c", {}, {}, {VersionConstraintKind::Minimum, "1"}}, }; - vp.emplace("c", {"1", 0}, Scheme::Relaxed); + vp.emplace("c", {"1", 0}, VersionScheme::Relaxed); // c@2 is used to detect if certain constraints were evaluated - vp.emplace("c", {"2", 0}, Scheme::Relaxed); + vp.emplace("c", {"2", 0}, VersionScheme::Relaxed); MockBaselineProvider bp; bp.v["b"] = {"2", 0}; @@ -1354,7 +1389,7 @@ TEST_CASE ("version install constraint-reduction", "[versionplan]") bp, var_provider, { - Dependency{"b", {}, {}, {Constraint::Type::Minimum, "1"}}, + Dependency{"b", {}, {}, {VersionConstraintKind::Minimum, "1"}}, }, {}, toplevel_spec())); @@ -1368,16 +1403,16 @@ TEST_CASE ("version install constraint-reduction", "[versionplan]") { MockVersionedPortfileProvider vp; - vp.emplace("b", {"1", 0}, Scheme::Relaxed).source_control_file->core_paragraph->dependencies = { - Dependency{"c", {}, {}, {Constraint::Type::Minimum, "2"}}, + vp.emplace("b", {"1", 0}, VersionScheme::Relaxed).source_control_file->core_paragraph->dependencies = { + Dependency{"c", {}, {}, {VersionConstraintKind::Minimum, "2"}}, }; - vp.emplace("b", {"2", 0}, Scheme::Relaxed).source_control_file->core_paragraph->dependencies = { - Dependency{"c", {}, {}, {Constraint::Type::Minimum, "1"}}, + vp.emplace("b", {"2", 0}, VersionScheme::Relaxed).source_control_file->core_paragraph->dependencies = { + Dependency{"c", {}, {}, {VersionConstraintKind::Minimum, "1"}}, }; - vp.emplace("c", {"1", 0}, Scheme::Relaxed); + vp.emplace("c", {"1", 0}, VersionScheme::Relaxed); // c@2 is used to detect if certain constraints were evaluated - vp.emplace("c", {"2", 0}, Scheme::Relaxed); + vp.emplace("c", {"2", 0}, VersionScheme::Relaxed); MockBaselineProvider bp; bp.v["b"] = {"1", 0}; @@ -1388,7 +1423,7 @@ TEST_CASE ("version install constraint-reduction", "[versionplan]") bp, var_provider, { - Dependency{"b", {}, {}, {Constraint::Type::Minimum, "2"}}, + Dependency{"b", {}, {}, {VersionConstraintKind::Minimum, "2"}}, }, {}, toplevel_spec())); @@ -1405,10 +1440,10 @@ TEST_CASE ("version install overrides", "[versionplan]") MockVersionedPortfileProvider vp; - vp.emplace("b", {"1", 0}, Scheme::Relaxed); - vp.emplace("b", {"2", 0}, Scheme::Relaxed); - vp.emplace("c", {"1", 0}, Scheme::String); - vp.emplace("c", {"2", 0}, Scheme::String); + vp.emplace("b", {"1", 0}, VersionScheme::Relaxed); + vp.emplace("b", {"2", 0}, VersionScheme::Relaxed); + vp.emplace("c", {"1", 0}, VersionScheme::String); + vp.emplace("c", {"2", 0}, VersionScheme::String); MockBaselineProvider bp; bp.v["b"] = {"2", 0}; @@ -1449,12 +1484,12 @@ TEST_CASE ("version install transitive overrides", "[versionplan]") MockVersionedPortfileProvider vp; - vp.emplace("b", {"1", 0}, Scheme::Relaxed) + vp.emplace("b", {"1", 0}, VersionScheme::Relaxed) .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); + {"c", {}, {}, {VersionConstraintKind::Minimum, "2", 1}}); + vp.emplace("b", {"2", 0}, VersionScheme::Relaxed); + vp.emplace("c", {"1", 0}, VersionScheme::String); + vp.emplace("c", {"2", 1}, VersionScheme::String); MockBaselineProvider bp; bp.v["b"] = {"2", 0}; @@ -1478,7 +1513,7 @@ TEST_CASE ("version install default features", "[versionplan]") MockVersionedPortfileProvider vp; auto a_x = make_fpgh("x"); - auto& a_scf = vp.emplace("a", {"1", 0}, Scheme::Relaxed).source_control_file; + auto& a_scf = vp.emplace("a", {"1", 0}, VersionScheme::Relaxed).source_control_file; a_scf->core_paragraph->default_features.push_back("x"); a_scf->feature_paragraphs.push_back(std::move(a_x)); @@ -1499,7 +1534,7 @@ TEST_CASE ("version dont install default features", "[versionplan]") MockVersionedPortfileProvider vp; auto a_x = make_fpgh("x"); - auto& a_scf = vp.emplace("a", {"1", 0}, Scheme::Relaxed).source_control_file; + auto& a_scf = vp.emplace("a", {"1", 0}, VersionScheme::Relaxed).source_control_file; a_scf->core_paragraph->default_features.push_back("x"); a_scf->feature_paragraphs.push_back(std::move(a_x)); @@ -1520,14 +1555,14 @@ TEST_CASE ("version install transitive default features", "[versionplan]") MockVersionedPortfileProvider vp; auto a_x = make_fpgh("x"); - auto& a_scf = vp.emplace("a", {"1", 0}, Scheme::Relaxed).source_control_file; + auto& a_scf = vp.emplace("a", {"1", 0}, VersionScheme::Relaxed).source_control_file; a_scf->core_paragraph->default_features.push_back("x"); a_scf->feature_paragraphs.push_back(std::move(a_x)); - auto& b_scf = vp.emplace("b", {"1", 0}, Scheme::Relaxed).source_control_file; + auto& b_scf = vp.emplace("b", {"1", 0}, VersionScheme::Relaxed).source_control_file; b_scf->core_paragraph->dependencies.push_back({"a", {"core"}}); - auto& c_scf = vp.emplace("c", {"1", 0}, Scheme::Relaxed).source_control_file; + auto& c_scf = vp.emplace("c", {"1", 0}, VersionScheme::Relaxed).source_control_file; c_scf->core_paragraph->dependencies.push_back({"a"}); MockCMakeVarProvider var_provider; @@ -1561,8 +1596,8 @@ TEST_CASE ("version install qualified dependencies", "[versionplan]") { MockVersionedPortfileProvider vp; - vp.emplace("b", {"1", 0}, Scheme::Relaxed); - vp.emplace("c", {"1", 0}, Scheme::Relaxed); + vp.emplace("b", {"1", 0}, VersionScheme::Relaxed); + vp.emplace("c", {"1", 0}, VersionScheme::Relaxed); MockBaselineProvider bp; bp.v["b"] = {"1", 0}; @@ -1607,11 +1642,11 @@ TEST_CASE ("version install qualified default suppression", "[versionplan]") { MockVersionedPortfileProvider vp; - auto& a_scf = vp.emplace("a", {"1", 0}, Scheme::Relaxed).source_control_file; + auto& a_scf = vp.emplace("a", {"1", 0}, VersionScheme::Relaxed).source_control_file; a_scf->core_paragraph->default_features.push_back("x"); a_scf->feature_paragraphs.push_back(make_fpgh("x")); - vp.emplace("b", {"1", 0}, Scheme::Relaxed) + vp.emplace("b", {"1", 0}, VersionScheme::Relaxed) .source_control_file->core_paragraph->dependencies.push_back({"a", {"core"}}); MockCMakeVarProvider var_provider; @@ -1637,10 +1672,10 @@ TEST_CASE ("version install qualified transitive", "[versionplan]") { MockVersionedPortfileProvider vp; - vp.emplace("a", {"1", 0}, Scheme::Relaxed); - vp.emplace("c", {"1", 0}, Scheme::Relaxed); + vp.emplace("a", {"1", 0}, VersionScheme::Relaxed); + vp.emplace("c", {"1", 0}, VersionScheme::Relaxed); - auto& b_scf = vp.emplace("b", {"1", 0}, Scheme::Relaxed).source_control_file; + auto& b_scf = vp.emplace("b", {"1", 0}, VersionScheme::Relaxed).source_control_file; b_scf->core_paragraph->dependencies.push_back({"a", {}, parse_platform("!linux")}); b_scf->core_paragraph->dependencies.push_back({"c", {}, parse_platform("linux")}); @@ -1662,13 +1697,13 @@ TEST_CASE ("version install different vars", "[versionplan]") { MockVersionedPortfileProvider vp; - auto& b_scf = vp.emplace("b", {"1", 0}, Scheme::Relaxed).source_control_file; + auto& b_scf = vp.emplace("b", {"1", 0}, VersionScheme::Relaxed).source_control_file; b_scf->core_paragraph->dependencies.push_back({"a", {}, parse_platform("!linux")}); - auto& a_scf = vp.emplace("a", {"1", 0}, Scheme::Relaxed).source_control_file; + auto& a_scf = vp.emplace("a", {"1", 0}, VersionScheme::Relaxed).source_control_file; a_scf->core_paragraph->dependencies.push_back({"c", {}, parse_platform("linux")}); - vp.emplace("c", {"1", 0}, Scheme::Relaxed); + vp.emplace("c", {"1", 0}, VersionScheme::Relaxed); MockCMakeVarProvider var_provider; var_provider.dep_info_vars[PackageSpec{"a", Test::X86_WINDOWS}] = {{"VCPKG_CMAKE_SYSTEM_NAME", "Linux"}}; @@ -1690,22 +1725,22 @@ TEST_CASE ("version install qualified features", "[versionplan]") { MockVersionedPortfileProvider vp; - auto& b_scf = vp.emplace("b", {"1", 0}, Scheme::Relaxed).source_control_file; + auto& b_scf = vp.emplace("b", {"1", 0}, VersionScheme::Relaxed).source_control_file; b_scf->core_paragraph->default_features.push_back("x"); b_scf->feature_paragraphs.push_back(make_fpgh("x")); b_scf->feature_paragraphs.back()->dependencies.push_back({"a", {}, parse_platform("!linux")}); - auto& a_scf = vp.emplace("a", {"1", 0}, Scheme::Relaxed).source_control_file; + auto& a_scf = vp.emplace("a", {"1", 0}, VersionScheme::Relaxed).source_control_file; a_scf->core_paragraph->default_features.push_back("y"); a_scf->feature_paragraphs.push_back(make_fpgh("y")); a_scf->feature_paragraphs.back()->dependencies.push_back({"c", {}, parse_platform("linux")}); - auto& c_scf = vp.emplace("c", {"1", 0}, Scheme::Relaxed).source_control_file; + auto& c_scf = vp.emplace("c", {"1", 0}, VersionScheme::Relaxed).source_control_file; c_scf->core_paragraph->default_features.push_back("z"); c_scf->feature_paragraphs.push_back(make_fpgh("z")); c_scf->feature_paragraphs.back()->dependencies.push_back({"d", {}, parse_platform("linux")}); - vp.emplace("d", {"1", 0}, Scheme::Relaxed); + vp.emplace("d", {"1", 0}, VersionScheme::Relaxed); MockCMakeVarProvider var_provider; var_provider.dep_info_vars[PackageSpec{"a", Test::X86_WINDOWS}] = {{"VCPKG_CMAKE_SYSTEM_NAME", "Linux"}}; @@ -1805,7 +1840,7 @@ TEST_CASE ("version remove features during upgrade", "[versionplan]") // a@0 -> b[x], c>=1 auto& a_scf = vp.emplace("a", {"1", 0}).source_control_file; a_scf->core_paragraph->dependencies.push_back({"b", {"x"}}); - a_scf->core_paragraph->dependencies.push_back({"c", {}, {}, {Constraint::Type::Minimum, "1", 1}}); + a_scf->core_paragraph->dependencies.push_back({"c", {}, {}, {VersionConstraintKind::Minimum, "1", 1}}); // a@1 -> b auto& a1_scf = vp.emplace("a", {"1", 1}).source_control_file; a1_scf->core_paragraph->dependencies.push_back({"b"}); @@ -1822,9 +1857,9 @@ TEST_CASE ("version remove features during upgrade", "[versionplan]") unwrap(create_versioned_install_plan(vp, bp, { - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "1"}}, - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "1", 1}}, - Dependency{"b", {}, {}, {Constraint::Type::Minimum, "1", 1}}, + Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "1"}}, + Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "1", 1}}, + Dependency{"b", {}, {}, {VersionConstraintKind::Minimum, "1", 1}}, Dependency{"c"}, })); @@ -1928,7 +1963,7 @@ TEST_CASE ("version overlay ports", "[versionplan]") vp.emplace("b", {"1", 0}).source_control_file->core_paragraph->dependencies.emplace_back(Dependency{"a"}); vp.emplace("c", {"1", 0}) .source_control_file->core_paragraph->dependencies.emplace_back( - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "1", 1}}); + Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "1", 1}}); MockCMakeVarProvider var_provider; @@ -1982,7 +2017,7 @@ TEST_CASE ("version overlay ports", "[versionplan]") oprovider, var_provider, { - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "1", 1}}, + Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "1", 1}}, }, {}, toplevel_spec())); @@ -1998,7 +2033,7 @@ TEST_CASE ("version overlay ports", "[versionplan]") oprovider, var_provider, { - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "1", 1}}, + Dependency{"a", {}, {}, {VersionConstraintKind::Minimum, "1", 1}}, }, { DependencyOverride{"a", "2", 0}, diff --git a/src/vcpkg-test/files.cpp b/src/vcpkg-test/files.cpp index 05ce1b403e..4457026145 100644 --- a/src/vcpkg-test/files.cpp +++ b/src/vcpkg-test/files.cpp @@ -167,6 +167,7 @@ namespace template void do_filesystem_enumeration_test(Enumerator&& enumerator, ExpectedGenerator&& generate_expected) { + // Note: not seeded with random data, so this will always produce the same sequence of names urbg_t urbg; auto& fs = setup(); @@ -186,6 +187,8 @@ namespace const auto target_inside_directory = target_directory / "some-inner-directory"; const auto target_inside_directory_symlink = target_directory / "symlink-to-some-inner-directory"; + fs.remove_all(temp_dir, VCPKG_LINE_INFO); + fs.create_directory(temp_dir, VCPKG_LINE_INFO); fs.create_directory(target_root, VCPKG_LINE_INFO); fs.create_directory(target_directory, VCPKG_LINE_INFO); @@ -198,6 +201,7 @@ namespace fs.create_symlink(target_file, target_symlink, ec); if (ec) { + INFO(ec.message()); REQUIRE(is_valid_symlink_failure(ec)); } else @@ -741,6 +745,23 @@ TEST_CASE ("get_files_recursive_symlinks", "[files]") }); } +TEST_CASE ("get_regular_files_recursive_proximate_symlinks", "[files]") +{ + do_filesystem_enumeration_test( + [](Filesystem& fs, const Path& root) { + return fs.get_regular_files_recursive_lexically_proximate(root, VCPKG_LINE_INFO); + }, + [](const Path&) { + Path somedir{"some-directory"}; + return std::vector{ + "file.txt", + somedir / "file2.txt", + somedir / "symlink-to-file2.txt", + "symlink-to-file.txt", + }; + }); +} + TEST_CASE ("get_files_non_recursive_symlinks", "[files]") { do_filesystem_enumeration_test( diff --git a/src/vcpkg-test/json.cpp b/src/vcpkg-test/json.cpp index 71039b0d59..09c4c0819a 100644 --- a/src/vcpkg-test/json.cpp +++ b/src/vcpkg-test/json.cpp @@ -236,8 +236,8 @@ TEST_CASE ("JSON track newlines", "[json]") REQUIRE(!res); REQUIRE(res.error()->format() == R"(filename:2:1: error: Unexpected character; expected property name - on expression: , - ^ + on expression: , + ^ )"); } @@ -247,7 +247,39 @@ TEST_CASE ("JSON duplicated object keys", "[json]") REQUIRE(!res); REQUIRE(res.error()->format() == R"(filename:1:13: error: Duplicated key "name" in an object - on expression: {"name": 1, "name": 2} - ^ + on expression: {"name": 1, "name": 2} + ^ +)"); +} + +TEST_CASE ("JSON support unicode characters in errors", "[json]") +{ + // unicode characters w/ bytes >1 + auto res = Json::parse(R"json("Δx/Δt" "")json", "filename"); + REQUIRE(!res); + CHECK(res.error()->format() == + R"(filename:1:9: error: Unexpected character; expected EOF + on expression: "Δx/Δt" "" + ^ +)"); + + // full width unicode characters + // note that the A is full width + res = Json::parse(R"json("姐姐aA" "")json", "filename"); + REQUIRE(!res); + CHECK(res.error()->format() == + R"(filename:1:8: error: Unexpected character; expected EOF + on expression: "姐姐aA" "" + ^ +)"); + + // incorrect errors in the face of combining characters + // (this test should be fixed once the underlying bug is fixed) + res = Json::parse(R"json("é" "")json", "filename"); + REQUIRE(!res); + CHECK(res.error()->format() == + R"(filename:1:6: error: Unexpected character; expected EOF + on expression: "é" "" + ^ )"); } diff --git a/src/vcpkg-test/manifests.cpp b/src/vcpkg-test/manifests.cpp index 8d22231af4..460bac0557 100644 --- a/src/vcpkg-test/manifests.cpp +++ b/src/vcpkg-test/manifests.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include @@ -28,21 +29,40 @@ static Json::Object parse_json_object(StringView sv) } else { + vcpkg::print2("Error found while parsing JSON document:\n", sv, '\n'); Checks::exit_with_message(VCPKG_LINE_INFO, json.error()->format()); } } -static Parse::ParseExpected test_parse_manifest(StringView sv, bool expect_fail = false) +enum class PrintErrors : bool { - auto object = parse_json_object(sv); - auto res = SourceControlFile::parse_manifest_object("", object); - if (!res.has_value() && !expect_fail) + No, + Yes, +}; + +static Parse::ParseExpected test_parse_manifest(const Json::Object& obj, + PrintErrors print = PrintErrors::Yes) +{ + auto res = SourceControlFile::parse_manifest_object("", obj); + if (!res.has_value() && print == PrintErrors::Yes) { print_error_message(res.error()); } - REQUIRE(res.has_value() == !expect_fail); return res; } +static Parse::ParseExpected test_parse_manifest(StringView obj, PrintErrors print = PrintErrors::Yes) +{ + return test_parse_manifest(parse_json_object(obj), print); +} + +static bool manifest_is_parseable(const Json::Object& obj) +{ + return test_parse_manifest(obj, PrintErrors::No).has_value(); +} +static bool manifest_is_parseable(StringView obj) +{ + return test_parse_manifest(parse_json_object(obj), PrintErrors::No).has_value(); +} static const FeatureFlagSettings feature_flags_with_versioning{false, false, false, true}; static const FeatureFlagSettings feature_flags_without_versioning{false, false, false, false}; @@ -58,7 +78,7 @@ TEST_CASE ("manifest construct minimum", "[manifests]") auto& pgh = **m_pgh.get(); REQUIRE(pgh.core_paragraph->name == "zlib"); - REQUIRE(pgh.core_paragraph->version == "1.2.8"); + REQUIRE(pgh.core_paragraph->raw_version == "1.2.8"); REQUIRE(pgh.core_paragraph->maintainers.empty()); REQUIRE(pgh.core_paragraph->contacts.is_empty()); REQUIRE(pgh.core_paragraph->summary.empty()); @@ -72,34 +92,34 @@ TEST_CASE ("manifest construct minimum", "[manifests]") TEST_CASE ("manifest versioning", "[manifests]") { - std::tuple data[] = { + std::tuple data[] = { {R"json({ "name": "zlib", "version-string": "abcd" } )json", - Versions::Scheme::String, + VersionScheme::String, "abcd"}, {R"json({ "name": "zlib", "version-date": "2020-01-01" } )json", - Versions::Scheme::Date, + VersionScheme::Date, "2020-01-01"}, {R"json({ "name": "zlib", "version": "1.2.3.4.5" } )json", - Versions::Scheme::Relaxed, + VersionScheme::Relaxed, "1.2.3.4.5"}, {R"json({ "name": "zlib", "version-semver": "1.2.3-rc3" } )json", - Versions::Scheme::Semver, + VersionScheme::Semver, "1.2.3-rc3"}, }; for (auto&& v : data) @@ -109,61 +129,53 @@ TEST_CASE ("manifest versioning", "[manifests]") auto& pgh = **m_pgh.get(); CHECK(Json::stringify(serialize_manifest(pgh), Json::JsonStyle::with_spaces(4)) == std::get<0>(v)); CHECK(pgh.core_paragraph->version_scheme == std::get<1>(v)); - CHECK(pgh.core_paragraph->version == std::get<2>(v)); + CHECK(pgh.core_paragraph->raw_version == std::get<2>(v)); CHECK(pgh.core_paragraph->port_version == 0); } - test_parse_manifest(R"json({ + REQUIRE_FALSE(manifest_is_parseable(R"json({ "name": "zlib", "version-string": "abcd", "version-semver": "1.2.3-rc3" - })json", - true); + })json")); - test_parse_manifest(R"json({ + REQUIRE_FALSE(manifest_is_parseable(R"json({ "name": "zlib", "version-string": "abcd#1" - })json", - true); - test_parse_manifest(R"json({ + })json")); + REQUIRE_FALSE(manifest_is_parseable(R"json({ "name": "zlib", "version": "abcd#1" - })json", - true); - test_parse_manifest(R"json({ + })json")); + REQUIRE_FALSE(manifest_is_parseable(R"json({ "name": "zlib", "version-date": "abcd#1" - })json", - true); - test_parse_manifest(R"json({ + })json")); + REQUIRE_FALSE(manifest_is_parseable(R"json({ "name": "zlib", "version-semver": "abcd#1" - })json", - true); + })json")); SECTION ("version syntax") { - test_parse_manifest(R"json({ + REQUIRE_FALSE(manifest_is_parseable(R"json({ "name": "zlib", "version-semver": "2020-01-01" - })json", - true); - test_parse_manifest(R"json({ + })json")); + REQUIRE_FALSE(manifest_is_parseable(R"json({ "name": "zlib", "version-date": "1.1.1" - })json", - true); - test_parse_manifest(R"json({ + })json")); + REQUIRE(manifest_is_parseable(R"json({ "name": "zlib", "version": "1.2.3-rc3" - })json", - false); + })json")); } } TEST_CASE ("manifest constraints hash", "[manifests]") { - auto p = unwrap(test_parse_manifest(R"json({ + auto m_pgh = test_parse_manifest(R"json({ "name": "zlib", "version-string": "abcd", "dependencies": [ @@ -172,11 +184,13 @@ TEST_CASE ("manifest constraints hash", "[manifests]") "version>=": "2018-09-01#1" } ] -})json")); +})json"); + REQUIRE(m_pgh.has_value()); + const auto& p = *m_pgh.get(); REQUIRE(p->core_paragraph->dependencies.at(0).constraint.value == "2018-09-01"); REQUIRE(p->core_paragraph->dependencies.at(0).constraint.port_version == 1); - test_parse_manifest(R"json({ + REQUIRE_FALSE(manifest_is_parseable(R"json({ "name": "zlib", "version-string": "abcd", "dependencies": [ @@ -185,10 +199,9 @@ TEST_CASE ("manifest constraints hash", "[manifests]") "version>=": "2018-09-01#0" } ] -})json", - true); +})json")); - test_parse_manifest(R"json({ + REQUIRE_FALSE(manifest_is_parseable(R"json({ "name": "zlib", "version-string": "abcd", "dependencies": [ @@ -197,10 +210,9 @@ TEST_CASE ("manifest constraints hash", "[manifests]") "version>=": "2018-09-01#-1" } ] -})json", - true); +})json")); - test_parse_manifest(R"json({ + REQUIRE_FALSE(manifest_is_parseable(R"json({ "name": "zlib", "version-string": "abcd", "dependencies": [ @@ -210,13 +222,12 @@ TEST_CASE ("manifest constraints hash", "[manifests]") "port-version": 1 } ] -})json", - true); +})json")); } TEST_CASE ("manifest overrides embedded port version", "[manifests]") { - test_parse_manifest(R"json({ + REQUIRE_FALSE(manifest_is_parseable(R"json({ "name": "zlib", "version-string": "abcd", "overrides": [ @@ -226,9 +237,8 @@ TEST_CASE ("manifest overrides embedded port version", "[manifests]") "port-version": 1 } ] -})json", - true); - test_parse_manifest(R"json({ +})json")); + REQUIRE_FALSE(manifest_is_parseable(R"json({ "name": "zlib", "version-string": "abcd", "overrides": [ @@ -238,9 +248,8 @@ TEST_CASE ("manifest overrides embedded port version", "[manifests]") "port-version": 1 } ] -})json", - true); - test_parse_manifest(R"json({ +})json")); + REQUIRE_FALSE(manifest_is_parseable(R"json({ "name": "zlib", "version-string": "abcd", "overrides": [ @@ -250,9 +259,8 @@ TEST_CASE ("manifest overrides embedded port version", "[manifests]") "port-version": 1 } ] -})json", - true); - test_parse_manifest(R"json({ +})json")); + REQUIRE_FALSE(manifest_is_parseable(R"json({ "name": "zlib", "version-string": "abcd", "overrides": [ @@ -262,10 +270,9 @@ TEST_CASE ("manifest overrides embedded port version", "[manifests]") "port-version": 1 } ] -})json", - true); +})json")); - CHECK(unwrap(test_parse_manifest(R"json({ + auto parsed = test_parse_manifest(R"json({ "name": "zlib", "version-string": "abcd", "overrides": [ @@ -274,11 +281,11 @@ TEST_CASE ("manifest overrides embedded port version", "[manifests]") "version-string": "abcd#1" } ] -})json", - false)) - ->core_paragraph->overrides.at(0) - .port_version == 1); - CHECK(unwrap(test_parse_manifest(R"json({ +})json"); + REQUIRE(parsed.has_value()); + CHECK((*parsed.get())->core_paragraph->overrides.at(0).port_version == 1); + + parsed = test_parse_manifest(R"json({ "name": "zlib", "version-string": "abcd", "overrides": [ @@ -287,11 +294,11 @@ TEST_CASE ("manifest overrides embedded port version", "[manifests]") "version-date": "2018-01-01#1" } ] -})json", - false)) - ->core_paragraph->overrides.at(0) - .port_version == 1); - CHECK(unwrap(test_parse_manifest(R"json({ +})json"); + REQUIRE(parsed.has_value()); + CHECK((*parsed.get())->core_paragraph->overrides.at(0).port_version == 1); + + parsed = test_parse_manifest(R"json({ "name": "zlib", "version-string": "abcd", "overrides": [ @@ -300,11 +307,11 @@ TEST_CASE ("manifest overrides embedded port version", "[manifests]") "version": "1.2#1" } ] -})json", - false)) - ->core_paragraph->overrides.at(0) - .port_version == 1); - CHECK(unwrap(test_parse_manifest(R"json({ +})json"); + REQUIRE(parsed.has_value()); + CHECK((*parsed.get())->core_paragraph->overrides.at(0).port_version == 1); + + parsed = test_parse_manifest(R"json({ "name": "zlib", "version-string": "abcd", "overrides": [ @@ -313,10 +320,9 @@ TEST_CASE ("manifest overrides embedded port version", "[manifests]") "version-semver": "1.2.0#1" } ] -})json", - false)) - ->core_paragraph->overrides.at(0) - .port_version == 1); +})json"); + REQUIRE(parsed.has_value()); + CHECK((*parsed.get())->core_paragraph->overrides.at(0).port_version == 1); } TEST_CASE ("manifest constraints", "[manifests]") @@ -347,17 +353,15 @@ TEST_CASE ("manifest constraints", "[manifests]") REQUIRE(Json::stringify(serialize_manifest(pgh), Json::JsonStyle::with_spaces(4)) == raw); 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[0].constraint == DependencyConstraint{VersionConstraintKind::None, "", 0}); REQUIRE(pgh.core_paragraph->dependencies[1].name == "c"); - REQUIRE(pgh.core_paragraph->dependencies[1].constraint == - DependencyConstraint{Versions::Constraint::Type::None, "", 0}); + REQUIRE(pgh.core_paragraph->dependencies[1].constraint == DependencyConstraint{VersionConstraintKind::None, "", 0}); REQUIRE(pgh.core_paragraph->dependencies[2].name == "d"); REQUIRE(pgh.core_paragraph->dependencies[2].constraint == - DependencyConstraint{Versions::Constraint::Type::Minimum, "2018-09-01", 0}); + DependencyConstraint{VersionConstraintKind::Minimum, "2018-09-01", 0}); REQUIRE(pgh.core_paragraph->builtin_baseline == "089fa4de7dca22c67dcab631f618d5cd0697c8d4"); - test_parse_manifest(R"json({ + REQUIRE_FALSE(manifest_is_parseable(R"json({ "name": "zlib", "version-string": "abcd", "dependencies": [ @@ -366,8 +370,7 @@ TEST_CASE ("manifest constraints", "[manifests]") "port-version": 5 } ] - })json", - true); + })json")); } TEST_CASE ("manifest builtin-baseline", "[manifests]") @@ -435,9 +438,9 @@ TEST_CASE ("manifest builtin-baseline", "[manifests]") REQUIRE(pgh.core_paragraph->dependencies.size() == 1); REQUIRE(pgh.core_paragraph->dependencies[0].constraint.value == "abcd"); REQUIRE(pgh.core_paragraph->dependencies[0].constraint.port_version == 1); - REQUIRE(pgh.core_paragraph->dependencies[0].constraint.type == Versions::Constraint::Type::Minimum); + REQUIRE(pgh.core_paragraph->dependencies[0].constraint.type == VersionConstraintKind::Minimum); REQUIRE(pgh.core_paragraph->overrides.size() == 1); - REQUIRE(pgh.core_paragraph->overrides[0].version_scheme == Versions::Scheme::String); + REQUIRE(pgh.core_paragraph->overrides[0].version_scheme == VersionScheme::String); REQUIRE(pgh.core_paragraph->overrides[0].version == "abcd"); REQUIRE(pgh.core_paragraph->overrides[0].port_version == 0); REQUIRE(pgh.core_paragraph->builtin_baseline.value_or("does not have a value") == @@ -472,9 +475,9 @@ TEST_CASE ("manifest builtin-baseline", "[manifests]") REQUIRE(pgh.core_paragraph->dependencies.size() == 1); REQUIRE(pgh.core_paragraph->dependencies[0].constraint.value == "abcd"); REQUIRE(pgh.core_paragraph->dependencies[0].constraint.port_version == 1); - REQUIRE(pgh.core_paragraph->dependencies[0].constraint.type == Versions::Constraint::Type::Minimum); + REQUIRE(pgh.core_paragraph->dependencies[0].constraint.type == VersionConstraintKind::Minimum); REQUIRE(pgh.core_paragraph->overrides.size() == 1); - REQUIRE(pgh.core_paragraph->overrides[0].version_scheme == Versions::Scheme::String); + REQUIRE(pgh.core_paragraph->overrides[0].version_scheme == VersionScheme::String); REQUIRE(pgh.core_paragraph->overrides[0].version == "abcd"); REQUIRE(pgh.core_paragraph->overrides[0].port_version == 0); REQUIRE(!pgh.core_paragraph->builtin_baseline.has_value()); @@ -485,7 +488,7 @@ TEST_CASE ("manifest builtin-baseline", "[manifests]") TEST_CASE ("manifest overrides", "[manifests]") { - std::tuple data[] = { + std::tuple data[] = { {R"json({ "name": "zlib", "version-date": "2020-01-01", @@ -498,7 +501,7 @@ TEST_CASE ("manifest overrides", "[manifests]") ] } )json", - Versions::Scheme::String, + VersionScheme::String, "abcd"}, {R"json({ "name": "zlib", @@ -512,7 +515,7 @@ TEST_CASE ("manifest overrides", "[manifests]") ] } )json", - Versions::Scheme::Date, + VersionScheme::Date, "2020-01-01"}, {R"json({ "name": "zlib", @@ -526,7 +529,7 @@ TEST_CASE ("manifest overrides", "[manifests]") ] } )json", - Versions::Scheme::Relaxed, + VersionScheme::Relaxed, "1.2.3.4.5"}, {R"json({ "name": "zlib", @@ -540,7 +543,7 @@ TEST_CASE ("manifest overrides", "[manifests]") ] } )json", - Versions::Scheme::Semver, + VersionScheme::Semver, "1.2.3-rc3"}, }; for (auto&& v : data) @@ -557,7 +560,7 @@ TEST_CASE ("manifest overrides", "[manifests]") REQUIRE(!pgh.check_against_feature_flags({}, feature_flags_with_versioning)); } - test_parse_manifest(R"json({ + REQUIRE_FALSE(manifest_is_parseable(R"json({ "name": "zlib", "version-string": "abcd", "builtin-baseline": "089fa4de7dca22c67dcab631f618d5cd0697c8d4", @@ -567,10 +570,9 @@ TEST_CASE ("manifest overrides", "[manifests]") "version-semver": "1.2.3-rc3", "version-string": "1.2.3-rc3" } - ]})json", - true); + ]})json")); - test_parse_manifest(R"json({ + REQUIRE_FALSE(manifest_is_parseable(R"json({ "name": "zlib", "version-string": "abcd", "builtin-baseline": "089fa4de7dca22c67dcab631f618d5cd0697c8d4", @@ -579,8 +581,7 @@ TEST_CASE ("manifest overrides", "[manifests]") "name": "abc", "port-version": 5 } - ]})json", - true); + ]})json")); std::string raw = R"json({ "name": "zlib", @@ -686,14 +687,12 @@ TEST_CASE ("manifest embed configuration", "[manifests]") REQUIRE(pgh.core_paragraph->builtin_baseline == "089fa4de7dca22c67dcab631f618d5cd0697c8d4"); 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[0].constraint == DependencyConstraint{VersionConstraintKind::None, "", 0}); REQUIRE(pgh.core_paragraph->dependencies[1].name == "b"); - REQUIRE(pgh.core_paragraph->dependencies[1].constraint == - DependencyConstraint{Versions::Constraint::Type::None, "", 0}); + REQUIRE(pgh.core_paragraph->dependencies[1].constraint == DependencyConstraint{VersionConstraintKind::None, "", 0}); REQUIRE(pgh.core_paragraph->dependencies[2].name == "c"); REQUIRE(pgh.core_paragraph->dependencies[2].constraint == - DependencyConstraint{Versions::Constraint::Type::Minimum, "2018-09-01", 0}); + DependencyConstraint{VersionConstraintKind::Minimum, "2018-09-01", 0}); auto maybe_config = Json::parse(raw_config, ""); REQUIRE(maybe_config.has_value()); @@ -755,7 +754,7 @@ TEST_CASE ("manifest construct maximum", "[manifests]") auto& pgh = **res.get(); REQUIRE(pgh.core_paragraph->name == "s"); - REQUIRE(pgh.core_paragraph->version == "v"); + REQUIRE(pgh.core_paragraph->raw_version == "v"); REQUIRE(pgh.core_paragraph->maintainers.size() == 1); REQUIRE(pgh.core_paragraph->maintainers[0] == "m"); REQUIRE(pgh.core_paragraph->contacts.size() == 1); @@ -862,7 +861,7 @@ TEST_CASE ("SourceParagraph manifest construct qualified dependencies", "[manife auto& pgh = **m_pgh.get(); REQUIRE(pgh.core_paragraph->name == "zlib"); - REQUIRE(pgh.core_paragraph->version == "1.2.8"); + REQUIRE(pgh.core_paragraph->raw_version == "1.2.8"); REQUIRE(pgh.core_paragraph->maintainers.empty()); REQUIRE(pgh.core_paragraph->description.empty()); REQUIRE(pgh.core_paragraph->dependencies.size() == 2); @@ -891,7 +890,7 @@ TEST_CASE ("SourceParagraph manifest construct host dependencies", "[manifests]" auto& pgh = **m_pgh.get(); REQUIRE(pgh.core_paragraph->name == "zlib"); - REQUIRE(pgh.core_paragraph->version == "1.2.8"); + REQUIRE(pgh.core_paragraph->raw_version == "1.2.8"); REQUIRE(pgh.core_paragraph->maintainers.empty()); REQUIRE(pgh.core_paragraph->description.empty()); REQUIRE(pgh.core_paragraph->dependencies.size() == 2); @@ -950,77 +949,146 @@ TEST_CASE ("SourceParagraph manifest supports", "[manifests]") TEST_CASE ("SourceParagraph manifest empty supports", "[manifests]") { - auto m_pgh = test_parse_manifest(R"json({ + REQUIRE_FALSE(manifest_is_parseable(R"json({ "name": "a", "version-string": "1.0", "supports": "" - })json", - true); - REQUIRE_FALSE(m_pgh.has_value()); + })json")); } TEST_CASE ("SourceParagraph manifest non-string supports", "[manifests]") { - auto m_pgh = test_parse_manifest(R"json({ + REQUIRE_FALSE(manifest_is_parseable(R"json({ "name": "a", "version-string": "1.0", "supports": true - })json", - true); - REQUIRE_FALSE(m_pgh.has_value()); + })json")); } -TEST_CASE ("Serialize all the ports", "[all-manifests]") +static Json::Object manifest_with_license(Json::Value&& license) +{ + Json::Object res; + res.insert("name", Json::Value::string("foo")); + res.insert("version", Json::Value::string("0")); + res.insert("license", std::move(license)); + return res; +} +static Json::Object manifest_with_license(StringView license) +{ + return manifest_with_license(Json::Value::string(license.to_string())); +} +static std::string test_serialized_license(StringView license) { - std::vector args_list = {"format-manifest"}; - auto& fs = get_real_filesystem(); - auto args = VcpkgCmdArguments::create_from_arg_sequence(args_list.data(), args_list.data() + args_list.size()); - args.imbue_from_environment(); - VcpkgPaths paths{fs, args}; + auto m_pgh = test_parse_manifest(manifest_with_license(license)); + REQUIRE(m_pgh.has_value()); - std::vector scfs; + return serialize_manifest(**m_pgh.get())["license"].string().to_string(); +} - for (auto&& dir : fs.get_directories_non_recursive(paths.builtin_ports_directory(), VCPKG_LINE_INFO)) - { - const auto control = dir / "CONTROL"; - const auto manifest = dir / "vcpkg.json"; - if (fs.exists(control, IgnoreErrors{})) - { - INFO(control.native()); - auto contents = fs.read_contents(control, VCPKG_LINE_INFO); - auto pghs = Paragraphs::parse_paragraphs(contents, control); - REQUIRE(pghs); +static bool license_is_parseable(StringView license) +{ + Parse::ParseMessages messages; + parse_spdx_license_expression(license, messages); + return messages.error == nullptr; +} +static bool license_is_strict(StringView license) +{ + Parse::ParseMessages messages; + parse_spdx_license_expression(license, messages); + return messages.error == nullptr && messages.warnings.empty(); +} - auto scf = SourceControlFile::parse_control_file(control, std::move(pghs).value_or_exit(VCPKG_LINE_INFO)); - if (!scf) - { - INFO(scf.error()->name); - INFO(scf.error()->error); - REQUIRE(scf); - } +static std::string test_format_parse_warning(const Parse::ParseMessage& msg) +{ + return msg.format("", Parse::MessageKind::Warning).extract_data(); +} - scfs.push_back(std::move(*scf.value_or_exit(VCPKG_LINE_INFO))); - } - else if (fs.exists(manifest, IgnoreErrors{})) - { - std::error_code ec; - auto contents = Json::parse_file(fs, manifest, ec); - REQUIRE_FALSE(ec); - REQUIRE(contents); +TEST_CASE ("simple license in manifest", "[manifests][license]") +{ + CHECK(manifest_is_parseable(manifest_with_license(Json::Value::null(nullptr)))); + CHECK_FALSE(manifest_is_parseable(manifest_with_license(""))); + CHECK(manifest_is_parseable(manifest_with_license("MIT"))); +} - auto scf = SourceControlFile::parse_manifest_object(manifest, - contents.value_or_exit(VCPKG_LINE_INFO).first.object()); - REQUIRE(scf); +TEST_CASE ("valid and invalid licenses", "[manifests][license]") +{ + CHECK(license_is_strict("mIt")); + CHECK(license_is_strict("Apache-2.0")); + CHECK(license_is_strict("GPL-2.0+")); + CHECK_FALSE(license_is_parseable("GPL-2.0++")); + CHECK(license_is_strict("LicenseRef-blah")); + CHECK_FALSE(license_is_strict("unknownlicense")); + CHECK(license_is_parseable("unknownlicense")); +} - scfs.push_back(std::move(*scf.value_or_exit(VCPKG_LINE_INFO))); - } - } +TEST_CASE ("licenses with compounds", "[manifests][license]") +{ + CHECK(license_is_strict("GPL-3.0+ WITH GCC-exception-3.1")); + CHECK(license_is_strict("Apache-2.0 WITH LLVM-exception")); + CHECK_FALSE(license_is_parseable("(Apache-2.0) WITH LLVM-exception")); + CHECK(license_is_strict("(Apache-2.0 OR MIT) AND GPL-3.0+ WITH GCC-exception-3.1")); + CHECK_FALSE(license_is_parseable("Apache-2.0 WITH")); + CHECK_FALSE(license_is_parseable("GPL-3.0+ AND")); + CHECK_FALSE(license_is_parseable("MIT and Apache-2.0")); + CHECK_FALSE(license_is_parseable("GPL-3.0 WITH GCC-exception+")); + CHECK_FALSE(license_is_parseable("(GPL-3.0 WITH GCC-exception)+")); +} - for (auto& scf : scfs) - { - auto serialized = serialize_manifest(scf); - auto serialized_scf = SourceControlFile::parse_manifest_object({}, serialized).value_or_exit(VCPKG_LINE_INFO); +TEST_CASE ("license serialization", "[manifests][license]") +{ + auto m_pgh = test_parse_manifest(manifest_with_license(Json::Value::null(nullptr))); + REQUIRE(m_pgh); + auto manifest = serialize_manifest(**m_pgh.get()); + REQUIRE(manifest.contains("license")); + CHECK(manifest["license"].is_null()); + + CHECK(test_serialized_license("MIT") == "MIT"); + CHECK(test_serialized_license("mit") == "MIT"); + CHECK(test_serialized_license("MiT AND (aPACHe-2.0 \tOR \n gpl-2.0+)") == "MIT AND (Apache-2.0 OR GPL-2.0+)"); + CHECK(test_serialized_license("uNkNoWnLiCeNsE") == "uNkNoWnLiCeNsE"); +} - REQUIRE(*serialized_scf == scf); - } +TEST_CASE ("license error messages", "[manifests][license]") +{ + Parse::ParseMessages messages; + parse_spdx_license_expression("", messages); + REQUIRE(messages.error); + CHECK(messages.error->format() == R"(:1:1: error: SPDX license expression was empty. + on expression: + ^ +)"); + + parse_spdx_license_expression("MIT ()", messages); + REQUIRE(messages.error); + CHECK(messages.error->format() == + R"(:1:5: error: Expected a compound or the end of the string, found a parenthesis. + on expression: MIT () + ^ +)"); + + parse_spdx_license_expression("MIT +", messages); + REQUIRE(messages.error); + CHECK( + messages.error->format() == + R"(:1:5: error: SPDX license expression contains an extra '+'. These are only allowed directly after a license identifier. + on expression: MIT + + ^ +)"); + + parse_spdx_license_expression("MIT AND", messages); + REQUIRE(messages.error); + CHECK(messages.error->format() == + R"(:1:8: error: Expected a license name, found the end of the string. + on expression: MIT AND + ^ +)"); + + parse_spdx_license_expression("MIT AND unknownlicense", messages); + CHECK(!messages.error); + REQUIRE(messages.warnings.size() == 1); + CHECK( + test_format_parse_warning(messages.warnings[0]) == + R"(:1:9: warning: Unknown license identifier 'unknownlicense'. Known values are listed at https://spdx.org/licenses/ + on expression: MIT AND unknownlicense + ^)"); } diff --git a/src/vcpkg-test/paragraph.cpp b/src/vcpkg-test/paragraph.cpp index b44aaf50ab..0239e4b6f5 100644 --- a/src/vcpkg-test/paragraph.cpp +++ b/src/vcpkg-test/paragraph.cpp @@ -45,7 +45,7 @@ TEST_CASE ("SourceParagraph construct minimum", "[paragraph]") auto& pgh = **m_pgh.get(); REQUIRE(pgh.core_paragraph->name == "zlib"); - REQUIRE(pgh.core_paragraph->version == "1.2.8"); + REQUIRE(pgh.core_paragraph->raw_version == "1.2.8"); REQUIRE(pgh.core_paragraph->maintainers.empty()); REQUIRE(pgh.core_paragraph->description.empty()); REQUIRE(pgh.core_paragraph->dependencies.size() == 0); @@ -109,7 +109,7 @@ TEST_CASE ("SourceParagraph construct maximum", "[paragraph]") auto& pgh = **m_pgh.get(); REQUIRE(pgh.core_paragraph->name == "s"); - REQUIRE(pgh.core_paragraph->version == "v"); + REQUIRE(pgh.core_paragraph->raw_version == "v"); REQUIRE(pgh.core_paragraph->maintainers.size() == 1); REQUIRE(pgh.core_paragraph->maintainers[0] == "m"); REQUIRE(pgh.core_paragraph->description.size() == 1); @@ -182,7 +182,7 @@ TEST_CASE ("SourceParagraph construct qualified dependencies", "[paragraph]") auto& pgh = **m_pgh.get(); REQUIRE(pgh.core_paragraph->name == "zlib"); - REQUIRE(pgh.core_paragraph->version == "1.2.8"); + REQUIRE(pgh.core_paragraph->raw_version == "1.2.8"); REQUIRE(pgh.core_paragraph->maintainers.empty()); REQUIRE(pgh.core_paragraph->description.empty()); REQUIRE(pgh.core_paragraph->dependencies.size() == 2); diff --git a/src/vcpkg-test/registries.cpp b/src/vcpkg-test/registries.cpp index 4337e11085..78f9461287 100644 --- a/src/vcpkg-test/registries.cpp +++ b/src/vcpkg-test/registries.cpp @@ -17,7 +17,7 @@ namespace void get_all_port_names(std::vector&) const override { } - Optional get_baseline_version(StringView) const override { return nullopt; } + Optional get_baseline_version(StringView) const override { return nullopt; } int number; @@ -248,11 +248,11 @@ TEST_CASE ("git_version_db_parsing", "[registries]") auto results_opt = r.visit(test_json, filesystem_version_db); auto& results = results_opt.value_or_exit(VCPKG_LINE_INFO); - CHECK(results[0].version == VersionT{"2021-06-26", 0}); + CHECK(results[0].version == Version{"2021-06-26", 0}); CHECK(results[0].git_tree == "9b07f8a38bbc4d13f8411921e6734753e15f8d50"); - CHECK(results[1].version == VersionT{"2021-01-14", 0}); + CHECK(results[1].version == Version{"2021-01-14", 0}); CHECK(results[1].git_tree == "12b84a31469a78dd4b42dcf58a27d4600f6b2d48"); - CHECK(results[2].version == VersionT{"2020-04-12", 0}); + CHECK(results[2].version == Version{"2020-04-12", 0}); CHECK(results[2].git_tree == "bd4565e8ab55bc5e098a1750fa5ff0bc4406ca9b"); CHECK(r.errors().empty()); } @@ -284,11 +284,11 @@ TEST_CASE ("filesystem_version_db_parsing", "[registries]") )json"); auto results_opt = r.visit(test_json, filesystem_version_db); auto& results = results_opt.value_or_exit(VCPKG_LINE_INFO); - CHECK(results[0].version == VersionT{"puppies", 0}); + CHECK(results[0].version == Version{"puppies", 0}); CHECK(results[0].p == "a/b" VCPKG_PREFERRED_SEPARATOR "c/d"); - CHECK(results[1].version == VersionT{"doggies", 0}); + CHECK(results[1].version == Version{"doggies", 0}); CHECK(results[1].p == "a/b" VCPKG_PREFERRED_SEPARATOR "e/d"); - CHECK(results[2].version == VersionT{"1.2.3", 0}); + CHECK(results[2].version == Version{"1.2.3", 0}); CHECK(results[2].p == "a/b" VCPKG_PREFERRED_SEPARATOR "semvers/here"); CHECK(r.errors().empty()); } diff --git a/src/vcpkg-test/system.cpp b/src/vcpkg-test/system.cpp index af9579b291..b7c86716ec 100644 --- a/src/vcpkg-test/system.cpp +++ b/src/vcpkg-test/system.cpp @@ -65,6 +65,7 @@ TEST_CASE ("[to_cpu_architecture]", "system") {nullopt, "ARM6"}, {nullopt, "AR"}, {nullopt, "Intel"}, + {nullopt, "%processor_architew6432%"}, }; for (auto&& instance : test_cases) diff --git a/src/vcpkg/archives.cpp b/src/vcpkg/archives.cpp index 271bb50a7e..0f4e313884 100644 --- a/src/vcpkg/archives.cpp +++ b/src/vcpkg/archives.cpp @@ -210,6 +210,48 @@ namespace vcpkg #endif } + int compress_directory_to_zip(const VcpkgPaths& paths, const Path& source, const Path& destination) + { + auto& fs = paths.get_filesystem(); + fs.remove(destination, VCPKG_LINE_INFO); +#if defined(_WIN32) + auto&& seven_zip_exe = paths.get_tool_exe(Tools::SEVEN_ZIP); + + return cmd_execute_and_capture_output( + Command{seven_zip_exe}.string_arg("a").path_arg(destination).path_arg(source / "*"), + get_clean_environment()) + .exit_code; + +#else + return cmd_execute_clean(Command{"zip"} + .string_arg("--quiet") + .string_arg("-y") + .string_arg("-r") + .path_arg(destination) + .string_arg("*") + .string_arg("--exclude") + .string_arg(".DS_Store"), + InWorkingDirectory{source}); +#endif + } + + Command decompress_zip_archive_cmd(const VcpkgPaths& paths, const Path& dst, const Path& archive_path) + { + Command cmd; +#if defined(_WIN32) + auto&& seven_zip_exe = paths.get_tool_exe(Tools::SEVEN_ZIP); + cmd.path_arg(seven_zip_exe) + .string_arg("x") + .path_arg(archive_path) + .string_arg("-o" + dst.native()) + .string_arg("-y"); +#else + (void)paths; + cmd.string_arg("unzip").string_arg("-qq").path_arg(archive_path).string_arg("-d" + dst.native()); +#endif + return cmd; + } + std::vector decompress_in_parallel(View jobs) { auto results = cmd_execute_and_capture_output_parallel(jobs, get_clean_environment()); diff --git a/src/vcpkg/base/checks.cpp b/src/vcpkg/base/checks.cpp index b91985114c..497b411674 100644 --- a/src/vcpkg/base/checks.cpp +++ b/src/vcpkg/base/checks.cpp @@ -66,6 +66,13 @@ namespace vcpkg exit_fail(line_info); } + [[noreturn]] void Checks::exit_with_message_and_line(const LineInfo& line_info, StringView error_message) + { + print2(Color::error, + Strings::format("%s(%d): %s\n", line_info.file_name, line_info.line_number, error_message)); + exit_fail(line_info); + } + void Checks::check_exit(const LineInfo& line_info, bool expression) { if (!expression) diff --git a/src/vcpkg/base/cofffilereader.cpp b/src/vcpkg/base/cofffilereader.cpp index e9d5f369dd..2a5da3713a 100644 --- a/src/vcpkg/base/cofffilereader.cpp +++ b/src/vcpkg/base/cofffilereader.cpp @@ -211,6 +211,7 @@ namespace vcpkg case MachineType::AMD64: case MachineType::ARM: case MachineType::ARM64: + case MachineType::ARM64EC: case MachineType::ARMNT: case MachineType::EBC: case MachineType::I386: diff --git a/src/vcpkg/base/files.cpp b/src/vcpkg/base/files.cpp index 29fac88676..9a436c6db3 100644 --- a/src/vcpkg/base/files.cpp +++ b/src/vcpkg/base/files.cpp @@ -30,6 +30,8 @@ #include #if defined(_WIN32) +#include + #include namespace stdfs = std::filesystem; #endif // _WIN32 @@ -71,8 +73,8 @@ namespace StringView call_name, std::initializer_list args) { - Checks::exit_with_message( - li, Strings::concat(call_name, "(", Strings::join(", ", args.begin(), args.end()), "): ", ec.message())); + auto arguments = args.size() == 0 ? "()" : "(\"" + Strings::join("\", \"", args.begin(), args.end()) + "\")"; + Checks::exit_with_message_and_line(li, Strings::concat(call_name, arguments, ": ", ec.message())); } #if defined(_WIN32) @@ -826,7 +828,7 @@ namespace { // if it isn't still a directory something is racy ec = std::make_error_code(std::errc::device_or_resource_busy); - mark_recursive_error(base, ec, failure_point); + failure_point = base; return; } @@ -1308,7 +1310,9 @@ namespace vcpkg WriteFilePointer::WriteFilePointer(const Path& file_path, std::error_code& ec) noexcept { #if defined(_WIN32) - ec.assign(::_wfopen_s(&m_fs, to_stdfs_path(file_path).c_str(), L"wb"), std::generic_category()); + m_fs = ::_wfsopen(to_stdfs_path(file_path).c_str(), L"wb", _SH_DENYWR); + ec.assign(m_fs == nullptr ? errno : 0, std::generic_category()); + if (m_fs != nullptr) ::setvbuf(m_fs, NULL, _IONBF, 0); #else // ^^^ _WIN32 / !_WIN32 vvv m_fs = ::fopen(file_path.c_str(), "wb"); if (m_fs) @@ -1418,6 +1422,18 @@ namespace vcpkg return maybe_directories; } + std::vector Filesystem::get_regular_files_recursive_lexically_proximate(const Path& dir, LineInfo li) const + { + std::error_code ec; + auto maybe_directories = this->get_regular_files_recursive_lexically_proximate(dir, ec); + if (ec) + { + exit_filesystem_call_error(li, ec, __func__, {dir}); + } + + return maybe_directories; + } + std::vector Filesystem::get_regular_files_non_recursive(const Path& dir, LineInfo li) const { std::error_code ec; @@ -2064,6 +2080,21 @@ namespace vcpkg { return get_regular_files_impl(dir, ec); } + + virtual std::vector get_regular_files_recursive_lexically_proximate(const Path& dir, + std::error_code& ec) const override + { + auto ret = this->get_regular_files_recursive(dir, ec); + if (!ec) + { + const auto base = to_stdfs_path(dir); + for (auto& p : ret) + { + p = from_stdfs_path(to_stdfs_path(p).lexically_proximate(base)); + } + } + return ret; + } #else // ^^^ _WIN32 // !_WIN32 vvv static void insert_if_stat_matches(std::vector& result, const Path& full, @@ -2099,6 +2130,7 @@ namespace vcpkg static void get_files_recursive_impl(std::vector& result, const Path& base, + const Path& out_base, std::error_code& ec, bool want_directories, bool want_regular_files, @@ -2133,6 +2165,7 @@ namespace vcpkg } const auto full = base / entry->d_name; + const auto out_full = out_base / entry->d_name; const auto entry_dtype = get_d_type(entry); struct stat s; struct stat ls; @@ -2142,11 +2175,11 @@ namespace vcpkg if (want_directories) { // push results before recursion to get outer entries first - result.push_back(full); + result.push_back(out_full); } get_files_recursive_impl( - result, full, ec, want_directories, want_regular_files, want_other); + result, full, out_full, ec, want_directories, want_regular_files, want_other); if (ec) { return; @@ -2156,7 +2189,7 @@ namespace vcpkg case PosixDType::Regular: if (want_regular_files) { - result.push_back(full); + result.push_back(out_full); } break; @@ -2167,7 +2200,7 @@ namespace vcpkg case PosixDType::BlockDevice: if (want_other) { - result.push_back(full); + result.push_back(out_full); } break; @@ -2194,7 +2227,7 @@ namespace vcpkg if (want_directories && want_regular_files && want_other) { // skip extra stat syscall since we want everything - result.push_back(full); + result.push_back(out_full); } else { @@ -2214,21 +2247,21 @@ namespace vcpkg } insert_if_stat_matches( - result, full, &s, want_directories, want_regular_files, want_other); + result, out_full, &s, want_directories, want_regular_files, want_other); } } else { // push results before recursion to get outer entries first insert_if_stat_matches( - result, full, &ls, want_directories, want_regular_files, want_other); + result, out_full, &ls, want_directories, want_regular_files, want_other); } // recursion check doesn't follow symlinks: if (S_ISDIR(ls.st_mode)) { get_files_recursive_impl( - result, full, ec, want_directories, want_regular_files, want_other); + result, full, out_full, ec, want_directories, want_regular_files, want_other); } break; } @@ -2284,7 +2317,8 @@ namespace vcpkg virtual std::vector get_files_recursive(const Path& dir, std::error_code& ec) const override { std::vector result; - get_files_recursive_impl(result, dir, ec, true, true, true); + Path out_base = dir; + get_files_recursive_impl(result, dir, out_base, ec, true, true, true); return result; } @@ -2298,7 +2332,8 @@ namespace vcpkg virtual std::vector get_directories_recursive(const Path& dir, std::error_code& ec) const override { std::vector result; - get_files_recursive_impl(result, dir, ec, true, false, false); + Path out_base = dir; + get_files_recursive_impl(result, dir, out_base, ec, true, false, false); return result; } @@ -2327,7 +2362,17 @@ namespace vcpkg virtual std::vector get_regular_files_recursive(const Path& dir, std::error_code& ec) const override { std::vector result; - get_files_recursive_impl(result, dir, ec, false, true, false); + Path out_base = dir; + get_files_recursive_impl(result, dir, out_base, ec, false, true, false); + return result; + } + + virtual std::vector get_regular_files_recursive_lexically_proximate(const Path& dir, + std::error_code& ec) const override + { + std::vector result; + Path out_base; + get_files_recursive_impl(result, dir, out_base, ec, false, true, false); return result; } diff --git a/src/vcpkg/base/graphs.cpp b/src/vcpkg/base/graphs.cpp new file mode 100644 index 0000000000..d44beb07e0 --- /dev/null +++ b/src/vcpkg/base/graphs.cpp @@ -0,0 +1,7 @@ +#include + +namespace vcpkg::Graphs +{ + REGISTER_MESSAGE(GraphCycleDetected); + REGISTER_MESSAGE(GraphCycleDetectedElement); +} diff --git a/src/vcpkg/base/messages.cpp b/src/vcpkg/base/messages.cpp index 64a49a5ce6..55e98c9d12 100644 --- a/src/vcpkg/base/messages.cpp +++ b/src/vcpkg/base/messages.cpp @@ -223,13 +223,18 @@ namespace vcpkg::msg } } + static std::string locale_file_name(StringView language) + { + std::string filename = "messages"; + filename.append(language.begin(), language.end()).append(".json"); + return filename; + } + void threadunsafe_initialize_context(const Filesystem& fs, StringView language, const Path& locale_base) { threadunsafe_initialize_context(); - auto path_to_locale = locale_base; - path_to_locale /= language; - path_to_locale += ".json"; + auto path_to_locale = locale_base / locale_file_name(language); auto message_map = Json::parse_file(VCPKG_LINE_INFO, fs, path_to_locale); if (!message_map.first.is_object()) diff --git a/src/vcpkg/base/parse.cpp b/src/vcpkg/base/parse.cpp index fb1b4c3bfa..73e7f216a2 100644 --- a/src/vcpkg/base/parse.cpp +++ b/src/vcpkg/base/parse.cpp @@ -1,7 +1,9 @@ +#include #include #include #include +#include #include using namespace vcpkg; @@ -25,28 +27,67 @@ namespace vcpkg::Parse std::string ParseError::format() const { - auto caret_spacing = std::string(18, ' '); auto decoder = Unicode::Utf8Decoder(line.data(), line.data() + line.size()); - for (int i = 0; i < caret_col; ++i, ++decoder) + ParseMessage as_message; + as_message.location = SourceLoc{std::next(decoder, caret_col), decoder, row, column}; + as_message.message = msg::LocalizedString::from_string_unchecked(std::string(message)); + + auto res = as_message.format(origin, MessageKind::Error).extract_data(); + res.push_back('\n'); + return res; + } + + DECLARE_AND_REGISTER_MESSAGE(FormattedParseMessageLocation, + (msg::path, msg::row, msg::column), + "{LOCKED}", + "{path}:{row}:{column}: "); + DECLARE_AND_REGISTER_MESSAGE(FormattedParseError, (msg::value), "", "error: {value}"); + DECLARE_AND_REGISTER_MESSAGE(FormattedParseWarning, (msg::value), "", "warning: {value}"); + DECLARE_AND_REGISTER_MESSAGE(FormattedParseMessageExpression, (msg::value), "", " on expression: {value}"); + + msg::LocalizedString ParseMessage::format(StringView origin, MessageKind kind) const + { + msg::LocalizedString res = msg::format(msgFormattedParseMessageLocation, + msg::path = origin, + msg::row = location.row, + msg::column = location.column); + if (kind == MessageKind::Warning) { - const char32_t cp = *decoder; - // this may eventually want to check for full-width characters and grapheme clusters as well - caret_spacing.push_back(cp == '\t' ? '\t' : ' '); + res.append(msg::format(msgFormattedParseWarning, msg::value = message)); } + else + { + res.append(msg::format(msgFormattedParseError, msg::value = message)); + } + res.appendnl(); + + auto line_end = Util::find_if(location.it, Parse::ParserBase::is_lineend); + StringView line = StringView{ + location.start_of_line.pointer_to_current(), + line_end.pointer_to_current(), + }; + res.append(msg::format(msgFormattedParseMessageExpression, msg::value = line)); + res.appendnl(); - return Strings::concat(origin, - ":", - row, - ":", - column, - ": error: ", - message, - "\n" - " on expression: ", // 18 columns - line, - "\n", - caret_spacing, - "^\n"); + auto caret_point = StringView{location.start_of_line.pointer_to_current(), location.it.pointer_to_current()}; + auto formatted_caret_point = msg::format(msgFormattedParseMessageExpression, msg::value = caret_point); + + std::string caret_string; + caret_string.reserve(formatted_caret_point.data().size()); + for (char32_t ch : Unicode::Utf8Decoder(formatted_caret_point)) + { + if (ch == '\t') + caret_string.push_back('\t'); + else if (Unicode::is_double_width_code_point(ch)) + caret_string.append(" "); + else + caret_string.push_back(' '); + } + caret_string.push_back('^'); + + res.append(msg::LocalizedString::from_string_unchecked(std::move(caret_string))); + + return res; } const std::string& ParseError::get_message() const { return this->message; } @@ -84,10 +125,15 @@ namespace vcpkg::Parse return cur(); } + void ParserBase::add_warning(msg::LocalizedString&& message, const SourceLoc& loc) + { + m_messages.warnings.push_back(ParseMessage{loc, std::move(message)}); + } + void ParserBase::add_error(std::string message, const SourceLoc& loc) { // avoid cascading errors by only saving the first - if (!m_err) + if (!m_messages.error) { // find end of line auto line_end = loc.it; @@ -95,7 +141,7 @@ namespace vcpkg::Parse { ++line_end; } - m_err = std::make_unique( + m_messages.error = std::make_unique( m_origin.to_string(), loc.row, loc.column, diff --git a/src/vcpkg/base/system.cpp b/src/vcpkg/base/system.cpp index b7d257b2cf..e6e6ad25a8 100644 --- a/src/vcpkg/base/system.cpp +++ b/src/vcpkg/base/system.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -10,6 +11,25 @@ #include #endif +namespace +{ + DECLARE_AND_REGISTER_MESSAGE(ProcessorArchitectureW6432Malformed, + (vcpkg::msg::value), + "", + "Failed to parse %PROCESSOR_ARCHITEW6432% ({value}) as a valid CPU architecture. " + "Falling back to %PROCESSOR_ARCHITECTURE%."); + + DECLARE_AND_REGISTER_MESSAGE(ProcessorArchitectureMissing, + (), + "", + "The required environment variable %PROCESSOR_ARCHITECTURE% is missing."); + + DECLARE_AND_REGISTER_MESSAGE(ProcessorArchitectureMalformed, + (vcpkg::msg::value), + "", + "Failed to parse %PROCESSOR_ARCHITECTURE% ({value}) as a valid CPU architecture."); +} + namespace vcpkg { long get_process_id() @@ -50,11 +70,43 @@ namespace vcpkg CPUArchitecture get_host_processor() { #if defined(_WIN32) - auto w6432 = get_environment_variable("PROCESSOR_ARCHITEW6432"); - if (const auto p = w6432.get()) return to_cpu_architecture(*p).value_or_exit(VCPKG_LINE_INFO); + auto raw_identifier = get_environment_variable("PROCESSOR_IDENTIFIER"); + if (const auto id = raw_identifier.get()) + { + // might be either ARMv8 (64-bit) or ARMv9 (64-bit) + if (Strings::contains(*id, "ARMv") && Strings::contains(*id, "(64-bit)")) + { + return CPUArchitecture::ARM64; + } + } + + auto raw_w6432 = get_environment_variable("PROCESSOR_ARCHITEW6432"); + if (const auto w6432 = raw_w6432.get()) + { + const auto parsed_w6432 = to_cpu_architecture(*w6432); + if (const auto parsed = parsed_w6432.get()) + { + return *parsed; + } + + msg::print(Color::warning, msgProcessorArchitectureW6432Malformed, msg::value = *w6432); + } + + const auto raw_processor_architecture = get_environment_variable("PROCESSOR_ARCHITECTURE"); + const auto processor_architecture = raw_processor_architecture.get(); + if (!processor_architecture) + { + Checks::exit_with_message(VCPKG_LINE_INFO, msgProcessorArchitectureMissing); + } + + const auto raw_parsed_processor_architecture = to_cpu_architecture(*processor_architecture); + if (const auto parsed_processor_architecture = raw_parsed_processor_architecture.get()) + { + return *parsed_processor_architecture; + } - const auto procarch = get_environment_variable("PROCESSOR_ARCHITECTURE").value_or_exit(VCPKG_LINE_INFO); - return to_cpu_architecture(procarch).value_or_exit(VCPKG_LINE_INFO); + Checks::exit_with_message( + VCPKG_LINE_INFO, msgProcessorArchitectureMalformed, msg::value = *processor_architecture); #else // ^^^ defined(_WIN32) / !defined(_WIN32) vvv #if defined(__x86_64__) || defined(_M_X64) #if defined(__APPLE__) diff --git a/src/vcpkg/base/system.process.cpp b/src/vcpkg/base/system.process.cpp index ea2f1bbcb2..84e121f3df 100644 --- a/src/vcpkg/base/system.process.cpp +++ b/src/vcpkg/base/system.process.cpp @@ -386,6 +386,9 @@ namespace vcpkg new_path += Strings::format(";%s", extra_env.find("PATH")->second); env_cstr.append(Strings::to_utf16(new_path)); env_cstr.push_back(L'\0'); + // NOTE: we support VS's without the english language pack, + // but we still want to default to english just in case your specific + // non-standard build system doesn't support non-english env_cstr.append(L"VSLANG=1033"); env_cstr.push_back(L'\0'); env_cstr.append(L"VSCMD_SKIP_SENDTELEMETRY=1"); @@ -909,6 +912,5 @@ namespace vcpkg } #else void register_console_ctrl_handler() { } - #endif } diff --git a/src/vcpkg/base/unicode.cpp b/src/vcpkg/base/unicode.cpp index d0758e45b4..bb81b24f72 100644 --- a/src/vcpkg/base/unicode.cpp +++ b/src/vcpkg/base/unicode.cpp @@ -92,6 +92,103 @@ namespace vcpkg::Unicode return count; } + std::pair utf8_decode_code_point(const char* first, + const char* last, + char32_t& out) noexcept + { + out = end_of_file; + if (first == last) + { + return {last, utf8_errc::NoError}; + } + + auto code_unit = *first; + auto kind = utf8_code_unit_kind(code_unit); + const int count = utf8_code_unit_count(kind); + + const char* it = first + 1; + + if (kind == Utf8CodeUnitKind::Invalid) + { + return {it, utf8_errc::InvalidCodeUnit}; + } + else if (kind == Utf8CodeUnitKind::Continue) + { + return {it, utf8_errc::UnexpectedContinue}; + } + else if (count > last - first) + { + return {last, utf8_errc::UnexpectedEof}; + } + + if (count == 1) + { + out = static_cast(code_unit); + return {it, utf8_errc::NoError}; + } + + // 2 -> 0b0001'1111, 6 + // 3 -> 0b0000'1111, 12 + // 4 -> 0b0000'0111, 18 + const auto start_mask = static_cast(0xFF >> (count + 1)); + const int start_shift = 6 * (count - 1); + char32_t code_point = static_cast(code_unit & start_mask) << start_shift; + + constexpr unsigned char continue_mask = 0b0011'1111; + for (int byte = 1; byte < count; ++byte) + { + code_unit = static_cast(*it++); + + kind = utf8_code_unit_kind(code_unit); + if (kind == Utf8CodeUnitKind::Invalid) + { + return {it, utf8_errc::InvalidCodeUnit}; + } + else if (kind != Utf8CodeUnitKind::Continue) + { + return {it, utf8_errc::UnexpectedStart}; + } + + const int shift = 6 * (count - byte - 1); + code_point |= (code_unit & continue_mask) << shift; + } + + if (code_point > 0x10'FFFF) + { + return {it, utf8_errc::InvalidCodePoint}; + } + + out = code_point; + return {it, utf8_errc::NoError}; + } + + // uses the C++20 definition + /* + [format.string.std] + * U+1100 - U+115F + * U+2329 - U+232A + * U+2E80 - U+303E + * U+3040 - U+A4CF + * U+AC00 - U+D7A3 + * U+F900 - U+FAFF + * U+FE10 - U+FE19 + * U+FE30 - U+FE6F + * U+FF00 - U+FF60 + * U+FFE0 - U+FFE6 + * U+1F300 - U+1F64F + * U+1F900 - U+1F9FF + * U+20000 - U+2FFFD + * U+30000 - U+3FFFD + */ + bool is_double_width_code_point(char32_t ch) noexcept + { + return (ch >= 0x1100 && ch <= 0x115F) || (ch >= 0x2329 && ch <= 0x232A) || (ch >= 0x2E80 && ch <= 0x303E) || + (ch >= 0x3040 && ch <= 0xA4CF) || (ch >= 0xAC00 && ch <= 0xD7A3) || (ch >= 0xF900 && ch <= 0xFAFF) || + (ch >= 0xFE10 && ch <= 0xFE19) || (ch >= 0xFE30 && ch <= 0xFE6F) || (ch >= 0xFF00 && ch <= 0xFF60) || + (ch >= 0xFFE0 && ch <= 0xFFE6) || (ch >= 0x1F300 && ch <= 0x1F64F) || (ch >= 0x1F900 && ch <= 0x1F9FF) || + (ch >= 0x20000 && ch <= 0x2FFFD) || (ch >= 0x30000 && ch <= 0x3FFFD); + } + bool utf8_is_valid_string(const char* first, const char* last) noexcept { utf8_errc err = utf8_errc::NoError; @@ -179,76 +276,22 @@ namespace vcpkg::Unicode return utf8_errc::NoError; } - unsigned char code_unit = static_cast(*next_++); - - auto kind = utf8_code_unit_kind(code_unit); - if (kind == Utf8CodeUnitKind::Invalid) - { - *this = sentinel(); - return utf8_errc::InvalidCodeUnit; - } - else if (kind == Utf8CodeUnitKind::Continue) + char32_t code_point; + auto new_next = utf8_decode_code_point(next_, last_, code_point); + if (new_next.second != utf8_errc::NoError) { *this = sentinel(); - return utf8_errc::UnexpectedContinue; + return new_next.second; } - const int count = utf8_code_unit_count(kind); - if (count == 1) + if (utf16_is_trailing_surrogate_code_point(code_point) && utf16_is_leading_surrogate_code_point(current_)) { - current_ = static_cast(code_unit); + *this = sentinel(); + return utf8_errc::PairedSurrogates; } - else - { - // 2 -> 0b0001'1111, 6 - // 3 -> 0b0000'1111, 12 - // 4 -> 0b0000'0111, 18 - const auto start_mask = static_cast(0xFF >> (count + 1)); - const int start_shift = 6 * (count - 1); - auto code_point = static_cast(code_unit & start_mask) << start_shift; - - constexpr unsigned char continue_mask = 0b0011'1111; - for (int byte = 1; byte < count; ++byte) - { - if (next_ == last_) - { - *this = sentinel(); - return utf8_errc::UnexpectedContinue; - } - code_unit = static_cast(*next_++); - - kind = utf8_code_unit_kind(code_unit); - if (kind == Utf8CodeUnitKind::Invalid) - { - *this = sentinel(); - return utf8_errc::InvalidCodeUnit; - } - else if (kind != Utf8CodeUnitKind::Continue) - { - *this = sentinel(); - return utf8_errc::UnexpectedStart; - } - - const int shift = 6 * (count - byte - 1); - code_point |= (code_unit & continue_mask) << shift; - } - if (code_point > 0x10'FFFF) - { - *this = sentinel(); - return utf8_errc::InvalidCodePoint; - } - else if (utf16_is_trailing_surrogate_code_point(code_point) && - utf16_is_leading_surrogate_code_point(current_)) - { - *this = sentinel(); - return utf8_errc::PairedSurrogates; - } - else - { - current_ = code_point; - } - } + next_ = new_next.first; + current_ = code_point; return utf8_errc::NoError; } diff --git a/src/vcpkg/binarycaching.cpp b/src/vcpkg/binarycaching.cpp index 35c60c0619..bc97f4bbc8 100644 --- a/src/vcpkg/binarycaching.cpp +++ b/src/vcpkg/binarycaching.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -38,6 +39,8 @@ namespace "Restored {value} packages from AWS servers in {elapsed}s"); DECLARE_AND_REGISTER_MESSAGE(AwsUploadedPackages, (msg::value), "", "Uploaded binaries to {value} AWS servers"); + using Parse::SourceLoc; + struct ConfigSegmentsParser : Parse::ParserBase { using Parse::ParserBase::ParserBase; @@ -134,10 +137,9 @@ namespace } } - std::vector>> ConfigSegmentsParser:: - parse_all_segments() + std::vector>> ConfigSegmentsParser::parse_all_segments() { - std::vector>> ret; + std::vector>> ret; while (!at_eof()) { std::vector> segments; @@ -182,45 +184,6 @@ namespace Checks::check_exit(VCPKG_LINE_INFO, created_last, "unable to clear path: %s", dir); } - static Command decompress_archive_cmd(const VcpkgPaths& paths, const Path& dst, const Path& archive_path) - { - Command cmd; -#if defined(_WIN32) - auto&& seven_zip_exe = paths.get_tool_exe(Tools::SEVEN_ZIP); - cmd.path_arg(seven_zip_exe) - .string_arg("x") - .path_arg(archive_path) - .string_arg("-o" + dst.native()) - .string_arg("-y"); -#else - (void)paths; - cmd.string_arg("unzip").string_arg("-qq").path_arg(archive_path).string_arg("-d" + dst.native()); -#endif - return cmd; - } - - // Compress the source directory into the destination file. - static void compress_directory(const VcpkgPaths& paths, const Path& source, const Path& destination) - { - auto& fs = paths.get_filesystem(); - fs.remove(destination, VCPKG_LINE_INFO); -#if defined(_WIN32) - auto&& seven_zip_exe = paths.get_tool_exe(Tools::SEVEN_ZIP); - - cmd_execute_and_capture_output( - Command{seven_zip_exe}.string_arg("a").path_arg(destination).path_arg(source / "*"), - get_clean_environment()); -#else - cmd_execute_clean(Command{"zip"} - .string_arg("--quiet") - .string_arg("-y") - .string_arg("-r") - .path_arg(destination) - .string_arg("*"), - InWorkingDirectory{source}); -#endif - } - static Path make_temp_archive_path(const Path& buildtrees, const PackageSpec& spec) { return buildtrees / spec.name() / (spec.triplet().to_string() + ".zip"); @@ -228,11 +191,13 @@ namespace struct ArchivesBinaryProvider : IBinaryProvider { - ArchivesBinaryProvider(std::vector&& read_dirs, + ArchivesBinaryProvider(const VcpkgPaths& paths, + std::vector&& read_dirs, std::vector&& write_dirs, std::vector&& put_url_templates, std::vector&& secrets) - : m_read_dirs(std::move(read_dirs)) + : paths(paths) + , m_read_dirs(std::move(read_dirs)) , m_write_dirs(std::move(write_dirs)) , m_put_url_templates(std::move(put_url_templates)) , m_secrets(std::move(secrets)) @@ -241,9 +206,7 @@ namespace static Path make_archive_subpath(const std::string& abi) { return Path(abi.substr(0, 2)) / (abi + ".zip"); } - void prefetch(const VcpkgPaths& paths, - View actions, - View cache_status) const override + void prefetch(View actions, View cache_status) const override { std::vector to_try_restore_idxs; std::vector to_try_restore; @@ -253,16 +216,17 @@ namespace const auto timer = ElapsedTimer::create_started(); to_try_restore_idxs.clear(); to_try_restore.clear(); - for (size_t idx = 0; idx < actions.size(); ++idx) + for (size_t idx = 0; idx < cache_status.size(); ++idx) { - auto&& action = actions[idx]; - if (action.has_package_abi() && cache_status[idx]->should_attempt_restore(this)) + auto idx_cache_status = cache_status[idx]; + if (idx_cache_status && idx_cache_status->should_attempt_restore(this)) { to_try_restore_idxs.push_back(idx); - to_try_restore.push_back(&action); + to_try_restore.push_back(&actions[idx]); } } - auto results = try_restore_n(paths, to_try_restore, archives_root_dir); + + auto results = try_restore_n(to_try_restore, archives_root_dir); int num_restored = 0; for (size_t n = 0; n < to_try_restore.size(); ++n) { @@ -283,8 +247,7 @@ namespace } } - std::vector try_restore_n(const VcpkgPaths& paths, - View actions, + std::vector try_restore_n(View actions, const Path& archives_root_dir) const { auto& fs = paths.get_filesystem(); @@ -302,14 +265,14 @@ namespace if (fs.exists(archive_path, IgnoreErrors{})) { auto pkg_path = paths.package_dir(spec); - clean_prepare_dir(paths.get_filesystem(), pkg_path); - jobs.push_back(decompress_archive_cmd(paths, pkg_path, archive_path)); + clean_prepare_dir(fs, pkg_path); + jobs.push_back(decompress_zip_archive_cmd(paths, pkg_path, archive_path)); action_idxs.push_back(i); archive_paths.push_back(std::move(archive_path)); } } - auto job_results = cmd_execute_and_capture_output_parallel(jobs, get_clean_environment()); + auto job_results = decompress_in_parallel(jobs); for (size_t j = 0; j < jobs.size(); ++j) { @@ -337,14 +300,14 @@ namespace return results; } - RestoreResult try_restore(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action) const override + RestoreResult try_restore(const Dependencies::InstallPlanAction& action) const override { // Note: this method is almost never called -- it will only be called if another provider promised to // restore a package but then failed at runtime auto p_action = &action; for (const auto& archives_root_dir : m_read_dirs) { - if (try_restore_n(paths, {&p_action, 1}, archives_root_dir)[0] == RestoreResult::restored) + if (try_restore_n({&p_action, 1}, archives_root_dir)[0] == RestoreResult::restored) { print2("Restored from ", archives_root_dir.native(), "\n"); return RestoreResult::restored; @@ -353,7 +316,7 @@ namespace return RestoreResult::unavailable; } - void push_success(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action) const override + void push_success(const Dependencies::InstallPlanAction& action) const override { if (m_write_dirs.empty() && m_put_url_templates.empty()) { @@ -365,7 +328,14 @@ namespace auto& fs = paths.get_filesystem(); const auto archive_subpath = make_archive_subpath(abi_tag); const auto tmp_archive_path = make_temp_archive_path(paths.buildtrees(), spec); - compress_directory(paths, paths.package_dir(spec), tmp_archive_path); + int code = compress_directory_to_zip(paths, paths.package_dir(spec), tmp_archive_path); + if (code != 0) + { + vcpkg::print2( + Color::warning, "Failed to compress folder '", paths.package_dir(spec), "', exit code: ", code); + return; + } + size_t http_remotes_pushed = 0; for (auto&& put_url_template : m_put_url_templates) { @@ -416,21 +386,19 @@ namespace } } - void precheck(const VcpkgPaths& paths, - View actions, - View cache_status) const override + void precheck(View actions, View cache_status) const override { auto& fs = paths.get_filesystem(); for (size_t idx = 0; idx < actions.size(); ++idx) { const auto& action = actions[idx]; - const auto abi_tag = action.package_abi().get(); - if (!abi_tag || !cache_status[idx]->should_attempt_precheck(this)) + const auto& abi_tag = action.package_abi().value_or_exit(VCPKG_LINE_INFO); + if (!cache_status[idx]->should_attempt_precheck(this)) { continue; } - const auto archive_subpath = make_archive_subpath(*abi_tag); + const auto archive_subpath = make_archive_subpath(abi_tag); bool any_available = false; for (auto&& archives_root_dir : m_read_dirs) { @@ -453,6 +421,7 @@ namespace } private: + const VcpkgPaths& paths; std::vector m_read_dirs; std::vector m_write_dirs; std::vector m_put_url_templates; @@ -460,18 +429,19 @@ namespace }; struct HttpGetBinaryProvider : IBinaryProvider { - HttpGetBinaryProvider(std::vector&& url_templates) : m_url_templates(std::move(url_templates)) { } + HttpGetBinaryProvider(const VcpkgPaths& paths, std::vector&& url_templates) + : paths(paths), m_url_templates(std::move(url_templates)) + { + } - RestoreResult try_restore(const VcpkgPaths&, const Dependencies::InstallPlanAction&) const override + RestoreResult try_restore(const Dependencies::InstallPlanAction&) const override { return RestoreResult::unavailable; } - void push_success(const VcpkgPaths&, const Dependencies::InstallPlanAction&) const override { } + void push_success(const Dependencies::InstallPlanAction&) const override { } - void prefetch(const VcpkgPaths& paths, - View actions, - View cache_status) const override + void prefetch(View actions, View cache_status) const override { const auto timer = ElapsedTimer::create_started(); auto& fs = paths.get_filesystem(); @@ -482,18 +452,19 @@ namespace { url_paths.clear(); url_indices.clear(); - for (size_t idx = 0; idx < actions.size(); ++idx) + for (size_t idx = 0; idx < cache_status.size(); ++idx) { - auto&& action = actions[idx]; - auto abi = action.package_abi(); - if (!abi || !cache_status[idx]->should_attempt_restore(this)) + auto this_cache_status = cache_status[idx]; + if (!this_cache_status || !this_cache_status->should_attempt_restore(this)) { continue; } + auto&& action = actions[idx]; clean_prepare_dir(fs, paths.package_dir(action.spec)); - url_paths.emplace_back(Strings::replace_all(url_template, "", *abi.get()), - make_temp_archive_path(paths.buildtrees(), action.spec)); + auto uri = Strings::replace_all( + url_template, "", action.package_abi().value_or_exit(VCPKG_LINE_INFO)); + url_paths.emplace_back(std::move(uri), make_temp_archive_path(paths.buildtrees(), action.spec)); url_indices.push_back(idx); } @@ -509,11 +480,11 @@ namespace if (codes[i] == 200) { action_idxs.push_back(i); - jobs.push_back(decompress_archive_cmd( + jobs.push_back(decompress_zip_archive_cmd( paths, paths.package_dir(actions[url_indices[i]].spec), url_paths[i].second)); } } - auto job_results = cmd_execute_and_capture_output_parallel(jobs, get_clean_environment()); + auto job_results = decompress_in_parallel(jobs); for (size_t j = 0; j < jobs.size(); ++j) { const auto i = action_idxs[j]; @@ -537,9 +508,7 @@ namespace ". Use --debug for more information.\n"); } - void precheck(const VcpkgPaths&, - View actions, - View cache_status) const override + void precheck(View actions, View cache_status) const override { std::vector actions_present{actions.size()}; std::vector urls; @@ -550,13 +519,13 @@ namespace url_indices.clear(); for (size_t idx = 0; idx < actions.size(); ++idx) { - auto abi = actions[idx].package_abi().get(); - if (!abi || !cache_status[idx]->should_attempt_precheck(this)) + const auto& abi = actions[idx].package_abi().value_or_exit(VCPKG_LINE_INFO); + if (!cache_status[idx]->should_attempt_precheck(this)) { continue; } - urls.push_back(Strings::replace_all(std::string(url_template), "", *abi)); + urls.push_back(Strings::replace_all(std::string(url_template), "", abi)); url_indices.push_back(idx); } @@ -586,6 +555,7 @@ namespace } } + const VcpkgPaths& paths; std::vector m_url_templates; }; @@ -602,13 +572,15 @@ namespace struct NugetBinaryProvider : IBinaryProvider { - NugetBinaryProvider(std::vector&& read_sources, + NugetBinaryProvider(const VcpkgPaths& paths, + std::vector&& read_sources, std::vector&& write_sources, std::vector&& read_configs, std::vector&& write_configs, std::string&& timeout, bool interactive) - : m_read_sources(std::move(read_sources)) + : paths(paths) + , m_read_sources(std::move(read_sources)) , m_write_sources(std::move(write_sources)) , m_read_configs(std::move(read_configs)) , m_write_configs(std::move(write_configs)) @@ -693,9 +665,7 @@ namespace fs.write_contents(packages_config, xml.buf, VCPKG_LINE_INFO); } - void prefetch(const VcpkgPaths& paths, - View actions, - View cache_status) const override + void prefetch(View actions, View cache_status) const override { if (m_read_sources.empty() && m_read_configs.empty()) { @@ -706,16 +676,16 @@ namespace auto& fs = paths.get_filesystem(); std::vector attempts; - for (size_t idx = 0; idx < actions.size(); ++idx) + for (size_t idx = 0; idx < cache_status.size(); ++idx) { - auto&& action = actions[idx]; - auto abi = action.package_abi().get(); - if (!abi || !cache_status[idx]->should_attempt_restore(this)) + auto this_cache_status = cache_status[idx]; + if (!this_cache_status || !this_cache_status->should_attempt_restore(this)) { continue; } - auto& spec = action.spec; + const auto& action = actions[idx]; + const auto& spec = action.spec; fs.remove_all(paths.package_dir(spec), VCPKG_LINE_INFO); attempts.push_back({spec, make_nugetref(action, get_nuget_prefix()), idx}); } @@ -841,12 +811,12 @@ namespace ". Use --debug for more information.\n"); } - RestoreResult try_restore(const VcpkgPaths&, const Dependencies::InstallPlanAction&) const override + RestoreResult try_restore(const Dependencies::InstallPlanAction&) const override { return RestoreResult::unavailable; } - void push_success(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action) const override + void push_success(const Dependencies::InstallPlanAction& action) const override { if (m_write_sources.empty() && m_write_configs.empty()) { @@ -857,7 +827,8 @@ namespace NugetReference nuget_ref = make_nugetref(action, get_nuget_prefix()); auto nuspec_path = paths.buildtrees() / spec.name() / (spec.triplet().to_string() + ".nuspec"); - paths.get_filesystem().write_contents( + auto& fs = paths.get_filesystem(); + fs.write_contents( nuspec_path, generate_nuspec(paths.package_dir(spec), action, nuget_ref), VCPKG_LINE_INFO); const auto& nuget_exe = paths.get_tool_exe("nuget"); @@ -940,12 +911,14 @@ namespace } } - paths.get_filesystem().remove(nupkg_path, IgnoreErrors{}); + fs.remove(nupkg_path, IgnoreErrors{}); } - void precheck(const VcpkgPaths&, View, View) const override { } + void precheck(View, View) const override { } private: + const VcpkgPaths& paths; + std::vector m_read_sources; std::vector m_write_sources; @@ -995,8 +968,10 @@ namespace struct GcsBinaryProvider : IBinaryProvider { - GcsBinaryProvider(std::vector&& read_prefixes, std::vector&& write_prefixes) - : m_read_prefixes(std::move(read_prefixes)), m_write_prefixes(std::move(write_prefixes)) + GcsBinaryProvider(const VcpkgPaths& paths, + std::vector&& read_prefixes, + std::vector&& write_prefixes) + : paths(paths), m_read_prefixes(std::move(read_prefixes)), m_write_prefixes(std::move(write_prefixes)) { } @@ -1005,9 +980,7 @@ namespace return Strings::concat(prefix, abi, ".zip"); } - void prefetch(const VcpkgPaths& paths, - View actions, - View cache_status) const override + void prefetch(View actions, View cache_status) const override { auto& fs = paths.get_filesystem(); @@ -1019,17 +992,17 @@ namespace std::vector> url_paths; std::vector url_indices; - for (size_t idx = 0; idx < actions.size(); ++idx) + for (size_t idx = 0; idx < cache_status.size(); ++idx) { - auto&& action = actions[idx]; - auto abi = action.package_abi().get(); - if (!abi || !cache_status[idx]->should_attempt_restore(this)) + const auto this_cache_status = cache_status[idx]; + if (!this_cache_status || !this_cache_status->should_attempt_restore(this)) { continue; } + auto&& action = actions[idx]; clean_prepare_dir(fs, paths.package_dir(action.spec)); - url_paths.emplace_back(make_gcs_path(prefix, *abi), + url_paths.emplace_back(make_gcs_path(prefix, action.package_abi().value_or_exit(VCPKG_LINE_INFO)), make_temp_archive_path(paths.buildtrees(), action.spec)); url_indices.push_back(idx); } @@ -1044,11 +1017,11 @@ namespace auto&& action = actions[url_indices[idx]]; auto&& url_path = url_paths[idx]; if (!gsutil_download_file(url_path.first, url_path.second)) continue; - jobs.push_back(decompress_archive_cmd(paths, paths.package_dir(action.spec), url_path.second)); + jobs.push_back(decompress_zip_archive_cmd(paths, paths.package_dir(action.spec), url_path.second)); idxs.push_back(idx); } - const auto job_results = cmd_execute_and_capture_output_parallel(jobs, get_clean_environment()); + const auto job_results = decompress_in_parallel(jobs); for (size_t j = 0; j < jobs.size(); ++j) { @@ -1073,19 +1046,24 @@ namespace ". Use --debug for more information.\n"); } - RestoreResult try_restore(const VcpkgPaths&, const Dependencies::InstallPlanAction&) const override + RestoreResult try_restore(const Dependencies::InstallPlanAction&) const override { return RestoreResult::unavailable; } - void push_success(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action) const override + void push_success(const Dependencies::InstallPlanAction& action) const override { if (m_write_prefixes.empty()) return; const auto& abi = action.package_abi().value_or_exit(VCPKG_LINE_INFO); auto& spec = action.spec; const auto tmp_archive_path = make_temp_archive_path(paths.buildtrees(), spec); - compress_directory(paths, paths.package_dir(spec), tmp_archive_path); - + int code = compress_directory_to_zip(paths, paths.package_dir(spec), tmp_archive_path); + if (code != 0) + { + vcpkg::print2( + Color::warning, "Failed to compress folder '", paths.package_dir(spec), "', exit code: ", code); + return; + } size_t upload_count = 0; for (const auto& prefix : m_write_prefixes) { @@ -1098,9 +1076,7 @@ namespace print2("Uploaded binaries to ", upload_count, " GCS remotes.\n"); } - void precheck(const VcpkgPaths&, - View actions, - View cache_status) const override + void precheck(View actions, View cache_status) const override { std::vector actions_availability{actions.size()}; for (const auto& prefix : m_read_prefixes) @@ -1108,13 +1084,13 @@ namespace for (size_t idx = 0; idx < actions.size(); ++idx) { auto&& action = actions[idx]; - const auto abi = action.package_abi().get(); - if (!abi || !cache_status[idx]->should_attempt_precheck(this)) + const auto& abi = action.package_abi().value_or_exit(VCPKG_LINE_INFO); + if (!cache_status[idx]->should_attempt_precheck(this)) { continue; } - if (gsutil_stat(make_gcs_path(prefix, *abi))) + if (gsutil_stat(make_gcs_path(prefix, abi))) { actions_availability[idx] = CacheAvailability::available; cache_status[idx]->mark_available(this); @@ -1133,6 +1109,8 @@ namespace } private: + const VcpkgPaths& paths; + std::vector m_read_prefixes; std::vector m_write_prefixes; }; @@ -1177,8 +1155,10 @@ namespace struct AwsBinaryProvider : IBinaryProvider { - AwsBinaryProvider(std::vector&& read_prefixes, std::vector&& write_prefixes) - : m_read_prefixes(std::move(read_prefixes)), m_write_prefixes(std::move(write_prefixes)) + AwsBinaryProvider(const VcpkgPaths& paths, + std::vector&& read_prefixes, + std::vector&& write_prefixes) + : paths(paths), m_read_prefixes(std::move(read_prefixes)), m_write_prefixes(std::move(write_prefixes)) { } @@ -1187,9 +1167,7 @@ namespace return Strings::concat(prefix, abi, ".zip"); } - void prefetch(const VcpkgPaths& paths, - View actions, - View cache_status) const override + void prefetch(View actions, View cache_status) const override { auto& fs = paths.get_filesystem(); @@ -1201,17 +1179,17 @@ namespace std::vector> url_paths; std::vector url_indices; - for (size_t idx = 0; idx < actions.size(); ++idx) + for (size_t idx = 0; idx < cache_status.size(); ++idx) { - auto&& action = actions[idx]; - auto abi = action.package_abi().get(); - if (!abi || !cache_status[idx]->should_attempt_restore(this)) + const auto this_cache_status = cache_status[idx]; + if (!this_cache_status || !this_cache_status->should_attempt_restore(this)) { continue; } + auto&& action = actions[idx]; clean_prepare_dir(fs, paths.package_dir(action.spec)); - url_paths.emplace_back(make_aws_path(prefix, *abi), + url_paths.emplace_back(make_aws_path(prefix, action.package_abi().value_or_exit(VCPKG_LINE_INFO)), make_temp_archive_path(paths.buildtrees(), action.spec)); url_indices.push_back(idx); } @@ -1227,7 +1205,7 @@ namespace auto&& action = actions[url_indices[idx]]; auto&& url_path = url_paths[idx]; if (!awscli_download_file(paths, url_path.first, url_path.second)) continue; - jobs.push_back(decompress_archive_cmd(paths, paths.package_dir(action.spec), url_path.second)); + jobs.push_back(decompress_zip_archive_cmd(paths, paths.package_dir(action.spec), url_path.second)); idxs.push_back(idx); } @@ -1254,18 +1232,24 @@ namespace msg::elapsed = timer.elapsed().as().count()); } - RestoreResult try_restore(const VcpkgPaths&, const Dependencies::InstallPlanAction&) const override + RestoreResult try_restore(const Dependencies::InstallPlanAction&) const override { return RestoreResult::unavailable; } - void push_success(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action) const override + void push_success(const Dependencies::InstallPlanAction& action) const override { if (m_write_prefixes.empty()) return; const auto& abi = action.package_abi().value_or_exit(VCPKG_LINE_INFO); auto& spec = action.spec; const auto tmp_archive_path = make_temp_archive_path(paths.buildtrees(), spec); - compress_directory(paths, paths.package_dir(spec), tmp_archive_path); + int code = compress_directory_to_zip(paths, paths.package_dir(spec), tmp_archive_path); + if (code != 0) + { + vcpkg::print2( + Color::warning, "Failed to compress folder '", paths.package_dir(spec), "', exit code: ", code); + return; + } size_t upload_count = 0; for (const auto& prefix : m_write_prefixes) @@ -1279,9 +1263,7 @@ namespace msg::println(msgAwsUploadedPackages, msg::value = upload_count); } - void precheck(const VcpkgPaths& paths, - View actions, - View cache_status) const override + void precheck(View actions, View cache_status) const override { std::vector actions_availability{actions.size()}; for (const auto& prefix : m_read_prefixes) @@ -1289,13 +1271,13 @@ namespace for (size_t idx = 0; idx < actions.size(); ++idx) { auto&& action = actions[idx]; - const auto abi = action.package_abi().get(); - if (!abi || !cache_status[idx]->should_attempt_precheck(this)) + const auto& abi = action.package_abi().value_or_exit(VCPKG_LINE_INFO); + if (!cache_status[idx]->should_attempt_precheck(this)) { continue; } - if (awscli_stat(paths, make_aws_path(prefix, *abi))) + if (awscli_stat(paths, make_aws_path(prefix, abi))) { actions_availability[idx] = CacheAvailability::available; cache_status[idx]->mark_available(this); @@ -1314,6 +1296,8 @@ namespace } private: + const VcpkgPaths& paths; + std::vector m_read_prefixes; std::vector m_write_prefixes; }; @@ -1321,7 +1305,10 @@ namespace namespace vcpkg { - BinaryCache::BinaryCache(const VcpkgCmdArguments& args) { install_providers_for(args); } + BinaryCache::BinaryCache(const VcpkgCmdArguments& args, const VcpkgPaths& paths) + { + install_providers_for(args, paths); + } void BinaryCache::install_providers(std::vector>&& providers) { @@ -1339,19 +1326,21 @@ namespace vcpkg } } - void BinaryCache::install_providers_for(const VcpkgCmdArguments& args) + void BinaryCache::install_providers_for(const VcpkgCmdArguments& args, const VcpkgPaths& paths) { if (args.binary_caching_enabled()) { - install_providers(create_binary_providers_from_configs(args.binary_sources).value_or_exit(VCPKG_LINE_INFO)); + install_providers( + create_binary_providers_from_configs(paths, args.binary_sources).value_or_exit(VCPKG_LINE_INFO)); } } - RestoreResult BinaryCache::try_restore(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action) + RestoreResult BinaryCache::try_restore(const Dependencies::InstallPlanAction& action) { const auto abi = action.package_abi().get(); if (!abi) { + // e.g. this is a `--head` package return RestoreResult::unavailable; } @@ -1364,7 +1353,7 @@ namespace vcpkg const auto available = cache_status.get_available_provider(); if (available) { - switch (available->try_restore(paths, action)) + switch (available->try_restore(action)) { case RestoreResult::unavailable: // Even though that provider thought it had it, it didn't; perhaps @@ -1388,7 +1377,7 @@ namespace vcpkg break; } - switch (provider->try_restore(paths, action)) + switch (provider->try_restore(action)) { case RestoreResult::restored: cache_status.mark_restored(); return RestoreResult::restored; case RestoreResult::unavailable: cache_status.mark_unavailable(provider.get()); break; @@ -1399,42 +1388,35 @@ namespace vcpkg return RestoreResult::unavailable; } - void BinaryCache::push_success(const VcpkgPaths& paths, const Dependencies::InstallPlanAction& action) + void BinaryCache::push_success(const Dependencies::InstallPlanAction& action) { const auto abi = action.package_abi().get(); if (abi) { for (auto&& provider : m_providers) { - provider->push_success(paths, action); + provider->push_success(action); } m_status[*abi].mark_restored(); } } - static std::vector build_cache_status_vector(View actions, - std::unordered_map& status) + void BinaryCache::prefetch(View actions) { - std::vector results{actions.size()}; + std::vector cache_status{actions.size()}; for (size_t idx = 0; idx < actions.size(); ++idx) { const auto abi = actions[idx].package_abi().get(); if (abi) { - results[idx] = &status[*abi]; + cache_status[idx] = &m_status[*abi]; } } - return results; - } - - void BinaryCache::prefetch(const VcpkgPaths& paths, View actions) - { - auto cache_status = build_cache_status_vector(actions, m_status); for (auto&& provider : m_providers) { - provider->prefetch(paths, actions, cache_status); + provider->prefetch(actions, cache_status); for (auto status : cache_status) { if (status) @@ -1445,13 +1427,23 @@ namespace vcpkg } } - std::vector BinaryCache::precheck(const VcpkgPaths& paths, - View actions) + std::vector BinaryCache::precheck(View actions) { - auto cache_status = build_cache_status_vector(actions, m_status); + std::vector cache_status{actions.size()}; + for (size_t idx = 0; idx < actions.size(); ++idx) + { + auto& action = actions[idx]; + const auto abi = action.package_abi().get(); + Checks::check_exit(VCPKG_LINE_INFO, + abi, + "Error: package %s did not have an abi during ci. This is an internal error.\n", + action.spec); + cache_status[idx] = &m_status[*abi]; + } + for (auto&& provider : m_providers) { - provider->precheck(paths, actions, cache_status); + provider->precheck(actions, cache_status); } std::vector results{actions.size()}; @@ -1551,6 +1543,26 @@ namespace vcpkg } } + void BinaryConfigParserState::clear() + { + m_cleared = true; + interactive = false; + nugettimeout = "100"; + archives_to_read.clear(); + archives_to_write.clear(); + url_templates_to_get.clear(); + azblob_templates_to_put.clear(); + gcs_read_prefixes.clear(); + gcs_write_prefixes.clear(); + aws_read_prefixes.clear(); + aws_write_prefixes.clear(); + sources_to_read.clear(); + sources_to_write.clear(); + configs_to_read.clear(); + configs_to_write.clear(); + secrets.clear(); + } + const ExpectedS& default_cache_path() { static auto cachepath = get_platform_cache_home().then([](Path p) -> ExpectedS { @@ -1589,65 +1601,18 @@ namespace vcpkg }); return cachepath; } - } + namespace { - struct State - { - bool m_cleared = false; - bool interactive = false; - std::string nugettimeout = "100"; - - std::vector archives_to_read; - std::vector archives_to_write; - - std::vector url_templates_to_get; - std::vector azblob_templates_to_put; - - std::vector gcs_read_prefixes; - std::vector gcs_write_prefixes; - - std::vector aws_read_prefixes; - std::vector aws_write_prefixes; - - std::vector sources_to_read; - std::vector sources_to_write; - - std::vector configs_to_read; - std::vector configs_to_write; - - std::vector secrets; - - void clear() - { - m_cleared = true; - interactive = false; - nugettimeout = "100"; - archives_to_read.clear(); - archives_to_write.clear(); - url_templates_to_get.clear(); - azblob_templates_to_put.clear(); - gcs_read_prefixes.clear(); - gcs_write_prefixes.clear(); - aws_read_prefixes.clear(); - aws_write_prefixes.clear(); - sources_to_read.clear(); - sources_to_write.clear(); - configs_to_read.clear(); - configs_to_write.clear(); - secrets.clear(); - } - }; - struct BinaryConfigParser : ConfigSegmentsParser { - BinaryConfigParser(StringView text, StringView origin, State* state) + BinaryConfigParser(StringView text, StringView origin, BinaryConfigParserState* state) : ConfigSegmentsParser(text, origin), state(state) { } - State* state; + BinaryConfigParserState* state; void parse() { @@ -2084,28 +2049,8 @@ ExpectedS vcpkg::parse_download_configuration(const Optio s.script}; } -ExpectedS>> vcpkg::create_binary_providers_from_configs( - View args) -{ - std::string env_string = get_environment_variable("VCPKG_BINARY_SOURCES").value_or(""); - if (Debug::g_debugging) - { - const auto& cachepath = default_cache_path(); - if (cachepath.has_value()) - { - Debug::print("Default binary cache path is: ", cachepath.value_or_exit(VCPKG_LINE_INFO), '\n'); - } - else - { - Debug::print("No binary cache path. Reason: ", cachepath.error(), '\n'); - } - } - - return create_binary_providers_from_configs_pure(env_string, args); -} - -ExpectedS>> vcpkg::create_binary_providers_from_configs_pure( - const std::string& env_string, View args) +ExpectedS vcpkg::create_binary_providers_from_configs_pure(const std::string& env_string, + View args) { { LockGuardPtr metrics(g_metrics); @@ -2120,7 +2065,7 @@ ExpectedS>> vcpkg::create_binary_pr } } - State s; + BinaryConfigParserState s; BinaryConfigParser default_parser("default,readwrite", "", &s); default_parser.parse(); @@ -2151,22 +2096,50 @@ ExpectedS>> vcpkg::create_binary_pr LockGuardPtr(g_metrics)->track_property("binarycaching-clear", "defined"); } + return s; +} + +ExpectedS>> vcpkg::create_binary_providers_from_configs( + const VcpkgPaths& paths, View args) +{ + std::string env_string = get_environment_variable("VCPKG_BINARY_SOURCES").value_or(""); + if (Debug::g_debugging) + { + const auto& cachepath = default_cache_path(); + if (cachepath.has_value()) + { + Debug::print("Default binary cache path is: ", cachepath.value_or_exit(VCPKG_LINE_INFO), '\n'); + } + else + { + Debug::print("No binary cache path. Reason: ", cachepath.error(), '\n'); + } + } + + auto sRawHolder = create_binary_providers_from_configs_pure(env_string, args); + if (!sRawHolder.has_value()) + { + return sRawHolder.error(); + } + + auto& s = sRawHolder.value_or_exit(VCPKG_LINE_INFO); std::vector> providers; if (!s.gcs_read_prefixes.empty() || !s.gcs_write_prefixes.empty()) { - providers.push_back( - std::make_unique(std::move(s.gcs_read_prefixes), std::move(s.gcs_write_prefixes))); + providers.push_back(std::make_unique( + paths, std::move(s.gcs_read_prefixes), std::move(s.gcs_write_prefixes))); } if (!s.aws_read_prefixes.empty() || !s.aws_write_prefixes.empty()) { - providers.push_back( - std::make_unique(std::move(s.aws_read_prefixes), std::move(s.aws_write_prefixes))); + providers.push_back(std::make_unique( + paths, std::move(s.aws_read_prefixes), std::move(s.aws_write_prefixes))); } if (!s.archives_to_read.empty() || !s.archives_to_write.empty() || !s.azblob_templates_to_put.empty()) { - providers.push_back(std::make_unique(std::move(s.archives_to_read), + providers.push_back(std::make_unique(paths, + std::move(s.archives_to_read), std::move(s.archives_to_write), std::move(s.azblob_templates_to_put), std::move(s.secrets))); @@ -2175,14 +2148,15 @@ ExpectedS>> vcpkg::create_binary_pr if (!s.url_templates_to_get.empty()) { LockGuardPtr(g_metrics)->track_property("binarycaching-url-get", "defined"); - providers.push_back(std::make_unique(std::move(s.url_templates_to_get))); + providers.push_back(std::make_unique(paths, std::move(s.url_templates_to_get))); } if (!s.sources_to_read.empty() || !s.sources_to_write.empty() || !s.configs_to_read.empty() || !s.configs_to_write.empty()) { LockGuardPtr(g_metrics)->track_property("binarycaching-nuget", "defined"); - providers.push_back(std::make_unique(std::move(s.sources_to_read), + providers.push_back(std::make_unique(paths, + std::move(s.sources_to_read), std::move(s.sources_to_write), std::move(s.configs_to_read), std::move(s.configs_to_write), @@ -2255,7 +2229,7 @@ std::string vcpkg::generate_nuspec(const Path& package_dir, { auto& spec = action.spec; auto& scf = *action.source_control_file_and_location.value_or_exit(VCPKG_LINE_INFO).source_control_file; - auto& version = scf.core_paragraph->version; + auto& version = scf.core_paragraph->raw_version; const auto& abi_info = action.abi_info.value_or_exit(VCPKG_LINE_INFO); const auto& compiler_info = abi_info.compiler_info.value_or_exit(VCPKG_LINE_INFO); std::string description = diff --git a/src/vcpkg/binaryparagraph.cpp b/src/vcpkg/binaryparagraph.cpp index 1a4974adcd..4dd380f638 100644 --- a/src/vcpkg/binaryparagraph.cpp +++ b/src/vcpkg/binaryparagraph.cpp @@ -108,7 +108,7 @@ namespace vcpkg const std::string& abi_tag, const std::vector& deps) : spec(spgh.name, triplet) - , version(spgh.version) + , version(spgh.raw_version) , port_version(spgh.port_version) , description(spgh.description) , maintainers(spgh.maintainers) diff --git a/src/vcpkg/build.cpp b/src/vcpkg/build.cpp index 46787a0fcc..1b253dcffc 100644 --- a/src/vcpkg/build.cpp +++ b/src/vcpkg/build.cpp @@ -183,7 +183,7 @@ namespace vcpkg::Build const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE); std::string first_arg = args.command_arguments[0]; - BinaryCache binary_cache{args}; + BinaryCache binary_cache{args, paths}; const FullPackageSpec spec = Input::check_and_get_full_package_spec( std::move(first_arg), default_triplet, COMMAND_STRUCTURE.example_text, paths); @@ -1080,6 +1080,10 @@ namespace vcpkg::Build size_t port_file_count = 0; for (auto& port_file : fs.get_regular_files_recursive(port_dir, VCPKG_LINE_INFO)) { + if (port_file.filename() == ".DS_Store") + { + continue; + } abi_tag_entries.emplace_back( port_file.filename(), vcpkg::Hash::get_file_hash(VCPKG_LINE_INFO, fs, port_file, Hash::Algorithm::Sha256)); @@ -1112,8 +1116,21 @@ namespace vcpkg::Build abi_tag_entries.emplace_back("ports.cmake", paths.get_ports_cmake_hash().to_string()); abi_tag_entries.emplace_back("post_build_checks", "2"); - std::vector sorted_feature_list = action.feature_list; - Util::sort(sorted_feature_list); + InternalFeatureSet sorted_feature_list = action.feature_list; + // Check that no "default" feature is present. Default features must be resolved before attempting to calculate + // a package ABI, so the "default" should not have made it here. + static constexpr auto default_literal = StringLiteral{"default"}; + const bool has_no_pseudo_features = std::none_of( + sorted_feature_list.begin(), sorted_feature_list.end(), [](StringView s) { return s == default_literal; }); + Checks::check_exit(VCPKG_LINE_INFO, has_no_pseudo_features); + Util::sort_unique_erase(sorted_feature_list); + + // Check that the "core" feature is present. After resolution into InternalFeatureSet "core" meaning "not + // default" should have already been handled so "core" should be here. + Checks::check_exit( + VCPKG_LINE_INFO, + std::binary_search(sorted_feature_list.begin(), sorted_feature_list.end(), StringLiteral{"core"})); + abi_tag_entries.emplace_back("features", Strings::join(";", sorted_feature_list)); Util::sort(abi_tag_entries); @@ -1290,7 +1307,7 @@ namespace vcpkg::Build if (result.code == BuildResult::SUCCEEDED) { - binary_cache.push_success(paths, action); + binary_cache.push_success(action); } return result; @@ -1339,7 +1356,7 @@ namespace vcpkg::Build std::string package = action.displayname(); if (auto scfl = action.source_control_file_and_location.get()) { - Strings::append(package, " -> ", scfl->to_versiont()); + Strings::append(package, " -> ", scfl->to_version()); } return Strings::format("Please ensure you're using the latest portfiles with `git pull` and `%s update`.\n" "Then check for known issues at:\n" diff --git a/src/vcpkg/commands.add-version.cpp b/src/vcpkg/commands.add-version.cpp index 3447ec8af7..9ff54429cc 100644 --- a/src/vcpkg/commands.add-version.cpp +++ b/src/vcpkg/commands.add-version.cpp @@ -25,7 +25,7 @@ namespace using VersionGitTree = std::pair; - void insert_version_to_json_object(Json::Object& obj, const VersionT& version, StringLiteral version_field) + void insert_version_to_json_object(Json::Object& obj, const Version& version, StringLiteral version_field) { obj.insert(version_field, Json::Value::string(version.text())); obj.insert("port-version", Json::Value::integer(version.port_version())); @@ -33,29 +33,29 @@ namespace void insert_schemed_version_to_json_object(Json::Object& obj, const SchemedVersion& version) { - if (version.scheme == Versions::Scheme::Relaxed) + if (version.scheme == VersionScheme::Relaxed) { - return insert_version_to_json_object(obj, version.versiont, VERSION_RELAXED); + return insert_version_to_json_object(obj, version.version, VERSION_RELAXED); } - if (version.scheme == Versions::Scheme::Semver) + if (version.scheme == VersionScheme::Semver) { - return insert_version_to_json_object(obj, version.versiont, VERSION_SEMVER); + return insert_version_to_json_object(obj, version.version, VERSION_SEMVER); } - if (version.scheme == Versions::Scheme::Date) + if (version.scheme == VersionScheme::Date) { - return insert_version_to_json_object(obj, version.versiont, VERSION_DATE); + return insert_version_to_json_object(obj, version.version, VERSION_DATE); } - if (version.scheme == Versions::Scheme::String) + if (version.scheme == VersionScheme::String) { - return insert_version_to_json_object(obj, version.versiont, VERSION_STRING); + return insert_version_to_json_object(obj, version.version, VERSION_STRING); } Checks::unreachable(VCPKG_LINE_INFO); } - static Json::Object serialize_baseline(const std::map>& baseline) + static Json::Object serialize_baseline(const std::map>& baseline) { Json::Object port_entries_obj; for (auto&& kv_pair : baseline) @@ -87,7 +87,7 @@ namespace } static void write_baseline_file(Filesystem& fs, - const std::map>& baseline_map, + const std::map>& baseline_map, const Path& output_path) { auto new_path = output_path + ".tmp"; @@ -113,9 +113,9 @@ namespace static void update_baseline_version(const VcpkgPaths& paths, const std::string& port_name, - const VersionT& version, + const Version& version, const Path& baseline_path, - std::map>& baseline_map, + std::map>& baseline_map, bool print_success) { auto& fs = paths.get_filesystem(); @@ -149,7 +149,7 @@ namespace static void update_version_db_file(const VcpkgPaths& paths, const std::string& port_name, - const SchemedVersion& version, + const SchemedVersion& port_version, const std::string& git_tree, const Path& version_db_file_path, bool overwrite_version, @@ -159,12 +159,14 @@ namespace auto& fs = paths.get_filesystem(); if (!fs.exists(version_db_file_path, VCPKG_LINE_INFO)) { - std::vector new_entry{{version, git_tree}}; + std::vector new_entry{{port_version, git_tree}}; write_versions_file(fs, new_entry, version_db_file_path); if (print_success) { - vcpkg::printf( - Color::success, "Added version `%s` to `%s` (new file).\n", version.versiont, version_db_file_path); + vcpkg::printf(Color::success, + "Added version `%s` to `%s` (new file).\n", + port_version.version, + version_db_file_path); } return; } @@ -178,13 +180,13 @@ namespace versions->begin(), versions_end, [&](auto&& entry) -> bool { return entry.second == git_tree; }); if (found_same_sha != versions_end) { - if (found_same_sha->first.versiont == version.versiont) + if (found_same_sha->first.version == port_version.version) { if (print_success) { vcpkg::printf(Color::success, "Version `%s` is already in `%s`\n", - version.versiont, + port_version.version, version_db_file_path); } return; @@ -194,16 +196,17 @@ namespace "-- SHA: %s\n" "-- Did you remember to commit your changes?\n" "***No files were updated.***\n", - found_same_sha->first.versiont, + found_same_sha->first.version, version_db_file_path, git_tree); if (keep_going) return; Checks::exit_fail(VCPKG_LINE_INFO); } - auto it = std::find_if(versions->begin(), versions_end, [&](auto&& entry) -> bool { - return entry.first.versiont == version.versiont; - }); + auto it = std::find_if( + versions->begin(), versions_end, [&](const std::pair& entry) -> bool { + return entry.first.version == port_version.version; + }); if (it != versions_end) { @@ -218,25 +221,26 @@ namespace "-- Pass `--overwrite-version` to bypass this check.\n" "***No files were updated.***\n", port_name, - version.versiont, + port_version.version, it->second, git_tree); if (keep_going) return; Checks::exit_fail(VCPKG_LINE_INFO); } - it->first = version; + it->first = port_version; it->second = git_tree; } else { - versions->insert(versions->begin(), std::make_pair(version, git_tree)); + versions->insert(versions->begin(), std::make_pair(port_version, git_tree)); } write_versions_file(fs, *versions, version_db_file_path); if (print_success) { - vcpkg::printf(Color::success, "Added version `%s` to `%s`.\n", version.versiont, version_db_file_path); + vcpkg::printf( + Color::success, "Added version `%s` to `%s`.\n", port_version.version, version_db_file_path); } return; } @@ -314,10 +318,10 @@ namespace vcpkg::Commands::AddVersion } } - auto baseline_map = [&]() -> std::map> { + auto baseline_map = [&]() -> std::map> { if (!fs.exists(baseline_path, VCPKG_LINE_INFO)) { - std::map> ret; + std::map> ret; return ret; } auto maybe_baseline_map = vcpkg::get_builtin_baseline(paths); @@ -381,7 +385,7 @@ namespace vcpkg::Commands::AddVersion auto port_versions_path = paths.builtin_registry_versions / prefix / Strings::concat(port_name, ".json"); update_version_db_file( paths, port_name, schemed_version, git_tree, port_versions_path, overwrite_version, verbose, add_all); - update_baseline_version(paths, port_name, schemed_version.versiont, baseline_path, baseline_map, verbose); + update_baseline_version(paths, port_name, schemed_version.version, baseline_path, baseline_map, verbose); } Checks::exit_success(VCPKG_LINE_INFO); } diff --git a/src/vcpkg/commands.buildexternal.cpp b/src/vcpkg/commands.buildexternal.cpp index 978c92fbbf..fb69c12c51 100644 --- a/src/vcpkg/commands.buildexternal.cpp +++ b/src/vcpkg/commands.buildexternal.cpp @@ -24,7 +24,7 @@ namespace vcpkg::Commands::BuildExternal { const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE); - BinaryCache binary_cache{args}; + BinaryCache binary_cache{args, paths}; const FullPackageSpec spec = Input::check_and_get_full_package_spec( std::string(args.command_arguments.at(0)), default_triplet, COMMAND_STRUCTURE.example_text, paths); diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index 63845d82ea..5efb217525 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -481,7 +482,7 @@ namespace vcpkg::Commands::CI const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE); const auto& settings = options.settings; - BinaryCache binary_cache{args}; + BinaryCache binary_cache{args, paths}; Triplet target_triplet = Triplet::from_canonical_name(std::string(args.command_arguments[0])); ExclusionPredicate is_excluded{ parse_exclusions(settings, OPTION_EXCLUDE), @@ -517,8 +518,6 @@ namespace vcpkg::Commands::CI XunitTestResults xunitTestResults; - std::vector all_ports = - Util::fmap(provider.load_all_control_files(), Paragraphs::get_name_of_control_file); std::vector results; auto timer = ElapsedTimer::create_started(); @@ -526,9 +525,16 @@ namespace vcpkg::Commands::CI xunitTestResults.push_collection(target_triplet.canonical_name()); - std::vector specs = PackageSpec::to_package_specs(all_ports, target_triplet); + std::vector all_port_names = + Util::fmap(provider.load_all_control_files(), Paragraphs::get_name_of_control_file); // Install the default features for every package - auto all_default_full_specs = Util::fmap(specs, [&](auto& spec) { return FullPackageSpec{spec, {"default"}}; }); + std::vector all_default_full_specs; + all_default_full_specs.reserve(all_port_names.size()); + for (auto&& port_name : all_port_names) + { + all_default_full_specs.emplace_back(PackageSpec{std::move(port_name), target_triplet}, + InternalFeatureSet{"core", "default"}); + } Dependencies::CreateInstallPlanOptions serialize_options(host_triplet, Dependencies::UnsupportedPortAction::Warn); @@ -551,7 +557,7 @@ namespace vcpkg::Commands::CI } auto action_plan = compute_full_plan(paths, provider, var_provider, all_default_full_specs, serialize_options); - const auto precheck_results = binary_cache.precheck(paths, action_plan.install_actions); + const auto precheck_results = binary_cache.precheck(action_plan.install_actions); auto split_specs = compute_action_statuses(is_excluded, var_provider, precheck_results, action_plan); { diff --git a/src/vcpkg/commands.civerifyversions.cpp b/src/vcpkg/commands.civerifyversions.cpp index e235098527..ba9fa22938 100644 --- a/src/vcpkg/commands.civerifyversions.cpp +++ b/src/vcpkg/commands.civerifyversions.cpp @@ -16,14 +16,14 @@ namespace { using namespace vcpkg; - std::string get_scheme_name(Versions::Scheme scheme) + std::string get_scheme_name(VersionScheme scheme) { switch (scheme) { - case Versions::Scheme::Relaxed: return "version"; - case Versions::Scheme::Semver: return "version-semver"; - case Versions::Scheme::String: return "version-string"; - case Versions::Scheme::Date: return "version-date"; + case VersionScheme::Relaxed: return "version"; + case VersionScheme::Semver: return "version-semver"; + case VersionScheme::String: return "version-string"; + case VersionScheme::Date: return "version-date"; default: Checks::unreachable(VCPKG_LINE_INFO); } } @@ -53,7 +53,7 @@ namespace vcpkg::Commands::CIVerifyVersions }; static ExpectedS verify_version_in_db(const VcpkgPaths& paths, - const std::map> baseline, + const std::map> baseline, StringView port_name, const Path& port_path, const Path& versions_file_path, @@ -107,7 +107,7 @@ namespace vcpkg::Commands::CIVerifyVersions " Found the following error(s):\n%s", port_name, versions_file_path, - version_entry.first.versiont, + version_entry.first.version, treeish, maybe_scf.error()->error), expected_right_tag, @@ -116,7 +116,7 @@ namespace vcpkg::Commands::CIVerifyVersions const auto& scf = maybe_scf.value_or_exit(VCPKG_LINE_INFO); auto&& git_tree_version = scf.get()->to_schemed_version(); - if (version_entry.first.versiont != git_tree_version.versiont) + if (version_entry.first.version != git_tree_version.version) { return { Strings::format( @@ -126,8 +126,8 @@ namespace vcpkg::Commands::CIVerifyVersions " Checked out Git SHA: %s", port_name, versions_file_path, - version_entry.first.versiont, - git_tree_version.versiont, + version_entry.first.version, + git_tree_version.version, version_entry.second), expected_right_tag, }; @@ -146,7 +146,7 @@ namespace vcpkg::Commands::CIVerifyVersions " Checked out Git SHA: %s", port_name, versions_file_path, - version_entry.first.versiont, + version_entry.first.version, version_entry.second), expected_right_tag, }; @@ -169,9 +169,10 @@ namespace vcpkg::Commands::CIVerifyVersions const auto local_port_version = maybe_scf.value_or_exit(VCPKG_LINE_INFO)->to_schemed_version(); auto versions_end = versions.end(); - auto it = std::find_if(versions.begin(), versions_end, [&](auto&& entry) { - return entry.first.versiont == local_port_version.versiont; - }); + auto it = + std::find_if(versions.begin(), versions_end, [&](const std::pair& entry) { + return entry.first.version == local_port_version.version; + }); if (it == versions_end) { return { @@ -182,7 +183,7 @@ namespace vcpkg::Commands::CIVerifyVersions " to add the new port version.", port_name, versions_file_path, - local_port_version.versiont, + local_port_version.version, port_name), expected_right_tag, }; @@ -201,7 +202,7 @@ namespace vcpkg::Commands::CIVerifyVersions " to overwrite the declared version's scheme.", port_name, versions_file_path, - entry.first.versiont, + entry.first.version, get_scheme_name(entry.first.scheme), get_scheme_name(local_port_version.scheme), port_name), @@ -222,7 +223,7 @@ namespace vcpkg::Commands::CIVerifyVersions " to add a new version.", port_name, versions_file_path, - entry.first.versiont, + entry.first.version, entry.second, local_git_tree, port_name), @@ -243,13 +244,13 @@ namespace vcpkg::Commands::CIVerifyVersions " to set version %s as the baseline version.", port_name, port_name, - local_port_version.versiont), + local_port_version.version), expected_right_tag, }; } auto&& baseline_version = maybe_baseline->second; - if (baseline_version != entry.first.versiont) + if (baseline_version != entry.first.version) { return { Strings::format("Error: While reading baseline version for port %s.\n" @@ -264,14 +265,14 @@ namespace vcpkg::Commands::CIVerifyVersions port_name, versions_file_path, baseline_version, - entry.first.versiont, + entry.first.version, port_name), expected_right_tag, }; } return { - Strings::format("OK: %s\t%s -> %s\n", entry.second, port_name, entry.first.versiont), + Strings::format("OK: %s\t%s -> %s\n", entry.second, port_name, entry.first.version), expected_left_tag, }; } diff --git a/src/vcpkg/commands.find.cpp b/src/vcpkg/commands.find.cpp index 19d874c1f7..da96e2dafc 100644 --- a/src/vcpkg/commands.find.cpp +++ b/src/vcpkg/commands.find.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include using namespace vcpkg; using vcpkg::PortFileProvider::PathsPortFileProvider; @@ -25,7 +25,7 @@ namespace auto& source_paragraph = scf->core_paragraph; Json::Object& library_obj = obj.insert(source_paragraph->name, Json::Object()); library_obj.insert("package_name", Json::Value::string(source_paragraph->name)); - library_obj.insert("version", Json::Value::string(source_paragraph->version)); + library_obj.insert("version", Json::Value::string(source_paragraph->raw_version)); library_obj.insert("port_version", Json::Value::integer(source_paragraph->port_version)); Json::Array& desc = library_obj.insert("description", Json::Array()); for (const auto& line : source_paragraph->description) @@ -39,7 +39,7 @@ namespace constexpr const int s_name_and_ver_columns = 41; void do_print(const SourceParagraph& source_paragraph, bool full_desc) { - auto full_version = VersionT(source_paragraph.version, source_paragraph.port_version).to_string(); + auto full_version = Version(source_paragraph.raw_version, source_paragraph.port_version).to_string(); if (full_desc) { vcpkg::printf("%-20s %-16s %s\n", diff --git a/src/vcpkg/commands.generate-message-map.cpp b/src/vcpkg/commands.generate-message-map.cpp index edec7d7889..dbdeb3f6ec 100644 --- a/src/vcpkg/commands.generate-message-map.cpp +++ b/src/vcpkg/commands.generate-message-map.cpp @@ -6,8 +6,19 @@ namespace vcpkg::Commands { using namespace msg; - void GenerateDefaultMessageMapCommand::perform_and_exit(const VcpkgCmdArguments&, Filesystem&) const + + const CommandStructure COMMAND_STRUCTURE = { + create_example_string(R"###(x-generate-default-message-map locales/messages.json)###"), + 0, + 1, + {{}, {}, {}}, + nullptr, + }; + + void GenerateDefaultMessageMapCommand::perform_and_exit(const VcpkgCmdArguments& args, Filesystem& fs) const { + auto parsed_args = args.parse_arguments(COMMAND_STRUCTURE); + // in order to implement sorting, we create a vector of messages before converting into a JSON object struct Message { @@ -39,7 +50,17 @@ namespace vcpkg::Commands obj.insert(fmt::format("_{}.comment", msg.name), Json::Value::string(std::move(msg.comment))); } } - msg::write_unlocalized_text_to_stdout(Color::none, Json::stringify(obj, {})); + + auto stringified = Json::stringify(obj, {}); + if (args.command_arguments.size() == 0) + { + msg::write_unlocalized_text_to_stdout(Color::none, stringified); + } + else + { + Path filepath = fs.current_path(VCPKG_LINE_INFO) / args.command_arguments[0]; + fs.write_contents(filepath, stringified, VCPKG_LINE_INFO); + } Checks::exit_success(VCPKG_LINE_INFO); } } diff --git a/src/vcpkg/commands.info.cpp b/src/vcpkg/commands.info.cpp index 1112609698..7bd7a83b9d 100644 --- a/src/vcpkg/commands.info.cpp +++ b/src/vcpkg/commands.info.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include namespace vcpkg::Commands::Info { diff --git a/src/vcpkg/commands.integrate.cpp b/src/vcpkg/commands.integrate.cpp index 1d2d5883ef..be9d35b543 100644 --- a/src/vcpkg/commands.integrate.cpp +++ b/src/vcpkg/commands.integrate.cpp @@ -155,13 +155,13 @@ namespace vcpkg::Commands::Integrate #if defined(_WIN32) static Path get_appdata_targets_path() { - return get_appdata_local().value_or_exit(VCPKG_LINE_INFO) / "vcpkg/vcpkg.user.targets"; + return get_appdata_local().value_or_exit(VCPKG_LINE_INFO) / "vcpkg\\vcpkg.user.targets"; } #endif #if defined(_WIN32) static Path get_appdata_props_path() { - return get_appdata_local().value_or_exit(VCPKG_LINE_INFO) / "vcpkg/vcpkg.user.props"; + return get_appdata_local().value_or_exit(VCPKG_LINE_INFO) / "vcpkg\\vcpkg.user.props"; } #endif @@ -246,8 +246,8 @@ namespace vcpkg::Commands::Integrate { std::error_code ec; const auto tmp_dir = paths.buildsystems / "tmp"; - fs.create_directory(paths.buildsystems, ec); - fs.create_directory(tmp_dir, ec); + fs.create_directory(paths.buildsystems, VCPKG_LINE_INFO); + fs.create_directory(tmp_dir, VCPKG_LINE_INFO); integrate_install_msbuild14(fs, tmp_dir); @@ -256,6 +256,9 @@ namespace vcpkg::Commands::Integrate appdata_src_path, create_appdata_shortcut(paths.buildsystems_msbuild_targets), VCPKG_LINE_INFO); auto appdata_dst_path = get_appdata_targets_path(); + const auto vcpkg_appdata_local = get_appdata_local().value_or_exit(VCPKG_LINE_INFO) / "vcpkg"; + fs.create_directory(vcpkg_appdata_local, VCPKG_LINE_INFO); + fs.copy_file(appdata_src_path, appdata_dst_path, CopyOptions::overwrite_existing, ec); if (ec) { diff --git a/src/vcpkg/commands.list.cpp b/src/vcpkg/commands.list.cpp index e1cd703bad..7f40d0b19e 100644 --- a/src/vcpkg/commands.list.cpp +++ b/src/vcpkg/commands.list.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include namespace vcpkg::Commands::List { @@ -52,7 +52,7 @@ namespace vcpkg::Commands::List static void do_print(const StatusParagraph& pgh, const bool full_desc) { - auto full_version = VersionT(pgh.package.version, pgh.package.port_version).to_string(); + auto full_version = Version(pgh.package.version, pgh.package.port_version).to_string(); if (full_desc) { vcpkg::printf("%-50s %-16s %s\n", diff --git a/src/vcpkg/commands.porthistory.cpp b/src/vcpkg/commands.porthistory.cpp index f52124346f..422eca20aa 100644 --- a/src/vcpkg/commands.porthistory.cpp +++ b/src/vcpkg/commands.porthistory.cpp @@ -25,7 +25,7 @@ namespace vcpkg::Commands::PortHistory std::string version_string; std::string version; int port_version; - Versions::Scheme scheme; + VersionScheme scheme; }; ExitCodeAndOutput run_git_command(const VcpkgPaths& paths, const Command& cmd) @@ -47,7 +47,7 @@ namespace vcpkg::Commands::PortHistory { if (const auto& scf = maybe_scf->get()) { - auto version = scf->core_paragraph->version; + auto version = scf->core_paragraph->raw_version; auto port_version = scf->core_paragraph->port_version; auto scheme = scf->core_paragraph->version_scheme; return HistoryVersion{ diff --git a/src/vcpkg/commands.portsdiff.cpp b/src/vcpkg/commands.portsdiff.cpp index 9335a74b81..10ef0491e4 100644 --- a/src/vcpkg/commands.portsdiff.cpp +++ b/src/vcpkg/commands.portsdiff.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include namespace vcpkg::Commands::PortsDiff { @@ -48,14 +48,14 @@ namespace vcpkg::Commands::PortsDiff static std::vector find_updated_ports( const std::vector& ports, - const std::map& previous_names_and_versions, - const std::map& current_names_and_versions) + const std::map& previous_names_and_versions, + const std::map& current_names_and_versions) { std::vector output; for (const std::string& name : ports) { - const VersionT& previous_version = previous_names_and_versions.at(name); - const VersionT& current_version = current_names_and_versions.at(name); + const Version& previous_version = previous_names_and_versions.at(name); + const Version& current_version = current_names_and_versions.at(name); if (previous_version == current_version) { continue; @@ -68,17 +68,17 @@ namespace vcpkg::Commands::PortsDiff } static void do_print_name_and_version(const std::vector& ports_to_print, - const std::map& names_and_versions) + const std::map& names_and_versions) { for (const std::string& name : ports_to_print) { - const VersionT& version = names_and_versions.at(name); + const Version& version = names_and_versions.at(name); vcpkg::printf(" - %-14s %-16s\n", name, version); } } - static std::map read_ports_from_commit(const VcpkgPaths& paths, - const std::string& git_commit_id) + static std::map read_ports_from_commit(const VcpkgPaths& paths, + const std::string& git_commit_id) { std::error_code ec; auto& fs = paths.get_filesystem(); @@ -101,11 +101,11 @@ namespace vcpkg::Commands::PortsDiff cmd_execute_and_capture_output(paths.git_cmd_builder(dot_git_dir, temp_checkout_path).string_arg("reset"), get_clean_environment()); const auto ports_at_commit = Paragraphs::load_overlay_ports(fs, temp_checkout_path / ports_dir_name); - std::map names_and_versions; + std::map names_and_versions; for (auto&& port : ports_at_commit) { const auto& core_pgh = *port.source_control_file->core_paragraph; - names_and_versions.emplace(core_pgh.name, VersionT(core_pgh.version, core_pgh.port_version)); + names_and_versions.emplace(core_pgh.name, Version(core_pgh.raw_version, core_pgh.port_version)); } fs.remove_all(temp_checkout_path, VCPKG_LINE_INFO); return names_and_versions; @@ -144,9 +144,9 @@ namespace vcpkg::Commands::PortsDiff check_commit_exists(paths, git_commit_id_for_current_snapshot); check_commit_exists(paths, git_commit_id_for_previous_snapshot); - const std::map current_names_and_versions = + const std::map current_names_and_versions = read_ports_from_commit(paths, git_commit_id_for_current_snapshot); - const std::map previous_names_and_versions = + const std::map previous_names_and_versions = read_ports_from_commit(paths, git_commit_id_for_previous_snapshot); // Already sorted, so set_difference can work on std::vector too diff --git a/src/vcpkg/commands.setinstalled.cpp b/src/vcpkg/commands.setinstalled.cpp index 86da98a76c..b792014607 100644 --- a/src/vcpkg/commands.setinstalled.cpp +++ b/src/vcpkg/commands.setinstalled.cpp @@ -153,7 +153,7 @@ namespace vcpkg::Commands::SetInstalled std::string(arg), default_triplet, COMMAND_STRUCTURE.example_text, paths); }); - BinaryCache binary_cache{args}; + BinaryCache binary_cache{args, paths}; const bool dry_run = Util::Sets::contains(options.switches, OPTION_DRY_RUN); diff --git a/src/vcpkg/commands.upgrade.cpp b/src/vcpkg/commands.upgrade.cpp index 4f8fa81ae4..bc28643b62 100644 --- a/src/vcpkg/commands.upgrade.cpp +++ b/src/vcpkg/commands.upgrade.cpp @@ -60,7 +60,7 @@ namespace vcpkg::Commands::Upgrade ? Dependencies::UnsupportedPortAction::Warn : Dependencies::UnsupportedPortAction::Error; - BinaryCache binary_cache{args}; + BinaryCache binary_cache{args, paths}; StatusParagraphs status_db = database_load_check(paths.get_filesystem(), paths.installed()); // Load ports from ports dirs @@ -121,9 +121,9 @@ namespace vcpkg::Commands::Upgrade const auto& control_file = maybe_control_file.value_or_exit(VCPKG_LINE_INFO); const auto& control_paragraph = *control_file.source_control_file->core_paragraph; - auto control_version = VersionT(control_paragraph.version, control_paragraph.port_version); + auto control_version = Version(control_paragraph.raw_version, control_paragraph.port_version); const auto& installed_paragraph = (*installed_status)->package; - auto installed_version = VersionT(installed_paragraph.version, installed_paragraph.port_version); + auto installed_version = Version(installed_paragraph.version, installed_paragraph.port_version); if (control_version == installed_version) { up_to_date.push_back(spec); diff --git a/src/vcpkg/dependencies.cpp b/src/vcpkg/dependencies.cpp index bbcd7feaed..c74287cfb1 100644 --- a/src/vcpkg/dependencies.cpp +++ b/src/vcpkg/dependencies.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -382,11 +383,11 @@ namespace vcpkg::Dependencies Strings::append(ret, s); if (scfl) { - Strings::append(ret, " -> ", scfl->to_versiont()); + Strings::append(ret, " -> ", scfl->to_version()); } else if (ipv) { - Strings::append(ret, " -> ", VersionT{ipv->core->package.version, ipv->core->package.port_version}); + Strings::append(ret, " -> ", Version{ipv->core->package.version, ipv->core->package.port_version}); } if (options.use_head_version == Build::UseHeadVersion::YES) { @@ -1201,7 +1202,7 @@ namespace vcpkg::Dependencies { } - void add_override(const std::string& name, const Versions::Version& v); + void add_override(const std::string& name, const Version& v); void add_roots(View dep, const PackageSpec& toplevel); @@ -1218,7 +1219,7 @@ namespace vcpkg::Dependencies struct DepSpec { PackageSpec spec; - Versions::Version ver; + Version ver; std::vector features; }; @@ -1226,15 +1227,15 @@ namespace vcpkg::Dependencies // there we save an object for every version) struct VersionSchemeInfo { - Versions::Scheme scheme; + VersionScheme scheme; const SourceControlFileAndLocation* scfl = nullptr; - Versions::Version version; + Version version; // This tracks a list of constraint sources for debugging purposes std::vector origins; // mapping from feature name -> dependencies of this feature std::map> deps; - bool is_less_than(const Versions::Version& new_ver) const; + bool is_less_than(const Version& new_ver) const; }; struct PackageNode @@ -1250,26 +1251,25 @@ namespace vcpkg::Dependencies // "1.0.1": { "version": "1.0.2" }, // "1.0.2": { "version": "1.0.2" } // } - std::map vermap; + std::map vermap; // We don't know how to compare "version-string" versions, so keep all the versions separately std::map exacts; - // for each version type besides string (relaxed, semver, date), we only track the latest version + // for each version type besides string (relaxed-semver, date), we only track the latest version // required - Optional> relaxed; - Optional> semver; + Optional> relaxed_semver; Optional> date; std::set requested_features; bool default_features = true; bool user_requested = false; - VersionSchemeInfo* get_node(const Versions::Version& ver); + VersionSchemeInfo* get_node(const Version& ver); // Adds the version to the version resolver: // - for string version schemes, just adds the newer version to the set // - for non-string version schemes: // - if the scheme doesn't exist in the set, adds the version to the set // - if the scheme already exists in the set, and the version is newer than the existing entry, // replaces the current entry for the scheme - VersionSchemeInfo& emplace_node(Versions::Scheme scheme, const Versions::Version& ver); + VersionSchemeInfo& emplace_node(VersionScheme scheme, const Version& ver); PackageNode() = default; PackageNode(const PackageNode&) = delete; @@ -1280,14 +1280,10 @@ namespace vcpkg::Dependencies template void foreach_vsi(F f) { - if (auto r = this->relaxed.get()) + if (auto r = this->relaxed_semver.get()) { f(**r); } - if (auto s = this->semver.get()) - { - f(**s); - } if (auto d = this->date.get()) { f(**d); @@ -1302,7 +1298,7 @@ namespace vcpkg::Dependencies // the roots of the dependency graph (given in the manifest file) std::vector m_roots; // mapping from portname -> version. "overrides" field in manifest file - std::map m_overrides; + std::map m_overrides; // mapping from { package specifier -> node containing resolution information for that package } std::map m_graph; @@ -1313,7 +1309,7 @@ namespace vcpkg::Dependencies const Dependency& dep, const std::string& origin); void require_port_version(std::pair& graph_entry, - const Versions::Version& ver, + const Version& ver, const std::string& origin); void require_port_feature(std::pair& ref, const std::string& feature, @@ -1325,7 +1321,7 @@ namespace vcpkg::Dependencies VersionSchemeInfo& vsi, const std::string& feature); - Optional dep_to_version(const std::string& name, const DependencyConstraint& dc); + Optional dep_to_version(const std::string& name, const DependencyConstraint& dc); static std::string format_incomparable_versions_message(const PackageSpec& on, StringView from, @@ -1335,42 +1331,30 @@ namespace vcpkg::Dependencies std::vector m_errors; }; - VersionedPackageGraph::VersionSchemeInfo& VersionedPackageGraph::PackageNode::emplace_node( - Versions::Scheme scheme, const Versions::Version& ver) + VersionedPackageGraph::VersionSchemeInfo& VersionedPackageGraph::PackageNode::emplace_node(VersionScheme scheme, + const Version& ver) { auto it = vermap.find(ver); if (it != vermap.end()) return *it->second; VersionSchemeInfo* vsi = nullptr; - if (scheme == Versions::Scheme::String) + if (scheme == VersionScheme::String) { vsi = &exacts[ver.text()]; } - else if (scheme == Versions::Scheme::Relaxed) - { - if (auto p = relaxed.get()) - { - vsi = p->get(); - } - else - { - relaxed = std::make_unique(); - vsi = relaxed.get()->get(); - } - } - else if (scheme == Versions::Scheme::Semver) + else if (scheme == VersionScheme::Relaxed || scheme == VersionScheme::Semver) { - if (auto p = semver.get()) + if (auto p = relaxed_semver.get()) { vsi = p->get(); } else { - semver = std::make_unique(); - vsi = semver.get()->get(); + relaxed_semver = std::make_unique(); + vsi = relaxed_semver.get()->get(); } } - else if (scheme == Versions::Scheme::Date) + else if (scheme == VersionScheme::Date) { if (auto p = date.get()) { @@ -1392,34 +1376,48 @@ namespace vcpkg::Dependencies return *vsi; } - VersionedPackageGraph::VersionSchemeInfo* VersionedPackageGraph::PackageNode::get_node( - const Versions::Version& ver) + VersionedPackageGraph::VersionSchemeInfo* VersionedPackageGraph::PackageNode::get_node(const Version& ver) { auto it = vermap.find(ver); return it == vermap.end() ? nullptr : it->second; } - using Versions::VerComp; - - static VerComp compare_versions(Versions::Scheme sa, - const Versions::Version& a, - Versions::Scheme sb, - const Versions::Version& b) + static VerComp compare_version_texts(VersionScheme sa, const Version& a, VersionScheme sb, const Version& b) { - if (sa != sb) return VerComp::unk; + if (sa == VersionScheme::String && sb == VersionScheme::String) + { + return int_to_vercomp(a.text().compare(b.text())); + } + + if (sa == VersionScheme::Date && sb == VersionScheme::Date) + { + return compare(DateVersion::try_parse(a.text()).value_or_exit(VCPKG_LINE_INFO), + DateVersion::try_parse(b.text()).value_or_exit(VCPKG_LINE_INFO)); + } + + if ((sa == VersionScheme::Semver || sa == VersionScheme::Relaxed) && + (sb == VersionScheme::Semver || sb == VersionScheme::Relaxed)) + { + return compare(DotVersion::try_parse(a.text(), sa).value_or_exit(VCPKG_LINE_INFO), + DotVersion::try_parse(b.text(), sb).value_or_exit(VCPKG_LINE_INFO)); + } - if (a.text() != b.text()) + return VerComp::unk; + } + + static VerComp compare_versions(VersionScheme sa, const Version& a, VersionScheme sb, const Version& b) + { + const auto inner_compare = compare_version_texts(sa, a, sb, b); + if (inner_compare == VerComp::eq) { - auto result = Versions::compare(a.text(), b.text(), sa); - if (result != VerComp::eq) return result; + if (a.port_version() < b.port_version()) return VerComp::lt; + if (a.port_version() > b.port_version()) return VerComp::gt; } - if (a.port_version() < b.port_version()) return VerComp::lt; - if (a.port_version() > b.port_version()) return VerComp::gt; - return VerComp::eq; + return inner_compare; } - bool VersionedPackageGraph::VersionSchemeInfo::is_less_than(const Versions::Version& new_ver) const + bool VersionedPackageGraph::VersionSchemeInfo::is_less_than(const Version& new_ver) const { Checks::check_exit(VCPKG_LINE_INFO, scfl); ASSUME(scfl != nullptr); @@ -1429,28 +1427,6 @@ namespace vcpkg::Dependencies return r == VerComp::lt; } - Versions::Version to_version(const SourceControlFile& scf) - { - return { - scf.core_paragraph->version, - scf.core_paragraph->port_version, - }; - } - Optional to_version(const DependencyConstraint& dc) - { - if (dc.type == Versions::Constraint::Type::None) - { - return nullopt; - } - else - { - return Versions::Version{ - dc.value, - dc.port_version, - }; - } - } - void VersionedPackageGraph::add_feature_to(std::pair& ref, VersionSchemeInfo& vsi, const std::string& feature) @@ -1514,21 +1490,20 @@ namespace vcpkg::Dependencies const Dependency& dep, const std::string& origin) { - auto maybe_overlay = m_o_provider.get_control_file(ref.first.name()); - auto over_it = m_overrides.find(ref.first.name()); + const auto maybe_overlay = m_o_provider.get_control_file(ref.first.name()); if (auto p_overlay = maybe_overlay.get()) { - auto overlay_version = to_version(*p_overlay->source_control_file); + const auto overlay_version = p_overlay->source_control_file->to_version(); require_port_version(ref, overlay_version, origin); } - else if (over_it != m_overrides.end()) + else if (const auto over_it = m_overrides.find(ref.first.name()); over_it != m_overrides.end()) { require_port_version(ref, over_it->second, origin); } else { - auto base_ver = m_base_provider.get_baseline_version(dep.name); - auto dep_ver = to_version(dep.constraint); + const auto base_ver = m_base_provider.get_baseline_version(dep.name); + const auto dep_ver = dep.constraint.try_get_minimum_version(); if (auto dv = dep_ver.get()) { @@ -1552,7 +1527,7 @@ namespace vcpkg::Dependencies } } void VersionedPackageGraph::require_port_version(std::pair& graph_entry, - const Versions::Version& version, + const Version& version, const std::string& origin) { ExpectedS maybe_scfl; @@ -1561,7 +1536,7 @@ namespace vcpkg::Dependencies auto maybe_overlay = m_o_provider.get_control_file(graph_entry.first.name()); if (auto p_overlay = maybe_overlay.get()) { - auto overlay_version = to_version(*p_overlay->source_control_file); + const auto overlay_version = p_overlay->source_control_file->to_version(); // If the original request did not match the overlay version, restart this function to operate on the // overlay version if (version != overlay_version) @@ -1604,7 +1579,7 @@ namespace vcpkg::Dependencies if (replace) { versioned_graph_entry.scfl = p_scfl; - versioned_graph_entry.version = to_version(*p_scfl->source_control_file); + versioned_graph_entry.version = p_scfl->source_control_file->to_version(); versioned_graph_entry.deps.clear(); // add all dependencies to the graph @@ -1671,13 +1646,12 @@ namespace vcpkg::Dependencies return *m_graph.emplace(spec, PackageNode{}).first; } - Optional VersionedPackageGraph::dep_to_version(const std::string& name, - const DependencyConstraint& dc) + Optional VersionedPackageGraph::dep_to_version(const std::string& name, const DependencyConstraint& dc) { auto maybe_overlay = m_o_provider.get_control_file(name); if (auto p_overlay = maybe_overlay.get()) { - return to_version(*p_overlay->source_control_file); + return p_overlay->source_control_file->to_version(); } auto over_it = m_overrides.find(name); @@ -1686,18 +1660,16 @@ namespace vcpkg::Dependencies return over_it->second; } - auto maybe_cons = to_version(dc); + const auto maybe_cons = dc.try_get_minimum_version(); if (maybe_cons) { return maybe_cons; } - else - { - return m_base_provider.get_baseline_version(name); - } + + return m_base_provider.get_baseline_version(name); } - void VersionedPackageGraph::add_override(const std::string& name, const Versions::Version& v) + void VersionedPackageGraph::add_override(const std::string& name, const Version& v) { m_overrides.emplace(name, v); } @@ -1760,7 +1732,7 @@ namespace vcpkg::Dependencies auto over_it = m_overrides.find(dep.name); if (auto p_overlay = maybe_overlay.get()) { - auto ver = to_version(*p_overlay->source_control_file); + const auto ver = p_overlay->source_control_file->to_version(); m_roots.push_back(DepSpec{spec, ver, dep.features}); require_port_version(node, ver, toplevel.name()); } @@ -1771,8 +1743,8 @@ namespace vcpkg::Dependencies } else { - auto dep_ver = to_version(dep.constraint); - auto base_ver = m_base_provider.get_baseline_version(dep.name); + const auto dep_ver = dep.constraint.try_get_minimum_version(); + const auto base_ver = m_base_provider.get_baseline_version(dep.name); if (auto p_dep_ver = dep_ver.get()) { m_roots.push_back(DepSpec{spec, *p_dep_ver, dep.features}); @@ -1865,8 +1837,9 @@ namespace vcpkg::Dependencies ExpectedS VersionedPackageGraph::finalize_extract_plan( const PackageSpec& toplevel, UnsupportedPortAction unsupported_port_action) { - if (m_errors.size() > 0) + if (!m_errors.empty()) { + Util::sort_unique_erase(m_errors); return Strings::join("\n", m_errors); } @@ -1884,7 +1857,7 @@ namespace vcpkg::Dependencies // Adds a new Frame to the stack if the spec was not already added auto push = [&emitted, this, &stack, unsupported_port_action, &ret]( const PackageSpec& spec, - const Versions::Version& new_ver, + const Version& new_ver, const PackageSpec& origin, View features) -> Optional { auto&& node = emplace_package(spec).second; @@ -1893,7 +1866,7 @@ namespace vcpkg::Dependencies VersionedPackageGraph::VersionSchemeInfo* p_vnode; if (auto p_overlay = overlay.get()) - p_vnode = node.get_node(to_version(*p_overlay->source_control_file)); + p_vnode = node.get_node(p_overlay->source_control_file->to_version()); else if (over_it != m_overrides.end()) p_vnode = node.get_node(over_it->second); else @@ -2055,7 +2028,7 @@ namespace vcpkg::Dependencies emitted[back.ipa.spec] = emplace_package(back.ipa.spec) .second.get_node( - to_version(*back.ipa.source_control_file_and_location.get()->source_control_file)); + back.ipa.source_control_file_and_location.get()->source_control_file->to_version()); ret.install_actions.push_back(std::move(back.ipa)); stack.pop_back(); } diff --git a/src/vcpkg/export.prefab.cpp b/src/vcpkg/export.prefab.cpp index c370f77d19..635bf69368 100644 --- a/src/vcpkg/export.prefab.cpp +++ b/src/vcpkg/export.prefab.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -194,22 +195,6 @@ namespace vcpkg::Export::Prefab return {}; } - static void compress_directory(const VcpkgPaths& paths, const Path& source, const Path& destination) - { - auto& fs = paths.get_filesystem(); - fs.remove(destination, VCPKG_LINE_INFO); -#if defined(_WIN32) - auto&& seven_zip_exe = paths.get_tool_exe(Tools::SEVEN_ZIP); - - cmd_execute_and_capture_output( - Command(seven_zip_exe).string_arg("a").path_arg(destination).path_arg(source / "*"), - get_clean_environment()); -#else - cmd_execute_clean(Command{"zip"}.string_arg("--quiet").string_arg("-r").path_arg(destination).string_arg("*"), - InWorkingDirectory{source}); -#endif - } - static void maven_install(const Path& aar, const Path& pom, const Options& prefab_options) { if (prefab_options.enable_debug) @@ -633,7 +618,9 @@ namespace vcpkg::Export::Prefab "[DEBUG] Exporting AAR And POM\n\tAAR Path %s\n\tPOM Path %s\n", exported_archive_path, pom_path)); } - compress_directory(paths, package_directory, exported_archive_path); + Checks::check_exit(VCPKG_LINE_INFO, + compress_directory_to_zip(paths, package_directory, exported_archive_path) != 0, + Strings::concat("Failed to compress folder ", package_directory)); std::string POM = R"( build_list_of_package_files(const Filesystem& fs, const Path& package_dir) { - const std::vector package_file_paths = fs.get_files_recursive(package_dir, IgnoreErrors{}); + std::vector package_file_paths = fs.get_files_recursive(package_dir, IgnoreErrors{}); + Util::erase_remove_if(package_file_paths, [](Path& path) { return path.filename() == ".DS_Store"; }); const size_t package_remove_char_count = package_dir.native().size() + 1; // +1 for the slash auto package_files = Util::fmap(package_file_paths, [package_remove_char_count](const Path& target) { return std::string(target.generic_u8string(), package_remove_char_count); @@ -329,7 +331,7 @@ namespace vcpkg::Install if (plan_type == InstallPlanType::BUILD_AND_INSTALL) { std::unique_ptr bcf; - auto restore = binary_cache.try_restore(paths, action); + auto restore = binary_cache.try_restore(action); if (restore == RestoreResult::restored) { auto maybe_bcf = Paragraphs::try_load_cached_package(fs, paths.package_dir(action.spec), action.spec); @@ -481,7 +483,7 @@ namespace vcpkg::Install } Build::compute_all_abis(paths, action_plan, var_provider, status_db); - binary_cache.prefetch(paths, action_plan.install_actions); + binary_cache.prefetch(action_plan.install_actions); for (auto&& action : action_plan.install_actions) { TrackedPackageInstallGuard this_install(action_index++, action_count, results, action.spec); @@ -850,7 +852,7 @@ namespace vcpkg::Install } if (failure) { - msg::println(msgUsingManifestAt, msg::path = paths.manifest_root_dir / "vcpkg.json"); + msg::println(msgUsingManifestAt, msg::path = paths.get_manifest_path().value_or_exit(VCPKG_LINE_INFO)); print2("\n"); print_usage(MANIFEST_COMMAND_STRUCTURE); Checks::exit_fail(VCPKG_LINE_INFO); @@ -889,7 +891,7 @@ namespace vcpkg::Install BinaryCache binary_cache; if (!only_downloads) { - binary_cache.install_providers_for(args); + binary_cache.install_providers_for(args, paths); } auto& fs = paths.get_filesystem(); @@ -985,7 +987,7 @@ namespace vcpkg::Install } if (std::any_of(dependencies.begin(), dependencies.end(), [](const Dependency& dep) { - return dep.constraint.type != Versions::Constraint::Type::None; + return dep.constraint.type != VersionConstraintKind::None; })) { LockGuardPtr(g_metrics)->track_property("manifest_version_constraint", "defined"); @@ -1272,9 +1274,8 @@ namespace vcpkg::Install for (auto&& install_action : plan.install_actions) { - auto&& version_as_string = install_action.source_control_file_and_location.value_or_exit(VCPKG_LINE_INFO) - .to_versiont() - .to_string(); + auto&& version_as_string = + install_action.source_control_file_and_location.value_or_exit(VCPKG_LINE_INFO).to_version().to_string(); if (!specs_string.empty()) specs_string.push_back(','); specs_string += Strings::concat(Hash::get_string_hash(install_action.spec.name(), Hash::Algorithm::Sha256), ":", diff --git a/src/vcpkg/packagespec.cpp b/src/vcpkg/packagespec.cpp index 587ed72e74..c2a67943a2 100644 --- a/src/vcpkg/packagespec.cpp +++ b/src/vcpkg/packagespec.cpp @@ -28,13 +28,6 @@ namespace vcpkg } } - std::vector PackageSpec::to_package_specs(const std::vector& ports, Triplet triplet) - { - return Util::fmap(ports, [&](const std::string& spec_as_string) -> PackageSpec { - return {spec_as_string, triplet}; - }); - } - const std::string& PackageSpec::name() const { return this->m_name; } Triplet PackageSpec::triplet() const { return this->m_triplet; } @@ -277,7 +270,19 @@ namespace vcpkg if (lhs.value != rhs.value) return false; return lhs.port_version == rhs.port_version; } - bool operator!=(const DependencyConstraint& lhs, const DependencyConstraint& rhs); + + Optional DependencyConstraint::try_get_minimum_version() const + { + if (type == VersionConstraintKind::None) + { + return nullopt; + } + + return Version{ + value, + port_version, + }; + } FullPackageSpec Dependency::to_full_spec(Triplet target, Triplet host_triplet, ImplicitDefault id) const { diff --git a/src/vcpkg/portfileprovider.cpp b/src/vcpkg/portfileprovider.cpp index 04b7dabb7d..4f91c72eb1 100644 --- a/src/vcpkg/portfileprovider.cpp +++ b/src/vcpkg/portfileprovider.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -12,18 +13,15 @@ #include using namespace vcpkg; -using namespace Versions; namespace { - using namespace vcpkg; - struct OverlayRegistryEntry final : RegistryEntry { - OverlayRegistryEntry(Path&& p, VersionT&& v) : root(p), version(v) { } + OverlayRegistryEntry(Path&& p, Version&& v) : root(p), version(v) { } - View get_port_versions() const override { return {&version, 1}; } - ExpectedS get_path_to_version(const VersionT& v) const override + View get_port_versions() const override { return {&version, 1}; } + ExpectedS get_path_to_version(const Version& v) const override { if (v == version) { @@ -33,7 +31,7 @@ namespace } Path root; - VersionT version; + Version version; }; } @@ -90,6 +88,12 @@ namespace vcpkg::PortFileProvider return Util::fmap(m, [](const auto& p) { return p.second; }); } + DECLARE_AND_REGISTER_MESSAGE(VersionSpecMismatch, + (msg::path, msg::expected, msg::actual), + "", + "Error: Failed to load port because version specs did not match\n Path: " + "{path}\n Expected: {expected}\n Actual: {actual}"); + namespace { struct BaselineProviderImpl : IBaselineProvider @@ -98,7 +102,7 @@ namespace vcpkg::PortFileProvider BaselineProviderImpl(const BaselineProviderImpl&) = delete; BaselineProviderImpl& operator=(const BaselineProviderImpl&) = delete; - virtual Optional get_baseline_version(StringView port_name) const override + virtual Optional get_baseline_version(StringView port_name) const override { auto it = m_baseline_cache.find(port_name); if (it != m_baseline_cache.end()) @@ -115,7 +119,7 @@ namespace vcpkg::PortFileProvider private: const VcpkgPaths& paths; - mutable std::map, std::less<>> m_baseline_cache; + mutable std::map, std::less<>> m_baseline_cache; }; struct VersionedPortfileProviderImpl : IVersionedPortfileProvider @@ -158,7 +162,7 @@ namespace vcpkg::PortFileProvider return entry_it->second; } - virtual View get_port_versions(StringView port_name) const override + virtual View get_port_versions(StringView port_name) const override { return entry(port_name).value_or_exit(VCPKG_LINE_INFO)->get_port_versions(); } @@ -175,18 +179,19 @@ namespace vcpkg::PortFileProvider auto maybe_control_file = Paragraphs::try_load_port(m_fs, *path); if (auto scf = maybe_control_file.get()) { - if (scf->get()->core_paragraph->name == version_spec.port_name) + auto scf_vspec = scf->get()->to_version_spec(); + if (scf_vspec == version_spec) { return std::unique_ptr( new SourceControlFileAndLocation{std::move(*scf), std::move(*path)}); } else { - return Strings::format("Error: Failed to load port from %s: names did " - "not match: '%s' != '%s'", - *path, - version_spec.port_name, - scf->get()->core_paragraph->name); + return msg::format(msgVersionSpecMismatch, + msg::path = *path, + msg::expected = version_spec, + msg::actual = scf_vspec) + .extract_data(); } } else @@ -226,7 +231,7 @@ namespace vcpkg::PortFileProvider for (auto&& scfl : all_ports) { auto port_name = scfl.source_control_file->core_paragraph->name; - auto version = scfl.source_control_file->core_paragraph->to_versiont(); + auto version = scfl.source_control_file->core_paragraph->to_version(); auto it = m_control_cache .emplace(VersionSpec{std::move(port_name), std::move(version)}, std::make_unique(std::move(scfl))) diff --git a/src/vcpkg/postbuildlint.cpp b/src/vcpkg/postbuildlint.cpp index f9e594ff76..bf037faa81 100644 --- a/src/vcpkg/postbuildlint.cpp +++ b/src/vcpkg/postbuildlint.cpp @@ -496,6 +496,7 @@ namespace vcpkg::PostBuildLint case MachineType::ARM: case MachineType::ARMNT: return "arm"; case MachineType::ARM64: return "arm64"; + case MachineType::ARM64EC: return "arm64ec"; default: return "Machine Type Code = " + std::to_string(static_cast(machine_type)); } } @@ -959,7 +960,7 @@ namespace vcpkg::PostBuildLint std::vector misplaced_files = fs.get_regular_files_non_recursive(dir, IgnoreErrors{}); Util::erase_remove_if(misplaced_files, [](const Path& target) { const auto filename = target.filename(); - return filename == "CONTROL" || filename == "BUILD_INFO"; + return filename == "CONTROL" || filename == "BUILD_INFO" || filename == ".DS_Store"; }); if (!misplaced_files.empty()) diff --git a/src/vcpkg/registries.cpp b/src/vcpkg/registries.cpp index b25feed713..3689a51340 100644 --- a/src/vcpkg/registries.cpp +++ b/src/vcpkg/registries.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include @@ -20,7 +20,7 @@ namespace { using namespace vcpkg; - using Baseline = std::map>; + using Baseline = std::map>; static constexpr StringLiteral registry_versions_dir_name = "versions"; @@ -30,8 +30,8 @@ namespace { GitRegistryEntry(const GitRegistry& reg, StringView name); - View get_port_versions() const override; - ExpectedS get_path_to_version(const VersionT& version) const override; + View get_port_versions() const override; + ExpectedS get_path_to_version(const Version& version) const override; private: void fill_data_from_path(const Filesystem& fs, const Path& port_versions_path) const; @@ -45,7 +45,7 @@ namespace // 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] - mutable std::vector port_versions; + mutable std::vector port_versions; mutable std::vector git_trees; }; @@ -65,7 +65,7 @@ namespace void get_all_port_names(std::vector&) const override; - Optional get_baseline_version(StringView) const override; + Optional get_baseline_version(StringView) const override; private: friend struct GitRegistryEntry; @@ -152,13 +152,13 @@ namespace struct BuiltinPortTreeRegistryEntry final : RegistryEntry { - BuiltinPortTreeRegistryEntry(StringView name_, Path root_, VersionT version_) + BuiltinPortTreeRegistryEntry(StringView name_, Path root_, Version version_) : name(name_.to_string()), root(root_), version(version_) { } - View get_port_versions() const override { return {&version, 1}; } - ExpectedS get_path_to_version(const VersionT& v) const override + View get_port_versions() const override { return {&version, 1}; } + ExpectedS get_path_to_version(const Version& v) const override { if (v == version) { @@ -175,15 +175,15 @@ namespace std::string name; Path root; - VersionT version; + Version version; }; struct BuiltinGitRegistryEntry final : RegistryEntry { BuiltinGitRegistryEntry(const VcpkgPaths& paths) : m_paths(paths) { } - View get_port_versions() const override { return port_versions; } - ExpectedS get_path_to_version(const VersionT& version) const override; + View get_port_versions() const override { return port_versions; } + ExpectedS get_path_to_version(const Version& version) const override; const VcpkgPaths& m_paths; @@ -191,7 +191,7 @@ namespace // 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 port_versions; + std::vector port_versions; std::vector git_trees; }; @@ -199,14 +199,14 @@ namespace { explicit FilesystemRegistryEntry(std::string&& port_name) : port_name(port_name) { } - View get_port_versions() const override { return port_versions; } + View get_port_versions() const override { return port_versions; } - ExpectedS get_path_to_version(const VersionT& version) const override; + ExpectedS get_path_to_version(const Version& version) const override; std::string port_name; // these two map port versions to paths // these shall have the same size, and paths[i] shall be the path for port_versions[i] - std::vector port_versions; + std::vector port_versions; std::vector version_paths; }; @@ -234,7 +234,7 @@ namespace void get_all_port_names(std::vector&) const override; - Optional get_baseline_version(StringView port_name) const override; + Optional get_baseline_version(StringView port_name) const override; Optional get_path_to_baseline_version(StringView port_name) const override { @@ -282,7 +282,7 @@ namespace void get_all_port_names(std::vector&) const override; - Optional get_baseline_version(StringView port_name) const override; + Optional get_baseline_version(StringView port_name) const override; ~BuiltinGitRegistry() = default; @@ -311,7 +311,7 @@ namespace void get_all_port_names(std::vector&) const override { fail_require_baseline(VCPKG_LINE_INFO); } - Optional get_baseline_version(StringView) const override { fail_require_baseline(VCPKG_LINE_INFO); } + Optional get_baseline_version(StringView) const override { fail_require_baseline(VCPKG_LINE_INFO); } Optional get_path_to_baseline_version(StringView) const override { @@ -342,7 +342,7 @@ namespace void get_all_port_names(std::vector&) const override; - Optional get_baseline_version(StringView) const override; + Optional get_baseline_version(StringView) const override; private: const Filesystem& m_fs; @@ -467,7 +467,7 @@ namespace if (scf->core_paragraph->name == port_name) { return std::make_unique( - scf->core_paragraph->name, port_directory, scf->to_versiont()); + scf->core_paragraph->name, port_directory, scf->to_version()); } Checks::exit_maybe_upgrade(VCPKG_LINE_INFO, @@ -481,14 +481,14 @@ namespace return nullptr; } - Optional BuiltinFilesRegistry::get_baseline_version(StringView port_name) const + Optional BuiltinFilesRegistry::get_baseline_version(StringView port_name) const { // if a baseline is not specified, use the ports directory version auto port_path = m_builtin_ports_directory / port_name; const auto& maybe_scf = get_scf(port_path); if (auto pscf = maybe_scf.get()) { - return (*pscf)->to_versiont(); + return (*pscf)->to_version(); } print_error_message(maybe_scf.error()); Checks::exit_maybe_upgrade(VCPKG_LINE_INFO, "Error: failed to load port from %s", port_path); @@ -539,7 +539,7 @@ namespace return m_files_impl->get_port_entry(port_name); } - Optional BuiltinGitRegistry::get_baseline_version(StringView port_name) const + Optional BuiltinGitRegistry::get_baseline_version(StringView port_name) const { const auto& baseline = m_baseline.get([this]() -> Baseline { auto maybe_path = git_checkout_baseline(m_paths, m_baseline_identifier); @@ -580,7 +580,7 @@ namespace // } BuiltinGitRegistry::RegistryImplementation // { FilesystemRegistry::RegistryImplementation - Optional FilesystemRegistry::get_baseline_version(StringView port_name) const + Optional FilesystemRegistry::get_baseline_version(StringView port_name) const { const auto& baseline = m_baseline.get([this]() -> Baseline { auto path_to_baseline = m_path / registry_versions_dir_name / "baseline.json"; @@ -655,7 +655,7 @@ namespace fill_data_from_path(parent.m_paths.get_filesystem(), vtp.p); } - Optional GitRegistry::get_baseline_version(StringView port_name) const + Optional GitRegistry::get_baseline_version(StringView port_name) const { const auto& baseline = m_baseline.get([this]() -> Baseline { // We delay baseline validation until here to give better error messages and suggestions @@ -758,22 +758,22 @@ namespace // { RegistryEntry // { BuiltinRegistryEntry::RegistryEntry - ExpectedS BuiltinGitRegistryEntry::get_path_to_version(const VersionT& version) const + ExpectedS BuiltinGitRegistryEntry::get_path_to_version(const Version& version) const { auto it = std::find(port_versions.begin(), port_versions.end(), version); if (it == port_versions.end()) { - 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", - Strings::join("", - port_versions, - [](const VersionT& v) { return Strings::concat(" ", v, "\n"); }), - "\nSee `vcpkg help versioning` for more information."), - expected_right_tag}; + 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", + Strings::join("", port_versions, [](const Version& v) { return Strings::concat(" ", v, "\n"); }), + "\nSee `vcpkg help versioning` for more information."), + expected_right_tag}; } const auto& git_tree = git_trees[it - port_versions.begin()]; @@ -782,7 +782,7 @@ namespace // } BuiltinRegistryEntry::RegistryEntry // { FilesystemRegistryEntry::RegistryEntry - ExpectedS FilesystemRegistryEntry::get_path_to_version(const VersionT& version) const + ExpectedS FilesystemRegistryEntry::get_path_to_version(const Version& version) const { auto it = std::find(port_versions.begin(), port_versions.end(), version); if (it == port_versions.end()) @@ -794,7 +794,7 @@ namespace // } FilesystemRegistryEntry::RegistryEntry // { GitRegistryEntry::RegistryEntry - View GitRegistryEntry::get_port_versions() const + View GitRegistryEntry::get_port_versions() const { if (stale) { @@ -803,7 +803,7 @@ namespace } return port_versions; } - ExpectedS GitRegistryEntry::get_path_to_version(const VersionT& version) const + ExpectedS GitRegistryEntry::get_path_to_version(const Version& version) const { auto it = std::find(port_versions.begin(), port_versions.end(), version); if (it == port_versions.end() && stale) @@ -814,16 +814,16 @@ namespace } if (it == port_versions.end()) { - return {Strings::concat("Error: No version entry for ", - port_name, - " at version ", - version, - ".\nAvailable versions:\n", - Strings::join("", - port_versions, - [](const VersionT& v) { return Strings::concat(" ", v, "\n"); }), - "\nSee `vcpkg help versioning` for more information."), - expected_right_tag}; + return { + Strings::concat( + "Error: No version entry for ", + port_name, + " at version ", + version, + ".\nAvailable versions:\n", + Strings::join("", port_versions, [](const Version& v) { return Strings::concat(" ", v, "\n"); }), + "\nSee `vcpkg help versioning` for more information."), + expected_right_tag}; } const auto& git_tree = git_trees[it - port_versions.begin()]; @@ -854,18 +854,18 @@ namespace { using namespace vcpkg; - struct BaselineDeserializer final : Json::IDeserializer>> + struct BaselineDeserializer final : Json::IDeserializer>> { StringView type_name() const override { return "a baseline object"; } Optional visit_object(Json::Reader& r, const Json::Object& obj) override { - std::map> result; + std::map> result; for (auto pr : obj) { const auto& version_value = pr.second; - VersionT version; + Version version; r.visit_in_key(version_value, pr.first, version, get_versiontag_deserializer_instance()); result.emplace(pr.first.to_string(), std::move(version)); @@ -969,7 +969,7 @@ namespace } Json::Reader r; - std::map> result; + std::map> result; r.visit_in_key(*baseline_value, real_baseline, result, BaselineDeserializer::instance); if (r.errors().empty()) { @@ -1004,6 +1004,8 @@ namespace Optional RegistryImplementation::get_path_to_baseline_version(StringView port_name) const { + // This code does not defend against the files in the baseline not matching the declared baseline version. + // However, this is only used by `Paragraphs::try_load_all_registry_ports` so it is not high-impact const auto baseline_version = this->get_baseline_version(port_name); if (auto b = baseline_version.get()) { @@ -1040,7 +1042,7 @@ namespace vcpkg auto schemed_version = visit_required_schemed_deserializer(type_name(), r, obj); ret.scheme = schemed_version.scheme; - ret.version = std::move(schemed_version.versiont); + ret.version = std::move(schemed_version.version); static Json::StringDeserializer git_tree_deserializer("a git object SHA"); static Json::StringDeserializer path_deserializer("a registry path"); @@ -1189,7 +1191,7 @@ namespace vcpkg return default_registry(); } - Optional RegistrySet::baseline_for_port(StringView port_name) const + Optional RegistrySet::baseline_for_port(StringView port_name) const { auto impl = registry_for_port(port_name); if (!impl) return nullopt; diff --git a/src/vcpkg/sourceparagraph.cpp b/src/vcpkg/sourceparagraph.cpp index 66d4a4eb30..a5e14805f8 100644 --- a/src/vcpkg/sourceparagraph.cpp +++ b/src/vcpkg/sourceparagraph.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -16,6 +17,85 @@ #include #include +namespace +{ + namespace msg = vcpkg::msg; + DECLARE_AND_REGISTER_MESSAGE(EmptyLicenseExpression, (), "", "SPDX license expression was empty."); + DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionContainsUnicode, + (msg::value, msg::pretty_value), + "", + "SPDX license expression contains a unicode character (U+{value:04x} " + "'{pretty_value}'), but these expressions are ASCII-only."); + DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionContainsInvalidCharacter, + (msg::value), + "", + "SPDX license expression contains an invalid character (0x{value:02x} '{value}')."); + DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionContainsExtraPlus, + (), + "", + "SPDX license expression contains an extra '+'. These are only allowed directly " + "after a license identifier."); + DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionDocumentRefUnsupported, + (), + "", + "The current implementation does not support DocumentRef- SPDX references."); + DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionExpectLicenseFoundEof, + (), + "", + "Expected a license name, found the end of the string."); + DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionExpectExceptionFoundEof, + (), + "", + "Expected an exception name, found the end of the string."); + DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionExpectCompoundFoundParen, + (), + "", + "Expected a compound or the end of the string, found a parenthesis."); + DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionExpectLicenseFoundParen, + (), + "", + "Expected a license name, found a parenthesis."); + DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionExpectExceptionFoundParen, + (), + "", + "Expected an exception name, found a parenthesis."); + DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionImbalancedParens, + (), + "", + "There was a close parenthesis without an opening parenthesis."); + DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionExpectLicenseFoundCompound, + (msg::value), + "", + "Expected a license name, found the compound {value}."); + DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionExpectExceptionFoundCompound, + (msg::value), + "", + "Expected an exception name, found the compound {value}."); + DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionExpectCompoundFoundWith, + (), + "", + "Expected either AND or OR, found WITH (WITH is only allowed after license names, not " + "parenthesized expressions)."); + DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionExpectCompoundOrWithFoundWord, + (msg::value), + "", + "Expected either AND, OR, or WITH, found a license or exception name: '{value}'."); + DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionExpectCompoundFoundWord, + (msg::value), + "", + "Expected either AND or OR, found a license or exception name: '{value}'."); + DECLARE_AND_REGISTER_MESSAGE( + LicenseExpressionUnknownLicense, + (msg::value), + "", + "Unknown license identifier '{value}'. Known values are listed at https://spdx.org/licenses/"); + DECLARE_AND_REGISTER_MESSAGE(LicenseExpressionUnknownException, + (msg::value), + "", + "Unknown license exception identifier '{value}'. Known values are listed at " + "https://spdx.org/licenses/exceptions-index.html"); +} // anonymous namespace + namespace vcpkg { using namespace vcpkg::Parse; @@ -32,7 +112,7 @@ namespace vcpkg bool operator==(const SourceParagraph& lhs, const SourceParagraph& rhs) { if (lhs.name != rhs.name) return false; - if (lhs.version != rhs.version) return false; + if (lhs.raw_version != rhs.raw_version) return false; if (lhs.version_scheme != rhs.version_scheme) return false; if (lhs.port_version != rhs.port_version) return false; if (!paragraph_equal(lhs.description, rhs.description)) return false; @@ -256,7 +336,7 @@ namespace vcpkg auto spgh = std::make_unique(); parser.required_field(SourceParagraphFields::NAME, spgh->name); - parser.required_field(SourceParagraphFields::VERSION, spgh->version); + parser.required_field(SourceParagraphFields::VERSION, spgh->raw_version); auto pv_str = parser.optional_field(SourceParagraphFields::PORT_VERSION); if (!pv_str.empty()) @@ -498,7 +578,7 @@ namespace vcpkg if (has_ge_constraint) { - dep.constraint.type = Versions::Constraint::Type::Minimum; + dep.constraint.type = VersionConstraintKind::Minimum; auto h = dep.constraint.value.find('#'); if (h != std::string::npos) { @@ -565,15 +645,15 @@ namespace vcpkg const Json::Object& obj, std::string& name, std::string& version, - Versions::Scheme& version_scheme, + VersionScheme& version_scheme, int& port_version) { r.required_object_field(type_name, obj, NAME, name, Json::IdentifierDeserializer::instance); auto schemed_version = visit_required_schemed_deserializer(type_name, r, obj, true); - version = schemed_version.versiont.text(); + version = schemed_version.version.text(); version_scheme = schemed_version.scheme; - port_version = schemed_version.versiont.port_version(); + port_version = schemed_version.version.port_version(); } virtual Optional visit_object(Json::Reader& r, const Json::Object& obj) override @@ -708,143 +788,253 @@ namespace vcpkg }; ContactsDeserializer ContactsDeserializer::instance; - static constexpr StringLiteral EXPRESSION_WORDS[] = { - "WITH", - "AND", - "OR", - }; - static constexpr StringLiteral VALID_LICENSES[] = -#include "spdx-licenses.inc" - ; - static constexpr StringLiteral VALID_EXCEPTIONS[] = + static constexpr StringLiteral VALID_LICENSES[] = { #include "spdx-licenses.inc" - ; + }; + static constexpr StringLiteral VALID_EXCEPTIONS[] = { +#include "spdx-exceptions.inc" + }; - // We "parse" this so that we can add actual license parsing at some point in the future - // without breaking anyone - struct LicenseExpressionDeserializer : Json::IDeserializer + // The "license" field; either: + // * a string, which must be an SPDX license expression. + // EBNF located at: https://github.com/microsoft/vcpkg/blob/master/docs/maintainers/manifest-files.md#license + // * `null`, for when the license of the package cannot be described by an SPDX expression + struct SpdxLicenseExpressionParser : Parse::ParserBase { - virtual StringView type_name() const override { return "an SPDX license expression"; } + SpdxLicenseExpressionParser(StringView sv, StringView origin) : Parse::ParserBase(sv, origin) { } - enum class Mode + static const StringLiteral* case_insensitive_find(View lst, StringView id) { - ExpectExpression, - ExpectContinue, - ExpectException, + return Util::find_if(lst, + [id](StringLiteral el) { return Strings::case_insensitive_ascii_equals(id, el); }); + } + static constexpr bool is_idstring_element(char32_t ch) { return is_alphanumdash(ch) || ch == '.'; } + + enum class Expecting + { + License, // at the beginning, or after a compound (AND, OR) + Exception, // after a WITH + CompoundOrWith, // after a license + Compound, // after an exception (only one WITH is allowed), or after a close paren }; - virtual Optional visit_string(Json::Reader&, StringView sv) override + void eat_idstring(std::string& result, Expecting& expecting) { - Mode mode = Mode::ExpectExpression; - size_t open_parens = 0; - std::string current_word; + auto loc = cur_loc(); + auto token = match_zero_or_more(is_idstring_element); - const auto check_current_word = [¤t_word, &mode] { - if (current_word.empty()) + if (Strings::starts_with(token, "DocumentRef-")) + { + add_error(msg::format(msgLicenseExpressionDocumentRefUnsupported), loc); + if (cur() == ':') { - return true; + next(); } - - Span valid_ids; - bool case_sensitive = false; - switch (mode) + return; + } + else if (token == "AND" || token == "OR" || token == "WITH") + { + if (expecting == Expecting::License) { - case Mode::ExpectExpression: - valid_ids = VALID_LICENSES; - mode = Mode::ExpectContinue; - // a single + is allowed on the end of licenses - if (current_word.back() == '+') - { - current_word.pop_back(); - } - break; - case Mode::ExpectContinue: - valid_ids = EXPRESSION_WORDS; - mode = Mode::ExpectExpression; - case_sensitive = true; - break; - case Mode::ExpectException: - valid_ids = VALID_EXCEPTIONS; - mode = Mode::ExpectContinue; - break; + add_error(msg::format(msgLicenseExpressionExpectLicenseFoundCompound, msg::value = token), loc); + } + if (expecting == Expecting::Exception) + { + add_error(msg::format(msgLicenseExpressionExpectExceptionFoundCompound, msg::value = token), loc); } - const auto equal = [&](StringView sv) { - if (case_sensitive) - { - return sv == current_word; - } - else + if (token == "WITH") + { + if (expecting == Expecting::Compound) { - return Strings::case_insensitive_ascii_equals(sv, current_word); + add_error(msg::format(msgLicenseExpressionExpectCompoundFoundWith), loc); } - }; - - if (std::find_if(valid_ids.begin(), valid_ids.end(), equal) == valid_ids.end()) - { - return false; + expecting = Expecting::Exception; } - - if (current_word == "WITH") + else { - mode = Mode::ExpectException; + expecting = Expecting::License; } - current_word.clear(); - return true; - }; + result.push_back(' '); + result.append(token.begin(), token.end()); + result.push_back(' '); + return; + } - for (const auto& ch : sv) + switch (expecting) { - if (ch == ' ' || ch == '\t') - { - if (!check_current_word()) + case Expecting::Compound: + add_error(msg::format(msgLicenseExpressionExpectCompoundFoundWord, msg::value = token), loc); + break; + case Expecting::CompoundOrWith: + add_error(msg::format(msgLicenseExpressionExpectCompoundOrWithFoundWord, msg::value = token), loc); + break; + case Expecting::License: + if (Strings::starts_with(token, "LicenseRef-")) { - return nullopt; + result.append(token.begin(), token.end()); } - } - else if (ch == '(') - { - if (!check_current_word()) - { - return nullopt; - } - if (mode != Mode::ExpectExpression) - { - return nullopt; - } - ++open_parens; - } - else if (ch == ')') - { - if (!check_current_word()) + else { - return nullopt; + auto it = case_insensitive_find(VALID_LICENSES, token); + if (it != std::end(VALID_LICENSES)) + { + result.append(it->begin(), it->end()); + } + else + { + add_warning(msg::format(msgLicenseExpressionUnknownLicense, msg::value = token), loc); + result.append(token.begin(), token.end()); + } + + if (cur() == '+') + { + next(); + result.push_back('+'); + } } - if (mode != Mode::ExpectContinue) + expecting = Expecting::CompoundOrWith; + break; + case Expecting::Exception: + auto it = case_insensitive_find(VALID_EXCEPTIONS, token); + if (it != std::end(VALID_EXCEPTIONS)) { - return nullopt; + // case normalization + result.append(it->begin(), it->end()); } - if (open_parens == 0) + else { - return nullopt; + add_warning(msg::format(msgLicenseExpressionUnknownException, msg::value = token), loc); + result.append(token.begin(), token.end()); } - --open_parens; - } - else + expecting = Expecting::Compound; + break; + } + } + + std::string parse() + { + if (cur() == Unicode::end_of_file) + { + add_error(msg::format(msgEmptyLicenseExpression)); + return ""; + } + + Expecting expecting = Expecting::License; + std::string result; + + size_t open_parens = 0; + while (!at_eof()) + { + skip_whitespace(); + switch (cur()) { - current_word.push_back(ch); + case '(': + if (expecting == Expecting::Compound || expecting == Expecting::CompoundOrWith) + { + add_error(msg::format(msgLicenseExpressionExpectCompoundFoundParen)); + } + if (expecting == Expecting::Exception) + { + add_error(msg::format(msgLicenseExpressionExpectExceptionFoundParen)); + } + result.push_back('('); + expecting = Expecting::License; + ++open_parens; + next(); + break; + case ')': + if (expecting == Expecting::License) + { + add_error(msg::format(msgLicenseExpressionExpectLicenseFoundParen)); + } + else if (expecting == Expecting::Exception) + { + add_error(msg::format(msgLicenseExpressionExpectExceptionFoundParen)); + } + if (open_parens == 0) + { + add_error(msg::format(msgLicenseExpressionImbalancedParens)); + } + result.push_back(')'); + expecting = Expecting::Compound; + --open_parens; + next(); + break; + case '+': + add_error(msg::format(msgLicenseExpressionContainsExtraPlus)); + next(); + break; + default: + if (cur() > 0x7F) + { + auto ch = cur(); + auto first = it().pointer_to_current(); + next(); + auto last = it().pointer_to_current(); + add_error(msg::format(msgLicenseExpressionContainsUnicode, + msg::value = ch, + msg::pretty_value = StringView{first, last})); + break; + } + if (!is_idstring_element(cur())) + { + add_error(msg::format(msgLicenseExpressionContainsInvalidCharacter, + msg::value = static_cast(cur()))); + next(); + break; + } + eat_idstring(result, expecting); + break; } } - if (!check_current_word()) + if (expecting == Expecting::License) { - return nullopt; + add_error(msg::format(msgLicenseExpressionExpectLicenseFoundEof)); } - else + if (expecting == Expecting::Exception) + { + add_error(msg::format(msgLicenseExpressionExpectExceptionFoundEof)); + } + + return result; + } + }; + + std::string parse_spdx_license_expression(StringView sv, Parse::ParseMessages& messages) + { + auto parser = SpdxLicenseExpressionParser(sv, ""); + auto result = parser.parse(); + messages = parser.extract_messages(); + return result; + } + + struct LicenseExpressionDeserializer : Json::IDeserializer + { + virtual StringView type_name() const override { return "an SPDX license expression"; } + + virtual Optional visit_null(Json::Reader&) override { return {std::string()}; } + + // if `sv` is a valid SPDX license expression, returns sv, + // but with whitespace normalized + virtual Optional visit_string(Json::Reader& r, StringView sv) override + { + auto parser = SpdxLicenseExpressionParser(sv, ""); + auto res = parser.parse(); + + for (const auto& warning : parser.messages().warnings) + { + msg::println(Color::warning, warning.format("", Parse::MessageKind::Warning)); + } + if (auto err = parser.get_error()) { - return sv.to_string(); + r.add_generic_error(type_name(), err->format()); + return std::string(); } + + return res; } static LicenseExpressionDeserializer instance; @@ -931,9 +1121,9 @@ namespace vcpkg static Json::StringDeserializer url_deserializer{"a url"}; r.required_object_field(type_name(), obj, NAME, spgh->name, Json::IdentifierDeserializer::instance); auto schemed_version = visit_required_schemed_deserializer(type_name(), r, obj, false); - spgh->version = schemed_version.versiont.text(); + spgh->raw_version = schemed_version.version.text(); spgh->version_scheme = schemed_version.scheme; - spgh->port_version = schemed_version.versiont.port_version(); + spgh->port_version = schemed_version.version.port_version(); r.optional_object_field(obj, MAINTAINERS, spgh->maintainers, Json::ParagraphDeserializer::instance); r.optional_object_field(obj, CONTACTS, spgh->contacts, ContactsDeserializer::instance); @@ -941,7 +1131,13 @@ namespace vcpkg r.optional_object_field(obj, DESCRIPTION, spgh->description, Json::ParagraphDeserializer::instance); r.optional_object_field(obj, HOMEPAGE, spgh->homepage, url_deserializer); r.optional_object_field(obj, DOCUMENTATION, spgh->documentation, url_deserializer); - r.optional_object_field(obj, LICENSE, spgh->license, LicenseExpressionDeserializer::instance); + + std::string license; + if (r.optional_object_field(obj, LICENSE, license, LicenseExpressionDeserializer::instance)) + { + spgh->license = {std::move(license)}; + } + r.optional_object_field(obj, DEPENDENCIES, spgh->dependencies, DependencyArrayDeserializer::instance); static Json::ArrayDeserializer overrides_deserializer{ "an array of overrides"}; @@ -1114,7 +1310,7 @@ namespace vcpkg auto check_deps = [&](View deps) -> Optional { for (auto&& dep : deps) { - if (dep.constraint.type != Versions::Constraint::Type::None) + if (dep.constraint.type != VersionConstraintKind::None) { LockGuardPtr(g_metrics)->track_property("error-versioning-disabled", "defined"); return Strings::concat( @@ -1160,7 +1356,7 @@ namespace vcpkg if (std::any_of(core_paragraph->dependencies.begin(), core_paragraph->dependencies.end(), [](const auto& dependency) { - return dependency.constraint.type != Versions::Constraint::Type::None; + return dependency.constraint.type != VersionConstraintKind::None; })) { LockGuardPtr(g_metrics)->track_property("error-versioning-no-baseline", "defined"); @@ -1326,7 +1522,7 @@ namespace vcpkg static bool is_dependency_trivial(const Dependency& dep) { return dep.features.empty() && dep.platform.is_empty() && dep.extra_info.is_empty() && - dep.constraint.type == Versions::Constraint::Type::None && !dep.host; + dep.constraint.type == VersionConstraintKind::None && !dep.host; } static Json::Object serialize_manifest_impl(const SourceControlFile& scf, bool debug) @@ -1398,7 +1594,7 @@ 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.type == Versions::Constraint::Type::Minimum) + if (dep.constraint.type == VersionConstraintKind::Minimum) { auto s = dep.constraint.value; if (dep.constraint.port_version != 0) @@ -1450,7 +1646,7 @@ namespace vcpkg serialize_schemed_version(obj, scf.core_paragraph->version_scheme, - scf.core_paragraph->version, + scf.core_paragraph->raw_version, scf.core_paragraph->port_version, debug); @@ -1464,7 +1660,21 @@ namespace vcpkg serialize_optional_string(obj, ManifestDeserializer::HOMEPAGE, scf.core_paragraph->homepage); serialize_optional_string(obj, ManifestDeserializer::DOCUMENTATION, scf.core_paragraph->documentation); - serialize_optional_string(obj, ManifestDeserializer::LICENSE, scf.core_paragraph->license); + if (auto license = scf.core_paragraph->license.get()) + { + if (license->empty()) + { + obj.insert(ManifestDeserializer::LICENSE, Json::Value::null(nullptr)); + } + else + { + obj.insert(ManifestDeserializer::LICENSE, Json::Value::string(*license)); + } + } + else if (debug) + { + obj.insert(ManifestDeserializer::LICENSE, Json::Value::string("")); + } serialize_optional_string( obj, ManifestDeserializer::SUPPORTS, to_string(scf.core_paragraph->supports_expression)); if (scf.core_paragraph->builtin_baseline.has_value()) diff --git a/src/vcpkg/spdx-exceptions.inc b/src/vcpkg/spdx-exceptions.inc index c89465c5e0..36d4ec9670 100644 --- a/src/vcpkg/spdx-exceptions.inc +++ b/src/vcpkg/spdx-exceptions.inc @@ -1,45 +1,43 @@ // Data downloaded from https://raw.githubusercontent.com/spdx/license-list-data/0af22f869f8b0906097cfac90ee0516992e8939f/json/exceptions.json -// Generated by scripts/Generate-SpdxLicenseList.ps1 -{ - "389-exception", - "Autoconf-exception-2.0", - "Autoconf-exception-3.0", - "Bison-exception-2.2", - "Bootloader-exception", - "Classpath-exception-2.0", - "CLISP-exception-2.0", - "DigiRule-FOSS-exception", - "eCos-exception-2.0", - "Fawkes-Runtime-exception", - "FLTK-exception", - "Font-exception-2.0", - "freertos-exception-2.0", - "GCC-exception-2.0", - "GCC-exception-3.1", - "gnu-javamail-exception", - "GPL-3.0-linking-exception", - "GPL-3.0-linking-source-exception", - "GPL-CC-1.0", - "i2p-gpl-java-exception", - "LGPL-3.0-linking-exception", - "Libtool-exception", - "Linux-syscall-note", - "LLVM-exception", - "LZMA-exception", - "mif-exception", - "Nokia-Qt-exception-1.1", - "OCaml-LGPL-linking-exception", - "OCCT-exception-1.0", - "OpenJDK-assembly-exception-1.0", - "openvpn-openssl-exception", - "PS-or-PDF-font-exception-20170817", - "Qt-GPL-exception-1.0", - "Qt-LGPL-exception-1.1", - "Qwt-exception-1.0", - "SHL-2.0", - "SHL-2.1", - "Swift-exception", - "u-boot-exception-2.0", - "Universal-FOSS-exception-1.0", - "WxWindows-exception-3.1", -} +// Generated by Generate-SpdxLicenseList.ps1 +"389-exception", +"Autoconf-exception-2.0", +"Autoconf-exception-3.0", +"Bison-exception-2.2", +"Bootloader-exception", +"Classpath-exception-2.0", +"CLISP-exception-2.0", +"DigiRule-FOSS-exception", +"eCos-exception-2.0", +"Fawkes-Runtime-exception", +"FLTK-exception", +"Font-exception-2.0", +"freertos-exception-2.0", +"GCC-exception-2.0", +"GCC-exception-3.1", +"gnu-javamail-exception", +"GPL-3.0-linking-exception", +"GPL-3.0-linking-source-exception", +"GPL-CC-1.0", +"i2p-gpl-java-exception", +"LGPL-3.0-linking-exception", +"Libtool-exception", +"Linux-syscall-note", +"LLVM-exception", +"LZMA-exception", +"mif-exception", +"Nokia-Qt-exception-1.1", +"OCaml-LGPL-linking-exception", +"OCCT-exception-1.0", +"OpenJDK-assembly-exception-1.0", +"openvpn-openssl-exception", +"PS-or-PDF-font-exception-20170817", +"Qt-GPL-exception-1.0", +"Qt-LGPL-exception-1.1", +"Qwt-exception-1.0", +"SHL-2.0", +"SHL-2.1", +"Swift-exception", +"u-boot-exception-2.0", +"Universal-FOSS-exception-1.0", +"WxWindows-exception-3.1", diff --git a/src/vcpkg/spdx-licenses.inc b/src/vcpkg/spdx-licenses.inc index 76ff65a1c5..c947223589 100644 --- a/src/vcpkg/spdx-licenses.inc +++ b/src/vcpkg/spdx-licenses.inc @@ -1,479 +1,477 @@ // Data downloaded from https://raw.githubusercontent.com/spdx/license-list-data/0af22f869f8b0906097cfac90ee0516992e8939f/json/licenses.json -// Generated by scripts/Generate-SpdxLicenseList.ps1 -{ - "0BSD", - "AAL", - "Abstyles", - "Adobe-2006", - "Adobe-Glyph", - "ADSL", - "AFL-1.1", - "AFL-1.2", - "AFL-2.0", - "AFL-2.1", - "AFL-3.0", - "Afmparse", - "AGPL-1.0", - "AGPL-1.0-only", - "AGPL-1.0-or-later", - "AGPL-3.0", - "AGPL-3.0-only", - "AGPL-3.0-or-later", - "Aladdin", - "AMDPLPA", - "AML", - "AMPAS", - "ANTLR-PD", - "ANTLR-PD-fallback", - "Apache-1.0", - "Apache-1.1", - "Apache-2.0", - "APAFML", - "APL-1.0", - "APSL-1.0", - "APSL-1.1", - "APSL-1.2", - "APSL-2.0", - "Artistic-1.0", - "Artistic-1.0-cl8", - "Artistic-1.0-Perl", - "Artistic-2.0", - "Bahyph", - "Barr", - "Beerware", - "BitTorrent-1.0", - "BitTorrent-1.1", - "blessing", - "BlueOak-1.0.0", - "Borceux", - "BSD-1-Clause", - "BSD-2-Clause", - "BSD-2-Clause-FreeBSD", - "BSD-2-Clause-NetBSD", - "BSD-2-Clause-Patent", - "BSD-2-Clause-Views", - "BSD-3-Clause", - "BSD-3-Clause-Attribution", - "BSD-3-Clause-Clear", - "BSD-3-Clause-LBNL", - "BSD-3-Clause-Modification", - "BSD-3-Clause-No-Military-License", - "BSD-3-Clause-No-Nuclear-License", - "BSD-3-Clause-No-Nuclear-License-2014", - "BSD-3-Clause-No-Nuclear-Warranty", - "BSD-3-Clause-Open-MPI", - "BSD-4-Clause", - "BSD-4-Clause-Shortened", - "BSD-4-Clause-UC", - "BSD-Protection", - "BSD-Source-Code", - "BSL-1.0", - "BUSL-1.1", - "bzip2-1.0.5", - "bzip2-1.0.6", - "C-UDA-1.0", - "CAL-1.0", - "CAL-1.0-Combined-Work-Exception", - "Caldera", - "CATOSL-1.1", - "CC-BY-1.0", - "CC-BY-2.0", - "CC-BY-2.5", - "CC-BY-2.5-AU", - "CC-BY-3.0", - "CC-BY-3.0-AT", - "CC-BY-3.0-DE", - "CC-BY-3.0-NL", - "CC-BY-3.0-US", - "CC-BY-4.0", - "CC-BY-NC-1.0", - "CC-BY-NC-2.0", - "CC-BY-NC-2.5", - "CC-BY-NC-3.0", - "CC-BY-NC-3.0-DE", - "CC-BY-NC-4.0", - "CC-BY-NC-ND-1.0", - "CC-BY-NC-ND-2.0", - "CC-BY-NC-ND-2.5", - "CC-BY-NC-ND-3.0", - "CC-BY-NC-ND-3.0-DE", - "CC-BY-NC-ND-3.0-IGO", - "CC-BY-NC-ND-4.0", - "CC-BY-NC-SA-1.0", - "CC-BY-NC-SA-2.0", - "CC-BY-NC-SA-2.0-FR", - "CC-BY-NC-SA-2.0-UK", - "CC-BY-NC-SA-2.5", - "CC-BY-NC-SA-3.0", - "CC-BY-NC-SA-3.0-DE", - "CC-BY-NC-SA-3.0-IGO", - "CC-BY-NC-SA-4.0", - "CC-BY-ND-1.0", - "CC-BY-ND-2.0", - "CC-BY-ND-2.5", - "CC-BY-ND-3.0", - "CC-BY-ND-3.0-DE", - "CC-BY-ND-4.0", - "CC-BY-SA-1.0", - "CC-BY-SA-2.0", - "CC-BY-SA-2.0-UK", - "CC-BY-SA-2.1-JP", - "CC-BY-SA-2.5", - "CC-BY-SA-3.0", - "CC-BY-SA-3.0-AT", - "CC-BY-SA-3.0-DE", - "CC-BY-SA-4.0", - "CC-PDDC", - "CC0-1.0", - "CDDL-1.0", - "CDDL-1.1", - "CDL-1.0", - "CDLA-Permissive-1.0", - "CDLA-Permissive-2.0", - "CDLA-Sharing-1.0", - "CECILL-1.0", - "CECILL-1.1", - "CECILL-2.0", - "CECILL-2.1", - "CECILL-B", - "CECILL-C", - "CERN-OHL-1.1", - "CERN-OHL-1.2", - "CERN-OHL-P-2.0", - "CERN-OHL-S-2.0", - "CERN-OHL-W-2.0", - "ClArtistic", - "CNRI-Jython", - "CNRI-Python", - "CNRI-Python-GPL-Compatible", - "Condor-1.1", - "copyleft-next-0.3.0", - "copyleft-next-0.3.1", - "CPAL-1.0", - "CPL-1.0", - "CPOL-1.02", - "Crossword", - "CrystalStacker", - "CUA-OPL-1.0", - "Cube", - "curl", - "D-FSL-1.0", - "diffmark", - "DOC", - "Dotseqn", - "DRL-1.0", - "DSDP", - "dvipdfm", - "ECL-1.0", - "ECL-2.0", - "eCos-2.0", - "EFL-1.0", - "EFL-2.0", - "eGenix", - "Entessa", - "EPICS", - "EPL-1.0", - "EPL-2.0", - "ErlPL-1.1", - "etalab-2.0", - "EUDatagrid", - "EUPL-1.0", - "EUPL-1.1", - "EUPL-1.2", - "Eurosym", - "Fair", - "Frameworx-1.0", - "FreeBSD-DOC", - "FreeImage", - "FSFAP", - "FSFUL", - "FSFULLR", - "FTL", - "GD", - "GFDL-1.1", - "GFDL-1.1-invariants-only", - "GFDL-1.1-invariants-or-later", - "GFDL-1.1-no-invariants-only", - "GFDL-1.1-no-invariants-or-later", - "GFDL-1.1-only", - "GFDL-1.1-or-later", - "GFDL-1.2", - "GFDL-1.2-invariants-only", - "GFDL-1.2-invariants-or-later", - "GFDL-1.2-no-invariants-only", - "GFDL-1.2-no-invariants-or-later", - "GFDL-1.2-only", - "GFDL-1.2-or-later", - "GFDL-1.3", - "GFDL-1.3-invariants-only", - "GFDL-1.3-invariants-or-later", - "GFDL-1.3-no-invariants-only", - "GFDL-1.3-no-invariants-or-later", - "GFDL-1.3-only", - "GFDL-1.3-or-later", - "Giftware", - "GL2PS", - "Glide", - "Glulxe", - "GLWTPL", - "gnuplot", - "GPL-1.0", - "GPL-1.0-only", - "GPL-1.0-or-later", - "GPL-1.0+", - "GPL-2.0", - "GPL-2.0-only", - "GPL-2.0-or-later", - "GPL-2.0-with-autoconf-exception", - "GPL-2.0-with-bison-exception", - "GPL-2.0-with-classpath-exception", - "GPL-2.0-with-font-exception", - "GPL-2.0-with-GCC-exception", - "GPL-2.0+", - "GPL-3.0", - "GPL-3.0-only", - "GPL-3.0-or-later", - "GPL-3.0-with-autoconf-exception", - "GPL-3.0-with-GCC-exception", - "GPL-3.0+", - "gSOAP-1.3b", - "HaskellReport", - "Hippocratic-2.1", - "HPND", - "HPND-sell-variant", - "HTMLTIDY", - "IBM-pibs", - "ICU", - "IJG", - "ImageMagick", - "iMatix", - "Imlib2", - "Info-ZIP", - "Intel", - "Intel-ACPI", - "Interbase-1.0", - "IPA", - "IPL-1.0", - "ISC", - "JasPer-2.0", - "JPNIC", - "JSON", - "LAL-1.2", - "LAL-1.3", - "Latex2e", - "Leptonica", - "LGPL-2.0", - "LGPL-2.0-only", - "LGPL-2.0-or-later", - "LGPL-2.0+", - "LGPL-2.1", - "LGPL-2.1-only", - "LGPL-2.1-or-later", - "LGPL-2.1+", - "LGPL-3.0", - "LGPL-3.0-only", - "LGPL-3.0-or-later", - "LGPL-3.0+", - "LGPLLR", - "Libpng", - "libpng-2.0", - "libselinux-1.0", - "libtiff", - "LiLiQ-P-1.1", - "LiLiQ-R-1.1", - "LiLiQ-Rplus-1.1", - "Linux-OpenIB", - "LPL-1.0", - "LPL-1.02", - "LPPL-1.0", - "LPPL-1.1", - "LPPL-1.2", - "LPPL-1.3a", - "LPPL-1.3c", - "MakeIndex", - "MirOS", - "MIT", - "MIT-0", - "MIT-advertising", - "MIT-CMU", - "MIT-enna", - "MIT-feh", - "MIT-Modern-Variant", - "MIT-open-group", - "MITNFA", - "Motosoto", - "mpich2", - "MPL-1.0", - "MPL-1.1", - "MPL-2.0", - "MPL-2.0-no-copyleft-exception", - "MS-PL", - "MS-RL", - "MTLL", - "MulanPSL-1.0", - "MulanPSL-2.0", - "Multics", - "Mup", - "NAIST-2003", - "NASA-1.3", - "Naumen", - "NBPL-1.0", - "NCGL-UK-2.0", - "NCSA", - "Net-SNMP", - "NetCDF", - "Newsletr", - "NGPL", - "NIST-PD", - "NIST-PD-fallback", - "NLOD-1.0", - "NLOD-2.0", - "NLPL", - "Nokia", - "NOSL", - "Noweb", - "NPL-1.0", - "NPL-1.1", - "NPOSL-3.0", - "NRL", - "NTP", - "NTP-0", - "Nunit", - "O-UDA-1.0", - "OCCT-PL", - "OCLC-2.0", - "ODbL-1.0", - "ODC-By-1.0", - "OFL-1.0", - "OFL-1.0-no-RFN", - "OFL-1.0-RFN", - "OFL-1.1", - "OFL-1.1-no-RFN", - "OFL-1.1-RFN", - "OGC-1.0", - "OGDL-Taiwan-1.0", - "OGL-Canada-2.0", - "OGL-UK-1.0", - "OGL-UK-2.0", - "OGL-UK-3.0", - "OGTSL", - "OLDAP-1.1", - "OLDAP-1.2", - "OLDAP-1.3", - "OLDAP-1.4", - "OLDAP-2.0", - "OLDAP-2.0.1", - "OLDAP-2.1", - "OLDAP-2.2", - "OLDAP-2.2.1", - "OLDAP-2.2.2", - "OLDAP-2.3", - "OLDAP-2.4", - "OLDAP-2.5", - "OLDAP-2.6", - "OLDAP-2.7", - "OLDAP-2.8", - "OML", - "OpenSSL", - "OPL-1.0", - "OPUBL-1.0", - "OSET-PL-2.1", - "OSL-1.0", - "OSL-1.1", - "OSL-2.0", - "OSL-2.1", - "OSL-3.0", - "Parity-6.0.0", - "Parity-7.0.0", - "PDDL-1.0", - "PHP-3.0", - "PHP-3.01", - "Plexus", - "PolyForm-Noncommercial-1.0.0", - "PolyForm-Small-Business-1.0.0", - "PostgreSQL", - "PSF-2.0", - "psfrag", - "psutils", - "Python-2.0", - "Qhull", - "QPL-1.0", - "Rdisc", - "RHeCos-1.1", - "RPL-1.1", - "RPL-1.5", - "RPSL-1.0", - "RSA-MD", - "RSCPL", - "Ruby", - "SAX-PD", - "Saxpath", - "SCEA", - "Sendmail", - "Sendmail-8.23", - "SGI-B-1.0", - "SGI-B-1.1", - "SGI-B-2.0", - "SHL-0.5", - "SHL-0.51", - "SimPL-2.0", - "SISSL", - "SISSL-1.2", - "Sleepycat", - "SMLNJ", - "SMPPL", - "SNIA", - "Spencer-86", - "Spencer-94", - "Spencer-99", - "SPL-1.0", - "SSH-OpenSSH", - "SSH-short", - "SSPL-1.0", - "StandardML-NJ", - "SugarCRM-1.1.3", - "SWL", - "TAPR-OHL-1.0", - "TCL", - "TCP-wrappers", - "TMate", - "TORQUE-1.1", - "TOSL", - "TU-Berlin-1.0", - "TU-Berlin-2.0", - "UCL-1.0", - "Unicode-DFS-2015", - "Unicode-DFS-2016", - "Unicode-TOU", - "Unlicense", - "UPL-1.0", - "Verbatim-man-pages", - "Vim", - "VOSTROM", - "VSL-1.0", - "W3C", - "W3C-19980720", - "W3C-20150513", - "Watcom-1.0", - "Wsuipa", - "WTFPL", - "wxWindows", - "X11", - "Xerox", - "XFree86-1.1", - "xinetd", - "Xnet", - "xpp", - "XSkat", - "YPL-1.0", - "YPL-1.1", - "Zed", - "Zend-2.0", - "Zimbra-1.3", - "Zimbra-1.4", - "Zlib", - "zlib-acknowledgement", - "ZPL-1.1", - "ZPL-2.0", - "ZPL-2.1", -} +// Generated by Generate-SpdxLicenseList.ps1 +"0BSD", +"AAL", +"Abstyles", +"Adobe-2006", +"Adobe-Glyph", +"ADSL", +"AFL-1.1", +"AFL-1.2", +"AFL-2.0", +"AFL-2.1", +"AFL-3.0", +"Afmparse", +"AGPL-1.0", +"AGPL-1.0-only", +"AGPL-1.0-or-later", +"AGPL-3.0", +"AGPL-3.0-only", +"AGPL-3.0-or-later", +"Aladdin", +"AMDPLPA", +"AML", +"AMPAS", +"ANTLR-PD", +"ANTLR-PD-fallback", +"Apache-1.0", +"Apache-1.1", +"Apache-2.0", +"APAFML", +"APL-1.0", +"APSL-1.0", +"APSL-1.1", +"APSL-1.2", +"APSL-2.0", +"Artistic-1.0", +"Artistic-1.0-cl8", +"Artistic-1.0-Perl", +"Artistic-2.0", +"Bahyph", +"Barr", +"Beerware", +"BitTorrent-1.0", +"BitTorrent-1.1", +"blessing", +"BlueOak-1.0.0", +"Borceux", +"BSD-1-Clause", +"BSD-2-Clause", +"BSD-2-Clause-FreeBSD", +"BSD-2-Clause-NetBSD", +"BSD-2-Clause-Patent", +"BSD-2-Clause-Views", +"BSD-3-Clause", +"BSD-3-Clause-Attribution", +"BSD-3-Clause-Clear", +"BSD-3-Clause-LBNL", +"BSD-3-Clause-Modification", +"BSD-3-Clause-No-Military-License", +"BSD-3-Clause-No-Nuclear-License", +"BSD-3-Clause-No-Nuclear-License-2014", +"BSD-3-Clause-No-Nuclear-Warranty", +"BSD-3-Clause-Open-MPI", +"BSD-4-Clause", +"BSD-4-Clause-Shortened", +"BSD-4-Clause-UC", +"BSD-Protection", +"BSD-Source-Code", +"BSL-1.0", +"BUSL-1.1", +"bzip2-1.0.5", +"bzip2-1.0.6", +"C-UDA-1.0", +"CAL-1.0", +"CAL-1.0-Combined-Work-Exception", +"Caldera", +"CATOSL-1.1", +"CC-BY-1.0", +"CC-BY-2.0", +"CC-BY-2.5", +"CC-BY-2.5-AU", +"CC-BY-3.0", +"CC-BY-3.0-AT", +"CC-BY-3.0-DE", +"CC-BY-3.0-NL", +"CC-BY-3.0-US", +"CC-BY-4.0", +"CC-BY-NC-1.0", +"CC-BY-NC-2.0", +"CC-BY-NC-2.5", +"CC-BY-NC-3.0", +"CC-BY-NC-3.0-DE", +"CC-BY-NC-4.0", +"CC-BY-NC-ND-1.0", +"CC-BY-NC-ND-2.0", +"CC-BY-NC-ND-2.5", +"CC-BY-NC-ND-3.0", +"CC-BY-NC-ND-3.0-DE", +"CC-BY-NC-ND-3.0-IGO", +"CC-BY-NC-ND-4.0", +"CC-BY-NC-SA-1.0", +"CC-BY-NC-SA-2.0", +"CC-BY-NC-SA-2.0-FR", +"CC-BY-NC-SA-2.0-UK", +"CC-BY-NC-SA-2.5", +"CC-BY-NC-SA-3.0", +"CC-BY-NC-SA-3.0-DE", +"CC-BY-NC-SA-3.0-IGO", +"CC-BY-NC-SA-4.0", +"CC-BY-ND-1.0", +"CC-BY-ND-2.0", +"CC-BY-ND-2.5", +"CC-BY-ND-3.0", +"CC-BY-ND-3.0-DE", +"CC-BY-ND-4.0", +"CC-BY-SA-1.0", +"CC-BY-SA-2.0", +"CC-BY-SA-2.0-UK", +"CC-BY-SA-2.1-JP", +"CC-BY-SA-2.5", +"CC-BY-SA-3.0", +"CC-BY-SA-3.0-AT", +"CC-BY-SA-3.0-DE", +"CC-BY-SA-4.0", +"CC-PDDC", +"CC0-1.0", +"CDDL-1.0", +"CDDL-1.1", +"CDL-1.0", +"CDLA-Permissive-1.0", +"CDLA-Permissive-2.0", +"CDLA-Sharing-1.0", +"CECILL-1.0", +"CECILL-1.1", +"CECILL-2.0", +"CECILL-2.1", +"CECILL-B", +"CECILL-C", +"CERN-OHL-1.1", +"CERN-OHL-1.2", +"CERN-OHL-P-2.0", +"CERN-OHL-S-2.0", +"CERN-OHL-W-2.0", +"ClArtistic", +"CNRI-Jython", +"CNRI-Python", +"CNRI-Python-GPL-Compatible", +"Condor-1.1", +"copyleft-next-0.3.0", +"copyleft-next-0.3.1", +"CPAL-1.0", +"CPL-1.0", +"CPOL-1.02", +"Crossword", +"CrystalStacker", +"CUA-OPL-1.0", +"Cube", +"curl", +"D-FSL-1.0", +"diffmark", +"DOC", +"Dotseqn", +"DRL-1.0", +"DSDP", +"dvipdfm", +"ECL-1.0", +"ECL-2.0", +"eCos-2.0", +"EFL-1.0", +"EFL-2.0", +"eGenix", +"Entessa", +"EPICS", +"EPL-1.0", +"EPL-2.0", +"ErlPL-1.1", +"etalab-2.0", +"EUDatagrid", +"EUPL-1.0", +"EUPL-1.1", +"EUPL-1.2", +"Eurosym", +"Fair", +"Frameworx-1.0", +"FreeBSD-DOC", +"FreeImage", +"FSFAP", +"FSFUL", +"FSFULLR", +"FTL", +"GD", +"GFDL-1.1", +"GFDL-1.1-invariants-only", +"GFDL-1.1-invariants-or-later", +"GFDL-1.1-no-invariants-only", +"GFDL-1.1-no-invariants-or-later", +"GFDL-1.1-only", +"GFDL-1.1-or-later", +"GFDL-1.2", +"GFDL-1.2-invariants-only", +"GFDL-1.2-invariants-or-later", +"GFDL-1.2-no-invariants-only", +"GFDL-1.2-no-invariants-or-later", +"GFDL-1.2-only", +"GFDL-1.2-or-later", +"GFDL-1.3", +"GFDL-1.3-invariants-only", +"GFDL-1.3-invariants-or-later", +"GFDL-1.3-no-invariants-only", +"GFDL-1.3-no-invariants-or-later", +"GFDL-1.3-only", +"GFDL-1.3-or-later", +"Giftware", +"GL2PS", +"Glide", +"Glulxe", +"GLWTPL", +"gnuplot", +"GPL-1.0", +"GPL-1.0-only", +"GPL-1.0-or-later", +"GPL-1.0+", +"GPL-2.0", +"GPL-2.0-only", +"GPL-2.0-or-later", +"GPL-2.0-with-autoconf-exception", +"GPL-2.0-with-bison-exception", +"GPL-2.0-with-classpath-exception", +"GPL-2.0-with-font-exception", +"GPL-2.0-with-GCC-exception", +"GPL-2.0+", +"GPL-3.0", +"GPL-3.0-only", +"GPL-3.0-or-later", +"GPL-3.0-with-autoconf-exception", +"GPL-3.0-with-GCC-exception", +"GPL-3.0+", +"gSOAP-1.3b", +"HaskellReport", +"Hippocratic-2.1", +"HPND", +"HPND-sell-variant", +"HTMLTIDY", +"IBM-pibs", +"ICU", +"IJG", +"ImageMagick", +"iMatix", +"Imlib2", +"Info-ZIP", +"Intel", +"Intel-ACPI", +"Interbase-1.0", +"IPA", +"IPL-1.0", +"ISC", +"JasPer-2.0", +"JPNIC", +"JSON", +"LAL-1.2", +"LAL-1.3", +"Latex2e", +"Leptonica", +"LGPL-2.0", +"LGPL-2.0-only", +"LGPL-2.0-or-later", +"LGPL-2.0+", +"LGPL-2.1", +"LGPL-2.1-only", +"LGPL-2.1-or-later", +"LGPL-2.1+", +"LGPL-3.0", +"LGPL-3.0-only", +"LGPL-3.0-or-later", +"LGPL-3.0+", +"LGPLLR", +"Libpng", +"libpng-2.0", +"libselinux-1.0", +"libtiff", +"LiLiQ-P-1.1", +"LiLiQ-R-1.1", +"LiLiQ-Rplus-1.1", +"Linux-OpenIB", +"LPL-1.0", +"LPL-1.02", +"LPPL-1.0", +"LPPL-1.1", +"LPPL-1.2", +"LPPL-1.3a", +"LPPL-1.3c", +"MakeIndex", +"MirOS", +"MIT", +"MIT-0", +"MIT-advertising", +"MIT-CMU", +"MIT-enna", +"MIT-feh", +"MIT-Modern-Variant", +"MIT-open-group", +"MITNFA", +"Motosoto", +"mpich2", +"MPL-1.0", +"MPL-1.1", +"MPL-2.0", +"MPL-2.0-no-copyleft-exception", +"MS-PL", +"MS-RL", +"MTLL", +"MulanPSL-1.0", +"MulanPSL-2.0", +"Multics", +"Mup", +"NAIST-2003", +"NASA-1.3", +"Naumen", +"NBPL-1.0", +"NCGL-UK-2.0", +"NCSA", +"Net-SNMP", +"NetCDF", +"Newsletr", +"NGPL", +"NIST-PD", +"NIST-PD-fallback", +"NLOD-1.0", +"NLOD-2.0", +"NLPL", +"Nokia", +"NOSL", +"Noweb", +"NPL-1.0", +"NPL-1.1", +"NPOSL-3.0", +"NRL", +"NTP", +"NTP-0", +"Nunit", +"O-UDA-1.0", +"OCCT-PL", +"OCLC-2.0", +"ODbL-1.0", +"ODC-By-1.0", +"OFL-1.0", +"OFL-1.0-no-RFN", +"OFL-1.0-RFN", +"OFL-1.1", +"OFL-1.1-no-RFN", +"OFL-1.1-RFN", +"OGC-1.0", +"OGDL-Taiwan-1.0", +"OGL-Canada-2.0", +"OGL-UK-1.0", +"OGL-UK-2.0", +"OGL-UK-3.0", +"OGTSL", +"OLDAP-1.1", +"OLDAP-1.2", +"OLDAP-1.3", +"OLDAP-1.4", +"OLDAP-2.0", +"OLDAP-2.0.1", +"OLDAP-2.1", +"OLDAP-2.2", +"OLDAP-2.2.1", +"OLDAP-2.2.2", +"OLDAP-2.3", +"OLDAP-2.4", +"OLDAP-2.5", +"OLDAP-2.6", +"OLDAP-2.7", +"OLDAP-2.8", +"OML", +"OpenSSL", +"OPL-1.0", +"OPUBL-1.0", +"OSET-PL-2.1", +"OSL-1.0", +"OSL-1.1", +"OSL-2.0", +"OSL-2.1", +"OSL-3.0", +"Parity-6.0.0", +"Parity-7.0.0", +"PDDL-1.0", +"PHP-3.0", +"PHP-3.01", +"Plexus", +"PolyForm-Noncommercial-1.0.0", +"PolyForm-Small-Business-1.0.0", +"PostgreSQL", +"PSF-2.0", +"psfrag", +"psutils", +"Python-2.0", +"Qhull", +"QPL-1.0", +"Rdisc", +"RHeCos-1.1", +"RPL-1.1", +"RPL-1.5", +"RPSL-1.0", +"RSA-MD", +"RSCPL", +"Ruby", +"SAX-PD", +"Saxpath", +"SCEA", +"Sendmail", +"Sendmail-8.23", +"SGI-B-1.0", +"SGI-B-1.1", +"SGI-B-2.0", +"SHL-0.5", +"SHL-0.51", +"SimPL-2.0", +"SISSL", +"SISSL-1.2", +"Sleepycat", +"SMLNJ", +"SMPPL", +"SNIA", +"Spencer-86", +"Spencer-94", +"Spencer-99", +"SPL-1.0", +"SSH-OpenSSH", +"SSH-short", +"SSPL-1.0", +"StandardML-NJ", +"SugarCRM-1.1.3", +"SWL", +"TAPR-OHL-1.0", +"TCL", +"TCP-wrappers", +"TMate", +"TORQUE-1.1", +"TOSL", +"TU-Berlin-1.0", +"TU-Berlin-2.0", +"UCL-1.0", +"Unicode-DFS-2015", +"Unicode-DFS-2016", +"Unicode-TOU", +"Unlicense", +"UPL-1.0", +"Verbatim-man-pages", +"Vim", +"VOSTROM", +"VSL-1.0", +"W3C", +"W3C-19980720", +"W3C-20150513", +"Watcom-1.0", +"Wsuipa", +"WTFPL", +"wxWindows", +"X11", +"Xerox", +"XFree86-1.1", +"xinetd", +"Xnet", +"xpp", +"XSkat", +"YPL-1.0", +"YPL-1.1", +"Zed", +"Zend-2.0", +"Zimbra-1.3", +"Zimbra-1.4", +"Zlib", +"zlib-acknowledgement", +"ZPL-1.1", +"ZPL-2.0", +"ZPL-2.1", diff --git a/src/vcpkg/tools.cpp b/src/vcpkg/tools.cpp index 2b068a30f4..2334326956 100644 --- a/src/vcpkg/tools.cpp +++ b/src/vcpkg/tools.cpp @@ -316,7 +316,10 @@ cmake version 3.10.2 CMake suite maintained and supported by Kitware (kitware.com/cmake). */ - return {Strings::find_exactly_one_enclosed(rc.output, "cmake version ", "\n").to_string(), + + // There are two expected output formats to handle: "cmake3 version x.x.x" and "cmake version x.x.x" + auto simplifiedOutput = Strings::replace_all(rc.output, "cmake3", "cmake"); + return {Strings::find_exactly_one_enclosed(simplifiedOutput, "cmake version ", "\n").to_string(), expected_left_tag}; } }; diff --git a/src/vcpkg/update.cpp b/src/vcpkg/update.cpp index c4e7a6cd92..0b2c179645 100644 --- a/src/vcpkg/update.cpp +++ b/src/vcpkg/update.cpp @@ -29,8 +29,8 @@ namespace vcpkg::Update if (auto p_scfl = maybe_scfl.get()) { const auto& latest_pgh = *p_scfl->source_control_file->core_paragraph; - auto latest_version = VersionT(latest_pgh.version, latest_pgh.port_version); - auto installed_version = VersionT(pgh->package.version, pgh->package.port_version); + auto latest_version = Version(latest_pgh.raw_version, latest_pgh.port_version); + auto installed_version = Version(pgh->package.version, pgh->package.port_version); if (latest_version != installed_version) { output.push_back( diff --git a/src/vcpkg/vcpkgpaths.cpp b/src/vcpkg/vcpkgpaths.cpp index 97ef973de5..80055b4366 100644 --- a/src/vcpkg/vcpkgpaths.cpp +++ b/src/vcpkg/vcpkgpaths.cpp @@ -263,59 +263,258 @@ namespace vcpkg } } - struct VcpkgPathsImpl + struct BundleSettings { - VcpkgPathsImpl(Filesystem& fs, FeatureFlagSettings ff_settings, RequireExactVersions abiToolsHandling) - : fs_ptr(&fs) - , m_tool_cache(get_tool_cache(abiToolsHandling)) - , m_env_cache(ff_settings.compiler_tracking) - , m_ff_settings(ff_settings) + bool m_readonly = false; + bool m_usegitregistry = false; + Optional m_embedded_git_sha; + }; + + static details::BundleSettings load_bundle_file(const Filesystem& fs, const Path& root) + { + details::BundleSettings ret; + const auto vcpkg_bundle_file = root / "vcpkg-bundle.json"; + std::error_code ec; + auto bundle_file = fs.read_contents(vcpkg_bundle_file, ec); + if (!ec) + { + auto maybe_bundle_doc = Json::parse(bundle_file, bundle_file); + if (auto bundle_doc = maybe_bundle_doc.get()) + { + const auto& first_object = bundle_doc->first.object(); + if (auto v = first_object.get("readonly")) + { + ret.m_readonly = v->boolean(); + } + + if (auto v = first_object.get("usegitregistry")) + { + ret.m_usegitregistry = v->boolean(); + } + + if (auto v = first_object.get("embeddedsha")) + { + ret.m_embedded_git_sha = v->string().to_string(); + } + } + else + { + print2(Color::error, "Error: Invalid bundle definition.\n", maybe_bundle_doc.error()->format()); + Checks::exit_fail(VCPKG_LINE_INFO); + } + } + return ret; + } + + static Optional maybe_get_tmp_path(const Filesystem& fs, + const details::BundleSettings& bundle, + const Optional& installed, + const Path& root, + const std::string* arg_path, + StringLiteral root_subpath, + StringLiteral readonly_subpath, + LineInfo li) + { + if (arg_path) { - const auto& cache_root = default_registries_cache_path().value_or_exit(VCPKG_LINE_INFO); - registries_work_tree_dir = cache_root / "git"; - registries_dot_git_dir = registries_work_tree_dir / ".git"; - registries_git_trees = cache_root / "git-trees"; + return fs.almost_canonical(*arg_path, li); } + else if (bundle.m_readonly) + { + if (auto i = installed.get()) + { + return fs.almost_canonical(i->vcpkg_dir() / readonly_subpath, li); + } + else + { + return nullopt; + } + } + else + { + return fs.almost_canonical(root / root_subpath, li); + } + } + + static Path compute_manifest_dir(const Filesystem& fs, const VcpkgCmdArguments& args, const Path& original_cwd) + { + if (args.manifests_enabled()) + { + if (args.manifest_root_dir) + { + return fs.almost_canonical(*args.manifest_root_dir, VCPKG_LINE_INFO); + } + else + { + return fs.find_file_recursively_up(original_cwd, "vcpkg.json", VCPKG_LINE_INFO); + } + } + return {}; + } + // This structure holds members for VcpkgPathsImpl that don't require explicit initialization/destruction + struct VcpkgPathsImplStage0 + { Lazy> available_triplets; Lazy toolsets; Lazy> cmake_script_hashes; Lazy ports_cmake_hash; + Cache m_triplets_cache; + Optional m_installed_lock; + }; - Filesystem* fs_ptr; + // This structure holds members that + // 1. Do not have any inter-member dependencies + // 2. Are const (and therefore initialized in the initializer list) + struct VcpkgPathsImplStage1 : VcpkgPathsImplStage0 + { + VcpkgPathsImplStage1(Filesystem& fs, + const VcpkgCmdArguments& args, + const Path& root, + const Path& original_cwd) + : m_fs(fs) + , m_ff_settings(args.feature_flag_settings()) + , m_cache_root(default_registries_cache_path().value_or_exit(VCPKG_LINE_INFO)) + , m_manifest_dir(compute_manifest_dir(fs, args, original_cwd)) + , m_bundle(load_bundle_file(fs, root)) + , m_tool_cache(get_tool_cache(args.exact_abi_tools_versions.value_or(false) ? RequireExactVersions::YES + : RequireExactVersions::NO)) + , m_download_manager( + parse_download_configuration(args.asset_sources_template()).value_or_exit(VCPKG_LINE_INFO)) + , m_builtin_ports(process_output_directory(fs, args.builtin_ports_root_dir.get(), root / "ports")) + , m_default_vs_path(args.default_visual_studio_path + ? fs.almost_canonical(*args.default_visual_studio_path, VCPKG_LINE_INFO) + : Path{}) + { + Debug::print("Bundle config: readonly=", + m_bundle.m_readonly, + ", usegitregistry=", + m_bundle.m_usegitregistry, + ", embeddedsha=", + m_bundle.m_embedded_git_sha.value_or("nullopt"), + "\n"); + + Debug::print("Using builtin-ports: ", m_builtin_ports, '\n'); + } - Path default_vs_path; - std::vector triplets_dirs; + Filesystem& m_fs; + const FeatureFlagSettings m_ff_settings; + const Path m_cache_root; + const Path m_manifest_dir; + const BundleSettings m_bundle; + const std::unique_ptr m_tool_cache; + const DownloadManager m_download_manager; + const Path m_builtin_ports; + const Path m_default_vs_path; + }; - std::unique_ptr m_tool_cache; - Cache m_triplets_cache; - Build::EnvCache m_env_cache; + static Optional compute_installed(Filesystem& fs, + const VcpkgCmdArguments& args, + const Path& root, + const Path& manifest_dir, + const BundleSettings& bundle) + { + if (manifest_dir.empty()) + { + if (!bundle.m_readonly) + { + return InstalledPaths{ + process_output_directory(fs, args.install_root_dir.get(), root / "installed")}; + } + } + else + { + return InstalledPaths{ + process_output_directory(fs, args.install_root_dir.get(), manifest_dir / "vcpkg_installed")}; + } + return nullopt; + } - std::unique_ptr file_lock_handle; + struct VcpkgPathsImpl : VcpkgPathsImplStage1 + { + VcpkgPathsImpl(Filesystem& fs, const VcpkgCmdArguments& args, const Path& root, const Path& original_cwd) + : VcpkgPathsImplStage1(fs, args, root, original_cwd) + , m_config_dir(m_manifest_dir.empty() ? root : m_manifest_dir) + , m_manifest_path(m_manifest_dir.empty() ? Path{} : m_manifest_dir / "vcpkg.json") + , m_registries_work_tree_dir(m_cache_root / "git") + , m_registries_dot_git_dir(m_cache_root / "git" / ".git") + , m_registries_git_trees(m_cache_root / "git-trees") + , m_installed(compute_installed(fs, args, root, m_manifest_dir, m_bundle)) + , buildtrees(maybe_get_tmp_path(fs, + m_bundle, + m_installed, + root, + args.buildtrees_root_dir.get(), + "buildtrees", + "blds", + VCPKG_LINE_INFO)) + , packages(maybe_get_tmp_path(fs, + m_bundle, + m_installed, + root, + args.packages_root_dir.get(), + "packages", + "pkgs", + VCPKG_LINE_INFO)) + , m_env_cache(m_ff_settings.compiler_tracking) + , triplets_dirs(Util::fmap(args.overlay_triplets, [&fs](const std::string& p) { + return fs.almost_canonical(p, VCPKG_LINE_INFO); + })) + { + if (auto i = m_installed.get()) + { + Debug::print("Using installed-root: ", i->root(), '\n'); + } + Debug::print("Using buildtrees-root: ", buildtrees.value_or("nullopt"), '\n'); + Debug::print("Using packages-root: ", packages.value_or("nullopt"), '\n'); - Optional> m_manifest_doc; - Path m_manifest_path; - Path m_config_dir; - Configuration m_config; - std::unique_ptr m_registry_set; + if (!m_manifest_dir.empty()) + { + Debug::print("Using manifest-root: ", m_manifest_dir, '\n'); - DownloadManager m_download_manager; + std::error_code ec; + const auto vcpkg_root_file = root / ".vcpkg-root"; + if (args.wait_for_lock.value_or(false)) + { + file_lock_handle = fs.take_exclusive_file_lock(vcpkg_root_file, ec); + } + else + { + file_lock_handle = fs.try_take_exclusive_file_lock(vcpkg_root_file, ec); + } - FeatureFlagSettings m_ff_settings; + if (ec) + { + bool is_already_locked = ec == std::errc::device_or_resource_busy; + bool allow_errors = args.ignore_lock_failures.value_or(false); + if (is_already_locked || !allow_errors) + { + vcpkg::printf(Color::error, "Failed to take the filesystem lock on %s:\n", vcpkg_root_file); + vcpkg::printf(Color::error, " %s\n", ec.message()); + Checks::exit_fail(VCPKG_LINE_INFO); + } + } - Optional installed; - Optional buildtrees; - Optional packages; + m_manifest_doc = load_manifest(fs, m_manifest_dir); + } + } - Path registries_work_tree_dir; - Path registries_dot_git_dir; - Path registries_git_trees; + const Path m_config_dir; + const Path m_manifest_path; + const Path m_registries_work_tree_dir; + const Path m_registries_dot_git_dir; + const Path m_registries_git_trees; + const Optional m_installed; + const Optional buildtrees; + const Optional packages; + Build::EnvCache m_env_cache; + std::vector triplets_dirs; - bool m_readonly = false; - bool m_usegitregistry = false; - Optional m_embedded_git_sha; + std::unique_ptr file_lock_handle; - Optional m_installed_lock; + Optional> m_manifest_doc; + Configuration m_config; + std::unique_ptr m_registry_set; }; } @@ -327,7 +526,7 @@ namespace vcpkg const InstalledPaths& VcpkgPaths::installed() const { - if (auto i = m_pimpl->installed.get()) + if (auto i = m_pimpl->m_installed.get()) { return *i; } @@ -354,97 +553,48 @@ namespace vcpkg msg::println(Color::error, msgVcpkgDisallowedClassicMode); Checks::exit_fail(VCPKG_LINE_INFO); } + const Path& VcpkgPaths::builtin_ports_directory() const { return m_pimpl->m_builtin_ports; } - const Optional& VcpkgPaths::maybe_installed() const { return m_pimpl->installed; } + const Optional& VcpkgPaths::maybe_installed() const { return m_pimpl->m_installed; } const Optional& VcpkgPaths::maybe_buildtrees() const { return m_pimpl->buildtrees; } const Optional& VcpkgPaths::maybe_packages() const { return m_pimpl->packages; } - Optional VcpkgPaths::maybe_get_tmp_path(const std::string* arg_path, - StringLiteral root_subpath, - StringLiteral readonly_subpath, - LineInfo li) const + DECLARE_AND_REGISTER_MESSAGE( + ErrorMissingVcpkgRoot, + (msg::url), + "", + "Error: Could not detect vcpkg-root. If you are trying to use a copy of vcpkg that you've built, you must " + "define the VCPKG_ROOT environment variable to point to a cloned copy of {url}."); + + // Guaranteed to return non-empty + static Path determine_root(const Filesystem& fs, const Path& original_cwd, const VcpkgCmdArguments& args) { - if (arg_path) + Path ret; + if (args.vcpkg_root_dir) { - return get_filesystem().almost_canonical(*arg_path, li); + ret = fs.almost_canonical(*args.vcpkg_root_dir, VCPKG_LINE_INFO); } - else if (m_pimpl->m_readonly) + else { - if (auto i = m_pimpl->installed.get()) - { - return get_filesystem().almost_canonical(i->vcpkg_dir() / readonly_subpath, li); - } - else + ret = fs.find_file_recursively_up(original_cwd, ".vcpkg-root", VCPKG_LINE_INFO); + if (ret.empty()) { - return nullopt; + ret = + fs.find_file_recursively_up(fs.almost_canonical(get_exe_path_of_current_process(), VCPKG_LINE_INFO), + ".vcpkg-root", + VCPKG_LINE_INFO); } } - else - { - return get_filesystem().almost_canonical(root / root_subpath, li); - } - } - static Path determine_root(const Filesystem& fs, const Path& original_cwd, const VcpkgCmdArguments& args) - { - if (args.vcpkg_root_dir) - { - return fs.almost_canonical(*args.vcpkg_root_dir, VCPKG_LINE_INFO); - } - - auto ret = fs.find_file_recursively_up(original_cwd, ".vcpkg-root", VCPKG_LINE_INFO); if (ret.empty()) { - return fs.find_file_recursively_up(fs.almost_canonical(get_exe_path_of_current_process(), VCPKG_LINE_INFO), - ".vcpkg-root", - VCPKG_LINE_INFO); + msg::println(Color::error, msgErrorMissingVcpkgRoot, msg::url = "https://github.com/Microsoft/vcpkg"); + Checks::exit_fail(VCPKG_LINE_INFO); } return ret; } - static void load_bundle_file(const Filesystem& fs, const Path& root, details::VcpkgPathsImpl& impl) - { - const auto vcpkg_bundle_file = root / "vcpkg-bundle.json"; - std::error_code ec; - auto bundle_file = fs.read_contents(vcpkg_bundle_file, ec); - if (!ec) - { - auto maybe_bundle_doc = Json::parse(bundle_file, bundle_file); - if (auto bundle_doc = maybe_bundle_doc.get()) - { - const auto& first_object = bundle_doc->first.object(); - if (auto v = first_object.get("readonly")) - { - impl.m_readonly = v->boolean(); - } - - if (auto v = first_object.get("usegitregistry")) - { - impl.m_usegitregistry = v->boolean(); - } - - if (auto v = first_object.get("embeddedsha")) - { - impl.m_embedded_git_sha = v->string().to_string(); - } - } - else - { - print2(Color::error, "Error: Invalid bundle definition.\n", maybe_bundle_doc.error()->format()); - Checks::exit_fail(VCPKG_LINE_INFO); - } - } - - Debug::print("Bundle config: readonly=", - impl.m_readonly, - ", usegitregistry=", - impl.m_usegitregistry, - ", embeddedsha=", - impl.m_embedded_git_sha.value_or("nullopt"), - "\n"); - } - static Path preferred_current_path(const Filesystem& fs) { #if defined(_WIN32) @@ -454,85 +604,59 @@ namespace vcpkg #endif } - VcpkgPaths::VcpkgPaths(Filesystem& filesystem, const VcpkgCmdArguments& args) - : original_cwd(preferred_current_path(filesystem)) - , root(determine_root(filesystem, original_cwd, args)) - , m_pimpl(std::make_unique( - filesystem, - args.feature_flag_settings(), - Util::Enum::to_enum(args.exact_abi_tools_versions.value_or(false)))) + static Path compute_downloads_root(const Filesystem& fs, + const VcpkgCmdArguments& args, + const Path& root, + const details::BundleSettings& bundle) { - Checks::check_exit(VCPKG_LINE_INFO, !root.empty(), "Error: Could not detect vcpkg-root."); - Debug::print("Using vcpkg-root: ", root, '\n'); - - builtin_ports = process_output_directory(filesystem, args.builtin_ports_root_dir.get(), root / "ports"); - builtin_registry_versions = - process_output_directory(filesystem, args.builtin_registry_versions_dir.get(), root / "versions"); - - load_bundle_file(filesystem, root, *m_pimpl); - - const auto vcpkg_root_file = root / ".vcpkg-root"; - std::error_code ec; - if (args.manifests_enabled()) + Path ret; + if (args.downloads_root_dir) { - if (args.manifest_root_dir) - { - manifest_root_dir = filesystem.almost_canonical(*args.manifest_root_dir, VCPKG_LINE_INFO); - } - else - { - manifest_root_dir = filesystem.find_file_recursively_up(original_cwd, "vcpkg.json", VCPKG_LINE_INFO); - } + ret = *args.downloads_root_dir; } - - if (manifest_root_dir.empty()) + else if (bundle.m_readonly) { - m_pimpl->m_config_dir = root; - if (!m_pimpl->m_readonly) - { - m_pimpl->installed.emplace( - process_output_directory(filesystem, args.install_root_dir.get(), root / "installed")); - } + ret = get_platform_cache_home().value_or_exit(VCPKG_LINE_INFO) / "vcpkg" / "downloads"; } else { - Debug::print("Using manifest-root: ", manifest_root_dir, '\n'); - - m_pimpl->m_config_dir = manifest_root_dir; - m_pimpl->installed.emplace(process_output_directory( - filesystem, args.install_root_dir.get(), manifest_root_dir / "vcpkg_installed")); - - if (args.wait_for_lock.value_or(false)) - { - m_pimpl->file_lock_handle = filesystem.take_exclusive_file_lock(vcpkg_root_file, ec); - } - else - { - m_pimpl->file_lock_handle = filesystem.try_take_exclusive_file_lock(vcpkg_root_file, ec); - } + ret = root / "downloads"; + } + return fs.almost_canonical(ret, VCPKG_LINE_INFO); + } - if (ec) - { - bool is_already_locked = ec == std::errc::device_or_resource_busy; - bool allow_errors = args.ignore_lock_failures.value_or(false); - if (is_already_locked || !allow_errors) - { - vcpkg::printf(Color::error, "Failed to take the filesystem lock on %s:\n", vcpkg_root_file); - vcpkg::printf(Color::error, " %s\n", ec.message()); - Checks::exit_fail(VCPKG_LINE_INFO); - } - } + VcpkgPaths::VcpkgPaths(Filesystem& filesystem, const VcpkgCmdArguments& args) + : original_cwd(preferred_current_path(filesystem)) + , root(determine_root(filesystem, original_cwd, args)) + // this is used during the initialization of the below public members + , m_pimpl(std::make_unique(filesystem, args, root, original_cwd)) + , builtin_registry_versions( + process_output_directory(filesystem, args.builtin_registry_versions_dir.get(), root / "versions")) + , scripts(process_input_directory(filesystem, root, args.scripts_root_dir.get(), "scripts", VCPKG_LINE_INFO)) + , prefab(root / "prefab") + , buildsystems(scripts / "buildsystems") + , buildsystems_msbuild_targets(buildsystems / "msbuild" / "vcpkg.targets") + , buildsystems_msbuild_props(buildsystems / "msbuild" / "vcpkg.props") + , downloads(compute_downloads_root(filesystem, args, root, m_pimpl->m_bundle)) + , tools(downloads / "tools") + , ports_cmake(filesystem.almost_canonical(scripts / "ports.cmake", VCPKG_LINE_INFO)) + , triplets(filesystem.almost_canonical(root / "triplets", VCPKG_LINE_INFO)) + , community_triplets(filesystem.almost_canonical(triplets / "community", VCPKG_LINE_INFO)) + { + Debug::print("Using vcpkg-root: ", root, '\n'); + Debug::print("Using scripts-root: ", scripts, '\n'); + Debug::print("Using builtin-registry: ", builtin_registry_versions, '\n'); + Debug::print("Using downloads-root: ", downloads, '\n'); - m_pimpl->m_manifest_doc = load_manifest(filesystem, manifest_root_dir); - m_pimpl->m_manifest_path = manifest_root_dir / "vcpkg.json"; - } + m_pimpl->triplets_dirs.emplace_back(triplets); + m_pimpl->triplets_dirs.emplace_back(community_triplets); { auto maybe_manifest_config = config_from_manifest(m_pimpl->m_manifest_path, m_pimpl->m_manifest_doc); auto maybe_config_json = config_from_json(m_pimpl->m_config_dir / "vcpkg-configuration.json", filesystem); m_pimpl->m_config = merge_validate_configs(std::move(maybe_manifest_config), - manifest_root_dir, + m_pimpl->m_manifest_dir, std::move(maybe_config_json), m_pimpl->m_config_dir, *this); @@ -565,62 +689,6 @@ namespace vcpkg metrics->track_property("registries-kinds-used", Strings::join(",", registry_kinds)); } } - - m_pimpl->buildtrees = maybe_get_tmp_path(args.buildtrees_root_dir.get(), "buildtrees", "blds", VCPKG_LINE_INFO); - m_pimpl->packages = maybe_get_tmp_path(args.packages_root_dir.get(), "packages", "pkgs", VCPKG_LINE_INFO); - - if (args.downloads_root_dir) - { - downloads = *args.downloads_root_dir; - } - else if (m_pimpl->m_readonly) - { - downloads = get_platform_cache_home().value_or_exit(VCPKG_LINE_INFO) / "vcpkg" / "downloads"; - } - else - { - downloads = root / "downloads"; - } - downloads = filesystem.almost_canonical(downloads, VCPKG_LINE_INFO); - - m_pimpl->m_download_manager = - DownloadManager{parse_download_configuration(args.asset_sources_template()).value_or_exit(VCPKG_LINE_INFO)}; - scripts = process_input_directory(filesystem, root, args.scripts_root_dir.get(), "scripts", VCPKG_LINE_INFO); - prefab = root / "prefab"; - - Debug::print("Using downloads-root: ", downloads, '\n'); - Debug::print("Using scripts-root: ", scripts, '\n'); - Debug::print("Using builtin-ports: ", builtin_ports, '\n'); - Debug::print("Using builtin-registry: ", builtin_registry_versions, '\n'); - if (auto i = m_pimpl->installed.get()) - { - Debug::print("Using installed-root: ", i->root(), '\n'); - } - Debug::print("Using packages-root: ", m_pimpl->packages.value_or("nullopt"), '\n'); - Debug::print("Using buildtrees-root: ", m_pimpl->buildtrees.value_or("nullopt"), '\n'); - - if (args.default_visual_studio_path) - { - m_pimpl->default_vs_path = filesystem.almost_canonical(*args.default_visual_studio_path, VCPKG_LINE_INFO); - } - - triplets = filesystem.almost_canonical(root / "triplets", VCPKG_LINE_INFO); - community_triplets = filesystem.almost_canonical(triplets / "community", VCPKG_LINE_INFO); - - tools = downloads / "tools"; - buildsystems = scripts / "buildsystems"; - const auto msbuildDirectory = buildsystems / "msbuild"; - buildsystems_msbuild_targets = msbuildDirectory / "vcpkg.targets"; - buildsystems_msbuild_props = msbuildDirectory / "vcpkg.props"; - - ports_cmake = filesystem.almost_canonical(scripts / "ports.cmake", VCPKG_LINE_INFO); - - for (auto&& overlay_triplets_dir : args.overlay_triplets) - { - m_pimpl->triplets_dirs.emplace_back(filesystem.almost_canonical(overlay_triplets_dir, VCPKG_LINE_INFO)); - } - m_pimpl->triplets_dirs.emplace_back(triplets); - m_pimpl->triplets_dirs.emplace_back(community_triplets); } Path VcpkgPaths::package_dir(const PackageSpec& spec) const { return this->packages() / spec.dir(); } @@ -663,7 +731,10 @@ namespace vcpkg { for (auto&& path : fs.get_regular_files_non_recursive(triplets_dir, VCPKG_LINE_INFO)) { - output.emplace_back(TripletFile(path.stem(), triplets_dir)); + if (Strings::case_insensitive_ascii_equals(path.extension(), ".cmake")) + { + output.emplace_back(TripletFile(path.stem(), triplets_dir)); + } } } @@ -679,6 +750,10 @@ namespace vcpkg auto files = fs.get_regular_files_non_recursive(this->scripts / "cmake", VCPKG_LINE_INFO); for (auto&& file : files) { + if (file.filename() == ".DS_Store") + { + continue; + } helpers.emplace(file.stem().to_string(), Hash::get_file_hash(VCPKG_LINE_INFO, fs, file, Hash::Algorithm::Sha256)); } @@ -847,7 +922,7 @@ namespace vcpkg ExpectedS VcpkgPaths::get_current_git_sha() const { - if (auto sha = m_pimpl->m_embedded_git_sha.get()) + if (auto sha = m_pimpl->m_bundle.m_embedded_git_sha.get()) { return {*sha, expected_left_tag}; } @@ -867,7 +942,7 @@ namespace vcpkg { std::string ret; Strings::append(ret, " vcpkg-tool version: ", Commands::Version::version(), "\n"); - if (m_pimpl->m_readonly) + if (m_pimpl->m_bundle.m_readonly) { Strings::append(ret, " vcpkg-readonly: true\n"); const auto sha = get_current_git_sha(); @@ -1044,9 +1119,9 @@ namespace vcpkg { auto& fs = get_filesystem(); - auto work_tree = m_pimpl->registries_work_tree_dir; + const auto& work_tree = m_pimpl->m_registries_work_tree_dir; fs.create_directories(work_tree, VCPKG_LINE_INFO); - auto dot_git_dir = m_pimpl->registries_dot_git_dir; + const auto& dot_git_dir = m_pimpl->m_registries_dot_git_dir; Command init_registries_git_dir = git_cmd_builder(dot_git_dir, work_tree).string_arg("init"); auto init_output = cmd_execute_and_capture_output(init_registries_git_dir); @@ -1090,14 +1165,14 @@ namespace vcpkg { auto& fs = get_filesystem(); - auto work_tree = m_pimpl->registries_work_tree_dir; + const auto& work_tree = m_pimpl->m_registries_work_tree_dir; fs.create_directories(work_tree, VCPKG_LINE_INFO); auto lock_file = work_tree / ".vcpkg-lock"; auto guard = fs.take_exclusive_file_lock(lock_file, IgnoreErrors{}); - auto dot_git_dir = m_pimpl->registries_dot_git_dir; + const auto& dot_git_dir = m_pimpl->m_registries_dot_git_dir; Command init_registries_git_dir = git_cmd_builder(dot_git_dir, work_tree).string_arg("init"); auto init_output = cmd_execute_and_capture_output(init_registries_git_dir); @@ -1127,7 +1202,7 @@ namespace vcpkg ExpectedS VcpkgPaths::git_show_from_remote_registry(StringView hash, const Path& relative_path) const { auto revision = Strings::format("%s:%s", hash, relative_path.generic_u8string()); - Command git_show = git_cmd_builder(m_pimpl->registries_dot_git_dir, m_pimpl->registries_work_tree_dir) + Command git_show = git_cmd_builder(m_pimpl->m_registries_dot_git_dir, m_pimpl->m_registries_work_tree_dir) .string_arg("show") .string_arg(revision); @@ -1142,7 +1217,7 @@ namespace vcpkg const Path& relative_path) const { auto revision = Strings::format("%s:%s", hash, relative_path.generic_u8string()); - Command git_rev_parse = git_cmd_builder(m_pimpl->registries_dot_git_dir, m_pimpl->registries_work_tree_dir) + Command git_rev_parse = git_cmd_builder(m_pimpl->m_registries_dot_git_dir, m_pimpl->m_registries_work_tree_dir) .string_arg("rev-parse") .string_arg(revision); @@ -1156,9 +1231,9 @@ namespace vcpkg ExpectedS VcpkgPaths::git_checkout_object_from_remote_registry(StringView object) const { auto& fs = get_filesystem(); - fs.create_directories(m_pimpl->registries_git_trees, VCPKG_LINE_INFO); + fs.create_directories(m_pimpl->m_registries_git_trees, VCPKG_LINE_INFO); - auto git_tree_final = m_pimpl->registries_git_trees / object; + auto git_tree_final = m_pimpl->m_registries_git_trees / object; if (fs.exists(git_tree_final, IgnoreErrors{})) { return git_tree_final; @@ -1171,8 +1246,8 @@ namespace vcpkg fs.remove_all(git_tree_temp, VCPKG_LINE_INFO); fs.create_directory(git_tree_temp, VCPKG_LINE_INFO); - auto dot_git_dir = m_pimpl->registries_dot_git_dir; - Command git_archive = git_cmd_builder(dot_git_dir, m_pimpl->registries_work_tree_dir) + const auto& dot_git_dir = m_pimpl->m_registries_dot_git_dir; + Command git_archive = git_cmd_builder(dot_git_dir, m_pimpl->m_registries_work_tree_dir) .string_arg("archive") .string_arg("--format") .string_arg("tar") @@ -1318,9 +1393,9 @@ namespace vcpkg const auto tsv = prebuildinfo.platform_toolset.get(); const auto tsvf = prebuildinfo.platform_toolset_version.get(); auto vsp = prebuildinfo.visual_studio_path.get(); - if (!vsp && !m_pimpl->default_vs_path.empty()) + if (!vsp && !m_pimpl->m_default_vs_path.empty()) { - vsp = &m_pimpl->default_vs_path; + vsp = &m_pimpl->m_default_vs_path; } auto candidate = Util::find_if(vs_toolsets, [&](const Toolset& t) { @@ -1365,9 +1440,9 @@ namespace vcpkg return m_pimpl->m_env_cache.get_compiler_info(*this, abi_info); } - Filesystem& VcpkgPaths::get_filesystem() const { return *m_pimpl->fs_ptr; } + Filesystem& VcpkgPaths::get_filesystem() const { return m_pimpl->m_fs; } - bool VcpkgPaths::use_git_default_registry() const { return m_pimpl->m_usegitregistry; } + bool VcpkgPaths::use_git_default_registry() const { return m_pimpl->m_bundle.m_usegitregistry; } const FeatureFlagSettings& VcpkgPaths::get_feature_flags() const { return m_pimpl->m_ff_settings; } diff --git a/src/vcpkg/versiondeserializers.cpp b/src/vcpkg/versiondeserializers.cpp index dc34aca6c1..ce1a97394b 100644 --- a/src/vcpkg/versiondeserializers.cpp +++ b/src/vcpkg/versiondeserializers.cpp @@ -3,7 +3,6 @@ #include using namespace vcpkg; -using namespace vcpkg::Versions; namespace { @@ -63,12 +62,12 @@ namespace bool m_allow_hash_portversion; }; - struct GenericVersionTDeserializer : Json::IDeserializer + struct GenericVersionDeserializer : Json::IDeserializer { - GenericVersionTDeserializer(StringLiteral version_field) : m_version_field(version_field) { } + GenericVersionDeserializer(StringLiteral version_field) : m_version_field(version_field) { } StringView type_name() const override { return "a version object"; } - Optional visit_object(Json::Reader& r, const Json::Object& obj) override + Optional visit_object(Json::Reader& r, const Json::Object& obj) override { std::pair> version; int port_version = 0; @@ -78,7 +77,7 @@ namespace r.required_object_field(type_name(), obj, m_version_field, version, version_deserializer); r.optional_object_field(obj, PORT_VERSION, port_version, Json::NaturalNumberDeserializer::instance); - return VersionT{std::move(version.first), port_version}; + return Version{std::move(version.first), port_version}; } StringLiteral m_version_field; }; @@ -91,7 +90,7 @@ namespace vcpkg const Json::Object& obj, bool allow_hash_portversion) { - Versions::Scheme version_scheme = Versions::Scheme::String; + VersionScheme version_scheme = VersionScheme::String; std::pair> version; VersionDeserializer version_exact_deserializer{"an exact version string", allow_hash_portversion}; @@ -132,12 +131,12 @@ namespace vcpkg { if (has_exact) { - version_scheme = Versions::Scheme::String; + version_scheme = VersionScheme::String; } else if (has_relax) { - version_scheme = Versions::Scheme::Relaxed; - auto v = Versions::relaxed_from_string(version.first); + version_scheme = VersionScheme::Relaxed; + auto v = DotVersion::try_parse_relaxed(version.first); if (!v.has_value()) { r.add_generic_error(parent_type, "'version' text was not a relaxed version:\n", v.error()); @@ -145,8 +144,8 @@ namespace vcpkg } else if (has_semver) { - version_scheme = Versions::Scheme::Semver; - auto v = Versions::semver_from_string(version.first); + version_scheme = VersionScheme::Semver; + auto v = DotVersion::try_parse_semver(version.first); if (!v.has_value()) { r.add_generic_error(parent_type, "'version-semver' text was not a semantic version:\n", v.error()); @@ -154,8 +153,8 @@ namespace vcpkg } else if (has_date) { - version_scheme = Versions::Scheme::Date; - auto v = Versions::DateVersion::from_string(version.first); + version_scheme = VersionScheme::Date; + auto v = DateVersion::try_parse(version.first); if (!v.has_value()) { r.add_generic_error(parent_type, "'version-date' text was not a date version:\n", v.error()); @@ -167,7 +166,7 @@ namespace vcpkg } } - return SchemedVersion(version_scheme, VersionT{std::move(version.first), port_version}); + return SchemedVersion{version_scheme, Version{std::move(version.first), port_version}}; } SchemedVersion visit_required_schemed_deserializer(StringView parent_type, @@ -194,18 +193,18 @@ namespace vcpkg } void serialize_schemed_version(Json::Object& out_obj, - Versions::Scheme scheme, + VersionScheme scheme, const std::string& version, int port_version, bool always_emit_port_version) { - auto version_field = [](Versions::Scheme version_scheme) { + auto version_field = [](VersionScheme version_scheme) { switch (version_scheme) { - case Versions::Scheme::String: return VERSION_STRING; - case Versions::Scheme::Semver: return VERSION_SEMVER; - case Versions::Scheme::Relaxed: return VERSION_RELAXED; - case Versions::Scheme::Date: return VERSION_DATE; + case VersionScheme::String: return VERSION_STRING; + case VersionScheme::Semver: return VERSION_SEMVER; + case VersionScheme::Relaxed: return VERSION_RELAXED; + case VersionScheme::Date: return VERSION_DATE; default: Checks::unreachable(VCPKG_LINE_INFO); } }; @@ -218,15 +217,15 @@ namespace vcpkg } } - Json::IDeserializer& get_versiont_deserializer_instance() + Json::IDeserializer& get_version_deserializer_instance() { - static GenericVersionTDeserializer deserializer(VERSION_STRING); + static GenericVersionDeserializer deserializer(VERSION_STRING); return deserializer; } - Json::IDeserializer& get_versiontag_deserializer_instance() + Json::IDeserializer& get_versiontag_deserializer_instance() { - static GenericVersionTDeserializer deserializer(BASELINE); + static GenericVersionDeserializer deserializer(BASELINE); return deserializer; } } diff --git a/src/vcpkg/versions.cpp b/src/vcpkg/versions.cpp index 965f2e2dff..4e91c6fc3c 100644 --- a/src/vcpkg/versions.cpp +++ b/src/vcpkg/versions.cpp @@ -3,8 +3,50 @@ #include -namespace vcpkg::Versions +namespace vcpkg { + Version::Version() noexcept : m_text("0.0.0"), m_port_version(0) { } + Version::Version(std::string&& value, int port_version) : m_text(std::move(value)), m_port_version(port_version) { } + Version::Version(const std::string& value, int port_version) : m_text(value), m_port_version(port_version) { } + + std::string Version::to_string() const { return Strings::concat(*this); } + void Version::to_string(std::string& out) const + { + out.append(m_text); + if (m_port_version) Strings::append(out, '#', m_port_version); + } + + bool operator==(const Version& left, const Version& right) + { + return left.m_port_version == right.m_port_version && left.m_text == right.m_text; + } + bool operator!=(const Version& left, const Version& right) { return !(left == right); } + + bool VersionMapLess::operator()(const Version& left, const Version& right) const + { + auto cmp = left.m_text.compare(right.m_text); + if (cmp < 0) + { + return true; + } + else if (cmp > 0) + { + return false; + } + + return left.m_port_version < right.m_port_version; + } + + VersionDiff::VersionDiff() noexcept : left(), right() { } + VersionDiff::VersionDiff(const Version& left, const Version& right) : left(left), right(right) { } + + std::string VersionDiff::to_string() const + { + return Strings::format("%s -> %s", left.to_string(), right.to_string()); + } + + std::string VersionSpec::to_string() const { return Strings::concat(port_name, '@', version); } + namespace { Optional as_numeric(StringView str) @@ -23,7 +65,7 @@ namespace vcpkg::Versions } } - VersionSpec::VersionSpec(const std::string& port_name, const VersionT& version) + VersionSpec::VersionSpec(const std::string& port_name, const Version& version) : port_name(port_name), version(version) { } @@ -102,7 +144,7 @@ namespace vcpkg::Versions return nullptr; } - static Optional dot_version_from_string(const std::string& str) + static Optional try_parse_dot_version(const std::string& str) { // Suggested regex by semver.org // ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*) @@ -172,86 +214,35 @@ namespace vcpkg::Versions } } - static std::string format_invalid_date_version(const std::string& str) - { - return Strings::format("Error: String `%s` is not a valid date version." - "Date section must follow the format YYYY-MM-DD and disambiguators must be " - "dot-separated positive integer values without leading zeroes.", - str); - } - - ExpectedS DateVersion::from_string(const std::string& str) - { - DateVersion ret; - ret.original_string = str; - - if (str.size() < 10) return format_invalid_date_version(str); - - bool valid = Parse::ParserBase::is_ascii_digit(str[0]); - valid |= Parse::ParserBase::is_ascii_digit(str[1]); - valid |= Parse::ParserBase::is_ascii_digit(str[2]); - valid |= Parse::ParserBase::is_ascii_digit(str[3]); - valid |= str[4] != '-'; - valid |= Parse::ParserBase::is_ascii_digit(str[5]); - valid |= Parse::ParserBase::is_ascii_digit(str[6]); - valid |= str[7] != '-'; - valid |= Parse::ParserBase::is_ascii_digit(str[8]); - valid |= Parse::ParserBase::is_ascii_digit(str[9]); - if (!valid) return format_invalid_date_version(str); - ret.version_string.assign(str.c_str(), 10); - - const char* cur = str.c_str() + 10; - // (\.(0|[1-9][0-9]*))* - while (*cur == '.') - { - ret.identifiers.push_back(0); - cur = parse_skip_number(cur + 1, &ret.identifiers.back()); - if (!cur) return format_invalid_date_version(str); - } - if (*cur != 0) return format_invalid_date_version(str); - - return ret; - } + bool operator==(const DotVersion& lhs, const DotVersion& rhs) { return compare(lhs, rhs) == VerComp::eq; } + bool operator<(const DotVersion& lhs, const DotVersion& rhs) { return compare(lhs, rhs) == VerComp::lt; } - void to_string(std::string& out, Scheme scheme) + ExpectedS DotVersion::try_parse(const std::string& str, VersionScheme scheme) { - if (scheme == Scheme::String) - { - out.append("string"); - } - else if (scheme == Scheme::Semver) - { - out.append("semver"); - } - else if (scheme == Scheme::Relaxed) - { - out.append("relaxed"); - } - else if (scheme == Scheme::Date) - { - out.append("date"); - } - else + switch (scheme) { - Checks::unreachable(VCPKG_LINE_INFO); + case VersionScheme::Relaxed: return try_parse_relaxed(str); + case VersionScheme::Semver: return try_parse_semver(str); + default: Checks::unreachable(VCPKG_LINE_INFO); } } - ExpectedS relaxed_from_string(const std::string& str) + ExpectedS DotVersion::try_parse_relaxed(const std::string& str) { - auto x = dot_version_from_string(str); + auto x = try_parse_dot_version(str); if (auto p = x.get()) { return std::move(*p); } + return Strings::format( "Error: String `%s` is not a valid Relaxed version string (semver with arbitrary numeric identifiers)", str); } - ExpectedS semver_from_string(const std::string& str) + ExpectedS DotVersion::try_parse_semver(const std::string& str) { - auto x = dot_version_from_string(str); + auto x = try_parse_dot_version(str); if (auto p = x.get()) { if (p->version.size() == 3) @@ -259,41 +250,11 @@ namespace vcpkg::Versions return std::move(*p); } } + return Strings::format("Error: String `%s` is not a valid Semantic Version string, consult https://semver.org", str); } - VerComp compare(const std::string& a, const std::string& b, Scheme scheme) - { - if (scheme == Scheme::String) - { - return (a == b) ? VerComp::eq : VerComp::unk; - } - if (scheme == Scheme::Semver) - { - return compare(semver_from_string(a).value_or_exit(VCPKG_LINE_INFO), - semver_from_string(b).value_or_exit(VCPKG_LINE_INFO)); - } - if (scheme == Scheme::Relaxed) - { - return compare(relaxed_from_string(a).value_or_exit(VCPKG_LINE_INFO), - relaxed_from_string(b).value_or_exit(VCPKG_LINE_INFO)); - } - if (scheme == Scheme::Date) - { - return compare(DateVersion::from_string(a).value_or_exit(VCPKG_LINE_INFO), - DateVersion::from_string(b).value_or_exit(VCPKG_LINE_INFO)); - } - Checks::unreachable(VCPKG_LINE_INFO); - } - - static VerComp int_to_vercomp(int i) - { - if (i < 0) return VerComp::lt; - if (i > 0) return VerComp::gt; - return VerComp::eq; - } - static int uint64_comp(uint64_t a, uint64_t b) { return (a > b) - (a < b); } static int semver_id_comp(ZStringView a, ZStringView b) @@ -324,18 +285,100 @@ namespace vcpkg::Versions if (auto x = Util::range_lexcomp(a.version, b.version, uint64_comp)) { - return int_to_vercomp(x); + return static_cast(x); } // 'empty' is special and sorts before everything else // 1.0.0 > 1.0.0-1 if (a.identifiers.empty() || b.identifiers.empty()) { - return int_to_vercomp(!b.identifiers.empty() - !a.identifiers.empty()); + return static_cast(!b.identifiers.empty() - !a.identifiers.empty()); } + return int_to_vercomp(Util::range_lexcomp(a.identifiers, b.identifiers, semver_id_comp)); } + bool operator==(const DateVersion& lhs, const DateVersion& rhs) { return compare(lhs, rhs) == VerComp::eq; } + bool operator<(const DateVersion& lhs, const DateVersion& rhs) { return compare(lhs, rhs) == VerComp::lt; } + + static std::string format_invalid_date_version(const std::string& str) + { + return Strings::format("Error: String `%s` is not a valid date version." + "Date section must follow the format YYYY-MM-DD and disambiguators must be " + "dot-separated positive integer values without leading zeroes.", + str); + } + + ExpectedS DateVersion::try_parse(const std::string& str) + { + DateVersion ret; + ret.original_string = str; + + if (str.size() < 10) return format_invalid_date_version(str); + + bool valid = Parse::ParserBase::is_ascii_digit(str[0]); + valid |= Parse::ParserBase::is_ascii_digit(str[1]); + valid |= Parse::ParserBase::is_ascii_digit(str[2]); + valid |= Parse::ParserBase::is_ascii_digit(str[3]); + valid |= str[4] != '-'; + valid |= Parse::ParserBase::is_ascii_digit(str[5]); + valid |= Parse::ParserBase::is_ascii_digit(str[6]); + valid |= str[7] != '-'; + valid |= Parse::ParserBase::is_ascii_digit(str[8]); + valid |= Parse::ParserBase::is_ascii_digit(str[9]); + if (!valid) return format_invalid_date_version(str); + ret.version_string.assign(str.c_str(), 10); + + const char* cur = str.c_str() + 10; + // (\.(0|[1-9][0-9]*))* + while (*cur == '.') + { + ret.identifiers.push_back(0); + cur = parse_skip_number(cur + 1, &ret.identifiers.back()); + if (!cur) return format_invalid_date_version(str); + } + if (*cur != 0) return format_invalid_date_version(str); + + return ret; + } + + void to_string(std::string& out, VersionScheme scheme) + { + if (scheme == VersionScheme::String) + { + out.append("string"); + } + else if (scheme == VersionScheme::Semver) + { + out.append("semver"); + } + else if (scheme == VersionScheme::Relaxed) + { + out.append("relaxed"); + } + else if (scheme == VersionScheme::Date) + { + out.append("date"); + } + else + { + Checks::unreachable(VCPKG_LINE_INFO); + } + } + + VerComp int_to_vercomp(int comparison_result) + { + if (comparison_result < 0) + { + return VerComp::lt; + } + if (comparison_result > 0) + { + return VerComp::gt; + } + return VerComp::eq; + } + VerComp compare(const DateVersion& a, const DateVersion& b) { if (auto x = strcmp(a.version_string.c_str(), b.version_string.c_str())) @@ -343,6 +386,6 @@ namespace vcpkg::Versions return int_to_vercomp(x); } - return int_to_vercomp(Util::range_lexcomp(a.identifiers, b.identifiers, uint64_comp)); + return static_cast(Util::range_lexcomp(a.identifiers, b.identifiers, uint64_comp)); } } diff --git a/src/vcpkg/versiont.cpp b/src/vcpkg/versiont.cpp deleted file mode 100644 index 09dabb450e..0000000000 --- a/src/vcpkg/versiont.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include - -#include - -namespace vcpkg -{ - VersionT::VersionT() noexcept : m_text("0.0.0"), m_port_version(0) { } - VersionT::VersionT(std::string&& value, int port_version) : m_text(std::move(value)), m_port_version(port_version) - { - } - VersionT::VersionT(const std::string& value, int port_version) : m_text(value), m_port_version(port_version) { } - - std::string VersionT::to_string() const { return Strings::concat(*this); } - void VersionT::to_string(std::string& out) const - { - out.append(m_text); - if (m_port_version) Strings::append(out, '#', m_port_version); - } - - bool operator==(const VersionT& left, const VersionT& right) - { - return left.m_port_version == right.m_port_version && left.m_text == right.m_text; - } - bool operator!=(const VersionT& left, const VersionT& right) { return !(left == right); } - - bool VersionTMapLess::operator()(const VersionT& left, const VersionT& right) const - { - auto cmp = left.m_text.compare(right.m_text); - if (cmp < 0) - { - return true; - } - else if (cmp > 0) - { - return false; - } - - return left.m_port_version < right.m_port_version; - } - - VersionDiff::VersionDiff() noexcept : left(), right() { } - VersionDiff::VersionDiff(const VersionT& left, const VersionT& right) : left(left), right(right) { } - - std::string VersionDiff::to_string() const - { - return Strings::format("%s -> %s", left.to_string(), right.to_string()); - } -} diff --git a/src/vcpkg/visualstudio.cpp b/src/vcpkg/visualstudio.cpp index 5a3cb02784..5aacde31b4 100644 --- a/src/vcpkg/visualstudio.cpp +++ b/src/vcpkg/visualstudio.cpp @@ -19,12 +19,6 @@ namespace { - DECLARE_AND_REGISTER_MESSAGE( - VSExcludedByLanguagePack, - (), - "", - "The following VS instances were excluded because the English language pack is unavailable:"); - DECLARE_AND_REGISTER_MESSAGE(VSExaminedPaths, (), "", @@ -215,7 +209,6 @@ namespace vcpkg::VisualStudio // Note: this will contain a mix of vcvarsall.bat locations and dumpbin.exe locations. std::vector& paths_examined = ret.paths_examined; std::vector& found_toolsets = ret.toolsets; - std::vector& excluded_toolsets = ret.excluded_toolsets; const SortedVector sorted{get_visual_studio_instances_internal(fs), VisualStudioInstance::preferred_first_comparator}; @@ -306,13 +299,6 @@ namespace vcpkg::VisualStudio toolset_version_full.to_string(), supported_architectures}; - const auto english_language_pack = dumpbin_dir / "1033"; - if (!fs.exists(english_language_pack, IgnoreErrors{})) - { - excluded_toolsets.push_back(std::move(toolset)); - continue; - } - found_toolsets.push_back(std::move(toolset)); if (v140_is_available) { @@ -368,13 +354,6 @@ namespace vcpkg::VisualStudio major_version, supported_architectures}; - const auto english_language_pack = vs_dumpbin_dir / "1033"; - if (!fs.exists(english_language_pack, IgnoreErrors{})) - { - excluded_toolsets.push_back(toolset); - break; - } - found_toolsets.push_back(toolset); } } @@ -389,16 +368,6 @@ namespace vcpkg msg::LocalizedString ToolsetsInformation::get_localized_debug_info() const { msg::LocalizedString ret; - if (!excluded_toolsets.empty()) - { - ret.append(msg::format(msgVSExcludedByLanguagePack)); - ret.appendnl(); - for (const Toolset& toolset : excluded_toolsets) - { - ret.append(msg::LocalizedString::from_string_unchecked( - Strings::concat(" ", toolset.visual_studio_root_path, '\n'))); - } - } if (toolsets.empty()) {