mirror of
https://github.com/ScoopInstaller/Scoop.git
synced 2025-11-21 08:56:11 +00:00
Compare commits
39 Commits
fix-bucket
...
v0.3.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8aee6f9980 | ||
|
|
9baf293ab6 | ||
|
|
7f47f662e2 | ||
|
|
7a599f062f | ||
|
|
146dab60d1 | ||
|
|
04595b417a | ||
|
|
782f3f1aa6 | ||
|
|
122fdc1a1c | ||
|
|
373007870c | ||
|
|
6fc65ed864 | ||
|
|
bfef3d8298 | ||
|
|
5ad35d6054 | ||
|
|
740322f74f | ||
|
|
e06c7f0c81 | ||
|
|
1985a05b59 | ||
|
|
dea9ebb01a | ||
|
|
08ecdd16a8 | ||
|
|
a9e5a974dd | ||
|
|
8619ee7603 | ||
|
|
bd123939dc | ||
|
|
ec04dd07bc | ||
|
|
4a31bd3302 | ||
|
|
5b5daa5ee9 | ||
|
|
9b4ee8795d | ||
|
|
7bfef4912c | ||
|
|
ca19d7b856 | ||
|
|
f945e20167 | ||
|
|
4d261e7349 | ||
|
|
c3b43625fa | ||
|
|
34da8507a8 | ||
|
|
288aee9ee9 | ||
|
|
eac520a4d8 | ||
|
|
6ae0d5eb8f | ||
|
|
9e2e2526fb | ||
|
|
664e667bed | ||
|
|
80b52e32a1 | ||
|
|
b4e0ff16a6 | ||
|
|
c5702ddd19 | ||
|
|
f992f049cc |
4
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
4
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
@@ -31,9 +31,9 @@ labels: "bug"
|
||||
|
||||
### System details
|
||||
|
||||
**Windows version:** [e.g. 7, 8, 10]
|
||||
**Windows version:** [e.g. 7, 8, 10, 11]
|
||||
|
||||
**OS architecture:** [e.g. 32bit, 64bit]
|
||||
**OS architecture:** [e.g. 32bit, 64bit, arm64]
|
||||
|
||||
**PowerShell version:** [output of `"$($PSVersionTable.PSVersion)"`]
|
||||
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
*.log
|
||||
.DS_Store
|
||||
._.DS_Store
|
||||
scoop.sublime-workspace
|
||||
|
||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -4,6 +4,9 @@
|
||||
"powershell.codeFormatting.preset": "OTBS",
|
||||
"powershell.codeFormatting.alignPropertyValuePairs": true,
|
||||
"powershell.codeFormatting.ignoreOneLineBlock": true,
|
||||
"powershell.codeFormatting.useConstantStrings": true,
|
||||
"powershell.codeFormatting.useCorrectCasing": true,
|
||||
"powershell.codeFormatting.whitespaceBetweenParameters": true,
|
||||
"files.exclude": {
|
||||
"**/.git": true,
|
||||
"**/.svn": true,
|
||||
|
||||
62
CHANGELOG.md
62
CHANGELOG.md
@@ -1,17 +1,71 @@
|
||||
## [Unreleased](https://github.com/ScoopInstaller/Scoop/compare/master...develop)
|
||||
## [v0.3.0](https://github.com/ScoopInstaller/Scoop/compare/v0.2.4...v0.3.0) - 2022-10-10
|
||||
|
||||
### Features
|
||||
|
||||
- **install:** Add support for ARM64 architecture ([#5154](https://github.com/ScoopInstaller/Scoop/issues/5154))
|
||||
- **install:** Show the running process ([#5102](https://github.com/ScoopInstaller/Scoop/issues/5102))
|
||||
- **getopt:** Support option terminator (`--`) ([#5121](https://github.com/ScoopInstaller/Scoop/issues/5121))
|
||||
- **subdir:** Allow subdir in 'bucket' ([#5119](https://github.com/ScoopInstaller/Scoop/issues/5119))
|
||||
- **scoop-config:** Allow 'hold_update_until' be set manually ([#5100](https://github.com/ScoopInstaller/Scoop/issues/5100))
|
||||
- **scoop-(un)hold:** Support `scoop (un)hold scoop` ([#5089](https://github.com/ScoopInstaller/Scoop/issues/5089))
|
||||
- **scoop-update:** Stash uncommitted changes before update ([#5091](https://github.com/ScoopInstaller/Scoop/issues/5091))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **config:** Change config option to snake_case in file and SCREAMING_CASE in code ([#5116](https://github.com/ScoopInstaller/Scoop/issues/5116))
|
||||
- **jsonpath:** Prevent converting date string to DateTime in JSONPath ([#5130](https://github.com/ScoopInstaller/Scoop/issues/5130))
|
||||
- **psmodule:** Remove folder recursively when unlinking previous module path ([#5127](https://github.com/ScoopInstaller/Scoop/issues/5127))
|
||||
- **scoop-update:** Add `uninstall_psmodule` to update process ([#5136](https://github.com/ScoopInstaller/Scoop/issues/5136))
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
- **download:** Rename `dl()` to `Invoke-Download()` ([#5143](https://github.com/ScoopInstaller/Scoop/issues/5143))
|
||||
- **path:** Use 'Convert-Path()' instead of 'Resolve-Path()' ([#5109](https://github.com/ScoopInstaller/Scoop/issues/5109))
|
||||
- **scoop-shim:** Use `getopt` to parse arguments ([#5125](https://github.com/ScoopInstaller/Scoop/issues/5125))
|
||||
|
||||
### Builds
|
||||
|
||||
- **checkver:** Implement SourceForge checkver functionality ([#5113](https://github.com/ScoopInstaller/Scoop/issues/5113), [#5163](https://github.com/ScoopInstaller/Scoop/issues/5163))
|
||||
- **checkurls:** Allow checking URLs from private_hosts ([#5152](https://github.com/ScoopInstaller/Scoop/issues/5152))
|
||||
- **schema:** Set manifest schema to be stricter ([#5093](https://github.com/ScoopInstaller/Scoop/issues/5093))
|
||||
- **vscode:** Tweak VSCode setting ([#5149](https://github.com/ScoopInstaller/Scoop/issues/5149))
|
||||
|
||||
## [v0.2.4](https://github.com/ScoopInstaller/Scoop/compare/v0.2.3...v0.2.4) - 2022-08-08
|
||||
|
||||
### Features
|
||||
|
||||
- **core:** Create no window by default in `Invoke-ExternalCommand` ([#5066](https://github.com/ScoopInstaller/Scoop/issues/5066))
|
||||
- **core:** Improve argument concatenation in `Invoke-ExternalCommand` ([#5065](https://github.com/ScoopInstaller/Scoop/issues/5065))
|
||||
- **install:** Show bucket name while installing an app ([#5075](https://github.com/ScoopInstaller/Scoop/issues/5075))
|
||||
- **scoop-status:** Add flag to disable remote checking ([#5073](https://github.com/ScoopInstaller/Scoop/issues/5073))
|
||||
- **scoop-update:** Add support for `pre_uninstall` and `post_uninstall` ([#5085](https://github.com/ScoopInstaller/Scoop/issues/5085))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **core:** Avoid deadlock in `Invoke-ExternalCommand` ([#5064](https://github.com/ScoopInstaller/Scoop/issues/5064))
|
||||
- **core:** Use 'System.Nullable<bool>' for param 'global' ([#5088](https://github.com/ScoopInstaller/Scoop/issues/5088))
|
||||
- **install:** Move from cache when `--no-cache` is specified ([#5039](https://github.com/ScoopInstaller/Scoop/issues/5039))
|
||||
- **scoop-status:** Correct formatting of `Info` output ([#5047](https://github.com/ScoopInstaller/Scoop/issues/5047))
|
||||
|
||||
### Builds
|
||||
|
||||
- **checkver:** Load page content before running 'script' ([#5080](https://github.com/ScoopInstaller/Scoop/issues/5080))
|
||||
- **json:** Update Newtonsoft.Json.Schema to 3.0.15-beta2 ([#5053](https://github.com/ScoopInstaller/Scoop/issues/5053))
|
||||
|
||||
## [v0.2.3](https://github.com/ScoopInstaller/Scoop/compare/v0.2.2...v0.2.3) - 2022-07-07
|
||||
|
||||
### Features
|
||||
|
||||
- **chore:** Add missing -a/--all param to all commands ([#5004](https://github.com/ScoopInstaller/Scoop/issues/5004))
|
||||
- **scoop-status:** Check bucket status, improve output ([#5011](https://github.com/ScoopInstaller/Scoop/issues/5011))
|
||||
- **scoop-info:** Show app installed/download size ([#4886](https://github.com/ScoopInstaller/Scoop/issues/4886))
|
||||
- **scoop-import:** Import a Scoop installation from JSON ([#5014](https://github.com/ScoopInstaller/Scoop/issues/5014))
|
||||
- **scoop-import:** Import a Scoop installation from JSON ([#5014](https://github.com/ScoopInstaller/Scoop/issues/5014), [#5034](https://github.com/ScoopInstaller/Scoop/issues/5034))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **chore:** Update help documentation ([#5002](https://github.com/ScoopInstaller/Scoop/issues/5002))
|
||||
- **chore:** Update help documentation ([#5002](https://github.com/ScoopInstaller/Scoop/issues/5002), [#5029](https://github.com/ScoopInstaller/Scoop/issues/5029))
|
||||
- **decompress:** Handle split RAR archives ([#4994](https://github.com/ScoopInstaller/Scoop/issues/4994))
|
||||
- **shortcuts:** Fix network drive shortcut creation ([#4410](https://github.com/ScoopInstaller/Scoop/issues/4410)), ([#5006](https://github.com/ScoopInstaller/Scoop/issues/5006))
|
||||
- **shortcuts:** Fix network drive shortcut creation ([#4410](https://github.com/ScoopInstaller/Scoop/issues/4410), [#5006](https://github.com/ScoopInstaller/Scoop/issues/5006))
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ param(
|
||||
if ($App -ne '*' -and (Test-Path $App -PathType Leaf)) {
|
||||
$Dir = Split-Path $App
|
||||
} elseif ($Dir) {
|
||||
$Dir = Resolve-Path $Dir
|
||||
$Dir = Convert-Path $Dir
|
||||
} else {
|
||||
throw "'-Dir' parameter required if '-App' is not a filepath!"
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ param(
|
||||
. "$PSScriptRoot\..\lib\install.ps1"
|
||||
. "$PSScriptRoot\..\lib\unix.ps1"
|
||||
|
||||
$Dir = Resolve-Path $Dir
|
||||
$Dir = Convert-Path $Dir
|
||||
if ($ForceUpdate) { $Update = $true }
|
||||
# Cleanup
|
||||
if (!$UseCache) { Remove-Item "$cachedir\*HASH_CHECK*" -Force }
|
||||
@@ -60,9 +60,10 @@ function err ([String] $name, [String[]] $message) {
|
||||
}
|
||||
|
||||
$MANIFESTS = @()
|
||||
foreach ($single in Get-ChildItem $Dir "$App.json") {
|
||||
$name = (strip_ext $single.Name)
|
||||
$manifest = parse_json "$Dir\$($single.Name)"
|
||||
foreach ($single in Get-ChildItem $Dir -Filter "$App.json" -Recurse) {
|
||||
$name = $single.BaseName
|
||||
$file = $single.FullName
|
||||
$manifest = parse_json $file
|
||||
|
||||
# Skip nighly manifests, since their hash validation is skipped
|
||||
if ($manifest.version -eq 'nightly') { continue }
|
||||
@@ -79,6 +80,8 @@ foreach ($single in Get-ChildItem $Dir "$App.json") {
|
||||
hash $manifest '64bit' | ForEach-Object { $hashes += $_ }
|
||||
script:url $manifest '32bit' | ForEach-Object { $urls += $_ }
|
||||
hash $manifest '32bit' | ForEach-Object { $hashes += $_ }
|
||||
script:url $manifest 'arm64' | ForEach-Object { $urls += $_ }
|
||||
hash $manifest 'arm64' | ForEach-Object { $hashes += $_ }
|
||||
} else {
|
||||
err $name 'Manifest does not contain URL property.'
|
||||
continue
|
||||
@@ -92,6 +95,7 @@ foreach ($single in Get-ChildItem $Dir "$App.json") {
|
||||
|
||||
$MANIFESTS += @{
|
||||
app = $name
|
||||
file = $file
|
||||
manifest = $manifest
|
||||
urls = $urls
|
||||
hashes = $hashes
|
||||
@@ -113,7 +117,7 @@ foreach ($current in $MANIFESTS) {
|
||||
$version = 'HASH_CHECK'
|
||||
$tmp = $expected_hash -split ':'
|
||||
|
||||
dl_with_cache $current.app $version $_ $null $null -use_cache:$UseCache
|
||||
Invoke-CachedDownload $current.app $version $_ $null $null -use_cache:$UseCache
|
||||
|
||||
$to_check = fullpath (cache_path $current.app $version $_)
|
||||
$actual_hash = compute_hash $to_check $algorithm
|
||||
@@ -158,23 +162,27 @@ foreach ($current in $MANIFESTS) {
|
||||
# Defaults to zero, don't know, which architecture is available
|
||||
$64bit_count = 0
|
||||
$32bit_count = 0
|
||||
$arm64_count = 0
|
||||
|
||||
# 64bit is get, donwloaded and added first
|
||||
if ($platforms.Contains('64bit')) {
|
||||
$64bit_count = $current.manifest.architecture.'64bit'.hash.Count
|
||||
# 64bit is get, donwloaded and added first
|
||||
$current.manifest.architecture.'64bit'.hash = $actuals[0..($64bit_count - 1)]
|
||||
}
|
||||
if ($platforms.Contains('32bit')) {
|
||||
$32bit_count = $current.manifest.architecture.'32bit'.hash.Count
|
||||
$max = $64bit_count + $32bit_count - 1 # Edge case if manifest contains 64bit and 32bit.
|
||||
$current.manifest.architecture.'32bit'.hash = $actuals[($64bit_count)..$max]
|
||||
$current.manifest.architecture.'32bit'.hash = $actuals[($64bit_count)..($64bit_count + $32bit_count - 1)]
|
||||
}
|
||||
if ($platforms.Contains('arm64')) {
|
||||
$arm64_count = $current.manifest.architecture.'arm64'.hash.Count
|
||||
$current.manifest.architecture.'arm64'.hash = $actuals[($64bit_count + $32bit_count)..($64bit_count + $32bit_count + $arm64_count - 1)]
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Writing updated $($current.app) manifest" -ForegroundColor DarkGreen
|
||||
|
||||
$current.manifest = $current.manifest | ConvertToPrettyJson
|
||||
$path = Resolve-Path "$Dir\$($current.app).json"
|
||||
$path = Convert-Path $current.file
|
||||
[System.IO.File]::WriteAllLines($path, $current.manifest)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,12 +30,12 @@ param(
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1"
|
||||
. "$PSScriptRoot\..\lib\install.ps1"
|
||||
|
||||
$Dir = Resolve-Path $Dir
|
||||
$Dir = Convert-Path $Dir
|
||||
$Queue = @()
|
||||
|
||||
Get-ChildItem $Dir "$App.json" | ForEach-Object {
|
||||
$manifest = parse_json "$Dir\$($_.Name)"
|
||||
$Queue += , @($_.Name, $manifest)
|
||||
Get-ChildItem $Dir -Filter "$App.json" -Recurse | ForEach-Object {
|
||||
$manifest = parse_json $_.FullName
|
||||
$Queue += , @($_.BaseName, $manifest)
|
||||
}
|
||||
|
||||
Write-Host '[' -NoNewLine
|
||||
@@ -62,6 +62,13 @@ function test_dl([String] $url, $cookies) {
|
||||
$wreq.Headers.Add('Cookie', (cookie_header $cookies))
|
||||
}
|
||||
}
|
||||
|
||||
get_config PRIVATE_HOSTS | Where-Object { $_ -ne $null -and $url -match $_.match } | ForEach-Object {
|
||||
(ConvertFrom-StringData -StringData $_.Headers).GetEnumerator() | ForEach-Object {
|
||||
$wreq.Headers[$_.Key] = $_.Value
|
||||
}
|
||||
}
|
||||
|
||||
$wres = $null
|
||||
try {
|
||||
$wres = $wreq.GetResponse()
|
||||
@@ -91,6 +98,7 @@ foreach ($man in $Queue) {
|
||||
} else {
|
||||
script:url $manifest '64bit' | ForEach-Object { $urls += $_ }
|
||||
script:url $manifest '32bit' | ForEach-Object { $urls += $_ }
|
||||
script:url $manifest 'arm64' | ForEach-Object { $urls += $_ }
|
||||
}
|
||||
|
||||
$urls | ForEach-Object {
|
||||
@@ -125,7 +133,7 @@ foreach ($man in $Queue) {
|
||||
Write-Host $failed -NoNewLine -ForegroundColor Red
|
||||
}
|
||||
Write-Host '] ' -NoNewLine
|
||||
Write-Host (strip_ext $name)
|
||||
Write-Host $name
|
||||
|
||||
$errors | ForEach-Object {
|
||||
Write-Host " > $_" -ForegroundColor DarkRed
|
||||
|
||||
@@ -78,10 +78,10 @@ param(
|
||||
|
||||
if ($App -ne '*' -and (Test-Path $App -PathType Leaf)) {
|
||||
$Dir = Split-Path $App
|
||||
$files = Get-ChildItem $Dir (Split-Path $App -Leaf)
|
||||
$files = Get-ChildItem $Dir -Filter (Split-Path $App -Leaf)
|
||||
} elseif ($Dir) {
|
||||
$Dir = Resolve-Path $Dir
|
||||
$files = Get-ChildItem $Dir "$App.json"
|
||||
$Dir = Convert-Path $Dir
|
||||
$files = Get-ChildItem $Dir -Filter "$App.json" -Recurse
|
||||
} else {
|
||||
throw "'-Dir' parameter required if '-App' is not a filepath!"
|
||||
}
|
||||
@@ -97,9 +97,10 @@ if ($App -eq '*' -and $Version -ne '') {
|
||||
$Queue = @()
|
||||
$json = ''
|
||||
$files | ForEach-Object {
|
||||
$json = parse_json "$Dir\$($_.Name)"
|
||||
$file = $_.FullName
|
||||
$json = parse_json $file
|
||||
if ($json.checkver) {
|
||||
$Queue += , @($_.Name, $json)
|
||||
$Queue += , @($_.BaseName, $json, $file)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +110,7 @@ Get-EventSubscriber | Unregister-Event
|
||||
|
||||
# start all downloads
|
||||
$Queue | ForEach-Object {
|
||||
$name, $json = $_
|
||||
$name, $json, $file = $_
|
||||
|
||||
$substitutions = Get-VersionSubstitution $json.version # 'autoupdate.ps1'
|
||||
|
||||
@@ -121,18 +122,32 @@ $Queue | ForEach-Object {
|
||||
}
|
||||
Register-ObjectEvent $wc downloadDataCompleted -ErrorAction Stop | Out-Null
|
||||
|
||||
$githubRegex = '\/releases\/tag\/(?:v|V)?([\d.]+)'
|
||||
|
||||
$url = $json.homepage
|
||||
# Not Specified
|
||||
if ($json.checkver.url) {
|
||||
$url = $json.checkver.url
|
||||
} else {
|
||||
$url = $json.homepage
|
||||
}
|
||||
|
||||
if ($json.checkver.re) {
|
||||
$regex = $json.checkver.re
|
||||
} elseif ($json.checkver.regex) {
|
||||
$regex = $json.checkver.regex
|
||||
} else {
|
||||
$regex = ''
|
||||
}
|
||||
|
||||
$jsonpath = ''
|
||||
$xpath = ''
|
||||
$replace = ''
|
||||
$useGithubAPI = $false
|
||||
|
||||
# GitHub
|
||||
if ($regex) {
|
||||
$githubRegex = $regex
|
||||
} else {
|
||||
$githubRegex = '/releases/tag/(?:v|V)?([\d.]+)'
|
||||
}
|
||||
if ($json.checkver -eq 'github') {
|
||||
if (!$json.homepage.StartsWith('https://github.com/')) {
|
||||
error "$name checkver expects the homepage to be a github repository"
|
||||
@@ -148,11 +163,38 @@ $Queue | ForEach-Object {
|
||||
if ($json.checkver.PSObject.Properties.Count -eq 1) { $useGithubAPI = $true }
|
||||
}
|
||||
|
||||
if ($json.checkver.re) {
|
||||
$regex = $json.checkver.re
|
||||
# SourceForge
|
||||
if ($regex) {
|
||||
$sourceforgeRegex = $regex
|
||||
} else {
|
||||
$sourceforgeRegex = '(?!\.)([\d.]+)(?<=\d)'
|
||||
}
|
||||
if ($json.checkver.regex) {
|
||||
$regex = $json.checkver.regex
|
||||
if ($json.checkver -eq 'sourceforge') {
|
||||
if ($json.homepage -match '//(sourceforge|sf)\.net/projects/(?<project>[^/]+)(/files/(?<path>[^/]+))?|//(?<project>[^.]+)\.(sourceforge\.(net|io)|sf\.net)') {
|
||||
$project = $Matches['project']
|
||||
$path = $Matches['path']
|
||||
} else {
|
||||
$project = strip_ext $name
|
||||
}
|
||||
$url = "https://sourceforge.net/projects/$project/rss"
|
||||
if ($path) {
|
||||
$url = $url + '?path=/' + $path.TrimStart('/')
|
||||
}
|
||||
$regex = "CDATA\[/$path/.*?$sourceforgeRegex.*?\]".Replace('//', '/')
|
||||
}
|
||||
if ($json.checkver.sourceforge) {
|
||||
if ($json.checkver.sourceforge -is [System.String] -and $json.checkver.sourceforge -match '(?<project>[\w-]*)(/(?<path>.*))?') {
|
||||
$project = $Matches['project']
|
||||
$path = $Matches['path']
|
||||
} else {
|
||||
$project = $json.checkver.sourceforge.project
|
||||
$path = $json.checkver.sourceforge.path
|
||||
}
|
||||
$url = "https://sourceforge.net/projects/$project/rss"
|
||||
if ($path) {
|
||||
$url = $url + '?path=/' + $path.TrimStart('/')
|
||||
}
|
||||
$regex = "CDATA\[/$path/.*?$sourceforgeRegex.*?\]".Replace('//', '/')
|
||||
}
|
||||
|
||||
if ($json.checkver.jp) {
|
||||
@@ -165,7 +207,7 @@ $Queue | ForEach-Object {
|
||||
$xpath = $json.checkver.xpath
|
||||
}
|
||||
|
||||
if ($json.checkver.replace -and $json.checkver.replace.GetType() -eq [System.String]) {
|
||||
if ($json.checkver.replace -is [System.String]) { # If `checkver` is [System.String], it has a method called `Replace`
|
||||
$replace = $json.checkver.replace
|
||||
}
|
||||
|
||||
@@ -185,7 +227,8 @@ $Queue | ForEach-Object {
|
||||
$url = substitute $url $substitutions
|
||||
|
||||
$state = New-Object psobject @{
|
||||
app = (strip_ext $name);
|
||||
app = $name;
|
||||
file = $file;
|
||||
url = $url;
|
||||
regex = $regex;
|
||||
json = $json;
|
||||
@@ -213,11 +256,13 @@ while ($in_progress -gt 0) {
|
||||
|
||||
$state = $ev.SourceEventArgs.UserState
|
||||
$app = $state.app
|
||||
$file = $state.file
|
||||
$json = $state.json
|
||||
$url = $state.url
|
||||
$regexp = $state.regex
|
||||
$jsonpath = $state.jsonpath
|
||||
$xpath = $state.xpath
|
||||
$script = $json.checkver.script
|
||||
$reverse = $state.reverse
|
||||
$replace = $state.replace
|
||||
$expected_ver = $json.version
|
||||
@@ -234,11 +279,12 @@ while ($in_progress -gt 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
if ($json.checkver.script) {
|
||||
$page = Invoke-Command ([scriptblock]::Create($json.checkver.script -join "`r`n"))
|
||||
} else {
|
||||
if ($url) {
|
||||
$page = (Get-Encoding($wc)).GetString($ev.SourceEventArgs.Result)
|
||||
}
|
||||
if ($script) {
|
||||
$page = Invoke-Command ([scriptblock]::Create($script -join "`r`n"))
|
||||
}
|
||||
|
||||
if ($jsonpath) {
|
||||
# Return only a single value if regex is absent
|
||||
@@ -317,7 +363,7 @@ while ($in_progress -gt 0) {
|
||||
# Skip actual only if versions are same and there is no -f
|
||||
if (($ver -eq $expected_ver) -and !$ForceUpdate -and $SkipUpdated) { continue }
|
||||
|
||||
Write-Host "$App`: " -NoNewline
|
||||
Write-Host "$app`: " -NoNewline
|
||||
|
||||
# version hasn't changed (step over if forced update)
|
||||
if ($ver -eq $expected_ver -and !$ForceUpdate) {
|
||||
@@ -343,7 +389,7 @@ while ($in_progress -gt 0) {
|
||||
Write-Host 'Forcing autoupdate!' -ForegroundColor DarkMagenta
|
||||
}
|
||||
try {
|
||||
Invoke-AutoUpdate $App $Dir $json $ver $matchesHashtable # 'autoupdate.ps1'
|
||||
Invoke-AutoUpdate $app $file $json $ver $matchesHashtable # 'autoupdate.ps1'
|
||||
} catch {
|
||||
if ($ThrowError) {
|
||||
throw $_
|
||||
|
||||
@@ -24,12 +24,12 @@ param(
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1"
|
||||
. "$PSScriptRoot\..\lib\description.ps1"
|
||||
|
||||
$Dir = Resolve-Path $Dir
|
||||
$Dir = Convert-Path $Dir
|
||||
$Queue = @()
|
||||
|
||||
Get-ChildItem $Dir "$App.json" | ForEach-Object {
|
||||
$manifest = parse_json "$Dir\$($_.Name)"
|
||||
$Queue += , @(($_.Name -replace '\.json$', ''), $manifest)
|
||||
Get-ChildItem $Dir -Filter "$App.json" -Recurse | ForEach-Object {
|
||||
$manifest = parse_json $_.FullName
|
||||
$Queue += , @($_.BaseName, $manifest)
|
||||
}
|
||||
|
||||
$Queue | ForEach-Object {
|
||||
|
||||
@@ -31,15 +31,14 @@ param(
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1"
|
||||
. "$PSScriptRoot\..\lib\json.ps1"
|
||||
|
||||
$Dir = Resolve-Path $Dir
|
||||
|
||||
Get-ChildItem $Dir "$App.json" | ForEach-Object {
|
||||
if ($PSVersionTable.PSVersion.Major -gt 5) { $_ = $_.Name } # Fix for pwsh
|
||||
$Dir = Convert-Path $Dir
|
||||
|
||||
Get-ChildItem $Dir -Filter "$App.json" -Recurse | ForEach-Object {
|
||||
$file = $_.FullName
|
||||
# beautify
|
||||
$json = parse_json "$Dir\$_" | ConvertToPrettyJson
|
||||
$json = parse_json $file | ConvertToPrettyJson
|
||||
|
||||
# convert to 4 spaces
|
||||
$json = $json -replace "`t", ' '
|
||||
[System.IO.File]::WriteAllLines("$Dir\$_", $json)
|
||||
[System.IO.File]::WriteAllLines($file, $json)
|
||||
}
|
||||
|
||||
@@ -41,10 +41,10 @@ if (Get-Command -Name 'scoop' -ErrorAction SilentlyContinue) {
|
||||
$dir = ensure (versiondir 'scoop' 'current')
|
||||
|
||||
# download scoop zip
|
||||
$zipurl = 'https://github.com/ScoopInstaller/Scoop/archive/master.zip'
|
||||
$zipfile = "$dir\scoop.zip"
|
||||
$zipUrl = 'https://github.com/ScoopInstaller/Scoop/archive/master.zip'
|
||||
$zipFile = "$dir\scoop.zip"
|
||||
Write-Output 'Downloading scoop...'
|
||||
dl $zipurl $zipfile
|
||||
Invoke-WebRequest -Uri $zipUrl -OutFile $zipFile
|
||||
|
||||
Write-Output 'Extracting...'
|
||||
Add-Type -Assembly "System.IO.Compression.FileSystem"
|
||||
@@ -57,11 +57,11 @@ shim "$dir\bin\scoop.ps1" $false
|
||||
|
||||
# download main bucket
|
||||
$dir = "$scoopdir\buckets\main"
|
||||
$zipurl = 'https://github.com/ScoopInstaller/Main/archive/master.zip'
|
||||
$zipfile = "$dir\main-bucket.zip"
|
||||
$zipUrl = 'https://github.com/ScoopInstaller/Main/archive/master.zip'
|
||||
$zipFile = "$dir\main-bucket.zip"
|
||||
Write-Output 'Downloading main bucket...'
|
||||
New-Item $dir -Type Directory -Force | Out-Null
|
||||
dl $zipurl $zipfile
|
||||
New-Item -Path $dir -Type Directory -Force | Out-Null
|
||||
Invoke-WebRequest -Uri $zipUrl -OutFile $zipFile
|
||||
|
||||
Write-Output 'Extracting...'
|
||||
[IO.Compression.ZipFile]::ExtractToDirectory($zipfile, "$dir\_tmp")
|
||||
@@ -70,7 +70,7 @@ Remove-Item "$dir\_tmp", $zipfile -Recurse -Force
|
||||
|
||||
ensure_robocopy_in_path
|
||||
|
||||
scoop config lastupdate ([System.DateTime]::Now.ToString('o'))
|
||||
set_config LAST_UPDATE ([System.DateTime]::Now.ToString('o')) | Out-Null
|
||||
success 'Scoop was installed successfully!'
|
||||
|
||||
Write-Output "Type 'scoop help' for instructions."
|
||||
|
||||
@@ -26,7 +26,7 @@ param(
|
||||
. "$PSScriptRoot\..\lib\core.ps1"
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1"
|
||||
|
||||
$Dir = Resolve-Path $Dir
|
||||
$Dir = Convert-Path $Dir
|
||||
|
||||
Write-Host '[' -NoNewLine
|
||||
Write-Host 'C' -NoNewLine -ForegroundColor Green
|
||||
@@ -36,8 +36,8 @@ Write-Host 'A' -NoNewLine -ForegroundColor Cyan
|
||||
Write-Host ']utoupdate'
|
||||
Write-Host ' | |'
|
||||
|
||||
Get-ChildItem $Dir "$App.json" | ForEach-Object {
|
||||
$json = parse_json "$Dir\$($_.Name)"
|
||||
Get-ChildItem $Dir -Filter "$App.json" -Recurse | ForEach-Object {
|
||||
$json = parse_json $_.FullName
|
||||
|
||||
if ($SkipSupported -and $json.checkver -and $json.autoupdate) { return }
|
||||
|
||||
@@ -48,5 +48,5 @@ Get-ChildItem $Dir "$App.json" | ForEach-Object {
|
||||
Write-Host '[' -NoNewLine
|
||||
Write-Host $(if ($json.autoupdate) { 'A' } else { ' ' }) -NoNewLine -ForegroundColor Cyan
|
||||
Write-Host '] ' -NoNewLine
|
||||
Write-Host (strip_ext $_.Name)
|
||||
Write-Host $_.BaseName
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ function get_hash_for_app([String] $app, $config, [String] $version, [String] $u
|
||||
write-host -f Green $basename -NoNewline
|
||||
write-host -f DarkYellow ' to compute hashes!'
|
||||
try {
|
||||
dl_with_cache $app $version $url $null $null $true
|
||||
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"
|
||||
@@ -449,7 +449,7 @@ function Invoke-AutoUpdate {
|
||||
# 'Set-Content -Encoding ASCII' don't works in PowerShell 5
|
||||
# Wait for 'UTF8NoBOM' Encoding in PowerShell 7
|
||||
# $Manifest | ConvertToPrettyJson | Set-Content -Path (Join-Path $Path "$AppName.json") -Encoding UTF8NoBOM
|
||||
[System.IO.File]::WriteAllLines((Join-Path $Path "$AppName.json"), (ConvertToPrettyJson $Manifest))
|
||||
[System.IO.File]::WriteAllLines($Path, (ConvertToPrettyJson $Manifest))
|
||||
# notes
|
||||
$note = "`nUpdating note:"
|
||||
if ($Manifest.autoupdate.note) {
|
||||
@@ -457,7 +457,7 @@ function Invoke-AutoUpdate {
|
||||
$hasNote = $true
|
||||
}
|
||||
if ($Manifest.autoupdate.architecture) {
|
||||
'64bit', '32bit' | ForEach-Object {
|
||||
'64bit', '32bit', 'arm64' | ForEach-Object {
|
||||
if ($Manifest.autoupdate.architecture.$_.note) {
|
||||
$note += "`n$_-arch: $($Manifest.autoupdate.architecture.$_.note)"
|
||||
$hasNote = $true
|
||||
|
||||
@@ -50,7 +50,7 @@ function known_buckets {
|
||||
}
|
||||
|
||||
function apps_in_bucket($dir) {
|
||||
return Get-ChildItem $dir | Where-Object { $_.Name.EndsWith('.json') } | ForEach-Object { $_.Name -replace '.json$', '' }
|
||||
return (Get-ChildItem $dir -Filter '*.json' -Recurse).BaseName
|
||||
}
|
||||
|
||||
function Get-LocalBucket {
|
||||
@@ -120,7 +120,7 @@ function add_bucket($name, $repo) {
|
||||
|
||||
$dir = Find-BucketDirectory $name -Root
|
||||
if (Test-Path $dir) {
|
||||
warn "The '$name' bucket already exists. Use 'scoop bucket rm $name' to remove it."
|
||||
warn "The '$name' bucket already exists. To add this bucket again, first remove it by running 'scoop bucket rm $name'."
|
||||
return 2
|
||||
}
|
||||
|
||||
|
||||
215
lib/core.ps1
215
lib/core.ps1
@@ -24,7 +24,7 @@ function Get-Encoding($wc) {
|
||||
}
|
||||
|
||||
function Get-UserAgent() {
|
||||
return "Scoop/1.0 (+http://scoop.sh/) PowerShell/$($PSVersionTable.PSVersion.Major).$($PSVersionTable.PSVersion.Minor) (Windows NT $([System.Environment]::OSVersion.Version.Major).$([System.Environment]::OSVersion.Version.Minor); $(if($env:PROCESSOR_ARCHITECTURE -eq 'AMD64'){'Win64; x64; '})$(if($env:PROCESSOR_ARCHITEW6432 -eq 'AMD64'){'WOW64; '})$PSEdition)"
|
||||
return "Scoop/1.0 (+http://scoop.sh/) PowerShell/$($PSVersionTable.PSVersion.Major).$($PSVersionTable.PSVersion.Minor) (Windows NT $([System.Environment]::OSVersion.Version.Major).$([System.Environment]::OSVersion.Version.Minor); $(if(${env:ProgramFiles(Arm)}){'ARM64; '}elseif($env:PROCESSOR_ARCHITECTURE -eq 'AMD64'){'Win64; x64; '})$(if($env:PROCESSOR_ARCHITEW6432 -in 'AMD64','ARM64'){'WOW64; '})$PSEdition)"
|
||||
}
|
||||
|
||||
function Show-DeprecatedWarning {
|
||||
@@ -59,6 +59,7 @@ function load_cfg($file) {
|
||||
}
|
||||
|
||||
function get_config($name, $default) {
|
||||
$name = $name.ToLowerInvariant()
|
||||
if($null -eq $scoopConfig.$name -and $null -ne $default) {
|
||||
return $default
|
||||
}
|
||||
@@ -72,6 +73,8 @@ function set_config {
|
||||
$value
|
||||
)
|
||||
|
||||
$name = $name.ToLowerInvariant()
|
||||
|
||||
if ($null -eq $scoopConfig -or $scoopConfig.Count -eq 0) {
|
||||
ensure (Split-Path -Path $configFile) | Out-Null
|
||||
$scoopConfig = New-Object -TypeName PSObject
|
||||
@@ -98,7 +101,7 @@ function set_config {
|
||||
|
||||
function setup_proxy() {
|
||||
# note: '@' and ':' in password must be escaped, e.g. 'p@ssword' -> p\@ssword'
|
||||
$proxy = get_config 'proxy'
|
||||
$proxy = get_config PROXY
|
||||
if(!$proxy) {
|
||||
return
|
||||
}
|
||||
@@ -126,7 +129,7 @@ function setup_proxy() {
|
||||
}
|
||||
|
||||
function git_cmd {
|
||||
$proxy = get_config 'proxy'
|
||||
$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"
|
||||
@@ -153,7 +156,7 @@ function error($msg) { write-host "ERROR $msg" -f darkred }
|
||||
function warn($msg) { write-host "WARN $msg" -f darkyellow }
|
||||
function info($msg) { write-host "INFO $msg" -f darkgray }
|
||||
function debug($obj) {
|
||||
if((get_config 'debug' $false) -ine 'true' -and $env:SCOOP_DEBUG -ine 'true') {
|
||||
if ((get_config DEBUG $false) -ine 'true' -and $env:SCOOP_DEBUG -ine 'true') {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -210,7 +213,7 @@ function appdir($app, $global) { "$(appsdir $global)\$app" }
|
||||
function versiondir($app, $version, $global) { "$(appdir $app $global)\$version" }
|
||||
|
||||
function currentdir($app, $global) {
|
||||
if (get_config NO_JUNCTIONS) {
|
||||
if (get_config NO_JUNCTION) {
|
||||
$version = Select-CurrentVersion -App $app -Global:$global
|
||||
} else {
|
||||
$version = 'current'
|
||||
@@ -225,8 +228,8 @@ function cache_path($app, $version, $url) { "$cachedir\$app#$version#$($url -rep
|
||||
|
||||
# apps
|
||||
function sanitary_path($path) { return [regex]::replace($path, "[/\\?:*<>|]", "") }
|
||||
function installed($app, $global) {
|
||||
if (-not $PSBoundParameters.ContainsKey('global')) {
|
||||
function installed($app, [Nullable[bool]]$global) {
|
||||
if ($null -eq $global) {
|
||||
return (installed $app $false) -or (installed $app $true)
|
||||
}
|
||||
# Dependencies of the format "bucket/dependency" install in a directory of form
|
||||
@@ -246,7 +249,7 @@ function installed_apps($global) {
|
||||
function failed($app, $global) {
|
||||
$app = ($app -split '/|\\')[-1]
|
||||
$appPath = appdir $app $global
|
||||
$hasCurrent = (get_config NO_JUNCTIONS) -or (Test-Path "$appPath\current")
|
||||
$hasCurrent = (get_config NO_JUNCTION) -or (Test-Path "$appPath\current")
|
||||
return (Test-Path $appPath) -and !($hasCurrent -and (installed $app $global))
|
||||
}
|
||||
|
||||
@@ -394,7 +397,7 @@ function app_status($app, $global) {
|
||||
|
||||
$status.outdated = $false
|
||||
if ($status.version -and $status.latest_version) {
|
||||
if (get_config 'force_update' $false) {
|
||||
if (get_config FORCE_UPDATE $false) {
|
||||
$status.outdated = ((Compare-Version -ReferenceVersion $status.version -DifferenceVersion $status.latest_version) -ne 0)
|
||||
} else {
|
||||
$status.outdated = ((Compare-Version -ReferenceVersion $status.version -DifferenceVersion $status.latest_version) -gt 0)
|
||||
@@ -507,12 +510,12 @@ function Invoke-ExternalCommand {
|
||||
}
|
||||
$Process = New-Object System.Diagnostics.Process
|
||||
$Process.StartInfo.FileName = $FilePath
|
||||
$Process.StartInfo.Arguments = ($ArgumentList | Select-Object -Unique) -join ' '
|
||||
$Process.StartInfo.UseShellExecute = $false
|
||||
if ($LogPath) {
|
||||
if ($FilePath -match '(^|\W)msiexec($|\W)') {
|
||||
$Process.StartInfo.Arguments += " /lwe `"$LogPath`""
|
||||
if ($FilePath -match '^msiexec(.exe)?$') {
|
||||
$ArgumentList += "/lwe `"$LogPath`""
|
||||
} else {
|
||||
$redirectToLogFile = $true
|
||||
$Process.StartInfo.RedirectStandardOutput = $true
|
||||
$Process.StartInfo.RedirectStandardError = $true
|
||||
}
|
||||
@@ -520,9 +523,32 @@ function Invoke-ExternalCommand {
|
||||
if ($RunAs) {
|
||||
$Process.StartInfo.UseShellExecute = $true
|
||||
$Process.StartInfo.Verb = 'RunAs'
|
||||
} else {
|
||||
$Process.StartInfo.CreateNoWindow = $true
|
||||
}
|
||||
if ($FilePath -match '^((cmd|cscript|wscript|msiexec)(\.exe)?|.*\.(bat|cmd|js|vbs|wsf))$') {
|
||||
$Process.StartInfo.Arguments = $ArgumentList -join ' '
|
||||
} elseif ($Process.StartInfo.ArgumentList.Add) {
|
||||
# ArgumentList is supported in PowerShell 6.1 and later (built on .NET Core 2.1+)
|
||||
# ref-1: https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.processstartinfo.argumentlist?view=net-6.0
|
||||
# ref-2: https://docs.microsoft.com/en-us/powershell/scripting/whats-new/differences-from-windows-powershell?view=powershell-7.2#net-framework-vs-net-core
|
||||
$ArgumentList | ForEach-Object { $Process.StartInfo.ArgumentList.Add($_) }
|
||||
} else {
|
||||
# escape arguments manually in lower versions, refer to https://docs.microsoft.com/en-us/previous-versions/17w5ykft(v=vs.85)
|
||||
$escapedArgs = $ArgumentList | ForEach-Object {
|
||||
# escape N consecutive backslash(es), which are followed by a double quote, to 2N consecutive ones
|
||||
$s = $_ -replace '(\\+)"', '$1$1"'
|
||||
# escape N consecutive backslash(es), which are at the end of the string, to 2N consecutive ones
|
||||
$s = $s -replace '(\\+)$', '$1$1'
|
||||
# escape double quotes
|
||||
$s = $s -replace '"', '\"'
|
||||
# quote the argument
|
||||
"`"$s`""
|
||||
}
|
||||
$Process.StartInfo.Arguments = $escapedArgs -join ' '
|
||||
}
|
||||
try {
|
||||
$Process.Start() | Out-Null
|
||||
[void]$Process.Start()
|
||||
} catch {
|
||||
if ($Activity) {
|
||||
Write-Host "error." -ForegroundColor DarkRed
|
||||
@@ -530,11 +556,17 @@ function Invoke-ExternalCommand {
|
||||
error $_.Exception.Message
|
||||
return $false
|
||||
}
|
||||
if ($LogPath -and ($FilePath -notmatch '(^|\W)msiexec($|\W)')) {
|
||||
Out-UTF8File -FilePath $LogPath -Append -InputObject $Process.StandardOutput.ReadToEnd()
|
||||
Out-UTF8File -FilePath $LogPath -Append -InputObject $Process.StandardError.ReadToEnd()
|
||||
if ($redirectToLogFile) {
|
||||
# we do this to remove a deadlock potential
|
||||
# ref: https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.process.standardoutput?view=netframework-4.5#remarks
|
||||
$stdoutTask = $Process.StandardOutput.ReadToEndAsync()
|
||||
$stderrTask = $Process.StandardError.ReadToEndAsync()
|
||||
}
|
||||
$Process.WaitForExit()
|
||||
if ($redirectToLogFile) {
|
||||
Out-UTF8File -FilePath $LogPath -Append -InputObject $stdoutTask.Result
|
||||
Out-UTF8File -FilePath $LogPath -Append -InputObject $stderrTask.Result
|
||||
}
|
||||
if ($Process.ExitCode -ne 0) {
|
||||
if ($ContinueExitCodes -and ($ContinueExitCodes.ContainsKey($Process.ExitCode))) {
|
||||
if ($Activity) {
|
||||
@@ -556,13 +588,6 @@ function Invoke-ExternalCommand {
|
||||
return $true
|
||||
}
|
||||
|
||||
function dl($url,$to) {
|
||||
$wc = New-Object Net.Webclient
|
||||
$wc.headers.add('Referer', (strip_filename $url))
|
||||
$wc.Headers.Add('User-Agent', (Get-UserAgent))
|
||||
$wc.downloadFile($url,$to)
|
||||
}
|
||||
|
||||
function env($name,$global,$val='__get') {
|
||||
$target = 'User'; if($global) {$target = 'Machine'}
|
||||
if($val -eq '__get') { [environment]::getEnvironmentVariable($name,$target) }
|
||||
@@ -604,12 +629,12 @@ function movedir($from, $to) {
|
||||
$proc.StartInfo.RedirectStandardError = $true
|
||||
$proc.StartInfo.UseShellExecute = $false
|
||||
$proc.StartInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
|
||||
$proc.Start()
|
||||
$out = $proc.StandardOutput.ReadToEnd()
|
||||
[void]$proc.Start()
|
||||
$stdoutTask = $proc.StandardOutput.ReadToEndAsync()
|
||||
$proc.WaitForExit()
|
||||
|
||||
if($proc.ExitCode -ge 8) {
|
||||
debug $out
|
||||
debug $stdoutTask.Result
|
||||
throw "Could not find '$(fname $from)'! (error $($proc.ExitCode))"
|
||||
}
|
||||
|
||||
@@ -685,7 +710,7 @@ function shim($path, $global, $name, $arg) {
|
||||
Push-Location $abs_shimdir
|
||||
$relative_path = Resolve-Path -Relative $path
|
||||
Pop-Location
|
||||
$resolved_path = Resolve-Path $path
|
||||
$resolved_path = Convert-Path $path
|
||||
|
||||
if ($path -match '\.(exe|com)$') {
|
||||
# for programs with no awareness of any shell
|
||||
@@ -801,7 +826,7 @@ function shim($path, $global, $name, $arg) {
|
||||
|
||||
function get_shim_path() {
|
||||
$shim_path = "$(versiondir 'scoop' 'current')\supporting\shims\kiennq\shim.exe"
|
||||
$shim_version = get_config 'shim' 'default'
|
||||
$shim_version = get_config SHIM 'default'
|
||||
switch ($shim_version) {
|
||||
'71' { $shim_path = "$(versiondir 'scoop' 'current')\supporting\shims\71\shim.exe"; Break }
|
||||
'scoopcs' { $shim_path = "$(versiondir 'scoop' 'current')\supporting\shimexe\bin\shim.exe"; Break }
|
||||
@@ -832,15 +857,38 @@ function ensure_in_path($dir, $global) {
|
||||
}
|
||||
}
|
||||
|
||||
function ensure_architecture($architecture_opt) {
|
||||
if(!$architecture_opt) {
|
||||
return default_architecture
|
||||
function Get-DefaultArchitecture {
|
||||
$arch = get_config DEFAULT_ARCHITECTURE
|
||||
$system = if (${env:ProgramFiles(Arm)}) {
|
||||
'arm64'
|
||||
} elseif ([System.Environment]::Is64BitOperatingSystem) {
|
||||
'64bit'
|
||||
} else {
|
||||
'32bit'
|
||||
}
|
||||
$architecture_opt = $architecture_opt.ToString().ToLower()
|
||||
switch($architecture_opt) {
|
||||
if ($null -eq $arch) {
|
||||
$arch = $system
|
||||
} else {
|
||||
try {
|
||||
$arch = Format-ArchitectureString $arch
|
||||
} catch {
|
||||
warn 'Invalid default architecture configured. Determining default system architecture'
|
||||
$arch = $system
|
||||
}
|
||||
}
|
||||
return $arch
|
||||
}
|
||||
|
||||
function Format-ArchitectureString($Architecture) {
|
||||
if (!$Architecture) {
|
||||
return Get-DefaultArchitecture
|
||||
}
|
||||
$Architecture = $Architecture.ToString().ToLower()
|
||||
switch ($Architecture) {
|
||||
{ @('64bit', '64', 'x64', 'amd64', 'x86_64', 'x86-64') -contains $_ } { return '64bit' }
|
||||
{ @('32bit', '32', 'x86', 'i386', '386', 'i686') -contains $_ } { return '32bit' }
|
||||
default { throw [System.ArgumentException] "Invalid architecture: '$architecture_opt'"}
|
||||
{ @('arm64', 'arm', 'aarch64') -contains $_ } { return 'arm64' }
|
||||
default { throw [System.ArgumentException] "Invalid architecture: '$Architecture'" }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -967,29 +1015,39 @@ function show_app($app, $bucket, $version) {
|
||||
return $app
|
||||
}
|
||||
|
||||
function last_scoop_update() {
|
||||
# PowerShell 6 returns an DateTime Object
|
||||
$last_update = (get_config lastupdate)
|
||||
|
||||
if ($null -ne $last_update -and $last_update.GetType() -eq [System.String]) {
|
||||
try {
|
||||
$last_update = [System.DateTime]::Parse($last_update)
|
||||
} catch {
|
||||
$last_update = $null
|
||||
}
|
||||
}
|
||||
return $last_update
|
||||
}
|
||||
|
||||
function is_scoop_outdated() {
|
||||
$last_update = $(last_scoop_update)
|
||||
$now = [System.DateTime]::Now
|
||||
if($null -eq $last_update) {
|
||||
set_config lastupdate $now.ToString('o')
|
||||
# enforce an update for the first time
|
||||
try {
|
||||
$expireHour = (New-TimeSpan (get_config LAST_UPDATE) $now).TotalHours
|
||||
return ($expireHour -ge 3)
|
||||
} catch {
|
||||
# If not System.DateTime
|
||||
set_config LAST_UPDATE ($now.ToString('o')) | Out-Null
|
||||
return $true
|
||||
}
|
||||
return $last_update.AddHours(3) -lt $now.ToLocalTime()
|
||||
}
|
||||
|
||||
function Test-ScoopCoreOnHold() {
|
||||
$hold_update_until = get_config HOLD_UPDATE_UNTIL
|
||||
if ($null -eq $hold_update_until) {
|
||||
return $false
|
||||
}
|
||||
$parsed_date = New-Object -TypeName DateTime
|
||||
if ([System.DateTime]::TryParse($hold_update_until, $null, [System.Globalization.DateTimeStyles]::AssumeLocal, [ref]$parsed_date)) {
|
||||
if ((New-TimeSpan $parsed_date).TotalSeconds -lt 0) {
|
||||
warn "Skipping self-update of Scoop Core until $($parsed_date.ToLocalTime())..."
|
||||
warn "If you want to update Scoop Core immediately, use 'scoop unhold scoop; scoop update'."
|
||||
return $true
|
||||
} else {
|
||||
warn 'Self-update of Scoop Core is enabled again!'
|
||||
}
|
||||
} else {
|
||||
error "'hold_update_until' has been set in the wrong format and was removed."
|
||||
error 'If you want to disable self-update of Scoop Core for a moment,'
|
||||
error "use 'scoop hold scoop' or 'scoop config hold_update_until <YYYY-MM-DD>/<YYYY/MM/DD>'."
|
||||
}
|
||||
set_config HOLD_UPDATE_UNTIL $null | Out-Null
|
||||
return $false
|
||||
}
|
||||
|
||||
function substitute($entity, [Hashtable] $params, [Bool]$regexEscape = $false) {
|
||||
@@ -1057,7 +1115,7 @@ function get_hash([String] $multihash) {
|
||||
}
|
||||
|
||||
function Get-GitHubToken {
|
||||
return $env:SCOOP_GH_TOKEN, (get_config 'gh_token') | Where-Object -Property Length -Value 0 -GT | Select-Object -First 1
|
||||
return $env:SCOOP_GH_TOKEN, (get_config GH_TOKEN) | Where-Object -Property Length -Value 0 -GT | Select-Object -First 1
|
||||
}
|
||||
|
||||
function handle_special_urls($url)
|
||||
@@ -1157,31 +1215,56 @@ function Out-UTF8File {
|
||||
# for all communication with api.github.com
|
||||
Optimize-SecurityProtocol
|
||||
|
||||
# Scoop config file migration
|
||||
# Load Scoop config
|
||||
$configHome = $env:XDG_CONFIG_HOME, "$env:USERPROFILE\.config" | Select-Object -First 1
|
||||
$configFile = "$configHome\scoop\config.json"
|
||||
if ((Test-Path "$env:USERPROFILE\.scoop") -and !(Test-Path $configFile)) {
|
||||
New-Item -ItemType Directory (Split-Path -Path $configFile) -ErrorAction Ignore | Out-Null
|
||||
Move-Item "$env:USERPROFILE\.scoop" $configFile
|
||||
write-host "WARN Scoop configuration has been migrated from '~/.scoop'" -f darkyellow
|
||||
write-host "WARN to '$configFile'" -f darkyellow
|
||||
}
|
||||
|
||||
# Load Scoop config
|
||||
$scoopConfig = load_cfg $configFile
|
||||
|
||||
# NOTE Scoop config file migration. Remove this after 2023/6/30
|
||||
if ($scoopConfig) {
|
||||
$newConfigNames = @{
|
||||
'lastUpdate' = 'last_update'
|
||||
'SCOOP_REPO' = 'scoop_repo'
|
||||
'SCOOP_BRANCH' = 'scoop_branch'
|
||||
'7ZIPEXTRACT_USE_EXTERNAL' = 'use_external_7zip'
|
||||
'MSIEXTRACT_USE_LESSMSI' = 'use_lessmsi'
|
||||
'NO_JUNCTIONS' = 'no_junction'
|
||||
'manifest_review' = 'show_manifest'
|
||||
'rootPath' = 'root_path'
|
||||
'globalPath' = 'global_path'
|
||||
'cachePath' = 'cache_path'
|
||||
}
|
||||
$newConfigNames.GetEnumerator() | ForEach-Object {
|
||||
if ($null -ne $scoopConfig.$($_.Key)) {
|
||||
$value = $scoopConfig.$($_.Key)
|
||||
$scoopConfig.PSObject.Properties.Remove($_.Key)
|
||||
$scoopConfig | Add-Member -MemberType NoteProperty -Name $_.Value -Value $value
|
||||
if ($_.Key -eq 'lastUpdate') {
|
||||
$scoopConfigChg = $true
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($scoopConfigChg) { # Only save config file if there was a change
|
||||
ConvertTo-Json $scoopConfig | Out-UTF8File -FilePath $configFile
|
||||
}
|
||||
}
|
||||
# END NOTE
|
||||
|
||||
# Scoop root directory
|
||||
$scoopdir = $env:SCOOP, (get_config 'rootPath'), "$env:USERPROFILE\scoop" | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -First 1
|
||||
$scoopdir = $env:SCOOP, (get_config ROOT_PATH), "$env:USERPROFILE\scoop" | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -First 1
|
||||
|
||||
# Scoop global apps directory
|
||||
$globaldir = $env:SCOOP_GLOBAL, (get_config 'globalPath'), "$env:ProgramData\scoop" | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -first 1
|
||||
$globaldir = $env:SCOOP_GLOBAL, (get_config GLOBAL_PATH), "$env:ProgramData\scoop" | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -First 1
|
||||
|
||||
# Scoop cache directory
|
||||
# Note: Setting the SCOOP_CACHE environment variable to use a shared directory
|
||||
# is experimental and untested. There may be concurrency issues when
|
||||
# multiple users write and access cached files at the same time.
|
||||
# Use at your own risk.
|
||||
$cachedir = $env:SCOOP_CACHE, (get_config 'cachePath'), "$scoopdir\cache" | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -first 1
|
||||
$cachedir = $env:SCOOP_CACHE, (get_config CACHE_PATH), "$scoopdir\cache" | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -First 1
|
||||
|
||||
# OS information
|
||||
$WindowsBuild = [System.Environment]::OSVersion.Version.Build
|
||||
|
||||
# Setup proxy globally
|
||||
setup_proxy
|
||||
|
||||
@@ -18,20 +18,20 @@ function Expand-7zipArchive {
|
||||
[Switch]
|
||||
$Removal
|
||||
)
|
||||
if ((get_config 7ZIPEXTRACT_USE_EXTERNAL)) {
|
||||
if ((get_config USE_EXTERNAL_7ZIP)) {
|
||||
try {
|
||||
$7zPath = (Get-Command '7z' -CommandType Application -ErrorAction Stop | Select-Object -First 1).Source
|
||||
} catch [System.Management.Automation.CommandNotFoundException] {
|
||||
abort "`nCannot find external 7-Zip (7z.exe) while '7ZIPEXTRACT_USE_EXTERNAL' is 'true'!`nRun 'scoop config 7ZIPEXTRACT_USE_EXTERNAL false' or install 7-Zip manually and try again."
|
||||
abort "`nCannot find external 7-Zip (7z.exe) while 'use_external_7zip' is 'true'!`nRun 'scoop config use_external_7zip false' or install 7-Zip manually and try again."
|
||||
}
|
||||
} else {
|
||||
$7zPath = Get-HelperPath -Helper 7zip
|
||||
}
|
||||
$LogPath = "$(Split-Path $Path)\7zip.log"
|
||||
$ArgList = @('x', "`"$Path`"", "-o`"$DestinationPath`"", '-y')
|
||||
$ArgList = @('x', $Path, "-o$DestinationPath", '-y')
|
||||
$IsTar = ((strip_ext $Path) -match '\.tar$') -or ($Path -match '\.t[abgpx]z2?$')
|
||||
if (!$IsTar -and $ExtractDir) {
|
||||
$ArgList += "-ir!`"$ExtractDir\*`""
|
||||
$ArgList += "-ir!$ExtractDir\*"
|
||||
}
|
||||
if ($Switches) {
|
||||
$ArgList += (-split $Switches)
|
||||
@@ -53,7 +53,7 @@ function Expand-7zipArchive {
|
||||
}
|
||||
if ($IsTar) {
|
||||
# Check for tar
|
||||
$Status = Invoke-ExternalCommand $7zPath @('l', "`"$Path`"") -LogPath $LogPath
|
||||
$Status = Invoke-ExternalCommand $7zPath @('l', $Path) -LogPath $LogPath
|
||||
if ($Status) {
|
||||
# get inner tar file name
|
||||
$TarFile = (Select-String -Path $LogPath -Pattern '[^ ]*tar$').Matches.Value
|
||||
@@ -97,7 +97,7 @@ function Expand-ZstdArchive {
|
||||
$LogPath = Join-Path (Split-Path $Path) 'zstd.log'
|
||||
$DestinationPath = $DestinationPath.TrimEnd('\')
|
||||
ensure $DestinationPath | Out-Null
|
||||
$ArgList = @('-d', "`"$Path`"", '--output-dir-flat', "`"$DestinationPath`"", '-f', '-v')
|
||||
$ArgList = @('-d', $Path, '--output-dir-flat', $DestinationPath, '-f', '-v')
|
||||
|
||||
if ($Switches) {
|
||||
$ArgList += (-split $Switches)
|
||||
@@ -146,12 +146,12 @@ function Expand-MsiArchive {
|
||||
$OriDestinationPath = $DestinationPath
|
||||
$DestinationPath = "$DestinationPath\_tmp"
|
||||
}
|
||||
if ((get_config MSIEXTRACT_USE_LESSMSI)) {
|
||||
if ((get_config USE_LESSMSI)) {
|
||||
$MsiPath = Get-HelperPath -Helper Lessmsi
|
||||
$ArgList = @('x', "`"$Path`"", "`"$DestinationPath\\`"")
|
||||
$ArgList = @('x', $Path, "$DestinationPath\")
|
||||
} else {
|
||||
$MsiPath = 'msiexec.exe'
|
||||
$ArgList = @('/a', "`"$Path`"", '/qn', "TARGETDIR=`"$DestinationPath\\SourceDir`"")
|
||||
$ArgList = @('/a', "`"$Path`"", '/qn', "TARGETDIR=`"$DestinationPath\SourceDir`"")
|
||||
}
|
||||
$LogPath = "$(Split-Path $Path)\msi.log"
|
||||
if ($Switches) {
|
||||
@@ -200,7 +200,7 @@ function Expand-InnoArchive {
|
||||
$Removal
|
||||
)
|
||||
$LogPath = "$(Split-Path $Path)\innounp.log"
|
||||
$ArgList = @('-x', "-d`"$DestinationPath`"", "`"$Path`"", '-y')
|
||||
$ArgList = @('-x', "-d$DestinationPath", $Path, '-y')
|
||||
switch -Regex ($ExtractDir) {
|
||||
'^[^{].*' { $ArgList += "-c{app}\$ExtractDir" }
|
||||
'^{.*' { $ArgList += "-c$ExtractDir" }
|
||||
@@ -267,7 +267,7 @@ function Expand-DarkArchive {
|
||||
$Removal
|
||||
)
|
||||
$LogPath = "$(Split-Path $Path)\dark.log"
|
||||
$ArgList = @('-nologo', "-x `"$DestinationPath`"", "`"$Path`"")
|
||||
$ArgList = @('-nologo', '-x', $DestinationPath, $Path)
|
||||
if ($Switches) {
|
||||
$ArgList += (-split $Switches)
|
||||
}
|
||||
|
||||
@@ -106,10 +106,10 @@ function Get-InstallationHelper {
|
||||
$installer = arch_specific 'installer' $Manifest $Architecture
|
||||
$post_install = arch_specific 'post_install' $Manifest $Architecture
|
||||
$script = $pre_install + $installer.script + $post_install
|
||||
if (((Test-7zipRequirement -Uri $url) -or ($script -like '*Expand-7zipArchive *')) -and !(get_config 7ZIPEXTRACT_USE_EXTERNAL)) {
|
||||
if (((Test-7zipRequirement -Uri $url) -or ($script -like '*Expand-7zipArchive *')) -and !(get_config USE_EXTERNAL_7ZIP)) {
|
||||
$helper += '7zip'
|
||||
}
|
||||
if (((Test-LessmsiRequirement -Uri $url) -or ($script -like '*Expand-MsiArchive *')) -and (get_config MSIEXTRACT_USE_LESSMSI)) {
|
||||
if (((Test-LessmsiRequirement -Uri $url) -or ($script -like '*Expand-MsiArchive *')) -and (get_config USE_LESSMSI)) {
|
||||
$helper += 'lessmsi'
|
||||
}
|
||||
if ($Manifest.innosetup -or ($script -like '*Expand-InnoArchive *')) {
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
# array of strings that are long-form options. options that take
|
||||
# a parameter should end with '='
|
||||
# returns @(opts hash, remaining_args array, error string)
|
||||
# NOTES:
|
||||
# The first "--" in $argv, if any, will terminate all options; any
|
||||
# following arguments are treated as non-option arguments, even if
|
||||
# they begin with a hyphen. The "--" itself will not be included in
|
||||
# the returned $opts. (POSIX-compatible)
|
||||
function getopt($argv, $shortopts, $longopts) {
|
||||
$opts = @{}; $rem = @()
|
||||
|
||||
@@ -16,29 +21,35 @@ function getopt($argv, $shortopts, $longopts) {
|
||||
}
|
||||
|
||||
function regex_escape($str) {
|
||||
return [regex]::escape($str)
|
||||
return [Regex]::Escape($str)
|
||||
}
|
||||
|
||||
# ensure these are arrays
|
||||
$argv = @($argv)
|
||||
$longopts = @($longopts)
|
||||
|
||||
for($i = 0; $i -lt $argv.length; $i++) {
|
||||
for ($i = 0; $i -lt $argv.Length; $i++) {
|
||||
$arg = $argv[$i]
|
||||
if ($null -eq $arg) { continue }
|
||||
# don't try to parse array arguments
|
||||
if($arg -is [array]) { $rem += ,$arg; continue }
|
||||
if($arg -is [int]) { $rem += $arg; continue }
|
||||
if($arg -is [decimal]) { $rem += $arg; continue }
|
||||
if ($arg -is [Array]) { $rem += , $arg; continue }
|
||||
if ($arg -is [Int]) { $rem += $arg; continue }
|
||||
if ($arg -is [Decimal]) { $rem += $arg; continue }
|
||||
|
||||
if($arg.startswith('--')) {
|
||||
$name = $arg.substring(2)
|
||||
if ($arg -eq '--') {
|
||||
if ($i -lt $argv.Length - 1) {
|
||||
$rem += $argv[($i + 1)..($argv.Length - 1)]
|
||||
}
|
||||
break
|
||||
} elseif ($arg.StartsWith('--')) {
|
||||
$name = $arg.Substring(2)
|
||||
|
||||
$longopt = $longopts | Where-Object { $_ -match "^$name=?$" }
|
||||
|
||||
if ($longopt) {
|
||||
if($longopt.endswith('=')) { # requires arg
|
||||
if($i -eq $argv.length - 1) {
|
||||
if ($longopt.EndsWith('=')) {
|
||||
# requires arg
|
||||
if ($i -eq $argv.Length - 1) {
|
||||
return err "Option --$name requires an argument."
|
||||
}
|
||||
$opts.$name = $argv[++$i]
|
||||
@@ -48,14 +59,14 @@ function getopt($argv, $shortopts, $longopts) {
|
||||
} else {
|
||||
return err "Option --$name not recognized."
|
||||
}
|
||||
} elseif($arg.startswith('-') -and $arg -ne '-') {
|
||||
for($j = 1; $j -lt $arg.length; $j++) {
|
||||
$letter = $arg[$j].tostring()
|
||||
} elseif ($arg.StartsWith('-') -and $arg -ne '-') {
|
||||
for ($j = 1; $j -lt $arg.Length; $j++) {
|
||||
$letter = $arg[$j].ToString()
|
||||
|
||||
if ($shortopts -match "$(regex_escape $letter)`:?") {
|
||||
$shortopt = $matches[0]
|
||||
$shortopt = $Matches[0]
|
||||
if ($shortopt[1] -eq ':') {
|
||||
if($j -ne $arg.length -1 -or $i -eq $argv.length - 1) {
|
||||
if ($j -ne $arg.Length - 1 -or $i -eq $argv.Length - 1) {
|
||||
return err "Option -$letter requires an argument."
|
||||
}
|
||||
$opts.$letter = $argv[++$i]
|
||||
|
||||
@@ -25,14 +25,15 @@ function install_app($app, $architecture, $global, $suggested, $use_cache = $tru
|
||||
$check_hash = $false
|
||||
}
|
||||
|
||||
if(!(supports_architecture $manifest $architecture)) {
|
||||
write-host -f DarkRed "'$app' doesn't support $architecture architecture!"
|
||||
$architecture = Get-SupportedArchitecture $manifest $architecture
|
||||
if ($null -eq $architecture) {
|
||||
error "'$app' doesn't support current architecture!"
|
||||
return
|
||||
}
|
||||
|
||||
if ((get_config 'manifest_review' $false) -and ($MyInvocation.ScriptName -notlike '*scoop-update*')) {
|
||||
if ((get_config SHOW_MANIFEST $false) -and ($MyInvocation.ScriptName -notlike '*scoop-update*')) {
|
||||
Write-Host "Manifest: $app.json"
|
||||
$style = get_config cat_style
|
||||
$style = get_config CAT_STYLE
|
||||
if ($style) {
|
||||
$manifest | ConvertToPrettyJson | bat --no-paging --style $style --language json
|
||||
} else {
|
||||
@@ -43,13 +44,13 @@ function install_app($app, $architecture, $global, $suggested, $use_cache = $tru
|
||||
return
|
||||
}
|
||||
}
|
||||
write-output "Installing '$app' ($version) [$architecture]"
|
||||
Write-Output "Installing '$app' ($version) [$architecture]$(if ($bucket) { " from $bucket bucket" })"
|
||||
|
||||
$dir = ensure (versiondir $app $version $global)
|
||||
$original_dir = $dir # keep reference to real (not linked) directory
|
||||
$persist_dir = persistdir $app $global
|
||||
|
||||
$fname = dl_urls $app $version $manifest $bucket $architecture $dir $use_cache $check_hash
|
||||
$fname = Invoke-ScoopDownload $app $version $manifest $bucket $architecture $dir $use_cache $check_hash
|
||||
Invoke-HookScript -HookType 'pre_install' -Manifest $manifest -Arch $architecture
|
||||
|
||||
run_installer $fname $manifest $architecture $dir $global
|
||||
@@ -80,27 +81,31 @@ function install_app($app, $architecture, $global, $suggested, $use_cache = $tru
|
||||
show_notes $manifest $dir $original_dir $persist_dir
|
||||
}
|
||||
|
||||
function dl_with_cache($app, $version, $url, $to, $cookies = $null, $use_cache = $true) {
|
||||
function Invoke-CachedDownload ($app, $version, $url, $to, $cookies = $null, $use_cache = $true) {
|
||||
$cached = fullpath (cache_path $app $version $url)
|
||||
|
||||
if(!(test-path $cached) -or !$use_cache) {
|
||||
ensure $cachedir | Out-Null
|
||||
do_dl $url "$cached.download" $cookies
|
||||
Start-Download $url "$cached.download" $cookies
|
||||
Move-Item "$cached.download" $cached -force
|
||||
} else { write-host "Loading $(url_remote_filename $url) from cache"}
|
||||
|
||||
if (!($null -eq $to)) {
|
||||
if ($use_cache) {
|
||||
Copy-Item $cached $to
|
||||
} else {
|
||||
Move-Item $cached $to -Force
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function do_dl($url, $to, $cookies) {
|
||||
function Start-Download ($url, $to, $cookies) {
|
||||
$progress = [console]::isoutputredirected -eq $false -and
|
||||
$host.name -ne 'Windows PowerShell ISE Host'
|
||||
|
||||
try {
|
||||
$url = handle_special_urls $url
|
||||
dl $url $to $cookies $progress
|
||||
Invoke-Download $url $to $cookies $progress
|
||||
} catch {
|
||||
$e = $_.exception
|
||||
if($e.innerexception) { $e = $e.innerexception }
|
||||
@@ -175,7 +180,7 @@ function get_filename_from_metalink($file) {
|
||||
return $filename
|
||||
}
|
||||
|
||||
function dl_with_cache_aria2($app, $version, $manifest, $architecture, $dir, $cookies = $null, $use_cache = $true, $check_hash = $true) {
|
||||
function Invoke-CachedAria2Download ($app, $version, $manifest, $architecture, $dir, $cookies = $null, $use_cache = $true, $check_hash = $true) {
|
||||
$data = @{}
|
||||
$urls = @(script:url $manifest $architecture)
|
||||
|
||||
@@ -210,7 +215,7 @@ function dl_with_cache_aria2($app, $version, $manifest, $architecture, $dir, $co
|
||||
$options += "--header='Cookie: $(cookie_header $cookies)'"
|
||||
}
|
||||
|
||||
$proxy = get_config 'proxy'
|
||||
$proxy = get_config PROXY
|
||||
if ($proxy -ne 'none') {
|
||||
if ([Net.Webrequest]::DefaultWebProxy.Address) {
|
||||
$options += "--all-proxy='$([Net.Webrequest]::DefaultWebProxy.Address.Authority)'"
|
||||
@@ -351,7 +356,7 @@ function dl_with_cache_aria2($app, $version, $manifest, $architecture, $dir, $co
|
||||
}
|
||||
|
||||
# download with filesize and progress indicator
|
||||
function dl($url, $to, $cookies, $progress) {
|
||||
function Invoke-Download ($url, $to, $cookies, $progress) {
|
||||
$reqUrl = ($url -split '#')[0]
|
||||
$wreq = [Net.WebRequest]::Create($reqUrl)
|
||||
if ($wreq -is [Net.HttpWebRequest]) {
|
||||
@@ -367,7 +372,7 @@ function dl($url, $to, $cookies, $progress) {
|
||||
$wreq.Headers.Add('Cookie', (cookie_header $cookies))
|
||||
}
|
||||
|
||||
get_config 'private_hosts' | Where-Object { $_ -ne $null -and $url -match $_.match } | ForEach-Object {
|
||||
get_config PRIVATE_HOSTS | Where-Object { $_ -ne $null -and $url -match $_.match } | ForEach-Object {
|
||||
(ConvertFrom-StringData -StringData $_.Headers).GetEnumerator() | ForEach-Object {
|
||||
$wreq.Headers[$_.Key] = $_.Value
|
||||
}
|
||||
@@ -405,7 +410,7 @@ function dl($url, $to, $cookies, $progress) {
|
||||
$newUrl = "$newUrl#/$postfix"
|
||||
}
|
||||
|
||||
dl $newUrl $to $cookies $progress
|
||||
Invoke-Download $newUrl $to $cookies $progress
|
||||
return
|
||||
}
|
||||
|
||||
@@ -416,12 +421,12 @@ function dl($url, $to, $cookies, $progress) {
|
||||
|
||||
if ($progress -and ($total -gt 0)) {
|
||||
[console]::CursorVisible = $false
|
||||
function dl_onProgress($read) {
|
||||
dl_progress $read $total $url
|
||||
function Trace-DownloadProgress ($read) {
|
||||
Write-DownloadProgress $read $total $url
|
||||
}
|
||||
} else {
|
||||
write-host "Downloading $url ($(filesize $total))..."
|
||||
function dl_onProgress {
|
||||
function Trace-DownloadProgress {
|
||||
#no op
|
||||
}
|
||||
}
|
||||
@@ -433,17 +438,17 @@ function dl($url, $to, $cookies, $progress) {
|
||||
$totalRead = 0
|
||||
$sw = [diagnostics.stopwatch]::StartNew()
|
||||
|
||||
dl_onProgress $totalRead
|
||||
Trace-DownloadProgress $totalRead
|
||||
while(($read = $s.read($buffer, 0, $buffer.length)) -gt 0) {
|
||||
$fs.write($buffer, 0, $read)
|
||||
$totalRead += $read
|
||||
if ($sw.elapsedmilliseconds -gt 100) {
|
||||
$sw.restart()
|
||||
dl_onProgress $totalRead
|
||||
Trace-DownloadProgress $totalRead
|
||||
}
|
||||
}
|
||||
$sw.stop()
|
||||
dl_onProgress $totalRead
|
||||
Trace-DownloadProgress $totalRead
|
||||
} finally {
|
||||
if ($progress) {
|
||||
[console]::CursorVisible = $true
|
||||
@@ -459,7 +464,7 @@ function dl($url, $to, $cookies, $progress) {
|
||||
}
|
||||
}
|
||||
|
||||
function dl_progress_output($url, $read, $total, $console) {
|
||||
function Format-DownloadProgress ($url, $read, $total, $console) {
|
||||
$filename = url_remote_filename $url
|
||||
|
||||
# calculate current percentage done
|
||||
@@ -498,14 +503,14 @@ function dl_progress_output($url, $read, $total, $console) {
|
||||
"$left [$dashes$spaces] $right"
|
||||
}
|
||||
|
||||
function dl_progress($read, $total, $url) {
|
||||
function Write-DownloadProgress ($read, $total, $url) {
|
||||
$console = $host.UI.RawUI;
|
||||
$left = $console.CursorPosition.X;
|
||||
$top = $console.CursorPosition.Y;
|
||||
$width = $console.BufferSize.Width;
|
||||
|
||||
if($read -eq 0) {
|
||||
$maxOutputLength = $(dl_progress_output $url 100 $total $console).length
|
||||
$maxOutputLength = $(Format-DownloadProgress $url 100 $total $console).length
|
||||
if (($left + $maxOutputLength) -gt $width) {
|
||||
# not enough room to print progress on this line
|
||||
# print on new line
|
||||
@@ -516,11 +521,11 @@ function dl_progress($read, $total, $url) {
|
||||
}
|
||||
}
|
||||
|
||||
write-host $(dl_progress_output $url $read $total $console) -nonewline
|
||||
write-host $(Format-DownloadProgress $url $read $total $console) -nonewline
|
||||
[console]::SetCursorPosition($left, $top)
|
||||
}
|
||||
|
||||
function dl_urls($app, $version, $manifest, $bucket, $architecture, $dir, $use_cache = $true, $check_hash = $true) {
|
||||
function Invoke-ScoopDownload ($app, $version, $manifest, $bucket, $architecture, $dir, $use_cache = $true, $check_hash = $true) {
|
||||
# we only want to show this warning once
|
||||
if(!$use_cache) { warn "Cache is being ignored." }
|
||||
|
||||
@@ -541,13 +546,13 @@ function dl_urls($app, $version, $manifest, $bucket, $architecture, $dir, $use_c
|
||||
|
||||
# download first
|
||||
if(Test-Aria2Enabled) {
|
||||
dl_with_cache_aria2 $app $version $manifest $architecture $dir $cookies $use_cache $check_hash
|
||||
Invoke-CachedAria2Download $app $version $manifest $architecture $dir $cookies $use_cache $check_hash
|
||||
} else {
|
||||
foreach($url in $urls) {
|
||||
$fname = url_filename $url
|
||||
|
||||
try {
|
||||
dl_with_cache $app $version $url "$dir\$fname" $cookies $use_cache
|
||||
Invoke-CachedDownload $app $version $url "$dir\$fname" $cookies $use_cache
|
||||
} catch {
|
||||
write-host -f darkred $_
|
||||
abort "URL $url is not valid"
|
||||
@@ -584,7 +589,7 @@ function dl_urls($app, $version, $manifest, $bucket, $architecture, $dir, $use_c
|
||||
$extract_fn = 'Expand-InnoArchive'
|
||||
} elseif($fname -match '\.zip$') {
|
||||
# Use 7zip when available (more fast)
|
||||
if (((get_config 7ZIPEXTRACT_USE_EXTERNAL) -and (Test-CommandAvailable 7z)) -or (Test-HelperInstalled -Helper 7zip)) {
|
||||
if (((get_config USE_EXTERNAL_7ZIP) -and (Test-CommandAvailable 7z)) -or (Test-HelperInstalled -Helper 7zip)) {
|
||||
$extract_fn = 'Expand-7zipArchive'
|
||||
} else {
|
||||
$extract_fn = 'Expand-ZipArchive'
|
||||
@@ -905,7 +910,7 @@ function rm_shims($app, $manifest, $global, $arch) {
|
||||
# Returns the 'current' junction directory if in use, otherwise
|
||||
# the version directory.
|
||||
function link_current($versiondir) {
|
||||
if (get_config NO_JUNCTIONS) { return $versiondir.ToString() }
|
||||
if (get_config NO_JUNCTION) { return $versiondir.ToString() }
|
||||
|
||||
$currentdir = "$(Split-Path $versiondir)\current"
|
||||
|
||||
@@ -932,7 +937,7 @@ function link_current($versiondir) {
|
||||
# Returns the 'current' junction directory (if it exists),
|
||||
# otherwise the normal version directory.
|
||||
function unlink_current($versiondir) {
|
||||
if (get_config NO_JUNCTIONS) { return $versiondir.ToString() }
|
||||
if (get_config NO_JUNCTION) { return $versiondir.ToString() }
|
||||
$currentdir = "$(Split-Path $versiondir)\current"
|
||||
|
||||
if (Test-Path $currentdir) {
|
||||
@@ -1042,7 +1047,7 @@ function Invoke-HookScript {
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[PSCustomObject] $Manifest,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateSet('32bit', '64bit')]
|
||||
[ValidateSet('32bit', '64bit', 'arm64')]
|
||||
[String] $Arch
|
||||
)
|
||||
|
||||
@@ -1227,14 +1232,16 @@ function persist_permission($manifest, $global) {
|
||||
# test if there are running processes
|
||||
function test_running_process($app, $global) {
|
||||
$processdir = appdir $app $global | Convert-Path
|
||||
$running_processes = Get-Process | Where-Object { $_.Path -like "$processdir\*" }
|
||||
$running_processes = Get-Process | Where-Object { $_.Path -like "$processdir\*" } | Out-String
|
||||
|
||||
if ($running_processes) {
|
||||
if (get_config 'ignore_running_processes') {
|
||||
warn "Application `"$app`" is still running. Scoop is configured to ignore this condition."
|
||||
if (get_config IGNORE_RUNNING_PROCESSES) {
|
||||
warn "The following instances of `"$app`" are still running. Scoop is configured to ignore this condition."
|
||||
Write-Host $running_processes
|
||||
return $false
|
||||
} else {
|
||||
error "Application `"$app`" is still running. Close all instances and try again."
|
||||
error "The following instances of `"$app`" are still running. Close them and try again."
|
||||
Write-Host $running_processes
|
||||
return $true
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -98,7 +98,9 @@ function json_path([String] $json, [String] $jsonpath, [Hashtable] $substitution
|
||||
$jsonpath = substitute $jsonpath $substitutions ($jsonpath -like "*=~*")
|
||||
}
|
||||
try {
|
||||
$obj = [Newtonsoft.Json.Linq.JValue]::Parse($json)
|
||||
$settings = New-Object -Type Newtonsoft.Json.JsonSerializerSettings
|
||||
$settings.DateParseHandling = [Newtonsoft.Json.DateParseHandling]::None
|
||||
$obj = [Newtonsoft.Json.JsonConvert]::DeserializeObject($json, $settings)
|
||||
} catch [Newtonsoft.Json.JsonReaderException] {
|
||||
return $null
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
function manifest_path($app, $bucket) {
|
||||
fullpath "$(Find-BucketDirectory $bucket)\$(sanitary_path $app).json"
|
||||
(Get-ChildItem (Find-BucketDirectory $bucket) -Filter "$(sanitary_path $app).json" -Recurse).FullName
|
||||
}
|
||||
|
||||
function parse_json($path) {
|
||||
if (!(Test-Path $path)) { return $null }
|
||||
if ($null -eq $path -or !(Test-Path $path)) { return $null }
|
||||
try {
|
||||
Get-Content $path -Raw -Encoding UTF8 | ConvertFrom-Json -ErrorAction Stop
|
||||
} catch {
|
||||
@@ -102,23 +102,6 @@ function install_info($app, $version, $global) {
|
||||
parse_json $path
|
||||
}
|
||||
|
||||
function default_architecture {
|
||||
$arch = get_config 'default_architecture'
|
||||
$system = if ([Environment]::Is64BitOperatingSystem) { '64bit' } else { '32bit' }
|
||||
if ($null -eq $arch) {
|
||||
$arch = $system
|
||||
} else {
|
||||
try {
|
||||
$arch = ensure_architecture $arch
|
||||
} catch {
|
||||
warn 'Invalid default architecture configured. Determining default system architecture'
|
||||
$arch = $system
|
||||
}
|
||||
}
|
||||
|
||||
return $arch
|
||||
}
|
||||
|
||||
function arch_specific($prop, $manifest, $architecture) {
|
||||
if ($manifest.architecture) {
|
||||
$val = $manifest.architecture.$architecture.$prop
|
||||
@@ -128,8 +111,22 @@ function arch_specific($prop, $manifest, $architecture) {
|
||||
if ($manifest.$prop) { return $manifest.$prop }
|
||||
}
|
||||
|
||||
function supports_architecture($manifest, $architecture) {
|
||||
return -not [String]::IsNullOrEmpty((arch_specific 'url' $manifest $architecture))
|
||||
function Get-SupportedArchitecture($manifest, $architecture) {
|
||||
if ($architecture -eq 'arm64' -and ($manifest | ConvertToPrettyJson) -notmatch '[''"]arm64["'']') {
|
||||
# Windows 10 enables existing unmodified x86 apps to run on Arm devices.
|
||||
# Windows 11 adds the ability to run unmodified x64 Windows apps on Arm devices!
|
||||
# Ref: https://learn.microsoft.com/en-us/windows/arm/overview
|
||||
if ($WindowsBuild -ge 22000) {
|
||||
# Windows 11
|
||||
$architecture = '64bit'
|
||||
} else {
|
||||
# Windows 10
|
||||
$architecture = '32bit'
|
||||
}
|
||||
}
|
||||
if (![String]::IsNullOrEmpty((arch_specific 'url' $manifest $architecture))) {
|
||||
return $architecture
|
||||
}
|
||||
}
|
||||
|
||||
function generate_user_manifest($app, $bucket, $version) {
|
||||
@@ -145,10 +142,10 @@ function generate_user_manifest($app, $bucket, $version) {
|
||||
abort "'$app' does not have autoupdate capability`r`ncouldn't find manifest for '$app@$version'"
|
||||
}
|
||||
|
||||
ensure $(usermanifestsdir) | out-null
|
||||
ensure (usermanifestsdir) | out-null
|
||||
try {
|
||||
Invoke-AutoUpdate $app "$(resolve-path $(usermanifestsdir))" $manifest $version $(@{ })
|
||||
return "$(resolve-path $(usermanifest $app))"
|
||||
Invoke-AutoUpdate $app "$(Convert-Path (usermanifestsdir))\$app.json" $manifest $version $(@{ })
|
||||
return Convert-Path (usermanifest $app)
|
||||
} catch {
|
||||
write-host -f darkred "Could not install $app@$version"
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ function install_psmodule($manifest, $dir, $global) {
|
||||
|
||||
if (Test-Path $linkfrom) {
|
||||
warn "$(friendly_path $linkfrom) already exists. It will be replaced."
|
||||
Remove-Item -Path $linkfrom -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item -Path $linkfrom -Force -Recurse -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
New-DirectoryJunction $linkfrom $dir | Out-Null
|
||||
@@ -39,8 +39,8 @@ function uninstall_psmodule($manifest, $dir, $global) {
|
||||
$linkfrom = "$modulesdir\$module_name"
|
||||
if (Test-Path $linkfrom) {
|
||||
Write-Host "Removing $(friendly_path $linkfrom)"
|
||||
$linkfrom = Resolve-Path $linkfrom
|
||||
Remove-Item -Path $linkfrom -Force -ErrorAction SilentlyContinue
|
||||
$linkfrom = Convert-Path $linkfrom
|
||||
Remove-Item -Path $linkfrom -Force -Recurse -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,14 +10,14 @@ if(!(is_unix)) {
|
||||
}
|
||||
|
||||
# core.ps1
|
||||
$scoopdir = $env:SCOOP, (get_config 'rootPath'), (Join-Path $env:HOME "scoop") | Select-Object -first 1
|
||||
$globaldir = $env:SCOOP_GLOBAL, (get_config 'globalPath'), "/usr/local/scoop" | Select-Object -first 1
|
||||
$cachedir = $env:SCOOP_CACHE, (get_config 'cachePath'), (Join-Path $scoopdir "cache") | Select-Object -first 1
|
||||
$scoopdir = $env:SCOOP, (get_config ROOT_PATH), (Join-Path $env:HOME 'scoop') | Select-Object -First 1
|
||||
$globaldir = $env:SCOOP_GLOBAL, (get_config 'GLOBAL_PATH'), '/usr/local/scoop' | Select-Object -First 1
|
||||
$cachedir = $env:SCOOP_CACHE, (get_config 'CACHE_PATH'), (Join-Path $scoopdir 'cache') | Select-Object -First 1
|
||||
|
||||
# core.ps1
|
||||
function ensure($dir) {
|
||||
mkdir -p $dir > $null
|
||||
return resolve-path $dir
|
||||
return Convert-Path $dir
|
||||
}
|
||||
|
||||
# install.ps1
|
||||
|
||||
@@ -50,7 +50,7 @@ function Select-CurrentVersion { # 'manifest.ps1'
|
||||
)
|
||||
process {
|
||||
$currentPath = "$(appdir $AppName $Global)\current"
|
||||
if (!(get_config NO_JUNCTIONS)) {
|
||||
if (!(get_config NO_JUNCTION)) {
|
||||
$currentVersion = (parse_json "$currentPath\manifest.json").version
|
||||
if ($currentVersion -eq 'nightly') {
|
||||
$currentVersion = (Get-Item $currentPath).Target | Split-Path -Leaf
|
||||
|
||||
@@ -11,7 +11,7 @@ if (!$app) { error '<app> missing'; my_usage; exit 1 }
|
||||
$null, $manifest, $bucket, $url = Get-Manifest $app
|
||||
|
||||
if ($manifest) {
|
||||
$style = get_config cat_style
|
||||
$style = get_config CAT_STYLE
|
||||
if ($style) {
|
||||
$manifest | ConvertToPrettyJson | bat --no-paging --style $style --language json
|
||||
} else {
|
||||
|
||||
@@ -35,13 +35,13 @@ if (!(Test-HelperInstalled -Helper Dark)) {
|
||||
|
||||
$globaldir = New-Object System.IO.DriveInfo($globaldir)
|
||||
if ($globaldir.DriveFormat -ne 'NTFS') {
|
||||
error "Scoop requires an NTFS volume to work! Please point `$env:SCOOP_GLOBAL or 'globalPath' variable in '~/.config/scoop/config.json' to another Drive."
|
||||
error "Scoop requires an NTFS volume to work! Please point `$env:SCOOP_GLOBAL or 'global_path' variable in '~/.config/scoop/config.json' to another Drive."
|
||||
$issues++
|
||||
}
|
||||
|
||||
$scoopdir = New-Object System.IO.DriveInfo($scoopdir)
|
||||
if ($scoopdir.DriveFormat -ne 'NTFS') {
|
||||
error "Scoop requires an NTFS volume to work! Please point `$env:SCOOP or 'rootPath' variable in '~/.config/scoop/config.json' to another Drive."
|
||||
error "Scoop requires an NTFS volume to work! Please point `$env:SCOOP or 'root_path' variable in '~/.config/scoop/config.json' to another Drive."
|
||||
$issues++
|
||||
}
|
||||
|
||||
|
||||
@@ -21,20 +21,20 @@
|
||||
# Settings
|
||||
# --------
|
||||
#
|
||||
# 7ZIPEXTRACT_USE_EXTERNAL: $true|$false
|
||||
# use_external_7zip: $true|$false
|
||||
# External 7zip (from path) will be used for archives extraction.
|
||||
#
|
||||
# MSIEXTRACT_USE_LESSMSI: $true|$false
|
||||
# use_lessmsi: $true|$false
|
||||
# Prefer lessmsi utility over native msiexec.
|
||||
#
|
||||
# NO_JUNCTIONS: $true|$false
|
||||
# no_junction: $true|$false
|
||||
# The 'current' version alias will not be used. Shims and shortcuts will point to specific version instead.
|
||||
#
|
||||
# SCOOP_REPO: http://github.com/ScoopInstaller/Scoop
|
||||
# scoop_repo: http://github.com/ScoopInstaller/Scoop
|
||||
# Git repository containining scoop source code.
|
||||
# This configuration is useful for custom forks.
|
||||
#
|
||||
# SCOOP_BRANCH: master|develop
|
||||
# scoop_branch: master|develop
|
||||
# Allow to use different branch than master.
|
||||
# Could be used for testing specific functionalities before released into all users.
|
||||
# If you want to receive updates earlier to test new functionalities use develop (see: 'https://github.com/ScoopInstaller/Scoop/issues/2939')
|
||||
@@ -47,7 +47,11 @@
|
||||
# * An empty or unset value for proxy is equivalent to 'default' (with no username or password)
|
||||
# * To bypass the system proxy and connect directly, use 'none' (with no username or password)
|
||||
#
|
||||
# default_architecture: 64bit|32bit
|
||||
# autostash_on_conflict: $true|$false
|
||||
# When a conflict is detected during updating, Scoop will auto-stash the uncommitted changes.
|
||||
# (Default is $false, which will abort the update)
|
||||
#
|
||||
# default_architecture: 64bit|32bit|arm64
|
||||
# Allow to configure preferred architecture for application installation.
|
||||
# If not specified, architecture is determined be system.
|
||||
#
|
||||
@@ -60,20 +64,20 @@
|
||||
# show_update_log: $true|$false
|
||||
# Do not show changed commits on 'scoop update'
|
||||
#
|
||||
# manifest_review: $true|$false
|
||||
# show_manifest: $true|$false
|
||||
# Displays the manifest of every app that's about to
|
||||
# be installed, then asks user if they wish to proceed.
|
||||
#
|
||||
# shim: kiennq|scoopcs|71
|
||||
# Choose scoop shim build.
|
||||
#
|
||||
# rootPath: $Env:UserProfile\scoop
|
||||
# root_path: $Env:UserProfile\scoop
|
||||
# Path to Scoop root directory.
|
||||
#
|
||||
# globalPath: $Env:ProgramData\scoop
|
||||
# global_path: $Env:ProgramData\scoop
|
||||
# Path to Scoop root directory for global apps.
|
||||
#
|
||||
# cachePath:
|
||||
# cache_path:
|
||||
# For downloads, defaults to 'cache' folder under Scoop root directory.
|
||||
#
|
||||
# gh_token:
|
||||
@@ -101,6 +105,12 @@
|
||||
# For example, if you want to access a private GitHub repository,
|
||||
# you need to add the host to this list with 'match' and 'headers' strings.
|
||||
#
|
||||
# hold_update_until:
|
||||
# Disable/Hold Scoop self-updates, until the specified date.
|
||||
# `scoop hold scoop` will set the value to one day later.
|
||||
# Should be in the format 'YYYY-MM-DD', 'YYYY/MM/DD' or any other forms that accepted by '[System.DateTime]::Parse()'.
|
||||
# Ref: https://docs.microsoft.com/dotnet/api/system.datetime.parse?view=netframework-4.5#StringToParse
|
||||
#
|
||||
# ARIA2 configuration
|
||||
# -------------------
|
||||
#
|
||||
@@ -137,12 +147,30 @@ if (!$name) {
|
||||
} elseif ($name -like '--help') {
|
||||
my_usage
|
||||
} elseif ($name -like 'rm') {
|
||||
# NOTE Scoop config file migration. Remove this after 2023/6/30
|
||||
if ($value -notin 'SCOOP_REPO', 'SCOOP_BRANCH' -and $value -in $newConfigNames.Keys) {
|
||||
warn ('Config option "{0}" is deprecated, please use "{1}" instead next time.' -f $value, $newConfigNames.$value)
|
||||
$value = $newConfigNames.$value
|
||||
}
|
||||
# END NOTE
|
||||
set_config $value $null | Out-Null
|
||||
Write-Host "'$value' has been removed"
|
||||
} elseif ($null -ne $value) {
|
||||
# NOTE Scoop config file migration. Remove this after 2023/6/30
|
||||
if ($name -notin 'SCOOP_REPO', 'SCOOP_BRANCH' -and $name -in $newConfigNames.Keys) {
|
||||
warn ('Config option "{0}" is deprecated, please use "{1}" instead next time.' -f $name, $newConfigNames.$name)
|
||||
$name = $newConfigNames.$name
|
||||
}
|
||||
# END NOTE
|
||||
set_config $name $value | Out-Null
|
||||
Write-Host "'$name' has been set to '$value'"
|
||||
} else {
|
||||
# NOTE Scoop config file migration. Remove this after 2023/6/30
|
||||
if ($name -notin 'SCOOP_REPO', 'SCOOP_BRANCH' -and $name -in $newConfigNames.Keys) {
|
||||
warn ('Config option "{0}" is deprecated, please use "{1}" instead next time.' -f $name, $newConfigNames.$name)
|
||||
$name = $newConfigNames.$name
|
||||
}
|
||||
# END NOTE
|
||||
$value = get_config $name
|
||||
if($null -eq $value) {
|
||||
Write-Host "'$name' is not set"
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
|
||||
. "$PSScriptRoot\..\lib\getopt.ps1"
|
||||
. "$PSScriptRoot\..\lib\depends.ps1" # 'Get-Dependency'
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1" # 'default_architecture'
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1" # 'Get-Manifest' (indirectly)
|
||||
|
||||
$opt, $apps, $err = getopt $args 'a:' 'arch='
|
||||
$app = $apps[0]
|
||||
|
||||
if(!$app) { error '<app> missing'; my_usage; exit 1 }
|
||||
|
||||
$architecture = default_architecture
|
||||
$architecture = Get-DefaultArchitecture
|
||||
try {
|
||||
$architecture = ensure_architecture ($opt.a + $opt.arch)
|
||||
$architecture = Format-ArchitectureString ($opt.a + $opt.arch)
|
||||
} catch {
|
||||
abort "ERROR: $_"
|
||||
}
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
# -f, --force Force download (overwrite cache)
|
||||
# -h, --no-hash-check Skip hash verification (use with caution!)
|
||||
# -u, --no-update-scoop Don't update Scoop before downloading if it's outdated
|
||||
# -a, --arch <32bit|64bit> Use the specified architecture, if the app supports it
|
||||
# -a, --arch <32bit|64bit|arm64> Use the specified architecture, if the app supports it
|
||||
|
||||
. "$PSScriptRoot\..\lib\getopt.ps1"
|
||||
. "$PSScriptRoot\..\lib\json.ps1" # 'autoupdate.ps1' (indirectly)
|
||||
. "$PSScriptRoot\..\lib\autoupdate.ps1" # 'generate_user_manifest' (indirectly)
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1" # 'default_architecture' 'generate_user_manifest' 'Get-Manifest'
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1" # 'generate_user_manifest' 'Get-Manifest'
|
||||
. "$PSScriptRoot\..\lib\install.ps1"
|
||||
|
||||
$opt, $apps, $err = getopt $args 'fhua:' 'force', 'no-hash-check', 'no-update-scoop', 'arch='
|
||||
@@ -30,9 +30,9 @@ if ($err) { error "scoop download: $err"; exit 1 }
|
||||
|
||||
$check_hash = !($opt.h -or $opt.'no-hash-check')
|
||||
$use_cache = !($opt.f -or $opt.force)
|
||||
$architecture = default_architecture
|
||||
$architecture = Get-DefaultArchitecture
|
||||
try {
|
||||
$architecture = ensure_architecture ($opt.a + $opt.arch)
|
||||
$architecture = Format-ArchitectureString ($opt.a + $opt.arch)
|
||||
} catch {
|
||||
abort "ERROR: $_"
|
||||
}
|
||||
@@ -89,17 +89,18 @@ foreach ($curr_app in $apps) {
|
||||
$curr_check_hash = $false
|
||||
}
|
||||
|
||||
if(!(supports_architecture $manifest $architecture)) {
|
||||
error "'$app' doesn't support $architecture architecture!"
|
||||
$architecture = Get-SupportedArchitecture $manifest $architecture
|
||||
if ($null -eq $architecture) {
|
||||
error "'$app' doesn't support current architecture!"
|
||||
continue
|
||||
}
|
||||
|
||||
if(Test-Aria2Enabled) {
|
||||
dl_with_cache_aria2 $app $version $manifest $architecture $cachedir $manifest.cookie $use_cache $curr_check_hash
|
||||
Invoke-CachedAria2Download $app $version $manifest $architecture $cachedir $manifest.cookie $use_cache $curr_check_hash
|
||||
} else {
|
||||
foreach($url in script:url $manifest $architecture) {
|
||||
try {
|
||||
dl_with_cache $app $version $url $null $manifest.cookie $use_cache
|
||||
Invoke-CachedDownload $app $version $url $null $manifest.cookie $use_cache
|
||||
} catch {
|
||||
write-host -f darkred $_
|
||||
error "URL $url is not valid"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Usage: scoop export > scoopfile.json
|
||||
# Summary: Exports installed apps, buckets (and optionally configs) in JSON format
|
||||
# Options:
|
||||
# Help: Options:
|
||||
# -c, --config Export the Scoop configuration file too
|
||||
|
||||
. "$PSScriptRoot\..\lib\json.ps1" # 'ConvertToPrettyJson'
|
||||
@@ -10,7 +10,7 @@ $export = @{}
|
||||
if ($args[0] -eq '-c' -or $args[0] -eq '--config') {
|
||||
$export.config = $scoopConfig
|
||||
# Remove machine-specific properties
|
||||
foreach ($prop in 'lastUpdate', 'rootPath', 'globalPath', 'cachePath', 'alias') {
|
||||
foreach ($prop in 'last_update', 'root_path', 'global_path', 'cache_path', 'alias') {
|
||||
$export.config.PSObject.Properties.Remove($prop)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,12 @@ if ($global -and !(is_admin)) {
|
||||
$apps | ForEach-Object {
|
||||
$app = $_
|
||||
|
||||
if ($app -eq 'scoop') {
|
||||
$hold_update_until = [System.DateTime]::Now.AddDays(1)
|
||||
set_config HOLD_UPDATE_UNTIL $hold_update_until.ToString('o') | Out-Null
|
||||
success "$app is now held and might not be updated until $($hold_update_until.ToLocalTime())."
|
||||
return
|
||||
}
|
||||
if (!(installed $app $global)) {
|
||||
if ($global) {
|
||||
error "'$app' is not installed globally."
|
||||
@@ -41,7 +47,7 @@ $apps | ForEach-Object {
|
||||
return
|
||||
}
|
||||
|
||||
if (get_config NO_JUNCTIONS) {
|
||||
if (get_config NO_JUNCTION){
|
||||
$version = Select-CurrentVersion -App $app -Global:$global
|
||||
} else {
|
||||
$version = 'current'
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Usage: scoop import <path/url to scoopfile.json>
|
||||
# Summary: Imports apps, buckets and configs from a Scoopfile in JSON format
|
||||
# Help: To replicate a Scoop installation from a file stored on Desktop, run
|
||||
# scoop import Desktop\scoopfile.json
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
@@ -11,7 +13,7 @@ param(
|
||||
|
||||
$import = $null
|
||||
$bucket_names = @()
|
||||
$def_arch = default_architecture
|
||||
$def_arch = Get-DefaultArchitecture
|
||||
|
||||
if (Test-Path $scoopfile) {
|
||||
$import = parse_json $scoopfile
|
||||
@@ -21,42 +23,42 @@ if (Test-Path $scoopfile) {
|
||||
|
||||
if (!$import) { abort 'Input file not a valid JSON.' }
|
||||
|
||||
$import.config.PSObject.Properties | ForEach-Object {
|
||||
set_config $_.Name $_.Value | Out-Null
|
||||
Write-Host "'$($_.Name)' has been set to '$($_.Value)'"
|
||||
foreach ($item in $import.config.PSObject.Properties) {
|
||||
set_config $item.Name $item.Value | Out-Null
|
||||
Write-Host "'$($item.Name)' has been set to '$($item.Value)'"
|
||||
}
|
||||
|
||||
$import.buckets | ForEach-Object {
|
||||
add_bucket $_.Name $_.Source | Out-Null
|
||||
$bucket_names += $_.Name
|
||||
foreach ($item in $import.buckets) {
|
||||
add_bucket $item.Name $item.Source | Out-Null
|
||||
$bucket_names += $item.Name
|
||||
}
|
||||
|
||||
$import.apps | ForEach-Object {
|
||||
$info = $_.Info -Split ', '
|
||||
foreach ($item in $import.apps) {
|
||||
$info = $item.Info -Split ', '
|
||||
$global = if ('Global install' -in $info) {
|
||||
' --global'
|
||||
} else {
|
||||
''
|
||||
}
|
||||
$arch = if ('64bit' -in $info -and '32bit' -eq $def_arch) {
|
||||
$arch = if ('64bit' -in $info) {
|
||||
' --arch 64bit'
|
||||
} elseif ('32bit' -in $info -and '64bit' -eq $def_arch) {
|
||||
} elseif ('32bit' -in $info) {
|
||||
' --arch 32bit'
|
||||
} else {
|
||||
''
|
||||
' --arch arm64'
|
||||
}
|
||||
|
||||
$app = if ($_.Source -in $bucket_names) {
|
||||
"$($_.Source)/$($_.Name)"
|
||||
} elseif ($_.Source -eq '<auto-generated>') {
|
||||
"$($_.Name)@$($_.Version)"
|
||||
$app = if ($item.Source -in $bucket_names) {
|
||||
"$($item.Source)/$($item.Name)"
|
||||
} elseif ($item.Source -eq '<auto-generated>') {
|
||||
"$($item.Name)@$($item.Version)"
|
||||
} else {
|
||||
$_.Source
|
||||
$item.Source
|
||||
}
|
||||
|
||||
& "$PSScriptRoot\scoop-install.ps1" $app$global$arch
|
||||
|
||||
if ('Held package' -in $info) {
|
||||
& "$PSScriptRoot\scoop-hold.ps1" $($_.Name)$global
|
||||
& "$PSScriptRoot\scoop-hold.ps1" $($item.Name)$global
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ if ($status.installed) {
|
||||
if ($verbose) {
|
||||
# Get download size if app not installed
|
||||
$totalPackage = 0
|
||||
foreach ($url in @(url $manifest (default_architecture))) {
|
||||
foreach ($url in @(url $manifest (Get-DefaultArchitecture))) {
|
||||
try {
|
||||
if (Test-Path (fullpath (cache_path $app $manifest.version $url))) {
|
||||
$cached = " (latest version is cached)"
|
||||
|
||||
@@ -19,12 +19,12 @@
|
||||
# -k, --no-cache Don't use the download cache
|
||||
# -u, --no-update-scoop Don't update Scoop before installing if it's outdated
|
||||
# -s, --skip Skip hash validation (use with caution!)
|
||||
# -a, --arch <32bit|64bit> Use the specified architecture, if the app supports it
|
||||
# -a, --arch <32bit|64bit|arm64> Use the specified architecture, if the app supports it
|
||||
|
||||
. "$PSScriptRoot\..\lib\getopt.ps1"
|
||||
. "$PSScriptRoot\..\lib\json.ps1" # 'autoupdate.ps1' 'manifest.ps1' (indirectly)
|
||||
. "$PSScriptRoot\..\lib\autoupdate.ps1" # 'generate_user_manifest' (indirectly)
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1" # 'default_architecture' 'generate_user_manifest' 'Get-Manifest' 'Select-CurrentVersion' (indirectly)
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1" # 'generate_user_manifest' 'Get-Manifest' 'Select-CurrentVersion' (indirectly)
|
||||
. "$PSScriptRoot\..\lib\install.ps1"
|
||||
. "$PSScriptRoot\..\lib\decompress.ps1"
|
||||
. "$PSScriptRoot\..\lib\shortcuts.ps1"
|
||||
@@ -39,9 +39,9 @@ $global = $opt.g -or $opt.global
|
||||
$check_hash = !($opt.s -or $opt.skip)
|
||||
$independent = $opt.i -or $opt.independent
|
||||
$use_cache = !($opt.k -or $opt.'no-cache')
|
||||
$architecture = default_architecture
|
||||
$architecture = Get-DefaultArchitecture
|
||||
try {
|
||||
$architecture = ensure_architecture ($opt.a + $opt.arch)
|
||||
$architecture = Format-ArchitectureString ($opt.a + $opt.arch)
|
||||
} catch {
|
||||
abort "ERROR: $_"
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ param($query)
|
||||
. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1" # 'parse_json' 'Select-CurrentVersion' (indirectly)
|
||||
|
||||
$def_arch = default_architecture
|
||||
$def_arch = Get-DefaultArchitecture
|
||||
if (-not (Get-FormatData ScoopApps)) {
|
||||
Update-FormatData "$PSScriptRoot\..\supporting\formats\ScoopTypes.Format.ps1xml"
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ $apps | ForEach-Object {
|
||||
|
||||
write-host "Resetting $app ($version)."
|
||||
|
||||
$dir = resolve-path (versiondir $app $version $global)
|
||||
$dir = Convert-Path (versiondir $app $version $global)
|
||||
$original_dir = $dir
|
||||
$persist_dir = persistdir $app $global
|
||||
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
# Usage: scoop shim <subcommand> [<shim_names>] [<command_path> [<args>...]] [-g(lobal)]
|
||||
# Usage: scoop shim <subcommand> [<shim_name>...] [options] [other_args]
|
||||
# Summary: Manipulate Scoop shims
|
||||
# Help: Manipulate Scoop shims: add, rm, list, info, alter, etc.
|
||||
# Help: Available subcommands: add, rm, list, info, alter.
|
||||
#
|
||||
# To add a custom shim, use the 'add' subcommand:
|
||||
#
|
||||
# scoop shim add <shim_name> <command_path> [<args>...]
|
||||
#
|
||||
# To remove a shim, use the 'rm' subcommand (CAUTION: this could remove shims added by an app manifest):
|
||||
# To remove shims, use the 'rm' subcommand: (CAUTION: this could remove shims added by an app manifest)
|
||||
#
|
||||
# scoop shim rm <shim_names>
|
||||
# scoop shim rm <shim_name> [<shim_name>...]
|
||||
#
|
||||
# To list all shims or matching shims, use the 'list' subcommand:
|
||||
#
|
||||
# scoop shim list [<shim_names>]
|
||||
# scoop shim list [<shim_name>/<pattern>...]
|
||||
#
|
||||
# To show a shim's information, use the 'info' subcommand:
|
||||
#
|
||||
@@ -23,58 +23,38 @@
|
||||
# scoop shim alter <shim_name>
|
||||
#
|
||||
# Options:
|
||||
# -g(lobal) Add/Remove/Info/Alter global shim(s)
|
||||
# (NOTICE: USING SINGLE DASH)
|
||||
# (HINT: To pass arguments like '-g' or '-global' to the shim, use quotes)
|
||||
# -g, --global Manipulate global shim(s)
|
||||
#
|
||||
# HINT: The FIRST double-hyphen '--', if any, will be treated as the POSIX-style command option terminator
|
||||
# and will NOT be included in arguments, so if you want to pass arguments like '-g' or '--global' to
|
||||
# the shim, put them after a '--'. Note that in PowerShell, you must use a QUOTED '--', e.g.,
|
||||
#
|
||||
# scoop shim add myapp 'D:\path\myapp.exe' '--' myapp_args --global
|
||||
|
||||
param($SubCommand, $ShimName, [Switch]$global)
|
||||
param($SubCommand)
|
||||
|
||||
. "$PSScriptRoot\..\lib\getopt.ps1"
|
||||
. "$PSScriptRoot\..\lib\install.ps1" # for rm_shim
|
||||
|
||||
if ($SubCommand -notin @('add', 'rm', 'list', 'info', 'alter')) {
|
||||
'ERROR: <subcommand> must be one of: add, rm, list, info, alter'
|
||||
if (!$SubCommand) {
|
||||
error '<subcommand> missing'
|
||||
} else {
|
||||
error "'$SubCommand' is not one of available subcommands: add, rm, list, info, alter"
|
||||
}
|
||||
my_usage
|
||||
exit 1
|
||||
}
|
||||
|
||||
if ($SubCommand -ne 'list' -and !$ShimName) {
|
||||
"ERROR: <shim_name> must be specified for subcommand '$SubCommand'"
|
||||
my_usage
|
||||
exit 1
|
||||
}
|
||||
$opt, $other, $err = getopt $Args 'g' 'global'
|
||||
if ($err) { "scoop shim: $err"; exit 1 }
|
||||
|
||||
if ($Args) {
|
||||
switch ($SubCommand) {
|
||||
'add' {
|
||||
if ($Args[0] -like '-*') {
|
||||
"ERROR: <command_path> must be specified for subcommand 'add'"
|
||||
$global = $opt.g -or $opt.global
|
||||
|
||||
if ($SubCommand -ne 'list' -and $other.Length -eq 0) {
|
||||
error "<shim_name> must be specified for subcommand '$SubCommand'"
|
||||
my_usage
|
||||
exit 1
|
||||
} else {
|
||||
if (($Args -join ' ') -match "^'(.*?)'\s*(.*?)$") {
|
||||
$commandPath = $Matches[1]
|
||||
$commandArgs = $Matches[2]
|
||||
} else {
|
||||
$commandPath = $Args[0]
|
||||
if ($Args.Length -gt 1) {
|
||||
$commandArgs = $Args[1..($Args.Length - 1)]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'rm' {
|
||||
$ShimName = @($ShimName) + $Args
|
||||
}
|
||||
'list' {
|
||||
$ShimName = (@($ShimName) + $Args) -join '|'
|
||||
}
|
||||
default {
|
||||
# For 'info' and 'alter'
|
||||
"ERROR: Option $Args not recognized."
|
||||
my_usage
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-not (Get-FormatData ScoopShims)) {
|
||||
@@ -110,6 +90,16 @@ function Get-ShimPath($ShimName, $Global) {
|
||||
|
||||
switch ($SubCommand) {
|
||||
'add' {
|
||||
if ($other.Length -lt 2 -or $other[1] -eq '') {
|
||||
error "<command_path> must be specified for subcommand 'add'"
|
||||
my_usage
|
||||
exit 1
|
||||
}
|
||||
$shimName = $other[0]
|
||||
$commandPath = $other[1]
|
||||
if ($other.Length -gt 2) {
|
||||
$commandArgs = $other[2..($other.Length - 1)]
|
||||
}
|
||||
if ($commandPath -notmatch '[\\/]') {
|
||||
$shortPath = $commandPath
|
||||
$commandPath = Get-ShimTarget (Get-ShimPath $shortPath $global)
|
||||
@@ -126,12 +116,14 @@ switch ($SubCommand) {
|
||||
Write-Host '...'
|
||||
shim $commandPath $global $shimName $commandArgs
|
||||
} else {
|
||||
abort "ERROR: '$($Args[0])' does not exist" 3
|
||||
Write-Host "ERROR: Command path does not exist: " -ForegroundColor Red -NoNewline
|
||||
Write-Host $($other[1]) -ForegroundColor Cyan
|
||||
exit 3
|
||||
}
|
||||
}
|
||||
'rm' {
|
||||
$failed = @()
|
||||
$ShimName | ForEach-Object {
|
||||
$other | ForEach-Object {
|
||||
if (Get-ShimPath $_ $global) {
|
||||
rm_shim $_ (shimdir $global)
|
||||
} else {
|
||||
@@ -139,61 +131,82 @@ switch ($SubCommand) {
|
||||
}
|
||||
}
|
||||
if ($failed) {
|
||||
Write-Host 'Shims not found: ' -NoNewline
|
||||
Write-Host $failed -ForegroundColor Cyan
|
||||
$failed | ForEach-Object {
|
||||
Write-Host "ERROR: $(if ($global) { 'Global' } else {'Local' }) shim not found: " -ForegroundColor Red -NoNewline
|
||||
Write-Host $_ -ForegroundColor Cyan
|
||||
}
|
||||
exit 3
|
||||
}
|
||||
}
|
||||
'list' {
|
||||
$shims = Get-ChildItem -Path $localShimDir -Recurse -Include '*.shim', '*.ps1' |
|
||||
Where-Object { !$ShimName -or ($_.BaseName -match $ShimName) } |
|
||||
$other = @($other) -ne '*'
|
||||
# Validate all given patterns before matching.
|
||||
$other | ForEach-Object {
|
||||
try {
|
||||
$pattern = $_
|
||||
[Regex]::New($pattern)
|
||||
} catch {
|
||||
Write-Host "ERROR: Invalid pattern: " -ForegroundColor Red -NoNewline
|
||||
Write-Host $pattern -ForegroundColor Magenta
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
$pattern = $other -join '|'
|
||||
$shims = @()
|
||||
if (!$global) {
|
||||
$shims += Get-ChildItem -Path $localShimDir -Recurse -Include '*.shim', '*.ps1' |
|
||||
Where-Object { !$pattern -or ($_.BaseName -match $pattern) } |
|
||||
Select-Object -ExpandProperty FullName
|
||||
}
|
||||
if (Test-Path $globalShimDir) {
|
||||
$shims += Get-ChildItem -Path $globalShimDir -Recurse -Include '*.shim', '*.ps1' |
|
||||
Where-Object { !$ShimName -or ($_.BaseName -match $ShimName) } |
|
||||
Where-Object { !$pattern -or ($_.BaseName -match $pattern) } |
|
||||
Select-Object -ExpandProperty FullName
|
||||
}
|
||||
$shims.ForEach({ Get-ShimInfo $_ }) | Add-Member -TypeName 'ScoopShims' -PassThru
|
||||
}
|
||||
'info' {
|
||||
$shimPath = Get-ShimPath $ShimName $global
|
||||
$shimName = $other[0]
|
||||
$shimPath = Get-ShimPath $shimName $global
|
||||
if ($shimPath) {
|
||||
Get-ShimInfo $shimPath
|
||||
} else {
|
||||
Write-Host "$(if ($global) { 'Global' } else { 'Local' }) shim not found: " -NoNewline
|
||||
Write-Host $ShimName -ForegroundColor Cyan
|
||||
if (Get-ShimPath $ShimName (!$global)) {
|
||||
Write-Host "ERROR: $(if ($global) { 'Global' } else { 'Local' }) shim not found: " -ForegroundColor Red -NoNewline
|
||||
Write-Host $shimName -ForegroundColor Cyan
|
||||
if (Get-ShimPath $shimName (!$global)) {
|
||||
Write-Host "But a $(if ($global) { 'local' } else {'global' }) shim exists, " -NoNewline
|
||||
Write-Host "run 'scoop shim info $ShimName$(if (!$global) { ' -global' })' to show its info"
|
||||
Write-Host "run 'scoop shim info $shimName$(if (!$global) { ' --global' })' to show its info"
|
||||
exit 2
|
||||
}
|
||||
exit 3
|
||||
}
|
||||
}
|
||||
'alter' {
|
||||
$shimPath = Get-ShimPath $ShimName $global
|
||||
$shimName = $other[0]
|
||||
$shimPath = Get-ShimPath $shimName $global
|
||||
if ($shimPath) {
|
||||
$shimInfo = Get-ShimInfo $shimPath
|
||||
if ($null -eq $shimInfo.Alternatives) {
|
||||
Write-Host 'No alternatives of ' -NoNewline
|
||||
Write-Host $ShimName -ForegroundColor Cyan -NoNewline
|
||||
Write-Host ' found.'
|
||||
Write-Host 'ERROR: No alternatives of ' -ForegroundColor Red -NoNewline
|
||||
Write-Host $shimName -ForegroundColor Cyan -NoNewline
|
||||
Write-Host ' found.' -ForegroundColor Red
|
||||
exit 2
|
||||
}
|
||||
$shimInfo.Alternatives = $shimInfo.Alternatives.Split(' ')
|
||||
[System.Management.Automation.Host.ChoiceDescription[]]$altApps = 1..$shimInfo.Alternatives.Length | ForEach-Object {
|
||||
New-Object System.Management.Automation.Host.ChoiceDescription "&$($_)`b$($shimInfo.Alternatives[$_ - 1])", "Sets '$ShimName' shim from $($shimInfo.Alternatives[$_ - 1])."
|
||||
New-Object System.Management.Automation.Host.ChoiceDescription "&$($_)`b$($shimInfo.Alternatives[$_ - 1])", "Sets '$shimName' shim from $($shimInfo.Alternatives[$_ - 1])."
|
||||
}
|
||||
$selected = $Host.UI.PromptForChoice("Alternatives of '$ShimName' command", "Please choose one that provides '$ShimName' as default:", $altApps, 0)
|
||||
$selected = $Host.UI.PromptForChoice("Alternatives of '$shimName' command", "Please choose one that provides '$shimName' as default:", $altApps, 0)
|
||||
if ($selected -eq 0) {
|
||||
Write-Host $ShimName -ForegroundColor Cyan -NoNewline
|
||||
Write-Host 'INFO: ' -ForegroundColor Blue -NoNewline
|
||||
Write-Host $shimName -ForegroundColor Cyan -NoNewline
|
||||
Write-Host ' is already from ' -NoNewline
|
||||
Write-Host $shimInfo.Source -ForegroundColor DarkYellow -NoNewline
|
||||
Write-Host ', nothing changed.'
|
||||
} else {
|
||||
$newApp = $shimInfo.Alternatives[$selected]
|
||||
Write-Host 'Use ' -NoNewline
|
||||
Write-Host $ShimName -ForegroundColor Cyan -NoNewline
|
||||
Write-Host $shimName -ForegroundColor Cyan -NoNewline
|
||||
Write-Host ' from ' -NoNewline
|
||||
Write-Host $newApp -ForegroundColor DarkYellow -NoNewline
|
||||
Write-Host ' as default...' -NoNewline
|
||||
@@ -211,11 +224,11 @@ switch ($SubCommand) {
|
||||
Write-Host 'done.'
|
||||
}
|
||||
} else {
|
||||
Write-Host "$(if ($global) { 'Global' } else { 'Local' }) shim not found: " -NoNewline
|
||||
Write-Host $ShimName -ForegroundColor Cyan
|
||||
if (Get-ShimPath $ShimName (!$global)) {
|
||||
Write-Host "ERROR: $(if ($global) { 'Global' } else { 'Local' }) shim not found: " -ForegroundColor Red -NoNewline
|
||||
Write-Host $shimName -ForegroundColor Cyan
|
||||
if (Get-ShimPath $shimName (!$global)) {
|
||||
Write-Host "But a $(if ($global) { 'local' } else {'global' }) shim exists, " -NoNewline
|
||||
Write-Host "run 'scoop shim alter $ShimName$(if (!$global) { ' -global' })' to alternate its source"
|
||||
Write-Host "run 'scoop shim alter $shimName$(if (!$global) { ' --global' })' to alternate its source"
|
||||
exit 2
|
||||
}
|
||||
exit 3
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
# Usage: scoop status
|
||||
# Summary: Show status and check for new app versions
|
||||
# Help: Options:
|
||||
# -l, --local Checks the status for only the locally installed apps,
|
||||
# and disables remote fetching/checking for Scoop and buckets
|
||||
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1" # 'manifest' 'parse_json' "install_info"
|
||||
. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
|
||||
@@ -9,6 +12,8 @@ $currentdir = fullpath $(versiondir 'scoop' 'current')
|
||||
$needs_update = $false
|
||||
$bucket_needs_update = $false
|
||||
$script:network_failure = $false
|
||||
$no_remotes = $args[0] -eq '-l' -or $args[0] -eq '--local'
|
||||
if (!(Get-Command git -ErrorAction SilentlyContinue)) { $no_remotes = $true }
|
||||
$list = @()
|
||||
if (!(Get-FormatData ScoopStatus)) {
|
||||
Update-FormatData "$PSScriptRoot\..\supporting\formats\ScoopTypes.Format.ps1xml"
|
||||
@@ -27,10 +32,13 @@ function Test-UpdateStatus($repopath) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!$no_remotes) {
|
||||
$needs_update = Test-UpdateStatus $currentdir
|
||||
foreach ($bucket in Get-LocalBucket) {
|
||||
if (Test-UpdateStatus (Find-BucketDirectory $bucket -Root)) {
|
||||
$bucket_needs_update = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +46,7 @@ if ($needs_update) {
|
||||
warn "Scoop out of date. Run 'scoop update' to get the latest changes."
|
||||
} elseif ($bucket_needs_update) {
|
||||
warn "Scoop bucket(s) out of date. Run 'scoop update' to get the latest changes."
|
||||
} elseif (!$script:network_failure) {
|
||||
} elseif (!$script:network_failure -and !$no_remotes) {
|
||||
success 'Scoop is up to date.'
|
||||
}
|
||||
|
||||
@@ -57,7 +65,7 @@ $true, $false | ForEach-Object { # local and global apps
|
||||
$item.'Installed Version' = $status.version
|
||||
$item.'Latest Version' = if ($status.outdated) { $status.latest_version } else { "" }
|
||||
$item.'Missing Dependencies' = $status.missing_deps -Split ' ' -Join ' | '
|
||||
$info = $()
|
||||
$info = @()
|
||||
if ($status.failed) { $info += 'Install failed' }
|
||||
if ($status.hold) { $info += 'Held package' }
|
||||
if ($status.removed) { $info += 'Manifest removed' }
|
||||
|
||||
@@ -32,6 +32,11 @@ if ($global -and !(is_admin)) {
|
||||
$apps | ForEach-Object {
|
||||
$app = $_
|
||||
|
||||
if ($app -eq 'scoop') {
|
||||
set_config HOLD_UPDATE_UNTIL $null | Out-Null
|
||||
success "$app is no longer held and can be updated again."
|
||||
return
|
||||
}
|
||||
if (!(installed $app $global)) {
|
||||
if ($global) {
|
||||
error "'$app' is not installed globally."
|
||||
@@ -41,7 +46,7 @@ $apps | ForEach-Object {
|
||||
return
|
||||
}
|
||||
|
||||
if (get_config NO_JUNCTIONS) {
|
||||
if (get_config NO_JUNCTION){
|
||||
$version = Select-CurrentVersion -App $app -Global:$global
|
||||
} else {
|
||||
$version = 'current'
|
||||
|
||||
@@ -54,16 +54,18 @@ if(($PSVersionTable.PSVersion.Major) -lt 5) {
|
||||
Write-Output "Upgrade PowerShell: https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-windows"
|
||||
break
|
||||
}
|
||||
$show_update_log = get_config SHOW_UPDATE_LOG $true
|
||||
|
||||
function update_scoop($show_update_log) {
|
||||
# Test if Scoop Core is hold
|
||||
if(Test-ScoopCoreOnHold) {
|
||||
return
|
||||
}
|
||||
|
||||
function update_scoop() {
|
||||
# check for git
|
||||
if (!(Test-CommandAvailable git)) { abort "Scoop uses Git to update itself. Run 'scoop install git' and try again." }
|
||||
|
||||
Write-Host "Updating Scoop..."
|
||||
$last_update = $(last_scoop_update)
|
||||
if ($null -eq $last_update) {$last_update = [System.DateTime]::Now}
|
||||
$last_update = $last_update.ToString('s')
|
||||
$show_update_log = get_config 'show_update_log' $true
|
||||
$currentdir = fullpath $(versiondir 'scoop' 'current')
|
||||
if (!(Test-Path "$currentdir\.git")) {
|
||||
$newdir = "$currentdir\..\new"
|
||||
@@ -98,6 +100,17 @@ function update_scoop() {
|
||||
$isRepoChanged = !($currentRepo -match $configRepo)
|
||||
$isBranchChanged = !($currentBranch -match "\*\s+$configBranch")
|
||||
|
||||
# Stash uncommitted changes
|
||||
if (git -C "$currentdir" 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
|
||||
} else {
|
||||
warn "Uncommitted changes detected. Update aborted."
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
# Change remote url if the repo is changed
|
||||
if ($isRepoChanged) {
|
||||
git -C "$currentdir" config remote.origin.url "$configRepo"
|
||||
@@ -135,6 +148,11 @@ function update_scoop() {
|
||||
# }
|
||||
|
||||
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." }
|
||||
|
||||
foreach ($bucket in Get-LocalBucket) {
|
||||
Write-Host "Updating '$bucket' bucket..."
|
||||
@@ -165,9 +183,6 @@ function update_scoop() {
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
||||
set_config lastupdate ([System.DateTime]::Now.ToString('o')) | Out-Null
|
||||
success 'Scoop was updated successfully!'
|
||||
}
|
||||
|
||||
function update($app, $global, $quiet = $false, $independent, $suggested, $use_cache = $true, $check_hash = $true) {
|
||||
@@ -176,7 +191,7 @@ function update($app, $global, $quiet = $false, $independent, $suggested, $use_c
|
||||
$install = install_info $app $old_version $global
|
||||
|
||||
# re-use architecture, bucket and url from first install
|
||||
$architecture = ensure_architecture $install.architecture
|
||||
$architecture = Format-ArchitectureString $install.architecture
|
||||
$bucket = $install.bucket
|
||||
if ($null -eq $bucket) {
|
||||
$bucket = 'main'
|
||||
@@ -210,12 +225,12 @@ function update($app, $global, $quiet = $false, $independent, $suggested, $use_c
|
||||
# Remove and replace whole region after proper fix
|
||||
Write-Host "Downloading new version"
|
||||
if (Test-Aria2Enabled) {
|
||||
dl_with_cache_aria2 $app $version $manifest $architecture $cachedir $manifest.cookie $true $check_hash
|
||||
Invoke-CachedAria2Download $app $version $manifest $architecture $cachedir $manifest.cookie $true $check_hash
|
||||
} else {
|
||||
$urls = script:url $manifest $architecture
|
||||
|
||||
foreach ($url in $urls) {
|
||||
dl_with_cache $app $version $url $null $manifest.cookie $true
|
||||
Invoke-CachedDownload $app $version $url $null $manifest.cookie $true
|
||||
|
||||
if ($check_hash) {
|
||||
$manifest_hash = hash_for_url $manifest $url $architecture
|
||||
@@ -243,6 +258,8 @@ function update($app, $global, $quiet = $false, $independent, $suggested, $use_c
|
||||
$dir = versiondir $app $old_version $global
|
||||
$persist_dir = persistdir $app $global
|
||||
|
||||
Invoke-HookScript -HookType 'pre_uninstall' -Manifest $old_manifest -Arch $architecture
|
||||
|
||||
#region Workaround for #2952
|
||||
if (test_running_process $app $global) {
|
||||
return
|
||||
@@ -260,6 +277,8 @@ function update($app, $global, $quiet = $false, $independent, $suggested, $use_c
|
||||
# directory.
|
||||
$refdir = unlink_current $dir
|
||||
|
||||
uninstall_psmodule $old_manifest $refdir $global
|
||||
|
||||
if ($force -and ($old_version -eq $version)) {
|
||||
if (!(Test-Path "$dir/../_$version.old")) {
|
||||
Move-Item "$dir" "$dir/../_$version.old"
|
||||
@@ -272,6 +291,8 @@ function update($app, $global, $quiet = $false, $independent, $suggested, $use_c
|
||||
}
|
||||
}
|
||||
|
||||
Invoke-HookScript -HookType 'post_uninstall' -Manifest $old_manifest -Arch $architecture
|
||||
|
||||
if ($bucket) {
|
||||
# add bucket name it was installed from
|
||||
$app = "$bucket/$app"
|
||||
@@ -300,7 +321,10 @@ if (-not ($apps -or $all)) {
|
||||
error 'scoop update: --no-cache is invalid when <app> is not specified.'
|
||||
exit 1
|
||||
}
|
||||
update_scoop
|
||||
update_scoop $show_update_log
|
||||
update_bucket $show_update_log
|
||||
set_config LAST_UPDATE ([System.DateTime]::Now.ToString('o')) | Out-Null
|
||||
success 'Scoop was updated successfully!'
|
||||
} else {
|
||||
if ($global -and !(is_admin)) {
|
||||
'ERROR: You need admin rights to update global apps.'; exit 1
|
||||
@@ -312,7 +336,10 @@ if (-not ($apps -or $all)) {
|
||||
$apps_param = $apps
|
||||
|
||||
if ($updateScoop) {
|
||||
update_scoop
|
||||
update_scoop $show_update_log
|
||||
update_bucket $show_update_log
|
||||
set_config LAST_UPDATE ([System.DateTime]::Now.ToString('o')) | Out-Null
|
||||
success 'Scoop was updated successfully!'
|
||||
}
|
||||
|
||||
if ($apps_param -eq '*' -or $all) {
|
||||
@@ -336,7 +363,7 @@ if (-not ($apps -or $all)) {
|
||||
} else {
|
||||
warn "'$app' is held to version $($status.version)"
|
||||
}
|
||||
} elseif ($apps_param -ne '*') {
|
||||
} elseif ($apps_param -ne '*' -and !$all) {
|
||||
if ($status.installed) {
|
||||
ensure_none_failed $app
|
||||
Write-Host "$app`: $($status.version) (latest version)" -ForegroundColor Green
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
$opt, $apps, $err = getopt $args 'asnup' @('all', 'scan', 'no-depends', 'no-update-scoop', 'passthru')
|
||||
if ($err) { "scoop virustotal: $err"; exit 1 }
|
||||
if (!$apps) { my_usage; exit 1 }
|
||||
$architecture = ensure_architecture
|
||||
$architecture = Format-ArchitectureString
|
||||
|
||||
if (is_scoop_outdated) {
|
||||
if ($opt.u -or $opt.'no-update-scoop') {
|
||||
@@ -66,7 +66,7 @@ $_ERR_NO_API_KEY = 16
|
||||
$exit_code = 0
|
||||
|
||||
# Global API key:
|
||||
$api_key = get_config virustotal_api_key
|
||||
$api_key = get_config VIRUSTOTAL_API_KEY
|
||||
if (!$api_key) {
|
||||
abort ("VirusTotal API key is not configured`n" +
|
||||
" You could get one from https://www.virustotal.com/gui/my-apikey and set with`n" +
|
||||
|
||||
154
schema.json
154
schema.json
@@ -179,19 +179,11 @@
|
||||
"type": "array"
|
||||
},
|
||||
"autoupdateArch": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"url": {
|
||||
"$ref": "#/definitions/autoupdateUriOrArrayOfAutoupdateUris"
|
||||
},
|
||||
"hash": {
|
||||
"$ref": "#/definitions/hashExtractionOrArrayOfHashExtractions"
|
||||
},
|
||||
"extract_dir": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStrings"
|
||||
},
|
||||
"extract_to": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStrings"
|
||||
"bin": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStringsOrAnArrayOfArrayOfStrings"
|
||||
},
|
||||
"env_add_path": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStrings"
|
||||
@@ -199,55 +191,33 @@
|
||||
"env_set": {
|
||||
"type": "object"
|
||||
},
|
||||
"bin": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStringsOrAnArrayOfArrayOfStrings"
|
||||
"extract_dir": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStrings"
|
||||
},
|
||||
"shortcuts": {
|
||||
"$ref": "#/definitions/shortcutsArray"
|
||||
"hash": {
|
||||
"$ref": "#/definitions/hashExtractionOrArrayOfHashExtractions"
|
||||
},
|
||||
"installer": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"post_install": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStrings"
|
||||
},
|
||||
"psmodule": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
"shortcuts": {
|
||||
"$ref": "#/definitions/shortcutsArray"
|
||||
},
|
||||
"persist": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStringsOrAnArrayOfArrayOfStrings"
|
||||
},
|
||||
"license": {
|
||||
"$ref": "#/definitions/license"
|
||||
},
|
||||
"notes": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStrings"
|
||||
"url": {
|
||||
"$ref": "#/definitions/autoupdateUriOrArrayOfAutoupdateUris"
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"autoupdate": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/autoupdateArch"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"notes": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStrings"
|
||||
},
|
||||
"architecture": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
@@ -257,14 +227,50 @@
|
||||
},
|
||||
"64bit": {
|
||||
"$ref": "#/definitions/autoupdateArch"
|
||||
},
|
||||
"arm64": {
|
||||
"$ref": "#/definitions/autoupdateArch"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
},
|
||||
"bin": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStringsOrAnArrayOfArrayOfStrings"
|
||||
},
|
||||
"env_add_path": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStrings"
|
||||
},
|
||||
"env_set": {
|
||||
"type": "object"
|
||||
},
|
||||
"extract_dir": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStrings"
|
||||
},
|
||||
"hash": {
|
||||
"$ref": "#/definitions/hashExtractionOrArrayOfHashExtractions"
|
||||
},
|
||||
"license": {
|
||||
"$ref": "#/definitions/license"
|
||||
},
|
||||
"notes": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStrings"
|
||||
},
|
||||
"persist": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStringsOrAnArrayOfArrayOfStrings"
|
||||
},
|
||||
"psmodule": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"$ref": "#/definitions/autoupdateUriOrArrayOfAutoupdateUris"
|
||||
}
|
||||
}
|
||||
},
|
||||
"checkver": {
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -315,6 +321,25 @@
|
||||
"script": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStrings",
|
||||
"description": "Custom PowerShell script to retrieve application version using more complex approach."
|
||||
},
|
||||
"sourceforge": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"project": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
@@ -508,6 +533,9 @@
|
||||
},
|
||||
"64bit": {
|
||||
"$ref": "#/definitions/architecture"
|
||||
},
|
||||
"arm64": {
|
||||
"$ref": "#/definitions/architecture"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
@@ -614,6 +642,34 @@
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"if": {
|
||||
"properties": {
|
||||
"architecture": {
|
||||
"properties": {
|
||||
"64bit": {
|
||||
"properties": {
|
||||
"url": false
|
||||
}
|
||||
},
|
||||
"32bit": {
|
||||
"properties": {
|
||||
"url": false
|
||||
}
|
||||
},
|
||||
"arm64": {
|
||||
"properties": {
|
||||
"url": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"required": [
|
||||
"url"
|
||||
]
|
||||
},
|
||||
"required": [
|
||||
"version",
|
||||
"homepage",
|
||||
|
||||
Binary file not shown.
@@ -1,4 +1,4 @@
|
||||
b624949df8b0e3a6153fdfb730a7c6f4990b6592ee0d922e1788433d276610f3 *Newtonsoft.Json.dll
|
||||
cff8fc4ce358d7daff84ab47129a776797a4ec819c1586a15bd5e63144f5b73f *Newtonsoft.Json.Schema.dll
|
||||
9abb57d73d82a2d77008321a85aff2b62e5ac68bebb54ece8668c96cc112e36b *Newtonsoft.Json.Schema.dll
|
||||
0318c8221ce4d44806f8def619bcc02886be0902aab80080e6251c50c6ca53a9 *Scoop.Validator.dll
|
||||
40a70bee96d108701f8f2e81392f9b79fd003f1cb4e1653ad2429753153fd7ee *validator.exe
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
2fdf035661f349206f58ea1feed8805b7f9517a21f9c113e7301c69de160f184c774350a12a710046e3ff6baa37345d319b6f47fd24fbba4e042d54014bee511 *Newtonsoft.Json.dll
|
||||
298d3d0b656acbb1fe5ed0c3abb49a640c47889184ab7bd4b594e51a7d7f829d5c8685edbd10a286fd56bfd8d601b9f187da463a5a9c8509365eddaea280642f *Newtonsoft.Json.Schema.dll
|
||||
855ab2e30c9d523c9f321ae861c5969244185f660fa47e05cec96df8e2970d19843dbd3d89a0fca845544641915d1adf4b4a2145ef568dd99da7791e5064d70e *Newtonsoft.Json.Schema.dll
|
||||
338793e6127330c0b05728291fcf18441127ffb56e1bd5c0f0588cd7436605f4b852f4bb622f655896a7eb7b1262add142b200fd5f37391b47d1401becb6b81c *Scoop.Validator.dll
|
||||
d497c27b48f44f4cff270d3c8801b0cecc74108f8786a4a7c40e57541308ae33a69f5456cfc43ae1ce4214038d20da9fbeac1bcf76cc58d972863b58dab18401 *validator.exe
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net45" />
|
||||
<package id="Newtonsoft.Json.Schema" version="3.0.14" targetFramework="net45" />
|
||||
<package id="Newtonsoft.Json.Schema" version="3.0.15-beta2" targetFramework="net45" />
|
||||
<package id="Microsoft.Net.Compilers.Toolset" version="4.2.0" targetFramework="net45" developmentDependency="true" />
|
||||
</packages>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json.Schema, Version=3.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed">
|
||||
<HintPath>packages\Newtonsoft.Json.Schema.3.0.14\lib\net45\Newtonsoft.Json.Schema.dll</HintPath>
|
||||
<HintPath>packages\Newtonsoft.Json.Schema.3.0.15-beta2\lib\net45\Newtonsoft.Json.Schema.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
|
||||
@@ -82,7 +82,7 @@ Describe 'manifest validates against the schema' -Tag 'Manifests' {
|
||||
}
|
||||
$changed_manifests = (Get-GitChangedFile -Path $repo_dir -Include '*.json' -Commit $commit)
|
||||
}
|
||||
$manifest_files = Get-ChildItem $bucketdir *.json
|
||||
$manifest_files = Get-ChildItem $bucketdir -Filter '*.json' -Recurse
|
||||
$validator = New-Object Scoop.Validator($schema, $true)
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ Describe 'Style constraints for non-binary project files' {
|
||||
It 'file newlines are CRLF' -Skip:$(-not $files_exist) {
|
||||
$badFiles = @(
|
||||
foreach ($file in $files) {
|
||||
$content = Get-Content -Raw $file.FullName
|
||||
$content = [System.IO.File]::ReadAllText($file.FullName)
|
||||
if (!$content) {
|
||||
throw "File contents are null: $($file.FullName)"
|
||||
}
|
||||
|
||||
@@ -397,3 +397,40 @@ Describe 'app' -Tag 'Scoop' {
|
||||
$version | Should -Be '1.8.0-rc2'
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'Format Architecture String' -Tag 'Scoop' {
|
||||
It 'should keep correct architectures' {
|
||||
Format-ArchitectureString '32bit' | Should -Be '32bit'
|
||||
Format-ArchitectureString '32' | Should -Be '32bit'
|
||||
Format-ArchitectureString 'x86' | Should -Be '32bit'
|
||||
Format-ArchitectureString 'X86' | Should -Be '32bit'
|
||||
Format-ArchitectureString 'i386' | Should -Be '32bit'
|
||||
Format-ArchitectureString '386' | Should -Be '32bit'
|
||||
Format-ArchitectureString 'i686' | Should -Be '32bit'
|
||||
|
||||
Format-ArchitectureString '64bit' | Should -Be '64bit'
|
||||
Format-ArchitectureString '64' | Should -Be '64bit'
|
||||
Format-ArchitectureString 'x64' | Should -Be '64bit'
|
||||
Format-ArchitectureString 'X64' | Should -Be '64bit'
|
||||
Format-ArchitectureString 'amd64' | Should -Be '64bit'
|
||||
Format-ArchitectureString 'AMD64' | Should -Be '64bit'
|
||||
Format-ArchitectureString 'x86_64' | Should -Be '64bit'
|
||||
Format-ArchitectureString 'x86-64' | Should -Be '64bit'
|
||||
|
||||
Format-ArchitectureString 'arm64' | Should -Be 'arm64'
|
||||
Format-ArchitectureString 'arm' | Should -Be 'arm64'
|
||||
Format-ArchitectureString 'aarch64' | Should -Be 'arm64'
|
||||
Format-ArchitectureString 'ARM64' | Should -Be 'arm64'
|
||||
Format-ArchitectureString 'ARM' | Should -Be 'arm64'
|
||||
Format-ArchitectureString 'AARCH64' | Should -Be 'arm64'
|
||||
}
|
||||
|
||||
It 'should fallback to the default architecture on empty input' {
|
||||
Format-ArchitectureString '' | Should -Be $(Get-DefaultArchitecture)
|
||||
Format-ArchitectureString $null | Should -Be $(Get-DefaultArchitecture)
|
||||
}
|
||||
|
||||
It 'should show an error with an invalid architecture' {
|
||||
{ Format-ArchitectureString 'PPC' } | Should -Throw "Invalid architecture: 'ppc'"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,14 +46,14 @@ Describe 'Package Dependencies' -Tag 'Scoop' {
|
||||
Get-InstallationHelper -Manifest $manifest2 -Architecture '32bit' | Should -Be @('7zip')
|
||||
}
|
||||
It 'Helpers reflect config changes' {
|
||||
Mock get_config { $false } -ParameterFilter { $name -eq 'MSIEXTRACT_USE_LESSMSI' }
|
||||
Mock get_config { $true } -ParameterFilter { $name -eq '7ZIPEXTRACT_USE_EXTERNAL' }
|
||||
Mock get_config { $false } -ParameterFilter { $name -eq 'USE_LESSMSI' }
|
||||
Mock get_config { $true } -ParameterFilter { $name -eq 'USE_EXTERNAL_7ZIP' }
|
||||
Get-InstallationHelper -Manifest $manifest1 -Architecture '32bit' | Should -BeNullOrEmpty
|
||||
Get-InstallationHelper -Manifest $manifest2 -Architecture '32bit' | Should -BeNullOrEmpty
|
||||
}
|
||||
It 'Not return installed helpers' {
|
||||
Mock get_config { $true } -ParameterFilter { $name -eq 'MSIEXTRACT_USE_LESSMSI' }
|
||||
Mock get_config { $false } -ParameterFilter { $name -eq '7ZIPEXTRACT_USE_EXTERNAL' }
|
||||
Mock get_config { $true } -ParameterFilter { $name -eq 'USE_LESSMSI' }
|
||||
Mock get_config { $false } -ParameterFilter { $name -eq 'USE_EXTERNAL_7ZIP' }
|
||||
Mock Test-HelperInstalled { $true }-ParameterFilter { $Helper -eq '7zip' }
|
||||
Mock Test-HelperInstalled { $false }-ParameterFilter { $Helper -eq 'Lessmsi' }
|
||||
Get-InstallationHelper -Manifest $manifest1 -Architecture '32bit' | Should -Be @('lessmsi')
|
||||
@@ -68,7 +68,7 @@ Describe 'Package Dependencies' -Tag 'Scoop' {
|
||||
Context 'Dependencies resolution' {
|
||||
BeforeAll {
|
||||
Mock Test-HelperInstalled { $false }
|
||||
Mock get_config { $true } -ParameterFilter { $name -eq 'MSIEXTRACT_USE_LESSMSI' }
|
||||
Mock get_config { $true } -ParameterFilter { $name -eq 'USE_LESSMSI' }
|
||||
Mock Get-Manifest { 'lessmsi', @{}, $null, $null } -ParameterFilter { $app -eq 'lessmsi' }
|
||||
Mock Get-Manifest { '7zip', @{ url = 'test.msi' }, $null, $null } -ParameterFilter { $app -eq '7zip' }
|
||||
Mock Get-Manifest { 'innounp', @{}, $null, $null } -ParameterFilter { $app -eq 'innounp' }
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
. "$PSScriptRoot\Scoop-TestLib.ps1"
|
||||
. "$PSScriptRoot\..\lib\json.ps1"
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1"
|
||||
|
||||
Describe 'Pretty json formating' -Tag 'Scoop' {
|
||||
BeforeAll {
|
||||
$format = "$PSScriptRoot\fixtures\format"
|
||||
$manifests = Get-ChildItem "$format\formatted" -File -Filter '*.json'
|
||||
}
|
||||
|
||||
Context 'Beautify manifest' {
|
||||
$manifests | ForEach-Object {
|
||||
if ($PSVersionTable.PSVersion.Major -gt 5) { $_ = $_.Name } # Fix for pwsh
|
||||
|
||||
It "$_" {
|
||||
$pretty_json = (parse_json "$format\unformatted\$_") | ConvertToPrettyJson
|
||||
$correct = (Get-Content "$format\formatted\$_") -join "`r`n"
|
||||
$correct.CompareTo($pretty_json) | Should -Be 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,4 +68,18 @@ Describe 'getopt' -Tag 'Scoop' {
|
||||
$err | Should -BeNullOrEmpty
|
||||
$opt.'long-arg' | Should -Be 'test'
|
||||
}
|
||||
|
||||
It 'handles the option terminator' {
|
||||
$opt, $rem, $err = getopt '--long-arg', '--' '' 'long-arg'
|
||||
$err | Should -BeNullOrEmpty
|
||||
$opt.'long-arg' | Should -BeTrue
|
||||
$rem[0] | Should -BeNullOrEmpty
|
||||
$opt, $rem, $err = getopt '--long-arg', '--', '-x', '-y' 'xy' 'long-arg'
|
||||
$err | Should -BeNullOrEmpty
|
||||
$opt.'long-arg' | Should -BeTrue
|
||||
$opt.'x' | Should -BeNullOrEmpty
|
||||
$opt.'y' | Should -BeNullOrEmpty
|
||||
$rem[0] | Should -Be '-x'
|
||||
$rem[1] | Should -Be '-y'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,37 +6,6 @@
|
||||
|
||||
$isUnix = is_unix
|
||||
|
||||
Describe 'ensure_architecture' -Tag 'Scoop' {
|
||||
It 'should keep correct architectures' {
|
||||
ensure_architecture '32bit' | Should -Be '32bit'
|
||||
ensure_architecture '32' | Should -Be '32bit'
|
||||
ensure_architecture 'x86' | Should -Be '32bit'
|
||||
ensure_architecture 'X86' | Should -Be '32bit'
|
||||
ensure_architecture 'i386' | Should -Be '32bit'
|
||||
ensure_architecture '386' | Should -Be '32bit'
|
||||
ensure_architecture 'i686' | Should -Be '32bit'
|
||||
|
||||
ensure_architecture '64bit' | Should -Be '64bit'
|
||||
ensure_architecture '64' | Should -Be '64bit'
|
||||
ensure_architecture 'x64' | Should -Be '64bit'
|
||||
ensure_architecture 'X64' | Should -Be '64bit'
|
||||
ensure_architecture 'amd64' | Should -Be '64bit'
|
||||
ensure_architecture 'AMD64' | Should -Be '64bit'
|
||||
ensure_architecture 'x86_64' | Should -Be '64bit'
|
||||
ensure_architecture 'x86-64' | Should -Be '64bit'
|
||||
}
|
||||
|
||||
It 'should fallback to the default architecture on empty input' {
|
||||
ensure_architecture '' | Should -Be $(default_architecture)
|
||||
ensure_architecture $null | Should -Be $(default_architecture)
|
||||
}
|
||||
|
||||
It 'should show an error with an invalid architecture' {
|
||||
{ ensure_architecture 'PPC' } | Should -Throw
|
||||
{ ensure_architecture 'PPC' } | Should -Throw "Invalid architecture: 'ppc'"
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'appname_from_url' -Tag 'Scoop' {
|
||||
It 'should extract the correct name' {
|
||||
appname_from_url 'https://example.org/directory/foobar.json' | Should -Be 'foobar'
|
||||
|
||||
49
test/Scoop-Manifest.Tests.ps1
Normal file
49
test/Scoop-Manifest.Tests.ps1
Normal file
@@ -0,0 +1,49 @@
|
||||
. "$PSScriptRoot\Scoop-TestLib.ps1"
|
||||
. "$PSScriptRoot\..\lib\json.ps1"
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1"
|
||||
|
||||
Describe 'Pretty json formating' -Tag 'Scoop' {
|
||||
BeforeAll {
|
||||
$format = "$PSScriptRoot\fixtures\format"
|
||||
$manifests = Get-ChildItem "$format\formatted" -File -Filter '*.json'
|
||||
}
|
||||
|
||||
Context 'Beautify manifest' {
|
||||
$manifests | ForEach-Object {
|
||||
if ($PSVersionTable.PSVersion.Major -gt 5) { $_ = $_.Name } # Fix for pwsh
|
||||
|
||||
It "$_" {
|
||||
$pretty_json = (parse_json "$format\unformatted\$_") | ConvertToPrettyJson
|
||||
$correct = (Get-Content "$format\formatted\$_") -join "`r`n"
|
||||
$correct.CompareTo($pretty_json) | Should -Be 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'Handle ARM64 and correctly fallback' -Tag 'Scoop' {
|
||||
It 'Should return "arm64" if supported' {
|
||||
$manifest1 = @{ url = 'test'; architecture = @{ 'arm64' = @{ pre_install = 'test' } } }
|
||||
$manifest2 = @{ url = 'test'; pre_install = "'arm64'" }
|
||||
$manifest3 = @{ architecture = @{ 'arm64' = @{ url = 'test' } } }
|
||||
Get-SupportedArchitecture $manifest1 'arm64' | Should -Be 'arm64'
|
||||
Get-SupportedArchitecture $manifest2 'arm64' | Should -Be 'arm64'
|
||||
Get-SupportedArchitecture $manifest3 'arm64' | Should -Be 'arm64'
|
||||
}
|
||||
It 'Should return "64bit" if unsupported on Windows 11' {
|
||||
$WindowsBuild = 22000
|
||||
$manifest1 = @{ url = 'test' }
|
||||
$manifest2 = @{ architecture = @{ '64bit' = @{ url = 'test' } } }
|
||||
Get-SupportedArchitecture $manifest1 'arm64' | Should -Be '64bit'
|
||||
Get-SupportedArchitecture $manifest2 'arm64' | Should -Be '64bit'
|
||||
}
|
||||
It 'Should return "32bit" if unsupported on Windows 10' {
|
||||
$WindowsBuild = 19044
|
||||
$manifest2 = @{ url = 'test' }
|
||||
$manifest1 = @{ url = 'test'; architecture = @{ '64bit' = @{ pre_install = 'test' } } }
|
||||
$manifest3 = @{ architecture = @{ '64bit' = @{ url = 'test' } } }
|
||||
Get-SupportedArchitecture $manifest1 'arm64' | Should -Be '32bit'
|
||||
Get-SupportedArchitecture $manifest2 'arm64' | Should -Be '32bit'
|
||||
Get-SupportedArchitecture $manifest3 'arm64' | Should -BeNullOrEmpty
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
#Requires -Modules @{ ModuleName = 'Pester'; MaximumVersion = '4.99' }
|
||||
#Requires -Modules @{ ModuleName = 'PSScriptAnalyzer'; ModuleVersion = '1.17.1' }
|
||||
param(
|
||||
[String] $TestPath = $(Resolve-Path "$PSScriptRoot\..\")
|
||||
[String] $TestPath = $(Convert-Path "$PSScriptRoot\..\")
|
||||
)
|
||||
|
||||
$splat = @{
|
||||
@@ -21,7 +21,7 @@ if ($env:CI -eq $true) {
|
||||
$commitMessage = $env:BHCommitMessage
|
||||
|
||||
# Check if tests are called from the Core itself, if so, adding excludes
|
||||
if ($TestPath -eq $(Resolve-Path "$PSScriptRoot\..\")) {
|
||||
if ($TestPath -eq $(Convert-Path "$PSScriptRoot\..\")) {
|
||||
if ($commitMessage -match '!linter') {
|
||||
Write-Warning "Skipping code linting per commit flag '!linter'"
|
||||
$excludes += 'Linter'
|
||||
|
||||
Reference in New Issue
Block a user