Add the bash script, remove broken reset command from other scripts.
MODIFY
azure-pipelines/binary-signing.signproj
azure-pipelines/binary-signing.signproj
<Authenticode>Microsoft400</Authenticode>
</FilesToSign>
+ <FilesToSign Include="$(IntermediateOutputPath)\vcpkg-init">
+ <Authenticode>LinuxSign</Authenticode>
+ </FilesToSign>
<FilesToSign Include="$(IntermediateOutputPath)\vcpkg-glibc">
<Authenticode>LinuxSign</Authenticode>
</FilesToSign>

MODIFY
azure-pipelines/signing.yml
azure-pipelines/signing.yml
@@ -16,6 +16,7 @@ parameters:
- name: VcpkgBaseVersionOverride
displayName: vcpkg Base Version (default is today's date in ISO 8601)
type: string
+ default:
variables:
- ${{ if eq(parameters.VcpkgBaseVersionOverride, '') }}:
@@ -135,7 +136,7 @@ jobs:
inputs:
pwsh: true
filePath: vcpkg-init/mint-standalone-bundle.ps1
- arguments: '-DestinationTarballName "$(Build.BinariesDirectory)\vcpkg-standalone-bundle.tar.gz" -TempPath standalone-temp "$(Build.BinariesDirectory)\vcpkg-init.cmd" "$(Build.BinariesDirectory)\vcpkg-init.ps1"'
+ arguments: '-DestinationTarballName "$(Build.BinariesDirectory)\vcpkg-standalone-bundle.tar.gz" -TempPath standalone-temp "$(Build.BinariesDirectory)\vcpkg-init.cmd" "$(Build.BinariesDirectory)\vcpkg-init.ps1" "$(Build.BinariesDirectory)\vcpkg-init"'
- script: npm pack
displayName: Create vcpkg-ce Pack
workingDirectory: $(Build.BinariesDirectory)/vcpkg-ce
@@ -143,6 +144,7 @@ jobs:
mkdir "$(Build.ArtifactStagingDirectory)\staging"
move "$(Build.BinariesDirectory)\vcpkg-ce\vcpkg-ce-*.tgz" "$(Build.ArtifactStagingDirectory)\staging\vcpkg-ce.tgz"
move "$(Build.BinariesDirectory)\vcpkg-standalone-bundle.tar.gz" "$(Build.ArtifactStagingDirectory)\staging\vcpkg-standalone-bundle.tar.gz"
+ move "$(Build.BinariesDirectory)\vcpkg-init" "$(Build.ArtifactStagingDirectory)\staging\vcpkg-init"
move "$(Build.BinariesDirectory)\vcpkg-init.ps1" "$(Build.ArtifactStagingDirectory)\staging\vcpkg-init.ps1"
move "$(Build.BinariesDirectory)\vcpkg-init.cmd" "$(Build.ArtifactStagingDirectory)\staging\vcpkg-init.cmd"
displayName: 'Arrange Architecture-independent Files for Staging'
@@ -334,11 +336,12 @@ jobs:
inputs:
artifactName: staging
- task: CmdLine@2
- displayName: 'Move Linux Binaries to BinariesDirectory'
+ displayName: 'Copy Linux Binaries to BinariesDirectory'
inputs:
failOnStderr: true
script: |
mkdir "$(Build.BinariesDirectory)\build"
+ copy /Y "$(Build.ArtifactStagingDirectory)\staging\vcpkg-init" "$(Build.BinariesDirectory)\vcpkg-init"
copy /Y "$(Build.ArtifactStagingDirectory)\staging\vcpkg-glibc" "$(Build.BinariesDirectory)\vcpkg-glibc"
copy /Y "$(Build.ArtifactStagingDirectory)\staging\vcpkg-muslc" "$(Build.BinariesDirectory)\vcpkg-muslc"
- task: MSBuild@1
@@ -372,6 +375,7 @@ jobs:
script: |
mkdir "$(Build.ArtifactStagingDirectory)\drop"
+ move "$(Build.ArtifactStagingDirectory)\staging\vcpkg-init" "$(Build.ArtifactStagingDirectory)\drop\vcpkg-init"
move "$(Build.ArtifactStagingDirectory)\staging\vcpkg-init.cmd" "$(Build.ArtifactStagingDirectory)\drop\vcpkg-init.cmd"
move "$(Build.ArtifactStagingDirectory)\staging\vcpkg-init.ps1" "$(Build.ArtifactStagingDirectory)\drop\vcpkg-init.ps1"
move "$(Build.ArtifactStagingDirectory)\staging\vcpkg-ce.tgz" "$(Build.ArtifactStagingDirectory)\drop\vcpkg-ce.tgz"
@@ -397,6 +401,7 @@ jobs:
inputs:
failOnStderr: true
script: |
+ move "$(Build.BinariesDirectory)\vcpkg-init" "$(Build.ArtifactStagingDirectory)\drop\vcpkg-init.sig"
move "$(Build.BinariesDirectory)\vcpkg-glibc" "$(Build.ArtifactStagingDirectory)\drop\vcpkg-glibc.sig"
move "$(Build.BinariesDirectory)\vcpkg-muslc" "$(Build.ArtifactStagingDirectory)\drop\vcpkg-muslc.sig"
# Do compliance checks.

MODIFY
include/vcpkg/base/system.process.h
include/vcpkg/base/system.process.h
@@ -23,6 +23,8 @@ namespace vcpkg
std::string s;
};
+ void append_escaped_quoted_string(std::string& target, StringView content);
+
struct Command
{
Command() = default;
@@ -39,6 +41,7 @@ namespace vcpkg
{
buf.push_back(' ');
}
+
buf.append(s.data(), s.size());
return *this;
}
@@ -92,7 +95,9 @@ namespace vcpkg
{
#if defined(_WIN32)
std::wstring m_env_data;
-#endif
+#else // ^^^ _WIN32 // !_WIN32 vvv
+ std::string m_env_data;
+#endif // ^^^ !_WIN32
};
const Environment& get_clean_environment();

