mirror of
https://github.com/microsoft/vcpkg.git
synced 2024-12-27 18:31:15 +08:00
[vcpkg] Significantly reduce usage of powershell. Reduce console font switching bug
This commit is contained in:
parent
52f01eefa6
commit
1b0682a39e
@ -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"})
|
||||
return [bool]($object.psobject.Properties | Where-Object { $_.Name -eq "$propertyName"})
|
||||
}
|
||||
|
||||
function vcpkgCreateDirectoryIfNotExists([Parameter(Mandatory=$true)][string]$dirPath)
|
||||
function getProgramFiles32bit()
|
||||
{
|
||||
if (!(Test-Path $dirPath))
|
||||
$out = ${env:PROGRAMFILES(X86)}
|
||||
if ($out -eq $null)
|
||||
{
|
||||
New-Item -ItemType Directory -Path $dirPath | Out-Null
|
||||
$out = ${env:PROGRAMFILES}
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
function vcpkgCheckEqualFileHash( [Parameter(Mandatory=$true)][string]$url,
|
||||
[Parameter(Mandatory=$true)][string]$filePath,
|
||||
[Parameter(Mandatory=$true)][string]$expectedHash)
|
||||
{
|
||||
$actualHash = vcpkgGetSHA512 $filePath
|
||||
if ($expectedHash -ne $actualHash)
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
function vcpkgDownloadFile( [Parameter(Mandatory=$true)][string]$url,
|
||||
[Parameter(Mandatory=$true)][string]$downloadPath,
|
||||
[Parameter(Mandatory=$true)][string]$sha512)
|
||||
{
|
||||
if ($url -match "github")
|
||||
{
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
if ($out -eq $null)
|
||||
{
|
||||
throw "Could not find [Program Files 32-bit]"
|
||||
}
|
||||
|
||||
return $out
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
$vcpkgRootDir = $scriptsDir
|
||||
$withVSPath = $withVSPath -replace "\\$" # Remove potential trailing backslash
|
||||
|
||||
while (!($vcpkgRootDir -eq "") -and !(Test-Path "$vcpkgRootDir\.vcpkg-root"))
|
||||
{
|
||||
[xml]$asXml = Get-Content "$scriptsDir\vcpkgTools.xml"
|
||||
$toolData = $asXml.SelectSingleNode("//tools/tool[@name=`"git`"]")
|
||||
$gitFromDownload = "$vcpkgRootDir\downloads\$($toolData.exeRelativePath)"
|
||||
$gitDir = split-path -parent $gitFromDownload
|
||||
|
||||
$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"
|
||||
}
|
||||
}
|
||||
Write-Verbose "Examining $vcpkgRootDir for .vcpkg-root"
|
||||
$vcpkgRootDir = Split-path $vcpkgRootDir -Parent
|
||||
}
|
||||
finally
|
||||
{
|
||||
$env:path = $oldpath
|
||||
}
|
||||
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")
|
||||
|
||||
|
@ -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>"
|
@ -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."
|
@ -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
|
@ -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
|
@ -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
|
74
scripts/getVisualStudioInstances.ps1
Normal file
74
scripts/getVisualStudioInstances.ps1
Normal file
@ -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
|
@ -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>
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -66,6 +66,7 @@ namespace vcpkg
|
||||
fs::path triplets;
|
||||
fs::path scripts;
|
||||
|
||||
fs::path tools;
|
||||
fs::path buildsystems;
|
||||
fs::path buildsystems_msbuild_targets;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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'); }
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}();
|
||||
|
||||
const auto cmd_launch_cmake = System::make_cmake_cmd(cmake_exe_path,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
return input.substr(substring_start, to - substring_start);
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
return vs_instance.major_version() == "14";
|
||||
}) != vs_instances.cend();
|
||||
const SortedVector<VisualStudioInstance> sorted{get_visual_studio_instances(paths),
|
||||
VisualStudioInstance::prefered_first_comparator};
|
||||
|
||||
for (const VisualStudioInstance& vs_instance : vs_instances)
|
||||
const bool v140_is_available = Util::find_if(sorted, [&](const VisualStudioInstance& vs_instance) {
|
||||
return vs_instance.major_version() == "14";
|
||||
}) != sorted.end();
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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"},
|
||||
};
|
||||
|
||||
|
@ -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(); }
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user