aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Karatarakis <alkarata@microsoft.com>2018-05-05 04:23:19 -0700
committerAlexander Karatarakis <alkarata@microsoft.com>2018-05-15 23:27:14 -0700
commit1b0682a39e1143660c3d5aa371f66591a64e8a5d (patch)
treefed8de963661a5176f70b74b91ab1cef7bf00a74
parent52f01eefa6e1da7a9458807a1eb3d288ecd50613 (diff)
downloadvcpkg-1b0682a39e1143660c3d5aa371f66591a64e8a5d.tar.gz
vcpkg-1b0682a39e1143660c3d5aa371f66591a64e8a5d.zip
[vcpkg] Significantly reduce usage of powershell. Reduce console font switching bug
-rw-r--r--scripts/VcpkgPowershellUtils.ps1322
-rw-r--r--scripts/addPoshVcpkgToPowershellProfile.ps17
-rw-r--r--scripts/bootstrap.ps1108
-rw-r--r--scripts/fetchTool.ps1109
-rw-r--r--scripts/findAnyMSBuildWithCppPlatformToolset.ps158
-rw-r--r--scripts/findVisualStudioInstallationInstances.ps161
-rw-r--r--scripts/getProgramFiles32bit.ps117
-rw-r--r--scripts/getProgramFilesPlatformBitness.ps117
-rw-r--r--scripts/getVisualStudioInstances.ps174
-rw-r--r--scripts/vcpkgTools.xml15
-rw-r--r--toolsrc/include/vcpkg/base/system.h2
-rw-r--r--toolsrc/include/vcpkg/commands.h4
-rw-r--r--toolsrc/include/vcpkg/vcpkgpaths.h1
-rw-r--r--toolsrc/src/vcpkg/base/checks.cpp2
-rw-r--r--toolsrc/src/vcpkg/base/system.cpp19
-rw-r--r--toolsrc/src/vcpkg/build.cpp14
-rw-r--r--toolsrc/src/vcpkg/commands.cpp2
-rw-r--r--toolsrc/src/vcpkg/commands.fetch.cpp509
-rw-r--r--toolsrc/src/vcpkg/commands.hash.cpp7
-rw-r--r--toolsrc/src/vcpkg/export.cpp2
-rw-r--r--toolsrc/src/vcpkg/vcpkgpaths.cpp9
-rw-r--r--toolsrc/vcpkg.sln5
22 files changed, 596 insertions, 768 deletions
diff --git a/scripts/VcpkgPowershellUtils.ps1 b/scripts/VcpkgPowershellUtils.ps1
index 3ea18116b..259df4acb 100644
--- a/scripts/VcpkgPowershellUtils.ps1
+++ b/scripts/VcpkgPowershellUtils.ps1
@@ -1,8 +1,3 @@
-function vcpkgHasModule([Parameter(Mandatory=$true)][string]$moduleName)
-{
- return [bool](Get-Module -ListAvailable -Name $moduleName)
-}
-
function vcpkgHasProperty([Parameter(Mandatory=$true)][AllowNull()]$object, [Parameter(Mandatory=$true)]$propertyName)
{
if ($object -eq $null)
@@ -10,320 +5,21 @@ function vcpkgHasProperty([Parameter(Mandatory=$true)][AllowNull()]$object, [Par
return $false
}
- return [bool]($object.psobject.Properties | where { $_.Name -eq "$propertyName"})
-}
-
-function vcpkgCreateDirectoryIfNotExists([Parameter(Mandatory=$true)][string]$dirPath)
-{
- if (!(Test-Path $dirPath))
- {
- New-Item -ItemType Directory -Path $dirPath | Out-Null
- }
-}
-
-function vcpkgCreateParentDirectoryIfNotExists([Parameter(Mandatory=$true)][string]$path)
-{
- $parentDir = split-path -parent $path
- if ([string]::IsNullOrEmpty($parentDir))
- {
- return
- }
-
- if (!(Test-Path $parentDir))
- {
- New-Item -ItemType Directory -Path $parentDir | Out-Null
- }
-}
-
-function vcpkgIsDirectory([Parameter(Mandatory=$true)][string]$path)
-{
- return (Get-Item $path) -is [System.IO.DirectoryInfo]
-}
-
-function vcpkgRemoveItem([Parameter(Mandatory=$true)][string]$path)
-{
- if ([string]::IsNullOrEmpty($path))
- {
- return
- }
-
- if (Test-Path $path)
- {
- # Remove-Item -Recurse occasionally fails. This is a workaround
- if (vcpkgIsDirectory $path)
- {
- & cmd.exe /c rd /s /q $path
- }
- else
- {
- Remove-Item $path -Force
- }
- }
-}
-
-function vcpkgHasCommand([Parameter(Mandatory=$true)][string]$commandName)
-{
- return [bool](Get-Command -Name $commandName -ErrorAction SilentlyContinue)
-}
-
-function vcpkgHasCommandParameter([Parameter(Mandatory=$true)][string]$commandName, [Parameter(Mandatory=$true)][string]$parameterName)
-{
- return (Get-Command $commandName).Parameters.Keys -contains $parameterName
-}
-
-function vcpkgGetCredentials()
-{
- if (vcpkgHasCommandParameter -commandName 'Get-Credential' -parameterName 'Message')
- {
- return Get-Credential -Message "Enter credentials for Proxy Authentication"
- }
- else
- {
- Write-Host "Enter credentials for Proxy Authentication"
- return Get-Credential
- }
-}
-
-function vcpkgGetSHA512([Parameter(Mandatory=$true)][string]$filePath)
-{
- if (vcpkgHasCommand -commandName 'Microsoft.PowerShell.Utility\Get-FileHash')
- {
- Write-Verbose("Hashing with Microsoft.PowerShell.Utility\Get-FileHash")
- $hashresult = Microsoft.PowerShell.Utility\Get-FileHash -Path $filePath -Algorithm SHA512 -ErrorVariable hashError
- if ($hashError)
- {
- Start-Sleep 3
- $hashresult = Microsoft.PowerShell.Utility\Get-FileHash -Path $filePath -Algorithm SHA512 -ErrorVariable Stop
- }
- $hash = $hashresult.Hash
- }
- elseif(vcpkgHasCommand -commandName 'Pscx\Get-Hash')
- {
- Write-Verbose("Hashing with Pscx\Get-Hash")
- $hash = (Pscx\Get-Hash -Path $filePath -Algorithm SHA512).HashString
- }
- else
- {
- Write-Verbose("Hashing with .NET")
- $hashAlgorithm = [Security.Cryptography.HashAlgorithm]::Create("SHA512")
- $fileAsByteArray = [io.File]::ReadAllBytes($filePath)
- $hashByteArray = $hashAlgorithm.ComputeHash($fileAsByteArray)
- $hash = -Join ($hashByteArray | ForEach-Object {"{0:x2}" -f $_})
- }
-
- return $hash.ToLower()
+ return [bool]($object.psobject.Properties | Where-Object { $_.Name -eq "$propertyName"})
}
-function vcpkgCheckEqualFileHash( [Parameter(Mandatory=$true)][string]$url,
- [Parameter(Mandatory=$true)][string]$filePath,
- [Parameter(Mandatory=$true)][string]$expectedHash)
+function getProgramFiles32bit()
{
- $actualHash = vcpkgGetSHA512 $filePath
- if ($expectedHash -ne $actualHash)
+ $out = ${env:PROGRAMFILES(X86)}
+ if ($out -eq $null)
{
- Write-Host ("`nFile does not have expected hash:`n" +
- " url: [ $url ]`n" +
- " File path: [ $filePath ]`n" +
- " Expected hash: [ $expectedHash ]`n" +
- " Actual hash: [ $actualHash ]`n")
- throw
+ $out = ${env:PROGRAMFILES}
}
-}
-function vcpkgDownloadFile( [Parameter(Mandatory=$true)][string]$url,
- [Parameter(Mandatory=$true)][string]$downloadPath,
- [Parameter(Mandatory=$true)][string]$sha512)
-{
- if ($url -match "github")
+ if ($out -eq $null)
{
- if ([System.Enum]::IsDefined([Net.SecurityProtocolType], "Tls12"))
- {
- [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
- }
- else
- {
- Write-Warning "Github has dropped support for TLS versions prior to 1.2, which is not available on your system"
- Write-Warning "Please manually download $url to $downloadPath"
- Write-Warning "To solve this issue for future downloads, you can also install Windows Management Framework 5.1+"
- throw "Download failed"
- }
+ throw "Could not find [Program Files 32-bit]"
}
- vcpkgCreateParentDirectoryIfNotExists $downloadPath
-
- $downloadPartPath = "$downloadPath.part"
- vcpkgRemoveItem $downloadPartPath
-
- $wc = New-Object System.Net.WebClient
- if (!$wc.Proxy.IsBypassed($url))
- {
- $wc.Proxy.Credentials = vcpkgGetCredentials
- }
-
- $wc.DownloadFile($url, $downloadPartPath)
- vcpkgCheckEqualFileHash -url $url -filePath $downloadPartPath -expectedHash $sha512
- Move-Item -Path $downloadPartPath -Destination $downloadPath
-}
-
-function vcpkgDownloadFileWithAria2( [Parameter(Mandatory=$true)][string]$aria2exe,
- [Parameter(Mandatory=$true)][string]$url,
- [Parameter(Mandatory=$true)][string]$downloadPath,
- [Parameter(Mandatory=$true)][string]$sha512)
-{
- vcpkgCreateParentDirectoryIfNotExists $downloadPath
- $downloadPartPath = "$downloadPath.part"
- vcpkgRemoveItem $downloadPartPath
-
- $parentDir = split-path -parent $downloadPath
- $filename = split-path -leaf $downloadPath
-
- if ((Test-Path $url) -or ($url.StartsWith("file://"))) # if is local file
- {
- vcpkgDownloadFile $url $downloadPath $sha512
- return
- }
-
- $ec = vcpkgInvokeCommand "$aria2exe" "--dir=`"$parentDir`" --out=`"$filename.part`" $url"
- if ($ec -ne 0)
- {
- Write-Host "Could not download $url"
- throw
- }
-
- vcpkgCheckEqualFileHash -url $url -filePath $downloadPartPath -expectedHash $sha512
- Move-Item -Path $downloadPartPath -Destination $downloadPath
-}
-
-function vcpkgExtractFileWith7z([Parameter(Mandatory=$true)][string]$sevenZipExe,
- [Parameter(Mandatory=$true)][string]$archivePath,
- [Parameter(Mandatory=$true)][string]$destinationDir)
-{
- vcpkgRemoveItem $destinationDir
- $destinationPartial = "$destinationDir.partial"
- vcpkgRemoveItem $destinationPartial
- vcpkgCreateDirectoryIfNotExists $destinationPartial
- $ec = vcpkgInvokeCommand "$sevenZipExe" "x `"$archivePath`" -o`"$destinationPartial`" -y"
- if ($ec -ne 0)
- {
- Write-Host "Could not extract $archivePath"
- throw
- }
- Rename-Item -Path "$destinationPartial" -NewName $destinationDir -ErrorVariable renameResult
- if ($renameResult)
- {
- Start-Sleep 3
- Rename-Item -Path "$destinationPartial" -NewName $destinationDir -ErrorAction Stop
- }
-}
-
-function vcpkgExtractZipFile( [Parameter(Mandatory=$true)][string]$archivePath,
- [Parameter(Mandatory=$true)][string]$destinationDir)
-{
- vcpkgRemoveItem $destinationDir
- $destinationPartial = "$destinationDir.partial"
- vcpkgRemoveItem $destinationPartial
- vcpkgCreateDirectoryIfNotExists $destinationPartial
-
-
- if (vcpkgHasCommand -commandName 'Microsoft.PowerShell.Archive\Expand-Archive')
- {
- Write-Verbose("Extracting with Microsoft.PowerShell.Archive\Expand-Archive")
- Microsoft.PowerShell.Archive\Expand-Archive -path $archivePath -destinationpath $destinationPartial
- }
- elseif (vcpkgHasCommand -commandName 'Pscx\Expand-Archive')
- {
- Write-Verbose("Extracting with Pscx\Expand-Archive")
- Pscx\Expand-Archive -path $archivePath -OutputPath $destinationPartial
- }
- else
- {
- Write-Verbose("Extracting via shell")
- $shell = new-object -com shell.application
- $zip = $shell.NameSpace($(Get-Item $archivePath).fullname)
- foreach($item in $zip.items())
- {
- # Piping to Out-Null is used to block until finished
- $shell.Namespace($destinationPartial).copyhere($item) | Out-Null
- }
- }
-
- Rename-Item -Path "$destinationPartial" -NewName $destinationDir
-}
-
-function vcpkgInvokeCommand()
-{
- param ( [Parameter(Mandatory=$true)][string]$executable,
- [string]$arguments = "")
-
- Write-Verbose "Executing: ${executable} ${arguments}"
- $process = Start-Process -FilePath "`"$executable`"" -ArgumentList $arguments -PassThru -NoNewWindow
- Wait-Process -InputObject $process
- $ec = $process.ExitCode
- Write-Verbose "Execution terminated with exit code $ec."
- return $ec
-}
-
-function vcpkgInvokeCommandClean()
-{
- param ( [Parameter(Mandatory=$true)][string]$executable,
- [string]$arguments = "")
-
- Write-Verbose "Clean-Executing: ${executable} ${arguments}"
- $scriptsDir = split-path -parent $script:MyInvocation.MyCommand.Definition
- $cleanEnvScript = "$scriptsDir\VcpkgPowershellUtils-ClearEnvironment.ps1"
- $tripleQuotes = "`"`"`""
- $argumentsWithEscapedQuotes = $arguments -replace "`"", $tripleQuotes
- $command = ". $tripleQuotes$cleanEnvScript$tripleQuotes; & $tripleQuotes$executable$tripleQuotes $argumentsWithEscapedQuotes"
- $arg = "-NoProfile", "-ExecutionPolicy Bypass", "-command $command"
-
- $process = Start-Process -FilePath powershell.exe -ArgumentList $arg -PassThru -NoNewWindow
- Wait-Process -InputObject $process
- $ec = $process.ExitCode
- Write-Verbose "Execution terminated with exit code $ec."
- return $ec
-}
-
-function vcpkgFormatElapsedTime([TimeSpan]$ts)
-{
- if ($ts.TotalHours -ge 1)
- {
- return [string]::Format( "{0:N2} h", $ts.TotalHours);
- }
-
- if ($ts.TotalMinutes -ge 1)
- {
- return [string]::Format( "{0:N2} min", $ts.TotalMinutes);
- }
-
- if ($ts.TotalSeconds -ge 1)
- {
- return [string]::Format( "{0:N2} s", $ts.TotalSeconds);
- }
-
- if ($ts.TotalMilliseconds -ge 1)
- {
- return [string]::Format( "{0:N2} ms", $ts.TotalMilliseconds);
- }
-
- throw $ts
-}
-
-function vcpkgFindFileRecursivelyUp()
-{
- param(
- [ValidateNotNullOrEmpty()]
- [Parameter(Mandatory=$true)][string]$startingDir,
- [ValidateNotNullOrEmpty()]
- [Parameter(Mandatory=$true)][string]$filename
- )
-
- $currentDir = $startingDir
-
- while (!($currentDir -eq "") -and !(Test-Path "$currentDir\$filename"))
- {
- Write-Verbose "Examining $currentDir for $filename"
- $currentDir = Split-path $currentDir -Parent
- }
- Write-Verbose "Examining $currentDir for $filename - Found"
- return $currentDir
-}
+ return $out
+} \ No newline at end of file
diff --git a/scripts/addPoshVcpkgToPowershellProfile.ps1 b/scripts/addPoshVcpkgToPowershellProfile.ps1
index dcbd2e0be..5c13a8d4a 100644
--- a/scripts/addPoshVcpkgToPowershellProfile.ps1
+++ b/scripts/addPoshVcpkgToPowershellProfile.ps1
@@ -18,10 +18,10 @@ $scriptsDir = split-path -parent $script:MyInvocation.MyCommand.Definition
$profileEntry = "Import-Module '$scriptsDir\posh-vcpkg'"
$profilePath = $PROFILE # Implicit powershell variable
-if (!(Test-Path $profilePath))
+$profileDir = Split-Path $profilePath -Parent
+if (!(Test-Path $profileDir))
{
- $profileDir = Split-Path $profilePath -Parent
- vcpkgCreateDirectoryIfNotExists $profileDir
+ New-Item -ItemType Directory -Path $profileDir | Out-Null
}
Write-Host "`nAdding the following line to ${profilePath}:"
@@ -38,6 +38,7 @@ if ($existingImports.Count -gt 0)
return
}
+# Modifying the profile will invalidate any signatures.
# Posh-git does the following check, so we should too.
# https://github.com/dahlbyk/posh-git/blob/master/src/Utils.ps1
# If the profile script exists and is signed, then we should not modify it
diff --git a/scripts/bootstrap.ps1 b/scripts/bootstrap.ps1
index c8ba503d8..41ba25746 100644
--- a/scripts/bootstrap.ps1
+++ b/scripts/bootstrap.ps1
@@ -5,35 +5,18 @@ param(
)
Set-StrictMode -Version Latest
$scriptsDir = split-path -parent $script:MyInvocation.MyCommand.Definition
-. "$scriptsDir\VcpkgPowershellUtils.ps1"
-$vcpkgRootDir = vcpkgFindFileRecursivelyUp $scriptsDir .vcpkg-root
-Write-Verbose("vcpkg Path " + $vcpkgRootDir)
-$gitHash = "unknownhash"
-$oldpath = $env:path
-try
-{
- [xml]$asXml = Get-Content "$scriptsDir\vcpkgTools.xml"
- $toolData = $asXml.SelectSingleNode("//tools/tool[@name=`"git`"]")
- $gitFromDownload = "$vcpkgRootDir\downloads\$($toolData.exeRelativePath)"
- $gitDir = split-path -parent $gitFromDownload
+$vcpkgRootDir = $scriptsDir
+$withVSPath = $withVSPath -replace "\\$" # Remove potential trailing backslash
- $env:path += ";$gitDir"
- if (Get-Command "git" -ErrorAction SilentlyContinue)
- {
- $gitHash = git log HEAD -n 1 --format="%cd-%H" --date=short
- if ($LASTEXITCODE -ne 0)
- {
- $gitHash = "unknownhash"
- }
- }
-}
-finally
+while (!($vcpkgRootDir -eq "") -and !(Test-Path "$vcpkgRootDir\.vcpkg-root"))
{
- $env:path = $oldpath
+ Write-Verbose "Examining $vcpkgRootDir for .vcpkg-root"
+ $vcpkgRootDir = Split-path $vcpkgRootDir -Parent
}
-Write-Verbose("Git repo version string is " + $gitHash)
+Write-Verbose "Examining $vcpkgRootDir for .vcpkg-root - Found"
+$gitHash = "nohash"
$vcpkgSourcesPath = "$vcpkgRootDir\toolsrc"
if (!(Test-Path $vcpkgSourcesPath))
@@ -42,7 +25,58 @@ if (!(Test-Path $vcpkgSourcesPath))
return
}
-$msbuildExeWithPlatformToolset = & $scriptsDir\findAnyMSBuildWithCppPlatformToolset.ps1 $withVSPath
+function findAnyMSBuildWithCppPlatformToolset([string]$withVSPath)
+{
+ $VisualStudioInstances = & $scriptsDir\getVisualStudioInstances.ps1
+ if ($VisualStudioInstances -eq $null)
+ {
+ throw "Could not find Visual Studio. VS2015 or VS2017 (with C++) needs to be installed."
+ }
+
+ Write-Verbose "VS Candidates:`n`r$([system.String]::Join([Environment]::NewLine, $VisualStudioInstances))"
+ foreach ($instanceCandidateWithEOL in $VisualStudioInstances)
+ {
+ $instanceCandidate = $instanceCandidateWithEOL -replace "<sol>::" -replace "::<eol>"
+ Write-Verbose "Inspecting: $instanceCandidate"
+ $split = $instanceCandidate -split "::"
+ # $preferenceWeight = $split[0]
+ # $releaseType = $split[1]
+ $version = $split[2]
+ $path = $split[3]
+
+ if ($withVSPath -ne "" -and $withVSPath -ne $path)
+ {
+ Write-Verbose "Skipping: $instanceCandidate"
+ continue
+ }
+
+ $majorVersion = $version.Substring(0,2);
+ if ($majorVersion -eq "15")
+ {
+ $VCFolder= "$path\VC\Tools\MSVC\"
+ if (Test-Path $VCFolder)
+ {
+ Write-Verbose "Picking: $instanceCandidate"
+ return "$path\MSBuild\15.0\Bin\MSBuild.exe", "v141"
+ }
+ }
+
+ if ($majorVersion -eq "14")
+ {
+ $clExe= "$path\VC\bin\cl.exe"
+ if (Test-Path $clExe)
+ {
+ Write-Verbose "Picking: $instanceCandidate"
+ $programFilesPath = getProgramFiles32bit
+ return "$programFilesPath\MSBuild\14.0\Bin\MSBuild.exe", "v140"
+ }
+ }
+ }
+
+ throw "Could not find MSBuild version with C++ support. VS2015 or VS2017 (with C++) needs to be installed."
+}
+
+$msbuildExeWithPlatformToolset = findAnyMSBuildWithCppPlatformToolset $withVSPath
$msbuildExe = $msbuildExeWithPlatformToolset[0]
$platformToolset = $msbuildExeWithPlatformToolset[1]
$windowsSDK = & $scriptsDir\getWindowsSDK.ps1
@@ -54,10 +88,33 @@ $arguments = (
"/p:Platform=x86",
"/p:PlatformToolset=$platformToolset",
"/p:TargetPlatformVersion=$windowsSDK",
+"/verbosity:minimal",
"/m",
+"/nologo",
"`"$vcpkgSourcesPath\dirs.proj`"") -join " "
+function vcpkgInvokeCommandClean()
+{
+ param ( [Parameter(Mandatory=$true)][string]$executable,
+ [string]$arguments = "")
+
+ Write-Verbose "Clean-Executing: ${executable} ${arguments}"
+ $scriptsDir = split-path -parent $script:MyInvocation.MyCommand.Definition
+ $cleanEnvScript = "$scriptsDir\VcpkgPowershellUtils-ClearEnvironment.ps1"
+ $tripleQuotes = "`"`"`""
+ $argumentsWithEscapedQuotes = $arguments -replace "`"", $tripleQuotes
+ $command = ". $tripleQuotes$cleanEnvScript$tripleQuotes; & $tripleQuotes$executable$tripleQuotes $argumentsWithEscapedQuotes"
+ $arg = "-NoProfile", "-ExecutionPolicy Bypass", "-command $command"
+
+ $process = Start-Process -FilePath powershell.exe -ArgumentList $arg -PassThru -NoNewWindow
+ Wait-Process -InputObject $process
+ $ec = $process.ExitCode
+ Write-Verbose "Execution terminated with exit code $ec."
+ return $ec
+}
+
# vcpkgInvokeCommandClean cmd "/c echo %PATH%"
+Write-Host "`nBuilding vcpkg.exe ...`n"
$ec = vcpkgInvokeCommandClean $msbuildExe $arguments
if ($ec -ne 0)
@@ -65,6 +122,7 @@ if ($ec -ne 0)
Write-Error "Building vcpkg.exe failed. Please ensure you have installed Visual Studio with the Desktop C++ workload and the Windows SDK for Desktop C++."
return
}
+Write-Host "`nBuilding vcpkg.exe... done.`n"
Write-Verbose("Placing vcpkg.exe in the correct location")
diff --git a/scripts/fetchTool.ps1 b/scripts/fetchTool.ps1
deleted file mode 100644
index eca405b62..000000000
--- a/scripts/fetchTool.ps1
+++ /dev/null
@@ -1,109 +0,0 @@
-[CmdletBinding()]
-param(
- [Parameter(Mandatory=$true)][string]$tool
-)
-
-Set-StrictMode -Version Latest
-
-$scriptsDir = split-path -parent $script:MyInvocation.MyCommand.Definition
-. "$scriptsDir\VcpkgPowershellUtils.ps1"
-
-Write-Verbose "Fetching tool: $tool"
-$vcpkgRootDir = vcpkgFindFileRecursivelyUp $scriptsDir .vcpkg-root
-
-$downloadsDir = "$vcpkgRootDir\downloads"
-vcpkgCreateDirectoryIfNotExists $downloadsDir
-$downloadsDir = Resolve-Path $downloadsDir
-
-function fetchToolInternal([Parameter(Mandatory=$true)][string]$tool)
-{
- $tool = $tool.toLower()
-
- [xml]$asXml = Get-Content "$scriptsDir\vcpkgTools.xml"
- $toolData = $asXml.SelectSingleNode("//tools/tool[@name=`"$tool`"]") # Case-sensitive!
-
- if ($toolData -eq $null)
- {
- throw "Unknown tool $tool"
- }
-
- $toolPath="$downloadsDir\tools\$tool-$($toolData.version)-windows"
- $exePath = "$toolPath\$($toolData.exeRelativePath)"
-
- if (Test-Path $exePath)
- {
- return $exePath
- }
-
- $isArchive = vcpkgHasProperty -object $toolData -propertyName "archiveName"
- if ($isArchive)
- {
- $downloadPath = "$downloadsDir\$($toolData.archiveName)"
- }
- else
- {
- $downloadPath = "$toolPath\$($toolData.exeRelativePath)"
- }
-
- [String]$url = $toolData.url
- if (!(Test-Path $downloadPath))
- {
- Write-Host "Downloading $tool..."
-
- # Download aria2 with .NET. aria2 will be used to download everything else.
- if ($tool -eq "aria2")
- {
- vcpkgDownloadFile $url $downloadPath $toolData.sha512
- }
- else
- {
- $aria2exe = fetchToolInternal "aria2"
- vcpkgDownloadFileWithAria2 $aria2exe $url $downloadPath $toolData.sha512
- }
-
- Write-Host "Downloading $tool... done."
- }
- else
- {
- vcpkgCheckEqualFileHash -url $url -filePath $downloadPath -expectedHash $toolData.sha512
- }
-
- if ($isArchive)
- {
- Write-Host "Extracting $tool..."
- # Extract 7zip920 with shell because we need it to extract 7zip
- # Extract aria2 with shell because we need it to download 7zip
- if ($tool -eq "7zip920" -or $tool -eq "aria2")
- {
- vcpkgExtractZipFile -ArchivePath $downloadPath -DestinationDir $toolPath
- }
- elseif ($tool -eq "7zip")
- {
- $sevenZip920 = fetchToolInternal "7zip920"
- $ec = vcpkgInvokeCommand "$sevenZip920" "x `"$downloadPath`" -o`"$toolPath`" -y"
- if ($ec -ne 0)
- {
- Write-Host "Could not extract $downloadPath"
- throw
- }
- }
- else
- {
- $sevenZipExe = fetchToolInternal "7zip"
- vcpkgExtractFileWith7z -sevenZipExe "$sevenZipExe" -ArchivePath $downloadPath -DestinationDir $toolPath
- }
- Write-Host "Extracting $tool... done."
- }
-
- if (-not (Test-Path $exePath))
- {
- Write-Error "Could not detect or download $tool"
- throw
- }
-
- return $exePath
-}
-
-$path = fetchToolInternal $tool
-Write-Verbose "Fetching tool: $tool. Done."
-return "<sol>::$path::<eol>"
diff --git a/scripts/findAnyMSBuildWithCppPlatformToolset.ps1 b/scripts/findAnyMSBuildWithCppPlatformToolset.ps1
deleted file mode 100644
index d7fd24e24..000000000
--- a/scripts/findAnyMSBuildWithCppPlatformToolset.ps1
+++ /dev/null
@@ -1,58 +0,0 @@
-[CmdletBinding()]
-param(
- [Parameter(Mandatory=$False)]
- [string]$withVSPath = ""
-)
-
-Set-StrictMode -Version Latest
-$scriptsDir = split-path -parent $script:MyInvocation.MyCommand.Definition
-
-$withVSPath = $withVSPath -replace "\\$" # Remove potential trailing backslash
-
-$VisualStudioInstallationInstances = & $scriptsDir\findVisualStudioInstallationInstances.ps1
-if ($VisualStudioInstallationInstances -eq $null)
-{
- throw "Could not find Visual Studio. VS2015 or VS2017 (with C++) needs to be installed."
-}
-
-Write-Verbose "VS Candidates:`n`r$([system.String]::Join([Environment]::NewLine, $VisualStudioInstallationInstances))"
-foreach ($instanceCandidateWithEOL in $VisualStudioInstallationInstances)
-{
- $instanceCandidate = $instanceCandidateWithEOL -replace "<sol>::" -replace "::<eol>"
- Write-Verbose "Inspecting: $instanceCandidate"
- $split = $instanceCandidate -split "::"
- # $preferenceWeight = $split[0]
- # $releaseType = $split[1]
- $version = $split[2]
- $path = $split[3]
-
- if ($withVSPath -ne "" -and $withVSPath -ne $path)
- {
- Write-Verbose "Skipping: $instanceCandidate"
- continue
- }
-
- $majorVersion = $version.Substring(0,2);
- if ($majorVersion -eq "15")
- {
- $VCFolder= "$path\VC\Tools\MSVC\"
- if (Test-Path $VCFolder)
- {
- Write-Verbose "Picking: $instanceCandidate"
- return "$path\MSBuild\15.0\Bin\MSBuild.exe", "v141"
- }
- }
-
- if ($majorVersion -eq "14")
- {
- $clExe= "$path\VC\bin\cl.exe"
- if (Test-Path $clExe)
- {
- Write-Verbose "Picking: $instanceCandidate"
- $programFilesPath = & $scriptsDir\getProgramFiles32bit.ps1
- return "$programFilesPath\MSBuild\14.0\Bin\MSBuild.exe", "v140"
- }
- }
-}
-
-throw "Could not find MSBuild version with C++ support. VS2015 or VS2017 (with C++) needs to be installed." \ No newline at end of file
diff --git a/scripts/findVisualStudioInstallationInstances.ps1 b/scripts/findVisualStudioInstallationInstances.ps1
deleted file mode 100644
index cb51c345d..000000000
--- a/scripts/findVisualStudioInstallationInstances.ps1
+++ /dev/null
@@ -1,61 +0,0 @@
-[CmdletBinding()]
-param(
-
-)
-Set-StrictMode -Version Latest
-$scriptsDir = split-path -parent $script:MyInvocation.MyCommand.Definition
-. "$scriptsDir\VcpkgPowershellUtils.ps1"
-
-$vswhereExe = (& $scriptsDir\fetchTool.ps1 "vswhere") -replace "<sol>::" -replace "::<eol>"
-
-$output = & $vswhereExe -prerelease -legacy -products * -format xml
-[xml]$asXml = $output
-
-$results = New-Object System.Collections.ArrayList
-foreach ($instance in $asXml.instances.instance)
-{
- $installationPath = $instance.InstallationPath -replace "\\$" # Remove potential trailing backslash
- $installationVersion = $instance.InstallationVersion
-
- $isPrerelease = -7
- if (vcpkgHasProperty -object $instance -propertyName "isPrerelease")
- {
- $isPrerelease = $instance.isPrerelease
- }
-
- if ($isPrerelease -eq 0)
- {
- $releaseType = "PreferenceWeight3::StableRelease"
- }
- elseif ($isPrerelease -eq 1)
- {
- $releaseType = "PreferenceWeight2::PreRelease"
- }
- else
- {
- $releaseType = "PreferenceWeight1::Legacy"
- }
-
- # Placed like that for easy sorting according to preference
- $results.Add("<sol>::${releaseType}::${installationVersion}::${installationPath}::<eol>") > $null
-}
-
-# If nothing is found, attempt to find VS2015 Build Tools (not detected by vswhere.exe)
-if ($results.Count -eq 0)
-{
- $programFiles = & $scriptsDir\getProgramFiles32bit.ps1
- $installationPath = "$programFiles\Microsoft Visual Studio 14.0"
- $clExe = "$installationPath\VC\bin\cl.exe"
- $vcvarsallbat = "$installationPath\VC\vcvarsall.bat"
-
- if ((Test-Path $clExe) -And (Test-Path $vcvarsallbat))
- {
- return "<sol>::PreferenceWeight1::Legacy::14.0::$installationPath::<eol>"
- }
-}
-
-
-$results.Sort()
-$results.Reverse()
-
-return $results \ No newline at end of file
diff --git a/scripts/getProgramFiles32bit.ps1 b/scripts/getProgramFiles32bit.ps1
deleted file mode 100644
index 6b71915b1..000000000
--- a/scripts/getProgramFiles32bit.ps1
+++ /dev/null
@@ -1,17 +0,0 @@
-[CmdletBinding()]
-param(
-
-)
-
-$out = ${env:PROGRAMFILES(X86)}
-if ($out -eq $null)
-{
- $out = ${env:PROGRAMFILES}
-}
-
-if ($out -eq $null)
-{
- throw "Could not find [Program Files 32-bit]"
-}
-
-return $out \ No newline at end of file
diff --git a/scripts/getProgramFilesPlatformBitness.ps1 b/scripts/getProgramFilesPlatformBitness.ps1
deleted file mode 100644
index 2be4c1137..000000000
--- a/scripts/getProgramFilesPlatformBitness.ps1
+++ /dev/null
@@ -1,17 +0,0 @@
-[CmdletBinding()]
-param(
-
-)
-
-$out = ${env:ProgramW6432}
-if ($out -eq $null)
-{
- $out = ${env:PROGRAMFILES}
-}
-
-if ($out -eq $null)
-{
- throw "Could not find [Program Files Platform Bitness]"
-}
-
-return $out \ No newline at end of file
diff --git a/scripts/getVisualStudioInstances.ps1 b/scripts/getVisualStudioInstances.ps1
new file mode 100644
index 000000000..83b0b8ebd
--- /dev/null
+++ b/scripts/getVisualStudioInstances.ps1
@@ -0,0 +1,74 @@
+[CmdletBinding()]
+param(
+
+)
+Set-StrictMode -Version Latest
+$scriptsDir = split-path -parent $script:MyInvocation.MyCommand.Definition
+. "$scriptsDir\VcpkgPowershellUtils.ps1"
+
+$programFiles = getProgramFiles32bit
+
+$results = New-Object System.Collections.ArrayList
+
+$vswhereExe = "$programFiles\Microsoft Visual Studio\Installer\vswhere.exe"
+
+if (Test-Path $vswhereExe)
+{
+ $output = & $vswhereExe -prerelease -legacy -products * -format xml
+ [xml]$asXml = $output
+
+ foreach ($instance in $asXml.instances.instance)
+ {
+ $installationPath = $instance.InstallationPath -replace "\\$" # Remove potential trailing backslash
+ $installationVersion = $instance.InstallationVersion
+
+ $isPrerelease = -7
+ if (vcpkgHasProperty -object $instance -propertyName "isPrerelease")
+ {
+ $isPrerelease = $instance.isPrerelease
+ }
+
+ if ($isPrerelease -eq 0)
+ {
+ $releaseType = "PreferenceWeight3::StableRelease"
+ }
+ elseif ($isPrerelease -eq 1)
+ {
+ $releaseType = "PreferenceWeight2::PreRelease"
+ }
+ else
+ {
+ $releaseType = "PreferenceWeight1::Legacy"
+ }
+
+ # Placed like that for easy sorting according to preference
+ $results.Add("<sol>::${releaseType}::${installationVersion}::${installationPath}::<eol>") > $null
+ }
+}
+else
+{
+ Write-Verbose "Could not locate vswhere at $vswhereExe"
+}
+
+$installationPath = Split-Path -Parent $(Split-Path -Parent "$env:vs140comntools")
+$clExe = "$installationPath\VC\bin\cl.exe"
+$vcvarsallbat = "$installationPath\VC\vcvarsall.bat"
+
+if ((Test-Path $clExe) -And (Test-Path $vcvarsallbat))
+{
+ $results.Add("<sol>::PreferenceWeight1::Legacy::14.0::$installationPath::<eol>") > $null
+}
+
+$installationPath = "$programFiles\Microsoft Visual Studio 14.0"
+$clExe = "$installationPath\VC\bin\cl.exe"
+$vcvarsallbat = "$installationPath\VC\vcvarsall.bat"
+
+if ((Test-Path $clExe) -And (Test-Path $vcvarsallbat))
+{
+ $results.Add("<sol>::PreferenceWeight1::Legacy::14.0::$installationPath::<eol>") > $null
+}
+
+$results.Sort()
+$results.Reverse()
+
+return $results
diff --git a/scripts/vcpkgTools.xml b/scripts/vcpkgTools.xml
index 1f17102d2..9d5487577 100644
--- a/scripts/vcpkgTools.xml
+++ b/scripts/vcpkgTools.xml
@@ -61,17 +61,10 @@
</tool>
<tool name="7zip" os="windows">
<version>18.01.0</version>
- <exeRelativePath>7za.exe</exeRelativePath>
- <url>https://www.7-zip.org/a/7z1801-extra.7z</url>
- <sha512>9133fc551d76515e37fdd4dd8c1e28d464aea493548246b44565a42bba46715764f41f9cfa14d470d298c3a6e9829d200f8be5168cb67cf8f23d8042fca833bc</sha512>
- <archiveName>7z1801-extra.7z</archiveName>
- </tool>
- <tool name="7zip920" os="windows">
- <version>9.20.0</version>
- <exeRelativePath>7za.exe</exeRelativePath>
- <url>https://www.7-zip.org/a/7za920.zip</url>
- <sha512>84e830c91a0e8ae499cc4814080da6569d8a6acbddc585c8b62abc86c809793aeb669b0a741063a379fd281ade85f120bc27efeb67d63bf961be893eec8bc3b3</sha512>
- <archiveName>7za920.zip</archiveName>
+ <exeRelativePath>7-Zip.CommandLine.18.1.0\tools\7za.exe</exeRelativePath>
+ <url>https://www.nuget.org/api/v2/package/7-Zip.CommandLine/18.1.0</url>
+ <sha512>8c75314102e68d2b2347d592f8e3eb05812e1ebb525decbac472231633753f1d4ca31c8e6881a36144a8da26b2571305b3ae3f4e2b85fc4a290aeda63d1a13b8</sha512>
+ <archiveName>7-zip.commandline.18.1.0.nupkg</archiveName>
</tool>
<tool name="aria2" os="windows">
<version>18.01.0</version>
diff --git a/toolsrc/include/vcpkg/base/system.h b/toolsrc/include/vcpkg/base/system.h
index 0d089276f..cf9c78868 100644
--- a/toolsrc/include/vcpkg/base/system.h
+++ b/toolsrc/include/vcpkg/base/system.h
@@ -47,6 +47,7 @@ namespace vcpkg::System
ExitCodeAndOutput cmd_execute_and_capture_output(const CStringView cmd_line);
+#if defined(_WIN32)
void powershell_execute(const std::string& title,
const fs::path& script_path,
const std::vector<PowershellParameter>& parameters = {});
@@ -54,6 +55,7 @@ namespace vcpkg::System
std::string powershell_execute_and_capture_output(const std::string& title,
const fs::path& script_path,
const std::vector<PowershellParameter>& parameters = {});
+#endif
enum class Color
{
diff --git a/toolsrc/include/vcpkg/commands.h b/toolsrc/include/vcpkg/commands.h
index 6d29b7960..708151dce 100644
--- a/toolsrc/include/vcpkg/commands.h
+++ b/toolsrc/include/vcpkg/commands.h
@@ -132,14 +132,14 @@ namespace vcpkg::Commands
namespace Hash
{
std::string get_string_hash(const std::string& s, const std::string& hash_type);
- std::string get_file_hash(const VcpkgPaths& paths, const fs::path& path, const std::string& hash_type);
+ std::string get_file_hash(const Files::Filesystem& fs, const fs::path& path, const std::string& hash_type);
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths);
}
namespace Fetch
{
- std::vector<Toolset> find_toolset_instances(const VcpkgPaths& paths);
+ std::vector<Toolset> find_toolset_instances_prefered_first(const VcpkgPaths& paths);
fs::path get_tool_path(const VcpkgPaths& paths, const std::string& tool);
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths);
}
diff --git a/toolsrc/include/vcpkg/vcpkgpaths.h b/toolsrc/include/vcpkg/vcpkgpaths.h
index 9c8f2911a..a3c90fd33 100644
--- a/toolsrc/include/vcpkg/vcpkgpaths.h
+++ b/toolsrc/include/vcpkg/vcpkgpaths.h
@@ -66,6 +66,7 @@ namespace vcpkg
fs::path triplets;
fs::path scripts;
+ fs::path tools;
fs::path buildsystems;
fs::path buildsystems_msbuild_targets;
diff --git a/toolsrc/src/vcpkg/base/checks.cpp b/toolsrc/src/vcpkg/base/checks.cpp
index d96cb98ff..2ac5f9a15 100644
--- a/toolsrc/src/vcpkg/base/checks.cpp
+++ b/toolsrc/src/vcpkg/base/checks.cpp
@@ -16,6 +16,8 @@ namespace vcpkg::Checks
const auto elapsed_us = GlobalState::timer.lock()->microseconds();
+ Debug::println("Exiting after %d us", static_cast<int>(elapsed_us));
+
auto metrics = Metrics::g_metrics.lock();
metrics->track_metric("elapsed_us", elapsed_us);
GlobalState::debugging = false;
diff --git a/toolsrc/src/vcpkg/base/system.cpp b/toolsrc/src/vcpkg/base/system.cpp
index 95c9511f9..4da4548af 100644
--- a/toolsrc/src/vcpkg/base/system.cpp
+++ b/toolsrc/src/vcpkg/base/system.cpp
@@ -155,6 +155,7 @@ namespace vcpkg::System
int cmd_execute_clean(const CStringView cmd_line, const std::unordered_map<std::string, std::string>& extra_env)
{
+ auto timer = Chrono::ElapsedTimer::create_started();
#if defined(_WIN32)
static const std::string SYSTEM_ROOT = get_environment_variable("SystemRoot").value_or_exit(VCPKG_LINE_INFO);
static const std::string SYSTEM_32 = SYSTEM_ROOT + R"(\system32)";
@@ -271,7 +272,7 @@ namespace vcpkg::System
DWORD exit_code = 0;
GetExitCodeProcess(process_info.hProcess, &exit_code);
- Debug::println("CreateProcessW() returned %lu", exit_code);
+ Debug::println("CreateProcessW() returned %lu after %d us", exit_code, static_cast<int>(timer.microseconds()));
return static_cast<int>(exit_code);
#else
Debug::println("system(%s)", cmd_line.c_str());
@@ -369,13 +370,20 @@ namespace vcpkg::System
#endif
}
+#if defined(_WIN32)
void powershell_execute(const std::string& title,
const fs::path& script_path,
const std::vector<PowershellParameter>& parameters)
{
+ SetConsoleCP(437);
+ SetConsoleOutputCP(437);
+
const std::string cmd = make_powershell_cmd(script_path, parameters);
const int rc = System::cmd_execute(cmd);
+ SetConsoleCP(CP_UTF8);
+ SetConsoleOutputCP(CP_UTF8);
+
if (rc)
{
System::println(Color::error,
@@ -394,14 +402,22 @@ namespace vcpkg::System
Checks::exit_with_code(VCPKG_LINE_INFO, rc);
}
}
+#endif
+#if defined(_WIN32)
std::string powershell_execute_and_capture_output(const std::string& title,
const fs::path& script_path,
const std::vector<PowershellParameter>& parameters)
{
+ SetConsoleCP(437);
+ SetConsoleOutputCP(437);
+
const std::string cmd = make_powershell_cmd(script_path, parameters);
auto rc = System::cmd_execute_and_capture_output(cmd);
+ SetConsoleCP(CP_UTF8);
+ SetConsoleOutputCP(CP_UTF8);
+
if (rc.exit_code)
{
System::println(Color::error,
@@ -433,6 +449,7 @@ namespace vcpkg::System
return rc.output;
}
+#endif
void println() { putchar('\n'); }
diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp
index 1ed5e744a..b8ccb15bf 100644
--- a/toolsrc/src/vcpkg/build.cpp
+++ b/toolsrc/src/vcpkg/build.cpp
@@ -461,9 +461,9 @@ namespace vcpkg::Build
abi_tag_entries.insert(abi_tag_entries.end(), dependency_abis.begin(), dependency_abis.end());
abi_tag_entries.emplace_back(
- AbiEntry{"portfile", Commands::Hash::get_file_hash(paths, config.port_dir / "portfile.cmake", "SHA1")});
+ AbiEntry{"portfile", Commands::Hash::get_file_hash(fs, config.port_dir / "portfile.cmake", "SHA1")});
abi_tag_entries.emplace_back(
- AbiEntry{"control", Commands::Hash::get_file_hash(paths, config.port_dir / "CONTROL", "SHA1")});
+ AbiEntry{"control", Commands::Hash::get_file_hash(fs, config.port_dir / "CONTROL", "SHA1")});
abi_tag_entries.emplace_back(AbiEntry{"triplet", pre_build_info.triplet_abi_tag});
@@ -498,7 +498,7 @@ namespace vcpkg::Build
const auto abi_file_path = paths.buildtrees / name / (triplet.canonical_name() + ".vcpkg_abi_info.txt");
fs.write_contents(abi_file_path, full_abi_info);
- return AbiTagAndFile{Commands::Hash::get_file_hash(paths, abi_file_path, "SHA1"), abi_file_path};
+ return AbiTagAndFile{Commands::Hash::get_file_hash(fs, abi_file_path, "SHA1"), abi_file_path};
}
System::println(
@@ -783,14 +783,12 @@ namespace vcpkg::Build
{
return it_hash->second;
}
- auto hash = Commands::Hash::get_file_hash(paths, triplet_file_path, "SHA1");
+ auto hash = Commands::Hash::get_file_hash(paths.get_filesystem(), triplet_file_path, "SHA1");
s_hash_cache.emplace(triplet_file_path, hash);
return hash;
}
- else
- {
- return std::string();
- }
+
+ return std::string();
}();
const auto cmd_launch_cmake = System::make_cmake_cmd(cmake_exe_path,
diff --git a/toolsrc/src/vcpkg/commands.cpp b/toolsrc/src/vcpkg/commands.cpp
index 8b6ffb3d7..09da57705 100644
--- a/toolsrc/src/vcpkg/commands.cpp
+++ b/toolsrc/src/vcpkg/commands.cpp
@@ -43,7 +43,7 @@ namespace vcpkg::Commands
{"portsdiff", &PortsDiff::perform_and_exit},
{"autocomplete", &Autocomplete::perform_and_exit},
{"hash", &Hash::perform_and_exit},
- // {"fetch", &Fetch::perform_and_exit},
+ {"fetch", &Fetch::perform_and_exit},
};
return t;
}
diff --git a/toolsrc/src/vcpkg/commands.fetch.cpp b/toolsrc/src/vcpkg/commands.fetch.cpp
index a6cfec3f0..d50d13c59 100644
--- a/toolsrc/src/vcpkg/commands.fetch.cpp
+++ b/toolsrc/src/vcpkg/commands.fetch.cpp
@@ -1,6 +1,7 @@
#include "pch.h"
#include <vcpkg/base/checks.h>
+#include <vcpkg/base/sortedvector.h>
#include <vcpkg/base/strings.h>
#include <vcpkg/base/system.h>
#include <vcpkg/base/util.h>
@@ -19,6 +20,7 @@ namespace vcpkg::Commands::Fetch
fs::path exe_path;
std::string url;
fs::path download_path;
+ bool is_archive;
fs::path tool_dir_path;
std::string sha512;
};
@@ -41,20 +43,85 @@ namespace vcpkg::Commands::Fetch
return result;
}
- static Optional<std::string> extract_string_between_delimiters(const std::string& input,
- const std::string& left_delim,
- const std::string& right_delim,
- const size_t& starting_offset = 0)
+ struct VcpkgStringRange
{
- const size_t from = input.find(left_delim, starting_offset);
- if (from == std::string::npos) return nullopt;
+ VcpkgStringRange() = default;
- const size_t substring_start = from + left_delim.length();
+ // Implicit by design
+ VcpkgStringRange(const std::string& s) : begin(s.cbegin()), end(s.cend()) {}
- const size_t to = input.find(right_delim, substring_start);
- if (from == std::string::npos) return nullopt;
+ VcpkgStringRange(const std::string::const_iterator begin, const std::string::const_iterator end)
+ : begin(begin), end(end)
+ {
+ }
+
+ std::string::const_iterator begin;
+ std::string::const_iterator end;
+
+ std::string to_string() const { return std::string(this->begin, this->end); }
+ };
+
+ static std::vector<VcpkgStringRange> find_all_enclosed(const VcpkgStringRange& input,
+ const std::string& left_delim,
+ const std::string& right_delim)
+ {
+ std::string::const_iterator it_left = input.begin;
+ std::string::const_iterator it_right = input.begin;
+
+ std::vector<VcpkgStringRange> output;
- return input.substr(substring_start, to - substring_start);
+ while (true)
+ {
+ it_left = std::search(it_right, input.end, left_delim.cbegin(), left_delim.cend());
+ if (it_left == input.end) break;
+
+ it_left += left_delim.length();
+
+ it_right = std::search(it_left, input.end, right_delim.cbegin(), right_delim.cend());
+ if (it_right == input.end) break;
+
+ output.emplace_back(it_left, it_right);
+
+ ++it_right;
+ }
+
+ return output;
+ }
+
+ static VcpkgStringRange find_exactly_one_enclosed(const VcpkgStringRange& input,
+ const std::string& left_tag,
+ const std::string& right_tag)
+ {
+ std::vector<VcpkgStringRange> result = find_all_enclosed(input, left_tag, right_tag);
+ Checks::check_exit(VCPKG_LINE_INFO,
+ result.size() == 1,
+ "Found %d sets of %s.*%s but expected exactly 1, in block:\n%s",
+ result.size(),
+ left_tag,
+ right_tag,
+ input);
+ return std::move(result.front());
+ }
+
+ static Optional<VcpkgStringRange> find_at_most_one_enclosed(const VcpkgStringRange& input,
+ const std::string& left_tag,
+ const std::string& right_tag)
+ {
+ std::vector<VcpkgStringRange> result = find_all_enclosed(input, left_tag, right_tag);
+ Checks::check_exit(VCPKG_LINE_INFO,
+ result.size() <= 1,
+ "Found %d sets of %s.*%s but expected at most 1, in block:\n%s",
+ result.size(),
+ left_tag,
+ right_tag,
+ input);
+
+ if (result.empty())
+ {
+ return nullopt;
+ }
+
+ return result.front();
}
static ToolData parse_tool_data_from_xml(const VcpkgPaths& paths, const std::string& tool)
@@ -72,21 +139,6 @@ namespace vcpkg::Commands::Fetch
#if defined(_WIN32) || defined(__APPLE__) || defined(__linux__)
static const std::string XML_VERSION = "2";
static const fs::path XML_PATH = paths.scripts / "vcpkgTools.xml";
-
- const auto get_string_inside_tags =
- [](const std::string& input, const std::string& left_delim, const std::string& right_delim) -> std::string {
- Optional<std::string> result = extract_string_between_delimiters(input, left_delim, right_delim);
- Checks::check_exit(VCPKG_LINE_INFO,
- result.has_value(),
- "Could not find tag <%s>.*<%s> in %s",
- left_delim,
- right_delim,
- XML_PATH.generic_string());
-
- auto r = *result.get();
- return Strings::trim(std::move(r));
- };
-
static const std::regex XML_VERSION_REGEX{R"###(<tools[\s]+version="([^"]+)">)###"};
static const std::string XML = paths.get_filesystem().read_contents(XML_PATH).value_or_exit(VCPKG_LINE_INFO);
std::smatch match_xml_version;
@@ -112,14 +164,14 @@ namespace vcpkg::Commands::Fetch
tool,
XML_PATH.generic_string());
- const std::string tool_data = get_string_inside_tags(XML, match_tool_entry[0], R"(</tool>)");
-
- const std::string version_as_string = get_string_inside_tags(tool_data, "<version>", R"(</version>)");
+ const std::string tool_data = find_exactly_one_enclosed(XML, match_tool_entry[0], "</tool>").to_string();
+ const std::string version_as_string =
+ find_exactly_one_enclosed(tool_data, "<version>", "</version>").to_string();
const std::string exe_relative_path =
- get_string_inside_tags(tool_data, "<exeRelativePath>", R"(</exeRelativePath>)");
- const std::string url = get_string_inside_tags(tool_data, "<url>", R"(</url>)");
- const std::string sha512 = get_string_inside_tags(tool_data, "<sha512>", R"(</sha512>)");
- auto archive_name = extract_string_between_delimiters(tool_data, "<archiveName>", R"(</archiveName>)");
+ find_exactly_one_enclosed(tool_data, "<exeRelativePath>", "</exeRelativePath>").to_string();
+ const std::string url = find_exactly_one_enclosed(tool_data, "<url>", "</url>").to_string();
+ const std::string sha512 = find_exactly_one_enclosed(tool_data, "<sha512>", "</sha512>").to_string();
+ auto archive_name = find_at_most_one_enclosed(tool_data, "<archiveName>", "</archiveName>");
const Optional<std::array<int, 3>> version = parse_version_string(version_as_string);
Checks::check_exit(VCPKG_LINE_INFO,
@@ -129,13 +181,14 @@ namespace vcpkg::Commands::Fetch
version_as_string);
const std::string tool_dir_name = Strings::format("%s-%s-%s", tool, version_as_string, OS_STRING);
- const fs::path tool_dir_path = paths.downloads / "tools" / tool_dir_name;
+ const fs::path tool_dir_path = paths.tools / tool_dir_name;
const fs::path exe_path = tool_dir_path / exe_relative_path;
return ToolData{*version.get(),
exe_path,
url,
- paths.downloads / archive_name.value_or(exe_relative_path),
+ paths.downloads / archive_name.value_or(exe_relative_path).to_string(),
+ archive_name.has_value(),
tool_dir_path,
sha512};
#endif
@@ -163,51 +216,87 @@ namespace vcpkg::Commands::Fetch
actual_version[2] >= expected_version[2]));
}
- static Optional<fs::path> find_if_has_equal_or_greater_version(const std::vector<fs::path>& candidate_paths,
+ static Optional<fs::path> find_if_has_equal_or_greater_version(Files::Filesystem& fs,
+ const std::vector<fs::path>& candidate_paths,
const std::string& version_check_arguments,
const std::array<int, 3>& expected_version)
{
- auto it = Util::find_if(candidate_paths, [&](const fs::path& p) {
+ const auto it = Util::find_if(candidate_paths, [&](const fs::path& p) {
+ if (!fs.exists(p)) return false;
const std::string cmd = Strings::format(R"("%s" %s)", p.u8string(), version_check_arguments);
return exists_and_has_equal_or_greater_version(cmd, expected_version);
});
if (it != candidate_paths.cend())
{
- return std::move(*it);
+ return *it;
}
return nullopt;
}
- static std::vector<std::string> keep_data_lines(const std::string& data_blob)
- {
- static const std::regex DATA_LINE_REGEX(R"(<sol>::(.+?)(?=::<eol>))");
-
- std::vector<std::string> data_lines;
-
- const std::sregex_iterator it(data_blob.cbegin(), data_blob.cend(), DATA_LINE_REGEX);
- const std::sregex_iterator end;
- for (std::sregex_iterator i = it; i != end; ++i)
- {
- const std::smatch match = *i;
- data_lines.push_back(match[1].str());
- }
-
- return data_lines;
- }
-
-#if !defined(_WIN32)
static void extract_archive(const VcpkgPaths& paths, const fs::path& archive, const fs::path& to_path)
{
Files::Filesystem& fs = paths.get_filesystem();
const fs::path to_path_partial = to_path.u8string() + ".partial";
std::error_code ec;
+ fs.remove_all(to_path, ec);
fs.remove_all(to_path_partial, ec);
fs.create_directories(to_path_partial, ec);
-
const auto ext = archive.extension();
+#if defined(_WIN32)
+ if (ext == ".nupkg")
+ {
+ static bool recursion_limiter_sevenzip_old = false;
+ Checks::check_exit(VCPKG_LINE_INFO, !recursion_limiter_sevenzip_old);
+ recursion_limiter_sevenzip_old = true;
+ const auto nuget_exe = get_tool_path(paths, Tools::NUGET);
+
+ const std::string stem = archive.stem().u8string();
+ // assuming format of [name].[version in the form d.d.d]
+ // This assumption may not always hold
+ std::smatch match;
+ const bool has_match = std::regex_match(stem, match, std::regex{R"###(^(.+)\.(\d+\.\d+\.\d+)$)###"});
+ Checks::check_exit(VCPKG_LINE_INFO,
+ has_match,
+ "Could not deduce nuget id and version from filename: %s",
+ archive.u8string());
+
+ const std::string nugetid = match[1];
+ const std::string version = match[2];
+
+ const auto code_and_output = System::cmd_execute_and_capture_output(Strings::format(
+ R"("%s" install %s -Version %s -OutputDirectory "%s" -Source "%s" -nocache -DirectDownload -NonInteractive -ForceEnglishOutput -PackageSaveMode nuspec)",
+ nuget_exe.u8string(),
+ nugetid,
+ version,
+ to_path_partial.u8string(),
+ paths.downloads.u8string()));
+
+ Checks::check_exit(VCPKG_LINE_INFO,
+ code_and_output.exit_code == 0,
+ "Failed to extract '%s' with message:\n%s",
+ archive.u8string(),
+ code_and_output.output);
+ recursion_limiter_sevenzip_old = false;
+ }
+ else
+ {
+ static bool recursion_limiter_sevenzip = false;
+ Checks::check_exit(VCPKG_LINE_INFO, !recursion_limiter_sevenzip);
+ recursion_limiter_sevenzip = true;
+ const auto seven_zip = get_tool_path(paths, Tools::SEVEN_ZIP);
+ const auto code_and_output = System::cmd_execute_and_capture_output(Strings::format(
+ R"("%s" x "%s" -o"%s" -y)", seven_zip.u8string(), archive.u8string(), to_path_partial.u8string()));
+ Checks::check_exit(VCPKG_LINE_INFO,
+ code_and_output.exit_code == 0,
+ "7zip failed while extracting '%s' with message:\n%s",
+ archive.u8string(),
+ code_and_output.output);
+ recursion_limiter_sevenzip = false;
+ }
+#else
if (ext == ".gz" && ext.extension() != ".tar")
{
const auto code = System::cmd_execute(
@@ -224,16 +313,23 @@ namespace vcpkg::Commands::Fetch
{
Checks::exit_with_message(VCPKG_LINE_INFO, "Unexpected archive extension: %s", ext.u8string());
}
+#endif
- fs.rename(to_path_partial, to_path);
+ fs.rename(to_path_partial, to_path, ec);
+ Checks::check_exit(VCPKG_LINE_INFO,
+ !ec,
+ "Failed to do post-extract rename-in-place.\nfs.rename(%s, %s, %s)",
+ to_path_partial.u8string(),
+ to_path.u8string(),
+ ec.message());
}
- static void verify_hash(const VcpkgPaths& paths,
+ static void verify_hash(const Files::Filesystem& fs,
const std::string& url,
const fs::path& path,
const std::string& sha512)
{
- const std::string actual_hash = Hash::get_file_hash(paths, path, "SHA512");
+ const std::string actual_hash = Hash::get_file_hash(fs, path, "SHA512");
Checks::check_exit(VCPKG_LINE_INFO,
sha512 == actual_hash,
"File does not have the expected hash:\n"
@@ -247,24 +343,119 @@ namespace vcpkg::Commands::Fetch
actual_hash);
}
- static void download_file(const VcpkgPaths& paths,
+#if defined(_WIN32)
+ static void winhttp_download_file(Files::Filesystem& fs,
+ CStringView target_file_path,
+ CStringView hostname,
+ CStringView url_path)
+ {
+ // Make sure the directories are present, otherwise fopen_s fails
+ const auto dir = fs::path(target_file_path.c_str()).parent_path();
+ std::error_code ec;
+ fs.create_directories(dir, ec);
+ Checks::check_exit(VCPKG_LINE_INFO, !ec, "Could not create directories %s", dir.u8string());
+
+ FILE* f = nullptr;
+ const errno_t err = fopen_s(&f, target_file_path.c_str(), "wb");
+ Checks::check_exit(VCPKG_LINE_INFO,
+ !err,
+ "Could not download https://%s%s. Failed to open file %s. Error code was %s",
+ hostname,
+ url_path,
+ target_file_path,
+ std::to_string(err));
+
+ auto hSession = WinHttpOpen(
+ L"vcpkg/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
+ Checks::check_exit(VCPKG_LINE_INFO, hSession, "WinHttpOpen() failed: %d", GetLastError());
+
+ // Use Windows 10 defaults on Windows 7
+ DWORD secure_protocols(WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 |
+ WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2);
+ WinHttpSetOption(hSession, WINHTTP_OPTION_SECURE_PROTOCOLS, &secure_protocols, sizeof(secure_protocols));
+
+ // Specify an HTTP server.
+ auto hConnect = WinHttpConnect(hSession, Strings::to_utf16(hostname).c_str(), INTERNET_DEFAULT_HTTPS_PORT, 0);
+ Checks::check_exit(VCPKG_LINE_INFO, hConnect, "WinHttpConnect() failed: %d", GetLastError());
+
+ // Create an HTTP request handle.
+ auto hRequest = WinHttpOpenRequest(hConnect,
+ L"GET",
+ Strings::to_utf16(url_path).c_str(),
+ nullptr,
+ WINHTTP_NO_REFERER,
+ WINHTTP_DEFAULT_ACCEPT_TYPES,
+ WINHTTP_FLAG_SECURE);
+ Checks::check_exit(VCPKG_LINE_INFO, hRequest, "WinHttpOpenRequest() failed: %d", GetLastError());
+
+ // Send a request.
+ auto bResults =
+ WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
+ Checks::check_exit(VCPKG_LINE_INFO, bResults, "WinHttpSendRequest() failed: %d", GetLastError());
+
+ // End the request.
+ bResults = WinHttpReceiveResponse(hRequest, NULL);
+ Checks::check_exit(VCPKG_LINE_INFO, bResults, "WinHttpReceiveResponse() failed: %d", GetLastError());
+
+ std::vector<char> buf;
+
+ size_t total_downloaded_size = 0;
+ DWORD dwSize = 0;
+ do
+ {
+ DWORD downloaded_size = 0;
+ bResults = WinHttpQueryDataAvailable(hRequest, &dwSize);
+ Checks::check_exit(VCPKG_LINE_INFO, bResults, "WinHttpQueryDataAvailable() failed: %d", GetLastError());
+
+ if (buf.size() < dwSize) buf.resize(dwSize * 2);
+
+ bResults = WinHttpReadData(hRequest, (LPVOID)buf.data(), dwSize, &downloaded_size);
+ Checks::check_exit(VCPKG_LINE_INFO, bResults, "WinHttpReadData() failed: %d", GetLastError());
+ fwrite(buf.data(), 1, downloaded_size, f);
+
+ total_downloaded_size += downloaded_size;
+ } while (dwSize > 0);
+
+ WinHttpCloseHandle(hSession);
+ WinHttpCloseHandle(hConnect);
+ WinHttpCloseHandle(hRequest);
+ fflush(f);
+ fclose(f);
+ }
+#endif
+
+ static void download_file(Files::Filesystem& fs,
const std::string& url,
const fs::path& download_path,
const std::string& sha512)
{
- Files::Filesystem& fs = paths.get_filesystem();
const std::string download_path_part = download_path.u8string() + ".part";
std::error_code ec;
+ fs.remove(download_path, ec);
fs.remove(download_path_part, ec);
+#if defined(_WIN32)
+ auto url_no_proto = url.substr(8); // drop https://
+ auto path_begin = Util::find(url_no_proto, '/');
+ std::string hostname(url_no_proto.begin(), path_begin);
+ std::string path(path_begin, url_no_proto.end());
+
+ winhttp_download_file(fs, download_path_part.c_str(), hostname, path);
+#else
const auto code = System::cmd_execute(
Strings::format(R"(curl -L '%s' --create-dirs --output '%s')", url, download_path_part));
Checks::check_exit(VCPKG_LINE_INFO, code == 0, "Could not download %s", url);
+#endif
- verify_hash(paths, url, download_path_part, sha512);
- fs.rename(download_path_part, download_path);
+ verify_hash(fs, url, download_path_part, sha512);
+ fs.rename(download_path_part, download_path, ec);
+ Checks::check_exit(VCPKG_LINE_INFO,
+ !ec,
+ "Failed to do post-download rename-in-place.\nfs.rename(%s, %s, %s)",
+ download_path_part,
+ download_path.u8string(),
+ ec.message());
}
-#endif
static fs::path fetch_tool(const VcpkgPaths& paths, const std::string& tool_name, const ToolData& tool_data)
{
const std::array<int, 3>& version = tool_data.version;
@@ -280,50 +471,37 @@ namespace vcpkg::Commands::Fetch
version_as_string,
tool_name,
version_as_string);
-#if defined(_WIN32)
- const fs::path script = paths.scripts / "fetchtool.ps1";
- const std::string title = Strings::format(
- "Fetching %s version %s (No sufficient installed version was found)", tool_name, version_as_string);
- const System::PowershellParameter tool_param("tool", tool_name);
- const std::string output = System::powershell_execute_and_capture_output(title, script, {tool_param});
-
- const std::vector<std::string> tool_path = keep_data_lines(output);
- Checks::check_exit(VCPKG_LINE_INFO, tool_path.size() == 1, "Expected tool path, but got %s", output);
-
- const fs::path actual_downloaded_path = Strings::trim(std::string{tool_path.at(0)});
- const fs::path& expected_downloaded_path = tool_data.exe_path;
- std::error_code ec;
- const auto eq = fs::stdfs::equivalent(expected_downloaded_path, actual_downloaded_path, ec);
- Checks::check_exit(VCPKG_LINE_INFO,
- eq && !ec,
- "Expected tool downloaded path to be %s, but was %s",
- expected_downloaded_path.u8string(),
- actual_downloaded_path.u8string());
- return actual_downloaded_path;
-#else
- const auto& fs = paths.get_filesystem();
+ auto& fs = paths.get_filesystem();
if (!fs.exists(tool_data.download_path))
{
System::println("Downloading %s...", tool_name);
- download_file(paths, tool_data.url, tool_data.download_path, tool_data.sha512);
+ download_file(fs, tool_data.url, tool_data.download_path, tool_data.sha512);
System::println("Downloading %s... done.", tool_name);
}
else
{
- verify_hash(paths, tool_data.url, tool_data.download_path, tool_data.sha512);
+ verify_hash(fs, tool_data.url, tool_data.download_path, tool_data.sha512);
}
- System::println("Extracting %s...", tool_name);
- extract_archive(paths, tool_data.download_path, tool_data.tool_dir_path);
- System::println("Extracting %s... done.", tool_name);
+ if (tool_data.is_archive)
+ {
+ System::println("Extracting %s...", tool_name);
+ extract_archive(paths, tool_data.download_path, tool_data.tool_dir_path);
+ System::println("Extracting %s... done.", tool_name);
+ }
+ else
+ {
+ std::error_code ec;
+ fs.create_directories(tool_data.exe_path.parent_path(), ec);
+ fs.rename(tool_data.download_path, tool_data.exe_path, ec);
+ }
Checks::check_exit(VCPKG_LINE_INFO,
fs.exists(tool_data.exe_path),
- "Expected %s to exist after extracting",
- tool_data.exe_path);
+ "Expected %s to exist after fetching",
+ tool_data.exe_path.u8string());
return tool_data.exe_path;
-#endif
}
static fs::path get_cmake_path(const VcpkgPaths& paths)
@@ -345,8 +523,8 @@ namespace vcpkg::Commands::Fetch
const auto& program_files_32_bit = System::get_program_files_32_bit();
if (const auto pf = program_files_32_bit.get()) candidate_paths.push_back(*pf / "CMake" / "bin" / "cmake.exe");
- const Optional<fs::path> path =
- find_if_has_equal_or_greater_version(candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.version);
+ const Optional<fs::path> path = find_if_has_equal_or_greater_version(
+ paths.get_filesystem(), candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.version);
if (const auto p = path.get())
{
return *p;
@@ -378,7 +556,8 @@ namespace vcpkg::Commands::Fetch
const std::vector<fs::path> from_path = Files::find_from_PATH("ninja");
candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
- auto path = find_if_has_equal_or_greater_version(candidate_paths, "--version", TOOL_DATA.version);
+ auto path = find_if_has_equal_or_greater_version(
+ paths.get_filesystem(), candidate_paths, "--version", TOOL_DATA.version);
if (const auto p = path.get())
{
return *p;
@@ -396,7 +575,8 @@ namespace vcpkg::Commands::Fetch
const std::vector<fs::path> from_path = Files::find_from_PATH("nuget");
candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
- auto path = find_if_has_equal_or_greater_version(candidate_paths, "", TOOL_DATA.version);
+ auto path =
+ find_if_has_equal_or_greater_version(paths.get_filesystem(), candidate_paths, "", TOOL_DATA.version);
if (const auto p = path.get())
{
return *p;
@@ -422,8 +602,8 @@ namespace vcpkg::Commands::Fetch
const auto& program_files_32_bit = System::get_program_files_32_bit();
if (const auto pf = program_files_32_bit.get()) candidate_paths.push_back(*pf / "git" / "cmd" / "git.exe");
- const Optional<fs::path> path =
- find_if_has_equal_or_greater_version(candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.version);
+ const Optional<fs::path> path = find_if_has_equal_or_greater_version(
+ paths.get_filesystem(), candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.version);
if (const auto p = path.get())
{
return *p;
@@ -448,8 +628,8 @@ namespace vcpkg::Commands::Fetch
// candidate_paths.push_back(fs::path(System::get_environment_variable("HOMEDRIVE").value_or("C:")) / "Qt" /
// "QtIFW-3.1.0" / "bin" / "installerbase.exe");
- const Optional<fs::path> path =
- find_if_has_equal_or_greater_version(candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.version);
+ const Optional<fs::path> path = find_if_has_equal_or_greater_version(
+ paths.get_filesystem(), candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.version);
if (const auto p = path.get())
{
return *p;
@@ -460,48 +640,114 @@ namespace vcpkg::Commands::Fetch
struct VisualStudioInstance
{
+ enum class ReleaseType
+ {
+ STABLE,
+ PRERELEASE,
+ LEGACY
+ };
+
+ static bool prefered_first_comparator(const VisualStudioInstance& left, const VisualStudioInstance& right)
+ {
+ const auto get_preference_weight = [](const ReleaseType& type) -> int {
+ switch (type)
+ {
+ case ReleaseType::STABLE: return 3;
+ case ReleaseType::PRERELEASE: return 2;
+ case ReleaseType::LEGACY: return 1;
+ default: Checks::unreachable(VCPKG_LINE_INFO);
+ }
+ };
+
+ if (left.release_type != right.release_type)
+ {
+ return get_preference_weight(left.release_type) > get_preference_weight(right.release_type);
+ }
+
+ return left.version > right.version;
+ }
+
+ VisualStudioInstance(fs::path&& root_path, std::string&& version, const ReleaseType& release_type)
+ : root_path(std::move(root_path)), version(std::move(version)), release_type(release_type)
+ {
+ }
+
fs::path root_path;
std::string version;
- std::string release_type;
- std::string preference_weight; // Mostly unused, just for verification that order is as intended
+ ReleaseType release_type;
std::string major_version() const { return version.substr(0, 2); }
};
static std::vector<VisualStudioInstance> get_visual_studio_instances(const VcpkgPaths& paths)
{
- const fs::path script = paths.scripts / "findVisualStudioInstallationInstances.ps1";
- const std::string output =
- System::powershell_execute_and_capture_output("Detecting Visual Studio instances", script);
+ const auto& fs = paths.get_filesystem();
+
+ const auto& program_files_32_bit = System::get_program_files_32_bit().value_or_exit(VCPKG_LINE_INFO);
+ const fs::path vswhere_exe = program_files_32_bit / "Microsoft Visual Studio" / "Installer" / "vswhere.exe";
+ Checks::check_exit(
+ VCPKG_LINE_INFO, fs.exists(vswhere_exe), "Could not locate vswhere at %s", vswhere_exe.u8string());
+
+ const auto code_and_output = System::cmd_execute_and_capture_output(
+ Strings::format(R"("%s" -prerelease -legacy -products * -format xml)", vswhere_exe.u8string()));
- const std::vector<std::string> instances_as_strings = keep_data_lines(output);
Checks::check_exit(VCPKG_LINE_INFO,
- !instances_as_strings.empty(),
- "Could not detect any Visual Studio instances.\n"
- "Powershell script:\n"
- " %s\n"
- "returned:\n"
- "%s",
- script.generic_string(),
- output);
+ code_and_output.exit_code == 0,
+ "Running vswhere.exe failed with message:\n%s",
+ code_and_output.output);
+
+ const auto& xml_as_string = code_and_output.output;
+
+ const auto instance_entries = find_all_enclosed(xml_as_string, "<instance>", "</instance>");
std::vector<VisualStudioInstance> instances;
- for (const std::string& instance_as_string : instances_as_strings)
+ for (const VcpkgStringRange& instance : instance_entries)
{
- const std::vector<std::string> split = Strings::split(instance_as_string, "::");
- Checks::check_exit(VCPKG_LINE_INFO,
- split.size() == 4,
- "Invalid Visual Studio instance format.\n"
- "Expected: PreferenceWeight::ReleaseType::Version::PathToVisualStudio\n"
- "Actual : %s\n",
- instance_as_string);
- instances.push_back({split.at(3), split.at(2), split.at(1), split.at(0)});
+ auto maybe_is_prerelease = find_at_most_one_enclosed(instance, "<isPrerelease>", "</isPrerelease>");
+
+ VisualStudioInstance::ReleaseType release_type = VisualStudioInstance::ReleaseType::LEGACY;
+ if (auto p = maybe_is_prerelease.get())
+ {
+ auto s = p->to_string();
+ if (s == "0")
+ release_type = VisualStudioInstance::ReleaseType::STABLE;
+ else if (s == "1")
+ release_type = VisualStudioInstance::ReleaseType::PRERELEASE;
+ else
+ Checks::unreachable(VCPKG_LINE_INFO);
+ }
+
+ instances.emplace_back(
+ find_exactly_one_enclosed(instance, "<installationPath>", "</installationPath>").to_string(),
+ find_exactly_one_enclosed(instance, "<installationVersion>", "</installationVersion>").to_string(),
+ release_type);
}
+ const auto append_if_has_cl = [&](fs::path&& path_root) {
+ const auto cl_exe = path_root / "VC" / "bin" / "cl.exe";
+ const auto vcvarsall_bat = path_root / "VC" / "vcvarsall.bat";
+
+ if (fs.exists(cl_exe) && fs.exists(vcvarsall_bat))
+ instances.emplace_back(std::move(path_root), "14.0", VisualStudioInstance::ReleaseType::LEGACY);
+ };
+
+ auto maybe_vs140comntools = System::get_environment_variable("vs140comntools");
+ if (const auto path_as_string = maybe_vs140comntools.get())
+ {
+ // We want lexically_normal(), but it is not available
+ // Correct root path might be 2 or 3 levels up, depending on if the path has trailing backslash. Try both.
+ auto common7_tools = fs::path{*path_as_string};
+ append_if_has_cl(fs::path{*path_as_string}.parent_path().parent_path());
+ append_if_has_cl(fs::path{*path_as_string}.parent_path().parent_path().parent_path());
+ }
+
+ append_if_has_cl(program_files_32_bit / "Microsoft Visual Studio 14.0");
+
return instances;
}
- std::vector<Toolset> find_toolset_instances(const VcpkgPaths& paths)
+#if defined(_WIN32)
+ std::vector<Toolset> find_toolset_instances_prefered_first(const VcpkgPaths& paths)
{
using CPU = System::CPUArchitecture;
@@ -513,12 +759,14 @@ namespace vcpkg::Commands::Fetch
std::vector<Toolset> found_toolsets;
std::vector<Toolset> excluded_toolsets;
- const std::vector<VisualStudioInstance> vs_instances = get_visual_studio_instances(paths);
- const bool v140_is_available = Util::find_if(vs_instances, [&](const VisualStudioInstance& vs_instance) {
+ const SortedVector<VisualStudioInstance> sorted{get_visual_studio_instances(paths),
+ VisualStudioInstance::prefered_first_comparator};
+
+ const bool v140_is_available = Util::find_if(sorted, [&](const VisualStudioInstance& vs_instance) {
return vs_instance.major_version() == "14";
- }) != vs_instances.cend();
+ }) != sorted.end();
- for (const VisualStudioInstance& vs_instance : vs_instances)
+ for (const VisualStudioInstance& vs_instance : sorted)
{
const std::string major_version = vs_instance.major_version();
if (major_version == "15")
@@ -672,6 +920,7 @@ namespace vcpkg::Commands::Fetch
return found_toolsets;
}
+#endif
fs::path get_tool_path(const VcpkgPaths& paths, const std::string& tool)
{
diff --git a/toolsrc/src/vcpkg/commands.hash.cpp b/toolsrc/src/vcpkg/commands.hash.cpp
index 1f709f87b..d7d653ca3 100644
--- a/toolsrc/src/vcpkg/commands.hash.cpp
+++ b/toolsrc/src/vcpkg/commands.hash.cpp
@@ -154,10 +154,9 @@ namespace vcpkg::Commands::Hash
};
}
- std::string get_file_hash(const VcpkgPaths& paths, const fs::path& path, const std::string& hash_type)
+ std::string get_file_hash(const Files::Filesystem& fs, const fs::path& path, const std::string& hash_type)
{
- Checks::check_exit(
- VCPKG_LINE_INFO, paths.get_filesystem().exists(path), "File %s does not exist", path.u8string());
+ Checks::check_exit(VCPKG_LINE_INFO, fs.exists(path), "File %s does not exist", path.u8string());
return BCryptHasher{hash_type}.hash_file(path);
}
@@ -239,7 +238,7 @@ namespace vcpkg::Commands::Hash
const fs::path file_to_hash = args.command_arguments[0];
const std::string algorithm = args.command_arguments.size() == 2 ? args.command_arguments[1] : "SHA512";
- const std::string hash = get_file_hash(paths, file_to_hash, algorithm);
+ const std::string hash = get_file_hash(paths.get_filesystem(), file_to_hash, algorithm);
System::println(hash);
Checks::exit_success(VCPKG_LINE_INFO);
}
diff --git a/toolsrc/src/vcpkg/export.cpp b/toolsrc/src/vcpkg/export.cpp
index 152252018..b13140de2 100644
--- a/toolsrc/src/vcpkg/export.cpp
+++ b/toolsrc/src/vcpkg/export.cpp
@@ -227,8 +227,6 @@ namespace vcpkg::Export
{fs::path{"scripts"} / "buildsystems" / "vcpkg.cmake"},
{fs::path{"scripts"} / "cmake" / "vcpkg_get_windows_sdk.cmake"},
{fs::path{"scripts"} / "getWindowsSDK.ps1"},
- {fs::path{"scripts"} / "getProgramFilesPlatformBitness.ps1"},
- {fs::path{"scripts"} / "getProgramFiles32bit.ps1"},
{fs::path{"scripts"} / "VcpkgPowershellUtils.ps1"},
};
diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp
index 0903c2d76..caf09f526 100644
--- a/toolsrc/src/vcpkg/vcpkgpaths.cpp
+++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp
@@ -39,6 +39,7 @@ namespace vcpkg
paths.triplets = paths.root / "triplets";
paths.scripts = paths.root / "scripts";
+ paths.tools = paths.downloads / "tools";
paths.buildsystems = paths.scripts / "buildsystems";
paths.buildsystems_msbuild_targets = paths.buildsystems / "msbuild" / "vcpkg.targets";
@@ -113,9 +114,11 @@ namespace vcpkg
return external_toolset;
}
- // Invariant: toolsets are non-empty and sorted with newest at back()
+#if !defined(_WIN32)
+ Checks::exit_with_message(VCPKG_LINE_INFO, "Cannot build windows triplets from non-windows.");
+#else
const std::vector<Toolset>& vs_toolsets =
- this->toolsets.get_lazy([this]() { return Commands::Fetch::find_toolset_instances(*this); });
+ this->toolsets.get_lazy([this]() { return Commands::Fetch::find_toolset_instances_prefered_first(*this); });
std::vector<const Toolset*> candidates = Util::element_pointers(vs_toolsets);
const auto tsv = prebuildinfo.platform_toolset.get();
@@ -159,6 +162,8 @@ namespace vcpkg
Checks::check_exit(VCPKG_LINE_INFO, !candidates.empty(), "No suitable Visual Studio instances were found");
return *candidates.front();
+
+#endif
}
Files::Filesystem& VcpkgPaths::get_filesystem() const { return Files::get_real_filesystem(); }
diff --git a/toolsrc/vcpkg.sln b/toolsrc/vcpkg.sln
index eae73a760..792d39906 100644
--- a/toolsrc/vcpkg.sln
+++ b/toolsrc/vcpkg.sln
@@ -15,11 +15,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{F589
ProjectSection(SolutionItems) = preProject
..\scripts\bootstrap.ps1 = ..\scripts\bootstrap.ps1
..\scripts\fetchDependency.ps1 = ..\scripts\fetchDependency.ps1
- ..\scripts\findAnyMSBuildWithCppPlatformToolset.ps1 = ..\scripts\findAnyMSBuildWithCppPlatformToolset.ps1
- ..\scripts\findVisualStudioInstallationInstances.ps1 = ..\scripts\findVisualStudioInstallationInstances.ps1
+ ..\scripts\getVisualStudioInstances.ps1 = ..\scripts\getVisualStudioInstances.ps1
..\scripts\get_triplet_environment.cmake = ..\scripts\get_triplet_environment.cmake
- ..\scripts\getProgramFiles32bit.ps1 = ..\scripts\getProgramFiles32bit.ps1
- ..\scripts\getProgramFilesPlatformBitness.ps1 = ..\scripts\getProgramFilesPlatformBitness.ps1
..\scripts\getWindowsSDK.ps1 = ..\scripts\getWindowsSDK.ps1
..\scripts\internalCI.ps1 = ..\scripts\internalCI.ps1
..\scripts\ports.cmake = ..\scripts\ports.cmake