diff --git a/azure-pipelines/e2e-ports/overlays/broken-no-name/portfile.cmake b/azure-pipelines/e2e-ports/broken-manifests/broken-no-name/portfile.cmake similarity index 100% rename from azure-pipelines/e2e-ports/overlays/broken-no-name/portfile.cmake rename to azure-pipelines/e2e-ports/broken-manifests/broken-no-name/portfile.cmake diff --git a/azure-pipelines/e2e-ports/overlays/broken-no-name/vcpkg.json b/azure-pipelines/e2e-ports/broken-manifests/broken-no-name/vcpkg.json similarity index 100% rename from azure-pipelines/e2e-ports/overlays/broken-no-name/vcpkg.json rename to azure-pipelines/e2e-ports/broken-manifests/broken-no-name/vcpkg.json diff --git a/azure-pipelines/e2e-ports/overlays/broken-no-version/portfile.cmake b/azure-pipelines/e2e-ports/broken-manifests/broken-no-version/portfile.cmake similarity index 100% rename from azure-pipelines/e2e-ports/overlays/broken-no-version/portfile.cmake rename to azure-pipelines/e2e-ports/broken-manifests/broken-no-version/portfile.cmake diff --git a/azure-pipelines/e2e-ports/overlays/broken-no-version/vcpkg.json b/azure-pipelines/e2e-ports/broken-manifests/broken-no-version/vcpkg.json similarity index 100% rename from azure-pipelines/e2e-ports/overlays/broken-no-version/vcpkg.json rename to azure-pipelines/e2e-ports/broken-manifests/broken-no-version/vcpkg.json diff --git a/azure-pipelines/e2e-ports/broken-manifests/malformed/portfile.cmake b/azure-pipelines/e2e-ports/broken-manifests/malformed/portfile.cmake new file mode 100644 index 0000000000..065116c276 --- /dev/null +++ b/azure-pipelines/e2e-ports/broken-manifests/malformed/portfile.cmake @@ -0,0 +1 @@ +set(VCPKG_POLICY_EMPTY_PACKAGE enabled) diff --git a/azure-pipelines/e2e-ports/broken-manifests/malformed/vcpkg.json b/azure-pipelines/e2e-ports/broken-manifests/malformed/vcpkg.json new file mode 100644 index 0000000000..01850f8037 --- /dev/null +++ b/azure-pipelines/e2e-ports/broken-manifests/malformed/vcpkg.json @@ -0,0 +1,4 @@ +{ + "name": "malformed", + "version": "1", +} diff --git a/azure-pipelines/e2e-ports/ci/feature-dep-missing/portfile.cmake b/azure-pipelines/e2e-ports/ci/feature-dep-missing/portfile.cmake new file mode 100644 index 0000000000..065116c276 --- /dev/null +++ b/azure-pipelines/e2e-ports/ci/feature-dep-missing/portfile.cmake @@ -0,0 +1 @@ +set(VCPKG_POLICY_EMPTY_PACKAGE enabled) diff --git a/azure-pipelines/e2e-ports/ci/feature-dep-missing/vcpkg.json b/azure-pipelines/e2e-ports/ci/feature-dep-missing/vcpkg.json new file mode 100644 index 0000000000..cb34c6f616 --- /dev/null +++ b/azure-pipelines/e2e-ports/ci/feature-dep-missing/vcpkg.json @@ -0,0 +1,12 @@ +{ + "name": "feature-dep-missing", + "version": "1", + "features": { + "dep-missing": { + "description": "dependency does not exist", + "dependencies": [ + "this-dependency-does-not-exist" + ] + } + } +} diff --git a/azure-pipelines/end-to-end-tests-dir/build-test-ports.ps1 b/azure-pipelines/end-to-end-tests-dir/build-test-ports.ps1 index be70cb4be4..d2dc4f97b3 100644 --- a/azure-pipelines/end-to-end-tests-dir/build-test-ports.ps1 +++ b/azure-pipelines/end-to-end-tests-dir/build-test-ports.ps1 @@ -20,33 +20,43 @@ if ($output -match 'vcpkg-internal-e2e-test-port3') { throw "Should not emit messages about -port3 while checking -port2" } -Run-Vcpkg @commonArgs --overlay-ports="$PSScriptRoot/../e2e-ports/overlays" install vcpkg-empty-port +# Note that broken-manifests contains ports that must not be 'visited' while trying to install these +Run-Vcpkg @commonArgs --overlay-ports="$PSScriptRoot/../e2e-ports/overlays" --overlay-ports="$PSScriptRoot/../e2e-ports/broken-manifests" install vcpkg-empty-port Throw-IfFailed -Run-Vcpkg @commonArgs --overlay-ports="$PSScriptRoot/../e2e-ports" install vcpkg-internal-e2e-test-port +Run-Vcpkg @commonArgs --overlay-ports="$PSScriptRoot/../e2e-ports" --overlay-ports="$PSScriptRoot/../e2e-ports/broken-manifests" install vcpkg-internal-e2e-test-port Throw-IfFailed -Run-Vcpkg @commonArgs --overlay-ports="$PSScriptRoot/../e2e-ports" install control-file +Run-Vcpkg @commonArgs --overlay-ports="$PSScriptRoot/../e2e-ports" --overlay-ports="$PSScriptRoot/../e2e-ports/broken-manifests" install control-file Throw-IfFailed -$output = Run-VcpkgAndCaptureOutput @commonArgs --overlay-ports="$PSScriptRoot/../e2e-ports/overlays" install broken-no-name + +$output = Run-VcpkgAndCaptureOutput @commonArgs --overlay-ports="$PSScriptRoot/../e2e-ports/broken-manifests" install broken-no-name Throw-IfNotFailed if ($output -notmatch "missing required field 'name'") { throw 'Did not detect missing field' } -$output = Run-VcpkgAndCaptureOutput @commonArgs --overlay-ports="$PSScriptRoot/../e2e-ports/overlays" install broken-no-version +$output = Run-VcpkgAndCaptureOutput @commonArgs --overlay-ports="$PSScriptRoot/../e2e-ports/broken-manifests" install broken-no-version Throw-IfNotFailed if ($output -notmatch 'expected a versioning field') { throw 'Did not detect missing field' } +Remove-Problem-Matchers +$output = Run-VcpkgAndCaptureOutput @commonArgs --overlay-ports="$PSScriptRoot/../e2e-ports/broken-manifests" install malformed +Restore-Problem-Matchers +Throw-IfNotFailed +if ($output -notmatch 'Trailing comma') { + throw 'Did not detect malformed JSON' +} + # Check for msgAlreadyInstalled vs. msgAlreadyInstalledNotHead $output = Run-VcpkgAndCaptureOutput @commonArgs --overlay-ports="$PSScriptRoot/../e2e-ports" install vcpkg-internal-e2e-test-port3 Throw-IfFailed if ($output -notmatch 'vcpkg-internal-e2e-test-port3:[^ ]+ is already installed') { - throw 'Wrong already installed message' + throw 'Wrong already installed message' } $output = Run-VcpkgAndCaptureOutput @commonArgs --overlay-ports="$PSScriptRoot/../e2e-ports" install vcpkg-internal-e2e-test-port3 --head Throw-IfFailed if ($output -notmatch 'vcpkg-internal-e2e-test-port3:[^ ]+ is already installed -- not building from HEAD') { - throw 'Wrong already installed message for --head' + throw 'Wrong already installed message for --head' } diff --git a/azure-pipelines/end-to-end-tests-dir/ci.ps1 b/azure-pipelines/end-to-end-tests-dir/ci.ps1 index f02177fa28..8966c150b4 100644 --- a/azure-pipelines/end-to-end-tests-dir/ci.ps1 +++ b/azure-pipelines/end-to-end-tests-dir/ci.ps1 @@ -12,7 +12,10 @@ if (-not ($Output.Contains("not-sup-host-b:${Triplet}: skip"))) { if (-not ($Output.Contains("feature-not-sup:${Triplet}: *"))) { throw 'feature-not-sup must be build because the port that causes this port to skip should not be installed' } -if ($Output.Split("*").Length -ne 3) { +if (-not ($Output.Contains("feature-dep-missing:${Triplet}: *"))) { + throw 'feature-dep-missing must be build because the broken feature is not selected.' +} +if ($Output.Split("*").Length -ne 4) { throw 'base-port should not be installed for the host' } if (-not ($Output.Contains("REGRESSION: not-sup-host-b:${Triplet} is marked as fail but not supported for ${Triplet}."))) { @@ -21,3 +24,25 @@ if (-not ($Output.Contains("REGRESSION: not-sup-host-b:${Triplet} is marked as f if (-not ($Output.Contains("REGRESSION: dep-on-feature-not-sup:${Triplet} is marked as fail but one dependency is not supported for ${Triplet}."))) { throw "feature-not-sup's baseline fail entry should result in a regression because the port is cascade for this triplet" } + +# any invalid manifest must raise an error +$Output = Run-VcpkgAndCaptureOutput ci --dry-run --triplet=$Triplet --x-builtin-ports-root="$PSScriptRoot/../e2e-ports/broken-manifests" --binarysource=clear --ci-baseline="$PSScriptRoot/../e2e-assets/ci/ci.baseline.txt" +Throw-IfNotFailed + +# test malformed individual overlay port manifest +Remove-Problem-Matchers +$Output = Run-VcpkgAndCaptureOutput ci --dry-run --triplet=$Triplet --x-builtin-ports-root="$PSScriptRoot/../e2e-ports/ci" --binarysource=clear --ci-baseline="$PSScriptRoot/../e2e-assets/ci/ci.baseline.txt" --overlay-ports="$PSScriptRoot/../e2e-ports/broken-manifests/malformed" +Restore-Problem-Matchers +Throw-IfNotFailed +if (-not ($Output.Contains("vcpkg.json:3:17: error: Trailing comma"))) { + throw 'malformed port manifest must raise a parsing error' +} + +# test malformed overlay port manifests +Remove-Problem-Matchers +$Output = Run-VcpkgAndCaptureOutput ci --dry-run --triplet=$Triplet --x-builtin-ports-root="$PSScriptRoot/../e2e-ports/ci" --binarysource=clear --ci-baseline="$PSScriptRoot/../e2e-assets/ci/ci.baseline.txt" --overlay-ports="$PSScriptRoot/../e2e-ports/broken-manifests" +Restore-Problem-Matchers +Throw-IfNotFailed +if (-not ($Output.Contains("vcpkg.json:3:17: error: Trailing comma"))) { + throw 'malformed overlay port manifest must raise a parsing error' +} diff --git a/azure-pipelines/end-to-end-tests-prelude.ps1 b/azure-pipelines/end-to-end-tests-prelude.ps1 index fe7e6095f2..e5b6156bec 100644 --- a/azure-pipelines/end-to-end-tests-prelude.ps1 +++ b/azure-pipelines/end-to-end-tests-prelude.ps1 @@ -158,4 +158,17 @@ function Run-Vcpkg { Run-VcpkgAndCaptureOutput -ForceExe:$ForceExe @TestArgs | Out-Null } + +# https://github.com/actions/toolkit/blob/main/docs/commands.md#problem-matchers +# .github/workflows/matchers.json +function Remove-Problem-Matchers { + Write-Host "::remove-matcher owner=vcpkg-msvc::" + Write-Host "::remove-matcher owner=vcpkg-gcc::" + Write-Host "::remove-matcher owner=vcpkg-catch::" +} +function Restore-Problem-Matchers { + Write-Host "::add-matcher::.github/workflows/matchers.json" +} + + Refresh-TestRoot diff --git a/include/vcpkg/paragraphs.h b/include/vcpkg/paragraphs.h index dd8040c272..71424a046d 100644 --- a/include/vcpkg/paragraphs.h +++ b/include/vcpkg/paragraphs.h @@ -62,5 +62,7 @@ namespace vcpkg::Paragraphs std::vector load_all_registry_ports(const ReadOnlyFilesystem& fs, const RegistrySet& registries); + + LoadResults try_load_overlay_ports(const ReadOnlyFilesystem& fs, const Path& dir); std::vector load_overlay_ports(const ReadOnlyFilesystem& fs, const Path& dir); } diff --git a/src/vcpkg/paragraphs.cpp b/src/vcpkg/paragraphs.cpp index 2f939e2922..d6eb550246 100644 --- a/src/vcpkg/paragraphs.cpp +++ b/src/vcpkg/paragraphs.cpp @@ -582,7 +582,7 @@ namespace vcpkg::Paragraphs return std::move(results.paragraphs); } - std::vector load_overlay_ports(const ReadOnlyFilesystem& fs, const Path& directory) + LoadResults try_load_overlay_ports(const ReadOnlyFilesystem& fs, const Path& directory) { LoadResults ret; @@ -608,8 +608,14 @@ namespace vcpkg::Paragraphs } } - load_results_print_error(ret); - return std::move(ret.paragraphs); + return ret; + } + + std::vector load_overlay_ports(const ReadOnlyFilesystem& fs, const Path& directory) + { + auto results = try_load_overlay_ports(fs, directory); + load_results_print_error(results); + return std::move(results.paragraphs); } uint64_t get_load_ports_stats() { return g_load_ports_stats.load(); } diff --git a/src/vcpkg/portfileprovider.cpp b/src/vcpkg/portfileprovider.cpp index a1fa7a47c9..7fe1ce7e55 100644 --- a/src/vcpkg/portfileprovider.cpp +++ b/src/vcpkg/portfileprovider.cpp @@ -370,8 +370,19 @@ namespace vcpkg } // Try loading all ports inside ports_dir - auto found_scfls = Paragraphs::load_overlay_ports(m_fs, ports_dir); - for (auto&& scfl : found_scfls) + auto results = Paragraphs::try_load_overlay_ports(m_fs, ports_dir); + if (!results.errors.empty()) + { + print_error_message(LocalizedString::from_raw(Strings::join( + "\n", + results.errors, + [](const std::pair& err) -> const LocalizedString& { + return err.second; + }))); + Checks::exit_maybe_upgrade(VCPKG_LINE_INFO); + } + + for (auto&& scfl : results.paragraphs) { auto name = scfl.to_name(); auto it = m_overlay_cache.emplace(std::move(name), std::move(scfl)).first;