diff --git a/azure-pipelines/end-to-end-tests-dir/format-manifest.ps1 b/azure-pipelines/end-to-end-tests-dir/format-manifest.ps1 index b30f6f4901..e25c5322f7 100644 --- a/azure-pipelines/end-to-end-tests-dir/format-manifest.ps1 +++ b/azure-pipelines/end-to-end-tests-dir/format-manifest.ps1 @@ -11,7 +11,7 @@ $testProjects | % { Write-Trace "test that format-manifest on $full produces $expectedPath" [string]$expected = Get-Content $expectedPath -Raw Copy-Item $asItem $tempItemPath - Run-Vcpkg format-manifest $tempItemPath + Run-Vcpkg format-manifest $tempItemPath | Out-Null $actual = Get-Content $tempItemPath -Raw if ($expected -ne $actual) { throw "Expected formatting $full to produce $expectedPath but was $tempItemPath" @@ -20,10 +20,12 @@ $testProjects | % { Write-Trace "test re-serializing every manifest" $manifestDir = "$TestingRoot/manifest-dir" + Copy-Item -Path "$env:VCPKG_ROOT/ports" -Destination $manifestDir -recurse -Force -Filter vcpkg.json +@("libuvc", "mlpack", "qt5-virtualkeyboard", "qtwebengine", "vamp-sdk") | % { Remove-Item -Recurse "$manifestDir/$_" } & git init $manifestDir && git -C $manifestDir add . && git -C $manifestDir -c user.name='vcpkg-test' -c user.email='my@example.com' commit -m "baseline" Throw-IfFailed -Run-Vcpkg format-manifest --all --x-builtin-ports-root=$manifestDir/ports +Run-Vcpkg format-manifest --all --x-builtin-ports-root=$manifestDir Throw-IfFailed $diff = (& git -C $manifestDir diff) | Out-String if ($diff.length -gt 0) { diff --git a/azure-pipelines/end-to-end-tests-dir/versions.ps1 b/azure-pipelines/end-to-end-tests-dir/versions.ps1 index 8e20d2ff33..d54d5c43bf 100644 --- a/azure-pipelines/end-to-end-tests-dir/versions.ps1 +++ b/azure-pipelines/end-to-end-tests-dir/versions.ps1 @@ -34,35 +34,35 @@ Throw-IfNotFailed $CurrentTest = "x-add-version cat" # Do not fail if there's nothing to update -Run-Vcpkg @portsRedirectArgsIncomplete x-add-version cat +Run-Vcpkg @portsRedirectArgsIncomplete x-add-version --skip-license-check cat Throw-IfFailed $CurrentTest = "x-add-version dog" # Local version is not in baseline and versions file -Run-Vcpkg @portsRedirectArgsIncomplete x-add-version dog +Run-Vcpkg @portsRedirectArgsIncomplete x-add-version --skip-license-check dog Throw-IfFailed $CurrentTest = "x-add-version duck" # Missing versions file -Run-Vcpkg @portsRedirectArgsIncomplete x-add-version duck +Run-Vcpkg @portsRedirectArgsIncomplete x-add-version --skip-license-check duck Throw-IfFailed $CurrentTest = "x-add-version ferret" # Missing versions file and missing baseline entry -Run-Vcpkg @portsRedirectArgsIncomplete x-add-version ferret +Run-Vcpkg @portsRedirectArgsIncomplete x-add-version --skip-license-check ferret Throw-IfFailed $CurrentTest = "x-add-version fish (must fail)" # Discrepancy between local SHA and SHA in fish.json. Requires --overwrite-version. -Run-Vcpkg @portsRedirectArgsIncomplete x-add-version fish +Run-Vcpkg @portsRedirectArgsIncomplete x-add-version --skip-license-check fish Throw-IfNotFailed $CurrentTest = "x-add-version fish --overwrite-version" -Run-Vcpkg @portsRedirectArgsIncomplete x-add-version fish --overwrite-version --skip-version-format-check +Run-Vcpkg @portsRedirectArgsIncomplete x-add-version fish --overwrite-version --skip-version-format-check --skip-license-check Throw-IfFailed $CurrentTest = "x-add-version mouse" # Missing baseline entry -Run-Vcpkg @portsRedirectArgsIncomplete x-add-version mouse +Run-Vcpkg @portsRedirectArgsIncomplete x-add-version --skip-license-check mouse Throw-IfFailed # Validate changes Run-Vcpkg @portsRedirectArgsIncomplete x-ci-verify-versions --verbose diff --git a/include/vcpkg/base/message-data.inc.h b/include/vcpkg/base/message-data.inc.h index 92b7fdc6c7..0f167c25d3 100644 --- a/include/vcpkg/base/message-data.inc.h +++ b/include/vcpkg/base/message-data.inc.h @@ -48,12 +48,20 @@ DECLARE_MESSAGE(AddVersionDetectLocalChangesError, (), "", "skipping detection of local changes due to unexpected format in git status output") +DECLARE_MESSAGE(AddVersionDisableCheck, + (msg::option), + "The -- before {option} must be preserved as they're part of the help message for the user.", + "Use --{option} to disable this check.") DECLARE_MESSAGE(AddVersionFileNotFound, (msg::path), "", "couldn't find required file {path}") DECLARE_MESSAGE(AddVersionFormatPortSuggestion, (msg::command_line), "", "Run `{command_line}` to format the file") DECLARE_MESSAGE(AddVersionIgnoringOptionAll, (msg::option), "The -- before {option} must be preserved as they're part of the help message for the user.", "ignoring --{option} since a port name argument was provided") +DECLARE_MESSAGE(AddVersionLintPort, + (msg::package_name), + "", + "You can run `./vcpkg x-lint-port --fix {package_name}` to fix these issues.") DECLARE_MESSAGE(AddVersionLoadPortFailed, (msg::package_name), "", "can't load port {package_name}") DECLARE_MESSAGE(AddVersionNewFile, (), "", "(new file)") DECLARE_MESSAGE(AddVersionNewShaIs, (msg::commit_sha), "", "new SHA: {commit_sha}") @@ -74,11 +82,46 @@ DECLARE_MESSAGE(AddVersionPortFilesShaUnchanged, "", "checked-in files for {package_name} are unchanged from version {version}") DECLARE_MESSAGE(AddVersionPortHasImproperFormat, (msg::package_name), "", "{package_name} is not properly formatted") -DECLARE_MESSAGE(AddVersionSuggestNewVersionScheme, - (msg::new_scheme, msg::old_scheme, msg::package_name, msg::option), - "The -- before {option} must be preserved as they're part of the help message for the user.", +DECLARE_MESSAGE(LintDeprecatedFunction, + (msg::package_name, msg::actual, msg::expected), + "{actual} is the currently used deprecated function, {expected} is the function that should be used", + "The deprecated function \"{actual}\" is used inside the port \"{package_name}\". Use the function " + "\"{expected}\" instead.") +DECLARE_MESSAGE( + LintDeprecatedLicenseExpressionWithReplacement, + (msg::package_name, msg::actual, msg::new_value), + "{actual} is the currently used license expression and {new_value} is the license expression that should be " + "used", + "The port \"{package_name}\" uses the deprecated license expression \"{actual}\". You shoud use the non " + "deprecated version \"{new_value}\".") +DECLARE_MESSAGE(LintDeprecatedLicenseExpressionWithoutReplacement, + (msg::package_name, msg::actual, msg::new_value), + "{actual} is the currently used license, {new_value} is the suggested WITH expression", + "The port \"{package_name}\" uses the deprecated license expression \"{actual}\". " + "Use license expression including main license, \"WITH\" operator, and identifier: \"{new_value}\"") +DECLARE_MESSAGE(LintMissingLicenseExpression, + (msg::package_name), + "", + "There is no license expression in port \"{package_name}\". You could use " + "https://tools.spdx.org/app/check_license/ to determine the right license expression.") +DECLARE_MESSAGE(LintSuggestNewVersionScheme, + (msg::new_scheme, msg::old_scheme, msg::package_name), + "", "Use the version scheme \"{new_scheme}\" instead of \"{old_scheme}\" in port " - "\"{package_name}\".\nUse --{option} to disable this check.") + "\"{package_name}\".") +DECLARE_MESSAGE(LintVcpkgCheckFeatures, + (msg::package_name), + "", + "Calling `vcpkg_check_features` without the `FEATURES` keyword has been deprecated. Please add the " + "`FEATURES` keyword to the call inside the port {package_name}.") +DECLARE_MESSAGE(LintPortErrorsFixed, + (msg::package_name), + "", + "Problems in the port \"{package_name}\" have been fixed.") +DECLARE_MESSAGE(LintPortErrors, + (msg::package_name), + "", + "The port \"{package_name}\" should be fixed. See warning(s) above.") DECLARE_MESSAGE(AddVersionUnableToParseVersionsFile, (msg::path), "", "unable to parse versions file {path}") DECLARE_MESSAGE(AddVersionUncommittedChanges, (msg::package_name), @@ -458,6 +501,8 @@ DECLARE_MESSAGE(CmdAddVersionOptAll, (), "", "Process versions for all ports.") DECLARE_MESSAGE(CmdAddVersionOptOverwriteVersion, (), "", "Overwrite `git-tree` of an existing version.") DECLARE_MESSAGE(CmdAddVersionOptSkipFormatChk, (), "", "Skips the formatting check of vcpkg.json files.") DECLARE_MESSAGE(CmdAddVersionOptSkipVersionFormatChk, (), "", "Skips the version format check.") +DECLARE_MESSAGE(CmdAddVersionOptSkipLicenseChk, (), "", "Skips the license expression check.") +DECLARE_MESSAGE(CmdAddVersionOptSkipPortfileChk, (), "", "Skips the portfile.cmake check.") DECLARE_MESSAGE(CmdAddVersionOptVerbose, (), "", "Print success messages instead of just errors.") DECLARE_MESSAGE(CmdContactOptSurvey, (), "", "Launch default browser to the current vcpkg survey") DECLARE_MESSAGE(CmdDependInfoOptDepth, (), "", "Show recursion depth in output") @@ -529,6 +574,9 @@ DECLARE_MESSAGE( "When generating the message map, exclude comments (useful for generating the English localization file)") DECLARE_MESSAGE(CmdInfoOptInstalled, (), "", "(experimental) Report on installed packages instead of available") DECLARE_MESSAGE(CmdInfoOptTransitive, (), "", "(experimental) Also report on dependencies of installed packages") +DECLARE_MESSAGE(CmdLintPortOptAllPorts, (), "", "Checks all ports.") +DECLARE_MESSAGE(CmdLintPortOptFix, (), "", "Tries to fix all problems that were found.") +DECLARE_MESSAGE(CmdLintPortOptIncreaseVersion, (), "", "Increase the port-version of a port if a problem was fixed.") DECLARE_MESSAGE(CmdNewOptApplication, (), "", "Create an application manifest (don't require name or version).") DECLARE_MESSAGE(CmdNewOptSingleFile, (), "", "Embed vcpkg-configuration.json into vcpkg.json.") DECLARE_MESSAGE(CmdNewOptVersionDate, (), "", "Interpret --version as an ISO 8601 date. (YYYY-MM-DD)") diff --git a/include/vcpkg/commands.lint-port.h b/include/vcpkg/commands.lint-port.h new file mode 100644 index 0000000000..0216b23a98 --- /dev/null +++ b/include/vcpkg/commands.lint-port.h @@ -0,0 +1,9 @@ +#pragma once + +#include +#include + +namespace vcpkg::Commands::LintPort +{ + void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths); +} diff --git a/include/vcpkg/portlint.h b/include/vcpkg/portlint.h new file mode 100644 index 0000000000..6a01a538df --- /dev/null +++ b/include/vcpkg/portlint.h @@ -0,0 +1,54 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include + +#include + +#include + +namespace vcpkg::Lint +{ + enum class Status : int + { + Ok = 0b0, + Problem = 0b01, + Fixed = 0b10, + PartiallyFixed = 0b11 + }; + + Status& operator|=(Status& self, Status s); + + enum class Fix + { + NO = 0, // A warning message is printed for every found problem + YES // The problem is fixed in place (SourceControlFile) and no message is printed + }; + + std::string get_recommended_license_expression(std::string original_license); + + VersionScheme get_recommended_version_scheme(StringView raw_version, VersionScheme original_scheme); + + Status check_used_version_scheme(SourceControlFile& scf, Fix fix); + + Status check_license_expression(SourceControlFile& scf, Fix fix); + + struct FixedPortfile + { + Status status; + std::string new_portfile_content; // empty if Fix::NO + std::set added_host_deps; // host-dependencies that need to be added, empty if Fix::NO + }; + + FixedPortfile check_portfile_deprecated_functions(std::string&& portfile_content, + StringView origin, + Fix fix, + MessageSink& warningsSink); + + Status check_portfile_deprecated_functions(Filesystem& fs, SourceControlFileAndLocation& scf, Fix fix); +} diff --git a/include/vcpkg/sourceparagraph.h b/include/vcpkg/sourceparagraph.h index 99d687d9b1..d08bd9a741 100644 --- a/include/vcpkg/sourceparagraph.h +++ b/include/vcpkg/sourceparagraph.h @@ -163,6 +163,8 @@ namespace vcpkg } VersionSpec to_version_spec() const { return {core_paragraph->name, core_paragraph->to_version()}; } + std::unique_ptr canonicalize(); + friend bool operator==(const SourceControlFile& lhs, const SourceControlFile& rhs); friend bool operator!=(const SourceControlFile& lhs, const SourceControlFile& rhs) { return !(lhs == rhs); } }; diff --git a/locales/messages.en.json b/locales/messages.en.json new file mode 100644 index 0000000000..92e485877c --- /dev/null +++ b/locales/messages.en.json @@ -0,0 +1,813 @@ +{ + "AddArtifactOnlyOne": "'{command_line}' can only add one artifact at a time.", + "AddCommandFirstArg": "The first parameter to add must be 'artifact' or 'port'.", + "AddFirstArgument": "The first argument to '{command_line}' must be 'artifact' or 'port'.", + "AddPortRequiresManifest": "'{command_line}' requires an active manifest file.", + "AddPortSucceeded": "Succeeded in adding ports to vcpkg.json file.", + "AddRecurseOption": "If you are sure you want to remove them, run the command with the --recurse option.", + "AddTripletExpressionNotAllowed": "triplet expressions are not allowed here. You may want to change `{package_name}:{triplet}` to `{package_name}` instead.", + "AddVersionAddedVersionToFile": "added version {version} to {path}", + "AddVersionCommitChangesReminder": "Did you remember to commit your changes?", + "AddVersionCommitResultReminder": "Don't forget to commit the result!", + "AddVersionDetectLocalChangesError": "skipping detection of local changes due to unexpected format in git status output", + "AddVersionDisableCheck": "Use --{option} to disable this check.", + "AddVersionFileNotFound": "couldn't find required file {path}", + "AddVersionFormatPortSuggestion": "Run `{command_line}` to format the file", + "AddVersionIgnoringOptionAll": "ignoring --{option} since a port name argument was provided", + "AddVersionLintPort": "You can run `./vcpkg x-lint-port --fix {package_name}` to fix these issues.", + "AddVersionLoadPortFailed": "can't load port {package_name}", + "AddVersionNewFile": "(new file)", + "AddVersionNewShaIs": "new SHA: {value}", + "AddVersionNoFilesUpdated": "No files were updated", + "AddVersionNoFilesUpdatedForPort": "No files were updated for {package_name}", + "AddVersionNoGitSha": "can't obtain SHA for port {package_name}", + "AddVersionOldShaIs": "old SHA: {value}", + "AddVersionOverwriteOptionSuggestion": "Use --{option} to bypass this check", + "AddVersionPortDoesNotExist": "{package_name} does not exist", + "AddVersionPortFilesShaChanged": "checked-in files for {package_name} have changed but the version was not updated", + "AddVersionPortFilesShaUnchanged": "checked-in files for {package_name} are unchanged from version {version}", + "AddVersionPortHasImproperFormat": "{package_name} is not properly formatted", + "AddVersionUnableToParseVersionsFile": "unable to parse versions file {path}", + "AddVersionUncommittedChanges": "there are uncommitted changes for {package_name}", + "AddVersionUpdateVersionReminder": "Did you remember to update the version or port version?", + "AddVersionUseOptionAll": "{command_name} with no arguments requires passing --{option} to update all port versions at once", + "AddVersionVersionAlreadyInFile": "version {version} is already in {path}", + "AddVersionVersionIs": "version: {version}", + "AddingCompletionEntry": "Adding vcpkg completion entry to {path}.", + "AdditionalPackagesToExport": "Additional packages (*) need to be exported to complete this operation.", + "AdditionalPackagesToRemove": "Additional packages (*) need to be removed to complete this operation.", + "AllFormatArgsRawArgument": "format string \"{value}\" contains a raw format argument", + "AllFormatArgsUnbalancedBraces": "unbalanced brace in format string \"{value}\"", + "AllPackagesAreUpdated": "All installed packages are up-to-date with the local portfile.", + "AlreadyInstalled": "{spec} is already installed", + "AlreadyInstalledNotHead": "{spec} is already installed -- not building from HEAD", + "AmbiguousConfigDeleteConfigFile": "Ambiguous vcpkg configuration provided by both manifest and configuration file.\n-- Delete configuration file {path}", + "AndroidHomeDirMissingProps": "source.properties missing in {env_var} directory: {path}", + "AnotherInstallationInProgress": "Another installation is in progress on the machine, sleeping 6s before retrying.", + "AppliedUserIntegration": "Applied user-wide integration for this vcpkg root.", + "ArtifactsOptionIncompatibility": "--{option} has no effect on find artifact.", + "AssetSourcesArg": "Add sources for asset caching. See 'vcpkg help assetcaching'.", + "AttemptingToFetchPackagesFromVendor": "Attempting to fetch {count} package(s) from {vendor}", + "AttemptingToSetBuiltInBaseline": "attempting to set builtin-baseline in vcpkg.json while overriding the default-registry in vcpkg-configuration.json.\nthe default-registry from vcpkg-configuration.json will be used.", + "AuthenticationMayRequireManualAction": "One or more {vendor} credential providers requested manual action. Add the binary source 'interactive' to allow interactivity.", + "AutoSettingEnvVar": "-- Automatically setting {env_var} environment variables to \"{url}\".", + "AutomaticLinkingForMSBuildProjects": "All MSBuild C++ projects can now #include any installed libraries. Linking will be handled automatically. Installing new libraries will make them instantly available.", + "AvailableArchitectureTriplets": "Available architecture triplets:", + "AvailableHelpTopics": "Available help topics:", + "BaselineConflict": "Specifying vcpkg-configuration.default-registry in a manifest file conflicts with built-in baseline.\nPlease remove one of these conflicting settings.", + "BaselineFileNoDefaultField": "The baseline file at commit {commit_sha} was invalid (no \"default\" field).", + "BaselineMissingDefault": "The baseline.json from commit `\"{commit_sha}\"` in the repo {url} was invalid (did not contain a \"default\" field).", + "BinarySourcesArg": "Add sources for binary caching. See 'vcpkg help binarycaching'.", + "BinaryWithInvalidArchitecture": "{path}\n Expected: {expected}, but was {actual}", + "BothYesAndNoOptionSpecifiedError": "cannot specify both --no-{option} and --{option}.", + "BuildAlreadyInstalled": "{spec} is already installed; please remove {spec} before attempting to build it.", + "BuildDependenciesMissing": "The build command requires all dependencies to be already installed.\nThe following dependencies are missing:", + "BuildResultBuildFailed": "BUILD_FAILED", + "BuildResultCacheMissing": "CACHE_MISSING", + "BuildResultCascadeDueToMissingDependencies": "CASCADED_DUE_TO_MISSING_DEPENDENCIES", + "BuildResultDownloaded": "DOWNLOADED", + "BuildResultExcluded": "EXCLUDED", + "BuildResultFileConflicts": "FILE_CONFLICTS", + "BuildResultPostBuildChecksFailed": "POST_BUILD_CHECKS_FAILED", + "BuildResultRemoved": "REMOVED", + "BuildResultSucceeded": "SUCCEEDED", + "BuildResultSummaryHeader": "SUMMARY FOR {triplet}", + "BuildResultSummaryLine": "{build_result}: {count}", + "BuildTreesRootDir": "(Experimental) Specify the buildtrees root directory.", + "BuildTroubleshootingMessage1": "Please ensure you're using the latest port files with `git pull` and `vcpkg update`.\nThen check for known issues at:", + "BuildTroubleshootingMessage2": "You can submit a new issue at:", + "BuildTroubleshootingMessage3": "Include '[{package_name}] Build error' in your bug report title, the following version information in your bug description, and attach any relevant failure logs from above.", + "BuildTroubleshootingMessage4": "Please use the prefilled template from {path} when reporting your issue.", + "BuildingFromHead": "Building {spec} from HEAD...", + "BuildingPackage": "Building {spec}...", + "BuildingPackageFailed": "building {spec} failed with: {build_result}", + "BuildingPackageFailedDueToMissingDeps": "due to the following missing dependencies:", + "BuiltInTriplets": "vcpkg built-in triplets:", + "BuiltWithIncorrectArchitecture": "The following files were built for an incorrect architecture:", + "CISettingsExclude": "Comma-separated list of ports to skip", + "CISettingsOptCIBase": "Path to the ci.baseline.txt file. Used to skip ports and detect regressions.", + "CISettingsOptExclude": "Comma separated list of ports to skip", + "CISettingsOptFailureLogs": "Directory to which failure logs will be copied", + "CISettingsOptHostExclude": "Comma separated list of ports to skip for the host triplet", + "CISettingsOptOutputHashes": "File to output all determined package hashes", + "CISettingsOptParentHashes": "File to read package hashes for a parent CI state, to reduce the set of changed packages", + "CISettingsOptSkippedCascadeCount": "Asserts that the number of --exclude and supports skips exactly equal this number", + "CISettingsOptXUnit": "File to output results in XUnit format (internal)", + "CISettingsVerifyGitTree": "Verify that each git tree object matches its declared version (this is very slow)", + "CISettingsVerifyVersion": "Print result for each port instead of just errors.", + "CISwitchOptAllowUnexpectedPassing": "Indicates that 'Passing, remove from fail list' results should not be emitted.", + "CISwitchOptDryRun": "Print out plan without execution", + "CISwitchOptRandomize": "Randomize the install order", + "CISwitchOptSkipFailures": "Indicates that ports marked `=fail` in ci.baseline.txt should be skipped.", + "CISwitchOptXUnitAll": "Report also unchanged ports to the XUnit output (internal)", + "CMakeTargetsUsage": "{package_name} provides CMake targets:", + "CMakeTargetsUsageHeuristicMessage": "# this is heuristically generated, and may not be correct", + "CMakeToolChainFile": "CMake projects should use: \"-DCMAKE_TOOLCHAIN_FILE={path}\"", + "CMakeUsingExportedLibs": "To use exported libraries in CMake projects, add {value} to your CMake command line.", + "ChecksFailedCheck": "vcpkg has crashed; no additional details are available.", + "ChecksUnreachableCode": "unreachable code was reached", + "ChecksUpdateVcpkg": "updating vcpkg by rerunning bootstrap-vcpkg may resolve this failure.", + "CiBaselineAllowUnexpectedPassingRequiresBaseline": "--allow-unexpected-passing can only be used if a baseline is provided via --ci-baseline.", + "CiBaselineDisallowedCascade": "REGRESSION: {spec} cascaded, but it is required to pass. ({path}).", + "CiBaselineRegression": "REGRESSION: {spec} failed with {build_result}. If expected, add {spec}=fail to {path}.", + "CiBaselineRegressionHeader": "REGRESSIONS:", + "CiBaselineUnexpectedPass": "PASSING, REMOVE FROM FAIL LIST: {spec} ({path}).", + "ClearingContents": "Clearing contents of {path}", + "CmakeTargetsExcluded": "note: {count} additional targets are not displayed.", + "CmdAddVersionOptAll": "Process versions for all ports.", + "CmdAddVersionOptOverwriteVersion": "Overwrite `git-tree` of an existing version.", + "CmdAddVersionOptSkipFormatChk": "Skips the formatting check of vcpkg.json files.", + "CmdAddVersionOptSkipLicenseChk": "Skips the license expression check.", + "CmdAddVersionOptSkipPortfileChk": "Skips the portfile.cmake check.", + "CmdAddVersionOptSkipVersionFormatChk": "Skips the version format check.", + "CmdAddVersionOptVerbose": "Print success messages instead of just errors.", + "CmdContactOptSurvey": "Launch default browser to the current vcpkg survey", + "CmdDependInfoOptDGML": "Creates graph on basis of dgml", + "CmdDependInfoOptDepth": "Show recursion depth in output", + "CmdDependInfoOptDot": "Creates graph on basis of dot", + "CmdDependInfoOptMaxRecurse": "Set max recursion depth, a value of -1 indicates no limit", + "CmdDependInfoOptSort": "Set sort order for the list of dependencies, accepted values are: lexicographical, topological (default), x-tree, reverse", + "CmdEditOptAll": "Open editor into the port as well as the port-specific buildtree subfolder", + "CmdEditOptBuildTrees": "Open editor into the port-specific buildtree subfolder", + "CmdEnvOptions": "Add installed {path} to {env_var}", + "CmdExportOpt7Zip": "Export to a 7zip (.7z) file", + "CmdExportOptChocolatey": "Export a Chocolatey package (experimental feature)", + "CmdExportOptDebug": "Enable prefab debug", + "CmdExportOptDryRun": "Do not actually export.", + "CmdExportOptIFW": "Export to an IFW-based installer", + "CmdExportOptInstalled": "Export all installed packages", + "CmdExportOptMaven": "Enable Maven", + "CmdExportOptNuget": "Export a NuGet package", + "CmdExportOptPrefab": "Export to Prefab format", + "CmdExportOptRaw": "Export to an uncompressed directory", + "CmdExportOptZip": "Export to a zip file", + "CmdExportSettingChocolateyMaint": "Specify the maintainer for the exported Chocolatey package (experimental feature)", + "CmdExportSettingChocolateyVersion": "Specify the version suffix to add for the exported Chocolatey package (experimental feature)", + "CmdExportSettingConfigFile": "Specify the temporary file path for the installer configuration", + "CmdExportSettingInstallerPath": "Specify the file path for the exported installer", + "CmdExportSettingNugetDesc": "Specify a description for the exported NuGet package", + "CmdExportSettingNugetID": "Specify the id for the exported NuGet package (overrides --output)", + "CmdExportSettingNugetVersion": "Specify the version for the exported NuGet package", + "CmdExportSettingOutput": "Specify the output name (used to construct filename)", + "CmdExportSettingOutputDir": "Specify the output directory for produced artifacts", + "CmdExportSettingPkgDir": "Specify the temporary directory path for the repacked packages", + "CmdExportSettingPrefabArtifactID": "Artifact Id is the name of the project according Maven specifications", + "CmdExportSettingPrefabGroupID": "GroupId uniquely identifies your project according Maven specifications", + "CmdExportSettingPrefabVersion": "Version is the name of the project according Maven specifications", + "CmdExportSettingRepoDir": "Specify the directory path for the exported repository", + "CmdExportSettingRepoURL": "Specify the remote repository URL for the online installer", + "CmdExportSettingSDKMinVersion": "Android minimum supported SDK version", + "CmdExportSettingSDKTargetVersion": "Android target sdk version", + "CmdFetchOptXStderrStatus": "Direct status/downloading messages to stderr rather than stdout. (Errors/failures still go to stdout)", + "CmdFormatManifestOptAll": "Format all ports' manifest files.", + "CmdFormatManifestOptConvertControl": "Convert CONTROL files to manifest files.", + "CmdGenerateMessageMapOptNoOutputComments": "When generating the message map, exclude comments (useful for generating the English localization file)", + "CmdGenerateMessageMapOptOutputComments": "When generating the message map, include comments (the default)", + "CmdInfoOptInstalled": "(experimental) Report on installed packages instead of available", + "CmdInfoOptTransitive": "(experimental) Also report on dependencies of installed packages", + "CmdLintPortOptAllPorts": "Checks all ports.", + "CmdLintPortOptFix": "Tries to fix all problems that were found.", + "CmdLintPortOptIncreaseVersion": "Increase the port-version of a port if a problem was fixed.", + "CmdNewOptApplication": "Create an application manifest (don't require name or version).", + "CmdNewOptSingleFile": "Embed vcpkg-configuration.json into vcpkg.json.", + "CmdNewOptVersionDate": "Interpret --version as an ISO 8601 date. (YYYY-MM-DD)", + "CmdNewOptVersionRelaxed": "Interpret --version as a relaxed-numeric version. (Nonnegative numbers separated by dots)", + "CmdNewOptVersionString": "Interpret --version as a string with no ordering behavior.", + "CmdNewSettingName": "Name for the new manifest.", + "CmdNewSettingVersion": "Version for the new manifest.", + "CmdRegenerateOptDryRun": "does not actually perform the action, shows only what would be done", + "CmdRegenerateOptForce": "proceeds with the (potentially dangerous) action without confirmation", + "CmdRegenerateOptNormalize": "apply any deprecation fixups", + "CmdRemoveOptDryRun": "Print the packages to be removed, but do not remove them", + "CmdRemoveOptOutdated": "Select all packages with versions that do not match the portfiles", + "CmdRemoveOptRecurse": "Allow removal of packages not explicitly specified on the command line", + "CmdSetInstalledOptDryRun": "Do not actually build or install", + "CmdSetInstalledOptNoUsage": "Don't print CMake usage information after install.", + "CmdSetInstalledOptWritePkgConfig": "Writes out a NuGet packages.config-formatted file for use with external binary caching.\nSee `vcpkg help binarycaching` for more information.", + "CmdSettingCopiedFilesLog": "Path to the copied files log to create", + "CmdSettingInstalledDir": "Path to the installed tree to use", + "CmdSettingTLogFile": "Path to the tlog file to create", + "CmdSettingTargetBin": "Path to the binary to analyze", + "CmdUpdateBaselineOptDryRun": "Print out plan without execution", + "CmdUpdateBaselineOptInitial": "add a `builtin-baseline` to a vcpkg.json that doesn't already have it", + "CmdUpgradeOptAllowUnsupported": "Instead of erroring on an unsupported port, continue with a warning.", + "CmdUpgradeOptNoDryRun": "Actually upgrade", + "CmdUpgradeOptNoKeepGoing": "Stop installing packages on failure", + "CmdXDownloadOptHeader": "Additional header to use when fetching from URLs", + "CmdXDownloadOptSha": "The hash of the file to be downloaded", + "CmdXDownloadOptSkipSha": "Do not check the SHA512 of the downloaded file", + "CmdXDownloadOptStore": "Indicates the file should be stored instead of fetched", + "CmdXDownloadOptUrl": "URL to download and store if missing from cache", + "CommandFailed": "command:\n{command_line}\nfailed with the following results:", + "CommunityTriplets": "VCPKG community triplets:", + "ComparingUtf8Decoders": "Comparing Utf8Decoders with different provenance; this is always an error", + "CompressFolderFailed": "Failed to compress folder \"{path}\":", + "ComputingInstallPlan": "Computing installation plan...", + "ConfigurationErrorRegistriesWithoutBaseline": "The configuration defined in {path} is invalid.\n\nUsing registries requires that a baseline is set for the default registry or that the default registry is null.\n\nSee {url} for more details.", + "ConflictingFiles": "The following files are already installed in {path} and are in conflict with {spec}", + "ConflictingValuesForOption": "conflicting values specified for '--{option}'.", + "ConstraintViolation": "Found a constraint violation:", + "ContinueCodeUnitInStart": "found continue code unit in start position", + "ControlAndManifestFilesPresent": "Both a manifest file and a CONTROL file exist in port directory: {path}", + "ControlCharacterInString": "Control character in string", + "CopyrightIsDir": "`{path}` being a directory is deprecated.", + "CorruptedDatabase": "Database corrupted.", + "CorruptedInstallTree": "Your vcpkg 'installed' tree is corrupted.", + "CouldNotDeduceNugetIdAndVersion": "Could not deduce nuget id and version from filename: {path}", + "CouldNotFindBaseline": "Could not find explicitly specified baseline `\"{commit_sha}\"` in baseline file {path}", + "CouldNotFindBaselineForRepo": "Couldn't find baseline `\"{commit_sha}\"` for repo {package_name}", + "CouldNotFindBaselineInCommit": "Couldn't find baseline in commit `\"{commit_sha}\"` from repo {package_name}:", + "CouldNotFindGitTreeAtCommit": "could not find the git tree for `versions` in repo {package_name} at commit {commit_sha}", + "CouldNotFindToolVersion": "Could not find in {path}", + "CreateFailureLogsDir": "Creating failure logs output directory {path}.", + "CreatedNuGetPackage": "Created nupkg: {path}", + "Creating7ZipArchive": "Creating 7zip archive...", + "CreatingNugetPackage": "Creating NuGet package...", + "CreatingZipArchive": "Creating zip archive...", + "CreationFailed": "Creating {path} failed.", + "CurlFailedToExecute": "curl failed to execute with exit code {exit_code}.", + "CurlFailedToPut": "curl failed to put file to {url} with exit code {exit_code}.", + "CurlFailedToPutHttp": "curl failed to put file to {url} with exit code {exit_code} and http code {value}.", + "CurlReportedUnexpectedResults": "curl has reported unexpected results to vcpkg and vcpkg cannot continue.\nPlease review the following text for sensitive information and open an issue on the Microsoft/vcpkg GitHub to help fix this problem!\ncmd: {command_line}\n=== curl output ===\n{actual}\n=== end curl output ===", + "CurlReturnedUnexpectedResponseCodes": "curl returned a different number of response codes than were expected for the request ({actual} vs expected {expected}).", + "CurrentCommitBaseline": "You can use the current commit as a baseline, which is:\n\t\"builtin-baseline\": \"{value}\"", + "DateTableHeader": "Date", + "DefaultBrowserLaunched": "Default browser launched to {url}.", + "DefaultFlag": "Defaulting to --{option} being on.", + "DefaultPathToBinaries": "Based on your system settings, the default path to store binaries is \"{path}\". This consults %LOCALAPPDATA%/%APPDATA% on Windows and $XDG_CACHE_HOME or $HOME on other platforms.", + "DeleteVcpkgConfigFromManifest": "-- Or remove \"vcpkg-configuration\" from the manifest file {path}.", + "DeprecatedPrefabDebugOption": "--prefab-debug is now deprecated.", + "DetectCompilerHash": "Detecting compiler hash for triplet {triplet}...", + "DocumentedFieldsSuggestUpdate": "If these are documented fields that should be recognized try updating the vcpkg tool.", + "DownloadAvailable": "A downloadable copy of this tool is available and can be used by unsetting {env_var}.", + "DownloadFailedCurl": "{url}: curl failed to download with exit code {exit_code}", + "DownloadFailedHashMismatch": "File does not have the expected hash:\nurl: {url}\nFile: {path}\nExpected hash: {expected}\nActual hash: {actual}", + "DownloadFailedRetrying": "Download failed -- retrying after {value}ms", + "DownloadFailedStatusCode": "{url}: failed: status code {value}", + "DownloadRootsDir": "Specify the downloads root directory.\n(default: {env_var})", + "DownloadWinHttpError": "{url}: {system_api} failed with exit code {exit_code}", + "DownloadedSources": "Downloaded sources for {spec}", + "DownloadingPortableToolVersionX": "A suitable version of {tool_name} was not found (required v{version}) Downloading portable {tool_name} {version}...", + "DownloadingTool": "Downloading {tool_name}...\n{url}->{path}", + "DownloadingUrl": "Downloading {url}", + "DownloadingVcpkgCeBundle": "Downloading vcpkg-artifacts bundle {version}...", + "DownloadingVcpkgCeBundleLatest": "Downloading latest vcpkg-artifacts bundle...", + "DownloadingVcpkgStandaloneBundle": "Downloading standalone bundle {version}.", + "DownloadingVcpkgStandaloneBundleLatest": "Downloading latest standalone bundle.", + "DuplicateCommandOption": "The option --{option} can only be passed once.", + "DuplicateOptions": "'--{value}' specified multiple times.", + "DuplicatePackagePattern": "Package \"{package_name}\" is duplicated.", + "DuplicatePackagePatternFirstOcurrence": "First declared in:", + "DuplicatePackagePatternIgnoredLocations": "The following redeclarations will be ignored:", + "DuplicatePackagePatternLocation": "location: {path}", + "DuplicatePackagePatternRegistry": "registry: {url}", + "DuplicatedKeyInObj": "Duplicated key \"{value}\" in an object", + "ElapsedForPackage": "Elapsed time to handle {spec}: {elapsed}", + "ElapsedInstallTime": "Total elapsed time: {count}", + "ElapsedTimeForChecks": "Time to determine pass/fail: {elapsed}", + "EmailVcpkgTeam": "Send an email to {url} with any feedback.", + "EmbeddingVcpkgConfigInManifest": "Embedding `vcpkg-configuration` in a manifest file is an EXPERIMENTAL feature.", + "EmptyArg": "The option --{option} must be passed a non-empty argument.", + "EmptyLicenseExpression": "SPDX license expression was empty.", + "EndOfStringInCodeUnit": "found end of string in middle of code point", + "EnvInvalidMaxConcurrency": "{env_var} is {value}, must be > 0", + "EnvStrFailedToExtract": "could not expand the environment string:", + "ErrorDetectingCompilerInfo": "while detecting compiler information:\nThe log file content at \"{path}\" is:", + "ErrorIndividualPackagesUnsupported": "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": "The option --{option} is not supported in classic mode and no manifest was found.", + "ErrorInvalidManifestModeOption": "The option --{option} is not supported in manifest mode.", + "ErrorMessage": "error: ", + "ErrorMessageMustUsePrintError": "The message named {value} starts with error:, it must be changed to prepend ErrorMessage in code instead.", + "ErrorMissingVcpkgRoot": "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 https://github.com/Microsoft/vcpkg.", + "ErrorNoVSInstance": "in triplet {triplet}: Unable to find a valid Visual Studio instance", + "ErrorNoVSInstanceAt": "at \"{path}\"", + "ErrorNoVSInstanceFullVersion": "with toolset version prefix {version}", + "ErrorNoVSInstanceVersion": "with toolset version {version}", + "ErrorParsingBinaryParagraph": "while parsing the Binary Paragraph for {spec}", + "ErrorRequireBaseline": "this vcpkg instance requires a manifest with a specified baseline in order to interact with ports. Please add 'builtin-baseline' to the manifest or add a 'vcpkg-configuration.json' that redefines the default registry.", + "ErrorRequirePackagesList": "`vcpkg install` requires a list of packages to install in classic mode.", + "ErrorUnableToDetectCompilerInfo": "vcpkg was unable to detect the active compiler's information. See above for the CMake failure output.", + "ErrorVcvarsUnsupported": "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.", + "ErrorVsCodeNotFound": "Visual Studio Code was not found and the environment variable {env_var} is not set or invalid.", + "ErrorVsCodeNotFoundPathExamined": "The following paths were examined:", + "ErrorWhileFetchingBaseline": "while fetching baseline `\"{value}\"` from repo {package_name}:", + "ErrorWhileParsing": "Errors occurred while parsing {path}.", + "ErrorWhileWriting": "Error occured while writing {path}", + "ErrorsFound": "Found the following errors:", + "ExceededRecursionDepth": "Recursion depth exceeded.", + "ExcludedPackage": "Excluded {spec}", + "ExcludedPackages": "The following packages are excluded:", + "ExpectedAtMostOneSetOfTags": "Found {count} sets of {old_value}.*{new_value} but expected at most 1, in block:\n{value}", + "ExpectedCascadeFailure": "Expected {expected} cascade failure, but there were {actual} cascade failures.", + "ExpectedCharacterHere": "expected '{expected}' here", + "ExpectedDigitsAfterDecimal": "Expected digits after the decimal point", + "ExpectedExtension": "The file extension was not {extension}: {path}", + "ExpectedFailOrSkip": "expected 'fail', 'skip', or 'pass' here", + "ExpectedOneSetOfTags": "Found {count} sets of {old_value}.*{new_value} but expected exactly 1, in block:\n{value}", + "ExpectedPathToExist": "Expected {path} to exist after fetching", + "ExpectedPortName": "expected a port name here", + "ExpectedStatusField": "Expected 'status' field in status paragraph", + "ExpectedTripletName": "expected a triplet name here", + "ExpectedValueForOption": "expected value after --{option}.", + "ExportArchitectureReq": "Export prefab requires targeting at least one of the following architectures arm64-v8a, armeabi-v7a, x86_64, x86 to be present.", + "ExportPrefabRequiresAndroidTriplet": "export prefab requires an Android triplet.", + "ExportUnsupportedInManifest": "vcpkg export does not support manifest mode, in order to allow for future design considerations. You may use export in classic mode by running vcpkg outside of a manifest-based project.", + "Exported7zipArchive": "7zip archive exported at: {path}", + "ExportedZipArchive": "Zip archive exported at: {path}", + "ExportingAlreadyBuiltPackages": "The following packages are already built and will be exported:", + "ExportingMaintenanceTool": "Exporting maintenance tool...", + "ExportingPackage": "Exporting {package_name}...", + "ExtendedDocumentationAtUrl": "Extended documentation available at '{url}'.", + "ExtractingTool": "Extracting {tool_name}...", + "FailedPostBuildChecks": "Found {count} post-build check problem(s). To submit these ports to curated catalogs, please first correct the portfile: {path}", + "FailedToCheckoutRepo": "failed to check out `versions` from repo {package_name}", + "FailedToDetermineArchitecture": "unable to determine the architecture of {path}.\n{command_line}", + "FailedToDetermineCurrentCommit": "Failed to determine the current commit:", + "FailedToDownloadFromMirrorSet": "Failed to download from mirror set", + "FailedToExtract": "Failed to extract \"{path}\":", + "FailedToFetchError": "{error_msg}\nFailed to fetch {package_name}:", + "FailedToFindBaseline": "Failed to find baseline.json", + "FailedToFindPortFeature": "Could not find {feature} in {spec}.", + "FailedToFormatMissingFile": "No files to format.\nPlease pass either --all, or the explicit files to format or convert.", + "FailedToLoadInstalledManifest": "The control or manifest file for {spec} could not be loaded due to the following error. Please remove {spec} and try again.", + "FailedToLoadManifest": "Failed to load manifest from directory {path}", + "FailedToLoadPort": "Failed to load port {package_name} from {path}", + "FailedToLoadPortFrom": "Failed to load port from {path}", + "FailedToLoadUnnamedPortFromPath": "Failed to load port from {path}", + "FailedToLocateSpec": "Failed to locate spec in graph: {spec}", + "FailedToObtainDependencyVersion": "Cannot find desired dependency version.", + "FailedToObtainLocalPortGitSha": "Failed to obtain git SHAs for local ports.", + "FailedToObtainPackageVersion": "Cannot find desired package version.", + "FailedToParseCMakeConsoleOut": "Failed to parse CMake console output to locate block start/end markers.", + "FailedToParseConfig": "Failed to parse configuration {path}", + "FailedToParseControl": "Failed to parse control file: {path}", + "FailedToParseJson": "Failed to parse JSON file: {path}", + "FailedToParseManifest": "Failed to parse manifest file: {path}", + "FailedToParseNoTopLevelObj": "Failed to parse {path}, expected a top-level object.", + "FailedToParseSerializedBinParagraph": "[sanity check] Failed to parse a serialized binary paragraph.\nPlease open an issue at https://github.com/microsoft/vcpkg, with the following output:\n{error_msg}\nSerialized Binary Paragraph:", + "FailedToParseVersionXML": "Could not parse version for tool {tool_name}. Version string was: {version}", + "FailedToProvisionCe": "Failed to provision vcpkg-artifacts.", + "FailedToRead": "Failed to read {path}: {error_msg}", + "FailedToReadParagraph": "Failed to read paragraphs from {path}", + "FailedToRemoveControl": "Failed to remove control file {path}", + "FailedToRunToolToDetermineVersion": "Failed to run \"{path}\" to determine the {tool_name} version.", + "FailedToStoreBackToMirror": "failed to store back to mirror:", + "FailedToStoreBinaryCache": "Failed to store binary cache {path}", + "FailedToTakeFileSystemLock": "Failed to take the filesystem lock on {path}", + "FailedToWriteManifest": "Failed to write manifest file {path}", + "FailedVendorAuthentication": "One or more {vendor} credential providers failed to authenticate. See '{url}' for more details on how to provide credentials.", + "FeedbackAppreciated": "Thank you for your feedback!", + "FetchingBaselineInfo": "Fetching baseline information from {package_name}...", + "FetchingRegistryInfo": "Fetching registry information from {url} ({value})...", + "FileNotFound": "{path}: file not found", + "FileReadFailed": "Failed to read {count} bytes from {path} at offset {byte_offset}.", + "FileSeekFailed": "Failed to seek to position {byte_offset} in {path}.", + "FileSystemOperationFailed": "Filesystem operation failed:", + "FilesExported": "Files exported at: {path}", + "FishCompletion": "vcpkg fish completion is already added at \"{path}\".", + "FloatingPointConstTooBig": "Floating point constant too big: {count}", + "FollowingPackagesMissingControl": "The following packages do not have a valid CONTROL or vcpkg.json:", + "FollowingPackagesNotInstalled": "The following packages are not installed:", + "FollowingPackagesUpgraded": "The following packages are up-to-date:", + "ForceSystemBinariesOnWeirdPlatforms": "Environment variable VCPKG_FORCE_SYSTEM_BINARIES must be set on arm, s390x, and ppc64le platforms.", + "FormattedParseMessageExpression": "on expression: {value}", + "GenerateMsgErrorParsingFormatArgs": "parsing format string for {value}:", + "GenerateMsgIncorrectComment": "message {value} has an incorrect comment:", + "GenerateMsgNoArgumentValue": "{{{value}}} was specified in a comment, but was not used in the message.", + "GenerateMsgNoCommentValue": "{{{value}}} was used in the message, but not commented.", + "GeneratedConfiguration": "Generated configuration {path}.", + "GeneratedInstaller": "{path} installer generated.", + "GeneratingConfiguration": "Generating configuration {path}...", + "GeneratingInstaller": "Generating installer {path}...", + "GeneratingRepo": "Generating repository {path}...", + "GetParseFailureInfo": "Use '--debug' to get more information about the parse failures.", + "GitCommandFailed": "failed to execute: {command_line}", + "GitRegistryMustHaveBaseline": "The git registry entry for \"{package_name}\" must have a \"baseline\" field that is a valid git commit SHA (40 hexadecimal characters).\nThe current HEAD of that repo is \"{value}\".", + "GitStatusOutputExpectedFileName": "expected a file name", + "GitStatusOutputExpectedNewLine": "expected new line", + "GitStatusOutputExpectedRenameOrNewline": "expected renamed file or new lines", + "GitStatusUnknownFileStatus": "unknown file status: {value}", + "GitUnexpectedCommandOutput": "unexpected git output", + "GraphCycleDetected": "Cycle detected within graph at {package_name}:", + "HashFileFailureToRead": "failed to read file \"{path}\" for hashing: ", + "HeaderOnlyUsage": "{package_name} is header-only and can be used from CMake via:", + "HelpBuiltinBase": "The baseline references a commit within the vcpkg repository that establishes a minimum version on every dependency in the graph. For example, if no other constraints are specified (directly or transitively), then the version will resolve to the baseline of the top level manifest. Baselines of transitive dependencies are ignored.", + "HelpContactCommand": "Display contact information to send feedback.", + "HelpCreateCommand": "Create a new port.", + "HelpDependInfoCommand": "Display a list of dependencies for ports.", + "HelpEditCommand": "Open a port for editing (use the environment variable '{env_var}' to set an editor program, defaults to 'code').", + "HelpEnvCommand": "Creates a clean shell environment for development or compiling.", + "HelpExampleCommand": "For more help (including examples) see the accompanying README.md and docs folder.", + "HelpExampleManifest": "Example manifest:", + "HelpExportCommand": "Exports a package.", + "HelpFormatManifestCommand": "Formats all vcpkg.json files. Run this before committing to vcpkg.", + "HelpHashCommand": "Hash a file by specific algorithm, default SHA512.", + "HelpInitializeRegistryCommand": "Initializes a registry in the directory .", + "HelpInstallCommand": "Install a package.", + "HelpListCommand": "List installed packages.", + "HelpManifestConstraints": "Manifests can place three kinds of constraints upon the versions used", + "HelpMinVersion": "Vcpkg will select the minimum version found that matches all applicable constraints, including the version from the baseline specified at top-level as well as any \"version>=\" constraints in the graph.", + "HelpOverrides": "When used as the top-level manifest (such as when running `vcpkg install` in the directory), overrides allow a manifest to short-circuit dependency resolution and specify exactly the version to use. These can be used to handle version conflicts, such as with `version-string` dependencies. They will not be considered when transitively depended upon.", + "HelpOwnsCommand": "Search for files in installed packages.", + "HelpPackagePublisher": "Additionally, package publishers can use \"version>=\" constraints to ensure that consumers are using at least a certain minimum version of a given dependency. For example, if a library needs an API added to boost-asio in 1.70, a \"version>=\" constraint will ensure transitive users use a sufficient version even in the face of individual version overrides or cross-registry references.", + "HelpPortVersionScheme": "Each version additionally has a \"port-version\" which is a nonnegative integer. When rendered as text, the port version (if nonzero) is added as a suffix to the primary version text separated by a hash (#). Port-versions are sorted lexographically after the primary version text, for example:\n1.0.0 < 1.0.0#1 < 1.0.1 < 1.0.1#5 < 2.0.0", + "HelpRemoveCommand": "Uninstall a package.", + "HelpRemoveOutdatedCommand": "Uninstall all out-of-date packages.", + "HelpResponseFileCommand": "Specify a response file to provide additional parameters.", + "HelpSearchCommand": "Search for packages available to be built.", + "HelpTextOptFullDesc": "Do not truncate long text", + "HelpTopicCommand": "Display help for a specific topic.", + "HelpTopicsCommand": "Display the list of help topics.", + "HelpTxtOptAllowUnsupportedPort": "Instead of erroring on an unsupported port, continue with a warning.", + "HelpTxtOptCleanAfterBuild": "Clean buildtrees, packages and downloads after building each package", + "HelpTxtOptCleanBuildTreesAfterBuild": "Clean buildtrees after building each package", + "HelpTxtOptCleanDownloadsAfterBuild": "Clean downloads after building each package", + "HelpTxtOptCleanPkgAfterBuild": "Clean packages after building each package", + "HelpTxtOptDryRun": "Do not actually build or install.", + "HelpTxtOptEditable": "Disable source re-extraction and binary caching for libraries on the command line (classic mode)", + "HelpTxtOptEnforcePortChecks": "Fail install if a port has detected problems or attempts to use a deprecated feature", + "HelpTxtOptKeepGoing": "Continue installing packages on failure", + "HelpTxtOptManifestFeature": "Additional feature from the top-level manifest to install (manifest mode).", + "HelpTxtOptManifestNoDefault": "Don't install the default features from the top-level manifest (manifest mode).", + "HelpTxtOptNoDownloads": "Do not download new sources", + "HelpTxtOptNoUsage": "Don't print CMake usage information after install.", + "HelpTxtOptOnlyBinCache": "Fail if cached binaries are not available", + "HelpTxtOptOnlyDownloads": "Download sources but don't build packages", + "HelpTxtOptRecurse": "Allow removal of packages as part of installation", + "HelpTxtOptUseAria2": "Use aria2 to perform download tasks", + "HelpTxtOptUseHeadVersion": "Install the libraries on the command line using the latest upstream sources (classic mode)", + "HelpTxtOptWritePkgConfig": "Writes out a NuGet packages.config-formatted file for use with external binary caching.\nSee `vcpkg help binarycaching` for more information.", + "HelpUpdateBaseline": "The best approach to keep your libraries up to date, the best approach is to update your baseline reference. This will ensure all packages, including transitive ones, are updated. However if you need to update a package independently, you can use a \"version>=\" constraint.", + "HelpUpdateCommand": "List packages that can be updated.", + "HelpUpgradeCommand": "Rebuild all outdated packages.", + "HelpVersionCommand": "Display version information.", + "HelpVersionDateScheme": "A date (2021-01-01.5)", + "HelpVersionGreater": "Within the \"dependencies\" field, each dependency can have a minimum constraint listed. These minimum constraints will be used when transitively depending upon this library. A minimum port-version can additionally be specified with a '#' suffix.", + "HelpVersionScheme": "A dot-separated sequence of numbers (1.2.3.4)", + "HelpVersionSchemes": "The following versioning schemes are accepted.", + "HelpVersionSemverScheme": "A Semantic Version 2.0 (2.1.0-rc2)", + "HelpVersionStringScheme": "An exact, incomparable version (Vista)", + "HelpVersioning": "Versioning allows you to deterministically control the precise revisions of dependencies used by your project from within your manifest file.", + "IgnoringVcpkgRootEnvironment": "The vcpkg {value} is using detected vcpkg root {actual} and ignoring mismatched VCPKG_ROOT environment value {path}. To suppress this message, unset the environment variable or use the --vcpkg-root command line switch.", + "IllegalFeatures": "List of features is not allowed in this context", + "IllegalPlatformSpec": "Platform qualifier is not allowed in this context", + "ImproperShaLength": "SHA512's must be 128 hex characters: {value}", + "IncorrectArchiveFileSignature": "Incorrect archive file signature", + "IncorrectLibHeaderEnd": "Incorrect lib header end", + "IncorrectNumberOfArgs": "'{command_name}' requires '{expected}' arguments, but '{actual}' were provided.", + "IncorrectPESignature": "Incorrect PE signature", + "IncrementedUtf8Decoder": "Incremented Utf8Decoder at the end of the string", + "InfoSetEnvVar": "You can also set the environment variable '{env_var}' to your editor of choice.", + "InitRegistryFailedNoRepo": "Could not create a registry at {path} because this is not a git repository root.\nUse `git init {command_line}` to create a git repository in this folder.", + "InstallFailed": "failed: {path}: {error_msg}", + "InstallPackageInstruction": "With a project open, go to Tools->NuGet Package Manager->Package Manager Console and paste:\n Install-Package \"{value}\" -Source \"{path}\"", + "InstallRootDir": "(Experimental) Specify the install root directory.", + "InstallWithSystemManager": "You may be able to install this tool via your system package manager.", + "InstallWithSystemManagerMono": "Ubuntu 18.04 users may need a newer version of mono, available at {url}.", + "InstallWithSystemManagerPkg": "You may be able to install this tool via your system package manager ({command_line}).", + "InstalledBy": "Installed by {path}", + "InstalledPackages": "The following packages are already installed:", + "InstalledRequestedPackages": "All requested packages are currently installed.", + "InstallingFromLocation": "-- Installing port from location: {path}", + "InstallingMavenFile": "{path} installing Maven file", + "InstallingPackage": "Installing {action_index}/{count} {spec}...", + "IntegrationFailed": "Integration was not applied.", + "InternalCICommand": "vcpkg ci is an internal command which will change incompatibly or be removed at any time.", + "InternalErrorMessage": "internal error: ", + "InternalErrorMessageContact": "Please open an issue at https://github.com/microsoft/vcpkg/issues/new?template=other-type-of-bug-report.md&labels=category:vcpkg-bug with detailed steps to reproduce the problem.", + "InvalidArgMustBeAnInt": "--{option} must be an integer.", + "InvalidArgMustBePositive": "--{option} must be non-negative.", + "InvalidArgument": "invalid argument", + "InvalidArgumentRequiresAbsolutePath": "invalid argument: binary config '{binary_source}' path arguments for binary config strings must be absolute", + "InvalidArgumentRequiresBaseUrl": "invalid argument: binary config '{binary_source}' requires a {base_url} base url as the first argument", + "InvalidArgumentRequiresBaseUrlAndToken": "invalid argument: binary config '{binary_source}' requires at least a base-url and a SAS token", + "InvalidArgumentRequiresNoneArguments": "invalid argument: binary config '{binary_source}' does not take arguments", + "InvalidArgumentRequiresOneOrTwoArguments": "invalid argument: binary config '{binary_source}' requires 1 or 2 arguments", + "InvalidArgumentRequiresPathArgument": "invalid argument: binary config '{binary_source}' requires at least one path argument", + "InvalidArgumentRequiresPrefix": "invalid argument: binary config '{binary_source}' requires at least one prefix", + "InvalidArgumentRequiresSingleArgument": "invalid argument: binary config '{binary_source}' does not take more than 1 argument", + "InvalidArgumentRequiresSingleStringArgument": "invalid argument: binary config '{binary_source}' expects a single string argument", + "InvalidArgumentRequiresSourceArgument": "invalid argument: binary config '{binary_source}' requires at least one source argument", + "InvalidArgumentRequiresTwoOrThreeArguments": "invalid argument: binary config '{binary_source}' requires 2 or 3 arguments", + "InvalidArgumentRequiresValidToken": "invalid argument: binary config '{binary_source}' requires a SAS token without a preceeding '?' as the second argument", + "InvalidBuildInfo": "Invalid BUILD_INFO file for package: {error_msg}", + "InvalidBuiltInBaseline": "the top-level builtin-baseline ({value}) was not a valid commit sha: expected 40 hexadecimal characters.", + "InvalidBundleDefinition": "Invalid bundle definition.", + "InvalidCodePoint": "Invalid code point passed to utf8_encoded_code_point_count", + "InvalidCodeUnit": "invalid code unit", + "InvalidCommandArgSort": "Value of --sort must be one of 'lexicographical', 'topological', 'reverse'.", + "InvalidCommentStyle": "vcpkg does not support c-style comments, however most objects allow $-prefixed fields to be used as comments.", + "InvalidCommitId": "Invalid commit id: {commit_sha}", + "InvalidFileType": "failed: {path} cannot handle file type", + "InvalidFilename": "Filename cannot contain invalid chars {value}, but was {path}", + "InvalidFloatingPointConst": "Invalid floating point constant: {count}", + "InvalidFormatString": "invalid format string: {actual}", + "InvalidHexDigit": "Invalid hex digit in unicode escape", + "InvalidIntegerConst": "Invalid integer constant: {count}", + "InvalidLinkage": "Invalid {system_name} linkage type: [{value}]", + "InvalidOptionForRemove": "'remove' accepts either libraries or '--outdated'", + "InvalidPortVersonName": "Found invalid port version file name: `{path}`.", + "InvalidString": "Invalid utf8 passed to Value::string(std::string)", + "InvalidTriplet": "Invalid triplet: {triplet}", + "InvalidUri": "unable to parse uri: {value}", + "IrregularFile": "path was not a regular file: {path}", + "JsonErrorMustBeAnObject": "Expected \"{path}\" to be an object.", + "JsonFileMissingExtension": "the JSON file {path} must have a .json (all lowercase) extension", + "JsonSwitch": "(Experimental) Request JSON output.", + "JsonValueNotArray": "json value is not an array", + "JsonValueNotObject": "json value is not an object", + "JsonValueNotString": "json value is not a string", + "LaunchingProgramFailed": "Launching {tool_name}:", + "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/", + "LintDeprecatedFunction": "The deprecated function \"{actual}\" is used inside the port \"{package_name}\". Use the function \"{expected}\" instead.", + "LintDeprecatedLicenseExpressionWithReplacement": "The port \"{package_name}\" uses the deprecated license expression \"{actual}\". You shoud use the non deprecated version \"{new_value}\".", + "LintDeprecatedLicenseExpressionWithoutReplacement": "The port \"{package_name}\" uses the deprecated license expression \"{actual}\". Use license expression including main license, \"WITH\" operator, and identifier: \"{new_value}\"", + "LintMissingLicenseExpression": "There is no license expression in port \"{package_name}\". You could use https://tools.spdx.org/app/check_license/ to determine the right license expression.", + "LintPortErrors": "The port \"{package_name}\" should be fixed. See warning(s) above.", + "LintPortErrorsFixed": "Problems in the port \"{package_name}\" have been fixed.", + "LintSuggestNewVersionScheme": "Use the version scheme \"{new_scheme}\" instead of \"{old_scheme}\" in port \"{package_name}\".", + "LintVcpkgCheckFeatures": "Calling `vcpkg_check_features` without the `FEATURES` keyword has been deprecated. Please add the `FEATURES` keyword to the call inside the port {package_name}.", + "ListOfValidFieldsForControlFiles": "This is the list of valid fields for CONTROL files (case-sensitive):", + "LoadingCommunityTriplet": "-- [COMMUNITY] Loading triplet configuration from: {path}", + "LoadingDependencyInformation": "Loading dependency information for {count} packages...", + "LoadingOverlayTriplet": "-- [OVERLAY] Loading triplet configuration from: {path}", + "LocalPortfileVersion": "Using local portfile versions. To update the local portfiles, use `git pull`.", + "LocalizedMessageMustNotContainIndents": "The message named {value} contains what appears to be indenting which must be changed to use LocalizedString::append_indent instead.", + "LocalizedMessageMustNotEndWithNewline": "The message named {value} ends with a newline which should be added by formatting rather than by localization.", + "ManifestConflict": "Found both a manifest and CONTROL files in port \"{path}\"; please rename one or the other", + "ManifestFormatCompleted": "Succeeded in formatting the manifest files.", + "MismatchedFiles": "file to store does not match hash", + "MismatchedManifestAfterReserialize": "The serialized manifest was different from the original manifest. Please open an issue at https://github.com/microsoft/vcpkg, with the following output:", + "MismatchedNames": "names did not match: '{package_name}' != '{actual}'", + "Missing7zHeader": "Unable to find 7z header.", + "MissingAndroidEnv": "ANDROID_NDK_HOME environment variable missing", + "MissingAndroidHomeDir": "ANDROID_NDK_HOME directory does not exist: {path}", + "MissingArgFormatManifest": "format-manifest was passed --convert-control without '--all'.\nThis doesn't do anything: control files passed explicitly are converted automatically.", + "MissingDependency": "Package {spec} is installed, but dependency {package_name} is not.", + "MissingExtension": "Missing '{extension}' extension.", + "MissingOption": "This command requires --{option}", + "MissingPortSuggestPullRequest": "If your port is not listed, please open an issue at and/or consider making a pull request.", + "MissmatchedBinParagraphs": "The serialized binary paragraph was different from the original binary paragraph. Please open an issue at https://github.com/microsoft/vcpkg with the following output:", + "MonoInstructions": "This may be caused by an incomplete mono installation. Full mono is available on some systems via `sudo apt install mono-complete`. Ubuntu 18.04 users may need a newer version of mono, available at https://www.mono-project.com/download/stable/", + "MsiexecFailedToExtract": "msiexec failed while extracting \"{path}\" with launch or exit code {exit_code} and message:", + "MultiArch": "Multi-Arch must be 'same' but was {option}", + "MutuallyExclusiveOption": "--{value} can not be used with --{option}.", + "NavigateToNPS": "Please navigate to {url} in your preferred browser.", + "NewConfigurationAlreadyExists": "Creating a manifest would overwrite a vcpkg-configuration.json at {path}.", + "NewManifestAlreadyExists": "A manifest is already present at {path}.", + "NewNameCannotBeEmpty": "--name cannot be empty.", + "NewOnlyOneVersionKind": "Only one of --version-relaxed, --version-date, or --version-string may be specified.", + "NewSpecifyNameVersionOrApplication": "Either specify --name and --version to produce a manifest intended for C++ libraries, or specify --application to indicate that the manifest is not intended to be used as a port.", + "NewVersionCannotBeEmpty": "--version cannot be empty.", + "NoArgumentsForOption": "The option --{option} does not accept an argument.", + "NoCachedPackages": "No packages are cached.", + "NoError": "no error", + "NoInstalledPackages": "No packages are installed. Did you mean `search`?", + "NoLocalizationForMessages": "No localized messages for the following: ", + "NoOutdatedPackages": "There are no outdated packages.", + "NoRegistryForPort": "no registry configured for port {package_name}", + "NoUrlsAndHashSpecified": "No urls specified to download SHA: {sha}", + "NoUrlsAndNoHashSpecified": "No urls specified and no hash specified.", + "NoteMessage": "note: ", + "NugetPackageFileSucceededButCreationFailed": "NuGet package creation succeeded, but no .nupkg was produced. Expected: \"{path}\"", + "OptionMustBeInteger": "Value of --{option} must be an integer.", + "OptionRequired": "--{option} option is required.", + "OptionRequiresOption": "--{value} requires --{option}", + "OriginalBinParagraphHeader": "\nOriginal Binary Paragraph", + "OverlayPatchDir": "Overlay path \"{path}\" must exist and must be a directory.", + "OverlayTriplets": "Overlay triplets from {path} :", + "OverwritingFile": "File {path} was already present and will be overwritten", + "PECoffHeaderTooShort": "While parsing Portable Executable {path}, size of COFF header too small to contain a valid PE header.", + "PEConfigCrossesSectionBoundary": "While parsing Portable Executable {path}, image config directory crosses a secion boundary.", + "PEImportCrossesSectionBoundary": "While parsing Portable Executable {path}, import table crosses a secion boundary.", + "PEPlusTagInvalid": "While parsing Portable Executable {path}, optional header was neither PE32 nor PE32+.", + "PERvaNotFound": "While parsing Portable Executable {path}, could not find RVA {value:#X}.", + "PESignatureMismatch": "While parsing Portable Executable {path}, signature mismatch.", + "PackageAlreadyRemoved": "unable to remove package {spec}: already removed", + "PackageFailedtWhileExtracting": "'{value}' failed while extracting {path}.", + "PackageRootDir": "(Experimental) Specify the packages root directory.", + "PackagesToInstall": "The following packages will be built and installed:", + "PackagesToInstallDirectly": "The following packages will be directly installed:", + "PackagesToModify": "Additional packages (*) will be modified to complete this operation.", + "PackagesToRebuild": "The following packages will be rebuilt:", + "PackagesToRebuildSuggestRecurse": "If you are sure you want to rebuild the above packages, run the command with the --recurse option.", + "PackagesToRemove": "The following packages will be removed:", + "PackagesUpToDate": "No packages need updating.", + "PackingVendorFailed": "Packing {vendor} failed. Use --debug for more information.", + "PairedSurrogatesAreInvalid": "trailing surrogate following leading surrogate (paired surrogates are invalid)", + "ParseControlErrorInfoInvalidFields": "The following fields were not expected:", + "ParseControlErrorInfoMissingFields": "The following fields were missing:", + "ParseControlErrorInfoTypesEntry": "{value} was expected to be {expected}", + "ParseControlErrorInfoWhileLoading": "while loading {path}:", + "ParseControlErrorInfoWrongTypeFields": "The following fields had the wrong types:", + "ParseIdentifierError": "\"{value}\" is not a valid identifier. Identifiers must be lowercase alphanumeric+hypens and not reserved (see {url} for more information)", + "ParsePackageNameError": "\"{package_name}\" is not a valid package name. Package names must be lowercase alphanumeric+hypens and not reserved (see {url} for more information)", + "ParsePackagePatternError": "\"{package_name}\" is not a valid package pattern. Package patterns must use only one wildcard character (*) and it must be the last character in the pattern (see {url} for more information)", + "PathMustBeAbsolute": "Value of environment variable X_VCPKG_REGISTRIES_CACHE is not absolute: {path}", + "PerformingPostBuildValidation": "-- Performing post-build validation", + "PortBugAllowRestrictedHeaders": "In exceptional circumstances, this policy can be disabled via {env_var}", + "PortBugBinDirExists": "There should be no bin\\ directory in a static build, but {path} is present.", + "PortBugDebugBinDirExists": "There should be no debug\\bin\\ directory in a static build, but {path} is present.", + "PortBugDebugShareDir": "/debug/share should not exist. Please reorganize any important files, then use\nfile(REMOVE_RECURSE \"${{CURRENT_PACKAGES_DIR}}/debug/share\")", + "PortBugDllAppContainerBitNotSet": "The App Container bit must be set for Windows Store apps. The following DLLs do not have the App Container bit set:", + "PortBugDllInLibDir": "The following dlls were found in /lib or /debug/lib. Please move them to /bin or /debug/bin, respectively.", + "PortBugDuplicateIncludeFiles": "Include files should not be duplicated into the /debug/include directory. If this cannot be disabled in the project cmake, use\nfile(REMOVE_RECURSE \"${{CURRENT_PACKAGES_DIR}}/debug/include\")", + "PortBugFoundCopyrightFiles": "The following files are potential copyright files:", + "PortBugFoundDebugBinaries": "Found {count} debug binaries:", + "PortBugFoundDllInStaticBuild": "DLLs should not be present in a static build, but the following DLLs were found:", + "PortBugFoundEmptyDirectories": "There should be no empty directories in {path}. The following empty directories were found:", + "PortBugFoundExeInBinDir": "The following EXEs were found in /bin or /debug/bin. EXEs are not valid distribution targets.", + "PortBugFoundReleaseBinaries": "Found {count} release binaries:", + "PortBugIncludeDirInCMakeHelperPort": "The folder /include exists in a cmake helper port; this is incorrect, since only cmake files should be installed", + "PortBugInspectFiles": "To inspect the {extension} files, use:", + "PortBugInvalidCrtLinkage": "Invalid crt linkage. Expected {expected}, but the following libs had:", + "PortBugMergeLibCMakeDir": "The /lib/cmake folder should be merged with /debug/lib/cmake and moved to /share/{spec}/cmake. Please use the helper function `vcpkg_cmake_config_fixup()` from the port vcpkg-cmake-config.`", + "PortBugMismatchedNumberOfBinaries": "Mismatching number of debug and release binaries.", + "PortBugMisplacedCMakeFiles": "The following cmake files were found outside /share/{spec}. Please place cmake files in /share/{spec}.", + "PortBugMisplacedFiles": "The following files are placed in {path}:", + "PortBugMisplacedFilesCont": "Files cannot be present in those directories.", + "PortBugMisplacedPkgConfigFiles": "pkgconfig directories should be one of share/pkgconfig (for header only libraries only), lib/pkgconfig, or lib/debug/pkgconfig. The following misplaced pkgconfig files were found:", + "PortBugMissingDebugBinaries": "Debug binaries were not found.", + "PortBugMissingFile": "The /{path} file does not exist. This file must exist for CMake helper ports.", + "PortBugMissingImportedLibs": "Import libraries were not present in {path}.\nIf this is intended, add the following line in the portfile:\nset(VCPKG_POLICY_DLLS_WITHOUT_LIBS enabled)", + "PortBugMissingIncludeDir": "The folder /include is empty or not present. This indicates the library was not correctly installed.", + "PortBugMissingLicense": "The software license must be available at ${{CURRENT_PACKAGES_DIR}}/share/{spec}/copyright", + "PortBugMissingReleaseBinaries": "Release binaries were not found.", + "PortBugMovePkgConfigFiles": "You can move the pkgconfig files with commands similar to:", + "PortBugOutdatedCRT": "Detected outdated dynamic CRT in the following files:", + "PortBugRemoveBinDir": "If the creation of bin\\ and/or debug\\bin\\ cannot be disabled, use this in the portfile to remove them", + "PortBugRemoveEmptyDirectories": "If a directory should be populated but is not, this might indicate an error in the portfile.\nIf the directories are not needed and their creation cannot be disabled, use something like this in the portfile to remove them:", + "PortBugRemoveEmptyDirs": "vcpkg_fixup_pkgconfig()\nfile(REMOVE_RECURSE empty directories left by the above renames)", + "PortBugRestrictedHeaderPaths": "The following restricted headers can prevent the core C++ runtime and other packages from compiling correctly. In exceptional circumstances, this policy can be disabled via {env_var}.", + "PortBugSetDllsWithoutExports": "DLLs without any exports are likely a bug in the build script. If this is intended, add the following line in the portfile:\nset(VCPKG_POLICY_DLLS_WITHOUT_EXPORTS enabled)\nThe following DLLs have no exports:", + "PortDependencyConflict": "Port {package_name} has the following unsupported dependencies:", + "PortNotInBaseline": "the baseline does not contain an entry for port {package_name}", + "PortSupportsField": "(supports: \"{supports_expression}\")", + "PortTypeConflict": "The port type of {spec} differs between the installed and available portfile.\nPlease manually remove {spec} and re-run this command.", + "PortVersionConflict": "The following packages differ from their port versions:", + "PortsAdded": "The following {count} ports were added:", + "PortsNoDiff": "There were no changes in the ports between the two commits.", + "PortsRemoved": "The following {count} ports were removed:", + "PortsUpdated": "\nThe following {count} ports were updated:", + "PrebuiltPackages": "There are packages that have not been built. To build them run:", + "PreviousIntegrationFileRemains": "Previous integration file was not removed.", + "ProgramReturnedNonzeroExitCode": "{tool_name} failed with exit code: ({exit_code}).", + "ProvideExportType": "At least one of the following options are required: --raw --nuget --ifw --zip --7zip --chocolatey --prefab.", + "PushingVendorFailed": "Pushing {vendor} to \"{path}\" failed. Use --debug for more information.", + "RegistryCreated": "Successfully created registry at {path}", + "RemoveDependencies": "To remove dependencies in manifest mode, edit your manifest (vcpkg.json) and run 'install'.", + "RemovePackageConflict": "Another installed package matches the name of an unmatched request. Did you mean {spec}?", + "RemovingPackage": "Removing {action_index}/{count} {spec}", + "RestoredPackage": "Restored package from \"{path}\"", + "RestoredPackagesFromVendor": "Restored {count} package(s) from {value} in {elapsed}. Use --debug to see more details.", + "ResultsHeader": "RESULTS", + "SecretBanner": "*** SECRET ***", + "SeeURL": "See {url} for more information.", + "SerializedBinParagraphHeader": "\nSerialized Binary Paragraph", + "SettingEnvVar": "-- Setting \"{env_var}\" environment variables to \"{url}\".", + "ShaPassedAsArgAndOption": "SHA512 passed as both an argument and as an option. Only pass one of these.", + "ShaPassedWithConflict": "SHA512 passed, but --skip-sha512 was also passed; only do one or the other.", + "ShallowRepositoryDetected": "vcpkg was cloned as a shallow repository in: {path}\nTry again with a full vcpkg clone.", + "SkipClearingInvalidDir": "Skipping clearing contents of {path} because it was not a directory.", + "SourceFieldPortNameMismatch": "The 'Source' field inside the CONTROL file, or \"name\" field inside the vcpkg.json file has the name {package_name} and does not match the port directory \"{path}\".", + "SpecifiedFeatureTurnedOff": "'{command_name}' feature specifically turned off, but --{option} was specified.", + "SpecifyDirectoriesContaining": "Specifiy directories containing triplets files.\n(also: '{env_var}')", + "SpecifyDirectoriesWhenSearching": "Specify directories to be used when searching for ports.\n(also: '{env_var}')", + "SpecifyHostArch": "Specify the host architecture triplet. See 'vcpkg help triplet'.\n(default: '{env_var}')", + "SpecifyTargetArch": "Specify the target architecture triplet. See 'vcpkg help triplet'.\n(default: '{env_var}')", + "StartCodeUnitInContinue": "found start code unit in continue position", + "StoreOptionMissingSha": "--store option is invalid without a sha512", + "StoredBinaryCache": "Stored binary cache: \"{path}\"", + "SuccessfulyExported": "Exported {package_name} to {path}", + "SuggestGitPull": "The result may be outdated. Run `git pull` to get the latest results.", + "SuggestResolution": "To attempt to resolve all errors at once, run:\nvcpkg {command_name} --{option}", + "SuggestStartingBashShell": "Please make sure you have started a new bash shell for the change to take effect.", + "SuggestUpdateVcpkg": "You may need to update the vcpkg binary; try running {command_line} to update.", + "SupportedPort": "Port {package_name} is supported.", + "SystemApiErrorMessage": "calling {system_api} failed with {exit_code} ({error_msg})", + "ToRemovePackages": "To only remove outdated packages, run\n{command_name} remove --outdated", + "ToUpdatePackages": "To update these packages and all dependencies, run\n{command_name} upgrade'", + "ToolFetchFailed": "Could not fetch {tool_name}.", + "ToolInWin10": "This utility is bundled with Windows 10 or later.", + "ToolOfVersionXNotFound": "A suitable version of {tool_name} was not found (required v{version}) and unable to automatically download a portable one. Please install a newer version of {tool_name}", + "TotalInstallTime": "Total install time: {elapsed}", + "TrailingCommaInArray": "Trailing comma in array", + "TrailingCommaInObj": "Trailing comma in an object", + "TripletFileNotFound": "Triplet file {triplet}.cmake not found", + "TwoFeatureFlagsSpecified": "Both '{value}' and -'{value}' were specified as feature flags.", + "UndeterminedToolChainForTriplet": "Unable to determine toolchain use for {triplet} with with CMAKE_SYSTEM_NAME {system_name}. Did you mean to use VCPKG_CHAINLOAD_TOOLCHAIN_FILE?", + "UnexpectedByteSize": "Expected {expected} bytes to be written, but {actual} were written.", + "UnexpectedCharExpectedCloseBrace": "Unexpected character; expected property or close brace", + "UnexpectedCharExpectedColon": "Unexpected character; expected colon", + "UnexpectedCharExpectedComma": "Unexpected character; expected comma or close brace", + "UnexpectedCharExpectedName": "Unexpected character; expected property name", + "UnexpectedCharExpectedValue": "Unexpected character; expected value", + "UnexpectedCharMidArray": "Unexpected character in middle of array", + "UnexpectedCharMidKeyword": "Unexpected character in middle of keyword", + "UnexpectedDigitsAfterLeadingZero": "Unexpected digits after a leading zero", + "UnexpectedEOFAfterEscape": "Unexpected EOF after escape character", + "UnexpectedEOFAfterMinus": "Unexpected EOF after minus sign", + "UnexpectedEOFExpectedChar": "Unexpected character; expected EOF", + "UnexpectedEOFExpectedCloseBrace": "Unexpected EOF; expected property or close brace", + "UnexpectedEOFExpectedColon": "Unexpected EOF; expected colon", + "UnexpectedEOFExpectedName": "Unexpected EOF; expected property name", + "UnexpectedEOFExpectedProp": "Unexpected EOF; expected property", + "UnexpectedEOFExpectedValue": "Unexpected EOF; expected value", + "UnexpectedEOFMidArray": "Unexpected EOF in middle of array", + "UnexpectedEOFMidKeyword": "Unexpected EOF in middle of keyword", + "UnexpectedEOFMidString": "Unexpected EOF in middle of string", + "UnexpectedEOFMidUnicodeEscape": "Unexpected end of file in middle of unicode escape", + "UnexpectedErrorDuringBulkDownload": "an unexpected error occurred during bulk download.", + "UnexpectedEscapeSequence": "Unexpected escape sequence continuation", + "UnexpectedExtension": "Unexpected archive extension: '{extension}'.", + "UnexpectedFormat": "Expected format is [{expected}], but was [{actual}].", + "UnexpectedPortName": "the port {expected} is declared as {actual} in {path}", + "UnexpectedToolOutput": "{tool_name} ({path}) produced unexpected output when attempting to determine the version:", + "UnknownBaselineFileContent": "unrecognizable baseline entry; expected 'port:triplet=(fail|skip|pass)'", + "UnknownBinaryProviderType": "unknown binary provider type: valid providers are 'clear', 'default', 'nuget', 'nugetconfig','nugettimeout', 'interactive', 'x-azblob', 'x-gcs', 'x-aws', 'x-aws-config', 'http', and 'files'", + "UnknownMachineCode": "Unknown machine type code {value}", + "UnknownOptions": "Unknown option(s) for command '{command_name}':", + "UnknownParameterForIntegrate": "Unknown parameter '{value}' for integrate.", + "UnknownPolicySetting": "Unknown setting for policy '{value}': {option}", + "UnknownSettingForBuildType": "Unknown setting for VCPKG_BUILD_TYPE {option}. Valid settings are '', 'debug', and 'release'.", + "UnknownTool": "vcpkg does not have a definition of this tool for this platform.", + "UnknownTopic": "unknown topic {value}", + "UnknownVariablesInTemplate": "invalid argument: url template '{value}' contains unknown variables: {list}", + "UnrecognizedConfigField": "configuration contains the following unrecognized fields:", + "UnrecognizedIdentifier": "Unrecognized identifer name {value}. Add to override list in triplet file.", + "UnsupportedFeature": "feature {feature} was passed, but that is not a feature supported by {package_name} supports.", + "UnsupportedPort": "Port {package_name} is not supported.", + "UnsupportedPortDependency": "- dependency {value} is not supported.", + "UnsupportedPortFeature": "{spec} is only supported on '{supports_expression}'", + "UnsupportedShortOptions": "short options are not supported: '{value}'", + "UnsupportedSyntaxInCDATA": "]]> is not supported in CDATA block", + "UnsupportedSystemName": "Could not map VCPKG_CMAKE_SYSTEM_NAME '{system_name}' to a vcvarsall platform. Supported system names are '', 'Windows' and 'WindowsStore'.", + "UnsupportedToolchain": "in triplet {triplet}: Unable to find a valid toolchain for requested target architecture {arch}.\nThe selected Visual Studio instance is at: {path}\nThe available toolchain combinations are: {list}", + "UnsupportedUpdateCMD": "the update command does not currently support manifest mode. Instead, modify your vcpkg.json and run install.", + "UpdateBaselineAddBaselineNoManifest": "the --{option} switch was passed, but there is no manifest file to add a `builtin-baseline` field to.", + "UpdateBaselineLocalGitError": "git failed to parse HEAD for the local vcpkg registry at \"{path}\"", + "UpdateBaselineNoConfiguration": "neither `vcpkg.json` nor `vcpkg-configuration.json` exist to update.", + "UpdateBaselineNoExistingBuiltinBaseline": "the manifest file currently does not contain a `builtin-baseline` field; in order to add one, pass the --{option} switch.", + "UpdateBaselineNoUpdate": "registry '{url}' not updated: '{value}'", + "UpdateBaselineRemoteGitError": "git failed to fetch remote repository '{url}'", + "UpdateBaselineUpdatedBaseline": "updated registry '{url}': baseline '{old_value}' -> '{new_value}'", + "UpgradeInManifest": "The upgrade command does not currently support manifest mode. Instead, modify your vcpkg.json and run install.", + "UpgradeRunWithNoDryRun": "If you are sure you want to rebuild the above packages, run this command with the --no-dry-run option.", + "UploadedBinaries": "Uploaded binaries to {count} {vendor}.", + "UploadedPackagesToVendor": "Uploaded {count} package(s) to {vendor} in {elapsed}", + "UploadingBinariesToVendor": "Uploading binaries for '{spec}' to '{vendor}' source \"{path}\".", + "UploadingBinariesUsingVendor": "Uploading binaries for '{spec}' using '{vendor}' \"{path}\".", + "UseEnvVar": "-- Using {env_var} in environment variables.", + "UserWideIntegrationDeleted": "User-wide integration is not installed.", + "UserWideIntegrationRemoved": "User-wide integration was removed.", + "UsingCommunityTriplet": "-- Using community triplet {triplet}. This triplet configuration is not guaranteed to succeed.", + "UsingManifestAt": "Using manifest file at {path}.", + "Utf8ConversionFailed": "Failed to convert to UTF-8", + "VSExaminedInstances": "The following Visual Studio instances were considered:", + "VSExaminedPaths": "The following paths were examined for Visual Studio instances:", + "VSNoInstances": "Could not locate a complete Visual Studio instance", + "VcpkgCeIsExperimental": "vcpkg-ce ('configure environment') is experimental and may change at any time.", + "VcpkgCommitTableHeader": "VCPKG Commit", + "VcpkgCompletion": "vcpkg {value} completion is already imported to your \"{path}\" file.\nThe following entries were found:", + "VcpkgDisallowedClassicMode": "Could not locate a manifest (vcpkg.json) above the current working directory.\nThis vcpkg distribution does not have a classic mode instance.", + "VcpkgHasCrashed": "vcpkg has crashed. Please create an issue at https://github.com/microsoft/vcpkg containing a brief summary of what you were trying to do and the following information.", + "VcpkgInVsPrompt": "vcpkg appears to be in a Visual Studio prompt targeting {value} but installing for {triplet}. Consider using --triplet {value}-windows or --triplet {value}-uwp.", + "VcpkgInvalidCommand": "invalid command: {command_name}", + "VcpkgRegistriesCacheIsNotDirectory": "Value of environment variable X_VCPKG_REGISTRIES_CACHE is not a directory: {path}", + "VcpkgRootRequired": "Setting VCPKG_ROOT is required for standalone bootstrap.", + "VcpkgRootsDir": "Specify the vcpkg root directory.\n(default: '{env_var}')", + "VcpkgSendMetricsButDisabled": "passed --sendmetrics, but metrics are disabled.", + "VersionCommandHeader": "vcpkg package management program version {version}\n\nSee LICENSE.txt for license information.", + "VersionConflictXML": "Expected {path} version: [{expected_version}], but was [{actual_version}]. Please re-run bootstrap-vcpkg.", + "VersionConstraintViolated": "dependency {spec} was expected to be at least version {expected_version}, but is currently {actual_version}.", + "VersionInvalidDate": "`{version}` is not a valid date version. Dates must follow the format YYYY-MM-DD and disambiguators must be dot-separated positive integer values without leading zeroes.", + "VersionInvalidRelaxed": "`{version}` is not a valid relaxed version (semver with arbitrary numeric element count).", + "VersionInvalidSemver": "`{version}` is not a valid semantic version, consult .", + "VersionSpecMismatch": "Failed to load port because versions are inconsistent. The file \"{path}\" contains the version {actual_version}, but the version database indicates that it should be {expected_version}.", + "VersionTableHeader": "Version", + "WaitingForChildrenToExit": "Waiting for child processes to exit...", + "WaitingToTakeFilesystemLock": "waiting to take filesystem lock on {path}...", + "WarnOnParseConfig": "Found the following warnings in configuration {path}:", + "WarningMessage": "warning: ", + "WarningMessageMustUsePrintWarning": "The message named {value} starts with warning:, it must be changed to prepend WarningMessage in code instead.", + "WarningsTreatedAsErrors": "previous warnings being interpreted as errors", + "WhileLookingForSpec": "while looking for {spec}:", + "WindowsOnlyCommand": "This command only supports Windows.", + "WroteNuGetPkgConfInfo": "Wrote NuGet package config information to {path}" +} diff --git a/locales/messages.json b/locales/messages.json index d24ef7a41e..05bb4b2609 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -59,12 +59,16 @@ "AddVersionCommitChangesReminder": "Did you remember to commit your changes?", "AddVersionCommitResultReminder": "Don't forget to commit the result!", "AddVersionDetectLocalChangesError": "skipping detection of local changes due to unexpected format in git status output", + "AddVersionDisableCheck": "Use --{option} to disable this check.", + "_AddVersionDisableCheck.comment": "The -- before {option} must be preserved as they're part of the help message for the user. An example of {option} is editable.", "AddVersionFileNotFound": "couldn't find required file {path}", "_AddVersionFileNotFound.comment": "An example of {path} is /foo/bar.", "AddVersionFormatPortSuggestion": "Run `{command_line}` to format the file", "_AddVersionFormatPortSuggestion.comment": "An example of {command_line} is vcpkg install zlib.", "AddVersionIgnoringOptionAll": "ignoring --{option} since a port name argument was provided", "_AddVersionIgnoringOptionAll.comment": "The -- before {option} must be preserved as they're part of the help message for the user. An example of {option} is editable.", + "AddVersionLintPort": "You can run `./vcpkg x-lint-port --fix {package_name}` to fix these issues.", + "_AddVersionLintPort.comment": "An example of {package_name} is zlib.", "AddVersionLoadPortFailed": "can't load port {package_name}", "_AddVersionLoadPortFailed.comment": "An example of {package_name} is zlib.", "AddVersionNewFile": "(new file)", @@ -85,8 +89,6 @@ "_AddVersionPortFilesShaUnchanged.comment": "An example of {package_name} is zlib. An example of {version} is 1.3.8.", "AddVersionPortHasImproperFormat": "{package_name} is not properly formatted", "_AddVersionPortHasImproperFormat.comment": "An example of {package_name} is zlib.", - "AddVersionSuggestNewVersionScheme": "Use the version scheme \"{new_scheme}\" instead of \"{old_scheme}\" in port \"{package_name}\".\nUse --{option} to disable this check.", - "_AddVersionSuggestNewVersionScheme.comment": "The -- before {option} must be preserved as they're part of the help message for the user. An example of {new_scheme} is version. An example of {old_scheme} is version-string. An example of {package_name} is zlib. An example of {option} is editable.", "AddVersionUnableToParseVersionsFile": "unable to parse versions file {path}", "_AddVersionUnableToParseVersionsFile.comment": "An example of {path} is /foo/bar.", "AddVersionUncommittedChanges": "there are uncommitted changes for {package_name}", @@ -267,6 +269,8 @@ "CmdAddVersionOptAll": "Process versions for all ports.", "CmdAddVersionOptOverwriteVersion": "Overwrite `git-tree` of an existing version.", "CmdAddVersionOptSkipFormatChk": "Skips the formatting check of vcpkg.json files.", + "CmdAddVersionOptSkipLicenseChk": "Skips the license expression check.", + "CmdAddVersionOptSkipPortfileChk": "Skips the portfile.cmake check.", "CmdAddVersionOptSkipVersionFormatChk": "Skips the version format check.", "CmdAddVersionOptVerbose": "Print success messages instead of just errors.", "CmdContactOptSurvey": "Launch default browser to the current vcpkg survey", @@ -313,6 +317,9 @@ "CmdGenerateMessageMapOptNoOutputComments": "When generating the message map, exclude comments (useful for generating the English localization file)", "CmdInfoOptInstalled": "(experimental) Report on installed packages instead of available", "CmdInfoOptTransitive": "(experimental) Also report on dependencies of installed packages", + "CmdLintPortOptAllPorts": "Checks all ports.", + "CmdLintPortOptFix": "Tries to fix all problems that were found.", + "CmdLintPortOptIncreaseVersion": "Increase the port-version of a port if a problem was fixed.", "CmdNewOptApplication": "Create an application manifest (don't require name or version).", "CmdNewOptSingleFile": "Embed vcpkg-configuration.json into vcpkg.json.", "CmdNewOptVersionDate": "Interpret --version as an ISO 8601 date. (YYYY-MM-DD)", @@ -979,6 +986,22 @@ "LinkageDynamicRelease": "Dynamic Release (/MD)", "LinkageStaticDebug": "Static Debug (/MTd)", "LinkageStaticRelease": "Static Release (/MT)", + "LintDeprecatedFunction": "The deprecated function \"{actual}\" is used inside the port \"{package_name}\". Use the function \"{expected}\" instead.", + "_LintDeprecatedFunction.comment": "{actual} is the currently used deprecated function, {expected} is the function that should be used An example of {package_name} is zlib.", + "LintDeprecatedLicenseExpressionWithReplacement": "The port \"{package_name}\" uses the deprecated license expression \"{actual}\". You shoud use the non deprecated version \"{new_value}\".", + "_LintDeprecatedLicenseExpressionWithReplacement.comment": "{actual} is the currently used license expression and {new_value} is the license expression that should be used An example of {package_name} is zlib.", + "LintDeprecatedLicenseExpressionWithoutReplacement": "The port \"{package_name}\" uses the deprecated license expression \"{actual}\". Use license expression including main license, \"WITH\" operator, and identifier: \"{new_value}\"", + "_LintDeprecatedLicenseExpressionWithoutReplacement.comment": "{actual} is the currently used license, {new_value} is the suggested WITH expression An example of {package_name} is zlib.", + "LintMissingLicenseExpression": "There is no license expression in port \"{package_name}\". You could use https://tools.spdx.org/app/check_license/ to determine the right license expression.", + "_LintMissingLicenseExpression.comment": "An example of {package_name} is zlib.", + "LintPortErrors": "The port \"{package_name}\" should be fixed. See warning(s) above.", + "_LintPortErrors.comment": "An example of {package_name} is zlib.", + "LintPortErrorsFixed": "Problems in the port \"{package_name}\" have been fixed.", + "_LintPortErrorsFixed.comment": "An example of {package_name} is zlib.", + "LintSuggestNewVersionScheme": "Use the version scheme \"{new_scheme}\" instead of \"{old_scheme}\" in port \"{package_name}\".", + "_LintSuggestNewVersionScheme.comment": "An example of {new_scheme} is version. An example of {old_scheme} is version-string. An example of {package_name} is zlib.", + "LintVcpkgCheckFeatures": "Calling `vcpkg_check_features` without the `FEATURES` keyword has been deprecated. Please add the `FEATURES` keyword to the call inside the port {package_name}.", + "_LintVcpkgCheckFeatures.comment": "An example of {package_name} is zlib.", "ListHelp": "The argument should be a substring to search for, or no argument to display all installed libraries.", "ListOfValidFieldsForControlFiles": "This is the list of valid fields for CONTROL files (case-sensitive):", "LoadingCommunityTriplet": "-- [COMMUNITY] Loading triplet configuration from: {path}", diff --git a/src/vcpkg-test/portlint.cpp b/src/vcpkg-test/portlint.cpp new file mode 100644 index 0000000000..b1ae7ae4b2 --- /dev/null +++ b/src/vcpkg-test/portlint.cpp @@ -0,0 +1,213 @@ +#include + +#include +#include + +#include + +using namespace vcpkg; +using namespace vcpkg::Lint; + +TEST_CASE ("Lint::get_recommended_license_expression", "[portlint]") +{ + REQUIRE(get_recommended_license_expression("GPL-1.0") == "GPL-1.0-only"); + REQUIRE(get_recommended_license_expression("GPL-1.0 OR test") == "GPL-1.0-only OR test"); + REQUIRE(get_recommended_license_expression("GPL-1.0 OR GPL-1.0") == "GPL-1.0-only OR GPL-1.0-only"); + REQUIRE(get_recommended_license_expression("GPL-1.0+ OR GPL-1.0") == "GPL-1.0-or-later OR GPL-1.0-only"); +} + +TEST_CASE ("Lint::get_recommended_version_scheme", "[portlint]") +{ + REQUIRE(get_recommended_version_scheme("1.0.0", VersionScheme::String) == VersionScheme::Relaxed); + REQUIRE(get_recommended_version_scheme("2020-01-01", VersionScheme::String) == VersionScheme::Date); + REQUIRE(get_recommended_version_scheme("latest", VersionScheme::String) == VersionScheme::String); +} + +namespace +{ + struct CountingMessageSink : MessageSink + { + int counter = 0; + void print(Color, StringView) override { ++counter; } + }; + + void check_replacement(StringView old_content, const std::string& new_content, StringView new_host_dependency) + { + CountingMessageSink msg_sink; + auto result = check_portfile_deprecated_functions(old_content.to_string(), "test", Fix::YES, msg_sink); + REQUIRE(result.status == Status::Fixed); + REQUIRE(msg_sink.counter == 0); + if (result.new_portfile_content != new_content) + { + REQUIRE(Strings::replace_all(result.new_portfile_content, "\r", "\\r") == + Strings::replace_all(new_content, "\r", "\\r")); + } + if (new_host_dependency.empty()) + { + REQUIRE(result.added_host_deps.empty()); + } + else + { + REQUIRE(result.added_host_deps.size() == 1); + REQUIRE(*result.added_host_deps.begin() == new_host_dependency); + } + + result = check_portfile_deprecated_functions(old_content.to_string(), "test", Fix::NO, msg_sink); + REQUIRE(result.status == Status::Problem); + REQUIRE(msg_sink.counter == 1); + REQUIRE(result.new_portfile_content.empty()); + REQUIRE(result.added_host_deps.empty()); + } +} + +TEST_CASE ("Lint::check_portfile_deprecated_functions", "[portlint]") +{ + SECTION ("vcpkg_build_msbuild") + { + auto content = R"-( +vcpkg_build_msbuild( + PROJECT_PATH "${SOURCE_PATH}/msvc/unicorn.sln" + PLATFORM "${UNICORN_PLATFORM}" +) +)-"; + CountingMessageSink msg_sink; + auto result = check_portfile_deprecated_functions(content, "test", Fix::YES, msg_sink); + REQUIRE(result.status == Status::Problem); + REQUIRE(msg_sink.counter == 1); + } + + SECTION ("vcpkg_configure_cmake -> vcpkg_cmake_configure") + { + auto content = R"-( +vcpkg_configure_cmake( + SOURCE_PATH ${SOURCE_PATH} + PREFER_NINJA + OPTIONS_DEBUG -DDISABLE_INSTALL_HEADERS=ON -DDISABLE_INSTALL_TOOLS=ON +) +vcpkg_configure_cmake( + SOURCE_PATH ${SOURCE_PATH} + OPTIONS_DEBUG -DDISABLE_INSTALL_HEADERS=ON -DDISABLE_INSTALL_TOOLS=ON +) +)-"; + auto new_content = R"-( +vcpkg_cmake_configure( + SOURCE_PATH ${SOURCE_PATH} + OPTIONS_DEBUG -DDISABLE_INSTALL_HEADERS=ON -DDISABLE_INSTALL_TOOLS=ON +) +vcpkg_cmake_configure( + SOURCE_PATH ${SOURCE_PATH} + OPTIONS_DEBUG -DDISABLE_INSTALL_HEADERS=ON -DDISABLE_INSTALL_TOOLS=ON +) +)-"; + check_replacement(content, new_content, "vcpkg-cmake"); + } + + SECTION ("vcpkg_build_cmake -> vcpkg_cmake_build") + { + auto content = R"-( +vcpkg_build_cmake(TARGET test) +)-"; + auto new_content = R"-( +vcpkg_cmake_build(TARGET test) +)-"; + check_replacement(content, new_content, "vcpkg-cmake"); + } + + SECTION ("vcpkg_install_cmake -> vcpkg_cmake_install") + { + auto content = R"-( +vcpkg_install_cmake() +)-"; + auto new_content = R"-( +vcpkg_cmake_install() +)-"; + check_replacement(content, new_content, "vcpkg-cmake"); + } + + SECTION ("vcpkg_fixup_cmake_targets -> vcpkg_cmake_config_fixup") + { + auto content = R"-( +vcpkg_fixup_cmake_targets(CONFIG_PATH lib/cmake/${PORT}) +vcpkg_fixup_cmake_targets(TARGET_PATH share/${PORT}) +vcpkg_fixup_cmake_targets(CONFIG_PATH share/unofficial-cfitsio TARGET_PATH share/unofficial-cfitsio) +vcpkg_fixup_cmake_targets(CONFIG_PATH cmake TARGET_PATH share/async++) +)-"; + auto new_content = R"-( +vcpkg_cmake_config_fixup(CONFIG_PATH lib/cmake/${PORT}) +vcpkg_cmake_config_fixup() +vcpkg_cmake_config_fixup(PACKAGE_NAME unofficial-cfitsio) +vcpkg_cmake_config_fixup(CONFIG_PATH cmake PACKAGE_NAME async++) +)-"; + check_replacement(content, new_content, "vcpkg-cmake-config"); + } + + SECTION ("vcpkg_extract_source_archive_ex -> vcpkg_extract_source_archive") + { + std::string content = R"-( +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH +) +vcpkg_extract_source_archive_ex( + OUT_SOURCE_PATH SOURCE_PATH + ARCHIVE ${ARCHIVE} + REF lib1.0.0 + PATCHES + remove_stdint_headers.patch + no-pragma-warning.patch +) +vcpkg_extract_source_archive_ex( + ARCHIVE ${ARCHIVE} + OUT_SOURCE_PATH SOURCE_PATH +REF +lib1.0.0 + PATCHES + remove_stdint_headers.patch + no-pragma-warning.patch +) +vcpkg_extract_source_archive_ex(OUT_SOURCE_PATH SOURCE_PATH ARCHIVE ${ARCHIVE}) +)-"; + std::string new_content = R"-( +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH +) +vcpkg_extract_source_archive( + SOURCE_PATH + ARCHIVE ${ARCHIVE} + SOURCE_BASE lib1.0.0 + PATCHES + remove_stdint_headers.patch + no-pragma-warning.patch +) +vcpkg_extract_source_archive( + SOURCE_PATH + ARCHIVE ${ARCHIVE} +SOURCE_BASE +lib1.0.0 + PATCHES + remove_stdint_headers.patch + no-pragma-warning.patch +) +vcpkg_extract_source_archive(SOURCE_PATH ARCHIVE ${ARCHIVE}) +)-"; + check_replacement(content, new_content, ""); + check_replacement( + Strings::replace_all(content, "\n", "\r\n"), Strings::replace_all(new_content, "\n", "\r\n"), ""); + } + + SECTION ("vcpkg_check_features") + { + auto content = R"-( +vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS + graphml IGRAPH_GRAPHML_SUPPORT + openmp IGRAPH_OPENMP_SUPPORT +) +)-"; + auto new_content = R"-( +vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS FEATURES + graphml IGRAPH_GRAPHML_SUPPORT + openmp IGRAPH_OPENMP_SUPPORT +) +)-"; + check_replacement(content, new_content, ""); + } +} diff --git a/src/vcpkg/base/message_sinks.cpp b/src/vcpkg/base/message_sinks.cpp index 62ffcebed2..e3e227d5a0 100644 --- a/src/vcpkg/base/message_sinks.cpp +++ b/src/vcpkg/base/message_sinks.cpp @@ -32,12 +32,12 @@ namespace vcpkg void MessageSink::println_warning(const LocalizedString& s) { - println(Color::warning, format(msg::msgWarningMessage).append(s)); + print(Color::warning, format(msg::msgWarningMessage).append(s).append_raw('\n')); } void MessageSink::println_error(const LocalizedString& s) { - println(Color::error, format(msg::msgErrorMessage).append(s)); + print(Color::error, format(msg::msgErrorMessage).append(s).append_raw('\n')); } MessageSink& null_sink = null_sink_instance; diff --git a/src/vcpkg/commands.add-version.cpp b/src/vcpkg/commands.add-version.cpp index bbc2f6327e..7f0ffdcfd2 100644 --- a/src/vcpkg/commands.add-version.cpp +++ b/src/vcpkg/commands.add-version.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,8 @@ namespace static constexpr StringLiteral OPTION_OVERWRITE_VERSION = "overwrite-version"; static constexpr StringLiteral OPTION_SKIP_FORMATTING_CHECK = "skip-formatting-check"; static constexpr StringLiteral OPTION_SKIP_VERSION_FORMAT_CHECK = "skip-version-format-check"; + static constexpr StringLiteral OPTION_SKIP_LICENSE_CHECK = "skip-license-check"; + static constexpr StringLiteral OPTION_SKIP_PORTFILE_CHECK = "skip-portfile-check"; static constexpr StringLiteral OPTION_VERBOSE = "verbose"; enum class UpdateResult @@ -68,31 +71,6 @@ namespace Checks::unreachable(VCPKG_LINE_INFO); } - void check_used_version_scheme(const SchemedVersion& version, const std::string& port_name) - { - if (version.scheme == VersionScheme::String) - { - if (DateVersion::try_parse(version.version.text())) - { - Checks::msg_exit_with_message(VCPKG_LINE_INFO, - msgAddVersionSuggestNewVersionScheme, - msg::new_scheme = VERSION_DATE, - msg::old_scheme = VERSION_STRING, - msg::package_name = port_name, - msg::option = OPTION_SKIP_VERSION_FORMAT_CHECK); - } - if (DotVersion::try_parse_relaxed(version.version.text())) - { - Checks::msg_exit_with_message(VCPKG_LINE_INFO, - msgAddVersionSuggestNewVersionScheme, - msg::new_scheme = VERSION_RELAXED, - msg::old_scheme = VERSION_STRING, - msg::package_name = port_name, - msg::option = OPTION_SKIP_VERSION_FORMAT_CHECK); - } - } - } - static Json::Object serialize_baseline(const std::map>& baseline) { Json::Object port_entries_obj; @@ -192,15 +170,44 @@ namespace bool overwrite_version, bool print_success, bool keep_going, - bool skip_version_format_check) + bool skip_version_format_check, + bool skip_license_check, + bool skip_portfile_check, + SourceControlFileAndLocation& scf) { auto& fs = paths.get_filesystem(); - if (!fs.exists(version_db_file_path, IgnoreErrors{})) - { + const auto lint_port = [=, &scf, &fs]() { + Lint::Status status = Lint::Status::Ok; if (!skip_version_format_check) { - check_used_version_scheme(port_version, port_name); + if (Lint::check_used_version_scheme(*scf.source_control_file, Lint::Fix::NO) == Lint::Status::Problem) + { + status = Lint::Status::Problem; + msg::println(msgAddVersionDisableCheck, msg::option = OPTION_SKIP_VERSION_FORMAT_CHECK); + } } + if (!skip_license_check) + { + if (Lint::check_license_expression(*scf.source_control_file, Lint::Fix::NO) == Lint::Status::Problem) + { + status = Lint::Status::Problem; + msg::println(msgAddVersionDisableCheck, msg::option = OPTION_SKIP_LICENSE_CHECK); + } + } + if (!skip_portfile_check) + { + if (Lint::check_portfile_deprecated_functions(fs, scf, Lint::Fix::NO) == Lint::Status::Problem) + { + status = Lint::Status::Problem; + msg::println(msgAddVersionDisableCheck, msg::option = OPTION_SKIP_PORTFILE_CHECK); + } + } + Checks::msg_check_exit( + VCPKG_LINE_INFO, status == Lint::Status::Ok, msgAddVersionLintPort, msg::package_name = port_name); + }; + if (!fs.exists(version_db_file_path, IgnoreErrors{})) + { + lint_port(); std::vector new_entry{{port_version, git_tree}}; write_versions_file(fs, new_entry, version_db_file_path); if (print_success) @@ -285,10 +292,7 @@ namespace versions->insert(versions->begin(), std::make_pair(port_version, git_tree)); } - if (!skip_version_format_check) - { - check_used_version_scheme(port_version, port_name); - } + lint_port(); write_versions_file(fs, *versions, version_db_file_path); if (print_success) @@ -315,6 +319,8 @@ namespace vcpkg::Commands::AddVersion {OPTION_OVERWRITE_VERSION, []() { return msg::format(msgCmdAddVersionOptOverwriteVersion); }}, {OPTION_SKIP_FORMATTING_CHECK, []() { return msg::format(msgCmdAddVersionOptSkipFormatChk); }}, {OPTION_SKIP_VERSION_FORMAT_CHECK, []() { return msg::format(msgCmdAddVersionOptSkipVersionFormatChk); }}, + {OPTION_SKIP_LICENSE_CHECK, []() { return msg::format(msgCmdAddVersionOptSkipLicenseChk); }}, + {OPTION_SKIP_PORTFILE_CHECK, []() { return msg::format(msgCmdAddVersionOptSkipPortfileChk); }}, {OPTION_VERBOSE, []() { return msg::format(msgCmdAddVersionOptVerbose); }}, }; @@ -334,6 +340,8 @@ namespace vcpkg::Commands::AddVersion const bool skip_formatting_check = Util::Sets::contains(parsed_args.switches, OPTION_SKIP_FORMATTING_CHECK); const bool skip_version_format_check = Util::Sets::contains(parsed_args.switches, OPTION_SKIP_VERSION_FORMAT_CHECK); + const bool skip_license_check = Util::Sets::contains(parsed_args.switches, OPTION_SKIP_LICENSE_CHECK); + const bool skip_portfile_check = Util::Sets::contains(parsed_args.switches, OPTION_SKIP_PORTFILE_CHECK); const bool verbose = !add_all || Util::Sets::contains(parsed_args.switches, OPTION_VERBOSE); auto& fs = paths.get_filesystem(); @@ -413,7 +421,8 @@ namespace vcpkg::Commands::AddVersion continue; } - const auto& scf = maybe_scf.value(VCPKG_LINE_INFO); + SourceControlFileAndLocation scf{std::move(maybe_scf).value(VCPKG_LINE_INFO), + paths.builtin_ports_directory() / port_name}; if (!skip_formatting_check) { @@ -422,7 +431,7 @@ namespace vcpkg::Commands::AddVersion if (fs.exists(path_to_manifest, IgnoreErrors{})) { const auto current_file_content = fs.read_contents(path_to_manifest, VCPKG_LINE_INFO); - const auto json = serialize_manifest(*scf); + const auto json = serialize_manifest(*scf.source_control_file); const auto formatted_content = Json::stringify(json); if (current_file_content != formatted_content) { @@ -446,7 +455,7 @@ namespace vcpkg::Commands::AddVersion msg::println_warning(msgAddVersionUncommittedChanges, msg::package_name = port_name); } - const auto& schemed_version = scf->to_schemed_version(); + const auto& schemed_version = scf.source_control_file->to_schemed_version(); auto git_tree_it = git_tree_map.find(port_name); if (git_tree_it == git_tree_map.end()) @@ -472,7 +481,10 @@ namespace vcpkg::Commands::AddVersion overwrite_version, verbose, add_all, - skip_version_format_check); + skip_version_format_check, + skip_license_check, + skip_portfile_check, + scf); auto updated_baseline_file = update_baseline_version( paths, port_name, schemed_version.version, baseline_path, baseline_map, verbose); if (verbose && updated_versions_file == UpdateResult::NotUpdated && diff --git a/src/vcpkg/commands.cpp b/src/vcpkg/commands.cpp index a5d0e7f507..be5ff72318 100644 --- a/src/vcpkg/commands.cpp +++ b/src/vcpkg/commands.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -91,6 +92,7 @@ namespace vcpkg::Commands {"/?", Help::perform_and_exit}, {"help", Help::perform_and_exit}, {"integrate", Integrate::perform_and_exit}, + {"x-lint-port", LintPort::perform_and_exit}, {"list", List::perform_and_exit}, {"new", command_new_and_exit}, {"owns", Owns::perform_and_exit}, diff --git a/src/vcpkg/commands.lint-port.cpp b/src/vcpkg/commands.lint-port.cpp new file mode 100644 index 0000000000..b14c84dddf --- /dev/null +++ b/src/vcpkg/commands.lint-port.cpp @@ -0,0 +1,124 @@ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace vcpkg; + +namespace +{ + constexpr StringLiteral OPTION_ALL = "all"; + constexpr StringLiteral OPTION_FIX = "fix"; + constexpr StringLiteral OPTION_INCREASE_VERSION = "increase-version"; +} + +namespace vcpkg::Commands::LintPort +{ + const CommandSwitch COMMAND_SWITCHES[] = { + {OPTION_ALL, []() { return msg::format(msgCmdLintPortOptAllPorts); }}, + {OPTION_FIX, []() { return msg::format(msgCmdLintPortOptFix); }}, + {OPTION_INCREASE_VERSION, []() { return msg::format(msgCmdLintPortOptIncreaseVersion); }}}; + + const CommandStructure COMMAND_STRUCTURE{ + []() { return create_example_string(R"###(x-lint-port )###"); }, + 0, + INT_MAX, + {{COMMAND_SWITCHES}, {}, {}}, + nullptr, + }; + + void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths) + { + auto parsed_args = args.parse_arguments(COMMAND_STRUCTURE); + const bool add_all = Util::Sets::contains(parsed_args.switches, OPTION_ALL); + const auto fix = Util::Enum::to_enum(Util::Sets::contains(parsed_args.switches, OPTION_FIX)); + const bool increase_version = Util::Sets::contains(parsed_args.switches, OPTION_INCREASE_VERSION); + + auto& fs = paths.get_filesystem(); + + std::vector port_names; + if (!parsed_args.command_arguments.empty()) + { + if (add_all) + { + msg::println_warning(msgAddVersionIgnoringOptionAll, msg::option = OPTION_ALL); + } + port_names = parsed_args.command_arguments; + } + else + { + Checks::msg_check_exit(VCPKG_LINE_INFO, + add_all, + msgAddVersionUseOptionAll, + msg::command_name = "x-lint-port", + msg::option = OPTION_ALL); + + for (auto&& port_dir : fs.get_directories_non_recursive(paths.builtin_ports_directory(), VCPKG_LINE_INFO)) + { + port_names.emplace_back(port_dir.stem().to_string()); + } + } + + for (auto&& port_name : port_names) + { + auto maybe_scf = Paragraphs::try_load_port(fs, paths.builtin_ports_directory() / port_name); + if (!maybe_scf) + { + msg::println_error(msgAddVersionLoadPortFailed, msg::package_name = port_name); + print_error_message(maybe_scf.error()); + Checks::check_exit(VCPKG_LINE_INFO, !add_all); + continue; + } + SourceControlFileAndLocation scf{std::move(maybe_scf).value(VCPKG_LINE_INFO), + paths.builtin_ports_directory() / port_name}; + Lint::Status s = Lint::check_license_expression(*scf.source_control_file, fix); + s |= Lint::check_used_version_scheme(*scf.source_control_file, fix); + s |= Lint::check_portfile_deprecated_functions(fs, scf, fix); + + if (s == Lint::Status::Fixed || s == Lint::Status::PartiallyFixed) + { + if (s == Lint::Status::Fixed) + { + msg::print(msg::format(msgLintPortErrorsFixed, msg::package_name = port_name).append_raw("\n\n")); + } + else + { + msg::print(Color::error, + msg::format(msgLintPortErrors, msg::package_name = port_name).append_raw("\n\n")); + } + if (increase_version) scf.source_control_file->core_paragraph->port_version += 1; + scf.source_control_file->canonicalize(); + std::error_code ec; + fs.write_contents(scf.source_location / "vcpkg.json", + Json::stringify(serialize_manifest(*scf.source_control_file)), + ec); + if (ec) + { + Checks::msg_exit_with_error( + VCPKG_LINE_INFO, + msg::format(msgFailedToWriteManifest, msg::path = scf.source_location / "vcpkg.json") + .append_raw(": ") + .append_raw(ec.message())); + } + } + else if (s == Lint::Status::Problem) + { + msg::print(Color::error, + msg::format(msgLintPortErrors, msg::package_name = port_name).append_raw("\n\n")); + } + } + Checks::exit_success(VCPKG_LINE_INFO); + } +} diff --git a/src/vcpkg/portlint.cpp b/src/vcpkg/portlint.cpp new file mode 100644 index 0000000000..3b4c529c8f --- /dev/null +++ b/src/vcpkg/portlint.cpp @@ -0,0 +1,456 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace vcpkg::Lint +{ + + constexpr StringLiteral VERSION_RELAXED = "version"; + constexpr StringLiteral VERSION_DATE = "version-date"; + constexpr StringLiteral VERSION_STRING = "version-string"; + + VersionScheme get_recommended_version_scheme(StringView raw_version, VersionScheme original_scheme) + { + if (DateVersion::try_parse(raw_version)) return VersionScheme::Date; + if (DotVersion::try_parse_relaxed(raw_version)) return VersionScheme::Relaxed; + return original_scheme; + } + + Status check_used_version_scheme(SourceControlFile& scf, Fix fix) + { + auto scheme = scf.core_paragraph->version_scheme; + if (scheme == VersionScheme::String) + { + auto new_scheme = get_recommended_version_scheme(scf.core_paragraph->raw_version, scheme); + if (scheme != new_scheme) + { + if (fix == Fix::YES) + { + scf.core_paragraph->version_scheme = new_scheme; + return Status::Fixed; + } + msg::println_warning(msgLintSuggestNewVersionScheme, + msg::new_scheme = + (new_scheme == VersionScheme::Date) ? VERSION_DATE : VERSION_RELAXED, + msg::old_scheme = VERSION_STRING, + msg::package_name = scf.core_paragraph->name); + return Status::Problem; + } + } + return Status::Ok; + } + + namespace + { + std::string::size_type find_license(const std::string& license_expression, + StringView license_identifier, + std::string::size_type offset = 0) + { + std::string::size_type index; + while ((index = license_expression.find(license_identifier.data(), offset, license_identifier.size())) != + std::string::npos) + { + const auto end_index = index + license_identifier.size(); + if (end_index >= license_expression.size() || license_expression[end_index] == ' ') + { + return index; + } + offset = end_index; + } + return std::string::npos; + } + } + + std::string get_recommended_license_expression(std::string original_license) + { + static constexpr std::pair deprecated_licenses[] = { + {"AGPL-1.0", "AGPL-1.0-only"}, + {"AGPL-3.0", "AGPL-3.0-only"}, + {"GFDL-1.1", "GFDL-1.1-or-later"}, + {"GFDL-1.2", "GFDL-1.2-or-later"}, + {"GFDL-1.3", "GFDL-1.3-or-later"}, + {"GPL-1.0", "GPL-1.0-only"}, + {"GPL-1.0+", "GPL-1.0-or-later"}, + {"GPL-2.0", "GPL-2.0-only"}, + {"GPL-2.0+", "GPL-2.0-or-later"}, + {"GPL-2.0-with-autoconf-exception", "GPL-2.0-only WITH Autoconf-exception-2.0"}, + {"GPL-2.0-with-bison-exception", "GPL-2.0-or-later WITH Bison-exception-2.2"}, + {"GPL-2.0-with-GCC-exception", "GPL-2.0-or-later WITH GCC-exception-2.0"}, + {"GPL-3.0", "GPL-3.0-only"}, + {"GPL-3.0+", "GPL-3.0-or-later"}, + {"GPL-3.0-with-autoconf-exception", "GPL-3.0-only WITH Autoconf-exception-3.0"}, + {"GPL-3.0-with-GCC-exception", "GPL-3.0-only WITH GCC-exception-3.1"}, + {"LGPL-2.0", "LGPL-2.0-only"}, + {"LGPL-2.0+", "LGPL-2.0-or-later"}, + {"LGPL-2.1", "LGPL-2.1-only"}, + {"LGPL-2.1+", "LGPL-2.1-or-later"}, + {"LGPL-3.0", "LGPL-3.0-only"}, + {"LGPL-3.0+", "LGPL-3.0-or-later"}, + {"StandardML-NJ", "SMLNJ"}}; + for (const auto dep_license : deprecated_licenses) + { + std::string::size_type index = 0; + while ((index = find_license(original_license, dep_license.first, index)) != std::string::npos) + { + original_license.replace(index, dep_license.first.size(), dep_license.second.c_str()); + } + } + return original_license; + } + + Status check_license_expression(SourceControlFile& scf, Fix fix) + { + if (!scf.core_paragraph->license.has_value()) + { + msg::println_warning(msgLintMissingLicenseExpression, msg::package_name = scf.core_paragraph->name); + return Status::Problem; + } + + Status status = Status::Ok; + auto& license = scf.core_paragraph->license.value_or_exit(VCPKG_LINE_INFO); + auto new_expr = get_recommended_license_expression(license); + if (new_expr != license) + { + if (fix == Fix::YES) + { + license = new_expr; + } + else + { + msg::println_warning(msgLintDeprecatedLicenseExpressionWithReplacement, + msg::package_name = scf.core_paragraph->name, + msg::actual = license, + msg::new_value = new_expr); + status |= Status::Problem; + } + } + static constexpr std::pair deprecated_licenses_WITH[] = { + {"eCos-2.0", "eCos-exception-2.0"}, + {"GPL-2.0-with-classpath-exception", "Classpath-exception-2.0"}, + {"GPL-2.0-with-font-exception", "Font-exception-2.0"}, + {"wxWindows", "WxWindows-exception-3.1"}, + }; + for (const auto dep_license : deprecated_licenses_WITH) + { + if (find_license(license, dep_license.first) != std::string::npos) + { + msg::println_warning(msgLintDeprecatedLicenseExpressionWithoutReplacement, + msg::package_name = scf.core_paragraph->name, + msg::actual = dep_license.first, + msg::new_value = dep_license.second); + status |= Status::Problem; + } + } + return status; + } + + Status check_portfile_deprecated_functions(Filesystem& fs, SourceControlFileAndLocation& scf, Fix fix) + { + auto contents = fs.read_contents(scf.source_location / "portfile.cmake", VCPKG_LINE_INFO); + auto lint_result = check_portfile_deprecated_functions( + std::move(contents), scf.source_control_file->core_paragraph->name, fix, stdout_sink); + + if (lint_result.status == Status::Fixed || lint_result.status == Status::PartiallyFixed) + { + fs.write_contents( + scf.source_location / "portfile.cmake", lint_result.new_portfile_content, VCPKG_LINE_INFO); + + for (StringView name : lint_result.added_host_deps) + { + if (!Util::any_of(scf.source_control_file->core_paragraph->dependencies, + [&](const Dependency& d) { return d.name == name; })) + { + scf.source_control_file->core_paragraph->dependencies.push_back( + Dependency{name.to_string(), {}, {}, {}, true}); + } + } + } + return lint_result.status; + } + + namespace + { + std::string::size_type find_param(const std::string& content, + ZStringView param, + std::string::size_type start, + std::string::size_type end) + { + while ((start = content.find(param.c_str(), start)) != std::string::npos) + { + if (start > end) return std::string::npos; + // param must be not included in another word + if (ParserBase::is_word_char(content[start - 1]) || + ParserBase::is_word_char(content[start + param.size()])) + { + start += param.size(); + } + else + { + return start; + } + } + return std::string::npos; + } + + void replace_param(std::string& content, + ZStringView old_param, + ZStringView new_param, + std::string::size_type start, + std::string::size_type end) + { + auto index = find_param(content, old_param, start, end); + if (index != std::string::npos) + { + content.replace(index, old_param.size(), new_param.c_str()); + } + } + + void remove_param(std::string& content, ZStringView param, std::string::size_type index) + { + const auto first_white_space = content.find_last_not_of(" \n\t\r", index - 1) + 1; + const auto white_space_length = index - first_white_space; + content.erase(first_white_space, white_space_length + param.size()); + } + + void find_remove_param(std::string& content, + ZStringView param, + std::string::size_type start, + std::string::size_type end) + { + const auto start_param = find_param(content, param, start, end); + if (start_param != std::string::npos) + { + remove_param(content, param, start_param); + } + } + + struct ParamAndValue + { + std::string::size_type start_param = std::string::npos; + std::string::size_type start_value = std::string::npos; + std::string::size_type end_value = std::string::npos; + bool found() const { return start_param != std::string::npos; } + bool value_found() const { return start_value != std::string::npos && end_value != std::string::npos; } + std::string get_value(const std::string& content) const + { + return content.substr(start_value, end_value - start_value); + } + std::string::size_type full_length() const { return end_value - start_param; } + }; + + ParamAndValue find_param_maybe_value(const std::string& content, + ZStringView param, + std::string::size_type start, + std::string::size_type end) + { + auto start_param = find_param(content, param, start, end); + if (start_param == std::string::npos) return {}; + const auto start_value = content.find_first_not_of(" \r\n\t)", start_param + param.size()); + const auto end_value = content.find_first_of(" \r\n\t)", start_value); + if (end_value == std::string::npos || end_value > end) return ParamAndValue{start_param}; + return ParamAndValue{start_param, start_value, end_value}; + } + } + + FixedPortfile check_portfile_deprecated_functions(std::string&& portfile_content, + StringView origin, + Fix fix, + MessageSink& warningsSink) + { + FixedPortfile fixedPortfile; + Status status = Status::Ok; + const auto handle_warning = [&](StringLiteral deprecated, StringLiteral new_func, bool can_fix = true) { + if (fix == Fix::NO || !can_fix) + { + status |= Status::Problem; + warningsSink.println_warning(msgLintDeprecatedFunction, + msg::package_name = origin, + msg::actual = deprecated, + msg::expected = new_func); + } + else + { + status |= Status::Fixed; + } + }; + if (Strings::contains(portfile_content, "vcpkg_build_msbuild")) + { + handle_warning("vcpkg_build_msbuild", "vcpkg_install_msbuild", false); + } + std::string::size_type index = 0; + while ((index = portfile_content.find("vcpkg_configure_cmake", index)) != std::string::npos) + { + handle_warning("vcpkg_configure_cmake", "vcpkg_cmake_configure"); + if (fix == Fix::NO) + { + break; + } + const auto end = portfile_content.find(')', index); + find_remove_param(portfile_content, "PREFER_NINJA", index, end); + portfile_content.replace(index, StringLiteral("vcpkg_configure_cmake").size(), "vcpkg_cmake_configure"); + fixedPortfile.added_host_deps.insert("vcpkg-cmake"); + } + if (Strings::contains(portfile_content, "vcpkg_build_cmake")) + { + handle_warning("vcpkg_build_cmake", "vcpkg_cmake_build"); + if (fix == Fix::YES) + { + Strings::inplace_replace_all(portfile_content, "vcpkg_build_cmake", "vcpkg_cmake_build"); + fixedPortfile.added_host_deps.insert("vcpkg-cmake"); + } + } + if (Strings::contains(portfile_content, "vcpkg_install_cmake")) + { + handle_warning("vcpkg_install_cmake", "vcpkg_cmake_install"); + if (fix == Fix::YES) + { + Strings::inplace_replace_all(portfile_content, "vcpkg_install_cmake", "vcpkg_cmake_install"); + fixedPortfile.added_host_deps.insert("vcpkg-cmake"); + } + } + index = 0; + while ((index = portfile_content.find("vcpkg_fixup_cmake_targets", index)) != std::string::npos) + { + handle_warning("vcpkg_fixup_cmake_targets", "vcpkg_fixup_cmake_targets"); + if (fix == Fix::NO) + { + break; + } + const auto end = portfile_content.find(')', index); + auto target = find_param_maybe_value(portfile_content, "TARGET_PATH", index, end); + if (target.found()) + { + if (target.value_found()) + { + const auto original_param = target.get_value(portfile_content); + auto param = StringView(original_param); + if (Strings::starts_with(param, "share/")) + { + param = param.substr(StringLiteral("share/").size()); + } + if (param == "${PORT}" || Strings::case_insensitive_ascii_equals(param, origin)) + { + portfile_content.erase(target.start_param, target.full_length()); + } + else + { + portfile_content.replace( + target.start_param, target.full_length() - param.size(), "PACKAGE_NAME "); + } + // remove the CONFIG_PATH part if it uses the same param + auto config = find_param_maybe_value(portfile_content, "CONFIG_PATH", index, end); + if (config.value_found()) + { + if (config.get_value(portfile_content) == original_param) + { + const auto start_next = portfile_content.find_first_not_of(' ', config.end_value); + portfile_content.erase(config.start_param, start_next - config.start_param); + } + } + } + else + { + remove_param(portfile_content, "TARGET_PATH", target.start_param); + } + } + portfile_content.replace( + index, StringLiteral("vcpkg_fixup_cmake_targets").size(), "vcpkg_cmake_config_fixup"); + fixedPortfile.added_host_deps.insert("vcpkg-cmake-config"); + } + index = 0; + while ((index = portfile_content.find("vcpkg_extract_source_archive_ex", index)) != std::string::npos) + { + handle_warning("vcpkg_extract_source_archive_ex", "vcpkg_extract_source_archive"); + if (fix == Fix::NO) + { + break; + } + const auto end = portfile_content.find(')', index); + auto out_source_path = find_param_maybe_value(portfile_content, "OUT_SOURCE_PATH", index, end); + if (out_source_path.value_found()) + { + const auto param_value = out_source_path.get_value(portfile_content); + + const auto before_param = portfile_content.find_last_not_of(' ', out_source_path.start_param - 1) + 1; + auto after_value = portfile_content.find_first_not_of(" \r", out_source_path.end_value); + const std::string line_ending = portfile_content[after_value - 1] == '\r' ? "\r\n" : "\n"; + if (portfile_content[after_value] != '\n') + { + // if OUT_SOURCE_PATH is not on its own line, don't remove new line character + after_value -= line_ending.size(); + } + // remove ' OUT_SOURCE_PATH FOOBAR ' line + portfile_content.erase(before_param, after_value + 1 - before_param); + + // Replace 'REF' by 'SOURCE_BASE' + replace_param(portfile_content, "REF", "SOURCE_BASE", index, end); + + // insert 'FOOBAR' or // '\n FOOBAR' after '(' + auto open_bracket = portfile_content.find('(', index); + if (open_bracket != std::string::npos && open_bracket < out_source_path.start_param) + { + char c = portfile_content[before_param - 1]; + if (c == '\n') + { + // if the OUT_SOURCE_PATH was in a new line, insert the param in a new line + auto num_spaces = out_source_path.start_param - before_param; + portfile_content.insert(open_bracket + 1, + line_ending + std::string(num_spaces, ' ') + param_value); + } + else + { + portfile_content.insert(open_bracket + 1, param_value + ' '); + } + } + } + portfile_content.replace( + index, StringLiteral("vcpkg_extract_source_archive_ex").size(), "vcpkg_extract_source_archive"); + } + index = 0; + while ((index = portfile_content.find("vcpkg_check_features", index)) != std::string::npos) + { + const auto end = portfile_content.find(')', index); + const auto features = find_param(portfile_content, "FEATURES", index, end); + const auto inverted_features = find_param(portfile_content, "INVERTED_FEATURES", index, end); + if (features == std::string::npos && inverted_features == std::string::npos) + { + if (fix == Fix::NO) + { + status |= Status::Problem; + warningsSink.println_warning(msgLintVcpkgCheckFeatures, msg::package_name = origin); + break; + } + status |= Status::Fixed; + + auto feature_options = find_param_maybe_value(portfile_content, "OUT_FEATURE_OPTIONS", index, end); + if (feature_options.value_found()) + { + portfile_content.insert(feature_options.end_value, " FEATURES"); + } + } + index = end; + } + + fixedPortfile.status = status; + if (fix == Fix::YES) + { + fixedPortfile.new_portfile_content = std::move(portfile_content); + } + return fixedPortfile; + } + + Status& operator|=(Status& self, Status s) + { + self = static_cast(static_cast>(self) | + static_cast>(s)); + return self; + } + +} diff --git a/src/vcpkg/sourceparagraph.cpp b/src/vcpkg/sourceparagraph.cpp index 5b29eadc74..868fd5905c 100644 --- a/src/vcpkg/sourceparagraph.cpp +++ b/src/vcpkg/sourceparagraph.cpp @@ -173,7 +173,7 @@ namespace vcpkg namespace { - constexpr static struct Canonicalize + constexpr struct Canonicalize { struct FeatureLess { @@ -249,16 +249,16 @@ namespace vcpkg void operator()(SourceParagraph& spgh) const { std::for_each(spgh.dependencies.begin(), spgh.dependencies.end(), *this); - std::sort(spgh.dependencies.begin(), spgh.dependencies.end(), DependencyLess{}); + Util::sort_unique_erase(spgh.dependencies, DependencyLess{}); - std::sort(spgh.default_features.begin(), spgh.default_features.end()); + Util::sort_unique_erase(spgh.default_features); spgh.extra_info.sort_keys(); } void operator()(FeatureParagraph& fpgh) const { std::for_each(fpgh.dependencies.begin(), fpgh.dependencies.end(), *this); - std::sort(fpgh.dependencies.begin(), fpgh.dependencies.end(), DependencyLess{}); + Util::sort_unique_erase(fpgh.dependencies, DependencyLess{}); fpgh.extra_info.sort_keys(); } @@ -281,7 +281,7 @@ namespace vcpkg } return nullptr; } - } canonicalize{}; + } canonicalize_{}; } static ParseExpected parse_source_paragraph(StringView origin, Paragraph&& fields) @@ -431,7 +431,7 @@ namespace vcpkg return std::move(maybe_feature).error(); } - if (auto maybe_error = canonicalize(*control_file)) + if (auto maybe_error = canonicalize_(*control_file)) { return maybe_error; } @@ -1121,7 +1121,7 @@ namespace vcpkg } } - if (auto maybe_error = canonicalize(*control_file)) + if (auto maybe_error = control_file->canonicalize()) { Checks::msg_exit_with_message(VCPKG_LINE_INFO, maybe_error->error); } @@ -1402,6 +1402,8 @@ namespace vcpkg return Unit{}; } + std::unique_ptr SourceControlFile::canonicalize() { return canonicalize_(*this); } + std::string ParseControlErrorInfo::format_errors(View> error_info_list) { std::string message;