mirror of
https://github.com/ScoopInstaller/Scoop.git
synced 2025-11-23 18:06:10 +00:00
Compare commits
10 Commits
analytics
...
rasa/sandb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2745b0f42b | ||
|
|
212dc3d2ee | ||
|
|
39da19bcfc | ||
|
|
68760de1e8 | ||
|
|
257304bbc7 | ||
|
|
52f9ce3a81 | ||
|
|
6369ba60ba | ||
|
|
af5ffcddab | ||
|
|
360daa706a | ||
|
|
f93028001f |
22
CHANGELOG.md
22
CHANGELOG.md
@@ -1,3 +1,25 @@
|
||||
## [Unreleased](https://github.com/ScoopInstaller/Scoop/compare/master...develop)
|
||||
|
||||
### Features
|
||||
|
||||
- **scoop-update:** Add support for parallel syncing buckets in PowerShell 7 and improve output ([#5122](https://github.com/ScoopInstaller/Scoop/issues/5122))
|
||||
- **testing:** Add ability to test manifests inside a Windows sandbox ([#5349](https://github.com/(https://github.com/ScoopInstaller/Scoop/pulls/5349))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **decompress:** Exclude '*.nsis' that may cause error ([#5294](https://github.com/ScoopInstaller/Scoop/issues/5294))
|
||||
- **autoupdate:** Fix file hash extraction ([#5295](https://github.com/ScoopInstaller/Scoop/issues/5295))
|
||||
- **shortcuts:** Output correctly formatted path ([#5333](https://github.com/ScoopInstaller/Scoop/issues/5333))
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
- **git:** Use Invoke-Git() with direct path to git.exe to prevent spawning shim subprocesses ([#5122](https://github.com/ScoopInstaller/Scoop/issues/5122))
|
||||
- **scoop-download:** Output more detailed manifest information ([#5277](https://github.com/ScoopInstaller/Scoop/issues/5277))
|
||||
|
||||
### Tests
|
||||
|
||||
- **bucket:** Skip manifest validation if no manifest changes ([#5270](https://github.com/ScoopInstaller/Scoop/issues/5270))
|
||||
|
||||
## [v0.3.1](https://github.com/ScoopInstaller/Scoop/compare/v0.3.0...v0.3.1) - 2022-11-15
|
||||
|
||||
### Features
|
||||
|
||||
237
bin/sandbox.ps1
Normal file
237
bin/sandbox.ps1
Normal file
@@ -0,0 +1,237 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
# Portions Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
# Parse arguments
|
||||
|
||||
Param(
|
||||
[Parameter(Position = 0, HelpMessage = 'The Manifest to install in the Sandbox.')]
|
||||
[String] $Manifest,
|
||||
[Parameter(Position = 1, HelpMessage = 'Options to pass to scoop.')]
|
||||
[String] $Options,
|
||||
[Parameter(Position = 2, HelpMessage = 'The script to run in the Sandbox.')]
|
||||
[ScriptBlock] $Script,
|
||||
[Parameter(HelpMessage = 'The folder to map in the Sandbox.')]
|
||||
[String] $MapFolder = $pwd
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$mapFolder = (Resolve-Path -Path $MapFolder).Path
|
||||
|
||||
if (-Not (Test-Path -Path $mapFolder -PathType Container)) {
|
||||
Write-Error -Category InvalidArgument -Message 'The provided MapFolder is not a folder.'
|
||||
}
|
||||
|
||||
# Check if Windows Sandbox is enabled
|
||||
|
||||
if (-Not (Get-Command 'WindowsSandbox' -ErrorAction SilentlyContinue)) {
|
||||
Write-Error -Category NotInstalled -Message @'
|
||||
Windows Sandbox does not seem to be available. Check the following URL for prerequisites and further details:
|
||||
https://docs.microsoft.com/windows/security/threat-protection/windows-sandbox/windows-sandbox-overview
|
||||
|
||||
You can run the following command in an elevated PowerShell for enabling Windows Sandbox:
|
||||
$ Enable-WindowsOptionalFeature -Online -FeatureName 'Containers-DisposableClientVM'
|
||||
'@
|
||||
}
|
||||
|
||||
# Close Windows Sandbox
|
||||
|
||||
$sandbox = Get-Process 'WindowsSandboxClient' -ErrorAction SilentlyContinue
|
||||
if ($sandbox) {
|
||||
Write-Host '--> Closing Windows Sandbox'
|
||||
|
||||
$sandbox | Stop-Process
|
||||
Start-Sleep -Seconds 5
|
||||
|
||||
Write-Host
|
||||
}
|
||||
Remove-Variable sandbox
|
||||
|
||||
# Initialize Temp Folder
|
||||
|
||||
$tempFolderName = 'SandboxTest'
|
||||
$tempFolder = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath $tempFolderName
|
||||
|
||||
Remove-Item $tempFolder -Force -Recurse
|
||||
|
||||
New-Item $tempFolder -ItemType Directory | Out-Null
|
||||
|
||||
if (-Not [String]::IsNullOrWhiteSpace($Manifest)) {
|
||||
Copy-Item -Path $Manifest -Recurse -Destination $tempFolder
|
||||
}
|
||||
|
||||
if ($null -eq $env:SCOOP_HOME) { $env:SCOOP_HOME = "$env:USERPROFILE\scoop" }
|
||||
$scoopCache = $env:SCOOP_HOME + '\cache'
|
||||
|
||||
Write-Host "Copying $scoopCache to $tempFolder\cache"
|
||||
|
||||
Copy-Item -Path $scoopCache -Recurse -Destination $tempFolder | Out-Null
|
||||
|
||||
$userprofileInSandbox = 'C:\Users\WDAGUtilityAccount'
|
||||
$desktopInSandbox = $userprofileInSandbox + '\Desktop'
|
||||
$sandboxTestInSandbox = $desktopInSandbox + '\' + $tempFolderName
|
||||
$copiedCacheInSandbox = $sandboxTestInSandbox + "\cache"
|
||||
$scoopCacheInSandbox = $userprofileInSandbox + "\scoop\cache"
|
||||
|
||||
# Create Bootstrap script
|
||||
|
||||
# See: https://stackoverflow.com/a/22670892/12156188
|
||||
$bootstrapPs1Content = @'
|
||||
function Update-EnvironmentVariables {
|
||||
foreach($level in "Machine","User") {
|
||||
[Environment]::GetEnvironmentVariables($level).GetEnumerator() | % {
|
||||
# For Path variables, append the new values, if they're not already in there
|
||||
if($_.Name -match 'Path$') {
|
||||
$_.Value = ($((Get-Content "Env:$($_.Name)") + ";$($_.Value)") -split ';' | Select -unique) -join ';'
|
||||
}
|
||||
$_
|
||||
} | Set-Content -Path { "Env:$($_.Name)" }
|
||||
}
|
||||
}
|
||||
|
||||
function Get-ARPTable {
|
||||
$registry_paths = @('HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*','HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*', 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*', 'HKCU:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*')
|
||||
return Get-ItemProperty $registry_paths -ErrorAction SilentlyContinue |
|
||||
Select-Object DisplayName, DisplayVersion, Publisher, @{N='ProductCode'; E={$_.PSChildName}} |
|
||||
Where-Object {$null -ne $_.DisplayName }
|
||||
}
|
||||
'@
|
||||
|
||||
$bootstrapPs1Content += @"
|
||||
Write-Host @'
|
||||
--> Installing Scoop, 7zip, git, innounp, dark and lessmsi
|
||||
'@
|
||||
`$ProgressPreference = 'SilentlyContinue'
|
||||
|
||||
irm get.scoop.sh -outfile 'install.ps1'
|
||||
.\install.ps1 -RunAsAdmin
|
||||
Update-EnvironmentVariables
|
||||
|
||||
xcopy /I /Q /Y $copiedCacheInSandbox\*.* $scoopCacheInSandbox\
|
||||
|
||||
scoop install --no-update-scoop main/7zip
|
||||
scoop install --no-update-scoop main/git
|
||||
scoop install --no-update-scoop main/innounp
|
||||
scoop install --no-update-scoop main/dark
|
||||
scoop install --no-update-scoop main/lessmsi
|
||||
|
||||
Write-Host @'
|
||||
Tip: you can type 'Update-EnvironmentVariables' to update your environment variables, such as after installing a new software.
|
||||
'@
|
||||
|
||||
|
||||
"@
|
||||
|
||||
if (-Not [String]::IsNullOrWhiteSpace($Manifest)) {
|
||||
$manifestFileName = Split-Path $Manifest -Leaf
|
||||
$manifestPathInSandbox = Join-Path -Path $desktopInSandbox -ChildPath (Join-Path -Path $tempFolderName -ChildPath $manifestFileName)
|
||||
|
||||
$bootstrapPs1Content += @"
|
||||
Write-Host @'
|
||||
|
||||
--> Saving current ARP entries
|
||||
'@
|
||||
`$originalARP = Get-ARPTable
|
||||
Write-Host @'
|
||||
|
||||
--> Running: scoop install $Options $Manifest
|
||||
|
||||
'@
|
||||
|
||||
scoop install $Options --no-update-scoop $manifestPathInSandbox
|
||||
|
||||
Write-Host @'
|
||||
|
||||
--> Refreshing environment variables
|
||||
'@
|
||||
Update-EnvironmentVariables
|
||||
|
||||
Write-Host @'
|
||||
|
||||
--> Comparing ARP entries
|
||||
'@
|
||||
(Compare-Object (Get-ARPTable) `$originalARP -Property DisplayName,DisplayVersion,Publisher,ProductCode)| Select-Object -Property * -ExcludeProperty SideIndicator | Format-Table
|
||||
|
||||
"@
|
||||
}
|
||||
|
||||
if (-Not [String]::IsNullOrWhiteSpace($Script)) {
|
||||
$bootstrapPs1Content += @"
|
||||
Write-Host @'
|
||||
|
||||
--> Running the following script:
|
||||
|
||||
{
|
||||
$Script
|
||||
}
|
||||
|
||||
'@
|
||||
|
||||
$Script
|
||||
|
||||
|
||||
"@
|
||||
}
|
||||
|
||||
$bootstrapPs1Content += @'
|
||||
Write-Host
|
||||
'@
|
||||
|
||||
$bootstrapPs1FileName = 'Bootstrap.ps1'
|
||||
$bootstrapPs1Content | Out-File (Join-Path -Path $tempFolder -ChildPath $bootstrapPs1FileName)
|
||||
|
||||
# Create Wsb file
|
||||
|
||||
$bootstrapPs1InSandbox = Join-Path -Path $desktopInSandbox -ChildPath (Join-Path -Path $tempFolderName -ChildPath $bootstrapPs1FileName)
|
||||
$mapFolderInSandbox = Join-Path -Path $desktopInSandbox -ChildPath (Split-Path -Path $mapFolder -Leaf)
|
||||
|
||||
$sandboxTestWsbContent = @"
|
||||
<Configuration>
|
||||
<MappedFolders>
|
||||
<MappedFolder>
|
||||
<HostFolder>$tempFolder</HostFolder>
|
||||
<ReadOnly>true</ReadOnly>
|
||||
</MappedFolder>
|
||||
<MappedFolder>
|
||||
<HostFolder>$mapFolder</HostFolder>
|
||||
</MappedFolder>
|
||||
</MappedFolders>
|
||||
<LogonCommand>
|
||||
<Command>PowerShell Start-Process PowerShell -WindowStyle Maximized -WorkingDirectory '$mapFolderInSandbox' -ArgumentList '-ExecutionPolicy Bypass -NoExit -NoLogo -File $bootstrapPs1InSandbox'</Command>
|
||||
</LogonCommand>
|
||||
</Configuration>
|
||||
"@
|
||||
|
||||
$sandboxTestWsbFileName = 'SandboxTest.wsb'
|
||||
$sandboxTestWsbFile = Join-Path -Path $tempFolder -ChildPath $sandboxTestWsbFileName
|
||||
$sandboxTestWsbContent | Out-File $sandboxTestWsbFile
|
||||
|
||||
Write-Host @"
|
||||
--> Starting Windows Sandbox, and:
|
||||
- Mounting the following directories:
|
||||
- $tempFolder as read-only
|
||||
- $mapFolder as read-and-write
|
||||
- Installing Scoop
|
||||
"@
|
||||
|
||||
if (-Not [String]::IsNullOrWhiteSpace($Manifest)) {
|
||||
Write-Host @"
|
||||
- Installing the Manifest $manifestFileName
|
||||
- Refreshing environment variables
|
||||
- Comparing ARP Entries
|
||||
"@
|
||||
}
|
||||
|
||||
if (-Not [String]::IsNullOrWhiteSpace($Script)) {
|
||||
Write-Host @"
|
||||
- Running the following script:
|
||||
|
||||
{
|
||||
$Script
|
||||
}
|
||||
"@
|
||||
}
|
||||
|
||||
Write-Host
|
||||
|
||||
WindowsSandbox $SandboxTestWsbFile
|
||||
@@ -20,8 +20,8 @@ switch ($subCommand) {
|
||||
}
|
||||
({ $subCommand -in @('-v', '--version') }) {
|
||||
Write-Host 'Current Scoop version:'
|
||||
if ((Test-CommandAvailable git) -and (Test-Path "$PSScriptRoot\..\.git") -and (get_config SCOOP_BRANCH 'master') -ne 'master') {
|
||||
git -C "$PSScriptRoot\.." --no-pager log --oneline HEAD -n 1
|
||||
if (Test-GitAvailable -and (Test-Path "$PSScriptRoot\..\.git") -and (get_config SCOOP_BRANCH 'master') -ne 'master') {
|
||||
Invoke-Git -Path "$PSScriptRoot\.." -ArgumentList @('log', 'HEAD', '-1', '--oneline')
|
||||
} else {
|
||||
$version = Select-String -Pattern '^## \[(v[\d.]+)\].*?([\d-]+)$' -Path "$PSScriptRoot\..\CHANGELOG.md"
|
||||
Write-Host $version.Matches.Groups[1].Value -ForegroundColor Cyan -NoNewline
|
||||
@@ -31,9 +31,9 @@ switch ($subCommand) {
|
||||
|
||||
Get-LocalBucket | ForEach-Object {
|
||||
$bucketLoc = Find-BucketDirectory $_ -Root
|
||||
if ((Test-Path "$bucketLoc\.git") -and (Test-CommandAvailable git)) {
|
||||
if (Test-GitAvailable -and (Test-Path "$bucketLoc\.git")) {
|
||||
Write-Host "'$_' bucket:"
|
||||
git -C "$bucketLoc" --no-pager log --oneline HEAD -n 1
|
||||
Invoke-Git -Path $bucketLoc -ArgumentList @('log', 'HEAD', '-1', '--oneline')
|
||||
Write-Host ''
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,9 @@ function find_hash_in_rdf([String] $url, [String] $basename) {
|
||||
$wc.Headers.Add('User-Agent', (Get-UserAgent))
|
||||
$data = $wc.DownloadData($url)
|
||||
[xml]$xml = (Get-Encoding($wc)).GetString($data)
|
||||
} catch [system.net.webexception] {
|
||||
write-host -f darkred $_
|
||||
write-host -f darkred "URL $url is not valid"
|
||||
} catch [System.Net.WebException] {
|
||||
Write-Host $_ -ForegroundColor DarkRed
|
||||
Write-Host "URL $url is not valid" -ForegroundColor DarkRed
|
||||
return $null
|
||||
}
|
||||
|
||||
@@ -24,12 +24,12 @@ function find_hash_in_textfile([String] $url, [Hashtable] $substitutions, [Strin
|
||||
$hashfile = $null
|
||||
|
||||
$templates = @{
|
||||
'$md5' = '([a-fA-F0-9]{32})';
|
||||
'$sha1' = '([a-fA-F0-9]{40})';
|
||||
'$sha256' = '([a-fA-F0-9]{64})';
|
||||
'$sha512' = '([a-fA-F0-9]{128})';
|
||||
'$checksum' = '([a-fA-F0-9]{32,128})';
|
||||
'$base64' = '([a-zA-Z0-9+\/=]{24,88})';
|
||||
'$md5' = '([a-fA-F0-9]{32})'
|
||||
'$sha1' = '([a-fA-F0-9]{40})'
|
||||
'$sha256' = '([a-fA-F0-9]{64})'
|
||||
'$sha512' = '([a-fA-F0-9]{128})'
|
||||
'$checksum' = '([a-fA-F0-9]{32,128})'
|
||||
'$base64' = '([a-zA-Z0-9+\/=]{24,88})'
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -39,8 +39,8 @@ function find_hash_in_textfile([String] $url, [Hashtable] $substitutions, [Strin
|
||||
$data = $wc.DownloadData($url)
|
||||
$hashfile = (Get-Encoding($wc)).GetString($data)
|
||||
} catch [system.net.webexception] {
|
||||
write-host -f darkred $_
|
||||
write-host -f darkred "URL $url is not valid"
|
||||
Write-Host $_ -ForegroundColor DarkRed
|
||||
Write-Host "URL $url is not valid" -ForegroundColor DarkRed
|
||||
return
|
||||
}
|
||||
|
||||
@@ -50,15 +50,15 @@ function find_hash_in_textfile([String] $url, [Hashtable] $substitutions, [Strin
|
||||
|
||||
$regex = substitute $regex $templates $false
|
||||
$regex = substitute $regex $substitutions $true
|
||||
debug $regex
|
||||
if ($hashfile -match $regex) {
|
||||
$hash = $matches[1] -replace '\s',''
|
||||
debug $regex
|
||||
$hash = $matches[1] -replace '\s', ''
|
||||
}
|
||||
|
||||
# convert base64 encoded hash values
|
||||
if ($hash -match '^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})$') {
|
||||
$base64 = $matches[0]
|
||||
if(!($hash -match '^[a-fA-F0-9]+$') -and $hash.length -notin @(32, 40, 64, 128)) {
|
||||
if (!($hash -match '^[a-fA-F0-9]+$') -and $hash.Length -notin @(32, 40, 64, 128)) {
|
||||
try {
|
||||
$hash = ([System.Convert]::FromBase64String($base64) | ForEach-Object { $_.ToString('x2') }) -join ''
|
||||
} catch {
|
||||
@@ -69,13 +69,15 @@ function find_hash_in_textfile([String] $url, [Hashtable] $substitutions, [Strin
|
||||
|
||||
# find hash with filename in $hashfile
|
||||
if ($hash.Length -eq 0) {
|
||||
$filenameRegex = "([a-fA-F0-9]{32,128})[\x20\t]+.*`$basename(?:[\x20\t]+\d+)?"
|
||||
$filenameRegex = "([a-fA-F0-9]{32,128})[\x20\t]+.*`$basename(?:\s|$)|`$basename[\x20\t]+.*?([a-fA-F0-9]{32,128})"
|
||||
$filenameRegex = substitute $filenameRegex $substitutions $true
|
||||
if ($hashfile -match $filenameRegex) {
|
||||
debug $filenameRegex
|
||||
$hash = $matches[1]
|
||||
}
|
||||
$metalinkRegex = "<hash[^>]+>([a-fA-F0-9]{64})"
|
||||
$metalinkRegex = '<hash[^>]+>([a-fA-F0-9]{64})'
|
||||
if ($hashfile -match $metalinkRegex) {
|
||||
debug $metalinkRegex
|
||||
$hash = $matches[1]
|
||||
}
|
||||
}
|
||||
@@ -92,13 +94,14 @@ function find_hash_in_json([String] $url, [Hashtable] $substitutions, [String] $
|
||||
$wc.Headers.Add('User-Agent', (Get-UserAgent))
|
||||
$data = $wc.DownloadData($url)
|
||||
$json = (Get-Encoding($wc)).GetString($data)
|
||||
} catch [system.net.webexception] {
|
||||
write-host -f darkred $_
|
||||
write-host -f darkred "URL $url is not valid"
|
||||
} catch [System.Net.WebException] {
|
||||
Write-Host $_ -ForegroundColor DarkRed
|
||||
Write-Host "URL $url is not valid" -ForegroundColor DarkRed
|
||||
return
|
||||
}
|
||||
debug $jsonpath
|
||||
$hash = json_path $json $jsonpath $substitutions
|
||||
if(!$hash) {
|
||||
if (!$hash) {
|
||||
$hash = json_path_legacy $json $jsonpath $substitutions
|
||||
}
|
||||
return format_hash $hash
|
||||
@@ -114,8 +117,8 @@ function find_hash_in_xml([String] $url, [Hashtable] $substitutions, [String] $x
|
||||
$data = $wc.DownloadData($url)
|
||||
$xml = [xml]((Get-Encoding($wc)).GetString($data))
|
||||
} catch [system.net.webexception] {
|
||||
write-host -f darkred $_
|
||||
write-host -f darkred "URL $url is not valid"
|
||||
Write-Host $_ -ForegroundColor DarkRed
|
||||
Write-Host "URL $url is not valid" -ForegroundColor DarkRed
|
||||
return
|
||||
}
|
||||
|
||||
@@ -125,13 +128,15 @@ function find_hash_in_xml([String] $url, [Hashtable] $substitutions, [String] $x
|
||||
}
|
||||
|
||||
# Find all `significant namespace declarations` from the XML file
|
||||
$nsList = $xml.SelectNodes("//namespace::*[not(. = ../../namespace::*)]")
|
||||
$nsList = $xml.SelectNodes('//namespace::*[not(. = ../../namespace::*)]')
|
||||
# Then add them into the NamespaceManager
|
||||
$nsmgr = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
|
||||
$nsList | ForEach-Object {
|
||||
$nsmgr.AddNamespace($_.LocalName, $_.Value)
|
||||
}
|
||||
|
||||
debug $xpath
|
||||
debug $nsmgr
|
||||
# Getting hash from XML, using XPath
|
||||
$hash = $xml.SelectSingleNode($xpath, $nsmgr).'#text'
|
||||
return format_hash $hash
|
||||
@@ -148,16 +153,16 @@ function find_hash_in_headers([String] $url) {
|
||||
$req.Timeout = 2000
|
||||
$req.Method = 'HEAD'
|
||||
$res = $req.GetResponse()
|
||||
if(([int]$res.StatusCode -ge 300) -and ([int]$res.StatusCode -lt 400)) {
|
||||
if($res.Headers['Digest'] -match 'SHA-256=([^,]+)' -or $res.Headers['Digest'] -match 'SHA=([^,]+)' -or $res.Headers['Digest'] -match 'MD5=([^,]+)') {
|
||||
if (([int]$res.StatusCode -ge 300) -and ([int]$res.StatusCode -lt 400)) {
|
||||
if ($res.Headers['Digest'] -match 'SHA-256=([^,]+)' -or $res.Headers['Digest'] -match 'SHA=([^,]+)' -or $res.Headers['Digest'] -match 'MD5=([^,]+)') {
|
||||
$hash = ([System.Convert]::FromBase64String($matches[1]) | ForEach-Object { $_.ToString('x2') }) -join ''
|
||||
debug $hash
|
||||
}
|
||||
}
|
||||
$res.Close()
|
||||
} catch [system.net.webexception] {
|
||||
write-host -f darkred $_
|
||||
write-host -f darkred "URL $url is not valid"
|
||||
} catch [System.Net.WebException] {
|
||||
Write-Host $_ -ForegroundColor DarkRed
|
||||
Write-Host "URL $url is not valid" -ForegroundColor DarkRed
|
||||
return
|
||||
}
|
||||
|
||||
@@ -182,10 +187,10 @@ function get_hash_for_app([String] $app, $config, [String] $version, [String] $u
|
||||
$hashfile_url = substitute $config.url $substitutions
|
||||
debug $hashfile_url
|
||||
if ($hashfile_url) {
|
||||
write-host -f DarkYellow 'Searching hash for ' -NoNewline
|
||||
write-host -f Green $basename -NoNewline
|
||||
write-host -f DarkYellow ' in ' -NoNewline
|
||||
write-host -f Green $hashfile_url
|
||||
Write-Host 'Searching hash for ' -ForegroundColor DarkYellow -NoNewline
|
||||
Write-Host $basename -ForegroundColor Green -NoNewline
|
||||
Write-Host ' in ' -ForegroundColor DarkYellow -NoNewline
|
||||
Write-Host $hashfile_url -ForegroundColor Green
|
||||
}
|
||||
|
||||
if ($hashmode.Length -eq 0 -and $config.url.Length -ne 0) {
|
||||
@@ -215,11 +220,11 @@ function get_hash_for_app([String] $app, $config, [String] $version, [String] $u
|
||||
$hashmode = 'xpath'
|
||||
}
|
||||
|
||||
if (!$hashfile_url -and $url -match "^(?:.*fosshub.com\/).*(?:\/|\?dwl=)(?<filename>.*)$") {
|
||||
if (!$hashfile_url -and $url -match '^(?:.*fosshub.com\/).*(?:\/|\?dwl=)(?<filename>.*)$') {
|
||||
$hashmode = 'fosshub'
|
||||
}
|
||||
|
||||
if (!$hashfile_url -and $url -match "(?:downloads\.)?sourceforge.net\/projects?\/(?<project>[^\/]+)\/(?:files\/)?(?<file>.*)") {
|
||||
if (!$hashfile_url -and $url -match '(?:downloads\.)?sourceforge.net\/projects?\/(?<project>[^\/]+)\/(?:files\/)?(?<file>.*)') {
|
||||
$hashmode = 'sourceforge'
|
||||
}
|
||||
|
||||
@@ -243,7 +248,7 @@ function get_hash_for_app([String] $app, $config, [String] $version, [String] $u
|
||||
}
|
||||
}
|
||||
'fosshub' {
|
||||
$hash = find_hash_in_textfile $url $substitutions ($Matches.filename+'.*?"sha256":"([a-fA-F0-9]{64})"')
|
||||
$hash = find_hash_in_textfile $url $substitutions ($matches.filename + '.*?"sha256":"([a-fA-F0-9]{64})"')
|
||||
}
|
||||
'sourceforge' {
|
||||
# change the URL because downloads.sourceforge.net doesn't have checksums
|
||||
@@ -254,29 +259,29 @@ function get_hash_for_app([String] $app, $config, [String] $version, [String] $u
|
||||
|
||||
if ($hash) {
|
||||
# got one!
|
||||
write-host -f DarkYellow 'Found: ' -NoNewline
|
||||
write-host -f Green $hash -NoNewline
|
||||
write-host -f DarkYellow ' using ' -NoNewline
|
||||
write-host -f Green "$((Get-Culture).TextInfo.ToTitleCase($hashmode)) Mode"
|
||||
Write-Host 'Found: ' -ForegroundColor DarkYellow -NoNewline
|
||||
Write-Host $hash -ForegroundColor Green -NoNewline
|
||||
Write-Host ' using ' -ForegroundColor DarkYellow -NoNewline
|
||||
Write-Host "$((Get-Culture).TextInfo.ToTitleCase($hashmode)) Mode" -ForegroundColor Green
|
||||
return $hash
|
||||
} elseif ($hashfile_url) {
|
||||
write-host -f DarkYellow "Could not find hash in $hashfile_url"
|
||||
Write-Host -f DarkYellow "Could not find hash in $hashfile_url"
|
||||
}
|
||||
|
||||
write-host -f DarkYellow 'Downloading ' -NoNewline
|
||||
write-host -f Green $basename -NoNewline
|
||||
write-host -f DarkYellow ' to compute hashes!'
|
||||
Write-Host 'Downloading ' -ForegroundColor DarkYellow -NoNewline
|
||||
Write-Host $basename -ForegroundColor Green -NoNewline
|
||||
Write-Host ' to compute hashes!' -ForegroundColor DarkYellow
|
||||
try {
|
||||
Invoke-CachedDownload $app $version $url $null $null $true
|
||||
} catch [system.net.webexception] {
|
||||
write-host -f darkred $_
|
||||
write-host -f darkred "URL $url is not valid"
|
||||
Write-Host $_ -ForegroundColor DarkRed
|
||||
Write-Host "URL $url is not valid" -ForegroundColor DarkRed
|
||||
return $null
|
||||
}
|
||||
$file = fullpath (cache_path $app $version $url)
|
||||
$hash = (Get-FileHash -Path $file -Algorithm SHA256).Hash.ToLower()
|
||||
write-host -f DarkYellow 'Computed hash: ' -NoNewline
|
||||
write-host -f Green $hash
|
||||
Write-Host 'Computed hash: ' -ForegroundColor DarkYellow -NoNewline
|
||||
Write-Host $hash -ForegroundColor Green
|
||||
return $hash
|
||||
}
|
||||
|
||||
@@ -346,7 +351,7 @@ function Update-ManifestProperty {
|
||||
$newValue = substitute $autoupdateProperty $Substitutions
|
||||
if (($autoupdateProperty.GetType().Name -eq 'Object[]') -and ($autoupdateProperty.Length -eq 1)) {
|
||||
# Make sure it's an array
|
||||
$newValue = ,$newValue
|
||||
$newValue = , $newValue
|
||||
}
|
||||
$Manifest.$currentProperty, $hasPropertyChanged = PropertyHelper -Property $Manifest.$currentProperty -Value $newValue
|
||||
$hasManifestChanged = $hasManifestChanged -or $hasPropertyChanged
|
||||
@@ -359,7 +364,7 @@ function Update-ManifestProperty {
|
||||
$newValue = substitute $autoupdateProperty $Substitutions
|
||||
if (($autoupdateProperty.GetType().Name -eq 'Object[]') -and ($autoupdateProperty.Length -eq 1)) {
|
||||
# Make sure it's an array
|
||||
$newValue = ,$newValue
|
||||
$newValue = , $newValue
|
||||
}
|
||||
$Manifest.architecture.$arch.$currentProperty, $hasPropertyChanged = PropertyHelper -Property $Manifest.architecture.$arch.$currentProperty -Value $newValue
|
||||
$hasManifestChanged = $hasManifestChanged -or $hasPropertyChanged
|
||||
@@ -388,25 +393,25 @@ function Get-VersionSubstitution {
|
||||
$firstPart = $Version.Split('-') | Select-Object -First 1
|
||||
$lastPart = $Version.Split('-') | Select-Object -Last 1
|
||||
$versionVariables = @{
|
||||
'$version' = $Version;
|
||||
'$dotVersion' = ($Version -replace '[._-]', '.');
|
||||
'$underscoreVersion' = ($Version -replace '[._-]', '_');
|
||||
'$dashVersion' = ($Version -replace '[._-]', '-');
|
||||
'$cleanVersion' = ($Version -replace '[._-]', '');
|
||||
'$majorVersion' = $firstPart.Split('.') | Select-Object -First 1;
|
||||
'$minorVersion' = $firstPart.Split('.') | Select-Object -Skip 1 -First 1;
|
||||
'$patchVersion' = $firstPart.Split('.') | Select-Object -Skip 2 -First 1;
|
||||
'$buildVersion' = $firstPart.Split('.') | Select-Object -Skip 3 -First 1;
|
||||
'$preReleaseVersion' = $lastPart;
|
||||
'$version' = $Version
|
||||
'$dotVersion' = ($Version -replace '[._-]', '.')
|
||||
'$underscoreVersion' = ($Version -replace '[._-]', '_')
|
||||
'$dashVersion' = ($Version -replace '[._-]', '-')
|
||||
'$cleanVersion' = ($Version -replace '[._-]', '')
|
||||
'$majorVersion' = $firstPart.Split('.') | Select-Object -First 1
|
||||
'$minorVersion' = $firstPart.Split('.') | Select-Object -Skip 1 -First 1
|
||||
'$patchVersion' = $firstPart.Split('.') | Select-Object -Skip 2 -First 1
|
||||
'$buildVersion' = $firstPart.Split('.') | Select-Object -Skip 3 -First 1
|
||||
'$preReleaseVersion' = $lastPart
|
||||
}
|
||||
if($Version -match "(?<head>\d+\.\d+(?:\.\d+)?)(?<tail>.*)") {
|
||||
$versionVariables.Set_Item('$matchHead', $Matches['head'])
|
||||
$versionVariables.Set_Item('$matchTail', $Matches['tail'])
|
||||
if ($Version -match '(?<head>\d+\.\d+(?:\.\d+)?)(?<tail>.*)') {
|
||||
$versionVariables.Add('$matchHead', $Matches['head'])
|
||||
$versionVariables.Add('$matchTail', $Matches['tail'])
|
||||
}
|
||||
if($CustomMatches) {
|
||||
if ($CustomMatches) {
|
||||
$CustomMatches.GetEnumerator() | ForEach-Object {
|
||||
if($_.Name -ne "0") {
|
||||
$versionVariables.Set_Item('$match' + (Get-Culture).TextInfo.ToTitleCase($_.Name), $_.Value)
|
||||
if ($_.Name -ne '0') {
|
||||
$versionVariables.Add('$match' + (Get-Culture).TextInfo.ToTitleCase($_.Name), $_.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,8 +99,8 @@ function list_buckets {
|
||||
$bucket = [Ordered]@{ Name = $_ }
|
||||
$path = Find-BucketDirectory $_ -Root
|
||||
if ((Test-Path (Join-Path $path '.git')) -and (Get-Command git -ErrorAction SilentlyContinue)) {
|
||||
$bucket.Source = git -C $path config remote.origin.url
|
||||
$bucket.Updated = git -C $path log --format='%aD' -n 1 | Get-Date
|
||||
$bucket.Source = Invoke-Git -Path $path -ArgumentList @('config', 'remote.origin.url')
|
||||
$bucket.Updated = Invoke-Git -Path $path -ArgumentList @('log', "--format='%aD'", '-n', '1')
|
||||
} else {
|
||||
$bucket.Source = friendly_path $path
|
||||
$bucket.Updated = (Get-Item "$path\bucket").LastWriteTime
|
||||
@@ -113,7 +113,7 @@ function list_buckets {
|
||||
}
|
||||
|
||||
function add_bucket($name, $repo) {
|
||||
if (!(Test-CommandAvailable git)) {
|
||||
if (!(Test-GitAvailable)) {
|
||||
error "Git is required for buckets. Run 'scoop install git' and try again."
|
||||
return 1
|
||||
}
|
||||
@@ -130,7 +130,7 @@ function add_bucket($name, $repo) {
|
||||
}
|
||||
foreach ($bucket in Get-LocalBucket) {
|
||||
if (Test-Path -Path "$bucketsdir\$bucket\.git") {
|
||||
$remote = git -C "$bucketsdir\$bucket" config --get remote.origin.url
|
||||
$remote = Invoke-Git -Path "$bucketsdir\$bucket" -ArgumentList @('config', '--get', 'remote.origin.url')
|
||||
if ((Convert-RepositoryUri -Uri $remote) -eq $uni_repo) {
|
||||
warn "Bucket $bucket already exists for $repo"
|
||||
return 2
|
||||
@@ -139,14 +139,14 @@ function add_bucket($name, $repo) {
|
||||
}
|
||||
|
||||
Write-Host 'Checking repo... ' -NoNewline
|
||||
$out = git_cmd ls-remote $repo 2>&1
|
||||
$out = Invoke-Git -ArgumentList @('ls-remote', $repo) 2>&1
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
error "'$repo' doesn't look like a valid git repository`n`nError given:`n$out"
|
||||
return 1
|
||||
}
|
||||
ensure $bucketsdir | Out-Null
|
||||
$dir = ensure $dir
|
||||
git_cmd clone "$repo" "`"$dir`"" -q
|
||||
Invoke-Git -ArgumentList @('clone', $repo, $dir, '-q')
|
||||
Write-Host 'OK'
|
||||
success "The $name bucket was added successfully."
|
||||
return 0
|
||||
@@ -169,7 +169,7 @@ function new_issue_msg($app, $bucket, $title, $body) {
|
||||
$bucket_path = "$bucketsdir\$bucket"
|
||||
|
||||
if (Test-Path $bucket_path) {
|
||||
$remote = git -C "$bucket_path" config --get remote.origin.url
|
||||
$remote = Invoke-Git -Path $bucket_path -ArgumentList @('config', '--get', 'remote.origin.url')
|
||||
# Support ssh and http syntax
|
||||
# git@PROVIDER:USER/REPO.git
|
||||
# https://PROVIDER/USER/REPO.git
|
||||
|
||||
89
lib/core.ps1
89
lib/core.ps1
@@ -128,13 +128,78 @@ function setup_proxy() {
|
||||
}
|
||||
}
|
||||
|
||||
function git_cmd {
|
||||
function Invoke-Git {
|
||||
[CmdletBinding()]
|
||||
[OutputType([String])]
|
||||
param(
|
||||
[Parameter(Mandatory = $false, Position = 0)]
|
||||
[Alias('PSPath', 'Path')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[String]
|
||||
$WorkingDirectory,
|
||||
[Parameter(Mandatory = $true, Position = 1)]
|
||||
[Alias('Args')]
|
||||
[String[]]
|
||||
$ArgumentList
|
||||
)
|
||||
|
||||
$proxy = get_config PROXY
|
||||
$cmd = "git $($args | ForEach-Object { "$_ " })"
|
||||
if ($proxy -and $proxy -ne 'none') {
|
||||
$cmd = "SET HTTPS_PROXY=$proxy&&SET HTTP_PROXY=$proxy&&$cmd"
|
||||
$git = Get-HelperPath -Helper Git
|
||||
$arguments = $ArgumentList -join ' '
|
||||
$cmd = "`"$git`" $arguments"
|
||||
|
||||
if ($WorkingDirectory) {
|
||||
$cmd = "`"$git`" -C `"$WorkingDirectory`" $arguments"
|
||||
}
|
||||
$sb = [scriptblock]::Create("& $cmd")
|
||||
|
||||
if([String]::IsNullOrEmpty($proxy) -or $proxy -eq 'none') {
|
||||
return Invoke-Command $sb
|
||||
}
|
||||
|
||||
if($arguments -Match '\b(clone|checkout|pull|fetch|ls-remote)\b') {
|
||||
$old_https = $env:HTTPS_PROXY
|
||||
$old_http = $env:HTTP_PROXY
|
||||
try {
|
||||
# convert proxy setting for git
|
||||
if ($proxy.StartsWith('currentuser@')) {
|
||||
$proxy = $proxy.Replace('currentuser@', ':@')
|
||||
}
|
||||
$env:HTTPS_PROXY = $proxy
|
||||
$env:HTTP_PROXY = $proxy
|
||||
return Invoke-Command $sb
|
||||
}
|
||||
catch {
|
||||
error $_
|
||||
return
|
||||
}
|
||||
finally {
|
||||
$env:HTTPS_PROXY = $old_https
|
||||
$env:HTTP_PROXY = $old_http
|
||||
}
|
||||
}
|
||||
|
||||
return Invoke-Command $sb
|
||||
}
|
||||
|
||||
function Invoke-GitLog {
|
||||
[CmdletBinding()]
|
||||
Param (
|
||||
[Parameter(Mandatory, ValueFromPipeline)]
|
||||
[String]$Path,
|
||||
[Parameter(Mandatory, ValueFromPipeline)]
|
||||
[String]$CommitHash,
|
||||
[String]$Name = ''
|
||||
)
|
||||
Process {
|
||||
if ($Name) {
|
||||
if ($Name.Length -gt 12) {
|
||||
$Name = "$($Name.Substring(0, 10)).."
|
||||
}
|
||||
$Name = "%Cgreen$($Name.PadRight(12, ' ').Substring(0, 12))%Creset "
|
||||
}
|
||||
Invoke-Git -Path $Path -ArgumentList @('--no-pager', 'log', '--color', '--no-decorate', "--grep='^(chore)'", '--invert-grep', '--abbrev=12', "--format='tformat: * %C(yellow)%h%Creset %<|(72,trunc)%s $Name%C(cyan)%cr%Creset'", "$CommitHash..HEAD")
|
||||
}
|
||||
cmd.exe /d /c $cmd
|
||||
}
|
||||
|
||||
# helper functions
|
||||
@@ -293,12 +358,16 @@ Function Test-CommandAvailable {
|
||||
Return [Boolean](Get-Command $Name -ErrorAction Ignore)
|
||||
}
|
||||
|
||||
Function Test-GitAvailable {
|
||||
Return [Boolean](Test-Path (Get-HelperPath -Helper Git) -ErrorAction Ignore)
|
||||
}
|
||||
|
||||
function Get-HelperPath {
|
||||
[CmdletBinding()]
|
||||
[OutputType([String])]
|
||||
param(
|
||||
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
|
||||
[ValidateSet('7zip', 'Lessmsi', 'Innounp', 'Dark', 'Aria2', 'Zstd')]
|
||||
[ValidateSet('Git', '7zip', 'Lessmsi', 'Innounp', 'Dark', 'Aria2', 'Zstd')]
|
||||
[String]
|
||||
$Helper
|
||||
)
|
||||
@@ -307,6 +376,14 @@ function Get-HelperPath {
|
||||
}
|
||||
process {
|
||||
switch ($Helper) {
|
||||
'Git' {
|
||||
$internalgit = "$(versiondir 'git' 'current')\mingw64\bin\git.exe"
|
||||
if (Test-Path $internalgit) {
|
||||
$HelperPath = $internalgit
|
||||
} else {
|
||||
$HelperPath = (Get-Command git -ErrorAction Ignore).Source
|
||||
}
|
||||
}
|
||||
'7zip' {
|
||||
$HelperPath = Get-AppFilePath '7zip' '7z.exe'
|
||||
if ([String]::IsNullOrEmpty($HelperPath)) {
|
||||
|
||||
@@ -29,7 +29,7 @@ function Expand-7zipArchive {
|
||||
}
|
||||
$LogPath = "$(Split-Path $Path)\7zip.log"
|
||||
$DestinationPath = $DestinationPath.TrimEnd('\')
|
||||
$ArgList = @('x', $Path, "-o$DestinationPath", '-y')
|
||||
$ArgList = @('x', $Path, "-o$DestinationPath", '-xr!*.nsis', '-y')
|
||||
$IsTar = ((strip_ext $Path) -match '\.tar$') -or ($Path -match '\.t[abgpx]z2?$')
|
||||
if (!$IsTar -and $ExtractDir) {
|
||||
$ArgList += "-ir!$ExtractDir\*"
|
||||
|
||||
@@ -5,16 +5,16 @@ function create_startmenu_shortcuts($manifest, $dir, $global, $arch) {
|
||||
$target = [System.IO.Path]::Combine($dir, $_.item(0))
|
||||
$target = New-Object System.IO.FileInfo($target)
|
||||
$name = $_.item(1)
|
||||
$arguments = ""
|
||||
$arguments = ''
|
||||
$icon = $null
|
||||
if($_.length -ge 3) {
|
||||
if ($_.length -ge 3) {
|
||||
$arguments = $_.item(2)
|
||||
}
|
||||
if($_.length -ge 4) {
|
||||
if ($_.length -ge 4) {
|
||||
$icon = [System.IO.Path]::Combine($dir, $_.item(3))
|
||||
$icon = New-Object System.IO.FileInfo($icon)
|
||||
}
|
||||
$arguments = (substitute $arguments @{ '$dir' = $dir; '$original_dir' = $original_dir; '$persist_dir' = $persist_dir})
|
||||
$arguments = (substitute $arguments @{ '$dir' = $dir; '$original_dir' = $original_dir; '$persist_dir' = $persist_dir })
|
||||
startmenu_shortcut $target $name $arguments $icon $global
|
||||
}
|
||||
}
|
||||
@@ -29,11 +29,11 @@ function shortcut_folder($global) {
|
||||
}
|
||||
|
||||
function startmenu_shortcut([System.IO.FileInfo] $target, $shortcutName, $arguments, [System.IO.FileInfo]$icon, $global) {
|
||||
if(!$target.Exists) {
|
||||
if (!$target.Exists) {
|
||||
Write-Host -f DarkRed "Creating shortcut for $shortcutName ($(fname $target)) failed: Couldn't find $target"
|
||||
return
|
||||
}
|
||||
if($icon -and !$icon.Exists) {
|
||||
if ($icon -and !$icon.Exists) {
|
||||
Write-Host -f DarkRed "Creating shortcut for $shortcutName ($(fname $target)) failed: Couldn't find icon $icon"
|
||||
return
|
||||
}
|
||||
@@ -51,11 +51,11 @@ function startmenu_shortcut([System.IO.FileInfo] $target, $shortcutName, $argume
|
||||
if ($arguments) {
|
||||
$wsShell.Arguments = $arguments
|
||||
}
|
||||
if($icon -and $icon.Exists) {
|
||||
if ($icon -and $icon.Exists) {
|
||||
$wsShell.IconLocation = $icon.FullName
|
||||
}
|
||||
$wsShell.Save()
|
||||
write-host "Creating shortcut for $shortcutName ($(fname $target))"
|
||||
Write-Host "Creating shortcut for $shortcutName ($(fname $target))"
|
||||
}
|
||||
|
||||
# Removes the Startmenu shortcut if it exists
|
||||
@@ -63,10 +63,10 @@ function rm_startmenu_shortcuts($manifest, $global, $arch) {
|
||||
$shortcuts = @(arch_specific 'shortcuts' $manifest $arch)
|
||||
$shortcuts | Where-Object { $_ -ne $null } | ForEach-Object {
|
||||
$name = $_.item(1)
|
||||
$shortcut = "$(shortcut_folder $global)\$name.lnk"
|
||||
write-host "Removing shortcut $(friendly_path $shortcut)"
|
||||
if(Test-Path -Path $shortcut) {
|
||||
Remove-Item $shortcut
|
||||
$shortcut = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath("$(shortcut_folder $global)\$name.lnk")
|
||||
Write-Host "Removing shortcut $(friendly_path $shortcut)"
|
||||
if (Test-Path -Path $shortcut) {
|
||||
Remove-Item $shortcut
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ foreach ($curr_app in $apps) {
|
||||
$app, $bucket, $version = parse_app $curr_app
|
||||
$app, $manifest, $bucket, $url = Get-Manifest "$bucket/$app"
|
||||
|
||||
info "Starting download for $app..."
|
||||
info "Downloading '$app'$(if ($version) { " ($version)" }) [$architecture]$(if ($bucket) { " from $bucket bucket" })"
|
||||
|
||||
# Generate manifest if there is different version in manifest
|
||||
if (($null -ne $version) -and ($manifest.version -ne $version)) {
|
||||
|
||||
@@ -84,7 +84,7 @@ if ($manifest.depends) {
|
||||
|
||||
if (Test-Path $manifest_file) {
|
||||
if (Get-Command git -ErrorAction Ignore) {
|
||||
$gitinfo = (git -C (Split-Path $manifest_file) log -1 -s --format='%aD#%an' $manifest_file 2> $null) -Split '#'
|
||||
$gitinfo = (Invoke-Git -Path (Split-Path $manifest_file) -ArgumentList @('log', '-1', '-s', "--format='%aD#%an'", $manifest_file) 2> $null) -Split '#'
|
||||
}
|
||||
if ($gitinfo) {
|
||||
$item.'Updated at' = $gitinfo[0] | Get-Date
|
||||
|
||||
@@ -21,10 +21,10 @@ if (!(Get-FormatData ScoopStatus)) {
|
||||
|
||||
function Test-UpdateStatus($repopath) {
|
||||
if (Test-Path "$repopath\.git") {
|
||||
git_cmd -C "`"$repopath`"" fetch -q origin
|
||||
Invoke-Git -Path $repopath -ArgumentList @('fetch', '-q', 'origin')
|
||||
$script:network_failure = 128 -eq $LASTEXITCODE
|
||||
$branch = git -C $repopath branch --show-current
|
||||
$commits = git -C $repopath log "HEAD..origin/$branch" --oneline
|
||||
$branch = Invoke-Git -Path $repopath -ArgumentList @('branch', '--show-current')
|
||||
$commits = Invoke-Git -Path $repopath -ArgumentList @('log', "HEAD..origin/$branch", '--oneline')
|
||||
if ($commits) { return $true }
|
||||
else { return $false }
|
||||
} else {
|
||||
|
||||
@@ -56,14 +56,18 @@ if(($PSVersionTable.PSVersion.Major) -lt 5) {
|
||||
}
|
||||
$show_update_log = get_config SHOW_UPDATE_LOG $true
|
||||
|
||||
function update_scoop($show_update_log) {
|
||||
function Sync-Scoop {
|
||||
[CmdletBinding()]
|
||||
Param (
|
||||
[Switch]$Log
|
||||
)
|
||||
# Test if Scoop Core is hold
|
||||
if(Test-ScoopCoreOnHold) {
|
||||
return
|
||||
}
|
||||
|
||||
# check for git
|
||||
if (!(Test-CommandAvailable git)) { abort "Scoop uses Git to update itself. Run 'scoop install git' and try again." }
|
||||
if (!(Test-GitAvailable)) { abort "Scoop uses Git to update itself. Run 'scoop install git' and try again." }
|
||||
|
||||
Write-Host "Updating Scoop..."
|
||||
$currentdir = fullpath $(versiondir 'scoop' 'current')
|
||||
@@ -72,7 +76,7 @@ function update_scoop($show_update_log) {
|
||||
$olddir = "$currentdir\..\old"
|
||||
|
||||
# get git scoop
|
||||
git_cmd clone -q $configRepo --branch $configBranch --single-branch "`"$newdir`""
|
||||
Invoke-Git -ArgumentList @('clone', '-q', $configRepo, '--branch', $configBranch, '--single-branch', $newdir)
|
||||
|
||||
# check if scoop was successful downloaded
|
||||
if (!(Test-Path "$newdir\bin\scoop.ps1")) {
|
||||
@@ -93,18 +97,18 @@ function update_scoop($show_update_log) {
|
||||
Remove-Item "$currentdir\..\old" -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
$previousCommit = git -C "$currentdir" rev-parse HEAD
|
||||
$currentRepo = git -C "$currentdir" config remote.origin.url
|
||||
$currentBranch = git -C "$currentdir" branch
|
||||
$previousCommit = Invoke-Git -Path $currentdir -ArgumentList @('rev-parse', 'HEAD')
|
||||
$currentRepo = Invoke-Git -Path $currentdir -ArgumentList @('config', 'remote.origin.url')
|
||||
$currentBranch = Invoke-Git -Path $currentdir -ArgumentList @('branch')
|
||||
|
||||
$isRepoChanged = !($currentRepo -match $configRepo)
|
||||
$isBranchChanged = !($currentBranch -match "\*\s+$configBranch")
|
||||
|
||||
# Stash uncommitted changes
|
||||
if (git -C "$currentdir" diff HEAD --name-only) {
|
||||
if (Invoke-Git -Path $currentdir -ArgumentList @('diff', 'HEAD', '--name-only')) {
|
||||
if (get_config AUTOSTASH_ON_CONFLICT) {
|
||||
warn "Uncommitted changes detected. Stashing..."
|
||||
git -C "$currentdir" stash push -m "WIP at $([System.DateTime]::Now.ToString('o'))" -u -q
|
||||
Invoke-Git -Path $currentdir -ArgumentList @('stash', 'push', '-m', "WIP at $([System.DateTime]::Now.ToString('o'))", '-u', '-q')
|
||||
} else {
|
||||
warn "Uncommitted changes detected. Update aborted."
|
||||
return
|
||||
@@ -113,26 +117,26 @@ function update_scoop($show_update_log) {
|
||||
|
||||
# Change remote url if the repo is changed
|
||||
if ($isRepoChanged) {
|
||||
git -C "$currentdir" config remote.origin.url "$configRepo"
|
||||
Invoke-Git -Path $currentdir -ArgumentList @('config', 'remote.origin.url', $configRepo)
|
||||
}
|
||||
|
||||
# Fetch and reset local repo if the repo or the branch is changed
|
||||
if ($isRepoChanged -or $isBranchChanged) {
|
||||
# Reset git fetch refs, so that it can fetch all branches (GH-3368)
|
||||
git -C "$currentdir" config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
|
||||
Invoke-Git -Path $currentdir -ArgumentList @('config', 'remote.origin.fetch', '+refs/heads/*:refs/remotes/origin/*')
|
||||
# fetch remote branch
|
||||
git_cmd -C "`"$currentdir`"" fetch --force origin "refs/heads/`"$configBranch`":refs/remotes/origin/$configBranch" -q
|
||||
Invoke-Git -Path $currentdir -ArgumentList @('fetch', '--force', 'origin', "refs/heads/$configBranch`:refs/remotes/origin/$configBranch", '-q')
|
||||
# checkout and track the branch
|
||||
git_cmd -C "`"$currentdir`"" checkout -B $configBranch -t origin/$configBranch -q
|
||||
Invoke-Git -Path $currentdir -ArgumentList @('checkout', '-B', $configBranch, '-t', "origin/$configBranch", '-q')
|
||||
# reset branch HEAD
|
||||
git -C "$currentdir" reset --hard origin/$configBranch -q
|
||||
Invoke-Git -Path $currentdir -ArgumentList @('reset', '--hard', "origin/$configBranch", '-q')
|
||||
} else {
|
||||
git_cmd -C "`"$currentdir`"" pull -q
|
||||
Invoke-Git -Path $currentdir -ArgumentList @('pull', '-q')
|
||||
}
|
||||
|
||||
$res = $lastexitcode
|
||||
if ($show_update_log) {
|
||||
git -C "$currentdir" --no-pager log --no-decorate --grep='^(chore)' --invert-grep --format='tformat: * %C(yellow)%h%Creset %<|(72,trunc)%s %C(cyan)%cr%Creset' "$previousCommit..HEAD"
|
||||
if ($Log) {
|
||||
Invoke-GitLog -Path $currentdir -CommitHash $previousCommit
|
||||
}
|
||||
|
||||
if ($res -ne 0) {
|
||||
@@ -140,47 +144,63 @@ function update_scoop($show_update_log) {
|
||||
}
|
||||
}
|
||||
|
||||
# This should have been deprecated after 2019-05-12
|
||||
# if ((Get-LocalBucket) -notcontains 'main') {
|
||||
# info "The main bucket of Scoop has been separated to 'https://github.com/ScoopInstaller/Main'"
|
||||
# info "Adding main bucket..."
|
||||
# add_bucket 'main'
|
||||
# }
|
||||
|
||||
shim "$currentdir\bin\scoop.ps1" $false
|
||||
}
|
||||
|
||||
function update_bucket($show_update_log) {
|
||||
# check for git
|
||||
if (!(Test-CommandAvailable git)) { abort "Scoop uses Git to update main bucket and others. Run 'scoop install git' and try again." }
|
||||
function Sync-Bucket {
|
||||
Param (
|
||||
[Switch]$Log
|
||||
)
|
||||
Write-Host "Updating Buckets..."
|
||||
|
||||
foreach ($bucket in Get-LocalBucket) {
|
||||
Write-Host "Updating '$bucket' bucket..."
|
||||
|
||||
$bucketLoc = Find-BucketDirectory $bucket -Root
|
||||
|
||||
if (!(Test-Path (Join-Path $bucketLoc '.git'))) {
|
||||
if ($bucket -eq 'main') {
|
||||
# Make sure main bucket, which was downloaded as zip, will be properly "converted" into git
|
||||
Write-Host " Converting 'main' bucket to git repo..."
|
||||
$status = rm_bucket 'main'
|
||||
if ($status -ne 0) {
|
||||
abort "Failed to remove local 'main' bucket."
|
||||
}
|
||||
$status = add_bucket 'main' (known_bucket_repo 'main')
|
||||
if ($status -ne 0) {
|
||||
abort "Failed to add remote 'main' bucket."
|
||||
}
|
||||
} else {
|
||||
Write-Host "'$bucket' is not a git repository. Skipped."
|
||||
}
|
||||
continue
|
||||
if (!(Test-Path (Join-Path (Find-BucketDirectory 'main' -Root) '.git'))) {
|
||||
info "Converting 'main' bucket to git repo..."
|
||||
$status = rm_bucket 'main'
|
||||
if ($status -ne 0) {
|
||||
abort "Failed to remove local 'main' bucket."
|
||||
}
|
||||
$status = add_bucket 'main' (known_bucket_repo 'main')
|
||||
if ($status -ne 0) {
|
||||
abort "Failed to add remote 'main' bucket."
|
||||
}
|
||||
}
|
||||
|
||||
$previousCommit = git -C "$bucketLoc" rev-parse HEAD
|
||||
git_cmd -C "`"$bucketLoc`"" pull -q
|
||||
if ($show_update_log) {
|
||||
git -C "$bucketLoc" --no-pager log --no-decorate --grep='^(chore)' --invert-grep --format='tformat: * %C(yellow)%h%Creset %<|(72,trunc)%s %C(cyan)%cr%Creset' "$previousCommit..HEAD"
|
||||
|
||||
$buckets = Get-LocalBucket | ForEach-Object {
|
||||
$path = Find-BucketDirectory $_ -Root
|
||||
return @{
|
||||
name = $_
|
||||
valid = Test-Path (Join-Path $path '.git')
|
||||
path = $path
|
||||
}
|
||||
}
|
||||
|
||||
$buckets | Where-Object { !$_.valid } | ForEach-Object { Write-Host "'$($_.name)' is not a git repository. Skipped." }
|
||||
|
||||
if ($PSVersionTable.PSVersion.Major -ge 7) {
|
||||
# Parallel parameter is available since PowerShell 7
|
||||
$buckets | Where-Object { $_.valid } | ForEach-Object -ThrottleLimit 5 -Parallel {
|
||||
. "$using:PSScriptRoot\..\lib\core.ps1"
|
||||
|
||||
$bucketLoc = $_.path
|
||||
$name = $_.name
|
||||
|
||||
$previousCommit = Invoke-Git -Path $bucketLoc -ArgumentList @('rev-parse', 'HEAD')
|
||||
Invoke-Git -Path $bucketLoc -ArgumentList @('pull', '-q')
|
||||
if ($using:Log) {
|
||||
Invoke-GitLog -Path $bucketLoc -Name $name -CommitHash $previousCommit
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$buckets | Where-Object { $_.valid } | ForEach-Object {
|
||||
$bucketLoc = $_.path
|
||||
$name = $_.name
|
||||
|
||||
$previousCommit = Invoke-Git -Path $bucketLoc -ArgumentList @('rev-parse', 'HEAD')
|
||||
Invoke-Git -Path $bucketLoc -ArgumentList @('pull', '-q')
|
||||
if ($Log) {
|
||||
Invoke-GitLog -Path $bucketLoc -Name $name -CommitHash $previousCommit
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,8 +341,8 @@ if (-not ($apps -or $all)) {
|
||||
error 'scoop update: --no-cache is invalid when <app> is not specified.'
|
||||
exit 1
|
||||
}
|
||||
update_scoop $show_update_log
|
||||
update_bucket $show_update_log
|
||||
Sync-Scoop -Log:$show_update_log
|
||||
Sync-Bucket -Log:$show_update_log
|
||||
set_config LAST_UPDATE ([System.DateTime]::Now.ToString('o')) | Out-Null
|
||||
success 'Scoop was updated successfully!'
|
||||
} else {
|
||||
@@ -336,8 +356,8 @@ if (-not ($apps -or $all)) {
|
||||
$apps_param = $apps
|
||||
|
||||
if ($updateScoop) {
|
||||
update_scoop $show_update_log
|
||||
update_bucket $show_update_log
|
||||
Sync-Scoop -Log:$show_update_log
|
||||
Sync-Bucket -Log:$show_update_log
|
||||
set_config LAST_UPDATE ([System.DateTime]::Now.ToString('o')) | Out-Null
|
||||
success 'Scoop was updated successfully!'
|
||||
}
|
||||
|
||||
@@ -16,11 +16,9 @@ Describe 'Manifest validates against the schema' {
|
||||
}
|
||||
if ($env:CI -eq $true) {
|
||||
Set-BuildEnvironment -Force
|
||||
$changedManifests = @(Get-GitChangedFile -Path $bucketDir -Include '*.json' -Commit $env:BHCommitHash)
|
||||
}
|
||||
$manifestFiles = (Get-ChildItem $bucketDir -Filter '*.json' -Recurse).FullName
|
||||
if ($changedManifests) {
|
||||
$manifestFiles = $manifestFiles | Where-Object { $_ -in $changedManifests }
|
||||
$manifestFiles = @(Get-GitChangedFile -Path $bucketDir -Include '*.json' -Commit $env:BHCommitHash)
|
||||
} else {
|
||||
$manifestFiles = (Get-ChildItem $bucketDir -Filter '*.json' -Recurse).FullName
|
||||
}
|
||||
}
|
||||
BeforeAll {
|
||||
|
||||
Reference in New Issue
Block a user