mirror of
https://github.com/ScoopInstaller/Scoop.git
synced 2025-11-29 21:03:23 +00:00
Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f93028001f | ||
|
|
c60df9cdad | ||
|
|
ac71c6e1b7 | ||
|
|
0f795733d8 | ||
|
|
29ed3cb050 | ||
|
|
d7bfe52122 | ||
|
|
29e5898a45 | ||
|
|
ea6c73880a | ||
|
|
e4f9734b88 | ||
|
|
1630e5f908 | ||
|
|
2474ab73e4 | ||
|
|
d65fee6d26 | ||
|
|
01fe9ccd63 | ||
|
|
1c6ab39e90 | ||
|
|
c71376e12c | ||
|
|
c9dc41e7c4 | ||
|
|
5e6a9eeaa0 | ||
|
|
b308769b14 | ||
|
|
1eea29b0d1 | ||
|
|
7dcb7c0030 | ||
|
|
9fda5428ae | ||
|
|
d0cbc36a58 | ||
|
|
512ab44029 | ||
|
|
1f0f687a39 | ||
|
|
ec8161df6c | ||
|
|
24301ac028 | ||
|
|
8aee6f9980 | ||
|
|
9baf293ab6 | ||
|
|
7f47f662e2 | ||
|
|
7a599f062f | ||
|
|
146dab60d1 | ||
|
|
04595b417a | ||
|
|
782f3f1aa6 | ||
|
|
122fdc1a1c | ||
|
|
373007870c | ||
|
|
6fc65ed864 | ||
|
|
bfef3d8298 | ||
|
|
5ad35d6054 | ||
|
|
740322f74f | ||
|
|
e06c7f0c81 | ||
|
|
1985a05b59 | ||
|
|
dea9ebb01a | ||
|
|
08ecdd16a8 | ||
|
|
a9e5a974dd | ||
|
|
8619ee7603 | ||
|
|
bd123939dc | ||
|
|
ec04dd07bc | ||
|
|
4a31bd3302 | ||
|
|
5b5daa5ee9 | ||
|
|
9b4ee8795d | ||
|
|
7bfef4912c | ||
|
|
ca19d7b856 | ||
|
|
f945e20167 | ||
|
|
4d261e7349 | ||
|
|
c3b43625fa | ||
|
|
34da8507a8 | ||
|
|
288aee9ee9 | ||
|
|
eac520a4d8 | ||
|
|
6ae0d5eb8f | ||
|
|
9e2e2526fb | ||
|
|
664e667bed | ||
|
|
80b52e32a1 | ||
|
|
b4e0ff16a6 | ||
|
|
c5702ddd19 | ||
|
|
f992f049cc | ||
|
|
76c3bcd70c | ||
|
|
794f8a51aa | ||
|
|
53f0e9a18c | ||
|
|
1b5ee6f090 | ||
|
|
c4d1b9c22f | ||
|
|
9811a5f853 | ||
|
|
6629331799 | ||
|
|
4fec4d7089 | ||
|
|
83d0fef02f | ||
|
|
0fd6657572 | ||
|
|
9723725402 | ||
|
|
847756bd1e | ||
|
|
86e3efbaf0 |
4
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
4
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
@@ -31,9 +31,9 @@ labels: "bug"
|
||||
|
||||
### System details
|
||||
|
||||
**Windows version:** [e.g. 7, 8, 10]
|
||||
**Windows version:** [e.g. 7, 8, 10, 11]
|
||||
|
||||
**OS architecture:** [e.g. 32bit, 64bit]
|
||||
**OS architecture:** [e.g. 32bit, 64bit, arm64]
|
||||
|
||||
**PowerShell version:** [output of `"$($PSVersionTable.PSVersion)"`]
|
||||
|
||||
|
||||
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
@@ -10,13 +10,13 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@main
|
||||
with:
|
||||
fetch-depth: 2
|
||||
- name: Init Test Suite
|
||||
uses: potatoqualitee/psmodulecache@v4
|
||||
uses: potatoqualitee/psmodulecache@v5.1
|
||||
with:
|
||||
modules-to-cache: PSScriptAnalyzer, BuildHelpers, Pester:4.10.1
|
||||
modules-to-cache: BuildHelpers
|
||||
shell: powershell
|
||||
- name: Test Scoop Core
|
||||
shell: powershell
|
||||
@@ -26,13 +26,13 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@main
|
||||
with:
|
||||
fetch-depth: 2
|
||||
- name: Init Test Suite
|
||||
uses: potatoqualitee/psmodulecache@v4
|
||||
uses: potatoqualitee/psmodulecache@v5.1
|
||||
with:
|
||||
modules-to-cache: PSScriptAnalyzer, BuildHelpers, Pester:4.10.1
|
||||
modules-to-cache: BuildHelpers
|
||||
shell: pwsh
|
||||
- name: Test Scoop Core
|
||||
shell: pwsh
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
*.log
|
||||
.DS_Store
|
||||
._.DS_Store
|
||||
scoop.sublime-workspace
|
||||
|
||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -4,6 +4,9 @@
|
||||
"powershell.codeFormatting.preset": "OTBS",
|
||||
"powershell.codeFormatting.alignPropertyValuePairs": true,
|
||||
"powershell.codeFormatting.ignoreOneLineBlock": true,
|
||||
"powershell.codeFormatting.useConstantStrings": true,
|
||||
"powershell.codeFormatting.useCorrectCasing": true,
|
||||
"powershell.codeFormatting.whitespaceBetweenParameters": true,
|
||||
"files.exclude": {
|
||||
"**/.git": true,
|
||||
"**/.svn": true,
|
||||
|
||||
128
CHANGELOG.md
128
CHANGELOG.md
@@ -1,3 +1,131 @@
|
||||
## [v0.3.1](https://github.com/ScoopInstaller/Scoop/compare/v0.3.0...v0.3.1) - 2022-11-15
|
||||
|
||||
### Features
|
||||
|
||||
- **config:** Allow Scoop to check if apps versioned as 'nightly' are outdated ([#5166](https://github.com/ScoopInstaller/Scoop/issues/5166))
|
||||
- **checkup:** Add Windows Developer Mode check ([#5233](https://github.com/ScoopInstaller/Scoop/issues/5233))
|
||||
- **bucket:** Add 'sysinternals' bucket to known ([#5237](https://github.com/ScoopInstaller/Scoop/issues/5237))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **decompress:** Use PS's default 'Expand-Archive()' ([#5185](https://github.com/ScoopInstaller/Scoop/issues/5185))
|
||||
- **hash:** Fix SourceForge's hash extraction ([#5189](https://github.com/ScoopInstaller/Scoop/issues/5189))
|
||||
- **decompress:** Trim ending '/' ([#5195](https://github.com/ScoopInstaller/Scoop/issues/5195))
|
||||
- **shim:** Exit if shim creating failed 'cause no git ([#5225](https://github.com/ScoopInstaller/Scoop/issues/5225))
|
||||
- **scoop-import:** Add correct architecture argument ([#5210](https://github.com/ScoopInstaller/Scoop/issues/5210))
|
||||
- **scoop-config:** Output `[DateTime]` as `[String]` ([#5232](https://github.com/ScoopInstaller/Scoop/issues/5232))
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
- **hash:** Use `Get-FileHash()` directly ([#5177](https://github.com/ScoopInstaller/Scoop/issues/5177))
|
||||
- **installer:** Drop the old installer ([#5186](https://github.com/ScoopInstaller/Scoop/issues/5186))
|
||||
- **unix:** Remove `unix.ps1` ([#5235](https://github.com/ScoopInstaller/Scoop/issues/5235))
|
||||
|
||||
### Builds
|
||||
|
||||
- **auto-pr:** Add `CommitMessageFormat` option ([#5171](https://github.com/ScoopInstaller/Scoop/issues/5171))
|
||||
- **checkver:** Support XML default namespace ([#5191](https://github.com/ScoopInstaller/Scoop/issues/5191))
|
||||
- **pssa:** Remove unused 'ExcludeRules' ([#5201](https://github.com/ScoopInstaller/Scoop/issues/5201))
|
||||
- **schema:** Add 'installer' and 'shortcuts' to 'autoupdate' ([#5220](https://github.com/ScoopInstaller/Scoop/issues/5220))
|
||||
- **checkhashes:** Use correct version number if `UseCache` ([#5240](https://github.com/ScoopInstaller/Scoop/issues/5240))
|
||||
|
||||
### Continuous Integration
|
||||
|
||||
- **module:** Update modules version ([#5209](https://github.com/ScoopInstaller/Scoop/issues/5209))
|
||||
|
||||
### Tests
|
||||
|
||||
- **unix:** Fix tests in Linux and macOS ([#5179](https://github.com/ScoopInstaller/Scoop/issues/5179))
|
||||
- **pester:** Update to Pester 5 ([#5222](https://github.com/ScoopInstaller/Scoop/issues/5222))
|
||||
- **bucket:** Use BuildHelpers' EnvVars ([#5226](https://github.com/ScoopInstaller/Scoop/issues/5226))
|
||||
|
||||
### Documentation
|
||||
|
||||
- **scoop-cat:** Fix help message([#5224](https://github.com/ScoopInstaller/Scoop/issues/5224))
|
||||
|
||||
## [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), [#5034](https://github.com/ScoopInstaller/Scoop/issues/5034))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **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))
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
- **scoop-search:** Output PSObject, use API token ([#4997](https://github.com/ScoopInstaller/Scoop/issues/4997))
|
||||
|
||||
### Builds
|
||||
|
||||
- **checkver,auto-pr:** Allow passing file path ([#5019](https://github.com/ScoopInstaller/Scoop/issues/5019))
|
||||
- **checkver:** Exit routine earlier if error ([#5025](https://github.com/ScoopInstaller/Scoop/issues/5025))
|
||||
- **json:** Update Newton.Json to 13.0.1 ([#5026](https://github.com/ScoopInstaller/Scoop/issues/5026))
|
||||
|
||||
### Tests
|
||||
|
||||
- **typo:** Fix typo ('formated' -> 'formatted') ([#4217](https://github.com/ScoopInstaller/Scoop/issues/4217))
|
||||
|
||||
## [v0.2.2](https://github.com/ScoopInstaller/Scoop/compare/v0.2.1...v0.2.2) - 2022-06-21
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
# The PowerShell Script Analyzer will generate a warning
|
||||
# diagnostic record for this file due to a bug -
|
||||
# https://github.com/PowerShell/PSScriptAnalyzer/issues/472
|
||||
@{
|
||||
# Only diagnostic records of the specified severity will be generated.
|
||||
# Uncomment the following line if you only want Errors and Warnings but
|
||||
@@ -26,12 +23,6 @@
|
||||
# will be excluded.
|
||||
ExcludeRules = @(
|
||||
# Currently Scoop widely uses Write-Host to output colored text.
|
||||
'PSAvoidUsingWriteHost',
|
||||
# Temporarily allow uses of Invoke-Expression,
|
||||
# this command is used by some core functions and hard to be removed.
|
||||
'PSAvoidUsingInvokeExpression',
|
||||
# PSUseDeclaredVarsMoreThanAssignments doesn't currently work due to:
|
||||
# https://github.com/PowerShell/PSScriptAnalyzer/issues/636
|
||||
'PSUseDeclaredVarsMoreThanAssignments'
|
||||
'PSAvoidUsingWriteHost'
|
||||
)
|
||||
}
|
||||
|
||||
@@ -120,17 +120,21 @@ The following buckets are known to scoop:
|
||||
- [games](https://github.com/Calinou/scoop-games) - Open source/freeware games and game-related tools
|
||||
- [nerd-fonts](https://github.com/matthewjberger/scoop-nerd-fonts) - Nerd Fonts
|
||||
- [nirsoft](https://github.com/kodybrown/scoop-nirsoft) - Almost all of the [250+](https://rasa.github.io/scoop-directory/by-apps#kodybrown_scoop-nirsoft) apps from [Nirsoft](https://nirsoft.net)
|
||||
- [sysinternals](https://github.com/niheaven/scoop-sysinternals) - Sysinternals Suite and all individual application from [Microsoft](https://learn.microsoft.com/sysinternals/)
|
||||
- [java](https://github.com/ScoopInstaller/Java) - A collection of Java development kits (JDKs), Java runtime engines (JREs), Java's virtual machine debugging tools and Java based runtime engines.
|
||||
- [nonportable](https://github.com/ScoopInstaller/Nonportable) - Non-portable apps (may require UAC)
|
||||
- [php](https://github.com/ScoopInstaller/PHP) - Installers for most versions of PHP
|
||||
- [versions](https://github.com/ScoopInstaller/Versions) - Alternative versions of apps found in other buckets
|
||||
|
||||
The main bucket is installed by default. To add any of the other buckets, type:
|
||||
```
|
||||
|
||||
```console
|
||||
scoop bucket add bucketname
|
||||
```
|
||||
|
||||
For example, to add the extras bucket, type:
|
||||
```
|
||||
|
||||
```console
|
||||
scoop bucket add extras
|
||||
```
|
||||
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
.PARAMETER App
|
||||
Manifest name to search.
|
||||
Placeholders are supported.
|
||||
.PARAMETER CommitMessageFormat
|
||||
The format of the commit message.
|
||||
<app> will be replaced with the file name of manifest.
|
||||
<version> will be replaced with the version of the latest manifest.
|
||||
.PARAMETER Dir
|
||||
The directory where to search for manifests.
|
||||
.PARAMETER Push
|
||||
@@ -43,7 +47,7 @@ param(
|
||||
[String] $Upstream,
|
||||
[String] $OriginBranch = 'master',
|
||||
[String] $App = '*',
|
||||
[Parameter(Mandatory = $true)]
|
||||
[String] $CommitMessageFormat = '<app>: Update to version <version>',
|
||||
[ValidateScript( {
|
||||
if (!(Test-Path $_ -Type Container)) {
|
||||
throw "$_ is not a directory!"
|
||||
@@ -62,9 +66,14 @@ param(
|
||||
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1"
|
||||
. "$PSScriptRoot\..\lib\json.ps1"
|
||||
. "$PSScriptRoot\..\lib\unix.ps1"
|
||||
|
||||
$Dir = Resolve-Path $Dir
|
||||
if ($App -ne '*' -and (Test-Path $App -PathType Leaf)) {
|
||||
$Dir = Split-Path $App
|
||||
} elseif ($Dir) {
|
||||
$Dir = Convert-Path $Dir
|
||||
} else {
|
||||
throw "'-Dir' parameter required if '-App' is not a filepath!"
|
||||
}
|
||||
|
||||
if ((!$Push -and !$Request) -or $Help) {
|
||||
Write-Host @'
|
||||
@@ -82,7 +91,7 @@ Optional options:
|
||||
exit 0
|
||||
}
|
||||
|
||||
if (is_unix) {
|
||||
if ($IsLinux -or $IsMacOS) {
|
||||
if (!(which hub)) {
|
||||
Write-Host "Please install hub ('brew install hub' or visit: https://hub.github.com/)" -ForegroundColor Yellow
|
||||
exit 1
|
||||
@@ -105,7 +114,7 @@ function execute($cmd) {
|
||||
return $output
|
||||
}
|
||||
|
||||
function pull_requests($json, [String] $app, [String] $upstream, [String] $manifest) {
|
||||
function pull_requests($json, [String] $app, [String] $upstream, [String] $manifest, [String] $commitMessage) {
|
||||
$version = $json.version
|
||||
$homepage = $json.homepage
|
||||
$branch = "manifest/$app-$version"
|
||||
@@ -122,7 +131,7 @@ function pull_requests($json, [String] $app, [String] $upstream, [String] $manif
|
||||
Write-Host "Creating update $app ($version) ..." -ForegroundColor DarkCyan
|
||||
execute "hub checkout -b $branch"
|
||||
execute "hub add $manifest"
|
||||
execute "hub commit -m '${app}: Update to version $version'"
|
||||
execute "hub commit -m '$commitMessage"
|
||||
Write-Host "Pushing update $app ($version) ..." -ForegroundColor DarkCyan
|
||||
execute "hub push origin $branch"
|
||||
|
||||
@@ -137,7 +146,7 @@ function pull_requests($json, [String] $app, [String] $upstream, [String] $manif
|
||||
Write-Host "hub pull-request -m '<msg>' -b '$upstream' -h '$branch'" -ForegroundColor Green
|
||||
|
||||
$msg = @"
|
||||
$app`: Update to version $version
|
||||
$commitMessage
|
||||
|
||||
Hello lovely humans,
|
||||
a new version of [$app]($homepage) is available.
|
||||
@@ -150,7 +159,7 @@ a new version of [$app]($homepage) is available.
|
||||
hub pull-request -m "$msg" -b "$upstream" -h "$branch"
|
||||
if ($LASTEXITCODE -gt 0) {
|
||||
execute 'hub reset'
|
||||
abort "Pull Request failed! (hub pull-request -m '${app}: Update to version $version' -b '$upstream' -h '$branch')"
|
||||
abort "Pull Request failed! (hub pull-request -m '$commitMessage' -b '$upstream' -h '$branch')"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +193,7 @@ hub diff --name-only | ForEach-Object {
|
||||
return
|
||||
}
|
||||
$version = $json.version
|
||||
|
||||
$CommitMessage = $CommitMessageFormat -replace '<app>',$app -replace '<version>',$version
|
||||
if ($Push) {
|
||||
Write-Host "Creating update $app ($version) ..." -ForegroundColor DarkCyan
|
||||
execute "hub add $manifest"
|
||||
@@ -193,12 +202,12 @@ hub diff --name-only | ForEach-Object {
|
||||
$status = execute 'hub status --porcelain -uno'
|
||||
$status = $status | Where-Object { $_ -match "M\s{2}.*$app.json" }
|
||||
if ($status -and $status.StartsWith('M ') -and $status.EndsWith("$app.json")) {
|
||||
execute "hub commit -m '${app}: Update to version $version'"
|
||||
execute "hub commit -m '$commitMessage'"
|
||||
} else {
|
||||
Write-Host "Skipping $app because only LF/CRLF changes were detected ..." -ForegroundColor Yellow
|
||||
}
|
||||
} else {
|
||||
pull_requests $json $app $Upstream $manifest
|
||||
pull_requests $json $app $Upstream $manifest $CommitMessage
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,9 +47,8 @@ param(
|
||||
. "$PSScriptRoot\..\lib\json.ps1"
|
||||
. "$PSScriptRoot\..\lib\versions.ps1"
|
||||
. "$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 +59,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 +79,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 +94,7 @@ foreach ($single in Get-ChildItem $Dir "$App.json") {
|
||||
|
||||
$MANIFESTS += @{
|
||||
app = $name
|
||||
file = $file
|
||||
manifest = $manifest
|
||||
urls = $urls
|
||||
hashes = $hashes
|
||||
@@ -110,13 +113,16 @@ foreach ($current in $MANIFESTS) {
|
||||
|
||||
$current.urls | ForEach-Object {
|
||||
$algorithm, $expected = get_hash $current.hashes[$count]
|
||||
$version = 'HASH_CHECK'
|
||||
$tmp = $expected_hash -split ':'
|
||||
if ($UseCache) {
|
||||
$version = $current.manifest.version
|
||||
} else {
|
||||
$version = 'HASH_CHECK'
|
||||
}
|
||||
|
||||
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
|
||||
$actual_hash = (Get-FileHash -Path $to_check -Algorithm $algorithm).Hash.ToLower()
|
||||
|
||||
# Append type of algorithm to both expected and actual if it's not sha256
|
||||
if ($algorithm -ne 'sha256') {
|
||||
@@ -141,12 +147,12 @@ foreach ($current in $MANIFESTS) {
|
||||
Write-Host 'Mismatch found ' -ForegroundColor Red
|
||||
$mismatched | ForEach-Object {
|
||||
$file = fullpath (cache_path $current.app $version $current.urls[$_])
|
||||
Write-Host "`tURL:`t`t$($current.urls[$_])"
|
||||
Write-Host "`tURL:`t`t$($current.urls[$_])"
|
||||
if (Test-Path $file) {
|
||||
Write-Host "`tFirst bytes:`t$((get_magic_bytes_pretty $file ' ').ToUpper())"
|
||||
Write-Host "`tFirst bytes:`t$((get_magic_bytes_pretty $file ' ').ToUpper())"
|
||||
}
|
||||
Write-Host "`tExpected:`t$($current.hashes[$_])" -ForegroundColor Green
|
||||
Write-Host "`tActual:`t`t$($actuals[$_])" -ForegroundColor Red
|
||||
Write-Host "`tExpected:`t$($current.hashes[$_])" -ForegroundColor Green
|
||||
Write-Host "`tActual:`t`t$($actuals[$_])" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,23 +164,27 @@ foreach ($current in $MANIFESTS) {
|
||||
# Defaults to zero, don't know, which architecture is available
|
||||
$64bit_count = 0
|
||||
$32bit_count = 0
|
||||
$arm64_count = 0
|
||||
|
||||
# 64bit is get, donwloaded and added first
|
||||
if ($platforms.Contains('64bit')) {
|
||||
$64bit_count = $current.manifest.architecture.'64bit'.hash.Count
|
||||
# 64bit is get, donwloaded and added first
|
||||
$current.manifest.architecture.'64bit'.hash = $actuals[0..($64bit_count - 1)]
|
||||
}
|
||||
if ($platforms.Contains('32bit')) {
|
||||
$32bit_count = $current.manifest.architecture.'32bit'.hash.Count
|
||||
$max = $64bit_count + $32bit_count - 1 # Edge case if manifest contains 64bit and 32bit.
|
||||
$current.manifest.architecture.'32bit'.hash = $actuals[($64bit_count)..$max]
|
||||
$current.manifest.architecture.'32bit'.hash = $actuals[($64bit_count)..($64bit_count + $32bit_count - 1)]
|
||||
}
|
||||
if ($platforms.Contains('arm64')) {
|
||||
$arm64_count = $current.manifest.architecture.'arm64'.hash.Count
|
||||
$current.manifest.architecture.'arm64'.hash = $actuals[($64bit_count + $32bit_count)..($64bit_count + $32bit_count + $arm64_count - 1)]
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Writing updated $($current.app) manifest" -ForegroundColor DarkGreen
|
||||
|
||||
$current.manifest = $current.manifest | ConvertToPrettyJson
|
||||
$path = Resolve-Path "$Dir\$($current.app).json"
|
||||
$path = Convert-Path $current.file
|
||||
[System.IO.File]::WriteAllLines($path, $current.manifest)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,12 +30,12 @@ param(
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1"
|
||||
. "$PSScriptRoot\..\lib\install.ps1"
|
||||
|
||||
$Dir = Resolve-Path $Dir
|
||||
$Dir = Convert-Path $Dir
|
||||
$Queue = @()
|
||||
|
||||
Get-ChildItem $Dir "$App.json" | ForEach-Object {
|
||||
$manifest = parse_json "$Dir\$($_.Name)"
|
||||
$Queue += , @($_.Name, $manifest)
|
||||
Get-ChildItem $Dir -Filter "$App.json" -Recurse | ForEach-Object {
|
||||
$manifest = parse_json $_.FullName
|
||||
$Queue += , @($_.BaseName, $manifest)
|
||||
}
|
||||
|
||||
Write-Host '[' -NoNewLine
|
||||
@@ -62,6 +62,13 @@ function test_dl([String] $url, $cookies) {
|
||||
$wreq.Headers.Add('Cookie', (cookie_header $cookies))
|
||||
}
|
||||
}
|
||||
|
||||
get_config PRIVATE_HOSTS | Where-Object { $_ -ne $null -and $url -match $_.match } | ForEach-Object {
|
||||
(ConvertFrom-StringData -StringData $_.Headers).GetEnumerator() | ForEach-Object {
|
||||
$wreq.Headers[$_.Key] = $_.Value
|
||||
}
|
||||
}
|
||||
|
||||
$wres = $null
|
||||
try {
|
||||
$wres = $wreq.GetResponse()
|
||||
@@ -91,6 +98,7 @@ foreach ($man in $Queue) {
|
||||
} else {
|
||||
script:url $manifest '64bit' | ForEach-Object { $urls += $_ }
|
||||
script:url $manifest '32bit' | ForEach-Object { $urls += $_ }
|
||||
script:url $manifest 'arm64' | ForEach-Object { $urls += $_ }
|
||||
}
|
||||
|
||||
$urls | ForEach-Object {
|
||||
@@ -125,7 +133,7 @@ foreach ($man in $Queue) {
|
||||
Write-Host $failed -NoNewLine -ForegroundColor Red
|
||||
}
|
||||
Write-Host '] ' -NoNewLine
|
||||
Write-Host (strip_ext $name)
|
||||
Write-Host $name
|
||||
|
||||
$errors | ForEach-Object {
|
||||
Write-Host " > $_" -ForegroundColor DarkRed
|
||||
|
||||
122
bin/checkver.ps1
122
bin/checkver.ps1
@@ -52,7 +52,6 @@
|
||||
#>
|
||||
param(
|
||||
[String] $App = '*',
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateScript( {
|
||||
if (!(Test-Path $_ -Type Container)) {
|
||||
throw "$_ is not a directory!"
|
||||
@@ -75,10 +74,17 @@ param(
|
||||
. "$PSScriptRoot\..\lib\json.ps1"
|
||||
. "$PSScriptRoot\..\lib\versions.ps1"
|
||||
. "$PSScriptRoot\..\lib\install.ps1" # needed for hash generation
|
||||
. "$PSScriptRoot\..\lib\unix.ps1"
|
||||
|
||||
$Dir = Resolve-Path $Dir
|
||||
$Search = $App
|
||||
if ($App -ne '*' -and (Test-Path $App -PathType Leaf)) {
|
||||
$Dir = Split-Path $App
|
||||
$files = Get-ChildItem $Dir -Filter (Split-Path $App -Leaf)
|
||||
} elseif ($Dir) {
|
||||
$Dir = Convert-Path $Dir
|
||||
$files = Get-ChildItem $Dir -Filter "$App.json" -Recurse
|
||||
} else {
|
||||
throw "'-Dir' parameter required if '-App' is not a filepath!"
|
||||
}
|
||||
|
||||
$GitHubToken = Get-GitHubToken
|
||||
|
||||
# don't use $Version with $App = '*'
|
||||
@@ -89,21 +95,21 @@ if ($App -eq '*' -and $Version -ne '') {
|
||||
# get apps to check
|
||||
$Queue = @()
|
||||
$json = ''
|
||||
Get-ChildItem $Dir "$App.json" | ForEach-Object {
|
||||
$json = parse_json "$Dir\$($_.Name)"
|
||||
$files | ForEach-Object {
|
||||
$file = $_.FullName
|
||||
$json = parse_json $file
|
||||
if ($json.checkver) {
|
||||
$Queue += , @($_.Name, $json)
|
||||
$Queue += , @($_.BaseName, $json, $file)
|
||||
}
|
||||
}
|
||||
|
||||
# clear any existing events
|
||||
Get-Event | ForEach-Object {
|
||||
Remove-Event $_.SourceIdentifier
|
||||
}
|
||||
Get-Event | Remove-Event
|
||||
Get-EventSubscriber | Unregister-Event
|
||||
|
||||
# start all downloads
|
||||
$Queue | ForEach-Object {
|
||||
$name, $json = $_
|
||||
$name, $json, $file = $_
|
||||
|
||||
$substitutions = Get-VersionSubstitution $json.version # 'autoupdate.ps1'
|
||||
|
||||
@@ -115,18 +121,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
|
||||
}
|
||||
$regex = ''
|
||||
|
||||
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"
|
||||
@@ -142,11 +162,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) {
|
||||
@@ -159,7 +206,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
|
||||
}
|
||||
|
||||
@@ -179,7 +226,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;
|
||||
@@ -207,31 +255,34 @@ 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
|
||||
$ver = $Version
|
||||
|
||||
if (!$ver) {
|
||||
$page = (Get-Encoding($wc)).GetString($ev.SourceEventArgs.Result)
|
||||
$err = $ev.SourceEventArgs.Error
|
||||
if ($json.checkver.script) {
|
||||
$page = Invoke-Command ([scriptblock]::Create($json.checkver.script -join "`r`n"))
|
||||
if (!$regex -and $replace) {
|
||||
next "'replace' requires 're' or 'regex'"
|
||||
continue
|
||||
}
|
||||
|
||||
$err = $ev.SourceEventArgs.Error
|
||||
if ($err) {
|
||||
next "$($err.message)`r`nURL $url is not valid"
|
||||
continue
|
||||
}
|
||||
|
||||
if (!$regex -and $replace) {
|
||||
next "'replace' requires 're' or 'regex'"
|
||||
continue
|
||||
if ($url) {
|
||||
$page = (Get-Encoding($wc)).GetString($ev.SourceEventArgs.Result)
|
||||
}
|
||||
if ($script) {
|
||||
$page = Invoke-Command ([scriptblock]::Create($script -join "`r`n"))
|
||||
}
|
||||
|
||||
if ($jsonpath) {
|
||||
@@ -258,12 +309,17 @@ while ($in_progress -gt 0) {
|
||||
# Then add them into the NamespaceManager
|
||||
$nsmgr = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
|
||||
$nsList | ForEach-Object {
|
||||
$nsmgr.AddNamespace($_.LocalName, $_.Value)
|
||||
if ($_.LocalName -eq 'xmlns') {
|
||||
$nsmgr.AddNamespace('ns', $_.Value)
|
||||
$xpath = $xpath -replace '/([^:/]+)((?=/)|(?=$))', '/ns:$1'
|
||||
} else {
|
||||
$nsmgr.AddNamespace($_.LocalName, $_.Value)
|
||||
}
|
||||
}
|
||||
# Getting version from XML, using XPath
|
||||
$ver = $xml.SelectSingleNode($xpath, $nsmgr).'#text'
|
||||
if (!$ver) {
|
||||
next "couldn't find '$xpath' in $url"
|
||||
next "couldn't find '$($xpath -replace 'ns:', '')' in $url"
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -311,7 +367,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) {
|
||||
@@ -337,7 +393,7 @@ while ($in_progress -gt 0) {
|
||||
Write-Host 'Forcing autoupdate!' -ForegroundColor DarkMagenta
|
||||
}
|
||||
try {
|
||||
Invoke-AutoUpdate $App $Dir $json $ver $matchesHashtable # 'autoupdate.ps1'
|
||||
Invoke-AutoUpdate $app $file $json $ver $matchesHashtable # 'autoupdate.ps1'
|
||||
} catch {
|
||||
if ($ThrowError) {
|
||||
throw $_
|
||||
|
||||
@@ -24,12 +24,12 @@ param(
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1"
|
||||
. "$PSScriptRoot\..\lib\description.ps1"
|
||||
|
||||
$Dir = Resolve-Path $Dir
|
||||
$Dir = Convert-Path $Dir
|
||||
$Queue = @()
|
||||
|
||||
Get-ChildItem $Dir "$App.json" | ForEach-Object {
|
||||
$manifest = parse_json "$Dir\$($_.Name)"
|
||||
$Queue += , @(($_.Name -replace '\.json$', ''), $manifest)
|
||||
Get-ChildItem $Dir -Filter "$App.json" -Recurse | ForEach-Object {
|
||||
$manifest = parse_json $_.FullName
|
||||
$Queue += , @($_.BaseName, $manifest)
|
||||
}
|
||||
|
||||
$Queue | ForEach-Object {
|
||||
|
||||
@@ -31,15 +31,14 @@ param(
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1"
|
||||
. "$PSScriptRoot\..\lib\json.ps1"
|
||||
|
||||
$Dir = Resolve-Path $Dir
|
||||
|
||||
Get-ChildItem $Dir "$App.json" | ForEach-Object {
|
||||
if ($PSVersionTable.PSVersion.Major -gt 5) { $_ = $_.Name } # Fix for pwsh
|
||||
$Dir = Convert-Path $Dir
|
||||
|
||||
Get-ChildItem $Dir -Filter "$App.json" -Recurse | ForEach-Object {
|
||||
$file = $_.FullName
|
||||
# beautify
|
||||
$json = parse_json "$Dir\$_" | ConvertToPrettyJson
|
||||
$json = parse_json $file | ConvertToPrettyJson
|
||||
|
||||
# convert to 4 spaces
|
||||
$json = $json -replace "`t", ' '
|
||||
[System.IO.File]::WriteAllLines("$Dir\$_", $json)
|
||||
[System.IO.File]::WriteAllLines($file, $json)
|
||||
}
|
||||
|
||||
@@ -1,78 +1,2 @@
|
||||
#Requires -Version 5
|
||||
|
||||
# remote install:
|
||||
# Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')
|
||||
$old_erroractionpreference = $erroractionpreference
|
||||
$erroractionpreference = 'stop' # quit if anything goes wrong
|
||||
|
||||
if (($PSVersionTable.PSVersion.Major) -lt 5) {
|
||||
Write-Output "PowerShell 5 or later is required to run Scoop."
|
||||
Write-Output "Upgrade PowerShell: https://docs.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell"
|
||||
break
|
||||
}
|
||||
|
||||
# show notification to change execution policy:
|
||||
$allowedExecutionPolicy = @('Unrestricted', 'RemoteSigned', 'ByPass')
|
||||
if ((Get-ExecutionPolicy).ToString() -notin $allowedExecutionPolicy) {
|
||||
Write-Output "PowerShell requires an execution policy in [$($allowedExecutionPolicy -join ", ")] to run Scoop."
|
||||
Write-Output "For example, to set the execution policy to 'RemoteSigned' please run :"
|
||||
Write-Output "'Set-ExecutionPolicy RemoteSigned -scope CurrentUser'"
|
||||
break
|
||||
}
|
||||
|
||||
if ([System.Enum]::GetNames([System.Net.SecurityProtocolType]) -notcontains 'Tls12') {
|
||||
Write-Output "Scoop requires at least .NET Framework 4.5"
|
||||
Write-Output "Please download and install it first:"
|
||||
Write-Output "https://www.microsoft.com/net/download"
|
||||
break
|
||||
}
|
||||
|
||||
# get core functions
|
||||
$core_url = 'https://raw.githubusercontent.com/ScoopInstaller/Scoop/master/lib/core.ps1'
|
||||
Write-Output 'Initializing...'
|
||||
Invoke-Expression (new-object net.webclient).downloadstring($core_url)
|
||||
|
||||
# prep
|
||||
if (Get-Command -Name 'scoop' -ErrorAction SilentlyContinue) {
|
||||
write-host "Scoop is already installed. Run 'scoop update' to get the latest version." -f red
|
||||
# don't abort if invoked with iex that would close the PS session
|
||||
if ($myinvocation.mycommand.commandtype -eq 'Script') { return } else { exit 1 }
|
||||
}
|
||||
$dir = ensure (versiondir 'scoop' 'current')
|
||||
|
||||
# download scoop zip
|
||||
$zipurl = 'https://github.com/ScoopInstaller/Scoop/archive/master.zip'
|
||||
$zipfile = "$dir\scoop.zip"
|
||||
Write-Output 'Downloading scoop...'
|
||||
dl $zipurl $zipfile
|
||||
|
||||
Write-Output 'Extracting...'
|
||||
Add-Type -Assembly "System.IO.Compression.FileSystem"
|
||||
[IO.Compression.ZipFile]::ExtractToDirectory($zipfile, "$dir\_tmp")
|
||||
Copy-Item "$dir\_tmp\*master\*" $dir -Recurse -Force
|
||||
Remove-Item "$dir\_tmp", $zipfile -Recurse -Force
|
||||
|
||||
Write-Output 'Creating shim...'
|
||||
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"
|
||||
Write-Output 'Downloading main bucket...'
|
||||
New-Item $dir -Type Directory -Force | Out-Null
|
||||
dl $zipurl $zipfile
|
||||
|
||||
Write-Output 'Extracting...'
|
||||
[IO.Compression.ZipFile]::ExtractToDirectory($zipfile, "$dir\_tmp")
|
||||
Copy-Item "$dir\_tmp\*-master\*" $dir -Recurse -Force
|
||||
Remove-Item "$dir\_tmp", $zipfile -Recurse -Force
|
||||
|
||||
ensure_robocopy_in_path
|
||||
|
||||
scoop config lastupdate ([System.DateTime]::Now.ToString('o'))
|
||||
success 'Scoop was installed successfully!'
|
||||
|
||||
Write-Output "Type 'scoop help' for instructions."
|
||||
|
||||
$erroractionpreference = $old_erroractionpreference # Reset $erroractionpreference to original value
|
||||
Invoke-RestMethod https://get.scoop.sh | Invoke-Expression
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ switch ($subCommand) {
|
||||
}
|
||||
}
|
||||
default {
|
||||
"scoop: '$subCommand' isn't a scoop command. See 'scoop help'."
|
||||
warn "scoop: '$subCommand' isn't a scoop command. See 'scoop help'."
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"extras": "https://github.com/ScoopInstaller/Extras",
|
||||
"versions": "https://github.com/ScoopInstaller/Versions",
|
||||
"nirsoft": "https://github.com/kodybrown/scoop-nirsoft",
|
||||
"sysinternals": "https://github.com/niheaven/scoop-sysinternals",
|
||||
"php": "https://github.com/ScoopInstaller/PHP",
|
||||
"nerd-fonts": "https://github.com/matthewjberger/scoop-nerd-fonts",
|
||||
"nonportable": "https://github.com/ScoopInstaller/Nonportable",
|
||||
|
||||
@@ -248,7 +248,7 @@ function get_hash_for_app([String] $app, $config, [String] $version, [String] $u
|
||||
'sourceforge' {
|
||||
# change the URL because downloads.sourceforge.net doesn't have checksums
|
||||
$hashfile_url = (strip_filename (strip_fragment "https://sourceforge.net/projects/$($matches['project'])/files/$($matches['file'])")).TrimEnd('/')
|
||||
$hash = find_hash_in_textfile $hashfile_url $substitutions '"$basename":.*?"sha1":\s"([a-fA-F0-9]{40})"'
|
||||
$hash = find_hash_in_textfile $hashfile_url $substitutions '"$basename":.*?"sha1":\s*"([a-fA-F0-9]{40})"'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,14 +267,14 @@ 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"
|
||||
return $null
|
||||
}
|
||||
$file = fullpath (cache_path $app $version $url)
|
||||
$hash = compute_hash $file 'sha256'
|
||||
$hash = (Get-FileHash -Path $file -Algorithm SHA256).Hash.ToLower()
|
||||
write-host -f DarkYellow 'Computed hash: ' -NoNewline
|
||||
write-host -f Green $hash
|
||||
return $hash
|
||||
@@ -449,7 +449,7 @@ function Invoke-AutoUpdate {
|
||||
# 'Set-Content -Encoding ASCII' don't works in PowerShell 5
|
||||
# Wait for 'UTF8NoBOM' Encoding in PowerShell 7
|
||||
# $Manifest | ConvertToPrettyJson | Set-Content -Path (Join-Path $Path "$AppName.json") -Encoding UTF8NoBOM
|
||||
[System.IO.File]::WriteAllLines((Join-Path $Path "$AppName.json"), (ConvertToPrettyJson $Manifest))
|
||||
[System.IO.File]::WriteAllLines($Path, (ConvertToPrettyJson $Manifest))
|
||||
# notes
|
||||
$note = "`nUpdating note:"
|
||||
if ($Manifest.autoupdate.note) {
|
||||
@@ -457,7 +457,7 @@ function Invoke-AutoUpdate {
|
||||
$hasNote = $true
|
||||
}
|
||||
if ($Manifest.autoupdate.architecture) {
|
||||
'64bit', '32bit' | ForEach-Object {
|
||||
'64bit', '32bit', 'arm64' | ForEach-Object {
|
||||
if ($Manifest.autoupdate.architecture.$_.note) {
|
||||
$note += "`n$_-arch: $($Manifest.autoupdate.architecture.$_.note)"
|
||||
$hasNote = $true
|
||||
|
||||
@@ -50,7 +50,7 @@ function known_buckets {
|
||||
}
|
||||
|
||||
function apps_in_bucket($dir) {
|
||||
return Get-ChildItem $dir | Where-Object { $_.Name.EndsWith('.json') } | ForEach-Object { $_.Name -replace '.json$', '' }
|
||||
return (Get-ChildItem $dir -Filter '*.json' -Recurse).BaseName
|
||||
}
|
||||
|
||||
function Get-LocalBucket {
|
||||
@@ -120,7 +120,7 @@ function add_bucket($name, $repo) {
|
||||
|
||||
$dir = Find-BucketDirectory $name -Root
|
||||
if (Test-Path $dir) {
|
||||
warn "The '$name' bucket already exists. Use 'scoop bucket rm $name' to remove it."
|
||||
warn "The '$name' bucket already exists. To add this bucket again, first remove it by running 'scoop bucket rm $name'."
|
||||
return 2
|
||||
}
|
||||
|
||||
|
||||
224
lib/core.ps1
224
lib/core.ps1
@@ -24,7 +24,7 @@ function Get-Encoding($wc) {
|
||||
}
|
||||
|
||||
function Get-UserAgent() {
|
||||
return "Scoop/1.0 (+http://scoop.sh/) PowerShell/$($PSVersionTable.PSVersion.Major).$($PSVersionTable.PSVersion.Minor) (Windows NT $([System.Environment]::OSVersion.Version.Major).$([System.Environment]::OSVersion.Version.Minor); $(if($env:PROCESSOR_ARCHITECTURE -eq 'AMD64'){'Win64; x64; '})$(if($env:PROCESSOR_ARCHITEW6432 -eq 'AMD64'){'WOW64; '})$PSEdition)"
|
||||
return "Scoop/1.0 (+http://scoop.sh/) PowerShell/$($PSVersionTable.PSVersion.Major).$($PSVersionTable.PSVersion.Minor) (Windows NT $([System.Environment]::OSVersion.Version.Major).$([System.Environment]::OSVersion.Version.Minor); $(if(${env:ProgramFiles(Arm)}){'ARM64; '}elseif($env:PROCESSOR_ARCHITECTURE -eq 'AMD64'){'Win64; x64; '})$(if($env:PROCESSOR_ARCHITEW6432 -in 'AMD64','ARM64'){'WOW64; '})$PSEdition)"
|
||||
}
|
||||
|
||||
function Show-DeprecatedWarning {
|
||||
@@ -59,6 +59,7 @@ function load_cfg($file) {
|
||||
}
|
||||
|
||||
function get_config($name, $default) {
|
||||
$name = $name.ToLowerInvariant()
|
||||
if($null -eq $scoopConfig.$name -and $null -ne $default) {
|
||||
return $default
|
||||
}
|
||||
@@ -72,6 +73,8 @@ function set_config {
|
||||
$value
|
||||
)
|
||||
|
||||
$name = $name.ToLowerInvariant()
|
||||
|
||||
if ($null -eq $scoopConfig -or $scoopConfig.Count -eq 0) {
|
||||
ensure (Split-Path -Path $configFile) | Out-Null
|
||||
$scoopConfig = New-Object -TypeName PSObject
|
||||
@@ -98,7 +101,7 @@ function set_config {
|
||||
|
||||
function setup_proxy() {
|
||||
# note: '@' and ':' in password must be escaped, e.g. 'p@ssword' -> p\@ssword'
|
||||
$proxy = get_config 'proxy'
|
||||
$proxy = get_config PROXY
|
||||
if(!$proxy) {
|
||||
return
|
||||
}
|
||||
@@ -126,7 +129,7 @@ function setup_proxy() {
|
||||
}
|
||||
|
||||
function git_cmd {
|
||||
$proxy = get_config 'proxy'
|
||||
$proxy = get_config PROXY
|
||||
$cmd = "git $($args | ForEach-Object { "$_ " })"
|
||||
if ($proxy -and $proxy -ne 'none') {
|
||||
$cmd = "SET HTTPS_PROXY=$proxy&&SET HTTP_PROXY=$proxy&&$cmd"
|
||||
@@ -153,7 +156,7 @@ function error($msg) { write-host "ERROR $msg" -f darkred }
|
||||
function warn($msg) { write-host "WARN $msg" -f darkyellow }
|
||||
function info($msg) { write-host "INFO $msg" -f darkgray }
|
||||
function debug($obj) {
|
||||
if((get_config 'debug' $false) -ine 'true' -and $env:SCOOP_DEBUG -ine 'true') {
|
||||
if ((get_config DEBUG $false) -ine 'true' -and $env:SCOOP_DEBUG -ine 'true') {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -210,7 +213,7 @@ function appdir($app, $global) { "$(appsdir $global)\$app" }
|
||||
function versiondir($app, $version, $global) { "$(appdir $app $global)\$version" }
|
||||
|
||||
function currentdir($app, $global) {
|
||||
if (get_config NO_JUNCTIONS) {
|
||||
if (get_config NO_JUNCTION) {
|
||||
$version = Select-CurrentVersion -App $app -Global:$global
|
||||
} else {
|
||||
$version = 'current'
|
||||
@@ -225,8 +228,8 @@ function cache_path($app, $version, $url) { "$cachedir\$app#$version#$($url -rep
|
||||
|
||||
# apps
|
||||
function sanitary_path($path) { return [regex]::replace($path, "[/\\?:*<>|]", "") }
|
||||
function installed($app, $global) {
|
||||
if (-not $PSBoundParameters.ContainsKey('global')) {
|
||||
function installed($app, [Nullable[bool]]$global) {
|
||||
if ($null -eq $global) {
|
||||
return (installed $app $false) -or (installed $app $true)
|
||||
}
|
||||
# Dependencies of the format "bucket/dependency" install in a directory of form
|
||||
@@ -246,7 +249,7 @@ function installed_apps($global) {
|
||||
function failed($app, $global) {
|
||||
$app = ($app -split '/|\\')[-1]
|
||||
$appPath = appdir $app $global
|
||||
$hasCurrent = (get_config NO_JUNCTIONS) -or (Test-Path "$appPath\current")
|
||||
$hasCurrent = (get_config NO_JUNCTION) -or (Test-Path "$appPath\current")
|
||||
return (Test-Path $appPath) -and !($hasCurrent -and (installed $app $global))
|
||||
}
|
||||
|
||||
@@ -394,7 +397,7 @@ function app_status($app, $global) {
|
||||
|
||||
$status.outdated = $false
|
||||
if ($status.version -and $status.latest_version) {
|
||||
if (get_config 'force_update' $false) {
|
||||
if (get_config FORCE_UPDATE $false) {
|
||||
$status.outdated = ((Compare-Version -ReferenceVersion $status.version -DifferenceVersion $status.latest_version) -ne 0)
|
||||
} else {
|
||||
$status.outdated = ((Compare-Version -ReferenceVersion $status.version -DifferenceVersion $status.latest_version) -gt 0)
|
||||
@@ -507,12 +510,12 @@ function Invoke-ExternalCommand {
|
||||
}
|
||||
$Process = New-Object System.Diagnostics.Process
|
||||
$Process.StartInfo.FileName = $FilePath
|
||||
$Process.StartInfo.Arguments = ($ArgumentList | Select-Object -Unique) -join ' '
|
||||
$Process.StartInfo.UseShellExecute = $false
|
||||
if ($LogPath) {
|
||||
if ($FilePath -match '(^|\W)msiexec($|\W)') {
|
||||
$Process.StartInfo.Arguments += " /lwe `"$LogPath`""
|
||||
if ($FilePath -match '^msiexec(.exe)?$') {
|
||||
$ArgumentList += "/lwe `"$LogPath`""
|
||||
} else {
|
||||
$redirectToLogFile = $true
|
||||
$Process.StartInfo.RedirectStandardOutput = $true
|
||||
$Process.StartInfo.RedirectStandardError = $true
|
||||
}
|
||||
@@ -520,9 +523,32 @@ function Invoke-ExternalCommand {
|
||||
if ($RunAs) {
|
||||
$Process.StartInfo.UseShellExecute = $true
|
||||
$Process.StartInfo.Verb = 'RunAs'
|
||||
} else {
|
||||
$Process.StartInfo.CreateNoWindow = $true
|
||||
}
|
||||
if ($FilePath -match '^((cmd|cscript|wscript|msiexec)(\.exe)?|.*\.(bat|cmd|js|vbs|wsf))$') {
|
||||
$Process.StartInfo.Arguments = $ArgumentList -join ' '
|
||||
} elseif ($Process.StartInfo.ArgumentList.Add) {
|
||||
# ArgumentList is supported in PowerShell 6.1 and later (built on .NET Core 2.1+)
|
||||
# ref-1: https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.processstartinfo.argumentlist?view=net-6.0
|
||||
# ref-2: https://docs.microsoft.com/en-us/powershell/scripting/whats-new/differences-from-windows-powershell?view=powershell-7.2#net-framework-vs-net-core
|
||||
$ArgumentList | ForEach-Object { $Process.StartInfo.ArgumentList.Add($_) }
|
||||
} else {
|
||||
# escape arguments manually in lower versions, refer to https://docs.microsoft.com/en-us/previous-versions/17w5ykft(v=vs.85)
|
||||
$escapedArgs = $ArgumentList | ForEach-Object {
|
||||
# escape N consecutive backslash(es), which are followed by a double quote, to 2N consecutive ones
|
||||
$s = $_ -replace '(\\+)"', '$1$1"'
|
||||
# escape N consecutive backslash(es), which are at the end of the string, to 2N consecutive ones
|
||||
$s = $s -replace '(\\+)$', '$1$1'
|
||||
# escape double quotes
|
||||
$s = $s -replace '"', '\"'
|
||||
# quote the argument
|
||||
"`"$s`""
|
||||
}
|
||||
$Process.StartInfo.Arguments = $escapedArgs -join ' '
|
||||
}
|
||||
try {
|
||||
$Process.Start() | Out-Null
|
||||
[void]$Process.Start()
|
||||
} catch {
|
||||
if ($Activity) {
|
||||
Write-Host "error." -ForegroundColor DarkRed
|
||||
@@ -530,11 +556,17 @@ function Invoke-ExternalCommand {
|
||||
error $_.Exception.Message
|
||||
return $false
|
||||
}
|
||||
if ($LogPath -and ($FilePath -notmatch '(^|\W)msiexec($|\W)')) {
|
||||
Out-UTF8File -FilePath $LogPath -Append -InputObject $Process.StandardOutput.ReadToEnd()
|
||||
Out-UTF8File -FilePath $LogPath -Append -InputObject $Process.StandardError.ReadToEnd()
|
||||
if ($redirectToLogFile) {
|
||||
# we do this to remove a deadlock potential
|
||||
# ref: https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.process.standardoutput?view=netframework-4.5#remarks
|
||||
$stdoutTask = $Process.StandardOutput.ReadToEndAsync()
|
||||
$stderrTask = $Process.StandardError.ReadToEndAsync()
|
||||
}
|
||||
$Process.WaitForExit()
|
||||
if ($redirectToLogFile) {
|
||||
Out-UTF8File -FilePath $LogPath -Append -InputObject $stdoutTask.Result
|
||||
Out-UTF8File -FilePath $LogPath -Append -InputObject $stderrTask.Result
|
||||
}
|
||||
if ($Process.ExitCode -ne 0) {
|
||||
if ($ContinueExitCodes -and ($ContinueExitCodes.ContainsKey($Process.ExitCode))) {
|
||||
if ($Activity) {
|
||||
@@ -556,13 +588,6 @@ function Invoke-ExternalCommand {
|
||||
return $true
|
||||
}
|
||||
|
||||
function dl($url,$to) {
|
||||
$wc = New-Object Net.Webclient
|
||||
$wc.headers.add('Referer', (strip_filename $url))
|
||||
$wc.Headers.Add('User-Agent', (Get-UserAgent))
|
||||
$wc.downloadFile($url,$to)
|
||||
}
|
||||
|
||||
function env($name,$global,$val='__get') {
|
||||
$target = 'User'; if($global) {$target = 'Machine'}
|
||||
if($val -eq '__get') { [environment]::getEnvironmentVariable($name,$target) }
|
||||
@@ -604,12 +629,12 @@ function movedir($from, $to) {
|
||||
$proc.StartInfo.RedirectStandardError = $true
|
||||
$proc.StartInfo.UseShellExecute = $false
|
||||
$proc.StartInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
|
||||
$proc.Start()
|
||||
$out = $proc.StandardOutput.ReadToEnd()
|
||||
[void]$proc.Start()
|
||||
$stdoutTask = $proc.StandardOutput.ReadToEndAsync()
|
||||
$proc.WaitForExit()
|
||||
|
||||
if($proc.ExitCode -ge 8) {
|
||||
debug $out
|
||||
debug $stdoutTask.Result
|
||||
throw "Could not find '$(fname $from)'! (error $($proc.ExitCode))"
|
||||
}
|
||||
|
||||
@@ -685,7 +710,7 @@ function shim($path, $global, $name, $arg) {
|
||||
Push-Location $abs_shimdir
|
||||
$relative_path = Resolve-Path -Relative $path
|
||||
Pop-Location
|
||||
$resolved_path = Resolve-Path $path
|
||||
$resolved_path = Convert-Path $path
|
||||
|
||||
if ($path -match '\.(exe|com)$') {
|
||||
# for programs with no awareness of any shell
|
||||
@@ -781,6 +806,11 @@ function shim($path, $global, $name, $arg) {
|
||||
} else {
|
||||
warn_on_overwrite "$shim.cmd" $path
|
||||
# find path to Git's bash so that batch scripts can run bash scripts
|
||||
if (!(Get-CommandPath git)) {
|
||||
error "Can't shim '$shim': 'git' is needed but not installed."
|
||||
error "Please install git ('scoop install git') and try again."
|
||||
exit 1
|
||||
}
|
||||
$gitdir = (Get-Item (Get-CommandPath git) -ErrorAction:Stop).Directory.Parent
|
||||
if ($gitdir.FullName -imatch 'mingw') {
|
||||
$gitdir = $gitdir.Parent
|
||||
@@ -801,7 +831,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 +862,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) {
|
||||
{ @('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'"}
|
||||
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' }
|
||||
{ @('arm64', 'arm', 'aarch64') -contains $_ } { return 'arm64' }
|
||||
default { throw [System.ArgumentException] "Invalid architecture: '$Architecture'" }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -967,29 +1020,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 +1120,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 +1220,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), "$([System.Environment]::GetFolderPath('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), "$([System.Environment]::GetFolderPath('CommonApplicationData'))\scoop" | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -First 1
|
||||
|
||||
# Scoop cache directory
|
||||
# Note: Setting the SCOOP_CACHE environment variable to use a shared directory
|
||||
# is experimental and untested. There may be concurrency issues when
|
||||
# multiple users write and access cached files at the same time.
|
||||
# Use at your own risk.
|
||||
$cachedir = $env:SCOOP_CACHE, (get_config 'cachePath'), "$scoopdir\cache" | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -first 1
|
||||
$cachedir = $env:SCOOP_CACHE, (get_config CACHE_PATH), "$scoopdir\cache" | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -First 1
|
||||
|
||||
# OS information
|
||||
$WindowsBuild = [System.Environment]::OSVersion.Version.Build
|
||||
|
||||
# Setup proxy globally
|
||||
setup_proxy
|
||||
|
||||
@@ -18,20 +18,21 @@ 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')
|
||||
$DestinationPath = $DestinationPath.TrimEnd('\')
|
||||
$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 +54,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
|
||||
@@ -67,6 +68,9 @@ function Expand-7zipArchive {
|
||||
if (($Path -replace '.*\.([^\.]*)$', '$1') -eq '001') {
|
||||
# Remove splited 7-zip archive parts
|
||||
Get-ChildItem "$($Path -replace '\.[^\.]*$', '').???" | Remove-Item -Force
|
||||
} elseif (($Path -replace '.*\.part(\d+)\.rar$', '$1')[-1] -eq '1') {
|
||||
# Remove splitted RAR archive parts
|
||||
Get-ChildItem "$($Path -replace '\.part(\d+)\.rar$', '').part*.rar" | Remove-Item -Force
|
||||
} else {
|
||||
Remove-Item $Path -Force
|
||||
}
|
||||
@@ -94,7 +98,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)
|
||||
@@ -143,12 +147,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) {
|
||||
@@ -197,7 +201,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" }
|
||||
@@ -237,7 +241,8 @@ function Expand-ZipArchive {
|
||||
$OriDestinationPath = $DestinationPath
|
||||
$DestinationPath = "$DestinationPath\_tmp"
|
||||
}
|
||||
Expand-Archive -Path $Path -DestinationPath $DestinationPath -Force
|
||||
# Compatible with Pscx v3 (https://github.com/Pscx/Pscx) ('Microsoft.PowerShell.Archive' is not needed for Pscx v4)
|
||||
Microsoft.PowerShell.Archive\Expand-Archive -Path $Path -DestinationPath $DestinationPath -Force
|
||||
if ($ExtractDir) {
|
||||
movedir "$DestinationPath\$ExtractDir" $OriDestinationPath | Out-Null
|
||||
Remove-Item $DestinationPath -Recurse -Force
|
||||
@@ -264,7 +269,7 @@ function Expand-DarkArchive {
|
||||
$Removal
|
||||
)
|
||||
$LogPath = "$(Split-Path $Path)\dark.log"
|
||||
$ArgList = @('-nologo', "-x `"$DestinationPath`"", "`"$Path`"")
|
||||
$ArgList = @('-nologo', '-x', $DestinationPath, $Path)
|
||||
if ($Switches) {
|
||||
$ArgList += (-split $Switches)
|
||||
}
|
||||
|
||||
@@ -106,10 +106,10 @@ function Get-InstallationHelper {
|
||||
$installer = arch_specific 'installer' $Manifest $Architecture
|
||||
$post_install = arch_specific 'post_install' $Manifest $Architecture
|
||||
$script = $pre_install + $installer.script + $post_install
|
||||
if (((Test-7zipRequirement -Uri $url) -or ($script -like '*Expand-7zipArchive *')) -and !(get_config 7ZIPEXTRACT_USE_EXTERNAL)) {
|
||||
if (((Test-7zipRequirement -Uri $url) -or ($script -like '*Expand-7zipArchive *')) -and !(get_config USE_EXTERNAL_7ZIP)) {
|
||||
$helper += '7zip'
|
||||
}
|
||||
if (((Test-LessmsiRequirement -Uri $url) -or ($script -like '*Expand-MsiArchive *')) -and (get_config MSIEXTRACT_USE_LESSMSI)) {
|
||||
if (((Test-LessmsiRequirement -Uri $url) -or ($script -like '*Expand-MsiArchive *')) -and (get_config USE_LESSMSI)) {
|
||||
$helper += 'lessmsi'
|
||||
}
|
||||
if ($Manifest.innosetup -or ($script -like '*Expand-InnoArchive *')) {
|
||||
|
||||
@@ -53,3 +53,17 @@ function check_long_paths {
|
||||
|
||||
return $true
|
||||
}
|
||||
|
||||
function Get-WindowsDeveloperModeStatus {
|
||||
$DevModRegistryPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock"
|
||||
if (!(Test-Path -Path $DevModRegistryPath) -or (Get-ItemProperty -Path `
|
||||
$DevModRegistryPath -Name AllowDevelopmentWithoutDevLicense -ErrorAction `
|
||||
SilentlyContinue).AllowDevelopmentWithoutDevLicense -ne 1) {
|
||||
warn "Windows Developer Mode is not enabled. Operations relevant to symlinks may fail without proper rights."
|
||||
Write-Host " You may read more about the symlinks support here:"
|
||||
Write-Host " https://blogs.windows.com/windowsdeveloper/2016/12/02/symlinks-windows-10/"
|
||||
return $false
|
||||
}
|
||||
|
||||
return $true
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
$argv = @($argv -split ' ')
|
||||
$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 }
|
||||
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) {
|
||||
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]
|
||||
if($shortopt[1] -eq ':') {
|
||||
if($j -ne $arg.length -1 -or $i -eq $argv.length - 1) {
|
||||
if ($shortopts -match "$(regex_escape $letter)`:?") {
|
||||
$shortopt = $Matches[0]
|
||||
if ($shortopt[1] -eq ':') {
|
||||
if ($j -ne $arg.Length - 1 -or $i -eq $argv.Length - 1) {
|
||||
return err "Option -$letter requires an argument."
|
||||
}
|
||||
$opts.$letter = $argv[++$i]
|
||||
|
||||
111
lib/install.ps1
111
lib/install.ps1
@@ -1,9 +1,8 @@
|
||||
function nightly_version($date, $quiet = $false) {
|
||||
$date_str = $date.tostring("yyyyMMdd")
|
||||
function nightly_version($quiet = $false) {
|
||||
if (!$quiet) {
|
||||
warn "This is a nightly version. Downloaded files won't be verified."
|
||||
}
|
||||
"nightly-$date_str"
|
||||
return "nightly-$(Get-Date -Format 'yyyyMMdd')"
|
||||
}
|
||||
|
||||
function install_app($app, $architecture, $global, $suggested, $use_cache = $true, $check_hash = $true) {
|
||||
@@ -21,18 +20,19 @@ function install_app($app, $architecture, $global, $suggested, $use_cache = $tru
|
||||
|
||||
$is_nightly = $version -eq 'nightly'
|
||||
if ($is_nightly) {
|
||||
$version = nightly_version $(get-date)
|
||||
$version = nightly_version
|
||||
$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 +43,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 +80,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)) {
|
||||
Copy-Item $cached $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 +179,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 +214,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 +355,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 +371,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 +409,7 @@ function dl($url, $to, $cookies, $progress) {
|
||||
$newUrl = "$newUrl#/$postfix"
|
||||
}
|
||||
|
||||
dl $newUrl $to $cookies $progress
|
||||
Invoke-Download $newUrl $to $cookies $progress
|
||||
return
|
||||
}
|
||||
|
||||
@@ -416,12 +420,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 +437,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 +463,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 +502,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 +520,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 +545,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 +588,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'
|
||||
@@ -655,7 +659,7 @@ function hash_for_url($manifest, $url, $arch) {
|
||||
function check_hash($file, $hash, $app_name) {
|
||||
$file = fullpath $file
|
||||
if(!$hash) {
|
||||
warn "Warning: No hash in manifest. SHA256 for '$(fname $file)' is:`n $(compute_hash $file 'sha256')"
|
||||
warn "Warning: No hash in manifest. SHA256 for '$(fname $file)' is:`n $((Get-FileHash -Path $file -Algorithm SHA256).Hash.ToLower())"
|
||||
return $true, $null
|
||||
}
|
||||
|
||||
@@ -667,7 +671,7 @@ function check_hash($file, $hash, $app_name) {
|
||||
return $false, "Hash type '$algorithm' isn't supported."
|
||||
}
|
||||
|
||||
$actual = compute_hash $file $algorithm
|
||||
$actual = (Get-FileHash -Path $file -Algorithm $algorithm).Hash.ToLower()
|
||||
$expected = $expected.ToLower()
|
||||
|
||||
if($actual -ne $expected) {
|
||||
@@ -687,25 +691,6 @@ function check_hash($file, $hash, $app_name) {
|
||||
return $true, $null
|
||||
}
|
||||
|
||||
function compute_hash($file, $algname) {
|
||||
try {
|
||||
if(Test-CommandAvailable Get-FileHash) {
|
||||
return (Get-FileHash -Path $file -Algorithm $algname).Hash.ToLower()
|
||||
} else {
|
||||
$fs = [system.io.file]::openread($file)
|
||||
$alg = [system.security.cryptography.hashalgorithm]::create($algname)
|
||||
$hexbytes = $alg.computehash($fs) | ForEach-Object { $_.tostring('x2') }
|
||||
return [string]::join('', $hexbytes)
|
||||
}
|
||||
} catch {
|
||||
error $_.exception.message
|
||||
} finally {
|
||||
if($fs) { $fs.dispose() }
|
||||
if($alg) { $alg.dispose() }
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
# for dealing with installers
|
||||
function args($config, $dir, $global) {
|
||||
if($config) { return $config | ForEach-Object { (format $_ @{'dir'=$dir;'global'=$global}) } }
|
||||
@@ -905,7 +890,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 +917,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 +1027,7 @@ function Invoke-HookScript {
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[PSCustomObject] $Manifest,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateSet('32bit', '64bit')]
|
||||
[ValidateSet('32bit', '64bit', 'arm64')]
|
||||
[String] $Arch
|
||||
)
|
||||
|
||||
@@ -1227,14 +1212,16 @@ function persist_permission($manifest, $global) {
|
||||
# test if there are running processes
|
||||
function test_running_process($app, $global) {
|
||||
$processdir = appdir $app $global | Convert-Path
|
||||
$running_processes = Get-Process | Where-Object { $_.Path -like "$processdir\*" }
|
||||
$running_processes = Get-Process | Where-Object { $_.Path -like "$processdir\*" } | Out-String
|
||||
|
||||
if ($running_processes) {
|
||||
if (get_config 'ignore_running_processes') {
|
||||
warn "Application `"$app`" is still running. Scoop is configured to ignore this condition."
|
||||
if (get_config IGNORE_RUNNING_PROCESSES) {
|
||||
warn "The following instances of `"$app`" are still running. Scoop is configured to ignore this condition."
|
||||
Write-Host $running_processes
|
||||
return $false
|
||||
} else {
|
||||
error "Application `"$app`" is still running. Close all instances and try again."
|
||||
error "The following instances of `"$app`" are still running. Close them and try again."
|
||||
Write-Host $running_processes
|
||||
return $true
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -98,7 +98,9 @@ function json_path([String] $json, [String] $jsonpath, [Hashtable] $substitution
|
||||
$jsonpath = substitute $jsonpath $substitutions ($jsonpath -like "*=~*")
|
||||
}
|
||||
try {
|
||||
$obj = [Newtonsoft.Json.Linq.JValue]::Parse($json)
|
||||
$settings = New-Object -Type Newtonsoft.Json.JsonSerializerSettings
|
||||
$settings.DateParseHandling = [Newtonsoft.Json.DateParseHandling]::None
|
||||
$obj = [Newtonsoft.Json.JsonConvert]::DeserializeObject($json, $settings)
|
||||
} catch [Newtonsoft.Json.JsonReaderException] {
|
||||
return $null
|
||||
}
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
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 }
|
||||
Get-Content $path -raw -Encoding UTF8 | convertfrom-json -ea stop
|
||||
if ($null -eq $path -or !(Test-Path $path)) { return $null }
|
||||
try {
|
||||
Get-Content $path -Raw -Encoding UTF8 | ConvertFrom-Json -ErrorAction Stop
|
||||
} catch {
|
||||
warn "Error parsing JSON at $path."
|
||||
}
|
||||
}
|
||||
|
||||
function url_manifest($url) {
|
||||
@@ -20,7 +24,11 @@ function url_manifest($url) {
|
||||
throw
|
||||
}
|
||||
if(!$str) { return $null }
|
||||
$str | convertfrom-json
|
||||
try {
|
||||
$str | ConvertFrom-Json -ErrorAction Stop
|
||||
} catch {
|
||||
warn "Error parsing JSON at $url."
|
||||
}
|
||||
}
|
||||
|
||||
function Get-Manifest($app) {
|
||||
@@ -94,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
|
||||
@@ -120,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) {
|
||||
@@ -137,10 +142,10 @@ function generate_user_manifest($app, $bucket, $version) {
|
||||
abort "'$app' does not have autoupdate capability`r`ncouldn't find manifest for '$app@$version'"
|
||||
}
|
||||
|
||||
ensure $(usermanifestsdir) | out-null
|
||||
ensure (usermanifestsdir) | out-null
|
||||
try {
|
||||
Invoke-AutoUpdate $app "$(resolve-path $(usermanifestsdir))" $manifest $version $(@{ })
|
||||
return "$(resolve-path $(usermanifest $app))"
|
||||
Invoke-AutoUpdate $app "$(Convert-Path (usermanifestsdir))\$app.json" $manifest $version $(@{ })
|
||||
return Convert-Path (usermanifest $app)
|
||||
} catch {
|
||||
write-host -f darkred "Could not install $app@$version"
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ function install_psmodule($manifest, $dir, $global) {
|
||||
|
||||
if (Test-Path $linkfrom) {
|
||||
warn "$(friendly_path $linkfrom) already exists. It will be replaced."
|
||||
Remove-Item -Path $linkfrom -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item -Path $linkfrom -Force -Recurse -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
New-DirectoryJunction $linkfrom $dir | Out-Null
|
||||
@@ -39,8 +39,8 @@ function uninstall_psmodule($manifest, $dir, $global) {
|
||||
$linkfrom = "$modulesdir\$module_name"
|
||||
if (Test-Path $linkfrom) {
|
||||
Write-Host "Removing $(friendly_path $linkfrom)"
|
||||
$linkfrom = Resolve-Path $linkfrom
|
||||
Remove-Item -Path $linkfrom -Force -ErrorAction SilentlyContinue
|
||||
$linkfrom = Convert-Path $linkfrom
|
||||
Remove-Item -Path $linkfrom -Force -Recurse -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,11 +20,12 @@ function create_startmenu_shortcuts($manifest, $dir, $global, $arch) {
|
||||
}
|
||||
|
||||
function shortcut_folder($global) {
|
||||
$directory = [System.IO.Path]::Combine([Environment]::GetFolderPath('startmenu'), 'Programs', 'Scoop Apps')
|
||||
if($global) {
|
||||
$directory = [System.IO.Path]::Combine([Environment]::GetFolderPath('commonstartmenu'), 'Programs', 'Scoop Apps')
|
||||
if ($global) {
|
||||
$startmenu = 'CommonStartMenu'
|
||||
} else {
|
||||
$startmenu = 'StartMenu'
|
||||
}
|
||||
return $(ensure $directory)
|
||||
return Convert-Path (ensure ([System.IO.Path]::Combine([Environment]::GetFolderPath($startmenu), 'Programs', 'Scoop Apps')))
|
||||
}
|
||||
|
||||
function startmenu_shortcut([System.IO.FileInfo] $target, $shortcutName, $arguments, [System.IO.FileInfo]$icon, $global) {
|
||||
@@ -67,18 +68,5 @@ function rm_startmenu_shortcuts($manifest, $global, $arch) {
|
||||
if(Test-Path -Path $shortcut) {
|
||||
Remove-Item $shortcut
|
||||
}
|
||||
# Before issue 1514 Startmenu shortcut removal
|
||||
#
|
||||
# Shortcuts that should have been installed globally would
|
||||
# have been installed locally up until 27 June 2017.
|
||||
#
|
||||
# TODO: Remove this 'if' block and comment after
|
||||
# 27 June 2018.
|
||||
if($global) {
|
||||
$shortcut = "$(shortcut_folder $false)\$name.lnk"
|
||||
if(Test-Path -Path $shortcut) {
|
||||
Remove-Item $shortcut
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
45
lib/unix.ps1
45
lib/unix.ps1
@@ -1,45 +0,0 @@
|
||||
# Note: This file is for overwriting global variables and functions to make
|
||||
# them unix compatible. It has to be imported after everything else!
|
||||
|
||||
function is_unix() { $PSVersionTable.Platform -eq 'Unix' }
|
||||
function is_mac() { $PSVersionTable.OS.ToLower().StartsWith('darwin') }
|
||||
function is_linux() { $PSVersionTable.OS.ToLower().StartsWith('linux') }
|
||||
|
||||
if(!(is_unix)) {
|
||||
return # get the hell outta here
|
||||
}
|
||||
|
||||
# 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
|
||||
|
||||
# core.ps1
|
||||
function ensure($dir) {
|
||||
mkdir -p $dir > $null
|
||||
return resolve-path $dir
|
||||
}
|
||||
|
||||
# install.ps1
|
||||
function compute_hash($file, $algname) {
|
||||
if(is_mac) {
|
||||
switch ($algname)
|
||||
{
|
||||
"md5" { $result = (md5 -q $file) }
|
||||
"sha1" { $result = (shasum -ba 1 $file) }
|
||||
"sha256" { $result = (shasum -ba 256 $file) }
|
||||
"sha512" { $result = (shasum -ba 512 $file) }
|
||||
default { $result = (shasum -ba 256 $file) }
|
||||
}
|
||||
} else {
|
||||
switch ($algname)
|
||||
{
|
||||
"md5" { $result = (md5sum -b $file) }
|
||||
"sha1" { $result = (sha1sum -b $file) }
|
||||
"sha256" { $result = (sha256sum -b $file) }
|
||||
"sha512" { $result = (sha512sum -b $file) }
|
||||
default { $result = (sha256sum -b $file) }
|
||||
}
|
||||
}
|
||||
return $result.split(' ') | Select-Object -first 1
|
||||
}
|
||||
@@ -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
|
||||
@@ -147,9 +147,20 @@ function Compare-Version {
|
||||
$splitReferenceVersion = @(SplitVersion -Version $ReferenceVersion -Delimiter $Delimiter)
|
||||
$splitDifferenceVersion = @(SplitVersion -Version $DifferenceVersion -Delimiter $Delimiter)
|
||||
|
||||
# Nightly versions are always equal
|
||||
# Nightly versions are always equal unless UPDATE_NIGHTLY is $true
|
||||
if ($splitReferenceVersion[0] -eq 'nightly' -and $splitDifferenceVersion[0] -eq 'nightly') {
|
||||
return 0
|
||||
if (get_config UPDATE_NIGHTLY) {
|
||||
# nightly versions will be compared by date if UPDATE_NIGHTLY is $true
|
||||
if ($null -eq $splitReferenceVersion[1]) {
|
||||
$splitReferenceVersion += Get-Date -Format 'yyyyMMdd'
|
||||
}
|
||||
if ($null -eq $splitDifferenceVersion[1]) {
|
||||
$splitDifferenceVersion += Get-Date -Format 'yyyyMMdd'
|
||||
}
|
||||
return [Math]::Sign($splitDifferenceVersion[1] - $splitReferenceVersion[1])
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
for ($i = 0; $i -lt [Math]::Max($splitReferenceVersion.Length, $splitDifferenceVersion.Length); $i++) {
|
||||
|
||||
@@ -52,10 +52,10 @@ function add_alias($name, $command) {
|
||||
# generate script
|
||||
$shimdir = shimdir $false
|
||||
$script =
|
||||
@"
|
||||
# Summary: $description
|
||||
$command
|
||||
"@
|
||||
@(
|
||||
"# Summary: $description",
|
||||
"$command"
|
||||
) -join "`r`n"
|
||||
$script | Out-UTF8File "$shimdir\$alias_file.ps1"
|
||||
|
||||
# add alias to config
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#
|
||||
# To clear everything in your cache, use:
|
||||
# scoop cache rm *
|
||||
# You can also use the `-a/--all` switch in place of `*` here
|
||||
|
||||
param($cmd)
|
||||
|
||||
function cacheinfo($file) {
|
||||
@@ -36,7 +38,7 @@ function cacheremove($app) {
|
||||
'ERROR: <app(s)> missing'
|
||||
my_usage
|
||||
exit 1
|
||||
} elseif ($app -eq '*') {
|
||||
} elseif ($app -eq '*' -or $app -eq '-a' -or $app -eq '--all') {
|
||||
$files = @(Get-ChildItem $cachedir)
|
||||
} else {
|
||||
$app = '(' + ($app -join '|') + ')'
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
# Usage: scoop cat <app>
|
||||
# Summary: Show content of specified manifest. If available, `bat` will be used to pretty-print the JSON.
|
||||
# Summary: Show content of specified manifest.
|
||||
# Help: Show content of specified manifest.
|
||||
# If configured, `bat` will be used to pretty-print the JSON.
|
||||
# See `cat_style` in `scoop help config` for further information.
|
||||
|
||||
param($app)
|
||||
|
||||
@@ -11,7 +14,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 {
|
||||
|
||||
@@ -17,6 +17,7 @@ if ($adminPrivileges) {
|
||||
|
||||
$issues += !(check_main_bucket)
|
||||
$issues += !(check_long_paths)
|
||||
$issues += !(Get-WindowsDeveloperModeStatus)
|
||||
|
||||
if (!(Test-HelperInstalled -Helper 7zip)) {
|
||||
error "'7-Zip' is not installed! It's required for unpacking most programs. Please Run 'scoop install 7zip' or 'scoop install 7zip-zstd'."
|
||||
@@ -35,13 +36,13 @@ if (!(Test-HelperInstalled -Helper Dark)) {
|
||||
|
||||
$globaldir = New-Object System.IO.DriveInfo($globaldir)
|
||||
if ($globaldir.DriveFormat -ne 'NTFS') {
|
||||
error "Scoop requires an NTFS volume to work! Please point `$env:SCOOP_GLOBAL or 'globalPath' variable in '~/.config/scoop/config.json' to another Drive."
|
||||
error "Scoop requires an NTFS volume to work! Please point `$env:SCOOP_GLOBAL or 'global_path' variable in '~/.config/scoop/config.json' to another Drive."
|
||||
$issues++
|
||||
}
|
||||
|
||||
$scoopdir = New-Object System.IO.DriveInfo($scoopdir)
|
||||
if ($scoopdir.DriveFormat -ne 'NTFS') {
|
||||
error "Scoop requires an NTFS volume to work! Please point `$env:SCOOP or 'rootPath' variable in '~/.config/scoop/config.json' to another Drive."
|
||||
error "Scoop requires an NTFS volume to work! Please point `$env:SCOOP or 'root_path' variable in '~/.config/scoop/config.json' to another Drive."
|
||||
$issues++
|
||||
}
|
||||
|
||||
|
||||
@@ -21,20 +21,20 @@
|
||||
# Settings
|
||||
# --------
|
||||
#
|
||||
# 7ZIPEXTRACT_USE_EXTERNAL: $true|$false
|
||||
# use_external_7zip: $true|$false
|
||||
# External 7zip (from path) will be used for archives extraction.
|
||||
#
|
||||
# MSIEXTRACT_USE_LESSMSI: $true|$false
|
||||
# use_lessmsi: $true|$false
|
||||
# Prefer lessmsi utility over native msiexec.
|
||||
#
|
||||
# NO_JUNCTIONS: $true|$false
|
||||
# no_junction: $true|$false
|
||||
# The 'current' version alias will not be used. Shims and shortcuts will point to specific version instead.
|
||||
#
|
||||
# SCOOP_REPO: http://github.com/ScoopInstaller/Scoop
|
||||
# scoop_repo: http://github.com/ScoopInstaller/Scoop
|
||||
# Git repository containining scoop source code.
|
||||
# This configuration is useful for custom forks.
|
||||
#
|
||||
# SCOOP_BRANCH: master|develop
|
||||
# scoop_branch: master|develop
|
||||
# Allow to use different branch than master.
|
||||
# Could be used for testing specific functionalities before released into all users.
|
||||
# If you want to receive updates earlier to test new functionalities use develop (see: 'https://github.com/ScoopInstaller/Scoop/issues/2939')
|
||||
@@ -47,9 +47,13 @@
|
||||
# * 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.
|
||||
# If not specified, architecture is determined by system.
|
||||
#
|
||||
# debug: $true|$false
|
||||
# Additional and detailed output will be shown.
|
||||
@@ -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,16 @@
|
||||
# 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
|
||||
#
|
||||
# update_nightly: $true|$false
|
||||
# Nightly version is formatted as 'nightly-yyyyMMdd' and will be updated after one day if this is set to $true.
|
||||
# Otherwise, nightly version will not be updated unless `--force` is used.
|
||||
#
|
||||
# ARIA2 configuration
|
||||
# -------------------
|
||||
#
|
||||
@@ -137,17 +151,39 @@ 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"
|
||||
} else {
|
||||
$value
|
||||
if ($value -is [System.DateTime]) {
|
||||
$value.ToString('o')
|
||||
} else {
|
||||
$value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +1,28 @@
|
||||
# Usage: scoop depends <app>
|
||||
# Summary: List dependencies for an app
|
||||
# Summary: List dependencies for an app, in the order they'll be installed
|
||||
|
||||
. "$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: $_"
|
||||
}
|
||||
|
||||
$deps = @(Get-Dependency $app $architecture) -ne $app
|
||||
if($deps) {
|
||||
$deps[($deps.length - 1)..0]
|
||||
$deps = @()
|
||||
Get-Dependency $app $architecture | ForEach-Object {
|
||||
$dep = [ordered]@{}
|
||||
$dep.Source, $dep.Name = $_ -split '/'
|
||||
$deps += [PSCustomObject]$dep
|
||||
}
|
||||
$deps
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
# Help: e.g. The usual way to download an app, without installing it (uses your local 'buckets'):
|
||||
# scoop download git
|
||||
#
|
||||
# To download a different version of the app
|
||||
# (note that this will auto-generate the manifest using current version):
|
||||
# scoop download gh@2.7.0
|
||||
#
|
||||
# To download an app from a manifest at a URL:
|
||||
# scoop download https://raw.githubusercontent.com/ScoopInstaller/Main/master/bucket/runat.json
|
||||
#
|
||||
@@ -10,15 +14,15 @@
|
||||
# scoop download path\to\app.json
|
||||
#
|
||||
# Options:
|
||||
# -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
|
||||
# -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|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='
|
||||
@@ -26,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: $_"
|
||||
}
|
||||
@@ -81,21 +85,22 @@ foreach ($curr_app in $apps) {
|
||||
|
||||
$curr_check_hash = $check_hash
|
||||
if ($version -eq 'nightly') {
|
||||
$version = nightly_version $(get-date)
|
||||
$version = nightly_version
|
||||
$curr_check_hash = $false
|
||||
}
|
||||
|
||||
if(!(supports_architecture $manifest $architecture)) {
|
||||
error "'$app' doesn't support $architecture architecture!"
|
||||
$architecture = Get-SupportedArchitecture $manifest $architecture
|
||||
if ($null -eq $architecture) {
|
||||
error "'$app' doesn't support current architecture!"
|
||||
continue
|
||||
}
|
||||
|
||||
if(Test-Aria2Enabled) {
|
||||
dl_with_cache_aria2 $app $version $manifest $architecture $cachedir $manifest.cookie $use_cache $curr_check_hash
|
||||
Invoke-CachedAria2Download $app $version $manifest $architecture $cachedir $manifest.cookie $use_cache $curr_check_hash
|
||||
} else {
|
||||
foreach($url in script:url $manifest $architecture) {
|
||||
try {
|
||||
dl_with_cache $app $version $url $null $manifest.cookie $use_cache
|
||||
Invoke-CachedDownload $app $version $url $null $manifest.cookie $use_cache
|
||||
} catch {
|
||||
write-host -f darkred $_
|
||||
error "URL $url is not valid"
|
||||
|
||||
@@ -1,57 +1,23 @@
|
||||
# Usage: scoop export > filename
|
||||
# Summary: Exports (an importable) list of installed apps
|
||||
# Help: Lists all installed apps.
|
||||
# Usage: scoop export > scoopfile.json
|
||||
# Summary: Exports installed apps, buckets (and optionally configs) in JSON format
|
||||
# Help: Options:
|
||||
# -c, --config Export the Scoop configuration file too
|
||||
|
||||
. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1" # 'default_architecture' 'Select-CurrentVersion' (indirectly)
|
||||
. "$PSScriptRoot\..\lib\json.ps1" # 'ConvertToPrettyJson'
|
||||
|
||||
$def_arch = default_architecture
|
||||
$export = @{}
|
||||
|
||||
$local = installed_apps $false | ForEach-Object { @{ name = $_; global = $false } }
|
||||
$global = installed_apps $true | ForEach-Object { @{ name = $_; global = $true } }
|
||||
|
||||
$apps = @($local) + @($global)
|
||||
$count = 0
|
||||
|
||||
# json
|
||||
# echo "{["
|
||||
|
||||
if($apps) {
|
||||
$apps | Sort-Object { $_.name } | Where-Object { !$query -or ($_.name -match $query) } | ForEach-Object {
|
||||
$app = $_.name
|
||||
$global = $_.global
|
||||
$ver = Select-CurrentVersion -AppName $app -Global:$global
|
||||
$global_display = $null; if($global) { $global_display = ' *global*'}
|
||||
|
||||
$install_info = install_info $app $ver $global
|
||||
$bucket = ''
|
||||
if ($install_info.bucket) {
|
||||
$bucket = ' [' + $install_info.bucket + ']'
|
||||
} elseif ($install_info.url) {
|
||||
$bucket = ' [' + $install_info.url + ']'
|
||||
}
|
||||
if ($install_info.architecture -and $def_arch -ne $install_info.architecture) {
|
||||
$arch = ' {' + $install_info.architecture + '}'
|
||||
} else {
|
||||
$arch = ''
|
||||
}
|
||||
|
||||
# json
|
||||
# $val = "{ 'name': '$app', 'version': '$ver', 'global': $($global.toString().tolower()) }"
|
||||
# if($count -gt 0) {
|
||||
# " ," + $val
|
||||
# } else {
|
||||
# " " + $val
|
||||
# }
|
||||
|
||||
# "$app (v:$ver) global:$($global.toString().tolower())"
|
||||
"$app (v:$ver)$global_display$bucket$arch"
|
||||
|
||||
$count++
|
||||
if ($args[0] -eq '-c' -or $args[0] -eq '--config') {
|
||||
$export.config = $scoopConfig
|
||||
# Remove machine-specific properties
|
||||
foreach ($prop in 'last_update', 'root_path', 'global_path', 'cache_path', 'alias') {
|
||||
$export.config.PSObject.Properties.Remove($prop)
|
||||
}
|
||||
}
|
||||
|
||||
# json
|
||||
# echo "]}"
|
||||
$export.buckets = list_buckets
|
||||
$export.apps = @(& "$PSScriptRoot\scoop-list.ps1" 6>$null)
|
||||
|
||||
$export | ConvertToPrettyJSON
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -3,41 +3,42 @@
|
||||
param($cmd)
|
||||
|
||||
function print_help($cmd) {
|
||||
$file = Get-Content (command_path $cmd) -raw
|
||||
$file = Get-Content (command_path $cmd) -Raw
|
||||
|
||||
$usage = usage $file
|
||||
$summary = summary $file
|
||||
$help = scoop_help $file
|
||||
|
||||
if($usage) { "$usage`n" }
|
||||
if($help) { $help }
|
||||
if ($usage) { "$usage`n" }
|
||||
if ($help) { $help }
|
||||
}
|
||||
|
||||
function print_summaries {
|
||||
$commands = @{}
|
||||
$commands = @()
|
||||
|
||||
command_files | ForEach-Object {
|
||||
$command = command_name $_
|
||||
$summary = summary (Get-Content (command_path $command) -raw)
|
||||
if(!($summary)) { $summary = '' }
|
||||
$commands.add("$command ", $summary) # add padding
|
||||
$command = [ordered]@{}
|
||||
$command.Command = command_name $_
|
||||
$command.Summary = summary (Get-Content (command_path $command.Command))
|
||||
$commands += [PSCustomObject]$command
|
||||
}
|
||||
|
||||
$commands.getenumerator() | Sort-Object name | Format-Table -hidetablehead -autosize -wrap
|
||||
$commands
|
||||
}
|
||||
|
||||
$commands = commands
|
||||
|
||||
if(!($cmd)) {
|
||||
"Usage: scoop <command> [<args>]
|
||||
Write-Host "Usage: scoop <command> [<args>]
|
||||
|
||||
Some useful commands are:"
|
||||
Available commands are listed below.
|
||||
|
||||
Type 'scoop help <command>' to get more help for a specific command."
|
||||
print_summaries
|
||||
"Type 'scoop help <command>' to get help for a specific command."
|
||||
} elseif($commands -contains $cmd) {
|
||||
print_help $cmd
|
||||
} else {
|
||||
"scoop help: no such command '$cmd'"; exit 1
|
||||
warn "scoop help: no such command '$cmd'"
|
||||
exit 1
|
||||
}
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -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'
|
||||
|
||||
66
libexec/scoop-import.ps1
Normal file
66
libexec/scoop-import.ps1
Normal file
@@ -0,0 +1,66 @@
|
||||
# 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)]
|
||||
[String]
|
||||
$scoopfile
|
||||
)
|
||||
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1"
|
||||
|
||||
$import = $null
|
||||
$bucket_names = @()
|
||||
$def_arch = Get-DefaultArchitecture
|
||||
|
||||
if (Test-Path $scoopfile) {
|
||||
$import = parse_json $scoopfile
|
||||
} elseif ($scoopfile -match '^(ht|f)tps?://|\\\\') {
|
||||
$import = url_manifest $scoopfile
|
||||
}
|
||||
|
||||
if (!$import) { abort 'Input file not a valid JSON.' }
|
||||
|
||||
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)'"
|
||||
}
|
||||
|
||||
foreach ($item in $import.buckets) {
|
||||
add_bucket $item.Name $item.Source | Out-Null
|
||||
$bucket_names += $item.Name
|
||||
}
|
||||
|
||||
foreach ($item in $import.apps) {
|
||||
$info = $item.Info -Split ', '
|
||||
$global = if ('Global install' -in $info) {
|
||||
' --global'
|
||||
} else {
|
||||
''
|
||||
}
|
||||
$arch = if ('64bit' -in $info -and '64bit' -ne $def_arch) {
|
||||
' --arch 64bit'
|
||||
} elseif ('32bit' -in $info -and '32bit' -ne $def_arch) {
|
||||
' --arch 32bit'
|
||||
} elseif ('arm64' -in $info -and 'arm64' -ne $def_arch) {
|
||||
' --arch arm64'
|
||||
} else {
|
||||
''
|
||||
}
|
||||
|
||||
$app = if ($item.Source -in $bucket_names) {
|
||||
"$($item.Source)/$($item.Name)"
|
||||
} elseif ($item.Source -eq '<auto-generated>') {
|
||||
"$($item.Name)@$($item.Version)"
|
||||
} else {
|
||||
$item.Source
|
||||
}
|
||||
|
||||
& "$PSScriptRoot\scoop-install.ps1" $app$global$arch
|
||||
|
||||
if ('Held package' -in $info) {
|
||||
& "$PSScriptRoot\scoop-hold.ps1" $($item.Name)$global
|
||||
}
|
||||
}
|
||||
@@ -105,6 +105,85 @@ if ($status.installed) {
|
||||
$installed_output += if ($verbose) { versiondir $app $_ $global } else { "$_$(if ($global) { " *global*" })" }
|
||||
}
|
||||
$item.Installed = $installed_output -join "`n"
|
||||
|
||||
if ($verbose) {
|
||||
# Show size of installation
|
||||
$appsdir = appsdir $global
|
||||
|
||||
# Collect file list from each location
|
||||
$appFiles = Get-ChildItem $appsdir -Filter $app
|
||||
$currentFiles = Get-ChildItem $appFiles -Filter (Select-CurrentVersion $app $global)
|
||||
$persistFiles = Get-ChildItem $persist_dir -ErrorAction Ignore # Will fail if app does not persist data
|
||||
$cacheFiles = Get-ChildItem $cachedir -Filter "$app#*"
|
||||
|
||||
# Get the sum of each file list
|
||||
$fileTotals = @()
|
||||
foreach ($fileType in ($appFiles, $currentFiles, $persistFiles, $cacheFiles)) {
|
||||
if ($null -ne $fileType) {
|
||||
$fileSum = (Get-ChildItem $fileType -Recurse | Measure-Object -Property Length -Sum).Sum
|
||||
$fileTotals += coalesce $fileSum 0
|
||||
} else {
|
||||
$fileTotals += 0
|
||||
}
|
||||
}
|
||||
|
||||
# Old versions = app total - current version size
|
||||
$fileTotals += $fileTotals[0] - $fileTotals[1]
|
||||
|
||||
if ($fileTotals[2] + $fileTotals[3] + $fileTotals[4] -eq 0) {
|
||||
# Simple app size output if no old versions, persisted data, cached downloads
|
||||
$item.'Installed size' = filesize $fileTotals[1]
|
||||
} else {
|
||||
$fileSizes = [ordered] @{
|
||||
'Current version: ' = $fileTotals[1]
|
||||
'Old versions: ' = $fileTotals[4]
|
||||
'Persisted data: ' = $fileTotals[2]
|
||||
'Cached downloads: ' = $fileTotals[3]
|
||||
'Total: ' = $fileTotals[0] + $fileTotals[2] + $fileTotals[3]
|
||||
}
|
||||
|
||||
$fileSizeOutput = @()
|
||||
|
||||
# Don't output empty categories
|
||||
$fileSizes.GetEnumerator() | ForEach-Object {
|
||||
if ($_.Value -ne 0) {
|
||||
$fileSizeOutput += $_.Key + (filesize $_.Value)
|
||||
}
|
||||
}
|
||||
|
||||
$item.'Installed size' = $fileSizeOutput -join "`n"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($verbose) {
|
||||
# Get download size if app not installed
|
||||
$totalPackage = 0
|
||||
foreach ($url in @(url $manifest (Get-DefaultArchitecture))) {
|
||||
try {
|
||||
if (Test-Path (fullpath (cache_path $app $manifest.version $url))) {
|
||||
$cached = " (latest version is cached)"
|
||||
} else {
|
||||
$cached = $null
|
||||
}
|
||||
|
||||
[int]$urlLength = (Invoke-WebRequest $url -Method Head).Headers.'Content-Length'[0]
|
||||
$totalPackage += $urlLength
|
||||
} catch [System.Management.Automation.RuntimeException] {
|
||||
$totalPackage = 0
|
||||
$packageError = "the server at $(([System.Uri]$url).Host) did not send a Content-Length header"
|
||||
break
|
||||
} catch {
|
||||
$totalPackage = 0
|
||||
$packageError = "the server at $(([System.Uri]$url).Host) is down"
|
||||
break
|
||||
}
|
||||
}
|
||||
if ($totalPackage -ne 0) {
|
||||
$item.'Download size' = "$(filesize $totalPackage)$cached"
|
||||
} else {
|
||||
$item.'Download size' = "Unknown ($packageError)$cached"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$binaries = @(arch_specific 'bin' $manifest $install.architecture)
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
# Help: e.g. The usual way to install an app (uses your local 'buckets'):
|
||||
# scoop install git
|
||||
#
|
||||
# To install a different version of the app
|
||||
# (note that this will auto-generate the manifest using current version):
|
||||
# scoop install gh@2.7.0
|
||||
#
|
||||
# To install an app from a manifest at a URL:
|
||||
# scoop install https://raw.githubusercontent.com/ScoopInstaller/Main/master/bucket/runat.json
|
||||
#
|
||||
@@ -10,17 +14,17 @@
|
||||
# scoop install \path\to\app.json
|
||||
#
|
||||
# Options:
|
||||
# -g, --global Install the app globally
|
||||
# -i, --independent Don't install dependencies automatically
|
||||
# -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
|
||||
# -g, --global Install the app globally
|
||||
# -i, --independent Don't install dependencies automatically
|
||||
# -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|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"
|
||||
@@ -35,9 +39,9 @@ $global = $opt.g -or $opt.global
|
||||
$check_hash = !($opt.s -or $opt.skip)
|
||||
$independent = $opt.i -or $opt.independent
|
||||
$use_cache = !($opt.k -or $opt.'no-cache')
|
||||
$architecture = default_architecture
|
||||
$architecture = Get-DefaultArchitecture
|
||||
try {
|
||||
$architecture = ensure_architecture ($opt.a + $opt.arch)
|
||||
$architecture = Format-ArchitectureString ($opt.a + $opt.arch)
|
||||
} catch {
|
||||
abort "ERROR: $_"
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ param($query)
|
||||
. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1" # 'parse_json' 'Select-CurrentVersion' (indirectly)
|
||||
|
||||
$def_arch = default_architecture
|
||||
$def_arch = Get-DefaultArchitecture
|
||||
if (-not (Get-FormatData ScoopApps)) {
|
||||
Update-FormatData "$PSScriptRoot\..\supporting\formats\ScoopTypes.Format.ps1xml"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
# Help: Used to resolve conflicts in favor of a particular app. For example,
|
||||
# if you've installed 'python' and 'python27', you can use 'scoop reset' to switch between
|
||||
# using one or the other.
|
||||
#
|
||||
# You can use '*' in place of <app> or `-a`/`--all` switch to reset all apps.
|
||||
|
||||
. "$PSScriptRoot\..\lib\getopt.ps1"
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1" # 'Select-CurrentVersion' (indirectly)
|
||||
@@ -10,12 +12,13 @@
|
||||
. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
|
||||
. "$PSScriptRoot\..\lib\shortcuts.ps1"
|
||||
|
||||
$opt, $apps, $err = getopt $args
|
||||
$opt, $apps, $err = getopt $args 'a' 'all'
|
||||
if($err) { "scoop reset: $err"; exit 1 }
|
||||
$all = $opt.a -or $opt.all
|
||||
|
||||
if(!$apps) { error '<app> missing'; my_usage; exit 1 }
|
||||
if(!$apps -and !$all) { error '<app> missing'; my_usage; exit 1 }
|
||||
|
||||
if($apps -eq '*') {
|
||||
if($apps -eq '*' -or $all) {
|
||||
$local = installed_apps $false | ForEach-Object { ,@($_, $false) }
|
||||
$global = installed_apps $true | ForEach-Object { ,@($_, $true) }
|
||||
$apps = @($local) + @($global)
|
||||
@@ -60,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
|
||||
|
||||
|
||||
@@ -9,35 +9,43 @@ param($query)
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1" # 'manifest'
|
||||
. "$PSScriptRoot\..\lib\versions.ps1" # 'Get-LatestVersion'
|
||||
|
||||
function bin_match($manifest, $query) {
|
||||
if(!$manifest.bin) { return $false }
|
||||
foreach($bin in $manifest.bin) {
|
||||
$exe, $alias, $args = $bin
|
||||
$fname = split-path $exe -leaf -ea stop
|
||||
$list = @()
|
||||
|
||||
if((strip_ext $fname) -match $query) { return $fname }
|
||||
if($alias -match $query) { return $alias }
|
||||
try {
|
||||
$query = New-Object Regex $query, 'IgnoreCase'
|
||||
} catch {
|
||||
abort "Invalid regular expression: $($_.Exception.InnerException.Message)"
|
||||
}
|
||||
|
||||
$githubtoken = Get-GitHubToken
|
||||
$authheader = @{}
|
||||
if ($githubtoken) {
|
||||
$authheader = @{'Authorization' = "token $githubtoken"}
|
||||
}
|
||||
|
||||
function bin_match($manifest, $query) {
|
||||
if (!$manifest.bin) { return $false }
|
||||
$bins = foreach ($bin in $manifest.bin) {
|
||||
$exe, $alias, $args = $bin
|
||||
$fname = Split-Path $exe -Leaf -ErrorAction Stop
|
||||
|
||||
if ((strip_ext $fname) -match $query) { $fname }
|
||||
elseif ($alias -match $query) { $alias }
|
||||
}
|
||||
$false
|
||||
if ($bins) { return $bins }
|
||||
else { return $false }
|
||||
}
|
||||
|
||||
function search_bucket($bucket, $query) {
|
||||
$apps = apps_in_bucket (Find-BucketDirectory $bucket) | ForEach-Object {
|
||||
@{ name = $_ }
|
||||
}
|
||||
|
||||
if($query) {
|
||||
try {
|
||||
$query = new-object regex $query, 'IgnoreCase'
|
||||
} catch {
|
||||
abort "Invalid regular expression: $($_.exception.innerexception.message)"
|
||||
}
|
||||
$apps = apps_in_bucket (Find-BucketDirectory $bucket) | ForEach-Object { @{ name = $_ } }
|
||||
|
||||
if ($query) {
|
||||
$apps = $apps | Where-Object {
|
||||
if($_.name -match $query) { return $true }
|
||||
if ($_.name -match $query) { return $true }
|
||||
$bin = bin_match (manifest $_.name $bucket) $query
|
||||
if($bin) {
|
||||
$_.bin = $bin; return $true;
|
||||
if ($bin) {
|
||||
$_.bin = $bin
|
||||
return $true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,14 +54,19 @@ function search_bucket($bucket, $query) {
|
||||
|
||||
function download_json($url) {
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
$result = Invoke-WebRequest $url -UseBasicParsing | Select-Object -ExpandProperty content | ConvertFrom-Json
|
||||
$result = Invoke-WebRequest $url -UseBasicParsing -Headers $authheader | Select-Object -ExpandProperty content | ConvertFrom-Json
|
||||
$ProgressPreference = 'Continue'
|
||||
$result
|
||||
}
|
||||
|
||||
function github_ratelimit_reached {
|
||||
$api_link = 'https://api.github.com/rate_limit'
|
||||
(download_json $api_link).rate.remaining -eq 0
|
||||
$ret = (download_json $api_link).rate.remaining -eq 0
|
||||
if ($ret) {
|
||||
Write-Host "GitHub API rate limit reached.
|
||||
Please try again later or configure your API token using 'scoop config gh_token <your token>'."
|
||||
}
|
||||
$ret
|
||||
}
|
||||
|
||||
function search_remote($bucket, $query) {
|
||||
@@ -72,44 +85,59 @@ function search_remote($bucket, $query) {
|
||||
|
||||
function search_remotes($query) {
|
||||
$buckets = known_bucket_repos
|
||||
$names = $buckets | get-member -m noteproperty | Select-Object -exp name
|
||||
$names = $buckets | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty name
|
||||
|
||||
$results = $names | Where-Object { !(test-path $(Find-BucketDirectory $_)) } | ForEach-Object {
|
||||
@{"bucket" = $_; "results" = (search_remote $_ $query)}
|
||||
$results = $names | Where-Object { !(Test-Path $(Find-BucketDirectory $_)) } | ForEach-Object {
|
||||
@{ "bucket" = $_; "results" = (search_remote $_ $query) }
|
||||
} | Where-Object { $_.results }
|
||||
|
||||
if ($results.count -gt 0) {
|
||||
"Results from other known buckets..."
|
||||
"(add them using 'scoop bucket add <name>')"
|
||||
""
|
||||
Write-Host "Results from other known buckets...
|
||||
(add them using 'scoop bucket add <bucket name>')"
|
||||
}
|
||||
|
||||
$results | ForEach-Object {
|
||||
"'$($_.bucket)' bucket (install using 'scoop install $($_.bucket)/<app>'):"
|
||||
$_.results | ForEach-Object { " $_" }
|
||||
""
|
||||
$name = $_.bucket
|
||||
$_.results | ForEach-Object {
|
||||
$item = [ordered]@{}
|
||||
$item.Name = $_
|
||||
$item.Source = $name
|
||||
$list += [PSCustomObject]$item
|
||||
}
|
||||
}
|
||||
|
||||
$list
|
||||
}
|
||||
|
||||
Get-LocalBucket | ForEach-Object {
|
||||
$res = search_bucket $_ $query
|
||||
$local_results = $local_results -or $res
|
||||
if($res) {
|
||||
if ($res) {
|
||||
$name = "$_"
|
||||
|
||||
Write-Host "'$name' bucket:"
|
||||
$res | ForEach-Object {
|
||||
$item = " $($_.name) ($($_.version))"
|
||||
if($_.bin) { $item += " --> includes '$($_.bin)'" }
|
||||
$item
|
||||
$item = [ordered]@{}
|
||||
$item.Name = $_.name
|
||||
$item.Version = $_.version
|
||||
$item.Source = $name
|
||||
$item.Binaries = ""
|
||||
if ($_.bin) { $item.Binaries = $_.bin -join ' | ' }
|
||||
$list += [PSCustomObject]$item
|
||||
}
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
if ($list.Length -gt 0) {
|
||||
Write-Host "Results from local buckets..."
|
||||
$list
|
||||
}
|
||||
|
||||
if (!$local_results -and !(github_ratelimit_reached)) {
|
||||
$remote_results = search_remotes $query
|
||||
if(!$remote_results) { [console]::error.writeline("No matches found."); exit 1 }
|
||||
if (!$remote_results) {
|
||||
warn "No matches found."
|
||||
exit 1
|
||||
}
|
||||
$remote_results
|
||||
}
|
||||
|
||||
|
||||
@@ -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'
|
||||
my_usage
|
||||
exit 1
|
||||
}
|
||||
|
||||
if ($SubCommand -ne 'list' -and !$ShimName) {
|
||||
"ERROR: <shim_name> must be specified for subcommand '$SubCommand'"
|
||||
my_usage
|
||||
exit 1
|
||||
}
|
||||
|
||||
if ($Args) {
|
||||
switch ($SubCommand) {
|
||||
'add' {
|
||||
if ($Args[0] -like '-*') {
|
||||
"ERROR: <command_path> must be specified for subcommand 'add'"
|
||||
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 (!$SubCommand) {
|
||||
error '<subcommand> missing'
|
||||
} else {
|
||||
error "'$SubCommand' is not one of available subcommands: add, rm, list, info, alter"
|
||||
}
|
||||
my_usage
|
||||
exit 1
|
||||
}
|
||||
|
||||
$opt, $other, $err = getopt $Args 'g' 'global'
|
||||
if ($err) { "scoop shim: $err"; exit 1 }
|
||||
|
||||
$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
|
||||
}
|
||||
|
||||
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) } |
|
||||
Select-Object -ExpandProperty FullName
|
||||
$other = @($other) -ne '*'
|
||||
# Validate all given patterns before matching.
|
||||
$other | ForEach-Object {
|
||||
try {
|
||||
$pattern = $_
|
||||
[Regex]::New($pattern)
|
||||
} catch {
|
||||
Write-Host "ERROR: Invalid pattern: " -ForegroundColor Red -NoNewline
|
||||
Write-Host $pattern -ForegroundColor Magenta
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
$pattern = $other -join '|'
|
||||
$shims = @()
|
||||
if (!$global) {
|
||||
$shims += Get-ChildItem -Path $localShimDir -Recurse -Include '*.shim', '*.ps1' |
|
||||
Where-Object { !$pattern -or ($_.BaseName -match $pattern) } |
|
||||
Select-Object -ExpandProperty FullName
|
||||
}
|
||||
if (Test-Path $globalShimDir) {
|
||||
$shims += Get-ChildItem -Path $globalShimDir -Recurse -Include '*.shim', '*.ps1' |
|
||||
Where-Object { !$ShimName -or ($_.BaseName -match $ShimName) } |
|
||||
Where-Object { !$pattern -or ($_.BaseName -match $pattern) } |
|
||||
Select-Object -ExpandProperty FullName
|
||||
}
|
||||
$shims.ForEach({ Get-ShimInfo $_ }) | Add-Member -TypeName 'ScoopShims' -PassThru
|
||||
}
|
||||
'info' {
|
||||
$shimPath = Get-ShimPath $ShimName $global
|
||||
$shimName = $other[0]
|
||||
$shimPath = Get-ShimPath $shimName $global
|
||||
if ($shimPath) {
|
||||
Get-ShimInfo $shimPath
|
||||
} else {
|
||||
Write-Host "$(if ($global) { 'Global' } else { 'Local' }) shim not found: " -NoNewline
|
||||
Write-Host $ShimName -ForegroundColor Cyan
|
||||
if (Get-ShimPath $ShimName (!$global)) {
|
||||
Write-Host "ERROR: $(if ($global) { 'Global' } else { 'Local' }) shim not found: " -ForegroundColor Red -NoNewline
|
||||
Write-Host $shimName -ForegroundColor Cyan
|
||||
if (Get-ShimPath $shimName (!$global)) {
|
||||
Write-Host "But a $(if ($global) { 'local' } else {'global' }) shim exists, " -NoNewline
|
||||
Write-Host "run 'scoop shim info $ShimName$(if (!$global) { ' -global' })' to show its info"
|
||||
Write-Host "run 'scoop shim info $shimName$(if (!$global) { ' --global' })' to show its info"
|
||||
exit 2
|
||||
}
|
||||
exit 3
|
||||
}
|
||||
}
|
||||
'alter' {
|
||||
$shimPath = Get-ShimPath $ShimName $global
|
||||
$shimName = $other[0]
|
||||
$shimPath = Get-ShimPath $shimName $global
|
||||
if ($shimPath) {
|
||||
$shimInfo = Get-ShimInfo $shimPath
|
||||
if ($null -eq $shimInfo.Alternatives) {
|
||||
Write-Host 'No alternatives of ' -NoNewline
|
||||
Write-Host $ShimName -ForegroundColor Cyan -NoNewline
|
||||
Write-Host ' found.'
|
||||
Write-Host 'ERROR: No alternatives of ' -ForegroundColor Red -NoNewline
|
||||
Write-Host $shimName -ForegroundColor Cyan -NoNewline
|
||||
Write-Host ' found.' -ForegroundColor Red
|
||||
exit 2
|
||||
}
|
||||
$shimInfo.Alternatives = $shimInfo.Alternatives.Split(' ')
|
||||
[System.Management.Automation.Host.ChoiceDescription[]]$altApps = 1..$shimInfo.Alternatives.Length | ForEach-Object {
|
||||
New-Object System.Management.Automation.Host.ChoiceDescription "&$($_)`b$($shimInfo.Alternatives[$_ - 1])", "Sets '$ShimName' shim from $($shimInfo.Alternatives[$_ - 1])."
|
||||
New-Object System.Management.Automation.Host.ChoiceDescription "&$($_)`b$($shimInfo.Alternatives[$_ - 1])", "Sets '$shimName' shim from $($shimInfo.Alternatives[$_ - 1])."
|
||||
}
|
||||
$selected = $Host.UI.PromptForChoice("Alternatives of '$ShimName' command", "Please choose one that provides '$ShimName' as default:", $altApps, 0)
|
||||
$selected = $Host.UI.PromptForChoice("Alternatives of '$shimName' command", "Please choose one that provides '$shimName' as default:", $altApps, 0)
|
||||
if ($selected -eq 0) {
|
||||
Write-Host $ShimName -ForegroundColor Cyan -NoNewline
|
||||
Write-Host 'INFO: ' -ForegroundColor Blue -NoNewline
|
||||
Write-Host $shimName -ForegroundColor Cyan -NoNewline
|
||||
Write-Host ' is already from ' -NoNewline
|
||||
Write-Host $shimInfo.Source -ForegroundColor DarkYellow -NoNewline
|
||||
Write-Host ', nothing changed.'
|
||||
} else {
|
||||
$newApp = $shimInfo.Alternatives[$selected]
|
||||
Write-Host 'Use ' -NoNewline
|
||||
Write-Host $ShimName -ForegroundColor Cyan -NoNewline
|
||||
Write-Host $shimName -ForegroundColor Cyan -NoNewline
|
||||
Write-Host ' from ' -NoNewline
|
||||
Write-Host $newApp -ForegroundColor DarkYellow -NoNewline
|
||||
Write-Host ' as default...' -NoNewline
|
||||
@@ -211,11 +224,11 @@ switch ($SubCommand) {
|
||||
Write-Host 'done.'
|
||||
}
|
||||
} else {
|
||||
Write-Host "$(if ($global) { 'Global' } else { 'Local' }) shim not found: " -NoNewline
|
||||
Write-Host $ShimName -ForegroundColor Cyan
|
||||
if (Get-ShimPath $ShimName (!$global)) {
|
||||
Write-Host "ERROR: $(if ($global) { 'Global' } else { 'Local' }) shim not found: " -ForegroundColor Red -NoNewline
|
||||
Write-Host $shimName -ForegroundColor Cyan
|
||||
if (Get-ShimPath $shimName (!$global)) {
|
||||
Write-Host "But a $(if ($global) { 'local' } else {'global' }) shim exists, " -NoNewline
|
||||
Write-Host "run 'scoop shim alter $ShimName$(if (!$global) { ' -global' })' to alternate its source"
|
||||
Write-Host "run 'scoop shim alter $shimName$(if (!$global) { ' --global' })' to alternate its source"
|
||||
exit 2
|
||||
}
|
||||
exit 3
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
# Usage: scoop status
|
||||
# Summary: Show status and check for new app versions
|
||||
# Help: Options:
|
||||
# -l, --local Checks the status for only the locally installed apps,
|
||||
# and disables remote fetching/checking for Scoop and buckets
|
||||
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1" # 'manifest' 'parse_json' "install_info"
|
||||
. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
|
||||
@@ -7,24 +10,45 @@
|
||||
# check if scoop needs updating
|
||||
$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"
|
||||
}
|
||||
|
||||
if (Test-Path "$currentdir\.git") {
|
||||
git_cmd -C "`"$currentdir`"" fetch -q origin
|
||||
$commits = $(git -C $currentdir log "HEAD..origin/$(get_config SCOOP_BRANCH)" --oneline)
|
||||
if ($commits) { $needs_update = $true }
|
||||
} else {
|
||||
$needs_update = $true
|
||||
function Test-UpdateStatus($repopath) {
|
||||
if (Test-Path "$repopath\.git") {
|
||||
git_cmd -C "`"$repopath`"" fetch -q origin
|
||||
$script:network_failure = 128 -eq $LASTEXITCODE
|
||||
$branch = git -C $repopath branch --show-current
|
||||
$commits = git -C $repopath log "HEAD..origin/$branch" --oneline
|
||||
if ($commits) { return $true }
|
||||
else { return $false }
|
||||
} else {
|
||||
return $true
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($needs_update) {
|
||||
warn "Scoop is out of date. Run 'scoop update' to get the latest changes."
|
||||
} else { success 'Scoop is up to date.' }
|
||||
|
||||
$failed = @()
|
||||
$outdated = @()
|
||||
$removed = @()
|
||||
$missing_deps = @()
|
||||
$onhold = @()
|
||||
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 -and !$no_remotes) {
|
||||
success 'Scoop is up to date.'
|
||||
}
|
||||
|
||||
$true, $false | ForEach-Object { # local and global apps
|
||||
$global = $_
|
||||
@@ -34,64 +58,26 @@ $true, $false | ForEach-Object { # local and global apps
|
||||
Get-ChildItem $dir | Where-Object name -NE 'scoop' | ForEach-Object {
|
||||
$app = $_.name
|
||||
$status = app_status $app $global
|
||||
if ($status.failed) {
|
||||
$failed += @{ $app = $status.version }
|
||||
}
|
||||
if ($status.removed) {
|
||||
$removed += @{ $app = $status.version }
|
||||
}
|
||||
if ($status.outdated) {
|
||||
$outdated += @{ $app = @($status.version, $status.latest_version) }
|
||||
if ($status.hold) {
|
||||
$onhold += @{ $app = @($status.version, $status.latest_version) }
|
||||
}
|
||||
}
|
||||
if ($status.missing_deps) {
|
||||
$missing_deps += , (@($app) + @($status.missing_deps))
|
||||
}
|
||||
if (!$status.outdated -and !$status.failed -and !$status.removed -and !$status.missing_deps) { return }
|
||||
|
||||
$item = [ordered]@{}
|
||||
$item.Name = $app
|
||||
$item.'Installed Version' = $status.version
|
||||
$item.'Latest Version' = if ($status.outdated) { $status.latest_version } else { "" }
|
||||
$item.'Missing Dependencies' = $status.missing_deps -Split ' ' -Join ' | '
|
||||
$info = @()
|
||||
if ($status.failed) { $info += 'Install failed' }
|
||||
if ($status.hold) { $info += 'Held package' }
|
||||
if ($status.removed) { $info += 'Manifest removed' }
|
||||
$item.Info = $info -join ', '
|
||||
$list += [PSCustomObject]$item
|
||||
}
|
||||
}
|
||||
|
||||
if ($outdated) {
|
||||
Write-Host -f DarkCyan 'Updates are available for:'
|
||||
$outdated.keys | ForEach-Object {
|
||||
$versions = $outdated.$_
|
||||
" $_`: $($versions[0]) -> $($versions[1])"
|
||||
}
|
||||
}
|
||||
|
||||
if ($onhold) {
|
||||
Write-Host -f DarkCyan 'These apps are outdated and on hold:'
|
||||
$onhold.keys | ForEach-Object {
|
||||
$versions = $onhold.$_
|
||||
" $_`: $($versions[0]) -> $($versions[1])"
|
||||
}
|
||||
}
|
||||
|
||||
if ($removed) {
|
||||
Write-Host -f DarkCyan 'These app manifests have been removed:'
|
||||
$removed.keys | ForEach-Object {
|
||||
" $_"
|
||||
}
|
||||
}
|
||||
|
||||
if ($failed) {
|
||||
Write-Host -f DarkCyan 'These apps failed to install:'
|
||||
$failed.keys | ForEach-Object {
|
||||
" $_"
|
||||
}
|
||||
}
|
||||
|
||||
if ($missing_deps) {
|
||||
Write-Host -f DarkCyan 'Missing runtime dependencies:'
|
||||
$missing_deps | ForEach-Object {
|
||||
$app, $deps = $_
|
||||
" '$app' requires '$([string]::join("', '", $deps))'"
|
||||
}
|
||||
}
|
||||
|
||||
if (!$old -and !$removed -and !$failed -and !$missing_deps -and !$needs_update) {
|
||||
if ($list.Length -eq 0 -and !$needs_update -and !$bucket_needs_update -and !$script:network_failure) {
|
||||
success 'Everything is ok!'
|
||||
}
|
||||
|
||||
$list | Add-Member -TypeName ScoopStatus -PassThru
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -32,6 +32,11 @@ if ($global -and !(is_admin)) {
|
||||
$apps | ForEach-Object {
|
||||
$app = $_
|
||||
|
||||
if ($app -eq 'scoop') {
|
||||
set_config HOLD_UPDATE_UNTIL $null | Out-Null
|
||||
success "$app is no longer held and can be updated again."
|
||||
return
|
||||
}
|
||||
if (!(installed $app $global)) {
|
||||
if ($global) {
|
||||
error "'$app' is not installed globally."
|
||||
@@ -41,7 +46,7 @@ $apps | ForEach-Object {
|
||||
return
|
||||
}
|
||||
|
||||
if (get_config NO_JUNCTIONS) {
|
||||
if (get_config NO_JUNCTION){
|
||||
$version = Select-CurrentVersion -App $app -Global:$global
|
||||
} else {
|
||||
$version = 'current'
|
||||
|
||||
@@ -54,16 +54,18 @@ if(($PSVersionTable.PSVersion.Major) -lt 5) {
|
||||
Write-Output "Upgrade PowerShell: https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-windows"
|
||||
break
|
||||
}
|
||||
$show_update_log = get_config SHOW_UPDATE_LOG $true
|
||||
|
||||
function update_scoop($show_update_log) {
|
||||
# Test if Scoop Core is hold
|
||||
if(Test-ScoopCoreOnHold) {
|
||||
return
|
||||
}
|
||||
|
||||
function update_scoop() {
|
||||
# check for git
|
||||
if(!(Test-CommandAvailable git)) { abort "Scoop uses Git to update itself. Run 'scoop install git' and try again." }
|
||||
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'
|
||||
@@ -187,7 +202,7 @@ function update($app, $global, $quiet = $false, $independent, $suggested, $use_c
|
||||
$version = $manifest.version
|
||||
$is_nightly = $version -eq 'nightly'
|
||||
if ($is_nightly) {
|
||||
$version = nightly_version $(get-date) $quiet
|
||||
$version = nightly_version $quiet
|
||||
$check_hash = $false
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Summary: Look for app's hash or url on virustotal.com
|
||||
# Help: Look for app's hash or url on virustotal.com
|
||||
#
|
||||
# Use a single '*' for app to check all installed apps.
|
||||
# Use a single '*' or the '-a/--all' switch to check all installed apps.
|
||||
#
|
||||
# To use this command, you have to sign up to VirusTotal's community,
|
||||
# and get an API key. Then, tell scoop about your API key with:
|
||||
@@ -20,7 +20,7 @@
|
||||
# 2 & 4 combined
|
||||
#
|
||||
# Options:
|
||||
# -a, --arch <32bit|64bit> Use the specified architecture, if the app supports it
|
||||
# -a, --all Check for all installed apps
|
||||
# -s, --scan For packages where VirusTotal has no information, send download URL
|
||||
# for analysis (and future retrieval). This requires you to configure
|
||||
# your virustotal_api_key.
|
||||
@@ -34,10 +34,10 @@
|
||||
. "$PSScriptRoot\..\lib\install.ps1" # 'hash_for_url'
|
||||
. "$PSScriptRoot\..\lib\depends.ps1" # 'Get-Dependency'
|
||||
|
||||
$opt, $apps, $err = getopt $args 'a:snup' @('arch=', 'scan', 'no-depends', 'no-update-scoop', 'passthru')
|
||||
$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 ($opt.a + $opt.arch)
|
||||
$architecture = Format-ArchitectureString
|
||||
|
||||
if (is_scoop_outdated) {
|
||||
if ($opt.u -or $opt.'no-update-scoop') {
|
||||
@@ -49,7 +49,7 @@ if (is_scoop_outdated) {
|
||||
|
||||
$apps_param = $apps
|
||||
|
||||
if ($apps_param -eq '*') {
|
||||
if ($apps_param -eq '*' -or $opt.a -or $opt.all) {
|
||||
$apps = installed_apps $false
|
||||
$apps += installed_apps $true
|
||||
}
|
||||
@@ -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" +
|
||||
|
||||
168
schema.json
168
schema.json
@@ -179,19 +179,11 @@
|
||||
"type": "array"
|
||||
},
|
||||
"autoupdateArch": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"url": {
|
||||
"$ref": "#/definitions/autoupdateUriOrArrayOfAutoupdateUris"
|
||||
},
|
||||
"hash": {
|
||||
"$ref": "#/definitions/hashExtractionOrArrayOfHashExtractions"
|
||||
},
|
||||
"extract_dir": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStrings"
|
||||
},
|
||||
"extract_to": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStrings"
|
||||
"bin": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStringsOrAnArrayOfArrayOfStrings"
|
||||
},
|
||||
"env_add_path": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStrings"
|
||||
@@ -199,71 +191,97 @@
|
||||
"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"
|
||||
"shortcuts": {
|
||||
"$ref": "#/definitions/shortcutsArray"
|
||||
},
|
||||
"psmodule": {
|
||||
"url": {
|
||||
"$ref": "#/definitions/autoupdateUriOrArrayOfAutoupdateUris"
|
||||
}
|
||||
}
|
||||
},
|
||||
"autoupdate": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"architecture": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
"32bit": {
|
||||
"$ref": "#/definitions/autoupdateArch"
|
||||
},
|
||||
"64bit": {
|
||||
"$ref": "#/definitions/autoupdateArch"
|
||||
},
|
||||
"arm64": {
|
||||
"$ref": "#/definitions/autoupdateArch"
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
"bin": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStringsOrAnArrayOfArrayOfStrings"
|
||||
},
|
||||
"env_add_path": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStrings"
|
||||
},
|
||||
"env_set": {
|
||||
"type": "object"
|
||||
},
|
||||
"persist": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStringsOrAnArrayOfArrayOfStrings"
|
||||
"extract_dir": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStrings"
|
||||
},
|
||||
"hash": {
|
||||
"$ref": "#/definitions/hashExtractionOrArrayOfHashExtractions"
|
||||
},
|
||||
"installer": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"license": {
|
||||
"$ref": "#/definitions/license"
|
||||
},
|
||||
"notes": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStrings"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"autoupdate": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/autoupdateArch"
|
||||
},
|
||||
{
|
||||
"persist": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStringsOrAnArrayOfArrayOfStrings"
|
||||
},
|
||||
"psmodule": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"notes": {
|
||||
"$ref": "#/definitions/stringOrArrayOfStrings"
|
||||
},
|
||||
"architecture": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"32bit": {
|
||||
"$ref": "#/definitions/autoupdateArch"
|
||||
},
|
||||
"64bit": {
|
||||
"$ref": "#/definitions/autoupdateArch"
|
||||
}
|
||||
}
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"shortcuts": {
|
||||
"$ref": "#/definitions/shortcutsArray"
|
||||
},
|
||||
"url": {
|
||||
"$ref": "#/definitions/autoupdateUriOrArrayOfAutoupdateUris"
|
||||
}
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"checkver": {
|
||||
"anyOf": [
|
||||
@@ -315,6 +333,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 +545,9 @@
|
||||
},
|
||||
"64bit": {
|
||||
"$ref": "#/definitions/architecture"
|
||||
},
|
||||
"arm64": {
|
||||
"$ref": "#/definitions/architecture"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
@@ -614,6 +654,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",
|
||||
|
||||
@@ -60,5 +60,34 @@
|
||||
</TableRowEntries>
|
||||
</TableControl>
|
||||
</View>
|
||||
<View>
|
||||
<Name>ScoopStatusType</Name>
|
||||
<ViewSelectedBy>
|
||||
<TypeName>ScoopStatus</TypeName>
|
||||
</ViewSelectedBy>
|
||||
<TableControl>
|
||||
<TableRowEntries>
|
||||
<TableRowEntry>
|
||||
<TableColumnItems>
|
||||
<TableColumnItem>
|
||||
<PropertyName>Name</PropertyName>
|
||||
</TableColumnItem>
|
||||
<TableColumnItem>
|
||||
<PropertyName>Installed Version</PropertyName>
|
||||
</TableColumnItem>
|
||||
<TableColumnItem>
|
||||
<PropertyName>Latest Version</PropertyName>
|
||||
</TableColumnItem>
|
||||
<TableColumnItem>
|
||||
<PropertyName>Missing Dependencies</PropertyName>
|
||||
</TableColumnItem>
|
||||
<TableColumnItem>
|
||||
<PropertyName>Info</PropertyName>
|
||||
</TableColumnItem>
|
||||
</TableColumnItems>
|
||||
</TableRowEntry>
|
||||
</TableRowEntries>
|
||||
</TableControl>
|
||||
</View>
|
||||
</ViewDefinitions>
|
||||
</Configuration>
|
||||
|
||||
@@ -16,7 +16,7 @@ Write-Output 'Computing checksums ...'
|
||||
Remove-Item "$PSScriptRoot\bin\checksum.sha256" -ErrorAction Ignore
|
||||
Remove-Item "$PSScriptRoot\bin\checksum.sha512" -ErrorAction Ignore
|
||||
Get-ChildItem "$PSScriptRoot\bin\*" -Include *.exe, *.dll | ForEach-Object {
|
||||
"$(compute_hash $_ 'sha256') *$($_.Name)" | Out-File "$PSScriptRoot\bin\checksum.sha256" -Append -Encoding oem
|
||||
"$(compute_hash $_ 'sha512') *$($_.Name)" | Out-File "$PSScriptRoot\bin\checksum.sha512" -Append -Encoding oem
|
||||
"$((Get-FileHash -Path $_ -Algorithm SHA256).Hash.ToLower()) *$($_.Name)" | Out-File "$PSScriptRoot\bin\checksum.sha256" -Append -Encoding oem
|
||||
"$((Get-FileHash -Path $_ -Algorithm SHA512).Hash.ToLower()) *$($_.Name)" | Out-File "$PSScriptRoot\bin\checksum.sha512" -Append -Encoding oem
|
||||
}
|
||||
Pop-Location
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Net.Compilers.Toolset" version="4.0.1" targetFramework="net45" developmentDependency="true" />
|
||||
<package id="Microsoft.Net.Compilers.Toolset" version="4.2.0" targetFramework="net45" developmentDependency="true" />
|
||||
</packages>
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="packages\Microsoft.Net.Compilers.Toolset.4.0.1\build\Microsoft.Net.Compilers.Toolset.props" Condition="Exists('packages\Microsoft.Net.Compilers.Toolset.4.0.1\build\Microsoft.Net.Compilers.Toolset.props')" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{381F9D2E-2355-4F84-9206-06BB9175F97B}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>Scoop.Shim</RootNamespace>
|
||||
<AssemblyName>Scoop.Shim</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="shim.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<Import Project="packages\Microsoft.Net.Compilers.Toolset.4.2.0\build\Microsoft.Net.Compilers.Toolset.props" Condition="Exists('packages\Microsoft.Net.Compilers.Toolset.4.2.0\build\Microsoft.Net.Compilers.Toolset.props')" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}.</ErrorText>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{381F9D2E-2355-4F84-9206-06BB9175F97B}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>Scoop.Shim</RootNamespace>
|
||||
<AssemblyName>Scoop.Shim</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('packages\Microsoft.Net.Compilers.Toolset.4.0.1\build\Microsoft.Net.Compilers.Toolset.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.Net.Compilers.Toolset.4.0.1\build\Microsoft.Net.Compilers.Toolset.props'))" />
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="shim.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('packages\Microsoft.Net.Compilers.Toolset.4.2.0\build\Microsoft.Net.Compilers.Toolset.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.Net.Compilers.Toolset.4.2.0\build\Microsoft.Net.Compilers.Toolset.props'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,4 +1,4 @@
|
||||
7f912b28a07c226e0be3acfb2f57f050538aba0100fa1f0bf2c39f1a1f1da814 *Newtonsoft.Json.dll
|
||||
cff8fc4ce358d7daff84ab47129a776797a4ec819c1586a15bd5e63144f5b73f *Newtonsoft.Json.Schema.dll
|
||||
0d6b228378cbabff23a30456d22f1a31337c466f90cf8b7997cc48bd171155f3 *Scoop.Validator.dll
|
||||
b624949df8b0e3a6153fdfb730a7c6f4990b6592ee0d922e1788433d276610f3 *Newtonsoft.Json.dll
|
||||
9abb57d73d82a2d77008321a85aff2b62e5ac68bebb54ece8668c96cc112e36b *Newtonsoft.Json.Schema.dll
|
||||
0318c8221ce4d44806f8def619bcc02886be0902aab80080e6251c50c6ca53a9 *Scoop.Validator.dll
|
||||
40a70bee96d108701f8f2e81392f9b79fd003f1cb4e1653ad2429753153fd7ee *validator.exe
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
3398094ce429ab5dcdecf2ad04803230669bb4accaef7083992e9b87afac55841ba8def2a5168358bd17e60799e55d076b0e5ca44c86b9e6c91150d3dc37c721 *Newtonsoft.Json.dll
|
||||
298d3d0b656acbb1fe5ed0c3abb49a640c47889184ab7bd4b594e51a7d7f829d5c8685edbd10a286fd56bfd8d601b9f187da463a5a9c8509365eddaea280642f *Newtonsoft.Json.Schema.dll
|
||||
afabe1df6ab837395a5da5ec8dd12bf3f36a8512b76e6f751c14045544246980e9d4061d437792836db792864b7db2761e84f1bf65bac688657a862b68fc7b45 *Scoop.Validator.dll
|
||||
2fdf035661f349206f58ea1feed8805b7f9517a21f9c113e7301c69de160f184c774350a12a710046e3ff6baa37345d319b6f47fd24fbba4e042d54014bee511 *Newtonsoft.Json.dll
|
||||
855ab2e30c9d523c9f321ae861c5969244185f660fa47e05cec96df8e2970d19843dbd3d89a0fca845544641915d1adf4b4a2145ef568dd99da7791e5064d70e *Newtonsoft.Json.Schema.dll
|
||||
338793e6127330c0b05728291fcf18441127ffb56e1bd5c0f0588cd7436605f4b852f4bb622f655896a7eb7b1262add142b200fd5f37391b47d1401becb6b81c *Scoop.Validator.dll
|
||||
d497c27b48f44f4cff270d3c8801b0cecc74108f8786a4a7c40e57541308ae33a69f5456cfc43ae1ce4214038d20da9fbeac1bcf76cc58d972863b58dab18401 *validator.exe
|
||||
|
||||
@@ -21,7 +21,7 @@ Write-Output 'Computing checksums ...'
|
||||
Remove-Item "$PSScriptRoot\bin\checksum.sha256" -ErrorAction Ignore
|
||||
Remove-Item "$PSScriptRoot\bin\checksum.sha512" -ErrorAction Ignore
|
||||
Get-ChildItem "$PSScriptRoot\bin\*" -Include *.exe, *.dll | ForEach-Object {
|
||||
"$(compute_hash $_ 'sha256') *$($_.Name)" | Out-File "$PSScriptRoot\bin\checksum.sha256" -Append -Encoding oem
|
||||
"$(compute_hash $_ 'sha512') *$($_.Name)" | Out-File "$PSScriptRoot\bin\checksum.sha512" -Append -Encoding oem
|
||||
"$((Get-FileHash -Path $_ -Algorithm SHA256).Hash.ToLower()) *$($_.Name)" | Out-File "$PSScriptRoot\bin\checksum.sha256" -Append -Encoding oem
|
||||
"$((Get-FileHash -Path $_ -Algorithm SHA512).Hash.ToLower()) *$($_.Name)" | Out-File "$PSScriptRoot\bin\checksum.sha512" -Append -Encoding oem
|
||||
}
|
||||
Pop-Location
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net45" />
|
||||
<package id="Newtonsoft.Json.Schema" version="3.0.14" targetFramework="net45" />
|
||||
<package id="Microsoft.Net.Compilers.Toolset" version="4.0.1" targetFramework="net45" developmentDependency="true" />
|
||||
<package id="Newtonsoft.Json" version="13.0.1" 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>
|
||||
|
||||
@@ -1,48 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="packages\Microsoft.Net.Compilers.Toolset.4.0.1\build\Microsoft.Net.Compilers.Toolset.props" Condition="Exists('packages\Microsoft.Net.Compilers.Toolset.4.0.1\build\Microsoft.Net.Compilers.Toolset.props')" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{8EB9B38A-1BAB-4D89-B4CB-ACE5E7C1073B}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>Scoop.Validator</RootNamespace>
|
||||
<AssemblyName>Scoop.Validator</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed">
|
||||
<HintPath>packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<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>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="validator.cs" />
|
||||
<Compile Include="Scoop.Validator.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<Import Project="packages\Microsoft.Net.Compilers.Toolset.4.2.0\build\Microsoft.Net.Compilers.Toolset.props" Condition="Exists('packages\Microsoft.Net.Compilers.Toolset.4.2.0\build\Microsoft.Net.Compilers.Toolset.props')" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}.</ErrorText>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{8EB9B38A-1BAB-4D89-B4CB-ACE5E7C1073B}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>Scoop.Validator</RootNamespace>
|
||||
<AssemblyName>Scoop.Validator</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('packages\Microsoft.Net.Compilers.Toolset.4.0.1\build\Microsoft.Net.Compilers.Toolset.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.Net.Compilers.Toolset.4.0.1\build\Microsoft.Net.Compilers.Toolset.props'))" />
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed">
|
||||
<HintPath>packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<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.15-beta2\lib\net45\Newtonsoft.Json.Schema.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="validator.cs" />
|
||||
<Compile Include="Scoop.Validator.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('packages\Microsoft.Net.Compilers.Toolset.4.2.0\build\Microsoft.Net.Compilers.Toolset.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.Net.Compilers.Toolset.4.2.0\build\Microsoft.Net.Compilers.Toolset.props'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
$repo_dir = (Get-Item $MyInvocation.MyCommand.Path).Directory.Parent.FullName
|
||||
|
||||
$repo_files = @( Get-ChildItem $repo_dir -File -Recurse -Force )
|
||||
|
||||
$project_file_exclusions = @(
|
||||
'[\\/]\.git[\\/]',
|
||||
'\.sublime-workspace$',
|
||||
'\.DS_Store$',
|
||||
'supporting(\\|/)validator(\\|/)packages(\\|/)*',
|
||||
'supporting(\\|/)shimexe(\\|/)packages(\\|/)*'
|
||||
)
|
||||
|
||||
Describe 'Project code' {
|
||||
|
||||
$files = @(
|
||||
$repo_files |
|
||||
Where-Object { $_.fullname -inotmatch $($project_file_exclusions -join '|') } |
|
||||
Where-Object { $_.fullname -imatch '.(ps1|psm1)$' }
|
||||
)
|
||||
|
||||
$files_exist = ($files.Count -gt 0)
|
||||
|
||||
It $('PowerShell code files exist ({0} found)' -f $files.Count) -Skip:$(-not $files_exist) {
|
||||
if (-not ($files.Count -gt 0)) {
|
||||
throw 'No PowerShell code files were found'
|
||||
}
|
||||
}
|
||||
|
||||
function Test-PowerShellSyntax {
|
||||
# ref: http://powershell.org/wp/forums/topic/how-to-check-syntax-of-scripts-automatically @@ https://archive.is/xtSv6
|
||||
# originally created by Alexander Petrovskiy & Dave Wyatt
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
|
||||
[string[]]
|
||||
$Path
|
||||
)
|
||||
|
||||
process {
|
||||
foreach ($scriptPath in $Path) {
|
||||
$contents = Get-Content -Path $scriptPath
|
||||
|
||||
if ($null -eq $contents) {
|
||||
continue
|
||||
}
|
||||
|
||||
$errors = $null
|
||||
$null = [System.Management.Automation.PSParser]::Tokenize($contents, [ref]$errors)
|
||||
|
||||
New-Object psobject -Property @{
|
||||
Path = $scriptPath
|
||||
SyntaxErrorsFound = ($errors.Count -gt 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
It 'PowerShell code files do not contain syntax errors' -Skip:$(-not $files_exist) {
|
||||
$badFiles = @(
|
||||
foreach ($file in $files) {
|
||||
if ( (Test-PowerShellSyntax $file.FullName).SyntaxErrorsFound ) {
|
||||
$file.FullName
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if ($badFiles.Count -gt 0) {
|
||||
throw "The following files have syntax errors: `r`n`r`n$($badFiles -join "`r`n")"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
. "$PSScriptRoot\Import-File-Tests.ps1"
|
||||
@@ -1,127 +1,54 @@
|
||||
#Requires -Version 5.0
|
||||
#Requires -Modules @{ ModuleName = 'Pester'; RequiredVersion = '4.10.1' }
|
||||
#Requires -Version 5.1
|
||||
#Requires -Modules @{ ModuleName = 'BuildHelpers'; ModuleVersion = '2.0.1' }
|
||||
#Requires -Modules @{ ModuleName = 'Pester'; ModuleVersion = '5.2.0' }
|
||||
param(
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[String]
|
||||
$repo_dir = (Split-Path -Path $MyInvocation.PSCommandPath -Parent)
|
||||
[String] $BucketPath = $MyInvocation.PSScriptRoot
|
||||
)
|
||||
|
||||
. "$PSScriptRoot\Scoop-TestLib.ps1"
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1"
|
||||
. "$PSScriptRoot\..\lib\unix.ps1"
|
||||
. "$PSScriptRoot\Scoop-00File.Tests.ps1" -TestPath $BucketPath
|
||||
|
||||
$bucketdir = $repo_dir
|
||||
if (Test-Path("$repo_dir\..\bucket")) {
|
||||
$bucketdir = "$repo_dir\..\bucket"
|
||||
} elseif (Test-Path("$repo_dir\bucket")) {
|
||||
$bucketdir = "$repo_dir\bucket"
|
||||
}
|
||||
|
||||
# Tests for non manifest files
|
||||
$repo_files = @(Get-ChildItem -Path $repo_dir -File -Recurse)
|
||||
$project_file_exclusions = @(
|
||||
'[\\/]\.git[\\/]',
|
||||
'.sublime-workspace$',
|
||||
'.DS_Store$'
|
||||
)
|
||||
. "$PSScriptRoot\Import-File-Tests.ps1"
|
||||
|
||||
# Tests for manifest files
|
||||
Describe 'Manifest Validator' -Tag 'Validator' {
|
||||
BeforeAll {
|
||||
$schema = "$PSScriptRoot\..\schema.json"
|
||||
$working_dir = setup_working 'manifest'
|
||||
Add-Type -Path "$PSScriptRoot\..\supporting\validator\bin\Newtonsoft.Json.dll"
|
||||
Add-Type -Path "$PSScriptRoot\..\supporting\validator\bin\Newtonsoft.Json.Schema.dll"
|
||||
Add-Type -Path "$PSScriptRoot\..\supporting\validator\bin\Scoop.Validator.dll"
|
||||
}
|
||||
|
||||
It 'Scoop.Validator is available' {
|
||||
([System.Management.Automation.PSTypeName]'Scoop.Validator').Type | Should -Be 'Scoop.Validator'
|
||||
}
|
||||
|
||||
Context 'parse_json function' {
|
||||
It 'fails with invalid json' {
|
||||
{ parse_json "$working_dir\broken_wget.json" } | Should -Throw
|
||||
Describe 'Manifest validates against the schema' {
|
||||
BeforeDiscovery {
|
||||
$bucketDir = if (Test-Path "$BucketPath\bucket") {
|
||||
"$BucketPath\bucket"
|
||||
} else {
|
||||
$BucketPath
|
||||
}
|
||||
}
|
||||
|
||||
Context 'schema validation' {
|
||||
It 'fails with broken schema' {
|
||||
$validator = New-Object Scoop.Validator("$working_dir\broken_schema.json", $true)
|
||||
$validator.Validate("$working_dir\wget.json") | Should -BeFalse
|
||||
$validator.Errors.Count | Should -Be 1
|
||||
$validator.Errors | Select-Object -First 1 | Should -Match 'broken_schema.*(line 6).*(position 4)'
|
||||
}
|
||||
It 'fails with broken manifest' {
|
||||
$validator = New-Object Scoop.Validator($schema, $true)
|
||||
$validator.Validate("$working_dir\broken_wget.json") | Should -BeFalse
|
||||
$validator.Errors.Count | Should -Be 1
|
||||
$validator.Errors | Select-Object -First 1 | Should -Match 'broken_wget.*(line 5).*(position 4)'
|
||||
}
|
||||
It 'fails with invalid manifest' {
|
||||
$validator = New-Object Scoop.Validator($schema, $true)
|
||||
$validator.Validate("$working_dir\invalid_wget.json") | Should -BeFalse
|
||||
$validator.Errors.Count | Should -Be 16
|
||||
$validator.Errors | Select-Object -First 1 | Should -Match "Property 'randomproperty' has not been defined and the schema does not allow additional properties\."
|
||||
$validator.Errors | Select-Object -Last 1 | Should -Match 'Required properties are missing from object: version\.'
|
||||
}
|
||||
}
|
||||
}
|
||||
Describe 'manifest validates against the schema' -Tag 'Manifests' {
|
||||
BeforeAll {
|
||||
$schema = "$PSScriptRoot\..\schema.json"
|
||||
$changed_manifests = @()
|
||||
if ($env:CI -eq $true) {
|
||||
# AppVeyor
|
||||
$commit = if ($env:APPVEYOR_PULL_REQUEST_HEAD_COMMIT) { $env:APPVEYOR_PULL_REQUEST_HEAD_COMMIT } else { $env:APPVEYOR_REPO_COMMIT }
|
||||
|
||||
# GitHub Actions
|
||||
if ($env:GITHUB_SHA) {
|
||||
$commit = $env:GITHUB_SHA
|
||||
}
|
||||
$changed_manifests = (Get-GitChangedFile -Path $repo_dir -Include '*.json' -Commit $commit)
|
||||
Set-BuildEnvironment -Force
|
||||
$changedManifests = @(Get-GitChangedFile -Path $bucketDir -Include '*.json' -Commit $env:BHCommitHash)
|
||||
}
|
||||
$manifestFiles = (Get-ChildItem $bucketDir -Filter '*.json' -Recurse).FullName
|
||||
if ($changedManifests) {
|
||||
$manifestFiles = $manifestFiles | Where-Object { $_ -in $changedManifests }
|
||||
}
|
||||
$manifest_files = Get-ChildItem $bucketdir *.json
|
||||
$validator = New-Object Scoop.Validator($schema, $true)
|
||||
}
|
||||
|
||||
$quota_exceeded = $false
|
||||
|
||||
$manifest_files | ForEach-Object {
|
||||
$skip_manifest = ($changed_manifests -inotcontains $_.FullName)
|
||||
if ($env:CI -ne $true -or $changed_manifests -imatch 'schema.json') {
|
||||
$skip_manifest = $false
|
||||
}
|
||||
It "$_" -Skip:$skip_manifest {
|
||||
BeforeAll {
|
||||
Add-Type -Path "$PSScriptRoot\..\supporting\validator\bin\Scoop.Validator.dll"
|
||||
# Could not use backslash '\' in Linux/macOS for .NET object 'Scoop.Validator'
|
||||
$validator = New-Object Scoop.Validator("$PSScriptRoot/../schema.json", $true)
|
||||
$global:quotaExceeded = $false
|
||||
}
|
||||
It '<_>' -TestCases $manifestFiles {
|
||||
if ($global:quotaExceeded) {
|
||||
Set-ItResult -Skipped -Because 'Schema validation limit exceeded.'
|
||||
} else {
|
||||
$file = $_ # exception handling may overwrite $_
|
||||
|
||||
if (!($quota_exceeded)) {
|
||||
try {
|
||||
$validator.Validate($file.fullname)
|
||||
|
||||
if ($validator.Errors.Count -gt 0) {
|
||||
Write-Host -f red " [-] $_ has $($validator.Errors.Count) Error$(If($validator.Errors.Count -gt 1) { 's' })!"
|
||||
Write-Host -f yellow $validator.ErrorsAsString
|
||||
}
|
||||
$validator.Errors.Count | Should -Be 0
|
||||
} catch {
|
||||
if ($_.exception.message -like '*The free-quota limit of 1000 schema validations per hour has been reached.*') {
|
||||
$quota_exceeded = $true
|
||||
Write-Host -f darkyellow 'Schema validation limit exceeded. Will skip further validations.'
|
||||
} else {
|
||||
throw
|
||||
}
|
||||
try {
|
||||
$validator.Validate($file)
|
||||
if ($validator.Errors.Count -gt 0) {
|
||||
Write-Host " [-] $_ has $($validator.Errors.Count) Error$(If($validator.Errors.Count -gt 1) { 's' })!" -ForegroundColor Red
|
||||
Write-Host $validator.ErrorsAsString -ForegroundColor Yellow
|
||||
}
|
||||
$validator.Errors.Count | Should -Be 0
|
||||
} catch {
|
||||
if ($_.Exception.Message -like '*The free-quota limit of 1000 schema validations per hour has been reached.*') {
|
||||
$global:quotaExceeded = $true
|
||||
Set-ItResult -Skipped -Because 'Schema validation limit exceeded.'
|
||||
} else {
|
||||
throw
|
||||
}
|
||||
}
|
||||
|
||||
$manifest = parse_json $file.fullname
|
||||
$url = arch_specific 'url' $manifest '32bit'
|
||||
$url64 = arch_specific 'url' $manifest '64bit'
|
||||
if (!$url) {
|
||||
$url = $url64
|
||||
}
|
||||
$url | Should -Not -BeNullOrEmpty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
if ([String]::IsNullOrEmpty($MyInvocation.PSScriptRoot)) {
|
||||
Write-Error 'This script should not be called directly! It has to be imported from a buckets test file!'
|
||||
exit 1
|
||||
}
|
||||
|
||||
Describe 'Style constraints for non-binary project files' {
|
||||
|
||||
$files = @(
|
||||
# gather all files except '*.exe', '*.zip', or any .git repository files
|
||||
$repo_files |
|
||||
Where-Object { $_.fullname -inotmatch $($project_file_exclusions -join '|') } |
|
||||
Where-Object { $_.fullname -inotmatch '(.exe|.zip|.dll)$' } |
|
||||
Where-Object { $_.fullname -inotmatch '(unformated)' }
|
||||
)
|
||||
|
||||
$files_exist = ($files.Count -gt 0)
|
||||
|
||||
It $('non-binary project files exist ({0} found)' -f $files.Count) -Skip:$(-not $files_exist) {
|
||||
if (-not ($files.Count -gt 0)) {
|
||||
throw 'No non-binary project were found'
|
||||
}
|
||||
}
|
||||
|
||||
It 'files do not contain leading UTF-8 BOM' -Skip:$(-not $files_exist) {
|
||||
# UTF-8 BOM == 0xEF 0xBB 0xBF
|
||||
# see http://www.powershellmagazine.com/2012/12/17/pscxtip-how-to-determine-the-byte-order-mark-of-a-text-file @@ https://archive.is/RgT42
|
||||
# ref: http://poshcode.org/2153 @@ https://archive.is/sGnnu
|
||||
$badFiles = @(
|
||||
foreach ($file in $files) {
|
||||
if ((Get-Command Get-Content).parameters.ContainsKey('AsByteStream')) {
|
||||
# PowerShell Core (6.0+) '-Encoding byte' is replaced by '-AsByteStream'
|
||||
$content = ([char[]](Get-Content $file.FullName -AsByteStream -TotalCount 3) -join '')
|
||||
} else {
|
||||
$content = ([char[]](Get-Content $file.FullName -Encoding byte -TotalCount 3) -join '')
|
||||
}
|
||||
if ([regex]::match($content, '(?ms)^\xEF\xBB\xBF').success) {
|
||||
$file.FullName
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if ($badFiles.Count -gt 0) {
|
||||
throw "The following files have utf-8 BOM: `r`n`r`n$($badFiles -join "`r`n")"
|
||||
}
|
||||
}
|
||||
|
||||
It 'files end with a newline' -Skip:$(-not $files_exist) {
|
||||
$badFiles = @(
|
||||
foreach ($file in $files) {
|
||||
# Ignore previous TestResults.xml
|
||||
if ($file -match 'TestResults.xml') {
|
||||
continue
|
||||
}
|
||||
$string = [System.IO.File]::ReadAllText($file.FullName)
|
||||
if ($string.Length -gt 0 -and $string[-1] -ne "`n") {
|
||||
$file.FullName
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if ($badFiles.Count -gt 0) {
|
||||
throw "The following files do not end with a newline: `r`n`r`n$($badFiles -join "`r`n")"
|
||||
}
|
||||
}
|
||||
|
||||
It 'file newlines are CRLF' -Skip:$(-not $files_exist) {
|
||||
$badFiles = @(
|
||||
foreach ($file in $files) {
|
||||
$content = Get-Content -Raw $file.FullName
|
||||
if (!$content) {
|
||||
throw "File contents are null: $($file.FullName)"
|
||||
}
|
||||
$lines = [regex]::split($content, '\r\n')
|
||||
$lineCount = $lines.Count
|
||||
|
||||
for ($i = 0; $i -lt $lineCount; $i++) {
|
||||
if ( [regex]::match($lines[$i], '\r|\n').success ) {
|
||||
$file.FullName
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if ($badFiles.Count -gt 0) {
|
||||
throw "The following files have non-CRLF line endings: `r`n`r`n$($badFiles -join "`r`n")"
|
||||
}
|
||||
}
|
||||
|
||||
It 'files have no lines containing trailing whitespace' -Skip:$(-not $files_exist) {
|
||||
$badLines = @(
|
||||
foreach ($file in $files) {
|
||||
# Ignore previous TestResults.xml
|
||||
if ($file -match 'TestResults.xml') {
|
||||
continue
|
||||
}
|
||||
$lines = [System.IO.File]::ReadAllLines($file.FullName)
|
||||
$lineCount = $lines.Count
|
||||
|
||||
for ($i = 0; $i -lt $lineCount; $i++) {
|
||||
if ($lines[$i] -match '\s+$') {
|
||||
'File: {0}, Line: {1}' -f $file.FullName, ($i + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if ($badLines.Count -gt 0) {
|
||||
throw "The following $($badLines.Count) lines contain trailing whitespace: `r`n`r`n$($badLines -join "`r`n")"
|
||||
}
|
||||
}
|
||||
|
||||
It 'any leading whitespace consists only of spaces (excepting makefiles)' -Skip:$(-not $files_exist) {
|
||||
$badLines = @(
|
||||
foreach ($file in $files) {
|
||||
if ($file.fullname -inotmatch '(^|.)makefile$') {
|
||||
$lines = [System.IO.File]::ReadAllLines($file.FullName)
|
||||
$lineCount = $lines.Count
|
||||
|
||||
for ($i = 0; $i -lt $lineCount; $i++) {
|
||||
if ($lines[$i] -notmatch '^[ ]*(\S|$)') {
|
||||
'File: {0}, Line: {1}' -f $file.FullName, ($i + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if ($badLines.Count -gt 0) {
|
||||
throw "The following $($badLines.Count) lines contain TABs within leading whitespace: `r`n`r`n$($badLines -join "`r`n")"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
189
test/Scoop-00File.Tests.ps1
Normal file
189
test/Scoop-00File.Tests.ps1
Normal file
@@ -0,0 +1,189 @@
|
||||
param(
|
||||
[String] $TestPath = "$PSScriptRoot\.."
|
||||
)
|
||||
|
||||
BeforeDiscovery {
|
||||
$project_file_exclusions = @(
|
||||
'[\\/]\.git[\\/]',
|
||||
'\.sublime-workspace$',
|
||||
'\.DS_Store$',
|
||||
'supporting(\\|/)validator(\\|/)packages(\\|/)*',
|
||||
'supporting(\\|/)shimexe(\\|/)packages(\\|/)*'
|
||||
)
|
||||
$repo_files = (Get-ChildItem $TestPath -File -Recurse).FullName |
|
||||
Where-Object { $_ -inotmatch $($project_file_exclusions -join '|') }
|
||||
}
|
||||
|
||||
Describe 'Code Syntax' -ForEach @(, $repo_files) -Tag 'File' {
|
||||
BeforeAll {
|
||||
$files = @(
|
||||
$_ | Where-Object { $_ -imatch '.(ps1|psm1)$' }
|
||||
)
|
||||
function Test-PowerShellSyntax {
|
||||
# ref: http://powershell.org/wp/forums/topic/how-to-check-syntax-of-scripts-automatically @@ https://archive.is/xtSv6
|
||||
# originally created by Alexander Petrovskiy & Dave Wyatt
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
|
||||
[string[]]
|
||||
$Path
|
||||
)
|
||||
|
||||
process {
|
||||
foreach ($scriptPath in $Path) {
|
||||
$contents = Get-Content -Path $scriptPath
|
||||
|
||||
if ($null -eq $contents) {
|
||||
continue
|
||||
}
|
||||
|
||||
$errors = $null
|
||||
$null = [System.Management.Automation.PSParser]::Tokenize($contents, [ref]$errors)
|
||||
|
||||
New-Object psobject -Property @{
|
||||
Path = $scriptPath
|
||||
SyntaxErrorsFound = ($errors.Count -gt 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
It 'PowerShell code files do not contain syntax errors' {
|
||||
$badFiles = @(
|
||||
foreach ($file in $files) {
|
||||
if ( (Test-PowerShellSyntax $file).SyntaxErrorsFound ) {
|
||||
$file
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if ($badFiles.Count -gt 0) {
|
||||
throw "The following files have syntax errors: `r`n`r`n$($badFiles -join "`r`n")"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Describe 'Style constraints for non-binary project files' -ForEach @(, $repo_files) -Tag 'File' {
|
||||
BeforeAll {
|
||||
$files = @(
|
||||
# gather all files except '*.exe', '*.zip', or any .git repository files
|
||||
$_ |
|
||||
Where-Object { $_ -inotmatch '(.exe|.zip|.dll)$' } |
|
||||
Where-Object { $_ -inotmatch '(unformatted)' }
|
||||
)
|
||||
}
|
||||
|
||||
It 'files do not contain leading UTF-8 BOM' {
|
||||
# UTF-8 BOM == 0xEF 0xBB 0xBF
|
||||
# see http://www.powershellmagazine.com/2012/12/17/pscxtip-how-to-determine-the-byte-order-mark-of-a-text-file @@ https://archive.is/RgT42
|
||||
# ref: http://poshcode.org/2153 @@ https://archive.is/sGnnu
|
||||
$badFiles = @(
|
||||
foreach ($file in $files) {
|
||||
if ((Get-Command Get-Content).parameters.ContainsKey('AsByteStream')) {
|
||||
# PowerShell Core (6.0+) '-Encoding byte' is replaced by '-AsByteStream'
|
||||
$content = ([char[]](Get-Content $file -AsByteStream -TotalCount 3) -join '')
|
||||
} else {
|
||||
$content = ([char[]](Get-Content $file -Encoding byte -TotalCount 3) -join '')
|
||||
}
|
||||
if ([regex]::match($content, '(?ms)^\xEF\xBB\xBF').success) {
|
||||
$file
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if ($badFiles.Count -gt 0) {
|
||||
throw "The following files have utf-8 BOM: `r`n`r`n$($badFiles -join "`r`n")"
|
||||
}
|
||||
}
|
||||
|
||||
It 'files end with a newline' {
|
||||
$badFiles = @(
|
||||
foreach ($file in $files) {
|
||||
# Ignore previous TestResults.xml
|
||||
if ($file -match 'TestResults.xml') {
|
||||
continue
|
||||
}
|
||||
$string = [System.IO.File]::ReadAllText($file)
|
||||
if ($string.Length -gt 0 -and $string[-1] -ne "`n") {
|
||||
$file
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if ($badFiles.Count -gt 0) {
|
||||
throw "The following files do not end with a newline: `r`n`r`n$($badFiles -join "`r`n")"
|
||||
}
|
||||
}
|
||||
|
||||
It 'file newlines are CRLF' {
|
||||
$badFiles = @(
|
||||
foreach ($file in $files) {
|
||||
$content = [System.IO.File]::ReadAllText($file)
|
||||
if (!$content) {
|
||||
throw "File contents are null: $($file)"
|
||||
}
|
||||
$lines = [regex]::split($content, '\r\n')
|
||||
$lineCount = $lines.Count
|
||||
|
||||
for ($i = 0; $i -lt $lineCount; $i++) {
|
||||
if ( [regex]::match($lines[$i], '\r|\n').success ) {
|
||||
$file
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if ($badFiles.Count -gt 0) {
|
||||
throw "The following files have non-CRLF line endings: `r`n`r`n$($badFiles -join "`r`n")"
|
||||
}
|
||||
}
|
||||
|
||||
It 'files have no lines containing trailing whitespace' {
|
||||
$badLines = @(
|
||||
foreach ($file in $files) {
|
||||
# Ignore previous TestResults.xml
|
||||
if ($file -match 'TestResults.xml') {
|
||||
continue
|
||||
}
|
||||
$lines = [System.IO.File]::ReadAllLines($file)
|
||||
$lineCount = $lines.Count
|
||||
|
||||
for ($i = 0; $i -lt $lineCount; $i++) {
|
||||
if ($lines[$i] -match '\s+$') {
|
||||
'File: {0}, Line: {1}' -f $file, ($i + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if ($badLines.Count -gt 0) {
|
||||
throw "The following $($badLines.Count) lines contain trailing whitespace: `r`n`r`n$($badLines -join "`r`n")"
|
||||
}
|
||||
}
|
||||
|
||||
It 'any leading whitespace consists only of spaces (excepting makefiles)' {
|
||||
$badLines = @(
|
||||
foreach ($file in $files) {
|
||||
if ($file -inotmatch '(^|.)makefile$') {
|
||||
$lines = [System.IO.File]::ReadAllLines($file)
|
||||
$lineCount = $lines.Count
|
||||
|
||||
for ($i = 0; $i -lt $lineCount; $i++) {
|
||||
if ($lines[$i] -notmatch '^[ ]*(\S|$)') {
|
||||
'File: {0}, Line: {1}' -f $file, ($i + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if ($badLines.Count -gt 0) {
|
||||
throw "The following $($badLines.Count) lines contain TABs within leading whitespace: `r`n`r`n$($badLines -join "`r`n")"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
33
test/Scoop-00Linting.Tests.ps1
Normal file
33
test/Scoop-00Linting.Tests.ps1
Normal file
@@ -0,0 +1,33 @@
|
||||
Describe 'PSScriptAnalyzer' -Tag 'Linter' {
|
||||
BeforeDiscovery {
|
||||
$scriptDir = @('.', 'bin', 'lib', 'libexec', 'test')
|
||||
}
|
||||
|
||||
BeforeAll {
|
||||
$lintSettings = "$PSScriptRoot\..\PSScriptAnalyzerSettings.psd1"
|
||||
}
|
||||
|
||||
It 'PSScriptAnalyzerSettings.ps1 should exist' {
|
||||
$lintSettings | Should -Exist
|
||||
}
|
||||
|
||||
Context 'Linting all *.psd1, *.psm1 and *.ps1 files' {
|
||||
BeforeEach {
|
||||
$analysis = Invoke-ScriptAnalyzer -Path "$PSScriptRoot\..\$_" -Settings $lintSettings
|
||||
}
|
||||
It 'Should pass: <_>' -TestCases $scriptDir {
|
||||
$analysis | Should -HaveCount 0
|
||||
if ($analysis) {
|
||||
foreach ($result in $analysis) {
|
||||
switch -wildCard ($result.ScriptName) {
|
||||
'*.psm1' { $type = 'Module' }
|
||||
'*.ps1' { $type = 'Script' }
|
||||
'*.psd1' { $type = 'Manifest' }
|
||||
}
|
||||
Write-Warning " [*] $($result.Severity): $($result.Message)"
|
||||
Write-Warning " $($result.RuleName) in $type`: $directory\$($result.ScriptName):$($result.Line)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,56 +1,45 @@
|
||||
. "$PSScriptRoot\Scoop-TestLib.ps1"
|
||||
. "$PSScriptRoot\..\lib\core.ps1"
|
||||
. "$PSScriptRoot\..\lib\help.ps1"
|
||||
. "$PSScriptRoot\..\libexec\scoop-alias.ps1" | Out-Null
|
||||
|
||||
Describe 'add_alias' -Tag 'Scoop' {
|
||||
Mock shimdir { "$env:TEMP\shims" }
|
||||
Mock set_config { }
|
||||
Mock get_config { @{} }
|
||||
|
||||
$shimdir = shimdir
|
||||
ensure $shimdir
|
||||
|
||||
Context "alias doesn't exist" {
|
||||
It 'creates a new alias' {
|
||||
$alias_file = "$shimdir\scoop-rm.ps1"
|
||||
$alias_file | Should -Not -Exist
|
||||
|
||||
add_alias 'rm' '"hello, world!"'
|
||||
& $alias_file | Should -Be 'hello, world!'
|
||||
}
|
||||
}
|
||||
|
||||
Context 'alias exists' {
|
||||
It 'does not change existing alias' {
|
||||
$alias_file = "$shimdir\scoop-rm.ps1"
|
||||
New-Item $alias_file -Type File -Force
|
||||
$alias_file | Should -Exist
|
||||
|
||||
add_alias 'rm' 'test'
|
||||
$alias_file | Should -FileContentMatch ''
|
||||
}
|
||||
}
|
||||
BeforeAll {
|
||||
. "$PSScriptRoot\Scoop-TestLib.ps1"
|
||||
. "$PSScriptRoot\..\lib\core.ps1"
|
||||
. "$PSScriptRoot\..\lib\help.ps1"
|
||||
. "$PSScriptRoot\..\libexec\scoop-alias.ps1" | Out-Null
|
||||
}
|
||||
|
||||
Describe 'rm_alias' -Tag 'Scoop' {
|
||||
Mock shimdir { "$env:TEMP\shims" }
|
||||
Mock set_config { }
|
||||
Mock get_config { @{} }
|
||||
Describe 'Manipulate Alias' -Tag 'Scoop' {
|
||||
BeforeAll {
|
||||
Mock shimdir { "$TestDrive\shims" }
|
||||
Mock set_config { }
|
||||
Mock get_config { @{} }
|
||||
|
||||
$shimdir = shimdir
|
||||
ensure $shimdir
|
||||
$shimdir = shimdir
|
||||
ensure $shimdir
|
||||
}
|
||||
|
||||
Context 'alias exists' {
|
||||
It 'removes an existing alias' {
|
||||
$alias_file = "$shimdir\scoop-rm.ps1"
|
||||
add_alias 'rm' '"hello, world!"'
|
||||
It 'Creates a new alias if alias doesn''t exist' {
|
||||
$alias_file = "$shimdir\scoop-rm.ps1"
|
||||
$alias_file | Should -Not -Exist
|
||||
|
||||
$alias_file | Should -Exist
|
||||
Mock get_config { @(@{'rm' = 'scoop-rm' }) }
|
||||
add_alias 'rm' '"hello, world!"'
|
||||
& $alias_file | Should -Be 'hello, world!'
|
||||
}
|
||||
|
||||
rm_alias 'rm'
|
||||
$alias_file | Should -Not -Exist
|
||||
}
|
||||
It 'Does not change existing alias if alias exists' {
|
||||
$alias_file = "$shimdir\scoop-rm.ps1"
|
||||
New-Item $alias_file -Type File -Force
|
||||
$alias_file | Should -Exist
|
||||
|
||||
add_alias 'rm' 'test'
|
||||
& $alias_file | Should -Not -Be 'test'
|
||||
}
|
||||
|
||||
It 'Removes an existing alias' {
|
||||
$alias_file = "$shimdir\scoop-rm.ps1"
|
||||
add_alias 'rm' '"hello, world!"'
|
||||
|
||||
$alias_file | Should -Exist
|
||||
Mock get_config { @(@{'rm' = 'scoop-rm' }) }
|
||||
|
||||
rm_alias 'rm'
|
||||
$alias_file | Should -Not -Exist
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
. "$PSScriptRoot\Scoop-TestLib.ps1"
|
||||
. "$PSScriptRoot\..\lib\core.ps1"
|
||||
BeforeAll {
|
||||
. "$PSScriptRoot\Scoop-TestLib.ps1"
|
||||
. "$PSScriptRoot\..\lib\core.ps1"
|
||||
}
|
||||
|
||||
Describe 'config' -Tag 'Scoop' {
|
||||
BeforeAll {
|
||||
$configFile = "$env:TEMP\ScoopTestFixtures\config.json"
|
||||
if (Test-Path $configFile) {
|
||||
Remove-Item -Path $configFile -Force
|
||||
}
|
||||
$configFile = [IO.Path]::GetTempFileName()
|
||||
$unicode = [Regex]::Unescape('\u4f60\u597d\u3053\u3093\u306b\u3061\u306f') # 你好こんにちは
|
||||
}
|
||||
|
||||
BeforeEach {
|
||||
$scoopConfig = $null
|
||||
AfterAll {
|
||||
Remove-Item -Path $configFile -Force
|
||||
}
|
||||
|
||||
It 'load_cfg should return null if config file does not exist' {
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
. "$PSScriptRoot\Scoop-TestLib.ps1"
|
||||
. "$PSScriptRoot\..\lib\core.ps1"
|
||||
. "$PSScriptRoot\..\lib\install.ps1"
|
||||
. "$PSScriptRoot\..\lib\unix.ps1"
|
||||
|
||||
$repo_dir = (Get-Item $MyInvocation.MyCommand.Path).directory.parent.FullName
|
||||
$isUnix = is_unix
|
||||
BeforeAll {
|
||||
. "$PSScriptRoot\Scoop-TestLib.ps1"
|
||||
. "$PSScriptRoot\..\lib\core.ps1"
|
||||
. "$PSScriptRoot\..\lib\install.ps1"
|
||||
}
|
||||
|
||||
Describe 'Get-AppFilePath' -Tag 'Scoop' {
|
||||
BeforeAll {
|
||||
@@ -128,15 +126,14 @@ Describe 'is_directory' -Tag 'Scoop' {
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'movedir' -Tag 'Scoop' {
|
||||
$extract_dir = 'subdir'
|
||||
$extract_to = $null
|
||||
|
||||
Describe 'movedir' -Tag 'Scoop', 'Windows' {
|
||||
BeforeAll {
|
||||
$working_dir = setup_working 'movedir'
|
||||
$extract_dir = 'subdir'
|
||||
$extract_to = $null
|
||||
}
|
||||
|
||||
It 'moves directories with no spaces in path' -Skip:$isUnix {
|
||||
It 'moves directories with no spaces in path' {
|
||||
$dir = "$working_dir\user"
|
||||
movedir "$dir\_tmp\$extract_dir" "$dir\$extract_to"
|
||||
|
||||
@@ -144,7 +141,7 @@ Describe 'movedir' -Tag 'Scoop' {
|
||||
"$dir\_tmp\$extract_dir" | Should -Not -Exist
|
||||
}
|
||||
|
||||
It 'moves directories with spaces in path' -Skip:$isUnix {
|
||||
It 'moves directories with spaces in path' {
|
||||
$dir = "$working_dir\user with space"
|
||||
movedir "$dir\_tmp\$extract_dir" "$dir\$extract_to"
|
||||
|
||||
@@ -157,7 +154,7 @@ Describe 'movedir' -Tag 'Scoop' {
|
||||
"$dir\_tmp" | Should -Not -Exist
|
||||
}
|
||||
|
||||
It 'moves directories with quotes in path' -Skip:$isUnix {
|
||||
It 'moves directories with quotes in path' {
|
||||
$dir = "$working_dir\user with 'quote"
|
||||
movedir "$dir\_tmp\$extract_dir" "$dir\$extract_to"
|
||||
|
||||
@@ -166,14 +163,14 @@ Describe 'movedir' -Tag 'Scoop' {
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'shim' -Tag 'Scoop' {
|
||||
Describe 'shim' -Tag 'Scoop', 'Windows' {
|
||||
BeforeAll {
|
||||
$working_dir = setup_working 'shim'
|
||||
$shimdir = shimdir
|
||||
$(ensure_in_path $shimdir) | Out-Null
|
||||
}
|
||||
|
||||
It "links a file onto the user's path" -Skip:$isUnix {
|
||||
It "links a file onto the user's path" {
|
||||
{ Get-Command 'shim-test' -ea stop } | Should -Throw
|
||||
{ Get-Command 'shim-test.ps1' -ea stop } | Should -Throw
|
||||
{ Get-Command 'shim-test.cmd' -ea stop } | Should -Throw
|
||||
@@ -186,15 +183,13 @@ Describe 'shim' -Tag 'Scoop' {
|
||||
shim-test | Should -Be 'Hello, world!'
|
||||
}
|
||||
|
||||
Context 'user with quote' {
|
||||
It 'shims a file with quote in path' -Skip:$isUnix {
|
||||
{ Get-Command 'shim-test' -ea stop } | Should -Throw
|
||||
{ shim-test } | Should -Throw
|
||||
It 'shims a file with quote in path' {
|
||||
{ Get-Command 'shim-test' -ea stop } | Should -Throw
|
||||
{ shim-test } | Should -Throw
|
||||
|
||||
shim "$working_dir\user with 'quote\shim-test.ps1" $false 'shim-test'
|
||||
{ Get-Command 'shim-test' -ea stop } | Should -Not -Throw
|
||||
shim-test | Should -Be 'Hello, world!'
|
||||
}
|
||||
shim "$working_dir\user with 'quote\shim-test.ps1" $false 'shim-test'
|
||||
{ Get-Command 'shim-test' -ea stop } | Should -Not -Throw
|
||||
shim-test | Should -Be 'Hello, world!'
|
||||
}
|
||||
|
||||
AfterEach {
|
||||
@@ -202,14 +197,14 @@ Describe 'shim' -Tag 'Scoop' {
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'rm_shim' -Tag 'Scoop' {
|
||||
Describe 'rm_shim' -Tag 'Scoop', 'Windows' {
|
||||
BeforeAll {
|
||||
$working_dir = setup_working 'shim'
|
||||
$shimdir = shimdir
|
||||
$(ensure_in_path $shimdir) | Out-Null
|
||||
}
|
||||
|
||||
It 'removes shim from path' -Skip:$isUnix {
|
||||
It 'removes shim from path' {
|
||||
shim "$working_dir\shim-test.ps1" $false 'shim-test'
|
||||
|
||||
rm_shim 'shim-test' $shimdir
|
||||
@@ -221,7 +216,7 @@ Describe 'rm_shim' -Tag 'Scoop' {
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'get_app_name_from_shim' -Tag 'Scoop' {
|
||||
Describe 'get_app_name_from_shim' -Tag 'Scoop', 'Windows' {
|
||||
BeforeAll {
|
||||
$working_dir = setup_working 'shim'
|
||||
$shimdir = shimdir
|
||||
@@ -229,11 +224,11 @@ Describe 'get_app_name_from_shim' -Tag 'Scoop' {
|
||||
Mock appsdir { $working_dir }
|
||||
}
|
||||
|
||||
It 'returns empty string if file does not exist' -Skip:$isUnix {
|
||||
It 'returns empty string if file does not exist' {
|
||||
get_app_name_from_shim 'non-existent-file' | Should -Be ''
|
||||
}
|
||||
|
||||
It 'returns app name if file exists and is a shim to an app' -Skip:$isUnix {
|
||||
It 'returns app name if file exists and is a shim to an app' {
|
||||
ensure "$working_dir/mockapp/current/"
|
||||
Write-Output '' | Out-File "$working_dir/mockapp/current/mockapp1.ps1"
|
||||
shim "$working_dir/mockapp/current/mockapp1.ps1" $false 'shim-test1'
|
||||
@@ -246,7 +241,7 @@ Describe 'get_app_name_from_shim' -Tag 'Scoop' {
|
||||
get_app_name_from_shim "$shim_path2" | Should -Be 'mockapp'
|
||||
}
|
||||
|
||||
It 'returns empty string if file exists and is not a shim' -Skip:$isUnix {
|
||||
It 'returns empty string if file exists and is not a shim' {
|
||||
Write-Output 'lorem ipsum' | Out-File -Encoding ascii "$working_dir/mock-shim.ps1"
|
||||
get_app_name_from_shim "$working_dir/mock-shim.ps1" | Should -Be ''
|
||||
}
|
||||
@@ -263,35 +258,33 @@ Describe 'get_app_name_from_shim' -Tag 'Scoop' {
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'ensure_robocopy_in_path' -Tag 'Scoop' {
|
||||
$shimdir = shimdir $false
|
||||
Mock versiondir { $repo_dir }
|
||||
|
||||
Context 'robocopy is not in path' {
|
||||
It 'shims robocopy when not on path' -Skip:$isUnix {
|
||||
Mock Test-CommandAvailable { $false }
|
||||
Test-CommandAvailable robocopy | Should -Be $false
|
||||
|
||||
ensure_robocopy_in_path
|
||||
|
||||
# "$shimdir/robocopy.ps1" | should -exist
|
||||
"$shimdir/robocopy.exe" | Should -Exist
|
||||
|
||||
# clean up
|
||||
rm_shim robocopy $(shimdir $false) | Out-Null
|
||||
}
|
||||
Describe 'ensure_robocopy_in_path' -Tag 'Scoop', 'Windows' {
|
||||
BeforeAll {
|
||||
$shimdir = shimdir $false
|
||||
Mock versiondir { "$PSScriptRoot\.." }
|
||||
}
|
||||
|
||||
Context 'robocopy is in path' {
|
||||
It 'does not shim robocopy when it is in path' -Skip:$isUnix {
|
||||
Mock Test-CommandAvailable { $true }
|
||||
Test-CommandAvailable robocopy | Should -Be $true
|
||||
It 'shims robocopy when not on path' {
|
||||
Mock Test-CommandAvailable { $false }
|
||||
Test-CommandAvailable robocopy | Should -Be $false
|
||||
|
||||
ensure_robocopy_in_path
|
||||
ensure_robocopy_in_path
|
||||
|
||||
# "$shimdir/robocopy.ps1" | should -not -exist
|
||||
"$shimdir/robocopy.exe" | Should -Not -Exist
|
||||
}
|
||||
# "$shimdir/robocopy.ps1" | should -exist
|
||||
"$shimdir/robocopy.exe" | Should -Exist
|
||||
|
||||
# clean up
|
||||
rm_shim robocopy $(shimdir $false) | Out-Null
|
||||
}
|
||||
|
||||
It 'does not shim robocopy when it is in path' {
|
||||
Mock Test-CommandAvailable { $true }
|
||||
Test-CommandAvailable robocopy | Should -Be $true
|
||||
|
||||
ensure_robocopy_in_path
|
||||
|
||||
# "$shimdir/robocopy.ps1" | should -not -exist
|
||||
"$shimdir/robocopy.exe" | Should -Not -Exist
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,3 +390,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'"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
. "$PSScriptRoot\Scoop-TestLib.ps1"
|
||||
. "$PSScriptRoot\..\lib\core.ps1"
|
||||
. "$PSScriptRoot\..\lib\decompress.ps1"
|
||||
. "$PSScriptRoot\..\lib\install.ps1"
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1"
|
||||
. "$PSScriptRoot\..\lib\versions.ps1"
|
||||
. "$PSScriptRoot\..\lib\unix.ps1"
|
||||
BeforeAll {
|
||||
. "$PSScriptRoot\Scoop-TestLib.ps1"
|
||||
. "$PSScriptRoot\..\lib\core.ps1"
|
||||
. "$PSScriptRoot\..\lib\decompress.ps1"
|
||||
. "$PSScriptRoot\..\lib\install.ps1"
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1"
|
||||
. "$PSScriptRoot\..\lib\versions.ps1"
|
||||
}
|
||||
|
||||
$isUnix = is_unix
|
||||
|
||||
Describe 'Decompression function' -Tag 'Scoop', 'Decompress' {
|
||||
Describe 'Decompression function' -Tag 'Scoop', 'Windows', 'Decompress' {
|
||||
|
||||
BeforeAll {
|
||||
$working_dir = setup_working 'decompress'
|
||||
@@ -19,13 +18,17 @@ Describe 'Decompression function' -Tag 'Scoop', 'Decompress' {
|
||||
return $to
|
||||
}
|
||||
|
||||
It 'Decompression test cases should exist' {
|
||||
}
|
||||
Context 'Decompression test cases should exist' {
|
||||
BeforeAll {
|
||||
$testcases = "$working_dir\TestCases.zip"
|
||||
}
|
||||
It 'Test cases should exist and hash should match' {
|
||||
$testcases | Should -Exist
|
||||
compute_hash $testcases 'sha256' | Should -Be '16507166814dbd02be80c14b737eb6b0245c47439ca3ed308b5625d64babecc8'
|
||||
if (!$isUnix) {
|
||||
Microsoft.PowerShell.Archive\Expand-Archive $testcases $working_dir
|
||||
}
|
||||
(Get-FileHash -Path $testcases -Algorithm SHA256).Hash.ToLower() | Should -Be '791bfce192917a2ff225dcdd87d23ae5f720b20178d85e68e4b1b56139cf8e6a'
|
||||
}
|
||||
It 'Test cases should be extracted correctly' {
|
||||
{ Microsoft.PowerShell.Archive\Expand-Archive -Path $testcases -DestinationPath $working_dir } | Should -Not -Throw
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,16 +47,19 @@ Describe 'Decompression function' -Tag 'Scoop', 'Decompress' {
|
||||
$test5_1 = "$working_dir\7ZipTest5.7z.001"
|
||||
$test5_2 = "$working_dir\7ZipTest5.7z.002"
|
||||
$test5_3 = "$working_dir\7ZipTest5.7z.003"
|
||||
$test6_1 = "$working_dir\7ZipTest6.part01.rar"
|
||||
$test6_2 = "$working_dir\7ZipTest6.part02.rar"
|
||||
$test6_3 = "$working_dir\7ZipTest6.part03.rar"
|
||||
}
|
||||
|
||||
It 'extract normal compressed file' -Skip:$isUnix {
|
||||
It 'extract normal compressed file' {
|
||||
$to = test_extract 'Expand-7zipArchive' $test1
|
||||
$to | Should -Exist
|
||||
"$to\empty" | Should -Exist
|
||||
(Get-ChildItem $to).Count | Should -Be 1
|
||||
}
|
||||
|
||||
It 'extract nested compressed file' -Skip:$isUnix {
|
||||
It 'extract nested compressed file' {
|
||||
# file ext: tgz
|
||||
$to = test_extract 'Expand-7zipArchive' $test2
|
||||
$to | Should -Exist
|
||||
@@ -67,21 +73,28 @@ Describe 'Decompression function' -Tag 'Scoop', 'Decompress' {
|
||||
(Get-ChildItem $to).Count | Should -Be 1
|
||||
}
|
||||
|
||||
It 'extract nested compressed file with different inner name' -Skip:$isUnix {
|
||||
It 'extract nested compressed file with different inner name' {
|
||||
$to = test_extract 'Expand-7zipArchive' $test4
|
||||
$to | Should -Exist
|
||||
"$to\empty" | Should -Exist
|
||||
(Get-ChildItem $to).Count | Should -Be 1
|
||||
}
|
||||
|
||||
It 'extract splited 7z archives (.001, .002, ...)' -Skip:$isUnix {
|
||||
It 'extract splited 7z archives (.001, .002, ...)' {
|
||||
$to = test_extract 'Expand-7zipArchive' $test5_1
|
||||
$to | Should -Exist
|
||||
"$to\empty" | Should -Exist
|
||||
(Get-ChildItem $to).Count | Should -Be 1
|
||||
}
|
||||
|
||||
It 'works with "-Removal" switch ($removal param)' -Skip:$isUnix {
|
||||
It 'extract splited RAR archives (.part01.rar, .part02.rar, ...)' {
|
||||
$to = test_extract 'Expand-7zipArchive' $test6_1
|
||||
$to | Should -Exist
|
||||
"$to\dummy" | Should -Exist
|
||||
(Get-ChildItem $to).Count | Should -Be 1
|
||||
}
|
||||
|
||||
It 'works with "-Removal" switch ($removal param)' {
|
||||
$test1 | Should -Exist
|
||||
test_extract 'Expand-7zipArchive' $test1 $true
|
||||
$test1 | Should -Not -Exist
|
||||
@@ -92,6 +105,13 @@ Describe 'Decompression function' -Tag 'Scoop', 'Decompress' {
|
||||
$test5_1 | Should -Not -Exist
|
||||
$test5_2 | Should -Not -Exist
|
||||
$test5_3 | Should -Not -Exist
|
||||
$test6_1 | Should -Exist
|
||||
$test6_2 | Should -Exist
|
||||
$test6_3 | Should -Exist
|
||||
test_extract 'Expand-7zipArchive' $test6_1 $true
|
||||
$test6_1 | Should -Not -Exist
|
||||
$test6_2 | Should -Not -Exist
|
||||
$test6_3 | Should -Not -Exist
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,21 +129,21 @@ Describe 'Decompression function' -Tag 'Scoop', 'Decompress' {
|
||||
$test2 = "$working_dir\ZstdTest.tar.zst"
|
||||
}
|
||||
|
||||
It 'extract normal compressed file' -Skip:$isUnix {
|
||||
It 'extract normal compressed file' {
|
||||
$to = test_extract 'Expand-ZstdArchive' $test1
|
||||
$to | Should -Exist
|
||||
"$to\ZstdTest" | Should -Exist
|
||||
(Get-ChildItem $to).Count | Should -Be 1
|
||||
}
|
||||
|
||||
It 'extract nested compressed file' -Skip:$isUnix {
|
||||
It 'extract nested compressed file' {
|
||||
$to = test_extract 'Expand-ZstdArchive' $test2
|
||||
$to | Should -Exist
|
||||
"$to\ZstdTest" | Should -Exist
|
||||
(Get-ChildItem $to).Count | Should -Be 1
|
||||
}
|
||||
|
||||
It 'works with "-Removal" switch ($removal param)' -Skip:$isUnix {
|
||||
It 'works with "-Removal" switch ($removal param)' {
|
||||
$test1 | Should -Exist
|
||||
test_extract 'Expand-ZstdArchive' $test1 $true
|
||||
$test1 | Should -Not -Exist
|
||||
@@ -142,7 +162,7 @@ Describe 'Decompression function' -Tag 'Scoop', 'Decompress' {
|
||||
$test2 = "$working_dir\MSITestNull.msi"
|
||||
}
|
||||
|
||||
It 'extract normal MSI file' -Skip:$isUnix {
|
||||
It 'extract normal MSI file' {
|
||||
Mock get_config { $false }
|
||||
$to = test_extract 'Expand-MsiArchive' $test1
|
||||
$to | Should -Exist
|
||||
@@ -150,13 +170,13 @@ Describe 'Decompression function' -Tag 'Scoop', 'Decompress' {
|
||||
(Get-ChildItem "$to\MSITest").Count | Should -Be 1
|
||||
}
|
||||
|
||||
It 'extract empty MSI file using lessmsi' -Skip:$isUnix {
|
||||
It 'extract empty MSI file using lessmsi' {
|
||||
Mock get_config { $true }
|
||||
$to = test_extract 'Expand-MsiArchive' $test2
|
||||
$to | Should -Exist
|
||||
}
|
||||
|
||||
It 'works with "-Removal" switch ($removal param)' -Skip:$isUnix {
|
||||
It 'works with "-Removal" switch ($removal param)' {
|
||||
Mock get_config { $false }
|
||||
$test1 | Should -Exist
|
||||
test_extract 'Expand-MsiArchive' $test1 $true
|
||||
@@ -175,14 +195,14 @@ Describe 'Decompression function' -Tag 'Scoop', 'Decompress' {
|
||||
$test = "$working_dir\InnoTest.exe"
|
||||
}
|
||||
|
||||
It 'extract Inno Setup file' -Skip:$isUnix {
|
||||
It 'extract Inno Setup file' {
|
||||
$to = test_extract 'Expand-InnoArchive' $test
|
||||
$to | Should -Exist
|
||||
"$to\empty" | Should -Exist
|
||||
(Get-ChildItem $to).Count | Should -Be 1
|
||||
}
|
||||
|
||||
It 'works with "-Removal" switch ($removal param)' -Skip:$isUnix {
|
||||
It 'works with "-Removal" switch ($removal param)' {
|
||||
$test | Should -Exist
|
||||
test_extract 'Expand-InnoArchive' $test $true
|
||||
$test | Should -Not -Exist
|
||||
@@ -195,14 +215,14 @@ Describe 'Decompression function' -Tag 'Scoop', 'Decompress' {
|
||||
$test = "$working_dir\ZipTest.zip"
|
||||
}
|
||||
|
||||
It 'extract compressed file' -Skip:$isUnix {
|
||||
It 'extract compressed file' {
|
||||
$to = test_extract 'Expand-ZipArchive' $test
|
||||
$to | Should -Exist
|
||||
"$to\empty" | Should -Exist
|
||||
(Get-ChildItem $to).Count | Should -Be 1
|
||||
}
|
||||
|
||||
It 'works with "-Removal" switch ($removal param)' -Skip:$isUnix {
|
||||
It 'works with "-Removal" switch ($removal param)' {
|
||||
$test | Should -Exist
|
||||
test_extract 'Expand-ZipArchive' $test $true
|
||||
$test | Should -Not -Exist
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
. "$PSScriptRoot\Scoop-TestLib.ps1"
|
||||
. "$PSScriptRoot\..\lib\core.ps1"
|
||||
. "$PSScriptRoot\..\lib\depends.ps1"
|
||||
. "$PSScriptRoot\..\lib\buckets.ps1"
|
||||
. "$PSScriptRoot\..\lib\install.ps1"
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1"
|
||||
BeforeAll {
|
||||
. "$PSScriptRoot\Scoop-TestLib.ps1"
|
||||
. "$PSScriptRoot\..\lib\core.ps1"
|
||||
. "$PSScriptRoot\..\lib\depends.ps1"
|
||||
. "$PSScriptRoot\..\lib\buckets.ps1"
|
||||
. "$PSScriptRoot\..\lib\install.ps1"
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1"
|
||||
}
|
||||
|
||||
Describe 'Package Dependencies' -Tag 'Scoop' {
|
||||
Context 'Requirement function' {
|
||||
@@ -32,7 +34,7 @@ Describe 'Package Dependencies' -Tag 'Scoop' {
|
||||
|
||||
Context 'InstallationHelper function' {
|
||||
BeforeAll {
|
||||
$working_dir = setup_working 'format/formated'
|
||||
$working_dir = setup_working 'format/formatted'
|
||||
$manifest1 = parse_json (Join-Path $working_dir '3-array-with-single-and-multi.json')
|
||||
$manifest2 = parse_json (Join-Path $working_dir '4-script-block.json')
|
||||
Mock Test-HelperInstalled { $false }
|
||||
@@ -46,14 +48,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 +70,7 @@ Describe 'Package Dependencies' -Tag 'Scoop' {
|
||||
Context 'Dependencies resolution' {
|
||||
BeforeAll {
|
||||
Mock Test-HelperInstalled { $false }
|
||||
Mock get_config { $true } -ParameterFilter { $name -eq 'MSIEXTRACT_USE_LESSMSI' }
|
||||
Mock get_config { $true } -ParameterFilter { $name -eq 'USE_LESSMSI' }
|
||||
Mock Get-Manifest { 'lessmsi', @{}, $null, $null } -ParameterFilter { $app -eq 'lessmsi' }
|
||||
Mock Get-Manifest { '7zip', @{ url = 'test.msi' }, $null, $null } -ParameterFilter { $app -eq '7zip' }
|
||||
Mock Get-Manifest { 'innounp', @{}, $null, $null } -ParameterFilter { $app -eq 'innounp' }
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
. "$PSScriptRoot\Scoop-TestLib.ps1"
|
||||
. "$PSScriptRoot\..\lib\json.ps1"
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1"
|
||||
|
||||
Describe 'Pretty json formating' -Tag 'Scoop' {
|
||||
BeforeAll {
|
||||
$format = "$PSScriptRoot\fixtures\format"
|
||||
$manifests = Get-ChildItem "$format\formated" -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\unformated\$_") | ConvertToPrettyJson
|
||||
$correct = (Get-Content "$format\formated\$_") -join "`r`n"
|
||||
$correct.CompareTo($pretty_json) | Should -Be 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
. "$PSScriptRoot\Scoop-TestLib.ps1"
|
||||
. "$PSScriptRoot\..\lib\getopt.ps1"
|
||||
BeforeAll {
|
||||
. "$PSScriptRoot\Scoop-TestLib.ps1"
|
||||
. "$PSScriptRoot\..\lib\getopt.ps1"
|
||||
}
|
||||
|
||||
Describe 'getopt' -Tag 'Scoop' {
|
||||
It 'handle short option with required argument missing' {
|
||||
@@ -68,4 +70,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'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +1,8 @@
|
||||
. "$PSScriptRoot\Scoop-TestLib.ps1"
|
||||
. "$PSScriptRoot\..\lib\core.ps1"
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1"
|
||||
. "$PSScriptRoot\..\lib\install.ps1"
|
||||
. "$PSScriptRoot\..\lib\unix.ps1"
|
||||
|
||||
$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'"
|
||||
}
|
||||
BeforeAll {
|
||||
. "$PSScriptRoot\Scoop-TestLib.ps1"
|
||||
. "$PSScriptRoot\..\lib\core.ps1"
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1"
|
||||
. "$PSScriptRoot\..\lib\install.ps1"
|
||||
}
|
||||
|
||||
Describe 'appname_from_url' -Tag 'Scoop' {
|
||||
@@ -65,8 +33,8 @@ Describe 'url_remote_filename' -Tag 'Scoop' {
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'is_in_dir' -Tag 'Scoop' {
|
||||
It 'should work correctly' -Skip:$isUnix {
|
||||
Describe 'is_in_dir' -Tag 'Scoop', 'Windows' {
|
||||
It 'should work correctly' {
|
||||
is_in_dir 'C:\test' 'C:\foo' | Should -BeFalse
|
||||
is_in_dir 'C:\test' 'C:\test\foo\baz.zip' | Should -BeTrue
|
||||
|
||||
@@ -75,18 +43,20 @@ Describe 'is_in_dir' -Tag 'Scoop' {
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'env add and remove path' -Tag 'Scoop' {
|
||||
# test data
|
||||
$manifest = @{
|
||||
'env_add_path' = @('foo', 'bar')
|
||||
Describe 'env add and remove path' -Tag 'Scoop', 'Windows' {
|
||||
BeforeAll {
|
||||
# test data
|
||||
$manifest = @{
|
||||
'env_add_path' = @('foo', 'bar')
|
||||
}
|
||||
$testdir = Join-Path $PSScriptRoot 'path-test-directory'
|
||||
$global = $false
|
||||
|
||||
# store the original path to prevent leakage of tests
|
||||
$origPath = $env:PATH
|
||||
}
|
||||
$testdir = Join-Path $PSScriptRoot 'path-test-directory'
|
||||
$global = $false
|
||||
|
||||
# store the original path to prevent leakage of tests
|
||||
$origPath = $env:PATH
|
||||
|
||||
It 'should concat the correct path' -Skip:$isUnix {
|
||||
It 'should concat the correct path' {
|
||||
Mock add_first_in_path {}
|
||||
Mock remove_from_path {}
|
||||
|
||||
@@ -152,37 +122,3 @@ Describe 'persist_def' -Tag 'Scoop' {
|
||||
$target | Should -Be 'foo'
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'compute_hash' -Tag 'Scoop' {
|
||||
BeforeAll {
|
||||
$working_dir = setup_working 'manifest'
|
||||
}
|
||||
|
||||
It 'computes MD5 correctly' {
|
||||
compute_hash (Join-Path "$working_dir" 'invalid_wget.json') 'md5' | Should -Be 'cf229eecc201063e32b436e73b71deba'
|
||||
compute_hash (Join-Path "$working_dir" 'wget.json') 'md5' | Should -Be '57c397fd5092cbd6a8b4df56be2551ab'
|
||||
compute_hash (Join-Path "$working_dir" 'broken_schema.json') 'md5' | Should -Be '0427c7f4edc33d6d336db98fc160beb0'
|
||||
compute_hash (Join-Path "$working_dir" 'broken_wget.json') 'md5' | Should -Be '30a7d4d3f64cb7a800d96c0f2ccec87f'
|
||||
}
|
||||
|
||||
It 'computes SHA-1 correctly' {
|
||||
compute_hash (Join-Path "$working_dir" 'invalid_wget.json') 'sha1' | Should -Be '33ae44df8feed86cdc8f544234029fb28280c3c5'
|
||||
compute_hash (Join-Path "$working_dir" 'wget.json') 'sha1' | Should -Be '98bfacb887da8cd05d3a1162f89d90173294be55'
|
||||
compute_hash (Join-Path "$working_dir" 'broken_schema.json') 'sha1' | Should -Be '6dcd64f8ce7a3ae6bbc3dc2288b7cb202dbfa3c8'
|
||||
compute_hash (Join-Path "$working_dir" 'broken_wget.json') 'sha1' | Should -Be '60b5b1d5bcb4193d19aeab265eab0bb9b0c46c8f'
|
||||
}
|
||||
|
||||
It 'computes SHA-256 correctly' {
|
||||
compute_hash (Join-Path "$working_dir" 'invalid_wget.json') 'sha256' | Should -Be '1a92ef57c5f3cecba74015ae8e92fc3f2dbe141f9d171c3a06f98645a522d58c'
|
||||
compute_hash (Join-Path "$working_dir" 'wget.json') 'sha256' | Should -Be '31d6d0953d4e95f0a42080acd61a8c2f92bc90cae324c0d6d2301a974c15f62f'
|
||||
compute_hash (Join-Path "$working_dir" 'broken_schema.json') 'sha256' | Should -Be 'f3e5082e366006c317d9426e590623254cb1ce23d4f70165afed340b03ce333b'
|
||||
compute_hash (Join-Path "$working_dir" 'broken_wget.json') 'sha256' | Should -Be 'da658987c3902658c6e754bfa6546dfd084aaa2c3ae25f1fd8aa4645bc9cae24'
|
||||
}
|
||||
|
||||
It 'computes SHA-512 correctly' {
|
||||
compute_hash (Join-Path "$working_dir" 'invalid_wget.json') 'sha512' | Should -Be '7a7b82ec17547f5ec13dc614a8cec919e897e6c344a6ce7d71205d6f1c3aed276c7b15cbc69acac8207f72417993299cef36884e1915d56758ea09efa2259870'
|
||||
compute_hash (Join-Path "$working_dir" 'wget.json') 'sha512' | Should -Be '216ebf07bb77062b51420f0f5eb6b7a94d9623d1d41d36c833436058f41e39898f2aa48d7020711c0d8765d02b87ac2e6810f3f502636a6e6f47dc4b9aa02d17'
|
||||
compute_hash (Join-Path "$working_dir" 'broken_schema.json') 'sha512' | Should -Be '8d3f5617517e61c33275eafea4b166f0a245ec229c40dea436173c354786bad72e4fd9d662f6ac2b9f3dd375c00815a07f10e12975eec1b12da7ba7db10f9c14'
|
||||
compute_hash (Join-Path "$working_dir" 'broken_wget.json') 'sha512' | Should -Be '7b16a714491e91cc6daa5f90e700547fac4d62e1fcec8c4b78f5a2386e04e68a8ed68f27503ece9555904a047df8050b3f12b4f779c05b1e4d0156e6e2d8fdbb'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
$repo_dir = (Get-Item $MyInvocation.MyCommand.Path).directory.parent.FullName
|
||||
|
||||
Describe 'PSScriptAnalyzer' -Tag 'Linter' {
|
||||
$scoop_modules = Get-ChildItem $repo_dir -Recurse -Include *.psd1, *.psm1, *.ps1
|
||||
$scoop_modules = $scoop_modules | Where-Object { $_.DirectoryName -notlike '*\supporting*' -and $_.DirectoryName -notlike '*\test*' }
|
||||
$scoop_modules = $scoop_modules | Select-Object -ExpandProperty Directory -Unique
|
||||
|
||||
Context 'Checking ScriptAnalyzer' {
|
||||
It 'Invoke-ScriptAnalyzer Cmdlet should exist' {
|
||||
{ Get-Command Invoke-ScriptAnalyzer -ErrorAction Stop } | Should -Not -Throw
|
||||
}
|
||||
It 'PSScriptAnalyzerSettings.ps1 should exist' {
|
||||
Test-Path "$repo_dir\PSScriptAnalyzerSettings.psd1" | Should -BeTrue
|
||||
}
|
||||
It 'There should be files to test' {
|
||||
$scoop_modules.Count | Should -Not -Be 0
|
||||
}
|
||||
}
|
||||
|
||||
$linting_settings = Get-Item -Path "$repo_dir\PSScriptAnalyzerSettings.psd1"
|
||||
|
||||
Context 'Linting all *.psd1, *.psm1 and *.ps1 files' {
|
||||
foreach ($directory in $scoop_modules) {
|
||||
$analysis = Invoke-ScriptAnalyzer -Path $directory.FullName -Settings $linting_settings.FullName
|
||||
It "Should pass: $directory" {
|
||||
$analysis.Count | Should -Be 0
|
||||
}
|
||||
if ($analysis) {
|
||||
foreach ($result in $analysis) {
|
||||
switch -wildCard ($result.ScriptName) {
|
||||
'*.psm1' { $type = 'Module' }
|
||||
'*.ps1' { $type = 'Script' }
|
||||
'*.psd1' { $type = 'Manifest' }
|
||||
}
|
||||
Write-Host -f Yellow " [*] $($result.Severity): $($result.Message)"
|
||||
Write-Host -f Yellow " $($result.RuleName) in $type`: $directory\$($result.ScriptName):$($result.Line)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
86
test/Scoop-Manifest.Tests.ps1
Normal file
86
test/Scoop-Manifest.Tests.ps1
Normal file
@@ -0,0 +1,86 @@
|
||||
BeforeAll {
|
||||
. "$PSScriptRoot\..\lib\json.ps1"
|
||||
. "$PSScriptRoot\..\lib\manifest.ps1"
|
||||
}
|
||||
|
||||
Describe 'JSON parse and beautify' -Tag 'Scoop' {
|
||||
Context 'Parse JSON' {
|
||||
It 'success with valid json' {
|
||||
{ parse_json "$PSScriptRoot\fixtures\manifest\wget.json" } | Should -Not -Throw
|
||||
}
|
||||
It 'fails with invalid json' {
|
||||
{ parse_json "$PSScriptRoot\fixtures\manifest\broken_wget.json" } | Should -Throw
|
||||
}
|
||||
}
|
||||
Context 'Beautify JSON' {
|
||||
BeforeDiscovery {
|
||||
$manifests = (Get-ChildItem "$PSScriptRoot\fixtures\format\formatted" -File -Filter '*.json').Name
|
||||
}
|
||||
BeforeAll {
|
||||
$format = "$PSScriptRoot\fixtures\format"
|
||||
}
|
||||
It '<_>' -ForEach $manifests {
|
||||
$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
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'Manifest Validator' -Tag 'Validator' {
|
||||
# Could not use backslash '\' in Linux/macOS for .NET object 'Scoop.Validator'
|
||||
BeforeAll {
|
||||
Add-Type -Path "$PSScriptRoot\..\supporting\validator\bin\Scoop.Validator.dll"
|
||||
$schema = "$PSScriptRoot/../schema.json"
|
||||
}
|
||||
|
||||
It 'Scoop.Validator is available' {
|
||||
([System.Management.Automation.PSTypeName]'Scoop.Validator').Type | Should -Be 'Scoop.Validator'
|
||||
}
|
||||
It 'fails with broken schema' {
|
||||
$validator = New-Object Scoop.Validator("$PSScriptRoot/fixtures/manifest/broken_schema.json", $true)
|
||||
$validator.Validate("$PSScriptRoot/fixtures/manifest/wget.json") | Should -BeFalse
|
||||
$validator.Errors.Count | Should -Be 1
|
||||
$validator.Errors | Select-Object -First 1 | Should -Match 'broken_schema.*(line 6).*(position 4)'
|
||||
}
|
||||
It 'fails with broken manifest' {
|
||||
$validator = New-Object Scoop.Validator($schema, $true)
|
||||
$validator.Validate("$PSScriptRoot/fixtures/manifest/broken_wget.json") | Should -BeFalse
|
||||
$validator.Errors.Count | Should -Be 1
|
||||
$validator.Errors | Select-Object -First 1 | Should -Match 'broken_wget.*(line 5).*(position 4)'
|
||||
}
|
||||
It 'fails with invalid manifest' {
|
||||
$validator = New-Object Scoop.Validator($schema, $true)
|
||||
$validator.Validate("$PSScriptRoot/fixtures/manifest/invalid_wget.json") | Should -BeFalse
|
||||
$validator.Errors.Count | Should -Be 16
|
||||
$validator.Errors | Select-Object -First 1 | Should -Match "Property 'randomproperty' has not been defined and the schema does not allow additional properties\."
|
||||
$validator.Errors | Select-Object -Last 1 | Should -Match 'Required properties are missing from object: version\.'
|
||||
}
|
||||
}
|
||||
@@ -1,69 +1,3 @@
|
||||
if (!$script:run) { $script:run = 0 }
|
||||
if (!$script:failed) { $script:failed = 0 }
|
||||
|
||||
function filter_tests($arg) {
|
||||
if (!$arg) { return }
|
||||
$script:filter = $arg -join ' '
|
||||
Write-Host "filtering by '$filter'"
|
||||
}
|
||||
function test($desc, $assertions) {
|
||||
if ($filter -and $desc -notlike "*$filter*") { return }
|
||||
$script:test = $desc
|
||||
$script:run++
|
||||
try {
|
||||
$assertions.invoke()
|
||||
} catch {
|
||||
script:fail $_.exception.innerexception.message
|
||||
}
|
||||
$script:test = $null
|
||||
}
|
||||
|
||||
function assert($x, $eq = '__undefined', $ne = '__undefined') {
|
||||
if ($args.length -gt 0) {
|
||||
fail "unexpected arguments: $args"
|
||||
}
|
||||
|
||||
if ($eq -ne '__undefined') {
|
||||
if ($x -ne $eq) { fail "$(fmt $x) != $(fmt $eq)" }
|
||||
} elseif ($ne -ne '__undefined') {
|
||||
if ($x -eq $ne) { fail "$(fmt $x) == $(fmt $ne)" }
|
||||
} else {
|
||||
if (!$x) { fail "$x" }
|
||||
}
|
||||
}
|
||||
|
||||
function test_results {
|
||||
$col = 'darkgreen'
|
||||
$res = 'all passed'
|
||||
if ($script:failed -gt 0) {
|
||||
$col = 'darkred'
|
||||
$res = "$script:failed failed"
|
||||
}
|
||||
|
||||
Write-Host "ran $script:run tests, " -NoNewline
|
||||
Write-Host $res -f $col
|
||||
}
|
||||
|
||||
function script:fail($msg) {
|
||||
$script:failed++
|
||||
$invoked = (Get-Variable -Scope 1 myinvocation).value
|
||||
|
||||
$script = Split-Path $invoked.scriptname -Leaf
|
||||
$line = $invoked.scriptlinenumber
|
||||
|
||||
if ($script:test) { $msg = "$script:test`r`n -> $msg" }
|
||||
|
||||
Write-Host "FAIL: $msg" -f darkred
|
||||
Write-Host "$script line $line`:"
|
||||
Write-Host (($invoked.positionmessage -split "`r`n")[1..2] -join "`r`n")
|
||||
}
|
||||
|
||||
function script:fmt($var) {
|
||||
if ($null -eq $var) { return "`$null" }
|
||||
if ($var -is [string]) { return "'$var'" }
|
||||
return $var
|
||||
}
|
||||
|
||||
# copies fixtures to a working directory
|
||||
function setup_working($name) {
|
||||
$fixtures = "$PSScriptRoot/fixtures/$name"
|
||||
@@ -73,11 +7,7 @@ function setup_working($name) {
|
||||
}
|
||||
|
||||
# reset working dir
|
||||
if ($PSVersionTable.Platform -eq 'Unix') {
|
||||
$working_dir = "/tmp/ScoopTestFixtures/$name"
|
||||
} else {
|
||||
$working_dir = "$env:TEMP/ScoopTestFixtures/$name"
|
||||
}
|
||||
$working_dir = "$([IO.Path]::GetTempPath())ScoopTestFixtures/$name"
|
||||
|
||||
if (Test-Path $working_dir) {
|
||||
Remove-Item -Recurse -Force $working_dir
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
. "$PSScriptRoot\Scoop-TestLib.ps1"
|
||||
. "$PSScriptRoot\..\lib\versions.ps1"
|
||||
BeforeAll {
|
||||
. "$PSScriptRoot\Scoop-TestLib.ps1"
|
||||
. "$PSScriptRoot\..\lib\versions.ps1"
|
||||
}
|
||||
|
||||
Describe 'versions comparison' -Tag 'Scoop' {
|
||||
Context 'semver compliant versions' {
|
||||
@@ -90,10 +92,21 @@ Describe 'versions comparison' -Tag 'Scoop' {
|
||||
}
|
||||
|
||||
It 'handles equal versions' {
|
||||
function get_config { $null }
|
||||
Compare-Version '12.0' '12.0' | Should -Be 0
|
||||
Compare-Version '7.0.4-9' '7.0.4-9' | Should -Be 0
|
||||
Compare-Version 'nightly-20190801' 'nightly' | Should -Be 0
|
||||
Compare-Version 'nightly-20190801' 'nightly-20200801' | Should -Be 0
|
||||
}
|
||||
|
||||
It 'handles nightly versions with `update_nightly`' {
|
||||
function get_config { $true }
|
||||
Mock Get-Date { '20200801' }
|
||||
Compare-Version 'nightly-20200801' 'nightly' | Should -Be 0
|
||||
Compare-Version 'nightly-20200730' 'nightly' | Should -Be 1
|
||||
Compare-Version 'nightly-20200730' 'nightly-20200801' | Should -Be 1
|
||||
Compare-Version 'nightly-20200802' 'nightly' | Should -Be -1
|
||||
Compare-Version 'nightly-20200802' 'nightly-20200801' | Should -Be -1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
#Requires -Version 5.1
|
||||
Write-Host "PowerShell: $($PSVersionTable.PSVersion)"
|
||||
Write-Host (7z.exe | Select-String -Pattern '7-Zip').ToString()
|
||||
Write-Host 'Check and install testsuite dependencies ...'
|
||||
if (Get-InstalledModule -Name Pester -MinimumVersion 4.0 -MaximumVersion 4.99 -ErrorAction SilentlyContinue) {
|
||||
Write-Host 'Pester 4 is already installed.'
|
||||
Write-Output "PowerShell: $($PSVersionTable.PSVersion)"
|
||||
Write-Output 'Check and install testsuite dependencies ...'
|
||||
if (Get-InstalledModule -Name Pester -MinimumVersion 5.2 -MaximumVersion 5.99 -ErrorAction SilentlyContinue) {
|
||||
Write-Output 'Pester 5 is already installed.'
|
||||
} else {
|
||||
Write-Host 'Installing Pester 4 ...'
|
||||
Install-Module -Repository PSGallery -Scope CurrentUser -Force -Name Pester -MinimumVersion 4.0 -MaximumVersion 4.99 -SkipPublisherCheck
|
||||
Write-Output 'Installing Pester 5 ...'
|
||||
Install-Module -Repository PSGallery -Scope CurrentUser -Force -Name Pester -MinimumVersion 5.2 -MaximumVersion 5.99 -SkipPublisherCheck
|
||||
}
|
||||
if (Get-InstalledModule -Name PSScriptAnalyzer -MinimumVersion 1.17 -ErrorAction SilentlyContinue) {
|
||||
Write-Host 'PSScriptAnalyzer is already installed.'
|
||||
Write-Output 'PSScriptAnalyzer is already installed.'
|
||||
} else {
|
||||
Write-Host 'Installing PSScriptAnalyzer ...'
|
||||
Write-Output 'Installing PSScriptAnalyzer ...'
|
||||
Install-Module -Repository PSGallery -Scope CurrentUser -Force -Name PSScriptAnalyzer -SkipPublisherCheck
|
||||
}
|
||||
if (Get-InstalledModule -Name BuildHelpers -MinimumVersion 2.0 -ErrorAction SilentlyContinue) {
|
||||
Write-Host 'BuildHelpers is already installed.'
|
||||
Write-Output 'BuildHelpers is already installed.'
|
||||
} else {
|
||||
Write-Host 'Installing BuildHelpers ...'
|
||||
Write-Output 'Installing BuildHelpers ...'
|
||||
Install-Module -Repository PSGallery -Scope CurrentUser -Force -Name BuildHelpers -SkipPublisherCheck
|
||||
}
|
||||
|
||||
@@ -1,40 +1,41 @@
|
||||
#Requires -Version 5.1
|
||||
#Requires -Modules @{ ModuleName = 'BuildHelpers'; ModuleVersion = '2.0.1' }
|
||||
#Requires -Modules @{ ModuleName = 'Pester'; MaximumVersion = '4.99' }
|
||||
#Requires -Modules @{ ModuleName = 'Pester'; ModuleVersion = '5.2.0' }
|
||||
#Requires -Modules @{ ModuleName = 'PSScriptAnalyzer'; ModuleVersion = '1.17.1' }
|
||||
param(
|
||||
[String] $TestPath = $(Resolve-Path "$PSScriptRoot\..\")
|
||||
[String] $TestPath = (Convert-Path "$PSScriptRoot\..")
|
||||
)
|
||||
|
||||
$splat = @{
|
||||
Path = $TestPath
|
||||
PassThru = $true
|
||||
$pesterConfig = New-PesterConfiguration -Hashtable @{
|
||||
Run = @{
|
||||
Path = $TestPath
|
||||
PassThru = $true
|
||||
}
|
||||
Output = @{
|
||||
Verbosity = 'Detailed'
|
||||
}
|
||||
}
|
||||
$excludes = @()
|
||||
|
||||
if ($IsLinux -or $IsMacOS) {
|
||||
Write-Warning 'Skipping Windows-only tests on Linux/macOS'
|
||||
$excludes += 'Windows'
|
||||
}
|
||||
|
||||
if ($env:CI -eq $true) {
|
||||
Write-Host "Load 'BuildHelpers' environment variables ..."
|
||||
Set-BuildEnvironment -Force
|
||||
$CI_WIN = (($env:RUNNER_OS -eq 'Windows') -or ($env:CI_WINDOWS -eq $true))
|
||||
|
||||
$excludes = @()
|
||||
$commit = $env:BHCommitHash
|
||||
$commitMessage = $env:BHCommitMessage
|
||||
|
||||
# Check if tests are called from the Core itself, if so, adding excludes
|
||||
if ($TestPath -eq $(Resolve-Path "$PSScriptRoot\..\")) {
|
||||
if ($commitMessage -match '!linter') {
|
||||
if ($TestPath -eq (Convert-Path "$PSScriptRoot\..")) {
|
||||
if ($env:BHCommitMessage -match '!linter') {
|
||||
Write-Warning "Skipping code linting per commit flag '!linter'"
|
||||
$excludes += 'Linter'
|
||||
}
|
||||
|
||||
if (!$CI_WIN) {
|
||||
Write-Warning 'Skipping tests and code linting for decompress.ps1 because they only work on Windows'
|
||||
$excludes += 'Decompress'
|
||||
}
|
||||
|
||||
$changedScripts = (Get-GitChangedFile -Include '*.ps1' -Commit $commit)
|
||||
$changedScripts = (Get-GitChangedFile -Include '*.ps1', '*.psd1', '*.psm1' -Commit $env:BHCommitHash)
|
||||
if (!$changedScripts) {
|
||||
Write-Warning "Skipping tests and code linting for *.ps1 files because they didn't change"
|
||||
Write-Warning "Skipping tests and code linting for PowerShell scripts because they didn't change"
|
||||
$excludes += 'Linter'
|
||||
$excludes += 'Scoop'
|
||||
}
|
||||
@@ -44,12 +45,14 @@ if ($env:CI -eq $true) {
|
||||
$excludes += 'Decompress'
|
||||
}
|
||||
|
||||
if ('Decompress' -notin $excludes) {
|
||||
if ('Decompress' -notin $excludes -and 'Windows' -notin $excludes) {
|
||||
Write-Host 'Install decompress dependencies ...'
|
||||
|
||||
Write-Host (7z.exe | Select-String -Pattern '7-Zip').ToString()
|
||||
|
||||
$env:SCOOP_HELPERS_PATH = 'C:\projects\helpers'
|
||||
if (!(Test-Path $env:SCOOP_HELPERS_PATH)) {
|
||||
New-Item -ItemType Directory -Path $env:SCOOP_HELPERS_PATH
|
||||
New-Item -ItemType Directory -Path $env:SCOOP_HELPERS_PATH | Out-Null
|
||||
}
|
||||
|
||||
$env:SCOOP_LESSMSI_PATH = "$env:SCOOP_HELPERS_PATH\lessmsi\lessmsi.exe"
|
||||
@@ -83,13 +86,8 @@ if ($env:CI -eq $true) {
|
||||
}
|
||||
}
|
||||
|
||||
if ($excludes.Length -gt 0) {
|
||||
$splat.ExcludeTag = $excludes
|
||||
}
|
||||
|
||||
# Display CI environment variables
|
||||
$buildVariables = ( Get-ChildItem -Path 'Env:' ).Where( { $_.Name -match '^(?:BH|CI(?:_|$)|APPVEYOR|GITHUB_|RUNNER_|SCOOP_)' } )
|
||||
$buildVariables += ( Get-Variable -Name 'CI_*' -Scope 'Script' )
|
||||
$buildVariables = (Get-ChildItem -Path 'Env:').Where({ $_.Name -match '^(?:BH|CI(?:_|$)|APPVEYOR|GITHUB_|RUNNER_|SCOOP_)' })
|
||||
$details = $buildVariables |
|
||||
Where-Object -FilterScript { $_.Name -notmatch 'EMAIL' } |
|
||||
Sort-Object -Property 'Name' |
|
||||
@@ -97,24 +95,22 @@ if ($env:CI -eq $true) {
|
||||
Out-String
|
||||
Write-Host 'CI variables:'
|
||||
Write-Host $details -ForegroundColor DarkGray
|
||||
|
||||
# AppVeyor
|
||||
if ($env:BHBuildSystem -eq "AppVeyor") {
|
||||
$resultsXml = "$PSScriptRoot\TestResults.xml"
|
||||
$splat += @{
|
||||
OutputFile = $resultsXml
|
||||
OutputFormat = 'NUnitXML'
|
||||
}
|
||||
|
||||
Write-Host 'Invoke-Pester' @splat
|
||||
$result = Invoke-Pester @splat
|
||||
|
||||
(New-Object Net.WebClient).UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", $resultsXml)
|
||||
exit $result.FailedCount
|
||||
}
|
||||
}
|
||||
|
||||
# GitHub Actions / Local
|
||||
Write-Host 'Invoke-Pester' @splat
|
||||
$result = Invoke-Pester @splat
|
||||
if ($excludes.Length -gt 0) {
|
||||
$pesterConfig.Filter.ExcludeTag = $excludes
|
||||
}
|
||||
|
||||
if ($env:BHBuildSystem -eq 'AppVeyor') {
|
||||
# AppVeyor
|
||||
$resultsXml = "$PSScriptRoot\TestResults.xml"
|
||||
$pesterConfig.TestResult.Enabled = $true
|
||||
$pesterConfig.TestResult.OutputPath = $resultsXml
|
||||
$result = Invoke-Pester -Configuration $pesterConfig
|
||||
Add-TestResultToAppveyor -TestFile $resultsXml
|
||||
} else {
|
||||
# GitHub Actions / Local
|
||||
$result = Invoke-Pester -Configuration $pesterConfig
|
||||
}
|
||||
|
||||
exit $result.FailedCount
|
||||
|
||||
BIN
test/fixtures/decompress/TestCases.zip
vendored
BIN
test/fixtures/decompress/TestCases.zip
vendored
Binary file not shown.
Reference in New Issue
Block a user