MODIFY
src/vcpkg/base/system.process.cpp
src/vcpkg/base/system.process.cpp
namespace vcpkg
{
+ void append_escaped_quoted_string(std::string& target, StringView content)
+ {
+ if (Strings::find_first_of(content, " \t\n\r\"\\,;&`^|'") != content.end())
+ {
+ // TODO: improve this to properly handle all escaping
+#if _WIN32
+ // On Windows, `\`s before a double-quote must be doubled. Inner double-quotes must be escaped.
+ target.push_back('"');
+ size_t n_slashes = 0;
+ for (auto ch : content)
+ {
+ if (ch == '\\')
+ {
+ ++n_slashes;
+ }
+ else if (ch == '"')
+ {
+ target.append(n_slashes + 1, '\\');
+ n_slashes = 0;
+ }
+ else
+ {
+ n_slashes = 0;
+ }
+ target.push_back(ch);
+ }
+ target.append(n_slashes, '\\');
+ target.push_back('"');
+#else
+ // On non-Windows, `\` is the escape character and always requires doubling. Inner double-quotes must be
+ // escaped.
+ target.push_back('"');
+ for (auto ch : content)
+ {
+ if (ch == '\\' || ch == '"') target.push_back('\\');
+ target.push_back(ch);
+ }
+ target.push_back('"');
+#endif
+ }
+ else
+ {
+ target.append(content.data(), content.size());
+ }
+ }
+
static std::atomic<uint64_t> g_subprocess_stats(0);
#if defined(_WIN32)
@@ -203,48 +249,7 @@ namespace vcpkg
Command& Command::string_arg(StringView s) &
{
if (!buf.empty()) buf.push_back(' ');
- if (Strings::find_first_of(s, " \t\n\r\"\\,;&`^|'") != s.end())
- {
- // TODO: improve this to properly handle all escaping
-#if _WIN32
- // On Windows, `\`s before a double-quote must be doubled. Inner double-quotes must be escaped.
- buf.push_back('"');
- size_t n_slashes = 0;
- for (auto ch : s)
- {
- if (ch == '\\')
- {
- ++n_slashes;
- }
- else if (ch == '"')
- {
- buf.append(n_slashes + 1, '\\');
- n_slashes = 0;
- }
- else
- {
- n_slashes = 0;
- }
- buf.push_back(ch);
- }
- buf.append(n_slashes, '\\');
- buf.push_back('"');
-#else
- // On non-Windows, `\` is the escape character and always requires doubling. Inner double-quotes must be
- // escaped.
- buf.push_back('"');
- for (auto ch : s)
- {
- if (ch == '\\' || ch == '"') buf.push_back('\\');
- buf.push_back(ch);
- }
- buf.push_back('"');
-#endif
- }
- else
- {
- Strings::append(buf, s);
- }
+ append_escaped_quoted_string(buf, s);
return *this;
}
@@ -394,9 +399,20 @@ namespace vcpkg
return {env_cstr};
}
#else
- Environment get_modified_clean_environment(const std::unordered_map<std::string, std::string>&, StringView)
+ Environment get_modified_clean_environment(const std::unordered_map<std::string, std::string>&,
+ StringView prepend_to_path)
{
- return {};
+ std::string result;
+ if (!prepend_to_path.empty())
+ {
+ std::string new_path = get_environment_variable("PATH").value_or_exit(VCPKG_LINE_INFO);
+ new_path.insert(new_path.begin(), prepend_to_path.size() + 1, ':');
+ std::copy_n(prepend_to_path.data(), prepend_to_path.size(), new_path.begin());
+ result = "PATH=";
+ append_escaped_quoted_string(result, new_path);
+ }
+
+ return {result};
}
#endif
const Environment& get_clean_environment()
@@ -706,16 +722,22 @@ namespace vcpkg
g_ctrl_c_state.transition_from_spawn_process();
#else
(void)env;
- std::string real_command_line;
- if (wd.working_directory.empty())
+ Command real_command_line_builder;
+ if (!wd.working_directory.empty())
{
- real_command_line = cmd_line.command_line().to_string();
+ real_command_line_builder.string_arg("cd");
+ real_command_line_builder.path_arg(wd.working_directory);
+ real_command_line_builder.raw_arg("&&");
}
- else
+
+ if (!env.m_env_data.empty())
{
- real_command_line =
- Command("cd").path_arg(wd.working_directory).raw_arg("&&").raw_arg(cmd_line.command_line()).extract();
+ real_command_line_builder.raw_arg(env.m_env_data);
}
+
+ real_command_line_builder.raw_arg(cmd_line.command_line());
+
+ std::string real_command_line = std::move(real_command_line_builder).extract();
Debug::print("system(", real_command_line, ")\n");
fflush(nullptr);

