39 Commits

Author SHA1 Message Date
Hsiao-nan Cheung
8aee6f9980 chore(release): Bump to version 0.3.0
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
Co-authored-by: Richard Kuhnt <r15ch13+git@gmail.com>
Co-authored-by: Mathias Hermansson <mathias.hermansson@se.ibm.com>
Co-authored-by: yi_Xu <yi_Xu@yixuju.cn>
Co-authored-by: Chawye Hsu <chawyehsu@hotmail.com>
Co-authored-by: L. Yeung <lewis_yeung-ly@outlook.com>
Co-authored-by: AkariiinMKII <6019344+AkariiinMKII@users.noreply.github.com>
Co-authored-by: KOGA Mitsuhiro <shiena.jp+github@gmail.com>
Co-authored-by: Jules <jules+dev@simplelogin.com>
Co-authored-by: César Román <thecesrom@gmail.com>
2022-10-13 19:09:34 +08:00
Hsiao-nan Cheung
9baf293ab6 docs(changelog): Prepare for version 0.3.0 (#5167) 2022-10-07 00:26:31 +08:00
Hsiao-nan Cheung
7f47f662e2 feat(subdir): Allow subdir in 'bucket' (#5119) 2022-09-28 11:22:33 +08:00
Rashil Gandhi
7a599f062f feat(install): Add support for ARM64 architecture (#5154)
* Initial support for ARMv8

* Add fallback mechanism

* Update changelog

* Update useragent

* Some typo and format changes

* Use `env:ProgramFiles(Arm)` to detect ARM64

- Move `default_architecture()` to `core.ps1`

* Rename 'ensure_architecture()' and 'default_architecture()'

* Refactor 'supports_architecture()' to 'Get-SupportedArchitecture()'

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-09-28 04:19:03 +05:30
Hsiao-nan Cheung
146dab60d1 builds(schema): Remove 'object' from 'anyOf' under 'sourceforge' (#5163) 2022-09-26 20:14:31 +08:00
Hsiao-nan Cheung
04595b417a builds(checkver): Implement SourceForge checkver functionality (#5113)
Co-authored-by: Mathias Hermansson <mathias.hermansson@se.ibm.com>
2022-09-26 19:56:40 +08:00
César Román
782f3f1aa6 feat(checkurls): Allow checking URLs from private_hosts (#5152) 2022-09-16 13:30:08 +08:00
Jules
122fdc1a1c refactor(download): Rename dl() to Invoke-Download() (#5143) 2022-09-16 10:36:40 +08:00
Hsiao-nan Cheung
373007870c builds(vscode): Tweak VSCode setting (#5149) 2022-09-16 10:28:22 +08:00
L. Yeung
6fc65ed864 refactor(scoop-shim): Use getopt to parse arguments (#5125)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-09-11 22:51:49 +08:00
AkariiinMKII
bfef3d8298 fix(scoop-update): Add uninstall_psmodule to update process (#5136) 2022-09-09 14:16:15 +08:00
KOGA Mitsuhiro
5ad35d6054 fix(jsonpath): Prevent converting date string to DateTime in JSONPath (#5130) 2022-09-09 13:40:44 +08:00
AkariiinMKII
740322f74f fix(psmodules): Remove folder recursively when unlinking previous module path (#5127)
* Update psmodules.ps1

* Update CHANGELOG.md

* Update CHANGELOG.md [skip ci]

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-08-29 21:50:27 +05:30
L. Yeung
e06c7f0c81 feat(getopt): Support option terminator (--) (#5121)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-08-25 11:08:31 +08:00
Hsiao-nan Cheung
1985a05b59 refactor(path): Use 'Convert-Path()' instead of 'Resolve-Path()' (#5109) 2022-08-22 15:12:46 +08:00
Chawye Hsu
dea9ebb01a builds(schema): Set manifest schema to be stricter (#5093) 2022-08-21 19:58:27 +08:00
Hsiao-nan Cheung
08ecdd16a8 fix(config): Change config option to snake_case in file and SCREAMING_CASE in code (#5116) 2022-08-21 19:51:31 +08:00
Hsiao-nan Cheung
a9e5a974dd feat(scoop-config): Allow 'hold_update_until' be set manually (#5100)
Co-authored-by: Richard Kuhnt <r15ch13+git@gmail.com>
2022-08-16 10:03:25 +08:00
yi_Xu
8619ee7603 feat(uninstall): Show the running processes (#5102)
* feat(install): show the running process

* docs(CHANGELOG): Update changelog

* perf(install): Show process-name in table format

* Update lib/install.ps1

Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>

* Update lib/install.ps1

Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>

Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
2022-08-15 15:02:47 +05:30
Hsiao-nan Cheung
bd123939dc feat(scoop-update): Stash uncommitted changes before update (#5091) 2022-08-11 18:10:42 +08:00
yi_Xu
ec04dd07bc feat(scoop-(un)hold): Support scoop (un)hold scoop (#5089)
* feat(scoop-config): Add new configuration of `SCOOP_HOLD`

Allow to disable Scoop itself updates.
This configuration have the same function with 'scoop (un)hold scoop'.

* perf(scoop-update): Separate `update_bucket` from `update_scoop`

* perf(scoop-(un)hold): remove big overarching if-statement

* perf(scoop-config): use `SCOOP_HOLD_DAYS` instead of `SCOOP_HOLD`

* perf(scoop-config): Update forward Compatible code

* Update libexec/scoop-config.ps1

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>

* Update libexec/scoop-hold.ps1

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>

* Update libexec/scoop-unhold.ps1

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>

* Update libexec/scoop-update.ps1

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>

* perf(scoop-update): Update last_scoop_update

* docs(changelog): update changelog to add feature

* fix(changelog): fix changelog typo

* Update libexec/scoop-update.ps1

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>

* Update libexec/scoop-config.ps1

Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>

* Update libexec/scoop-update.ps1

Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>

* refactor: Use `lastUpdate` instead of `lastupdate`

Consistent with scoop-export.

* fix(install): make config lastUpdate silent

* refactor(scoop-update): Remove `SCOOP_HOLD`

* fix: update changelog

remove none used code.

* Update lib/core.ps1

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>

* Update libexec/scoop-update.ps1

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>

* Update libexec/scoop-update.ps1

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>

* Update libexec/scoop-update.ps1

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>

* Update libexec/scoop-update.ps1

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>

* Update libexec/scoop-update.ps1

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>

* Update libexec/scoop-update.ps1

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>

* Update libexec/scoop-update.ps1

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>

* Update libexec/scoop-update.ps1

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>

* Update libexec/scoop-update.ps1

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>

* perf(scoop-update): Handle the judgment in try-catch

* fix(scoop-update): Remove 'update_until' when update scoop itself

* Update lib/core.ps1

Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>

* docs(CHANGELOG): Update changelog

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
2022-08-11 14:50:40 +05:30
Hsiao-nan Cheung
4a31bd3302 chore(release): Bump to version 0.2.4 2022-08-10 13:14:12 +08:00
Hsiao-nan Cheung
5b5daa5ee9 fix(installed): Use 'System.Nullable<bool>' for param 'global' (#5088) 2022-08-07 02:57:12 +08:00
Hsiao-nan Cheung
9b4ee8795d docs(changelog): Change version date [skip ci] (#5087) 2022-08-06 21:02:11 +08:00
yi_Xu
7bfef4912c feat(scoop-update): Add support for pre_uninstall and post_uninstall (#5085) 2022-08-06 20:59:39 +08:00
Hsiao-nan Cheung
ca19d7b856 docs(changelog): Prepare for version 0.2.4 (#5078) 2022-08-05 14:42:00 +08:00
Hsiao-nan Cheung
f945e20167 builds(checkver): Load page content before running 'script' (#5080) 2022-08-05 14:41:30 +08:00
Rashil Gandhi
4d261e7349 feat(scoop-status): Add flag to disable remote checking (#5073)
* feat(scoop-status): Add flag to disable remote checking

* changelog

* Add `break` to stop checking rest of the buckets

* change flag name to `--local`

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-08-04 08:35:28 +05:30
Rashil Gandhi
c3b43625fa feat(install): Show bucket name while installing an app (#5075)
* Update install.ps1

* Update CHANGELOG.md
2022-08-01 22:08:06 +05:30
L. Yeung
34da8507a8 feat(core): Create no window by default in Invoke-ExternalCommand (#5066) 2022-07-26 00:46:08 +08:00
L. Yeung
288aee9ee9 feat(core): Improve argument concatenation in Invoke-ExternalCommand (#5065) 2022-07-25 23:44:26 +08:00
L. Yeung
eac520a4d8 fix(core): Avoid deadlock in Invoke-ExternalCommand (#5064) 2022-07-25 23:43:08 +08:00
Hsiao-nan Cheung
6ae0d5eb8f builds(json): Update Newtonsoft.Json.Schema to 3.0.15-beta2 (#5053) 2022-07-19 15:01:28 +08:00
Rashil Gandhi
9e2e2526fb fix(install): Move from cache when --no-cache (#5039)
* fix(install): Move from cache when `--no-cache`

* Update CHANGELOG.md
2022-07-16 09:59:43 +05:30
L. Yeung
664e667bed fix(scoop-status): Correct formatting of Info output (#5047)
* fix(scoop-status): Correct formatting of `Info` output

* Update CHANGELOG.md
2022-07-15 11:38:30 +05:30
Rashil Gandhi
80b52e32a1 chore(release): Bump to version 0.2.3
Merge pull request #5031 from ScoopInstaller/develop
2022-07-07 15:25:40 +05:30
zStruCat
b4e0ff16a6 fix(scoop-import): Use foreach instead of ForEach-Object for nullity check (#5034)
* Add nullity check and alread_in_local_bucket check

* update CHANGELOG

* Use foreach instead of ForEach-Object

* changelog

* update help

* refine the info and warning when adding an already-added bucket

* Update lib/buckets.ps1

Make warning clearer

Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>

Co-authored-by: Rashil Gandhi <rashil2000@gmail.com>
Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
2022-07-07 10:49:53 +05:30
Hsiao-nan Cheung
c5702ddd19 docs(changelog): Prepare for v0.2.3 (#5036) 2022-07-05 18:11:10 +08:00
Rashil Gandhi
f992f049cc fix(chore): Fix help output of scoop-export (#5029) 2022-07-02 23:21:10 +08:00
56 changed files with 926 additions and 514 deletions

View File

@@ -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
View File

@@ -1,3 +1,4 @@
*.log
.DS_Store
._.DS_Store
scoop.sublime-workspace

View File

@@ -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,

View File

@@ -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

View File

@@ -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!"
}

View File

@@ -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)
}
}

View File

@@ -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

View File

@@ -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 $_

View File

@@ -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 {

View File

@@ -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)
}

View File

@@ -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."

View File

@@ -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
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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 *')) {

View File

@@ -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]

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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"
}

View File

@@ -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
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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 {

View File

@@ -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++
}

View File

@@ -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"

View File

@@ -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: $_"
}

View File

@@ -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"

View File

@@ -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)
}
}

View File

@@ -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'

View File

@@ -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
}
}

View File

@@ -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)"

View File

@@ -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: $_"
}

View File

@@ -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"
}

View File

@@ -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

View File

@@ -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

View File

@@ -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' }

View File

@@ -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'

View File

@@ -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

View File

@@ -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" +

View File

@@ -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",

View File

@@ -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

View File

@@ -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

View File

@@ -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>

View File

@@ -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" />

View File

@@ -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)
}

View File

@@ -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)"
}

View File

@@ -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'"
}
}

View File

@@ -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' }

View File

@@ -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
}
}
}
}

View File

@@ -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'
}
}

View File

@@ -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'

View 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
}
}

View File

@@ -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'