MODIFY
src/vcpkg/configure-environment.cpp
src/vcpkg/configure-environment.cpp
@@ -19,7 +19,7 @@ namespace vcpkg
auto& fs = paths.get_filesystem();
auto& download_manager = paths.get_download_manager();
auto node_path = paths.get_tool_exe(Tools::NODE);
- auto node_root = node_path.parent_path();
+ Path node_root = node_path.parent_path();
auto node_modules = paths.root / "node_modules";
auto ce_path = node_modules / "vcpkg-ce";
if (!fs.is_directory(ce_path))
@@ -38,7 +38,12 @@ namespace vcpkg
const auto ce_tarball = paths.downloads / "vcpkg-ce-latest.tgz";
download_manager.download_file(fs, ce_uri, ce_tarball, nullopt);
#endif // ^^^ !VCPKG_CE_BUNDLE_SHA
- auto npm_path = Path(node_root) / "node_modules" / "npm" / "bin" / "npm-cli.js";
+ auto npm_path = node_root / "node_modules" / "npm" / "bin" / "npm-cli.js";
+ if (!fs.exists(npm_path, VCPKG_LINE_INFO))
+ {
+ npm_path = Path(node_root.parent_path()) / "lib" / "node_modules" / "npm" / "bin" / "npm-cli.js";
+ }
+
Command cmd_provision(node_path);
cmd_provision.string_arg(npm_path);
cmd_provision.string_arg("--force");

MODIFY
vcpkg-init/lock-versions.ps1
vcpkg-init/lock-versions.ps1
@@ -8,6 +8,11 @@ Param(
$versionUnlockedUri = "https://github.com/microsoft/vcpkg-tool/releases/latest/download/"
$versionLockedUri = "https://github.com/microsoft/vcpkg-tool/releases/download/$VcpkgBaseVersion/"
+
$pwshInstaller = Get-Content "$PSScriptRoot\vcpkg-init.ps1" -Raw
$pwshInstaller = $pwshInstaller.Replace($versionUnlockedUri, $versionLockedUri)
-Set-Content -Path "$Destination\vcpkg-init.ps1" -Value $pwshInstaller
+Set-Content -Path "$Destination\vcpkg-init.ps1" -Value $pwshInstaller -NoNewline
+
+$shInstaller = Get-Content "$PSScriptRoot\vcpkg-init" -Raw
+$shInstaller = $shInstaller.Replace($versionUnlockedUri, $versionLockedUri)
+Set-Content -Path "$Destination\vcpkg-init" -Value $shInstaller -NoNewline

ADD
vcpkg-init/vcpkg-init
+#!/bin/sh
+
+# Copyright (c) Microsoft Corporation.
+# Licensed under the MIT License.
+
+# wrapper script for vcpkg
+# this is intended to be dot-sourced and then you can use the vcpkg() function.
+
+# check to see if we've been dot-sourced (should work for most POSIX shells)
+sourced=0
+
+if [ -n "$ZSH_EVAL_CONTEXT" ]; then
+ case $ZSH_EVAL_CONTEXT in *:file) sourced=1;; esac
+elif [ -n "$KSH_VERSION" ]; then
+ [ "$(cd $(dirname -- $0) && pwd -P)/$(basename -- $0)" != "$(cd $(dirname -- ${.sh.file}) && pwd -P)/$(basename -- ${.sh.file})" ] && sourced=1
+elif [ -n "$BASH_VERSION" ]; then
+ (return 0 2>/dev/null) && sourced=1
+else # All other shells: examine $0 for known shell binary filenames
+ # Detects `sh` and `dash`; add additional shell filenames as needed.
+ case ${0##*/} in sh|dash) sourced=1;; esac
+fi
+
+if [ $sourced -eq 0 ]; then
+ echo 'This script is expected to be dot-sourced so that it may load vcpkg into the'
+ echo 'current environment and not require permanent changes to the system when you activate.'
+ echo ''
+ echo "You should instead run '. $(basename $0)' first to import vcpkg into the current session."
+ exit
+fi
+
+Z_VCPKG_init() {
+ # find important cmdline args
+ Z_VCPKG_ARGS=()
+ for each in "$@"; do case $each in
+ --remove-vcpkg) Z_VCPKG_REMOVE=TRUE;;
+ *) Z_VCPKG_ARGS+=("$each");;
+ esac ;done
+}
+
+Z_VCPKG_bootstrap() {
+ if [ -f "${VCPKG_ROOT}/vcpkg" ]; then
+ return 0
+ fi
+
+ # it's not there!
+ # let's install it where we want it
+
+ echo installing vcpkg in $VCPKG_ROOT
+
+ if [ "$UNAME" = "Darwin" ]; then
+ curl -L -o "${VCPKG_ROOT}/vcpkg" https://github.com/microsoft/vcpkg-tool/releases/latest/download/vcpkg-macos
+ elif [ -e /etc/alpine-release ]; then
+ curl -L -o "${VCPKG_ROOT}/vcpkg" https://github.com/microsoft/vcpkg-tool/releases/latest/download/vcpkg-muslc
+ else
+ curl -L -o "${VCPKG_ROOT}/vcpkg" https://github.com/microsoft/vcpkg-tool/releases/latest/download/vcpkg-glibc
+ fi
+
+ if [ ! -f "${VCPKG_ROOT}/vcpkg" ]; then
+ echo "ERROR! Unable to find/get vcpkg binary ${VCPKG_ROOT}/vcpkg"
+ return 1;
+ fi
+
+ chmod +x "${VCPKG_ROOT}/vcpkg"
+ "${VCPKG_ROOT}/vcpkg" z-bootstrap-standalone
+ return 0;
+}
+
+Z_VCPKG_cleanup() {
+ # clear things that we're not going to need for the long term
+ unset Z_VCPKG_REMOVE
+ unset Z_VCPKG_ARGS
+ if [ -f "${Z_VCPKG_POSTSCRIPT}" ]; then
+ command rm "${Z_VCPKG_POSTSCRIPT}"
+ fi
+ unset Z_VCPKG_POSTSCRIPT
+ unset -f Z_VCPKG_bootstrap > /dev/null 2>&1
+}
+
+Z_VCPKG_remove() {
+ Z_VCPKG_cleanup
+ if [ -d "$VCPKG_ROOT" ]; then
+ rm -rf "$VCPKG_ROOT"
+ fi
+
+ unset -f Z_VCPKG_init > /dev/null 2>&1
+ unset -f Z_VCPKG_cleanup > /dev/null 2>&1
+ unset -f Z_VCPKG_remove > /dev/null 2>&1
+ unset -f vcpkg > /dev/null 2>&1
+}
+
+Z_VCPKG_init "$@"
+shift $#
+
+if [ -n "$VCPKG_ROOT" ]; then
+ export VCPKG_ROOT=$VCPKG_ROOT
+else
+ export VCPKG_ROOT=~/.vcpkg
+fi;
+
+mkdir -p "$VCPKG_ROOT"
+
+if [ ! -z "$Z_VCPKG_REMOVE" ]; then
+ Z_VCPKG_remove
+ return
+fi
+
+
+Z_VCPKG_bootstrap
+if [ $? -eq 1 ]; then
+ Z_VCPKG_cleanup
+ return 1;
+fi
+
+# So, we're the real script then.
+vcpkg() {
+ Z_VCPKG_init "$@"
+
+ if [ ! -z "$Z_VCPKG_REMOVE" ]; then
+ Z_VCPKG_remove
+ return;
+ fi
+
+ # set the response file
+ # Generate 32 bits of randomness, to avoid clashing with concurrent executions.
+ export Z_VCPKG_POSTSCRIPT="${VCPKG_ROOT}/VCPKG_tmp_$(dd if=/dev/urandom count=1 2> /dev/null | cksum | cut -f1 -d" ").sh"
+
+ # call vcpkg
+ # it picks up the Z_VCPKG_POSTSCRIPT environment variable to know where to dump the postscript
+ "${VCPKG_ROOT}/vcpkg" ${Z_VCPKG_ARGS[@]}
+
+ # Call the post-invocation script if it is present, then delete it.
+ # This allows the invocation to potentially modify the caller's environment (e.g. PATH)
+ if [ -f "${Z_VCPKG_POSTSCRIPT}" ]; then
+ . "${Z_VCPKG_POSTSCRIPT}"
+ command rm "${Z_VCPKG_POSTSCRIPT}"
+ unset Z_VCPKG_POSTSCRIPT
+ fi
+
+ Z_VCPKG_cleanup
+}
+
+# did they dotsource and have args go ahead and run it then!
+if [ -n "$Z_VCPKG_ARGS" ]; then
+ vcpkg "${Z_VCPKG_ARGS[@]}"
+fi
+
+Z_VCPKG_cleanup

MODIFY
vcpkg-init/vcpkg-init.ps1
vcpkg-init/vcpkg-init.ps1
@@ -74,25 +74,14 @@ if( $ENV:VCPKG_ROOT ) {
$VCPKG = "${VCPKG_ROOT}/vcpkg.exe"
$SCRIPT:VCPKG_SCRIPT = "${VCPKG_ROOT}/vcpkg-init.ps1"
-$reset = $args.IndexOf('--reset-vcpkg') -gt -1
$remove = $args.IndexOf('--remove-vcpkg') -gt -1
-if( $reset -or -$remove ) {
- $args.remove('--reset-vcpkg');
- $args.remove('--remove-vcpkg');
-
- if( $reset ) {
- write-host "Resetting vcpkg"
- }
-
- remove-item -recurse -force -ea 0 "$VCPKG_ROOT"
- $error.clear();
-
if( $remove ) {
write-host "Removing vcpkg"
+ remove-item -recurse -force -ea 0 "$VCPKG_ROOT"
+ $error.clear();
exit
}
-}
function bootstrap-vcpkg {
if( test-path $VCPKG_SCRIPT ) {
@@ -136,7 +125,7 @@ $shh = New-Module -name vcpkg -ArgumentList @($VCPKG,$VCPKG_ROOT) -ScriptBlock {
}
function vcpkg() {
- if( ($args.indexOf('--remove-vcpkg') -gt -1) -or ($args.indexOf('--reset-vcpkg') -gt -1)) {
+ if( ($args.indexOf('--remove-vcpkg') -gt -1)) {
# we really want to do call the ps1 script to do this.
if( test-path "${VCPKG_ROOT}/vcpkg.ps1" ) {
& "${VCPKG_ROOT}/vcpkg.ps1" @args
@@ -190,11 +179,8 @@ if exist $null erase $null
IF "%VCPKG_ROOT%"=="" SET VCPKG_ROOT=%USERPROFILE%\.vcpkg
:: we're running vcpkg from the home folder
-set VCPKG_CMD=%VCPKG_ROOT%\vcpkg-init.cmd
-set VCPKG_EXE=%VCPKG_ROOT%\vcpkg.exe
-
-:: if we're being asked to reset the install, call bootstrap
-if "%1" EQU "--reset-vcpkg" goto BOOTSTRAP
+set Z_VCPKG_CMD=%VCPKG_ROOT%\vcpkg-init.cmd
+set Z_VCPKG_EXE=%VCPKG_ROOT%\vcpkg.exe
:: if we're being asked to remove the install, call bootstrap
if "%1" EQU "--remove-vcpkg" (
@@ -204,13 +190,13 @@ if "%1" EQU "--remove-vcpkg" (
)
:: do we even have it installed?
-if NOT exist "%VCPKG_CMD%" goto BOOTSTRAP
+if NOT exist "%Z_VCPKG_CMD%" goto BOOTSTRAP
:: if this is the actual installed vcpkg-ce, let's get to the invocation
-if "%~dfp0" == "%VCPKG_CMD%" goto INVOKE
+if "%~dfp0" == "%Z_VCPKG_CMD%" goto INVOKE
:: this is not the 'right' vcpkg cmd, let's forward this on to that one.
-call "%VCPKG_CMD%" %*
+call "%Z_VCPKG_CMD%" %*
set VCPKG_EXITCODE=%ERRORLEVEL%
goto :eof
@@ -220,9 +206,9 @@ SET /A Z_VCPKG_POSTSCRIPT=%RANDOM% * 32768 + %RANDOM%
SET Z_VCPKG_POSTSCRIPT=%VCPKG_ROOT%\VCPKG_tmp_%Z_VCPKG_POSTSCRIPT%.cmd
:: call the program
-"%VCPKG_EXE%" %*
+"%Z_VCPKG_EXE%" %*
set VCPKG_EXITCODE=%ERRORLEVEL%
-doskey vcpkg="%VCPKG_CMD%" $*
+doskey vcpkg="%Z_VCPKG_CMD%" $*
:POSTSCRIPT
:: Call the post-invocation script if it is present, then delete it.
@@ -237,13 +223,13 @@ goto :fin
:: add the cmdline args to the environment so powershell can use them
set /a i=0 & for %%a in (%*) do call :set %%a
-set POWERSHELL_EXE=
+set Z_POWERSHELL_EXE=
for %%i in (pwsh.exe powershell.exe) do (
- if EXIST "%%~$PATH:i" set POWERSHELL_EXE=%%~$PATH:i & goto :gotpwsh
+ if EXIST "%%~$PATH:i" set Z_POWERSHELL_EXE=%%~$PATH:i & goto :gotpwsh
)
:gotpwsh
-"%POWERSHELL_EXE%" -noprofile -executionpolicy unrestricted -command "iex (get-content %~dfp0 -raw)#" && set REMOVE_VCPKG=
+"%Z_POWERSHELL_EXE%" -noprofile -executionpolicy unrestricted -command "iex (get-content %~dfp0 -raw)#" && set REMOVE_VCPKG=
set VCPKG_EXITCODE=%ERRORLEVEL%
:: clear out the arguments
@@ -258,9 +244,10 @@ if "%REMOVE_VCPKG%" EQU "TRUE" (
doskey vcpkg="%VCPKG_ROOT%\vcpkg-init.cmd" $*
:fin
+SET Z_POWERSHELL_EXE=
SET Z_VCPKG_POSTSCRIPT=
-SET VCPKG_CMD=
-set VCPKG_EXE=
+SET Z_VCPKG_CMD=
+set Z_VCPKG_EXE=
EXIT /B %VCPKG_EXITCODE%
goto :eof

Add the bash script, remove broken reset command from other scripts.