diff --git a/.editorconfig b/.editorconfig
index 2a6483b4f8..87230b083c 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -12,10 +12,14 @@ indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
-[*.{bat,cmd,[Bb][Aa][Tt],[Cc][Mm][Dd]]
+[*.{[Bb][Aa][Tt],[Cc][Mm][Dd]}]
# DOS/Win *requires* BAT/CMD files to have CRLF newlines
end_of_line = crlf
-[[Mm]akefile{,.*}]
-# TAB-style indentation
+[*.{yml, yaml}]
+indent_size = 2
+
+# Makefiles require tab indentation
+[{{M,m,GNU}akefile{,.*},*.mak,*.mk}]
indent_style = tab
+end_of_line = lf
diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md
new file mode 100644
index 0000000000..eec84250f6
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/Bug_report.md
@@ -0,0 +1,47 @@
+---
+name: "Bug Report"
+about: "I am facing some problems."
+title: '[Bug] '
+labels: "bug"
+
+---
+
+
+
+## Bug Report
+
+#### Current Behavior
+
+
+#### Expected Behavior
+
+
+#### Additional context/output
+
+
+#### Possible Solution
+
+
+### System details
+
+**Windows version:** [e.g. 7, 8, 10, 11]
+
+**OS architecture:** [e.g. 32bit, 64bit, arm64]
+
+**PowerShell version:** [output of `"$($PSVersionTable.PSVersion)"`]
+
+**Additional software:** [(optional) e.g. ConEmu, Git]
+
+#### Scoop Configuration
+
+
+```json
+//# Your configuration here
+```
diff --git a/.github/ISSUE_TEMPLATE/Feature_request.md b/.github/ISSUE_TEMPLATE/Feature_request.md
new file mode 100644
index 0000000000..32faf66b83
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/Feature_request.md
@@ -0,0 +1,27 @@
+---
+name: "Feature Request"
+about: "I have a suggestion (and may want to implement it)!"
+title: '[Feature] '
+labels: "enhancement"
+
+---
+
+
+
+## Feature Request
+
+#### Is your feature request related to a problem? Please describe.
+
+
+#### Describe the solution you'd like
+
+
+#### Describe alternatives you've considered
+
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000000..99d680b0ab
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,2 @@
+blank_issues_enabled: false
+
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000000..0a7a20bf89
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+#### Description
+
+
+#### Motivation and Context
+
+
+Closes #XXXX
+
+Relates to #XXXX
+
+#### How Has This Been Tested?
+
+
+
+
+#### Checklist:
+
+
+- [ ] I have read the [Contributing Guide](https://github.com/ScoopInstaller/.github/blob/main/.github/CONTRIBUTING.md).
+- [ ] I have ensured that I am targeting the `develop` branch.
+- [ ] I have updated the documentation accordingly.
+- [ ] I have updated the tests accordingly.
+- [ ] I have added an entry in the CHANGELOG.
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000000..91df8eba1f
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,8 @@
+---
+# ~/.github/dependabot.yml
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/" # == /.github/workflows/
+ schedule:
+ interval: "daily"
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000000..3c7541f7bb
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,39 @@
+name: Scoop Core CI Tests
+
+on:
+ pull_request:
+ workflow_dispatch:
+
+jobs:
+ test_powershell:
+ name: WindowsPowerShell
+ runs-on: windows-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@main
+ with:
+ fetch-depth: 2
+ - name: Init Test Suite
+ uses: potatoqualitee/psmodulecache@main
+ with:
+ modules-to-cache: BuildHelpers
+ shell: powershell
+ - name: Test Scoop Core
+ shell: powershell
+ run: ./test/bin/test.ps1
+ test_pwsh:
+ name: PowerShell
+ runs-on: windows-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@main
+ with:
+ fetch-depth: 2
+ - name: Init Test Suite
+ uses: potatoqualitee/psmodulecache@main
+ with:
+ modules-to-cache: BuildHelpers
+ shell: pwsh
+ - name: Test Scoop Core
+ shell: pwsh
+ run: ./test/bin/test.ps1
diff --git a/.gitignore b/.gitignore
index 71f9152c12..67ecc85d82 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,9 @@
+*.log
.DS_Store
._.DS_Store
scoop.sublime-workspace
test/installer/tmp/*
test/tmp/*
*~
+TestResults.xml
+supporting/sqlite/*
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 0000000000..a9056e417e
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,6 @@
+{
+ "recommendations": [
+ "EditorConfig.EditorConfig",
+ "ms-vscode.PowerShell"
+ ]
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000000..b250385bac
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,18 @@
+// Configure PSScriptAnalyzer settings
+{
+ "powershell.scriptAnalysis.settingsPath": "PSScriptAnalyzerSettings.psd1",
+ "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,
+ "**/.hg": true,
+ "**/CVS": true,
+ "**/.DS_Store": true,
+ "**/tmp": true
+ }
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000000..c0c15ec326
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,924 @@
+## [v0.5.3](https://github.com/ScoopInstaller/Scoop/compare/v0.5.2...v0.5.3) - 2025-08-11
+
+### Features
+
+**autoupdate:** GitHub predefined hashes support ([#6416](https://github.com/ScoopInstaller/Scoop/issues/6416), [#6435](https://github.com/ScoopInstaller/Scoop/issues/6435))
+
+### Bug Fixes
+
+- **scoop-download|install|update:** Fallback to default downloader when aria2 fails ([#4292](https://github.com/ScoopInstaller/Scoop/issues/4292))
+- **decompress**: `Expand-7zipArchive` only delete temp dir / `$extractDir` if it is empty ([#6092](https://github.com/ScoopInstaller/Scoop/issues/6092))
+- **decompress**: Replace deprecated 7ZIPEXTRACT_USE_EXTERNAL config with USE_EXTERNAL_7ZIP ([#6327](https://github.com/ScoopInstaller/Scoop/issues/6327))
+- **commands**: Handling broken aliases ([#6141](https://github.com/ScoopInstaller/Scoop/issues/6141))
+- **shim:** Do not suppress `stderr`, properly check `wslpath`/`cygpath` command first ([#6114](https://github.com/ScoopInstaller/Scoop/issues/6114))
+- **scoop-bucket:** Add missing import for `no_junction` envs ([#6181](https://github.com/ScoopInstaller/Scoop/issues/6181))
+- **scoop-uninstall:** Fix uninstaller does not gain Global state ([#6430](https://github.com/ScoopInstaller/Scoop/issues/6430))
+- **scoop-depends-tests:** Mocking `USE_EXTERNAL_7ZIP` as $false to avoding error when it is $true ([#6431](https://github.com/ScoopInstaller/Scoop/issues/6431))
+
+### Code Refactoring
+
+- **download:** Move download-related functions to 'download.ps1' ([#6095](https://github.com/ScoopInstaller/Scoop/issues/6095))
+- **Get-Manifest:** Select actual source for manifest ([#6142](https://github.com/ScoopInstaller/Scoop/issues/6142))
+
+### Performance Improvements
+
+- **shim:** Update kiennq-shim to v3.1.2 ([#6261](https://github.com/ScoopInstaller/Scoop/issues/6261))
+
+## [v0.5.2](https://github.com/ScoopInstaller/Scoop/compare/v0.5.1...v0.5.2) - 2024-07-26
+
+### Bug Fixes
+
+- **scoop-alias:** Fix 'Option --verbose not recognized.' ([#6062](https://github.com/ScoopInstaller/Scoop/issues/6062))
+- **scoop-hold:** Use 'foreach' loop to allow 'continue' statement ([#6078](https://github.com/ScoopInstaller/Scoop/issues/6078))
+- **core:** Use 'Join-Path' to construct cache file path ([#6079](https://github.com/ScoopInstaller/Scoop/issues/6079))
+- **json:** Don't serialize jsonpath return if only one result ([#6066](https://github.com/ScoopInstaller/Scoop/issues/6066), [#6073](https://github.com/ScoopInstaller/Scoop/issues/6073))
+
+### Builds
+
+- **supporting:** Update Json.Schema to 4.0.1 ([#6072](https://github.com/ScoopInstaller/Scoop/issues/6072))
+
+## [v0.5.1](https://github.com/ScoopInstaller/Scoop/compare/v0.5.0...v0.5.1) - 2024-07-16
+
+### Bug Fixes
+
+- **scoop-alias:** Pass options correctly ([#6003](https://github.com/ScoopInstaller/Scoop/issues/6003))
+- **scoop-virustotal:** Adjust `json_path` parameters to retrieve correct analysis stats ([#6044](https://github.com/ScoopInstaller/Scoop/issues/6044))
+- **bucket:** Implement error handling for failed bucket addition ([#6051](https://github.com/ScoopInstaller/Scoop/issues/6051))
+- **database:** Fix compatibility with Windows PowerShell ([#6045](https://github.com/ScoopInstaller/Scoop/issues/6045))
+- **install:** Expand `env_set` items before setting Environment Variables ([#6050](https://github.com/ScoopInstaller/Scoop/issues/6050))
+- **install:** Fix parsing error when installing multiple apps w/ specific version ([#6039](https://github.com/ScoopInstaller/Scoop/issues/6039))
+
+## [v0.5.0](https://github.com/ScoopInstaller/Scoop/compare/v0.4.2...v0.5.0) - 2024-07-01
+
+### Features
+
+- **scoop-search:** Use SQLite for caching apps to speed up local search ([#5851](https://github.com/ScoopInstaller/Scoop/issues/5851), [#5918](https://github.com/ScoopInstaller/Scoop/issues/5918), [#5946](https://github.com/ScoopInstaller/Scoop/issues/5946), [#5949](https://github.com/ScoopInstaller/Scoop/issues/5949), [#5955](https://github.com/ScoopInstaller/Scoop/issues/5955), [#5966](https://github.com/ScoopInstaller/Scoop/issues/5966), [#5967](https://github.com/ScoopInstaller/Scoop/issues/5967), [#5981](https://github.com/ScoopInstaller/Scoop/issues/5981))
+- **core:** New cache filename format ([#5929](https://github.com/ScoopInstaller/Scoop/issues/5929), [#5944](https://github.com/ScoopInstaller/Scoop/issues/5944))
+- **decompress:** Use innounp-unicode as default Inno Setup Unpacker ([#6028](https://github.com/ScoopInstaller/Scoop/issues/6028))
+- **install:** Added the ability to install specific version of app from URL/file link ([#5988](https://github.com/ScoopInstaller/Scoop/issues/5988))
+
+### Bug Fixes
+
+- **scoop-download|install|update:** Use consistent options ([#5956](https://github.com/ScoopInstaller/Scoop/issues/5956))
+- **scoop-info:** Fix download size estimating ([#5958](https://github.com/ScoopInstaller/Scoop/issues/5958))
+- **scoop-search:** Catch error of parsing invalid manifest ([#5930](https://github.com/ScoopInstaller/Scoop/issues/5930))
+- **checkver:** Correct variable 'regex' to 'regexp' ([#5993](https://github.com/ScoopInstaller/Scoop/issues/5993))
+- **checkver:** Correct error messages ([#6024](https://github.com/ScoopInstaller/Scoop/issues/6024))
+- **core:** Search for Git executable instead of any cmdlet ([#5998](https://github.com/ScoopInstaller/Scoop/issues/5998))
+- **core:** Use correct path in 'bash' ([#6006](https://github.com/ScoopInstaller/Scoop/issues/6006))
+- **core:** Limit the number of commands to get when search for git executable ([#6013](https://github.com/ScoopInstaller/Scoop/issues/6013))
+- **decompress:** Match `extract_dir`/`extract_to` and archives ([#5983](https://github.com/ScoopInstaller/Scoop/issues/5983))
+- **json:** Serialize jsonpath return ([#5921](https://github.com/ScoopInstaller/Scoop/issues/5921))
+- **shim:** Restore original path for JAR cmd ([#6030](https://github.com/ScoopInstaller/Scoop/issues/6030))
+
+### Code Refactoring
+
+- **decompress:** Use 7zip to extract Zstd archive ([#5973](https://github.com/ScoopInstaller/Scoop/issues/5973))
+- **install:** Separate archive extraction from downloader ([#5951](https://github.com/ScoopInstaller/Scoop/issues/5951))
+- **install:** Replace 'run_(un)installer()' with 'Invoke-Installer()' ([#5968](https://github.com/ScoopInstaller/Scoop/issues/5968), [#5971](https://github.com/ScoopInstaller/Scoop/issues/5971))
+
+## [v0.4.2](https://github.com/ScoopInstaller/Scoop/compare/v0.4.1...v0.4.2) - 2024-05-14
+
+### Bug Fixes
+
+- **autoupdate:** Copy `PSCustomObject`-type properties within `substitute()` to prevent reference changes ([#5934](https://github.com/ScoopInstaller/Scoop/issues/5934), [#5962](https://github.com/ScoopInstaller/Scoop/issues/5962))
+- **core:** Fix `Invoke-ExternalCommand` quoting rules ([#5945](https://github.com/ScoopInstaller/Scoop/issues/5945))
+- **system:** Fix argument passing to `Split-PathLikeEnvVar()` in deprecated `strip_path()` ([#5937](https://github.com/ScoopInstaller/Scoop/issues/5937))
+
+## [v0.4.1](https://github.com/ScoopInstaller/Scoop/compare/v0.4.0...v0.4.1) - 2024-04-25
+
+### Bug Fixes
+
+- **core:** Fix `Invoke-ExternalCommand` regression ([#5923](https://github.com/ScoopInstaller/Scoop/issues/5923))
+
+## [v0.4.0](https://github.com/ScoopInstaller/Scoop/compare/v0.3.1...v0.4.0) - 2024-04-18
+
+### Features
+
+- **scoop-update:** Add support for parallel syncing buckets in PowerShell 7 and improve output ([#5122](https://github.com/ScoopInstaller/Scoop/issues/5122))
+- **bucket:** Switch nirsoft bucket to ScoopInstaller/Nirsoft ([#5328](https://github.com/ScoopInstaller/Scoop/issues/5328))
+- **bucket:** Make official buckets higher priority ([#5398](https://github.com/ScoopInstaller/Scoop/issues/5398))
+- **config:** Support portable config file ([#5369](https://github.com/ScoopInstaller/Scoop/issues/5369))
+- **core:** Add `-Quiet` switch for `Invoke-ExternalCommand` ([#5346](https://github.com/ScoopInstaller/Scoop/issues/5346))
+- **core:** Allow global install of PowerShell modules ([#5611](https://github.com/ScoopInstaller/Scoop/issues/5611))
+- **path:** Isolate Scoop apps' PATH ([#5840](https://github.com/ScoopInstaller/Scoop/issues/5840))
+
+### Bug Fixes
+
+- **scoop-alias:** Prevent overwrite existing file when adding alias ([#5577](https://github.com/ScoopInstaller/Scoop/issues/5577))
+- **scoop-checkup:** Skip defender check in Windows Sandbox ([#5519](https://github.com/ScoopInstaller/Scoop/issues/5519))
+- **scoop-checkup:** Change the message level of helpers from ERROR to WARN ([#5614](https://github.com/ScoopInstaller/Scoop/issues/5614))
+- **scoop-checkup:** Don't throw 7zip error when external 7zip is used ([#5703](https://github.com/ScoopInstaller/Scoop/issues/5703))
+- **scoop-(un)hold:** Correct output the messages when manifest not found, (already|not) held ([#5519](https://github.com/ScoopInstaller/Scoop/issues/5519))
+- **scoop-info:** Fix errors in file size collection when `--verbose` ([#5352](https://github.com/ScoopInstaller/Scoop/issues/5352))
+- **scoop-reset:** Don't abort when multiple apps are passed and an app is running ([#5687](https://github.com/ScoopInstaller/Scoop/issues/5687))
+- **scoop-update:** Change error message to a better instruction ([#5677](https://github.com/ScoopInstaller/Scoop/issues/5677))
+- **scoop-virustotal:** Fix `scoop-virustotal` when `--all` has been passed without app ([#5593](https://github.com/ScoopInstaller/Scoop/issues/5593))
+- **scoop-virustotal:** Fix the issue that escape character not available in PowerShell 5.1 ([#5870](https://github.com/ScoopInstaller/Scoop/issues/5870))
+- **autoupdate:** Fix file hash extraction ([#5295](https://github.com/ScoopInstaller/Scoop/issues/5295))
+- **autoupdate:** Fix bug that 'WebClient' doesn't auto-extract 'gzip' ([#5901](https://github.com/ScoopInstaller/Scoop/issues/5901))
+- **buckets:** Avoid error messages for unexpected dir ([#5549](https://github.com/ScoopInstaller/Scoop/issues/5549))
+- **config:** Warn users about misconfigured GitHub token ([#5777](https://github.com/ScoopInstaller/Scoop/issues/5777))
+- **core:** Fix scripts' calling parameters ([#5365](https://github.com/ScoopInstaller/Scoop/issues/5365))
+- **core:** Fix `is_in_dir` under Unix ([#5391](https://github.com/ScoopInstaller/Scoop/issues/5391))
+- **core:** Rewrite config file when needed ([#5439](https://github.com/ScoopInstaller/Scoop/issues/5439))
+- **core:** Prevents leaking HTTP(S)_PROXY env vars to current sessions after Invoke-Git in parallel execution ([#5436](https://github.com/ScoopInstaller/Scoop/issues/5436))
+- **core:** Handle scoop aliases and broken(edited,copied) shim ([#5551](https://github.com/ScoopInstaller/Scoop/issues/5551))
+- **core:** Avoid error messages when deleting non-existent environment variable ([#5547](https://github.com/ScoopInstaller/Scoop/issues/5547))
+- **core:** Use relative path as fallback of `$scoopdir` ([#5544](https://github.com/ScoopInstaller/Scoop/issues/5544))
+- **core:** Fix detection of Git ([#5545](https://github.com/ScoopInstaller/Scoop/issues/5545))
+- **core:** Do not call `scoop` externally from inside the code ([#5695](https://github.com/ScoopInstaller/Scoop/issues/5695))
+- **core:** Fix arguments parsing method of `Invoke-ExternalCommand()` ([#5839](https://github.com/ScoopInstaller/Scoop/issues/5839))
+- **decompress:** Exclude '*.nsis' that may cause error ([#5294](https://github.com/ScoopInstaller/Scoop/issues/5294))
+- **decompress:** Remove unused parent dir w/ 'extract_dir' ([#5682](https://github.com/ScoopInstaller/Scoop/issues/5682))
+- **decompress:** Use `wix.exe` in WiX Toolset v4+ as primary extractor of `Expand-DarkArchive()` ([#5871](https://github.com/ScoopInstaller/Scoop/issues/5871))
+- **env:** Avoid automatic expansion of `%%` in env ([#5395](https://github.com/ScoopInstaller/Scoop/issues/5395), [#5452](https://github.com/ScoopInstaller/Scoop/issues/5452), [#5631](https://github.com/ScoopInstaller/Scoop/issues/5631))
+- **getopt:** Stop split arguments in `getopt()` and ensure array by explicit arguments type ([#5326](https://github.com/ScoopInstaller/Scoop/issues/5326))
+- **install:** Fix download from private GitHub repositories ([#5361](https://github.com/ScoopInstaller/Scoop/issues/5361))
+- **install:** Avoid error when unlinking non-existent junction/hardlink ([#5552](https://github.com/ScoopInstaller/Scoop/issues/5552))
+- **manifest:** Correct source of manifest ([#5575](https://github.com/ScoopInstaller/Scoop/issues/5575))
+- **shim:** Remove console window for GUI applications ([#5559](https://github.com/ScoopInstaller/Scoop/issues/5559))
+- **shim:** Use bash executable directly ([#5433](https://github.com/ScoopInstaller/Scoop/issues/5433))
+- **shim:** Check literal path in `Get-ShimPath` ([#5680](https://github.com/ScoopInstaller/Scoop/issues/5680))
+- **shim:** Avoid unexpected output of `list` subcommand ([#5681](https://github.com/ScoopInstaller/Scoop/issues/5681))
+- **shim:** Allow GUI applications to attach to the shell's console when launched using the GUI shim ([#5721](https://github.com/ScoopInstaller/Scoop/issues/5721))
+- **shim:** Run JAR file from app's root directory ([#5872](https://github.com/ScoopInstaller/Scoop/issues/5872))
+- **shortcuts:** Output correctly formatted path ([#5333](https://github.com/ScoopInstaller/Scoop/issues/5333))
+- **update/uninstall:** Remove items from PATH correctly ([#5833](https://github.com/ScoopInstaller/Scoop/issues/5833))
+
+### Performance Improvements
+
+- **scoop-search:** Improve performance for local search ([#5644](https://github.com/ScoopInstaller/Scoop/issues/5644))
+- **scoop-update:** Check for running process before wasting time on download ([#5799](https://github.com/ScoopInstaller/Scoop/issues/5799))
+- **decompress:** Disable progress bar to improve `Expand-Archive` performance ([#5410](https://github.com/ScoopInstaller/Scoop/issues/5410))
+- **shim:** Update kiennq-shim to v3.1.1 ([#5841](https://github.com/ScoopInstaller/Scoop/issues/5841), [#5847](https://github.com/ScoopInstaller/Scoop/issues/5847))
+
+### Code Refactoring
+
+- **scoop-download:** Output more detailed manifest information ([#5277](https://github.com/ScoopInstaller/Scoop/issues/5277))
+- **core:** Cleanup some old codes, e.g., msi section and config migration ([#5715](https://github.com/ScoopInstaller/Scoop/issues/5715), [#5824](https://github.com/ScoopInstaller/Scoop/issues/5824))
+- **core:** Rewrite and separate path-related functions to `system.ps1` ([#5836](https://github.com/ScoopInstaller/Scoop/issues/5836), [#5858](https://github.com/ScoopInstaller/Scoop/issues/5858), [#5864](https://github.com/ScoopInstaller/Scoop/issues/5864))
+- **core:** Get rid of 'fullpath' ([#3533](https://github.com/ScoopInstaller/Scoop/issues/3533))
+- **git:** Use Invoke-Git() with direct path to git.exe to prevent spawning shim subprocesses ([#5122](https://github.com/ScoopInstaller/Scoop/issues/5122), [#5375](https://github.com/ScoopInstaller/Scoop/issues/5375))
+- **helper:** Remove 7zip's fallback '7zip-zstd' ([#5548](https://github.com/ScoopInstaller/Scoop/issues/5548))
+- **shim:** Remove CS shim codebase ([#5903](https://github.com/ScoopInstaller/Scoop/issues/5903))
+
+### Builds
+
+- **checkver:** Read the private_host config variable ([#5381](https://github.com/ScoopInstaller/Scoop/issues/5381))
+- **supporting:** Update Json to 13.0.3, Json.Schema to 3.0.15 ([#5835](https://github.com/ScoopInstaller/Scoop/issues/5835))
+
+### Continuous Integration
+
+- **dependabot:** Add dependabot.yml for GitHub Actions ([#5377](https://github.com/ScoopInstaller/Scoop/issues/5377))
+- **module:** Update 'psmodulecache' version to 'main' ([#5828](https://github.com/ScoopInstaller/Scoop/issues/5828))
+
+### Tests
+
+- **bucket:** Skip manifest validation if no manifest changes ([#5270](https://github.com/ScoopInstaller/Scoop/issues/5270))
+
+### Documentation
+
+- **scoop-info:** Fix help message([#5445](https://github.com/ScoopInstaller/Scoop/issues/5445))
+- **readme:** Improve documentation language ([#5638](https://github.com/ScoopInstaller/Scoop/issues/5638))
+
+## [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))
+- **shim:** fixed shim add bug related to Resolve-Path ([#5492](https://github.com/ScoopInstaller/Scoop/issues/5492))
+
+### 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' 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
+
+- **core:** Add `Get-Encoding` function to fix missing webclient encoding ([#4956](https://github.com/ScoopInstaller/Scoop/issues/4956))
+- **scoop-(un)hold:** Add `-g`/`--global` flag ([#4991](https://github.com/ScoopInstaller/Scoop/issues/4991))
+- **scoop-update:** Support `scoop update scoop` ([#4992](https://github.com/ScoopInstaller/Scoop/issues/4992))
+- **scoop-virustotal:** Migrate to VirusTotal API v3 ([#4983](https://github.com/ScoopInstaller/Scoop/issues/4983))
+
+### Bug Fixes
+
+- **manifest:** Fix bugs in 'Get-Manifest()' ([#4986](https://github.com/ScoopInstaller/Scoop/issues/4986))
+
+## [v0.2.1](https://github.com/ScoopInstaller/Scoop/compare/v0.2.0...v0.2.1) - 2022-06-10
+
+### Features
+
+- **core:** Add pre_uninstall and post_uninstall hooks ([#4957](https://github.com/ScoopInstaller/Scoop/issues/4957), [#4962](https://github.com/ScoopInstaller/Scoop/issues/4962))
+
+### Bug Fixes
+
+- **bucket:** Make sure `list_buckets` return array ([#4979](https://github.com/ScoopInstaller/Scoop/issues/4979))
+- **chore:** Deprecate tls1 and tls1.1 ([#4950](https://github.com/ScoopInstaller/Scoop/issues/4950))
+- **chore:** Update Nonportable bucket URL ([#4955](https://github.com/ScoopInstaller/Scoop/issues/4955))
+- **core:** Using `Invoke-Command` instead of `Invoke-Expression` ([#4941](https://github.com/ScoopInstaller/Scoop/issues/4941))
+- **core:** Load config file before initialization ([#4932](https://github.com/ScoopInstaller/Scoop/issues/4932))
+- **core:** Allow to use '_' and '.' in bucket name ([#4952](https://github.com/ScoopInstaller/Scoop/issues/4952))
+- **depends:** Avoid digits in archive file extension (except for .7z and .001) ([#4915](https://github.com/ScoopInstaller/Scoop/issues/4915))
+- **bucket:** Don't check remote URL of non-git buckets ([#4923](https://github.com/ScoopInstaller/Scoop/issues/4923))
+- **bucket:** Don't write message OK before bucket is cloned ([#4925](https://github.com/ScoopInstaller/Scoop/issues/4925))
+- **shim:** Add 'Get-CommandPath()' to find git ([#4913](https://github.com/ScoopInstaller/Scoop/issues/4913))
+- **shim:** Remove character replacement in .cmd -> .ps1 shims ([#4914](https://github.com/ScoopInstaller/Scoop/issues/4914))
+- **scoop:** Pass CLI arguments as string objects ([#4931](https://github.com/ScoopInstaller/Scoop/issues/4931))
+- **scoop-info:** Fix error message when manifest is not found ([#4935](https://github.com/ScoopInstaller/Scoop/issues/4935))
+- **scoop-search:** Require files in 'bucket' dir for remote known buckets ([#4944](https://github.com/ScoopInstaller/Scoop/issues/4944))
+- **update:** Prevent uninstall when update ([#4949](https://github.com/ScoopInstaller/Scoop/issues/4949))
+- **scoop-download:** Use correct Args when calling `Get-Manifest` ([#4970](https://github.com/ScoopInstaller/Scoop/issues/4970))
+
+### Code Refactoring
+
+- **manifest:** Rename 'Find-Manifest()' to 'Get-Manifest() ([#4966](https://github.com/ScoopInstaller/Scoop/issues/4966), [#4981](https://github.com/ScoopInstaller/Scoop/issues/4981))
+
+### Documentation
+
+- **readme:** Update license badge ([#4929](https://github.com/ScoopInstaller/Scoop/issues/4929))
+
+## [v0.2.0](https://github.com/ScoopInstaller/Scoop/compare/v0.1.0...v0.2.0) - 2022-05-10
+
+### Features
+
+- **relicense:** Relicense to dual-license (Unlicense or MIT) ([#4903](https://github.com/ScoopInstaller/Scoop/issues/4903), [#4870](https://github.com/ScoopInstaller/Scoop/issues/4870))
+- **install:** Allow downloading from private repositories ([#4254](https://github.com/ScoopInstaller/Scoop/issues/4254))
+- **scoop-cleanup:** Add `-a/--all` switch to cleanup all apps ([#4906](https://github.com/ScoopInstaller/Scoop/issues/4906))
+
+### Bug Fixes
+
+- **bucket:** Return empty list correctly in `Get-LocalBucket` ([#4885](https://github.com/ScoopInstaller/Scoop/issues/4885))
+- **install:** Fix issue with installation inside containers ([#4837](https://github.com/ScoopInstaller/Scoop/issues/4837))
+- **installed:** If no `$global`, check both local and global installed ([#4798](https://github.com/ScoopInstaller/Scoop/issues/4798))
+- **shim:** Manipulating shims with UTF8 encoding ([#4791](https://github.com/ScoopInstaller/Scoop/issues/4791), [#4813](https://github.com/ScoopInstaller/Scoop/issues/4813))
+- **shim:** Correctly quote $@ in sh->ps1 shims ([#4809](https://github.com/ScoopInstaller/Scoop/issues/4809))
+- **update:** Skip logs starting with `(chore)` ([#4800](https://github.com/ScoopInstaller/Scoop/issues/4800))
+- **scoop-download:** Add failure check ([#4822](https://github.com/ScoopInstaller/Scoop/issues/4822))
+- **scoop-list:** Fix date in 'Updated' column showing the months in the place of minutes ([#4880](https://github.com/ScoopInstaller/Scoop/issues/4880))
+- **scoop-prefix:** Fix typo that breaks global installed apps ([#4795](https://github.com/ScoopInstaller/Scoop/issues/4795))
+
+### Performance Improvements
+
+- **scoop:** Load libs only once ([#4839](https://github.com/ScoopInstaller/Scoop/issues/4839), [#4884](https://github.com/ScoopInstaller/Scoop/issues/4884))
+
+### Code Refactoring
+
+- **bucket:** Move 'Find-Manifest' and 'list_buckets' to 'buckets' ([#4814](https://github.com/ScoopInstaller/Scoop/issues/4814))
+- **relpath:** Use `$PSScriptRoot` instead of `relpath` ([#4793](https://github.com/ScoopInstaller/Scoop/issues/4793))
+- **reset_aliases:** Move core function of `reset_aliases` to `scoop` ([#4794](https://github.com/ScoopInstaller/Scoop/issues/4794))
+- **config:** Rename checkver_token to gh_token and SCOOP_CHECKVER_TOKEN to SCOOP_GH_TOKEN ([#4832](https://github.com/ScoopInstaller/Scoop/issues/4832), [#4842](https://github.com/ScoopInstaller/Scoop/issues/4842))
+
+### Builds
+
+- **checkver:** Add option to throw error as exception ([#4867](https://github.com/ScoopInstaller/Scoop/issues/4867))
+- **schema:** Remove 'description' from required fields ([#4853](https://github.com/ScoopInstaller/Scoop/issues/4853), [#4874](https://github.com/ScoopInstaller/Scoop/issues/4874))
+
+### Documentation
+
+- **changelog:** Rearrange CHANGELOG ([#4897](https://github.com/ScoopInstaller/Scoop/issues/4897))
+- **readme:** Update installation instruction ([#4825](https://github.com/ScoopInstaller/Scoop/issues/4825))
+- **readme:** Fix badges for Gitter and CI Tests ([#4830](https://github.com/ScoopInstaller/Scoop/issues/4830))
+- **scoop-shim:** Fix typo ([#4836](https://github.com/ScoopInstaller/Scoop/issues/4836))
+
+## [v0.1.0](https://github.com/ScoopInstaller/Scoop/compare/2021-12-26...v0.1.0) - 2022-03-01
+
+### Features
+
+- **scoop-bucket:** List more detailed information for buckets ([#4704](https://github.com/ScoopInstaller/Scoop/issues/4704), [#4756](https://github.com/ScoopInstaller/Scoop/issues/4756), [#4759](https://github.com/ScoopInstaller/Scoop/issues/4759))
+- **scoop-cache:** Handle multiple apps and show detailed information ([#4738](https://github.com/ScoopInstaller/Scoop/issues/4738))
+- **scoop-cat:** Use `bat` to pretty-print JSON ([#4742](https://github.com/ScoopInstaller/Scoop/issues/4742))
+- **scoop-config:** Allow Scoop to ignore running processes during reset/uninstall/update ([#4713](https://github.com/ScoopInstaller/Scoop/issues/4713), [#4731](https://github.com/ScoopInstaller/Scoop/issues/4731))
+- **scoop-config:** Show all settings ([#4765](https://github.com/ScoopInstaller/Scoop/issues/4765))
+- **scoop-download:** Add `scoop download` command ([#4621](https://github.com/ScoopInstaller/Scoop/issues/4621))
+- **scoop-(install|virustotal):** Allow skipping update check ([#4634](https://github.com/ScoopInstaller/Scoop/issues/4634))
+- **scoop-list:** Allow list manipulation ([#4718](https://github.com/ScoopInstaller/Scoop/issues/4718))
+- **scoop-list:** Show last-updated time ([#4723](https://github.com/ScoopInstaller/Scoop/issues/4723))
+- **scoop-info:** Revamp details and show more information ([#4747](https://github.com/ScoopInstaller/Scoop/issues/4747))
+- **scoop-shim:** Add `scoop shim` to manipulate shims ([#4727](https://github.com/ScoopInstaller/Scoop/issues/4727), [#4736](https://github.com/ScoopInstaller/Scoop/issues/4736))
+
+### Bug Fixes
+
+- **autoupdate:** Allow checksum file that contains whitespaces ([#4619](https://github.com/ScoopInstaller/Scoop/issues/4619))
+- **autoupdate:** Rename $response to $res ([#4706](https://github.com/ScoopInstaller/Scoop/issues/4706))
+- **config:** Ensure manipulating config with UTF8 encoding ([#4644](https://github.com/ScoopInstaller/Scoop/issues/4644))
+- **config:** Allow scoop config use Unicode characters ([#4631](https://github.com/ScoopInstaller/Scoop/issues/4631))
+- **config:** Fix `set_config` bugs ([#3681](https://github.com/ScoopInstaller/Scoop/issues/3681))
+- **current:** Remove 'current' while it's not a junction ([#4687](https://github.com/ScoopInstaller/Scoop/issues/4687))
+- **depends:** Prevent error on no URL ([#4595](https://github.com/ScoopInstaller/Scoop/issues/4595))
+- **depends:** Check if extractor is available ([#4042](https://github.com/ScoopInstaller/Scoop/issues/4042))
+- **decompress:** Fix nested Zstd archive extraction ([#4608](https://github.com/ScoopInstaller/Scoop/issues/4608), [#4639](https://github.com/ScoopInstaller/Scoop/issues/4639))
+- **installed:** Fix 'core/installed' that mark failed app as 'installed' ([#4650](https://github.com/ScoopInstaller/Scoop/issues/4650), [#4676](https://github.com/ScoopInstaller/Scoop/issues/4676), [#4689](https://github.com/ScoopInstaller/Scoop/issues/4689), [#4785](https://github.com/ScoopInstaller/Scoop/issues/4785))
+- **no-junctions:** Fix error when `NO_JUNCTIONS` is been set ([#4722](https://github.com/ScoopInstaller/Scoop/issues/4722), [#4726](https://github.com/ScoopInstaller/Scoop/issues/4726))
+- **shim:** Fix PS1 shim error when in different drive in PS7 ([#4614](https://github.com/ScoopInstaller/Scoop/issues/4614))
+- **shim:** Fix `sh` shim error in WSL ([#4637](https://github.com/ScoopInstaller/Scoop/issues/4637))
+- **shim:** Use `-file` instead of `-command` in ps1 script shims ([#4721](https://github.com/ScoopInstaller/Scoop/issues/4721))
+- **shim:** Fix exe shim when app path has white spaces ([#4734](https://github.com/ScoopInstaller/Scoop/issues/4734), [#4780](https://github.com/ScoopInstaller/Scoop/issues/4780))
+- **versions:** Fix wrong version number when only one version dir ([#4679](https://github.com/ScoopInstaller/Scoop/issues/4679))
+- **versions:** Get current version from failed installation if possible ([#4720](https://github.com/ScoopInstaller/Scoop/issues/4720), [#4725](https://github.com/ScoopInstaller/Scoop/issues/4725))
+- **scoop-alias:** Fix alias initialization ([#4737](https://github.com/ScoopInstaller/Scoop/issues/4737))
+- **scoop-checkup:** Skip 'check_windows_defender' when have not admin privileges ([#4699](https://github.com/ScoopInstaller/Scoop/issues/4699))
+- **scoop-cleanup:** Remove apps other than current version ([#4665](https://github.com/ScoopInstaller/Scoop/issues/4665))
+- **scoop-search:** Remove redundant 'bucket/' in search result ([#4773](https://github.com/ScoopInstaller/Scoop/issues/4773))
+- **scoop-update:** Skip updating non git buckets ([#4670](https://github.com/ScoopInstaller/Scoop/issues/4670), [#4672](https://github.com/ScoopInstaller/Scoop/issues/4672))
+
+### Performance Improvements
+
+- **uninstall:** Avoid checking all files for unlinking persisted data ([#4681](https://github.com/ScoopInstaller/Scoop/issues/4681), [#4763](https://github.com/ScoopInstaller/Scoop/issues/4763))
+
+### Code Refactoring
+
+- **depends:** Rewrite 'depends.ps1' ([#4638](https://github.com/ScoopInstaller/Scoop/issues/4638), [#4673](https://github.com/ScoopInstaller/Scoop/issues/4673))
+- **mklink:** Use 'New-Item' instead of 'mklink' ([#4690](https://github.com/ScoopInstaller/Scoop/issues/4690))
+- **rmdir:** Use 'Remove-Item' instead of 'rmdir' ([#4691](https://github.com/ScoopInstaller/Scoop/issues/4691))
+- **COMSPEC:** Deprecate use of subshell cmd.exe ([#4692](https://github.com/ScoopInstaller/Scoop/issues/4692))
+- **git:** Use 'git -C' to specify the work directory instead of 'Push-Location'/'Pop-Location' ([#4697](https://github.com/ScoopInstaller/Scoop/issues/4697))
+- **scoop-info:** Use List View for output ([#4741](https://github.com/ScoopInstaller/Scoop/issues/4741))
+- **scoop-config:** Use underscores everywhere ([#4745](https://github.com/ScoopInstaller/Scoop/issues/4745))
+
+### Builds
+
+- **checkver:** Fix output with '-Version' ([#3774](https://github.com/ScoopInstaller/Scoop/issues/3774))
+- **schema:** Add '$schema' property ([#4623](https://github.com/ScoopInstaller/Scoop/issues/4623))
+- **schema:** Add explicit escape to opening bracket matcher in jp/jsonpath regex ([#3719](https://github.com/ScoopInstaller/Scoop/issues/3719))
+- **schema:** Fix typo ('note' -> 'notes') ([#4678](https://github.com/ScoopInstaller/Scoop/issues/4678))
+- **tests:** Support both AppVeyor and GitHub Actions ([#4655](https://github.com/ScoopInstaller/Scoop/issues/4655))
+- **tests:** Run GitHub Actions CI on each commit ([#4664](https://github.com/ScoopInstaller/Scoop/issues/4664))
+- **tests:** Use cache in GitHub Actions ([#4671](https://github.com/ScoopInstaller/Scoop/issues/4671))
+- **tests:** Disable CI test on 'push' ([#4677](https://github.com/ScoopInstaller/Scoop/issues/4677))
+- **vscode-settings:** Remove 'formatOnSave' trigger ([#4635](https://github.com/ScoopInstaller/Scoop/issues/4635))
+
+### Styles
+
+- **test:** Format scripts by VSCode's PowerShell extension ([#4609](https://github.com/ScoopInstaller/Scoop/issues/4609))
+- **style:** Use correct casing for `$PSScriptRoot` ([#4775](https://github.com/ScoopInstaller/Scoop/issues/4775))
+
+### Tests
+
+- **test-bin:** Only write output file in CI and fix trailing whitespaces ([#4613](https://github.com/ScoopInstaller/Scoop/issues/4613))
+- **manifest:** Fix manifests validation ([#4620](https://github.com/ScoopInstaller/Scoop/issues/4620))
+- **zstd:** Fix 'zstd' extraction error in test ([#4651](https://github.com/ScoopInstaller/Scoop/issues/4651))
+
+### Documentation
+
+- **changelog:** Add 'CHANGLOG.md' ([#4600](https://github.com/ScoopInstaller/Scoop/issues/4600))
+- **changelog:** Rearrange CHANGELOG ([#4729](https://github.com/ScoopInstaller/Scoop/issues/4729))
+- **changelog:** Link CHANGELOG headers to 'releases/tag' ([#4730](https://github.com/ScoopInstaller/Scoop/issues/4730))
+
+## [2021-12-26](https://github.com/ScoopInstaller/Scoop/compare/2021-11-22...2021-12-26)
+
+### Features
+
+- **core:** Redirect 'StandardError' in `Invoke-ExternalCommand()` ([#4570](https://github.com/ScoopInstaller/Scoop/issues/4570), [#4582](https://github.com/ScoopInstaller/Scoop/issues/4582))
+- **install:** Add portableapps.com to strip_filename skips ([#3244](https://github.com/ScoopInstaller/Scoop/issues/3244))
+- **install:** Show manifest on installation ([#4155](https://github.com/ScoopInstaller/Scoop/issues/4155), [fb496c48](https://github.com/ScoopInstaller/Scoop/commit/fb496c482bec4063e01b328f943224ab703dbbd8), [#4581](https://github.com/ScoopInstaller/Scoop/issues/4581))
+- **template:** Add issue/PR templates ([#4572](https://github.com/ScoopInstaller/Scoop/issues/4572))
+- **scoop-cat:** Add `scoop cat` command ([#4532](https://github.com/ScoopInstaller/Scoop/issues/4532))
+- **scoop-config:** Document all configuration options ([#4579](https://github.com/ScoopInstaller/Scoop/issues/4579))
+
+### Bug Fixes
+
+- **bucket:** Remove JetBrains bucket ([dec25980](https://github.com/ScoopInstaller/Scoop/commit/dec25980525a81c176b3fd5f238e964db00f3be3))
+- **bucket:** Remove nightlies bucket ([48b035d7](https://github.com/ScoopInstaller/Scoop/commit/48b035d7f99baa2e81d87ead4ff03a9594e49c3d))
+- **core:** Escape '.' in 'parse_app()'. ([#4578](https://github.com/ScoopInstaller/Scoop/issues/4578))
+- **core:** Use '-Encoding ASCII' in 'Out-File' ([#4571](https://github.com/ScoopInstaller/Scoop/issues/4571))
+- **depends:** Specify function scope ([4d5fee36](https://github.com/ScoopInstaller/Scoop/commit/4d5fee36e1ed13fc850fd22a5414186aec030c6e))
+- **install:** Use `Select-CurrentVersion` ([#4535](https://github.com/ScoopInstaller/Scoop/issues/4535))
+- **install:** 'env_add_path' doesn't append '.' ([#4550](https://github.com/ScoopInstaller/Scoop/issues/4550))
+- **repo:** Update repo links ([cbe29edd](https://github.com/ScoopInstaller/Scoop/commit/cbe29eddb3475e34740300eb1c2c52715446e3be))
+- **scoop-update:** Update apps with '--all' ([ac71fccb](https://github.com/ScoopInstaller/Scoop/commit/ac71fccbecb3d4158f249db9c1b9bb043cb8e966))
+- **scoop-update:** Fix scoop update -a requiring arguments ([#4531](https://github.com/ScoopInstaller/Scoop/issues/4531))
+
+### Code Refactoring
+
+- **shim:** Rework shimming logic ([#4543](https://github.com/ScoopInstaller/Scoop/issues/4543), [#4555](https://github.com/ScoopInstaller/Scoop/issues/4555), [3c90d1a0](https://github.com/ScoopInstaller/Scoop/commit/3c90d1a0701b0b64730dbf9ebc8d31f9b9c238f1), [2ec00d57](https://github.com/ScoopInstaller/Scoop/commit/2ec00d576c7e594dc5c0f1eac4536c5310ce6f17))
+
+### Builds
+
+- **auto-pr:** Remove hardcoded 'master' branch ([#4567](https://github.com/ScoopInstaller/Scoop/issues/4567))
+- **checkver:** Improve JSONPath extraction support ([#4522](https://github.com/ScoopInstaller/Scoop/issues/4522))
+- **checkver:** Use GitHub token from environment ([#4557](https://github.com/ScoopInstaller/Scoop/issues/4557))
+- **schema:** Enable autoupdate for 'license' ([#4528](https://github.com/ScoopInstaller/Scoop/issues/4528), [#4596](https://github.com/ScoopInstaller/Scoop/issues/4596))
+
+### Documentation
+
+- **readme:** Add link to Contributing Guide ([5e11c94a](https://github.com/ScoopInstaller/Scoop/commit/5e11c94a544ff2adbdbec5072c32a94d3e5acb9c))
+- **readme:** Fix links ([3bb7036e](https://github.com/ScoopInstaller/Scoop/commit/3bb7036ee111bfe58e82ba3d0fd39189b058776a))
+
+### Reverts
+
+- **shim:** Revert [#4229](https://github.com/ScoopInstaller/Scoop/issues/4229) ([#4553](https://github.com/ScoopInstaller/Scoop/issues/4553))
+
+## [2021-11-22](https://github.com/ScoopInstaller/Scoop/compare/2020-11-26...2021-11-22)
+
+### Features
+
+- **bucket:** Move extras bucket to [@ScoopInstaller](https://github.com/ScoopInstaller) ([3e9a4d4e](https://github.com/ScoopInstaller/Scoop/commit/3e9a4d4ea0e7e4d6489099c46a763f58db07e633))
+- **decompress:** Support Zstandard archive ([#4372](https://github.com/ScoopInstaller/Scoop/issues/4372), [e35ff313](https://github.com/ScoopInstaller/Scoop/commit/e35ff313a5d35cab1049024938c3423a5f6bf060), [47ebc6f1](https://github.com/ScoopInstaller/Scoop/commit/47ebc6f176b0db0afeb51b4ee237a20b2d8649e9))
+- **install:** Handle arch-specific env_add_path ([#4013](https://github.com/ScoopInstaller/Scoop/issues/4013))
+- **install:** s/lukesamson/ScoopInstaller in install.ps1 ([5226f26f](https://github.com/ScoopInstaller/Scoop/commit/5226f26f18157ed78f1529144404ec682374452e))
+- **message:** Add config to disable aria2 warning message ([#4422](https://github.com/ScoopInstaller/Scoop/issues/4422))
+- **shim:** Add another alternative shim written in rust ([#4229](https://github.com/ScoopInstaller/Scoop/issues/4229))
+- **scoop-prefix:** Remove unused imports and functions ([#4494](https://github.com/ScoopInstaller/Scoop/issues/4494))
+- **scoop-install:** Auto uninstall previous failed installation ([#3281](https://github.com/ScoopInstaller/Scoop/issues/3281))
+- **scoop-update:** Add flags `--all` as an alternative to '*' to update all ([#3871](https://github.com/ScoopInstaller/Scoop/issues/3871))
+
+### Bug Fixes
+
+- **core:** Change url() scope to avoid conflict with global aliases ([#4342](https://github.com/ScoopInstaller/Scoop/issues/4342), [#4492](https://github.com/ScoopInstaller/Scoop/issues/4492))
+- **install:** Fix `aria2`'s resume download feature ([#3292](https://github.com/ScoopInstaller/Scoop/issues/3292))
+- **shim:** Fixed trailing whitespace issue ([#4307](https://github.com/ScoopInstaller/Scoop/issues/4307))
+- **scoop-reset:** Skip when app instance is running ([#4359](https://github.com/ScoopInstaller/Scoop/issues/4359))
+
+### Code Refactoring
+
+- **versions:** Refactor 'versions.ps1' ([#3721](https://github.com/ScoopInstaller/Scoop/issues/3721), [e6630272](https://github.com/ScoopInstaller/Scoop/commit/e663027299d03ca768a252fa4bcbc51d124d4cae), [ae892138](https://github.com/ScoopInstaller/Scoop/commit/ae892138423bb9bbf54c8f0bed8331b93199f6b8))
+
+### Builds
+
+- **autoupdate:** Add multiple URL/hash/extract_dir... support ([#3518](https://github.com/ScoopInstaller/Scoop/issues/3518), [#4502](https://github.com/ScoopInstaller/Scoop/issues/4502))
+- **schema:** Fix Schema to support `+` in version ([#4504](https://github.com/ScoopInstaller/Scoop/issues/4504))
+- **supporting:** Update Json to 12.0.3, Json.Schema to 3.0.14 ([#3352](https://github.com/ScoopInstaller/Scoop/issues/3352))
+
+### Documentation
+
+- **readme:** Capitalize to prevent redirect ([#4483](https://github.com/ScoopInstaller/Scoop/issues/4483))
+- **readme:** s/lukesampson/ScoopInstaller in readme ([4f5acd72](https://github.com/ScoopInstaller/Scoop/commit/4f5acd72109a98a148d1bfa269c23a2d43644d23))
+- **readme:** Update extras bucket url in readme ([f1a46e10](https://github.com/ScoopInstaller/Scoop/commit/f1a46e109596c55c7e83c77fc1fc9daedbe71636))
+- **readme:** Update Java bucket text ([#4514](https://github.com/ScoopInstaller/Scoop/issues/4514))
+- **readme:** Update notes about the NirSoft bucket ([#4524](https://github.com/ScoopInstaller/Scoop/issues/4524))
+
+## [2020-11-26](https://github.com/ScoopInstaller/Scoop/compare/2020-10-22...2020-11-26)
+
+### Bug Fixes
+
+- **shim:** Fix Makefile typo ([0948824e](https://github.com/ScoopInstaller/Scoop/commit/0948824ec7269c979882d09342d9a269193cd674)) ([227de6cf](https://github.com/ScoopInstaller/Scoop/commit/227de6cfb8433a86ac0f0a279e691327ae04554c))
+
+## [2020-10-22](https://github.com/ScoopInstaller/Scoop/compare/2019-10-23...2020-10-22)
+
+### Features
+
+- **aria2:** Inline progress ([#3987](https://github.com/ScoopInstaller/Scoop/issues/3987))
+- **autoupdate:** Add $urlNoExt and $basenameNoExt substitutions ([#3742](https://github.com/ScoopInstaller/Scoop/issues/3742))
+- **config:** Add configuration option for default architecture ([#3778](https://github.com/ScoopInstaller/Scoop/issues/3778))
+- **install:** Follow HTTP redirections when downloading a file ([#3902](https://github.com/ScoopInstaller/Scoop/issues/3902))
+- **install:** Let pathes in 'env_add_path' be added ascendantly ([#3788](https://github.com/ScoopInstaller/Scoop/issues/3788), [#3976](https://github.com/ScoopInstaller/Scoop/issues/3976))
+- **list:** Display main bucket name ([#3759](https://github.com/ScoopInstaller/Scoop/issues/3759))
+- **shim:** Add alt-shim support ([#3998](https://github.com/ScoopInstaller/Scoop/issues/3998))
+- **scoop-checkup:** Add check_envs_requirements ([#3860](https://github.com/ScoopInstaller/Scoop/issues/3860))
+
+### Bug Fixes
+
+- **bucket:** Update scoop-nonportable URL ([#3776](https://github.com/ScoopInstaller/Scoop/issues/3776))
+- **download:** Fosshub download ([#4051](https://github.com/ScoopInstaller/Scoop/issues/4051))
+- **download:** Progress bar on small files ([96de9c14](https://github.com/ScoopInstaller/Scoop/commit/96de9c14bb483f9278e4b0a9e22b1923ee752901))
+- **hold:** Replace "locked" terminology with "held" for consistency ([#3917](https://github.com/ScoopInstaller/Scoop/issues/3917))
+- **git:** Don't execute autostart programs when executing git commands ([#3993](https://github.com/ScoopInstaller/Scoop/issues/3993))
+- **git:** Enforce pull without rebase ([#3765](https://github.com/ScoopInstaller/Scoop/issues/3765))
+- **install:** Aria2 inline progress negative values ([#4053](https://github.com/ScoopInstaller/Scoop/issues/4053))
+- **install:** Fix wrong output of 'install/failed' ([#3784](https://github.com/ScoopInstaller/Scoop/issues/3784), [#3867](https://github.com/ScoopInstaller/Scoop/issues/3867))
+- **install:** Re-add "Don't send referer to portableapps.com" ([#3961](https://github.com/ScoopInstaller/Scoop/issues/3961))
+- **scoop:** Remove temporary code from the scoop executable ([#3898](https://github.com/ScoopInstaller/Scoop/issues/3898))
+- **update:** Update outdated PowerShell 5 warning ([#3986](https://github.com/ScoopInstaller/Scoop/issues/3986))
+- **scoop-info:** Check bucket of installed app ([#3740](https://github.com/ScoopInstaller/Scoop/issues/3740))
+
+### Builds
+
+- **checkver:** Present script property ([#3900](https://github.com/ScoopInstaller/Scoop/issues/3900))
+
+### Tests
+
+- **init:** Force pester v4 ([#4040](https://github.com/ScoopInstaller/Scoop/issues/4040))
+
+## [2019-10-23](https://github.com/ScoopInstaller/Scoop/compare/2019-10-18...2019-10-23)
+
+### Features
+
+- **update:** Support $persist_dir in uninstaller.script ([#3692](https://github.com/ScoopInstaller/Scoop/issues/3692))
+
+### Bug Fixes
+
+- **core:** Use [Environment]::Is64BitOperatingSystem instead of [intptr]::size ([#3690](https://github.com/ScoopInstaller/Scoop/issues/3690))
+- **git:** Remove unnecessary git_proxy_cmd() calls for local commands ([8ee45a57](https://github.com/ScoopInstaller/Scoop/commit/8ee45a57dc01a525dcf8776bf9bb45263992c81f))
+- **install:** Check execution policy ([#3619](https://github.com/ScoopInstaller/Scoop/issues/3619))
+- **update:** Fix scoop update changelog output ([e997017f](https://github.com/ScoopInstaller/Scoop/commit/e997017f1a03e2eefef2157acdfefe2e4fced896))
+
+## [2019-10-18](https://github.com/ScoopInstaller/Scoop/compare/2019-06-24...2019-10-18)
+
+### Features
+
+- **core:** Tweak Invoke-ExternalCommand parameters ([#3547](https://github.com/ScoopInstaller/Scoop/issues/3547))
+- **install:** Use 7zip when available for faster zip file extraction ([#3460](https://github.com/ScoopInstaller/Scoop/issues/3460))
+- **install:** Add arch support to `env_add_path` and `env_set` ([#3503](https://github.com/ScoopInstaller/Scoop/issues/3503))
+- **install:** Allow $version to be used in uninstaller scripts ([#3592](https://github.com/ScoopInstaller/Scoop/issues/3592))
+- **install:** Allow installing specific version if latest is installed ([11c42d78](https://github.com/ScoopInstaller/Scoop/commit/11c42d782f8adb29fbe0d94daa5f121cdda935ab))
+- **update:** Allow updating apps from local manifest or URL ([#3685](https://github.com/ScoopInstaller/Scoop/issues/3685))
+
+### Bug Fixes
+
+- **autoupdate:** Decode basename when extract hash ([#3615](https://github.com/ScoopInstaller/Scoop/issues/3615))
+- **autoupdate:** Remove any whitespace from hash ([#3579](https://github.com/ScoopInstaller/Scoop/issues/3579))
+- **bucket:** Only lookup directories in buckets folder ([#3631](https://github.com/ScoopInstaller/Scoop/issues/3631))
+- **comspec:** Escape variables when calling COMSPEC commands ([#3538](https://github.com/ScoopInstaller/Scoop/issues/3538))
+- **decompress:** Fix bugs on extract_dir ([#3540](https://github.com/ScoopInstaller/Scoop/issues/3540))
+- **editorconfig:** Add missing } to bat/cmd regex ([#3529](https://github.com/ScoopInstaller/Scoop/issues/3529))
+- **help:** Rename help() to scoop_help() ([#3564](https://github.com/ScoopInstaller/Scoop/issues/3564))
+- **install:** Use Join-Path instead of string gluing. ([#3566](https://github.com/ScoopInstaller/Scoop/issues/3566))
+- **scoop-info:** Fix output for single binaries with alias ([#3651](https://github.com/ScoopInstaller/Scoop/issues/3651))
+- **scoop-info:** Remove a whitespace ([#3652](https://github.com/ScoopInstaller/Scoop/issues/3652))
+
+### Builds
+
+- **auto-pr:** Fix git status detection ([7decfd4c](https://github.com/ScoopInstaller/Scoop/commit/7decfd4c107b8d8a59d7eedfe8a56e1801120c2f))
+- **auto-pr:** Hard reset bucket after running ([79f8538b](https://github.com/ScoopInstaller/Scoop/commit/79f8538b57b9021db71a279879b9032fefd1ae52))
+- **checkurls:** Trim renaming suffix in url ([#3677](https://github.com/ScoopInstaller/Scoop/issues/3677))
+
+### Continuous Integration
+
+- **appveyor:** use VS2019 image to fix PS6 issues ([#3646](https://github.com/ScoopInstaller/Scoop/issues/3646))
+- **tests:** Do not force maintainers to have SCOOP_HELPERS ([#3604](https://github.com/ScoopInstaller/Scoop/issues/3604))
+
+### Documentation
+
+- **readme:** Improve installation instructions ([#3600](https://github.com/ScoopInstaller/Scoop/issues/3600))
+
+## [2019-06-24](https://github.com/ScoopInstaller/Scoop/compare/2019-05-15...2019-06-24)
+
+### Features
+
+- **decompress:** Add 'ExtractDir' to 'Expand-...' functions ([#3466](https://github.com/ScoopInstaller/Scoop/issues/3466), [#3470](https://github.com/ScoopInstaller/Scoop/issues/3470), [#3472](https://github.com/ScoopInstaller/Scoop/issues/3472))
+- **decompress:** Allow 'Expand-InnoArchive -ExtractDir' to accept '{xxx}' ([#3487](https://github.com/ScoopInstaller/Scoop/issues/3487))
+
+### Bug Fixes
+
+- **config:** Show correct output when removing a config value ([#3462](https://github.com/ScoopInstaller/Scoop/issues/3462))
+- **decompress:** Change dark.exe parameter order ([6141e46d](https://github.com/ScoopInstaller/Scoop/commit/6141e46d6ae74b3ccf65e02a1c3fc92e1b4d3e7a))
+- **proxy:** Rename parameters for Net.NetworkCredential ([#3483](https://github.com/ScoopInstaller/Scoop/issues/3483))
+
+### Code Refactoring
+
+- **core:** `run()` -> 'Invoke-ExternalCommand()' ([#3432](https://github.com/ScoopInstaller/Scoop/issues/3432))
+
+### Builds
+
+- **checkhashes:** Checkhashes downloading twice when architecture properties does hot have url property ([#3479](https://github.com/ScoopInstaller/Scoop/issues/3479))
+- **checkhashes:** Do not call scoop directly ([#3527](https://github.com/ScoopInstaller/Scoop/issues/3527))
+
+### Documentation
+
+- **readme:** Add known buckets to end of readme ([2849e0f9](https://github.com/ScoopInstaller/Scoop/commit/2849e0f96099004f761d7d8c715377e0d2c105f2))
+- **readme:** Adjust URL of `runat.json` ([#3484](https://github.com/ScoopInstaller/Scoop/issues/3484))
+- **readme:** Fix a small typo ([#3512](https://github.com/ScoopInstaller/Scoop/issues/3512))
+- **readme:** Fix typo in readme ([03bb07c8](https://github.com/ScoopInstaller/Scoop/commit/03bb07c8231563fa3a2092b9b52d4dde372f2a8e))
+- **readme:** Update readme with correct count of nirsoft apps ([e8d0be66](https://github.com/ScoopInstaller/Scoop/commit/e8d0be663b3bab25d9ee55c597b90bf922f4ec5d))
+
+## [2019-05-15](https://github.com/ScoopInstaller/Scoop/compare/2019-05-12...2019-05-15)
+
+### Features
+
+- **manifest:** XPath support in checkver and autoupdate ([#3458](https://github.com/ScoopInstaller/Scoop/issues/3458))
+- **update:** Support changing scoop tracking repository ([#3459](https://github.com/ScoopInstaller/Scoop/issues/3459))
+
+### Bug Fixes
+
+- **autoupdate:** Handle xml namespace in xpath mode ([#3465](https://github.com/ScoopInstaller/Scoop/issues/3465))
+
+## [2019-05-12](https://github.com/ScoopInstaller/Scoop/releases/tag/2019-05-12)
+
+### BREAKING CHANGE
+
+- **core:** Finalize bucket extraction ([#3399](https://github.com/ScoopInstaller/Scoop/issues/3399))
+- **core:** Bucket extraction and refactoring ([#3449](https://github.com/ScoopInstaller/Scoop/issues/3449))
+
+### Features
+
+- **autoupdate:** Add 'regex' alias for 'find' ([3453487e](https://github.com/ScoopInstaller/Scoop/commit/3453487ed65378cc9ba2efc658ed6bc1431ef463))
+- **autoupdate:** Allow simple metalink and meta4 hash extraction ([ecf627c3](https://github.com/ScoopInstaller/Scoop/commit/ecf627c3b8493b3ccf7ddb882b0c946533774d76))
+- **autoupdate:** Add version variables to autoupdate.hash.regex ([#2966](https://github.com/ScoopInstaller/Scoop/issues/2996))
+- **autoupdate:** Autoupdate improvements ([#1371](https://github.com/ScoopInstaller/Scoop/issues/1371))
+- **autoupdate:** Convert base64 encoded hash values ([04c9ddeb](https://github.com/ScoopInstaller/Scoop/commit/04c9ddeb6d3b99496c39543ad468d34f4f1adeff))
+- **autoupdate:** Improve base64 hash detection ([310096e2](https://github.com/ScoopInstaller/Scoop/commit/310096e2386ff3bf9082d547b140a98b92b87a83))
+- **core:** Add basic WSL support by appending .exe to powershell ([#2323](https://github.com/ScoopInstaller/Scoop/issues/2323))
+- **core:** Add Expand-DarkArchive and some other dependency features ([#3450](https://github.com/ScoopInstaller/Scoop/issues/3450))
+- **core:** Enable TLS 1.2 in core.ps1 ([#2074](https://github.com/ScoopInstaller/Scoop/issues/2074))
+- **core:** Prepare extraction of main bucket ([#3060](https://github.com/ScoopInstaller/Scoop/issues/3060))
+- **core:** Support loading basedirs from config ([#3121](https://github.com/ScoopInstaller/Scoop/issues/3121))
+- **core:** Update requirement to version 5 or greater ([#3330](https://github.com/ScoopInstaller/Scoop/issues/3330))
+- **core:** Use consistent User-Agent Header on all webrequests ([12962acf](https://github.com/ScoopInstaller/Scoop/commit/12962acfa853593e371d09186e51660aece331e5))
+- **core:** Warn on shim overwrite ([#2033](https://github.com/ScoopInstaller/Scoop/issues/2033))
+- **debug:** Add option to indent debug output ([bf54a978](https://github.com/ScoopInstaller/Scoop/commit/bf54a978a1bc2efcde52513a60ec5bcb7bb1a44e))
+- **decompress:** Allow other args to be passthrough ([#3411](https://github.com/ScoopInstaller/Scoop/issues/3411))
+- **download:** Add support for multi-connection downloads via aria2c ([#2312](https://github.com/ScoopInstaller/Scoop/issues/2312))
+- **download:** Convert sourceforge urls to use downloads mirror ([#3340](https://github.com/ScoopInstaller/Scoop/issues/3340))
+- **install:** Add .NET 4.5 check to scoop install script ([e52c24c9](https://github.com/ScoopInstaller/Scoop/commit/e52c24c94ec805a327440cc07aec699afc7cc308))
+- **install:** Set file write permission to global persist dir ([#2524](https://github.com/ScoopInstaller/Scoop/issues/2524))
+- **json:** Normalize multi-line strings to string arrays on format ([#2444](https://github.com/ScoopInstaller/Scoop/issues/2444))
+- **persist:** Support persisting files without a file extension ([#2408](https://github.com/ScoopInstaller/Scoop/issues/2408))
+- **shim:** Add '.com'-type shim ([#3366](https://github.com/ScoopInstaller/Scoop/issues/3366))
+- **shim:** Enabled applications which require elevated privileges ([#2053](https://github.com/ScoopInstaller/Scoop/issues/2053))
+- **shim:** Enabled shimming of external applications ([#2072](https://github.com/ScoopInstaller/Scoop/issues/2072))
+- **shim:** Enabled wide characters forwarding in shims ([#2106](https://github.com/ScoopInstaller/Scoop/issues/2106))
+- **shim:** Make shim support PowerShell 2.0 ([#2562](https://github.com/ScoopInstaller/Scoop/issues/2562))
+- **shim:** Create sh shim ([#1951](https://github.com/ScoopInstaller/Scoop/issues/1951))
+- **shortcuts:** Add subdirectories/arguments for shortcuts ([#1945](https://github.com/ScoopInstaller/Scoop/issues/1945))
+- **shortcuts:** Allow $dir, $original_dir and $persist_dir substitutions for shortcuts ([f3ddf0c0](https://github.com/ScoopInstaller/Scoop/commit/f3ddf0c0f81ee2a11466edf5d9f6e38a0fc2b9d4))
+- **shortcuts:** Get start menu folder location from environment rather than predefined user profile path ([c245a7fe](https://github.com/ScoopInstaller/Scoop/commit/c245a7fe96ffa0b0fba23bd47f31480ea93cc183))
+- **uninstall:** Print purge step to console ([#3123](https://github.com/ScoopInstaller/Scoop/issues/3123))
+- **uninstall:** Add support for soft/purge uninstalling of scoop itself ([#2781](https://github.com/ScoopInstaller/Scoop/issues/2781))
+- **update:** Add hold/unhold command ([#3444](https://github.com/ScoopInstaller/Scoop/issues/3444))
+- **scoop-checkup:** Add NTFS check to checkup command ([#1944](https://github.com/ScoopInstaller/Scoop/issues/1944))
+- **scoop-checkup:** Check for LongPaths setting ([#3387](https://github.com/ScoopInstaller/Scoop/issues/3387))
+- **scoop-info:** Add scoop-info command ([#2165](https://github.com/ScoopInstaller/Scoop/issues/2165))
+- **scoop-info:** Support url manifest ([#2538](https://github.com/ScoopInstaller/Scoop/issues/2538))
+- **scoop-prefix:** Add scoop prefix command ([#2117](https://github.com/ScoopInstaller/Scoop/issues/2117))
+- **scoop-update:** Add notification for new main bucket ([#3392](https://github.com/ScoopInstaller/Scoop/issues/3392))
+- **scoop-update:** Show changelog after updating scoop and buckets ([56c35f8f](https://github.com/ScoopInstaller/Scoop/commit/56c35f8f05ed387997ef1a80ec0362adec6e51a5))
+- **scoop-which:** Also show other applications in PATH with 'scoop which' ([79bf99c3](https://github.com/ScoopInstaller/Scoop/commit/79bf99c3c110494d799e147263db7b6f2f921d4e))
+
+### Bug Fixes
+
+- **autoupdate:** Fix base64 hash extraction ([98afb999](https://github.com/ScoopInstaller/Scoop/commit/98afb99990561c4f98f1e1334f348e52b4bee4e7))
+- **autoupdate:** Fix base64 hash extraction length ([#2852](https://github.com/ScoopInstaller/Scoop/issues/2852))
+- **autoupdate:** Fix metalink hash extraction ([2ad54747](https://github.com/ScoopInstaller/Scoop/commit/2ad547477b1432e7a269c90b393d62d88dce9803))
+- **autoupdate:** Fix single line hash extraction ([#3015](https://github.com/ScoopInstaller/Scoop/issues/3015))
+- **autoupdate:** Improve auto-update hash extraction regex ([21bf0dea](https://github.com/ScoopInstaller/Scoop/commit/21bf0dea561db021aa59bcd9363792436ac7c162))
+- **autoupdate:** Linter fix ([c9539b65](https://github.com/ScoopInstaller/Scoop/commit/c9539b6575e8842a8f895d82b4119c3aef01d7c2))
+- **autoupdate:** Use normal variable instead of magic $matches variable name ([d74e0a85](https://github.com/ScoopInstaller/Scoop/commit/d74e0a85b4081745bd1ab107a45794f02299737d))
+- **bucket:** Change wording of new_issue_msg() ([e82587df](https://github.com/ScoopInstaller/Scoop/commit/e82587dfc41618474e03347df333e847dfaffc70))
+- **bucket:** Fix new_issue_msg ([#3375](https://github.com/ScoopInstaller/Scoop/issues/3375))
+- **bucket:** Use $_.Name on gci result ([1eb2609d](https://github.com/ScoopInstaller/Scoop/commit/1eb2609db51587772a4b5d1b6f58114f52639568))
+- **config:** Enable writing to hidden .scoop file ([#1982](https://github.com/ScoopInstaller/Scoop/issues/1982))
+- **config:** Save and load true/false values as booleans in scoops config ([16aec1a4](https://github.com/ScoopInstaller/Scoop/commit/16aec1a40b45ba241ef2ac45ccf89de7206891be))
+- **core:** Allowed underscores in package names ([#2930](https://github.com/ScoopInstaller/Scoop/issues/2930))
+- **core:** Clean up some error messages ([#2032](https://github.com/ScoopInstaller/Scoop/issues/2032))
+- **core:** Change sf regex not to break some manifests ([#2476](https://github.com/ScoopInstaller/Scoop/issues/2476))
+- **core:** Check if 7zip installed via Scoop instead of using 7z.exe from PATH ([55ce0c0b](https://github.com/ScoopInstaller/Scoop/commit/55ce0c0b0c481ec3807655cb7aeac6dfcf9ef271))
+- **core:** Filter null or empty string from Scoops directory settings ([5d5c7fa9](https://github.com/ScoopInstaller/Scoop/commit/5d5c7fa91c03f05b705d3420618ec96d8e870174))
+- **core:** Fix "enable-encryptionscheme" for OSes before Windows 10 ([#2084](https://github.com/ScoopInstaller/Scoop/issues/2084))
+- **core:** Fix bug with Start-Process -Wait, exclusive to PowerShell Core on Windows 7 ([#3415](https://github.com/ScoopInstaller/Scoop/issues/3415))
+- **core:** Fix for relative paths ([ff9c0c3d](https://github.com/ScoopInstaller/Scoop/commit/ff9c0c3dafb3567ee958379b83205da84a925ecf))
+- **core:** Fix robocopy not releasing a directory after moving it ([e2792f2e](https://github.com/ScoopInstaller/Scoop/commit/e2792f2e02adee5947ebb95022a62282fb61024f))
+- **core:** Fix substitute() for arrays ([#2048](https://github.com/ScoopInstaller/Scoop/issues/2048))
+- **core:** Format hashes to lowercase ([5d56f8ff](https://github.com/ScoopInstaller/Scoop/commit/5d56f8ff5760ddedaf44eaf9652000e833b0944e))
+- **core:** Invoke powershell with -noprofile flag from bash shims ([#3165](https://github.com/ScoopInstaller/Scoop/issues/3165))
+- **core:** Removed the bucket from the app name when checking directories ([#2435](https://github.com/ScoopInstaller/Scoop/issues/2435))
+- **core:** Return true for checking if a directory is 'in' itself ([ac8a1567](https://github.com/ScoopInstaller/Scoop/commit/ac8a156796cb6d3d9cba24a2839271d924ab8fea))
+- **core:** Store last update time as String ([e8af15cc](https://github.com/ScoopInstaller/Scoop/commit/e8af15cc0615b707aee79be95f9c00e3ae0bfd9b))
+- **decompress:** Add .bz2 files to decompression ([#2085](https://github.com/ScoopInstaller/Scoop/issues/2085))
+- **decompress:** Added retry when unzip fail because of AV ([#1822](https://github.com/ScoopInstaller/Scoop/issues/1822))
+- **decompress:** Catch unzip failures from bad file names ([#2472](https://github.com/ScoopInstaller/Scoop/issues/2472))
+- **decompress:** Compatible Expand-ZipArchive() with Pscx ([#3425](https://github.com/ScoopInstaller/Scoop/issues/3425))
+- **decompress:** Correct deprecation function name ([#3406](https://github.com/ScoopInstaller/Scoop/issues/3406))
+- **decompress:** Fix dark parameter order ([87a1e784](https://github.com/ScoopInstaller/Scoop/commit/87a1e784d7463fea36fa41fcb7cb5537cbcfdc52))
+- **depends:** Don't force adding dark dependency ([#3453](https://github.com/ScoopInstaller/Scoop/issues/3453))
+- **depends:** Don't include the requested app in the list of dependencies ([1bc6a479](https://github.com/ScoopInstaller/Scoop/commit/1bc6a479ee969e44e2b0d83ed6ff19efd86c6ae9))
+- **depends:** Fix empty bucket name ([#2827](https://github.com/ScoopInstaller/Scoop/issues/2827))
+- **depends:** Fix null reference error when no buckets are configured ([88040972](https://github.com/ScoopInstaller/Scoop/commit/88040972a30b459a3859c7c2f883e47e19da9f84))
+- **depends:** Show message about missing bucket when installing dependencies ([7a6218c5](https://github.com/ScoopInstaller/Scoop/commit/7a6218c58677170fe32cf1c2bfcfe7488e4c3655))
+- **download:** Don't send referer to portableapps.com ([0c2b3da3](https://github.com/ScoopInstaller/Scoop/commit/0c2b3da3ff639722ad3ddf587219bb3155e97c7f))
+- **download:** Fix fosshub downloads with aria2c ([803525a8](https://github.com/ScoopInstaller/Scoop/commit/803525a8661ffaa39fc4ad6f0dc776cccad4c45e))
+- **download:** Interrupt download causes partial cache file to be used for next install ([5be02865](https://github.com/ScoopInstaller/Scoop/commit/5be0286561398debfee2c0610e51f006ef2dc2fb))
+- **download:** Overwrite any existing files when extracting ([58cca68f](https://github.com/ScoopInstaller/Scoop/commit/58cca68f7565bd5e8f63e08ad052c0029b98a23d))
+- **download:** Show warning about SourceForge.net hash validation fails ([8504338b](https://github.com/ScoopInstaller/Scoop/commit/8504338bc5faab3235cef2e1c2f41abd7ae496eb))
+- **getopt:** Don't try to parse int arguments ([23fe5a53](https://github.com/ScoopInstaller/Scoop/commit/23fe5a5319d4ede84c532df04f576c3854fd5826))
+- **getopt:** Don't try to parse array arguments ([9b6e7b5e](https://github.com/ScoopInstaller/Scoop/commit/9b6e7b5e0f7f6ddecdb139f932ad7d582fe639a4))
+- **getopt:** Return remaining args, use getopt for scoop install ([b7cfd6fd](https://github.com/ScoopInstaller/Scoop/commit/b7cfd6fdb0e18a623ceacfa6fc824241dabc6d01))
+- **getopt:** Skip if arg is $null ([f2d9f0d7](https://github.com/ScoopInstaller/Scoop/commit/f2d9f0d79fdf4a63879c1b87a6c0f5317a40a1d9))
+- **getopt:** Skip arg if it's decimal ([5f0c8cfb](https://github.com/ScoopInstaller/Scoop/commit/5f0c8cfb0a34078bb8118a21191cf046ddad18ac))
+- **git:** Disable git pager when running git log ([cac99759](https://github.com/ScoopInstaller/Scoop/commit/cac9975924691fe6e608789218b06be56bb8c658))
+- **git:** Fix update log output ([0daa25c6](https://github.com/ScoopInstaller/Scoop/commit/0daa25c6300cd2ab605d63b71037d741c9c904c6))
+- **json:** Catch JsonReaderException ([fb58e92c](https://github.com/ScoopInstaller/Scoop/commit/fb58e92c13552199f19f5df112801fc41321eee2))
+- **install:** Add filename to warning for files without hash in the manifest ([4c9beee8](https://github.com/ScoopInstaller/Scoop/commit/4c9beee8f2df891b2ec314e1efffb2ee9d5cca20))
+- **install:** Add multi-line support to pre/post_install ([#1980](https://github.com/ScoopInstaller/Scoop/issues/1980))
+- **install:** Added exclusion for sourceforge. [#METR-21516] ([#2109](https://github.com/ScoopInstaller/Scoop/issues/2109))
+- **install:** Ignore url fragment for PowerShell Core 6.1.0 ([#2602](https://github.com/ScoopInstaller/Scoop/issues/2602))
+- **install:** Fix fail when installing from non-default bucket ([#2247](https://github.com/ScoopInstaller/Scoop/issues/2247))
+- **install:** Fix PowerShell core crash ([#2554](https://github.com/ScoopInstaller/Scoop/issues/2554))
+- **install:** Option to skip hash validation and error message improvements ([#2260](https://github.com/ScoopInstaller/Scoop/issues/2260))
+- **install:** Remove env_ensure_home ([#1967](https://github.com/ScoopInstaller/Scoop/issues/1967))
+- **install:** Show first 8 bytes of file in the hash check error message ([e4cbb42e](https://github.com/ScoopInstaller/Scoop/commit/e4cbb42e64843e53b5b24de92f43062bca98c474))
+- **persist:** Fix condition for persist_permission() ([eb7b7cbf](https://github.com/ScoopInstaller/Scoop/commit/eb7b7cbf4f30e4122762856723155f3c1e980d1b)) ([1a2598bc](https://github.com/ScoopInstaller/Scoop/commit/1a2598bc3082a2e3fffac1a6bea0b42032e388f0))
+- **persist:** Fixed persisting bug when force update app with same version ([#2774](https://github.com/ScoopInstaller/Scoop/issues/2774))
+- **persist:** Fix the target didn't be created ([#3008](https://github.com/ScoopInstaller/Scoop/issues/3008))
+- **persist:** Prevent directory creation from being output ([#1999](https://github.com/ScoopInstaller/Scoop/issues/1999))
+- **scoop:** Force to add new main bucket ([#3419](https://github.com/ScoopInstaller/Scoop/issues/3419))
+- **shim:** Fix .ps1 shim parsing logic ([#2564](https://github.com/ScoopInstaller/Scoop/issues/2564))
+- **shim:** Fixed ps1/jar->ps1 shims args handling ([#2120](https://github.com/ScoopInstaller/Scoop/issues/2120))
+- **shortcuts:** Improve Shortcut creation ([83b82386](https://github.com/ScoopInstaller/Scoop/commit/83b823868f5ef5256d3dcfbecff278bb355fefc8))
+- **uninstall:** Better error handling during uninstallation ([#2079](https://github.com/ScoopInstaller/Scoop/issues/2079))
+- **uninstall:** Uninstall fails to remove architecture-specific shims ([8b1871b2](https://github.com/ScoopInstaller/Scoop/commit/8b1871b20df4dbf1b603d4066937ba213c03bb32))
+- **update:** Rewording PowerShell update notice ([d006fb93](https://github.com/ScoopInstaller/Scoop/commit/d006fb9315b55a9d8e6a36218cf5dbdde51433ec))
+- **versions:** Improvements for the reset command to deal with empty current alias dir correctly ([#2896](https://github.com/ScoopInstaller/Scoop/issues/2896))
+- **scoop-alias:** Improve "scoop alias list" output ([#2163](https://github.com/ScoopInstaller/Scoop/issues/2163))
+- **scoop-cache:** Display help on incorrect cache command ([#3431](https://github.com/ScoopInstaller/Scoop/issues/3431))
+- **scoop-cache:** scoop cache command not using $SCOOP_CACHE ([#1990](https://github.com/ScoopInstaller/Scoop/issues/1990))
+- **scoop-info:** Improve scoop-info license attributes output ([#2397](https://github.com/ScoopInstaller/Scoop/issues/2397))
+- **scoop-install:** Prevent installing programs from JSON multiple times ([936cf9cb](https://github.com/ScoopInstaller/Scoop/commit/936cf9cbb0c4dd3a594fbaf5c696ce519e586d8c))
+- **scoop-reset:** Persist data on reset ([#2773](https://github.com/ScoopInstaller/Scoop/issues/2773))
+- **scoop-reset:** Re-create shortcuts ([6e5b7e57](https://github.com/ScoopInstaller/Scoop/commit/6e5b7e57bb0628f072872d9a5b8c8a0fa58389e1))
+- **scoop-search:** Better handling for invalid query ([bf024705](https://github.com/ScoopInstaller/Scoop/commit/bf024705a8cc38592571aa3026dca2471f19ac5a))
+- **scoop-uninstall:** Checked if uninstaller removed its directory ([#2078](https://github.com/ScoopInstaller/Scoop/issues/2078))
+- **scoop-update:** Add config option "show_update_log" ([d68cb3ce](https://github.com/ScoopInstaller/Scoop/commit/d68cb3ce52acaa9983f278822febd506f54ebe02))
+- **scoop-update:** First scoop update fails because scoop deletes itself too early ([376630fd](https://github.com/ScoopInstaller/Scoop/commit/376630fd80a3f9012fd6e673460b9e28e375e951))
+- **scoop-update:** Fix branch switching ([#3372](https://github.com/ScoopInstaller/Scoop/issues/3372))
+- **scoop-update:** Fix update with cookies ([#3261](https://github.com/ScoopInstaller/Scoop/issues/3261))
+- **scoop-update:** Improve is_scoop_outdated() and add last_scoop_update() ([f3f559c4](https://github.com/ScoopInstaller/Scoop/commit/f3f559c460406689dab2375310fb1026e2be58bd))
+- **scoop-update:** Resolve linting, fix appveyor tests error ([#2148](https://github.com/ScoopInstaller/Scoop/issues/2148))
+
+### Code Refactoring
+
+- **bucket:** Move function into lib from lib-exec ([#3062](https://github.com/ScoopInstaller/Scoop/issues/3062))
+- **bucket:** Optimize buckets function ([#3341](https://github.com/ScoopInstaller/Scoop/issues/3341))
+- **config:** Move configuration handling to core.ps1 ([#3242](https://github.com/ScoopInstaller/Scoop/issues/3242))
+- **core:** aria2_path() -> file_path() ([0f464016](https://github.com/ScoopInstaller/Scoop/commit/0f4640168da8d68a52eb2b80af2f3ffa01c9b658))
+- **core:** cmd_available() -> Test-CommandAvailable() ([#3314](https://github.com/ScoopInstaller/Scoop/issues/3314))
+- **core:** ensure_all_installed() -> Confirm-InstallationStatus() ([#3293](https://github.com/ScoopInstaller/Scoop/issues/3293))
+- **core:** Move default_aliases into the scoped function ([#3233](https://github.com/ScoopInstaller/Scoop/issues/3233))
+- **core:** Refactor function names and fix installing 7zip locally if already globally available ([#3416](https://github.com/ScoopInstaller/Scoop/issues/3416))
+- **core:** Simplified last_scoop_update() ([#2931](https://github.com/ScoopInstaller/Scoop/issues/2931))
+- **core:** Tweak SecurityProtocol usage ([#3065](https://github.com/ScoopInstaller/Scoop/issues/3065))
+- **decompress:** Refactored (w/ install.ps1, core.ps1) ([#3169](https://github.com/ScoopInstaller/Scoop/issues/3169))
+- **decompress:** Refactor extraction handling functions ([#3204](https://github.com/ScoopInstaller/Scoop/issues/3204))
+- **download:** Download functionality refactor ([#1329](https://github.com/ScoopInstaller/Scoop/issues/1329))
+- **install:** Rename locate() to Find-Manifest() ([9eed3d89](https://github.com/ScoopInstaller/Scoop/commit/9eed3d8914c7a0fa294110eb0761776a01adf034))
+
+### Builds
+
+- **auto-pr:** Add -App parameter ([#3157](https://github.com/ScoopInstaller/Scoop/issues/3157))
+- **auto-pr:** Add SkipUpdated parameter ([#3168](https://github.com/ScoopInstaller/Scoop/issues/3168))
+- **checkhashes:** Add bin\checkhashes.ps1 ([#2766](https://github.com/ScoopInstaller/Scoop/issues/2766))
+- **checkurls:** Add SkipValid Parameter ([#2845](https://github.com/ScoopInstaller/Scoop/issues/2845))
+- **checkurls:** Import config.ps1 in checkurls.ps1 ([126e9c97](https://github.com/ScoopInstaller/Scoop/commit/126e9c97d2ef7db537a5137167089a97f343e98e))
+- **checkver:** Add 'useragent' property ([8feb3867](https://github.com/ScoopInstaller/Scoop/commit/8feb3867a74ea0340585e3e695934d96cf483a05))
+- **checkver:** Add 'jsonpath' alias for 'jp' ([76fdb6b7](https://github.com/ScoopInstaller/Scoop/commit/76fdb6b74c1772bf607d2dad5f6c50269369ff88))
+- **checkver:** Add 're' alias 'regex' ([468649c8](https://github.com/ScoopInstaller/Scoop/commit/468649c88dea9c1ff9614f2cdf29a521d572664e))
+- **checkver:** Allow using the current version in checkver URL ([607ac9ca](https://github.com/ScoopInstaller/Scoop/commit/607ac9ca7c185da61e2c746ea87d28c2abe62adc))
+- **checkver:** Fix example parameters ([#3413](https://github.com/ScoopInstaller/Scoop/issues/3413))
+- **checkver:** GitHub checkver case-insensitive version check ([2e2633e9](https://github.com/ScoopInstaller/Scoop/commit/2e2633e9640f6cab5c2f895b680345cd6ca))
+- **checkver:** Remove old commented code ([72754036](https://github.com/ScoopInstaller/Scoop/commit/72754036a251fffd2f2eb0e242edfd9895543e3c))
+- **checkver:** Resolve issue on Powershell >6.1.0 ([#2592](https://github.com/ScoopInstaller/Scoop/issues/2592))
+- **checkver:** Support skipping up to date manifests ([#2624](https://github.com/ScoopInstaller/Scoop/issues/2624))
+- **schema:** Add shortcutsArray definition to schema.json ([0c7e6002](https://github.com/ScoopInstaller/Scoop/commit/0c7e60024a06e122331b17a204a158e4c5800a3d))
+- **schema:** extract_to property is on active duty (not deprecated) ([59e994c5](https://github.com/ScoopInstaller/Scoop/commit/59e994c5fdeb8dffe6037ca6767d56ad13bf04da))
+- **schema:** Improve comments in schema.json ([b5ed0761](https://github.com/ScoopInstaller/Scoop/commit/b5ed0761aef4f3e864533dc0460d110115850ba7))
+- **supporting:** Update validator.exe and shim.exe ([#2024](https://github.com/ScoopInstaller/Scoop/issues/2024), [#2034](https://github.com/ScoopInstaller/Scoop/issues/2034))
+- **supporting:** Update Newtonsoft.Json to 11.0.2, Newtonsoft.Json.Schema to 3.0.10 ([#3043](https://github.com/ScoopInstaller/Scoop/issues/3043))
+- **validator:** Improve error reporting, add support for multiple files ([#3134](https://github.com/ScoopInstaller/Scoop/issues/3134))
+
+### Continuous Integration
+
+- **appveyor:** Rebuild cache ([7311b41b](https://github.com/ScoopInstaller/Scoop/commit/7311b41b8d1e2e010175fb7d079662bbcba5bac8))
+- **appveyor:** Run tests for PowerShell 5 and 6 ([#2603](https://github.com/ScoopInstaller/Scoop/issues/2603))
+- **test:** Improve installation of lessmsi and innounp ([#3409](https://github.com/ScoopInstaller/Scoop/issues/3409))
+
+### Styles
+
+- **lint:** PSAvoidUsingCmdletAliases ([#2075](https://github.com/ScoopInstaller/Scoop/issues/2075))
+
+### Tests
+
+- **bucket:** Add importable tests for Buckets ([478f52c4](https://github.com/ScoopInstaller/Scoop/commit/478f52c421ca35ea35b5fd0b2df2631cf7d82487))
+- **bucket:** Fix manifest tests for buckets ([589303fa](https://github.com/ScoopInstaller/Scoop/commit/589303facc5284f6f95c1305191e0558c0169691))
+- **bucket:** Handle JSON.NET schema validation limit exceeded. ([139813a8](https://github.com/ScoopInstaller/Scoop/commit/139813a8f50ace85e2752d9b6c9f82fc64ff3e48))
+- **file:** Move style constraints tests to separate test file ([7b7113fc](https://github.com/ScoopInstaller/Scoop/commit/7b7113fc3bf962aaeba625f58341c30a80f0fe6a))
+- **linux:** Fix some tests on linux ([#2153](https://github.com/ScoopInstaller/Scoop/issues/2153))
+- **manifest:** Expose bucketdir variable in manifest test script ([#2182](https://github.com/ScoopInstaller/Scoop/issues/2182))
+- **test:** Add -TestPath param to test.ps1 ([f857dce9](https://github.com/ScoopInstaller/Scoop/commit/f857dce9f59a490f6dd07085c3abaa51e9577fda))
+- **test:** Force install PSScriptAnalyzer and BuildHelpers ([7a1b5a18](https://github.com/ScoopInstaller/Scoop/commit/7a1b5a1840e30321951fa0f5333c34d10f57fa94))
+- **test:** Require BuildHelpers version 2.0.0 ([ac3ee766](https://github.com/ScoopInstaller/Scoop/commit/ac3ee766722e99c1f15dc60a1f1dfb0a48428c55))
+- **test:** Update BuildHelpers to version 2.0.1 ([dde4d0f9](https://github.com/ScoopInstaller/Scoop/commit/dde4d0f93f260191af5524c0ecab927f3e252361))
+- **core:** Use Pester 4.0 syntax in core tests ([#2712](https://github.com/ScoopInstaller/Scoop/issues/2712))
+- **install:** Use Pester 4.0 syntax to the install tests ([#2713](https://github.com/ScoopInstaller/Scoop/issues/2713))
+- **test:** Use Pester 4.0 syntax to multiple files ([#2714](https://github.com/ScoopInstaller/Scoop/issues/2714))
+
+### Documentation
+
+- **readme:** Add discord chat badge ([#3241](https://github.com/ScoopInstaller/Scoop/issues/3241))
+- **readme:** Add more details about scoops installation ([#2273](https://github.com/ScoopInstaller/Scoop/issues/2273))
+- **readme:** Corrected enable powershell executionpolicy ([#2020](https://github.com/ScoopInstaller/Scoop/issues/2020))
+- **readme:** Update Discord invite link ([5f269249](https://github.com/ScoopInstaller/Scoop/commit/5f269249609b43f5c4fa9aba4def999e7ee05fe1))
+- **readme:** Update requirements note ([#2509](https://github.com/ScoopInstaller/Scoop/issues/2509))
+- **readme:** Fix typo (you -> your), (it's -> its) ([#2698](https://github.com/ScoopInstaller/Scoop/issues/2698))
+- **readme:** Remove trailing whitespaces ([d25186bf](https://github.com/ScoopInstaller/Scoop/commit/d25186bf1f833e30d8c5b530b7c260fe399b75ed))
+- **readme:** Remove "tail" from example (is coreutils) ([#2158](https://github.com/ScoopInstaller/Scoop/issues/2158))
+
+## *Commits before 2018 are trimmed*
diff --git a/LICENSE b/LICENSE
index 68a49daad8..68b7fd92d6 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,3 +1,27 @@
+SPDX-License-Identifier: UNLICENSE or MIT
+
+INFORMATION ABOUT THIS PROJECT'S LICENSE (SHORT)
+============================================================================================
+This project is licensed under the Unlicense or the MIT license,
+at your option.
+
+INFORMATION ABOUT THIS PROJECT'S LICENSE (LONG)
+============================================================================================
+This project ("Scoop") is free software, licensed under the Unlicense or the
+MIT license, at your option. Scoop was previously licensed under only the Unlicense,
+but was dual-licensed from version 0.2.0.
+
+Scoop comes with ABSOLUTELY NO WARRANTY. Use it at your own risk. Scoop is provided
+on an AS-IS BASIS and its contributors disclaim all warranties.
+
+You may use, modify, distribute, sell, copy, compile, or merge Scoop by any means.
+
+Copies of both licenses can be found below.
+
+THE LICENSE OF SCOOP
+============================================================================================
+Unlicense
+---------
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
@@ -22,3 +46,28 @@ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to
+
+MIT license
+-----------
+The MIT License (MIT)
+
+Copyright (c) 2013-2017 Luke Sampson (https://github.com/lukesampson)
+Copyright (c) 2013-present Scoop contributors (https://github.com/ScoopInstaller/Scoop/graphs/contributors)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/PSScriptAnalyzerSettings.psd1 b/PSScriptAnalyzerSettings.psd1
new file mode 100644
index 0000000000..9ef165869e
--- /dev/null
+++ b/PSScriptAnalyzerSettings.psd1
@@ -0,0 +1,28 @@
+@{
+ # Only diagnostic records of the specified severity will be generated.
+ # Uncomment the following line if you only want Errors and Warnings but
+ # not Information diagnostic records.
+ Severity = @('Error')
+
+ # Analyze **only** the following rules. Use IncludeRules when you want
+ # to invoke only a small subset of the defualt rules.
+ # IncludeRules = @('PSAvoidDefaultValueSwitchParameter',
+ # 'PSMisleadingBacktick',
+ # 'PSMissingModuleManifestField',
+ # 'PSReservedCmdletChar',
+ # 'PSReservedParams',
+ # 'PSShouldProcess',
+ # 'PSUseApprovedVerbs',
+ # 'PSAvoidUsingCmdletAliases',
+ # 'PSUseDeclaredVarsMoreThanAssignments')
+
+ # Do not analyze the following rules. Use ExcludeRules when you have
+ # commented out the IncludeRules settings above and want to include all
+ # the default rules except for those you exclude below.
+ # Note: if a rule is in both IncludeRules and ExcludeRules, the rule
+ # will be excluded.
+ ExcludeRules = @(
+ # Currently Scoop widely uses Write-Host to output colored text.
+ 'PSAvoidUsingWriteHost'
+ )
+}
diff --git a/README.md b/README.md
index 69da89a3dd..641c0f6d76 100644
--- a/README.md
+++ b/README.md
@@ -1,65 +1,148 @@
-Scoop [](https://ci.appveyor.com/project/lukesampson/scoop) [](https://gitter.im/lukesampson/scoop)
-=====
+Scoop
+
+
+
+ Features
+ |
+ Installation
+ |
+ Documentation
+
+
+---
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Scoop is a command-line installer for Windows.
-Requirements:
+## What does Scoop do?
-* [PowerShell 3](https://www.microsoft.com/en-us/download/details.aspx?id=34595)
-* PowerShell must be enabled for your user account e.g. `set-executionpolicy remotesigned -s cu`
+Scoop installs apps from the command line with a minimal amount of friction. It:
-To install:
+- Eliminates [User Account Control](https://learn.microsoft.com/windows/security/application-security/application-control/user-account-control/) (UAC) prompt notifications.
+- Hides the graphical user interface (GUI) of wizard-style installers.
+- Prevents polluting the `PATH` environment variable. Normally, this variable gets cluttered as different apps are installed on the device.
+- Avoids unexpected side effects from installing and uninstalling apps.
+- Resolves and installs dependencies automatically.
+- Performs all the necessary steps to get an app to a working state.
- iex (new-object net.webclient).downloadstring('https://get.scoop.sh')
+Scoop is quite script-friendly. Your environment can become the way you like by using repeatable setups. For example:
-Once installed, run `scoop help` for instructions.
+```console
+scoop install sudo
+sudo scoop install 7zip git openssh --global
+scoop install aria2 curl grep sed less touch
+scoop install python ruby go perl
+```
-What does Scoop do?
--------------------
+If you have built software that you would like others to use, Scoop is an alternative to building an installer (like MSI or InnoSetup). You just need to compress your app to a `.zip` file and provide a JSON manifest that describes how to install it.
-Scoop installs programs from the command line with a minimal amount of friction. It tries to eliminate things like:
-* Permission popup windows
-* GUI wizard-style installers
-* Path pollution from installing lots of programs
-* Unexpected side-effects from installing and uninstalling programs
-* The need to find and install dependencies
-* The need to perform extra setup steps to get a working program
+## Installation
-Scoop is very scriptable, so you can run repeatable setups to get your environment just the way you like, e.g.:
+Run the following commands from a regular (non-admin) PowerShell terminal to install Scoop:
```powershell
-scoop install sudo
-sudo scoop install 7zip git openssh --global
-scoop install curl grep sed less tail touch
-scoop install python ruby go perl
+Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
+Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression
```
-If you've built software that you'd like others to use, Scoop is an alternative to building an installer (e.g. MSI or InnoSetup)—you just need to zip your program and provide a JSON manifest that describes how to install it.
+**Note**: The first command makes your device allow running the installation and management scripts. This is necessary because Windows 10 client devices restrict execution of any PowerShell scripts by default.
+
+It will install Scoop to its default location:
+
+`C:\Users\\scoop`
+
+You can find the complete documentation about the installer, including advanced installation configurations, in [ScoopInstaller/Install](https://github.com/ScoopInstaller/Install). Please create new issues there if you have questions about the installation.
+
+## Multi-connection downloads with `aria2`
+
+Scoop can utilize [`aria2`](https://github.com/aria2/aria2) to use multi-connection downloads. Simply install `aria2` through Scoop and it will be used for all downloads afterward.
+
+```console
+scoop install aria2
+```
-### [Documentation](https://github.com/lukesampson/scoop/wiki)
+By default, `scoop` displays a warning when running `scoop install` or `scoop update` while `aria2` is enabled. This warning can be suppressed by running `scoop config aria2-warning-enabled false`.
-Inspiration
------------
+You can tweak the following `aria2` settings with the `scoop config` command:
-* [Homebrew](http://mxcl.github.io/homebrew/)
-* [sub](https://github.com/37signals/sub#readme)
+- aria2-enabled (default: true)
+- aria2-warning-enabled (default: true)
+- [aria2-retry-wait](https://aria2.github.io/manual/en/html/aria2c.html#cmdoption-retry-wait) (default: 2)
+- [aria2-split](https://aria2.github.io/manual/en/html/aria2c.html#cmdoption-s) (default: 5)
+- [aria2-max-connection-per-server](https://aria2.github.io/manual/en/html/aria2c.html#cmdoption-x) (default: 5)
+- [aria2-min-split-size](https://aria2.github.io/manual/en/html/aria2c.html#cmdoption-k) (default: 5M)
+- [aria2-options](https://aria2.github.io/manual/en/html/aria2c.html#options) (default: )
-What sort of apps can Scoop install?
-------------------------------------
+## Inspiration
-The apps that install best with Scoop are commonly called "portable" apps: i.e. compressed program files that run stand-alone when extracted and don't have side-effects like changing the registry or putting files outside the program directory.
+- [Homebrew](https://brew.sh/)
+- [Sub](https://signalvnoise.com/posts/3264-automating-with-convention-introducing-sub)
-Since installers are common, Scoop supports them too (and their uninstallers).
+## What sort of apps can Scoop install?
-Scoop is also great at handling single-file programs and Powershell scripts. These don't even need to be compressed. See the [runat](https://github.com/lukesampson/scoop/blob/master/bucket/runat.json) package for an example: it's really just a GitHub gist.
+The apps that are most likely to get installed fine with Scoop are those referred to as "portable" apps. These apps are compressed files which can run standalone after being extracted. This type of apps does not produce side effects like changing the Windows Registry or placing files outside the app directory.
+Scoop also supports installer files and their uninstallation methods. Likewise, it can handle single-file apps and PowerShell scripts. These do not even need to be compressed. See the [runat](https://github.com/ScoopInstaller/Main/blob/master/bucket/runat.json) package for an example: it is simply a GitHub gist.
-Support this project
---------------------
+### Contribute to this project
+
+If you would like to improve Scoop by adding features or fixing bugs, please read our [Contributing Guide](https://github.com/ScoopInstaller/.github/blob/main/.github/CONTRIBUTING.md).
+
+### Support this project
+
+If you find Scoop useful and would like to support the ongoing development and maintenance of this project, you can donate here:
+
+- [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=DM2SUH9EUXSKJ) (one-time donations)
+
+## Known application buckets
+
+The following buckets are known to Scoop:
+
+- [main](https://github.com/ScoopInstaller/Main) - Default bucket which contains popular non-GUI apps.
+- [extras](https://github.com/ScoopInstaller/Extras) - Apps that do not fit the main bucket's [criteria](https://github.com/ScoopInstaller/Scoop/wiki/Criteria-for-including-apps-in-the-main-bucket).
+- [games](https://github.com/Calinou/scoop-games) - Open-source and freeware video games and game-related tools.
+- [nerd-fonts](https://github.com/matthewjberger/scoop-nerd-fonts) - Nerd Fonts.
+- [nirsoft](https://github.com/ScoopInstaller/Nirsoft) - A collection of over 250+ apps from [Nirsoft](https://nirsoft.net).
+- [sysinternals](https://github.com/niheaven/scoop-sysinternals) - The Sysinternals suite from [Microsoft](https://learn.microsoft.com/sysinternals/).
+- [java](https://github.com/ScoopInstaller/Java) - A collection of Java development kits (JDKs) and 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 trigger UAC prompts).
+- [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. You can make use of more buckets by typing:
+
+```console
+scoop bucket add
+```
+
+For example, to add the `extras` bucket, type:
+
+```console
+scoop bucket add extras
+```
-If you find Scoop useful and would like to support ongoing development and maintenance, here's how:
+You would be able to install apps from the `extras` bucket now.
-* [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=DM2SUH9EUXSKJ) (one-time donation)
-* [Gratipay](https://gratipay.com/~lukesampson) (ongoing donations)
+## Other application buckets
-[]()
+Many other application buckets hosted on GitHub can be found on [ScoopSearch](https://scoop.sh/) or via [other search engines](https://rasa.github.io/scoop-directory/#other-search-engines).
diff --git a/appveyor.yml b/appveyor.yml
index 4e72d287f4..f66a0c70d8 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,17 +1,35 @@
version: "{build}-{branch}"
-
branches:
except:
- gh-pages
-
-init:
- - ps: (get-psprovider 'FileSystem').Home = $(pwd)
- - ps: "if($env:APPVEYOR_CHOCO_PESTER_OPTIONS -ne $null) { write-host -f yellow 'NOTE: customized `pester` installation is being used' }"
- - ps: choco install -y pester $env:APPVEYOR_CHOCO_PESTER_OPTIONS
-
-build: off
-
-test_script:
- - ps: $result = invoke-pester -path test/ -outputfile TestResults.xml -outputformat NUnitXML -passthru; $env:failedcount = $result.failedcount
- - ps: (new-object net.webclient).uploadfile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", (resolve-path ./TestResults.xml))
- - ps: if($env:failedcount -gt 0) { exit $env:failedcount }
+build: false
+deploy: false
+clone_depth: 2
+image: Visual Studio 2022
+environment:
+ matrix:
+ - PowerShell: 5
+ - PowerShell: 7
+matrix:
+ fast_finish: true
+for:
+ - matrix:
+ only:
+ - PowerShell: 5
+ cache:
+ - '%USERPROFILE%\Documents\WindowsPowerShell\Modules -> appveyor.yml, test\bin\*.ps1'
+ - C:\projects\helpers -> appveyor.yml, test\bin\*.ps1
+ install:
+ - ps: .\test\bin\init.ps1
+ test_script:
+ - ps: .\test\bin\test.ps1
+ - matrix:
+ only:
+ - PowerShell: 7
+ cache:
+ - '%USERPROFILE%\Documents\PowerShell\Modules -> appveyor.yml, test\bin\*.ps1'
+ - C:\projects\helpers -> appveyor.yml, test\bin\*.ps1
+ install:
+ - pwsh: .\test\bin\init.ps1
+ test_script:
+ - pwsh: .\test\bin\test.ps1
diff --git a/bin/auto-pr.ps1 b/bin/auto-pr.ps1
index f89ff88551..766e49764d 100644
--- a/bin/auto-pr.ps1
+++ b/bin/auto-pr.ps1
@@ -1,157 +1,222 @@
-# Usage: .\bin\auto-pr.ps1 [options]
-# Summary: Updates manifests and pushes them or creates pull-requests
-# Help: Updates manifests and pushes them to directly the master branch or creates pull-requests for upstream
-#
-# Options:
-# -p, --push push updates directly to 'origin master'
-# -r, --request create pull-requests on 'upstream master' for each update
-# -u, --upstream upstream repository with target branch
-# only used if -r is set (default: lukesampson/scoop:master)
+<#
+.SYNOPSIS
+ Updates manifests and pushes them or creates pull-requests.
+.DESCRIPTION
+ Updates manifests and pushes them directly to the origin branch or creates pull-requests for upstream.
+.PARAMETER Upstream
+ Upstream repository with the target branch.
+ Must be in format '/:'
+.PARAMETER OriginBranch
+ Origin (local) branch name.
+.PARAMETER App
+ Manifest name to search.
+ Placeholders are supported.
+.PARAMETER CommitMessageFormat
+ The format of the commit message.
+ will be replaced with the file name of manifest.
+ will be replaced with the version of the latest manifest.
+.PARAMETER Dir
+ The directory where to search for manifests.
+.PARAMETER Push
+ Push updates directly to 'origin branch'.
+.PARAMETER Request
+ Create pull-requests on 'upstream branch' for each update.
+.PARAMETER Help
+ Print help to console.
+.PARAMETER SpecialSnowflakes
+ An array of manifests, which should be updated all the time. (-ForceUpdate parameter to checkver)
+.PARAMETER SkipUpdated
+ Updated manifests will not be shown.
+.PARAMETER ThrowError
+ Throw error as exception instead of just printing it.
+.EXAMPLE
+ PS BUCKETROOT > .\bin\auto-pr.ps1 'someUsername/repository:branch' -Request
+.EXAMPLE
+ PS BUCKETROOT > .\bin\auto-pr.ps1 -Push
+ Update all manifests inside 'bucket/' directory.
+#>
param(
- [String]$upstream = "lukesampson/scoop:master",
- [String]$dir,
- [Switch]$push = $false,
- [Switch]$request = $false,
- [Switch]$help = $false
+ [Parameter(Mandatory = $true)]
+ [ValidateScript( {
+ if (!($_ -match '^(.*)\/(.*):(.*)$')) {
+ throw 'Upstream must be in this format: /:'
+ }
+ $true
+ })]
+ [String] $Upstream,
+ [String] $OriginBranch = 'master',
+ [String] $App = '*',
+ [String] $CommitMessageFormat = ': Update to version ',
+ [ValidateScript( {
+ if (!(Test-Path $_ -Type Container)) {
+ throw "$_ is not a directory!"
+ } else {
+ $true
+ }
+ })]
+ [String] $Dir,
+ [Switch] $Push,
+ [Switch] $Request,
+ [Switch] $Help,
+ [string[]] $SpecialSnowflakes,
+ [Switch] $SkipUpdated,
+ [Switch] $ThrowError
)
-if(!$dir) { $dir = "$psscriptroot\..\bucket" }
-$dir = resolve-path $dir
+. "$PSScriptRoot\..\lib\manifest.ps1"
+. "$PSScriptRoot\..\lib\json.ps1"
-. "$psscriptroot\..\lib\manifest.ps1"
-. "$psscriptroot\..\lib\json.ps1"
-. "$psscriptroot\..\lib\unix.ps1"
+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 @'
+Usage: auto-pr.ps1 [OPTION]
+
+Mandatory options:
+ -p, -push push updates directly to 'origin branch'
+ -r, -request create pull-requests on 'upstream branch' for each update
+
+Optional options:
+ -u, -upstream upstream repository with target branch
+ -o, -originbranch origin (local) branch name
+ -h, -help
+'@
+ exit 0
+}
-if(is_unix) {
+if ($IsLinux -or $IsMacOS) {
if (!(which hub)) {
- Write-Host -f yellow "Please install hub ('brew install hub' or visit: https://hub.github.com/)"
+ Write-Host "Please install hub ('brew install hub' or visit: https://hub.github.com/)" -ForegroundColor Yellow
exit 1
}
} else {
if (!(scoop which hub)) {
- Write-Host -f yellow "Please install hub 'scoop install hub'"
+ Write-Host "Please install hub 'scoop install hub'" -ForegroundColor Yellow
exit 1
}
}
-if ((!$push -and !$request) -or $help) {
- Write-Host ""
- Write-Host "Usage: auto-pr.ps1 [OPTION]"
- Write-Host ""
- Write-Host "Mandatory options:"
- Write-Host " -p, -push push updates directly to 'origin master'"
- Write-Host " -r, -request create pull-requests on 'upstream master' for each update"
- Write-Host ""
- Write-Host "Optional options:"
- Write-Host " -u, -upstream upstream repository with target branch"
- Write-Host " only used if -r is set (default: lukesampson/scoop:master)"
- Write-Host " -h, -help"
- Write-Host ""
- exit 0
-}
-
-if(!($upstream -match "^(.*)\/(.*):(.*)$")) {
- Write-Host -f DarkRed "Upstream must have this format: /:"
- exit 1
-}
-
function execute($cmd) {
- Write-Host -f Green $cmd
- $output = iex $cmd
+ Write-Host $cmd -ForegroundColor Green
+ $output = Invoke-Command ([scriptblock]::Create($cmd))
- if($LASTEXITCODE -gt 0) {
- Write-Host -f Red "^^^ Error! See above ^^^ (last command: $cmd)"
- exit 1
+ if ($LASTEXITCODE -gt 0) {
+ abort "^^^ Error! See above ^^^ (last command: $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"
- execute "hub checkout master"
- Write-Host -f Green "hub rev-parse --verify $branch"
+ execute "hub checkout $OriginBranch"
+ Write-Host "hub rev-parse --verify $branch" -ForegroundColor Green
hub rev-parse --verify $branch
- if($LASTEXITCODE -eq 0) {
- Write-Host -f Yellow "Skipping update $app ($version) ..."
+ if ($LASTEXITCODE -eq 0) {
+ Write-Host "Skipping update $app ($version) ..." -ForegroundColor Yellow
return
}
- Write-Host -f DarkCyan "Creating update $app ($version) ..."
+ Write-Host "Creating update $app ($version) ..." -ForegroundColor DarkCyan
execute "hub checkout -b $branch"
execute "hub add $manifest"
- execute "hub commit -m 'Update $app to version $version'"
- Write-Host -f DarkCyan "Pushing update $app ($version) ..."
+ execute "hub commit -m '$commitMessage"
+ Write-Host "Pushing update $app ($version) ..." -ForegroundColor DarkCyan
execute "hub push origin $branch"
- if($LASTEXITCODE -gt 0) {
- Write-Host -f DarkRed "Push failed! (hub push origin $branch)"
- execute "hub reset"
+ if ($LASTEXITCODE -gt 0) {
+ error "Push failed! (hub push origin $branch)"
+ execute 'hub reset'
return
}
+
Start-Sleep 1
- Write-Host -f DarkCyan "Pull-Request update $app ($version) ..."
- Write-Host -f green "hub pull-request -m '' -b '$upstream' -h '$branch'"
- $msg = "Update $app to version $version`n`n"
- $msg += "Hello lovely humans,`n"
- $msg += "a new version of [$app]($homepage) is available.`n"
- $msg += ""
- $msg += "| State | Update :rocket: |
"
- $msg += "| New version | $version |
"
- $msg += "
"
- hub pull-request -m "$msg" -b '$upstream' -h '$branch'
- if($LASTEXITCODE -gt 0) {
- Write-Host -f DarkRed "Pull Request failed! (hub pull-request -m 'Update $app to version $version' -b '$upstream' -h '$branch')"
- execute "hub reset"
- exit 1
+ Write-Host "Pull-Request update $app ($version) ..." -ForegroundColor DarkCyan
+ Write-Host "hub pull-request -m '' -b '$upstream' -h '$branch'" -ForegroundColor Green
+
+ $msg = @"
+$commitMessage
+
+Hello lovely humans,
+a new version of [$app]($homepage) is available.
+
+| State | Update :rocket: |
+| :---------- | :-------------- |
+| New version | $version |
+"@
+
+ hub pull-request -m "$msg" -b "$upstream" -h "$branch"
+ if ($LASTEXITCODE -gt 0) {
+ execute 'hub reset'
+ abort "Pull Request failed! (hub pull-request -m '$commitMessage' -b '$upstream' -h '$branch')"
}
}
-Write-Host -f DarkCyan "Updating ..."
-if($push -eq $true) {
- execute("hub pull origin master")
- execute "hub checkout master"
+Write-Host 'Updating ...' -ForegroundColor DarkCyan
+if ($Push) {
+ execute "hub pull origin $OriginBranch"
+ execute "hub checkout $OriginBranch"
} else {
- execute("hub pull upstream master")
- execute("hub push origin master")
+ execute "hub pull upstream $OriginBranch"
+ execute "hub push origin $OriginBranch"
}
-. "$psscriptroot\checkver.ps1" * -update -dir $dir
+. "$PSScriptRoot\checkver.ps1" -App $App -Dir $Dir -Update -SkipUpdated:$SkipUpdated -ThrowError:$ThrowError
+if ($SpecialSnowflakes) {
+ Write-Host "Forcing update on our special snowflakes: $($SpecialSnowflakes -join ',')" -ForegroundColor DarkCyan
+ $SpecialSnowflakes -split ',' | ForEach-Object {
+ . "$PSScriptRoot\checkver.ps1" $_ -Dir $Dir -ForceUpdate -ThrowError:$ThrowError
+ }
+}
-hub diff --name-only | % {
+hub diff --name-only | ForEach-Object {
$manifest = $_
- if(!$manifest.EndsWith(".json")) {
+ if (!$manifest.EndsWith('.json')) {
return
}
$app = ([System.IO.Path]::GetFileNameWithoutExtension($manifest))
$json = parse_json $manifest
- if(!$json.version) {
- Write-Host -f Red "Invalid manifest: $manifest ..."
+ if (!$json.version) {
+ error "Invalid manifest: $manifest ..."
return
}
$version = $json.version
-
- if($push -eq $true) {
- Write-Host -f DarkCyan "Creating update $app ($version) ..."
+ $CommitMessage = $CommitMessageFormat -replace '',$app -replace '',$version
+ if ($Push) {
+ Write-Host "Creating update $app ($version) ..." -ForegroundColor DarkCyan
execute "hub add $manifest"
- execute "hub commit -m 'Update $app to version $version'"
+
+ # detect if file was staged, because it's not when only LF or CRLF have changed
+ $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 '$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
}
}
-if($push -eq $true) {
- Write-Host -f DarkCyan "Pushing updates ..."
- execute "hub push origin master"
+if ($Push) {
+ Write-Host 'Pushing updates ...' -ForegroundColor DarkCyan
+ execute "hub push origin $OriginBranch"
} else {
- Write-Host -f DarkCyan "Returning to master branch and removing unstaged files ..."
- execute "hub checkout -f master"
+ Write-Host "Returning to $OriginBranch branch and removing unstaged files ..." -ForegroundColor DarkCyan
+ execute "hub checkout -f $OriginBranch"
}
-execute "hub reset"
+execute 'hub reset --hard'
diff --git a/bin/checkhashes.ps1 b/bin/checkhashes.ps1
new file mode 100644
index 0000000000..6e6420fb2a
--- /dev/null
+++ b/bin/checkhashes.ps1
@@ -0,0 +1,190 @@
+<#
+.SYNOPSIS
+ Check if ALL urls inside manifest have correct hashes.
+.PARAMETER App
+ Manifest to be checked.
+ Wildcard is supported.
+.PARAMETER Dir
+ Where to search for manifest(s).
+.PARAMETER Update
+ When there are mismatched hashes, manifest will be updated.
+.PARAMETER ForceUpdate
+ Manifest will be updated all the time. Not only when there are mismatched hashes.
+.PARAMETER SkipCorrect
+ Manifests without mismatch will not be shown.
+.PARAMETER UseCache
+ Downloaded files will not be deleted after script finish.
+ Should not be used, because check should be used for downloading actual version of file (as normal user, not finding in some document from vendors, which could be damaged / wrong (Example: Slack@3.3.1 ScoopInstaller/Extras#1192)), not some previously downloaded.
+.EXAMPLE
+ PS BUCKETROOT> .\bin\checkhashes.ps1
+ Check all manifests for hash mismatch.
+.EXAMPLE
+ PS BUCKETROOT> .\bin\checkhashes.ps1 MANIFEST -Update
+ Check MANIFEST and Update if there are some wrong hashes.
+#>
+param(
+ [String] $App = '*',
+ [Parameter(Mandatory = $true)]
+ [ValidateScript( {
+ if (!(Test-Path $_ -Type Container)) {
+ throw "$_ is not a directory!"
+ } else {
+ $true
+ }
+ })]
+ [String] $Dir,
+ [Switch] $Update,
+ [Switch] $ForceUpdate,
+ [Switch] $SkipCorrect,
+ [Alias('k')]
+ [Switch] $UseCache
+)
+
+. "$PSScriptRoot\..\lib\core.ps1"
+. "$PSScriptRoot\..\lib\manifest.ps1"
+. "$PSScriptRoot\..\lib\buckets.ps1"
+. "$PSScriptRoot\..\lib\autoupdate.ps1"
+. "$PSScriptRoot\..\lib\json.ps1"
+. "$PSScriptRoot\..\lib\versions.ps1"
+. "$PSScriptRoot\..\lib\download.ps1"
+
+$Dir = Convert-Path $Dir
+if ($ForceUpdate) { $Update = $true }
+# Cleanup
+if (!$UseCache) { Remove-Item "$cachedir\*HASH_CHECK*" -Force }
+
+function err ([String] $name, [String[]] $message) {
+ Write-Host "$name`: " -ForegroundColor Red -NoNewline
+ Write-Host ($message -join "`r`n") -ForegroundColor Red
+}
+
+$MANIFESTS = @()
+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 }
+
+ $urls = @()
+ $hashes = @()
+
+ if ($manifest.url) {
+ $manifest.url | ForEach-Object { $urls += $_ }
+ $manifest.hash | ForEach-Object { $hashes += $_ }
+ } elseif ($manifest.architecture) {
+ # First handle 64bit
+ script:url $manifest '64bit' | ForEach-Object { $urls += $_ }
+ 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
+ }
+
+ # Number of URLS and Hashes is different
+ if ($urls.Length -ne $hashes.Length) {
+ err $name 'URLS and hashes count mismatch.'
+ continue
+ }
+
+ $MANIFESTS += @{
+ app = $name
+ file = $file
+ manifest = $manifest
+ urls = $urls
+ hashes = $hashes
+ }
+}
+
+# clear any existing events
+Get-Event | ForEach-Object { Remove-Event $_.SourceIdentifier }
+
+foreach ($current in $MANIFESTS) {
+ $count = 0
+ # Array of indexes mismatched hashes.
+ $mismatched = @()
+ # Array of computed hashes
+ $actuals = @()
+
+ $current.urls | ForEach-Object {
+ $algorithm, $expected = get_hash $current.hashes[$count]
+ if ($UseCache) {
+ $version = $current.manifest.version
+ } else {
+ $version = 'HASH_CHECK'
+ }
+
+ Invoke-CachedDownload $current.app $version $_ $null $null -use_cache:$UseCache
+
+ $to_check = cache_path $current.app $version $_
+ $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') {
+ $actual_hash = "$algorithm`:$actual_hash"
+ $expected = "$algorithm`:$expected"
+ }
+
+ $actuals += $actual_hash
+ if ($actual_hash -ne $expected) {
+ $mismatched += $count
+ }
+ $count++
+ }
+
+ if ($mismatched.Length -eq 0 ) {
+ if (!$SkipCorrect) {
+ Write-Host "$($current.app): " -NoNewline
+ Write-Host 'OK' -ForegroundColor Green
+ }
+ } else {
+ Write-Host "$($current.app): " -NoNewline
+ Write-Host 'Mismatch found ' -ForegroundColor Red
+ $mismatched | ForEach-Object {
+ $file = cache_path $current.app $version $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 "`tExpected:`t$($current.hashes[$_])" -ForegroundColor Green
+ Write-Host "`tActual:`t`t$($actuals[$_])" -ForegroundColor Red
+ }
+ }
+
+ if ($Update) {
+ if ($current.manifest.url -and $current.manifest.hash) {
+ $current.manifest.hash = $actuals
+ } else {
+ $platforms = ($current.manifest.architecture | Get-Member -MemberType NoteProperty).Name
+ # 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
+ $current.manifest.architecture.'64bit'.hash = $actuals[0..($64bit_count - 1)]
+ }
+ if ($platforms.Contains('32bit')) {
+ $32bit_count = $current.manifest.architecture.'32bit'.hash.Count
+ $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 = Convert-Path $current.file
+ [System.IO.File]::WriteAllLines($path, $current.manifest)
+ }
+}
diff --git a/bin/checkurls.ps1 b/bin/checkurls.ps1
index 315d214aef..0ac593362a 100644
--- a/bin/checkurls.ps1
+++ b/bin/checkurls.ps1
@@ -1,115 +1,141 @@
-# list manifests which do not specify a checkver regex
+<#
+.SYNOPSIS
+ List manifests which do not have valid URLs.
+.PARAMETER App
+ Manifest name to search.
+ Placeholder is supported.
+.PARAMETER Dir
+ Where to search for manifest(s).
+.PARAMETER Timeout
+ How long (seconds) the request can be pending before it times out.
+.PARAMETER SkipValid
+ Manifests will all valid URLs will not be shown.
+#>
param(
- [String]$app,
- [String]$dir,
- [Int]$timeout = 5
+ [String] $App = '*',
+ [Parameter(Mandatory = $true)]
+ [ValidateScript( {
+ if (!(Test-Path $_ -Type Container)) {
+ throw "$_ is not a directory!"
+ } else {
+ $true
+ }
+ })]
+ [String] $Dir,
+ [Int] $Timeout = 5,
+ [Switch] $SkipValid
)
-if(!$dir) { $dir = "$psscriptroot\..\bucket" }
-$dir = resolve-path $dir
-
-$search = "*"
-if($app) { $search = $app }
-
-. "$psscriptroot\..\lib\core.ps1"
-. "$psscriptroot\..\lib\manifest.ps1"
-. "$psscriptroot\..\lib\install.ps1"
+. "$PSScriptRoot\..\lib\core.ps1"
+. "$PSScriptRoot\..\lib\manifest.ps1"
+. "$PSScriptRoot\..\lib\download.ps1"
-if(!$dir) { $dir = "$psscriptroot\..\bucket" }
-$dir = resolve-path $dir
+$Dir = Convert-Path $Dir
+$Queue = @()
-# get apps to check
-$queue = @()
-gci $dir "$search.json" | % {
- $manifest = parse_json "$dir\$_"
- $queue += ,@($_, $manifest)
+Get-ChildItem $Dir -Filter "$App.json" -Recurse | ForEach-Object {
+ $manifest = parse_json $_.FullName
+ $Queue += , @($_.BaseName, $manifest)
}
-$original = use_any_https_protocol
-
-write-host "[" -nonewline
-write-host -f cyan "U" -nonewline
-write-host "]RLs"
-write-host " | [" -nonewline
-write-host -f green "O" -nonewline
-write-host "]kay"
-write-host " | | [" -nonewline
-write-host -f red "F" -nonewline
-write-host "]ailed"
-write-host " | | |"
-
-function test_dl($url, $cookies) {
- $wreq = [net.webrequest]::create($url)
- $wreq.timeout = $timeout * 1000
- if($wreq -is [net.httpwebrequest]) {
- $wreq.useragent = 'Scoop/1.0'
- $wreq.referer = strip_filename $url
- if($cookies) {
- $wreq.headers.add('Cookie', (cookie_header $cookies))
+Write-Host '[' -NoNewLine
+Write-Host 'U' -NoNewLine -ForegroundColor Cyan
+Write-Host ']RLs'
+Write-Host ' | [' -NoNewLine
+Write-Host 'O' -NoNewLine -ForegroundColor Green
+Write-Host ']kay'
+Write-Host ' | | [' -NoNewLine
+Write-Host 'F' -NoNewLine -ForegroundColor Red
+Write-Host ']ailed'
+Write-Host ' | | |'
+
+function test_dl([String] $url, $cookies) {
+ # Trim renaming suffix, prevent getting 40x response
+ $url = ($url -split '#/')[0]
+
+ $wreq = [Net.WebRequest]::Create($url)
+ $wreq.Timeout = $Timeout * 1000
+ if ($wreq -is [Net.HttpWebRequest]) {
+ $wreq.UserAgent = Get-UserAgent
+ $wreq.Referer = strip_filename $url
+ if ($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()
- return $url, $wres.statuscode, $null
+ $wres = $wreq.GetResponse()
+
+ return $url, $wres.StatusCode, $null
} catch {
- $e = $_.exception
- if($e.innerexception) { $e = $e.innerexception }
- return $url, "Error", $e.message
+ $e = $_.Exception
+ if ($e.InnerException) { $e = $e.InnerException }
+
+ return $url, 'Error', $e.Message
} finally {
- if($wres -ne $null -and $wres -isnot [net.ftpwebresponse]) {
- $wres.close()
+ if ($null -ne $wres -and $wres -isnot [Net.FtpWebResponse]) {
+ $wres.Close()
}
}
}
-$queue | % {
- $name, $manifest = $_
+foreach ($man in $Queue) {
+ $name, $manifest = $man
$urls = @()
$ok = 0
$failed = 0
$errors = @()
- if($manifest.url) {
- $manifest.url | % { $urls += $_ }
+ if ($manifest.url) {
+ $manifest.url | ForEach-Object { $urls += $_ }
} else {
- url $manifest "64bit" | % { $urls += $_ }
- url $manifest "32bit" | % { $urls += $_ }
+ script:url $manifest '64bit' | ForEach-Object { $urls += $_ }
+ script:url $manifest '32bit' | ForEach-Object { $urls += $_ }
+ script:url $manifest 'arm64' | ForEach-Object { $urls += $_ }
}
- $urls | % {
+ $urls | ForEach-Object {
$url, $status, $msg = test_dl $_ $manifest.cookie
- if($msg) { $errors += "$msg ($url)" }
- if($status -eq "OK" -or $status -eq "OpeningData") { $ok += 1 } else { $failed += 1 }
+ if ($msg) { $errors += "$msg ($url)" }
+ if ($status -eq 'OK' -or $status -eq 'OpeningData') { $ok += 1 } else { $failed += 1 }
}
- write-host "[" -nonewline
- write-host -f cyan -nonewline $urls.length
- write-host "]" -nonewline
+ if (($ok -eq $urls.Length) -and $SkipValid) { continue }
- write-host "[" -nonewline
- if($ok -eq $urls.length) {
- write-host -f green -nonewline $ok
- } elseif($ok -eq 0) {
- write-host -f red -nonewline $ok
+ # URLS
+ Write-Host '[' -NoNewLine
+ Write-Host $urls.Length -NoNewLine -ForegroundColor Cyan
+ Write-Host ']' -NoNewLine
+
+ # Okay
+ Write-Host '[' -NoNewLine
+ if ($ok -eq $urls.Length) {
+ Write-Host $ok -NoNewLine -ForegroundColor Green
+ } elseif ($ok -eq 0) {
+ Write-Host $ok -NoNewLine -ForegroundColor Red
} else {
- write-host -f yellow -nonewline $ok
+ Write-Host $ok -NoNewLine -ForegroundColor Yellow
}
- write-host "]" -nonewline
+ Write-Host ']' -NoNewLine
- write-host "[" -nonewline
- if($failed -eq 0) {
- write-host -f green -nonewline $failed
+ # Failed
+ Write-Host '[' -NoNewLine
+ if ($failed -eq 0) {
+ Write-Host $failed -NoNewLine -ForegroundColor Green
} else {
- write-host -f red -nonewline $failed
+ Write-Host $failed -NoNewLine -ForegroundColor Red
}
- write-host "] " -nonewline
- write-host (strip_ext $name)
+ Write-Host '] ' -NoNewLine
+ Write-Host $name
- $errors | % {
- write-host -f darkred " > $_"
+ $errors | ForEach-Object {
+ Write-Host " > $_" -ForegroundColor DarkRed
}
}
-
-
-set_https_protocols $original
diff --git a/bin/checkver.ps1 b/bin/checkver.ps1
index 910c940eba..33a4449488 100644
--- a/bin/checkver.ps1
+++ b/bin/checkver.ps1
@@ -1,217 +1,420 @@
-# checks websites for newer versions using an (optional) regular expression defined in the manifest
-# use $dir to specify a manifest directory to check from, otherwise ./bucket is used
+<#
+.SYNOPSIS
+ Check manifest for a newer version.
+.DESCRIPTION
+ Checks websites for newer versions using an (optional) regular expression defined in the manifest.
+.PARAMETER App
+ Manifest name to search.
+ Placeholders are supported.
+.PARAMETER Dir
+ Where to search for manifest(s).
+.PARAMETER Update
+ Update given manifest
+.PARAMETER ForceUpdate
+ Update given manifest(s) even when there is no new version.
+ Useful for hash updates.
+.PARAMETER SkipUpdated
+ Updated manifests will not be shown.
+.PARAMETER Version
+ Update manifest to specific version.
+.PARAMETER ThrowError
+ Throw error as exception instead of just printing it.
+.EXAMPLE
+ PS BUCKETROOT > .\bin\checkver.ps1
+ Check all manifest inside default directory.
+.EXAMPLE
+ PS BUCKETROOT > .\bin\checkver.ps1 -SkipUpdated
+ Check all manifest inside default directory (list only outdated manifests).
+.EXAMPLE
+ PS BUCKETROOT > .\bin\checkver.ps1 -Update
+ Check all manifests and update All outdated manifests.
+.EXAMPLE
+ PS BUCKETROOT > .\bin\checkver.ps1 APP
+ Check manifest APP.json inside default directory.
+.EXAMPLE
+ PS BUCKETROOT > .\bin\checkver.ps1 APP -Update
+ Check manifest APP.json and update, if there is newer version.
+.EXAMPLE
+ PS BUCKETROOT > .\bin\checkver.ps1 APP -ForceUpdate
+ Check manifest APP.json and update, even if there is no new version.
+.EXAMPLE
+ PS BUCKETROOT > .\bin\checkver.ps1 APP -Update -Version VER
+ Check manifest APP.json and update, using version VER
+.EXAMPLE
+ PS BUCKETROOT > .\bin\checkver.ps1 APP DIR
+ Check manifest APP.json inside ./DIR directory.
+.EXAMPLE
+ PS BUCKETROOT > .\bin\checkver.ps1 -Dir DIR
+ Check all manifests inside ./DIR directory.
+.EXAMPLE
+ PS BUCKETROOT > .\bin\checkver.ps1 APP DIR -Update
+ Check manifest APP.json inside ./DIR directory and update if there is newer version.
+#>
param(
- [String]$app,
- [String]$dir,
- [Switch]$update = $false,
- [Switch]$forceUpdate = $false
+ [String] $App = '*',
+ [ValidateScript( {
+ if (!(Test-Path $_ -Type Container)) {
+ throw "$_ is not a directory!"
+ } else {
+ $true
+ }
+ })]
+ [String] $Dir,
+ [Switch] $Update,
+ [Switch] $ForceUpdate,
+ [Switch] $SkipUpdated,
+ [String] $Version = '',
+ [Switch] $ThrowError
)
-if (!$app -and $update) {
- # While developing the feature we only allow specific updates
- Write-Host "[ERROR] AUTOUPDATE CAN ONLY BE USED WITH A APP SPECIFIED" -f DarkRed
- exit
+. "$PSScriptRoot\..\lib\core.ps1"
+. "$PSScriptRoot\..\lib\autoupdate.ps1"
+. "$PSScriptRoot\..\lib\manifest.ps1"
+. "$PSScriptRoot\..\lib\buckets.ps1"
+. "$PSScriptRoot\..\lib\json.ps1"
+. "$PSScriptRoot\..\lib\versions.ps1"
+. "$PSScriptRoot\..\lib\download.ps1"
+
+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!"
}
-. "$psscriptroot\..\lib\core.ps1"
-. "$psscriptroot\..\lib\manifest.ps1"
-. "$psscriptroot\..\lib\config.ps1"
-. "$psscriptroot\..\lib\buckets.ps1"
-. "$psscriptroot\..\lib\autoupdate.ps1"
-. "$psscriptroot\..\lib\json.ps1"
-. "$psscriptroot\..\lib\versions.ps1"
-. "$psscriptroot\..\lib\install.ps1" # needed for hash generation
-. "$psscriptroot\..\lib\unix.ps1"
-
-if(!$dir) { $dir = "$psscriptroot\..\bucket" }
-$dir = resolve-path $dir
+$GitHubToken = Get-GitHubToken
-$search = "*"
-if($app) { $search = $app }
+# don't use $Version with $App = '*'
+if ($App -eq '*' -and $Version -ne '') {
+ throw "Don't use '-Version' with '-App *'!"
+}
# get apps to check
-$queue = @()
-gci $dir "$search.json" | % {
- $json = parse_json "$dir\$_"
- if($json.checkver) {
- $queue += ,@($_, $json)
+$Queue = @()
+$json = ''
+$files | ForEach-Object {
+ $file = $_.FullName
+ $json = parse_json $file
+ if ($json.checkver) {
+ $Queue += , @($_.BaseName, $json, $file)
}
}
# clear any existing events
-get-event | % {
- remove-event $_.sourceidentifier
-}
-
-$original = use_any_https_protocol
+Get-Event | Remove-Event
+Get-EventSubscriber | Unregister-Event
# start all downloads
-$queue | % {
- $wc = new-object net.webclient
- $wc.Headers.Add("user-agent", "Scoop/1.0 (+http://scoop.sh/) (Windows NT 6.1; WOW64)")
- register-objectevent $wc downloadstringcompleted -ea stop | out-null
+$Queue | ForEach-Object {
+ $name, $json, $file = $_
- $name, $json = $_
+ $substitutions = Get-VersionSubstitution $json.version # 'autoupdate.ps1'
- $githubRegex = "\/releases\/tag\/(?:v)?([\d.]+)"
+ $wc = New-Object Net.Webclient
+ if ($json.checkver.useragent) {
+ $wc.Headers.Add('User-Agent', (substitute $json.checkver.useragent $substitutions))
+ } else {
+ $wc.Headers.Add('User-Agent', (Get-UserAgent))
+ }
+ Register-ObjectEvent $wc downloadDataCompleted -ErrorAction Stop | Out-Null
- $url = $json.homepage
- if($json.checkver.url) {
+ # Not Specified
+ if ($json.checkver.url) {
$url = $json.checkver.url
+ } else {
+ $url = $json.homepage
+ }
+
+ if ($json.checkver.re) {
+ $regex = $json.checkver.re
+ } elseif ($json.checkver.regex) {
+ $regex = $json.checkver.regex
+ } else {
+ $regex = ''
}
- $regex = ""
- $jsonpath = ""
- if ($json.checkver -eq "github") {
- if (!$json.homepage.StartsWith("https://github.com/")) {
- write-host "ERROR: $name checkver expects the homepage to be a github repository" -f DarkYellow
+ $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"
}
- $url = $json.homepage + "/releases/latest"
+ $url = $json.homepage.TrimEnd('/') + '/releases/latest'
$regex = $githubRegex
+ $useGithubAPI = $true
}
if ($json.checkver.github) {
- $url = $json.checkver.github + "/releases/latest"
+ $url = $json.checkver.github.TrimEnd('/') + '/releases/latest'
$regex = $githubRegex
+ 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 -eq 'sourceforge') {
+ if ($json.homepage -match '//(sourceforge|sf)\.net/projects/(?[^/]+)(/files/(?[^/]+))?|//(?[^.]+)\.(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 '(?[\w-]*)(/(?.*))?') {
+ $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) {
+ if ($json.checkver.jp) {
$jsonpath = $json.checkver.jp
}
+ if ($json.checkver.jsonpath) {
+ $jsonpath = $json.checkver.jsonpath
+ }
+ if ($json.checkver.xpath) {
+ $xpath = $json.checkver.xpath
+ }
+
+ if ($json.checkver.replace -is [System.String]) { # If `checkver` is [System.String], it has a method called `Replace`
+ $replace = $json.checkver.replace
+ }
- if(!$jsonpath -and !$regex) {
+ if (!$jsonpath -and !$regex -and !$xpath) {
$regex = $json.checkver
}
- $state = new-object psobject @{
- app = (strip_ext $name);
- url = $url;
- regex = $regex;
- json = $json;
- jsonpath = $jsonpath;
+ $reverse = $json.checkver.reverse -and $json.checkver.reverse -eq 'true'
+
+ if ($url -like '*api.github.com/*') { $useGithubAPI = $true }
+
+ if ($useGithubAPI -and ($null -ne $GitHubToken)) {
+ $url = $url -replace '//(www\.)?github.com/', '//api.github.com/repos/'
+ $wc.Headers.Add('Authorization', "token $GitHubToken")
+ }
+
+ $url = substitute $url $substitutions
+
+ $state = New-Object psobject @{
+ app = $name
+ file = $file
+ url = $url
+ regex = $regex
+ json = $json
+ jsonpath = $jsonpath
+ xpath = $xpath
+ reverse = $reverse
+ replace = $replace
}
- $wc.headers.add('Referer', (strip_filename $url))
- $wc.downloadstringasync($url, $state)
+ get_config PRIVATE_HOSTS | Where-Object { $_ -ne $null -and $url -match $_.match } | ForEach-Object {
+ (ConvertFrom-StringData -StringData $_.Headers).GetEnumerator() | ForEach-Object {
+ $wc.Headers[$_.Key] = $_.Value
+ }
+ }
+
+ $wc.Headers.Add('Referer', (strip_filename $url))
+ $wc.DownloadDataAsync($url, $state)
+}
+
+function next($er) {
+ Write-Host "$App`: " -NoNewline
+ Write-Host $er -ForegroundColor DarkRed
}
# wait for all to complete
-$in_progress = $queue.length
-while($in_progress -gt 0) {
- $ev = wait-event
- remove-event $ev.sourceidentifier
+$in_progress = $Queue.length
+while ($in_progress -gt 0) {
+ $ev = Wait-Event
+ Remove-Event $ev.SourceIdentifier
$in_progress--
- $state = $ev.sourceeventargs.userstate
+ $state = $ev.SourceEventArgs.UserState
+ $result = $ev.SourceEventArgs.Result
$app = $state.app
+ $file = $state.file
$json = $state.json
$url = $state.url
- $expected_ver = $json.version
$regexp = $state.regex
$jsonpath = $state.jsonpath
- $ver = ""
-
- $err = $ev.sourceeventargs.error
- $page = $ev.sourceeventargs.result
-
- write-host "$app`: " -nonewline
-
- if($err) {
- write-host -f darkred $err.message
- write-host -f darkred "URL $url is not valid"
- continue
- }
-
- if($jsonpath -and $regexp) {
- write-host -f darkred "'jp' and 're' shouldn't be used together"
- continue
- }
+ $xpath = $state.xpath
+ $script = $json.checkver.script
+ $reverse = $state.reverse
+ $replace = $state.replace
+ $expected_ver = $json.version
+ $ver = $Version
- if($jsonpath) {
- $ver = json_path ($page | ConvertFrom-Json -ea stop) $jsonpath
- if(!$ver) {
- write-host -f darkred "couldn't find '$jsonpath' in $url"
+ if (!$ver) {
+ if (!$regexp -and $replace) {
+ next "'replace' requires 're' or 'regex'"
continue
}
- }
-
- if($regexp) {
- if($page -match $regexp) {
- $ver = $matches[1]
- if(!$ver) {
- $ver = $matches['version']
- }
- } else {
- write-host -f darkred "couldn't match '$regexp' in $url"
+ $err = $ev.SourceEventArgs.Error
+ if ($err) {
+ next "$($err.message)`r`nURL $url is not valid"
continue
}
- }
- if(!$ver) {
- write-host -f darkred "couldn't find new version in $url"
- continue
- }
+ if ($url) {
+ $ms = New-Object System.IO.MemoryStream
+ $ms.Write($result, 0, $result.Length)
+ $ms.Seek(0, 0) | Out-Null
+ if ($result[0] -eq 0x1F -and $result[1] -eq 0x8B) {
+ $ms = New-Object System.IO.Compression.GZipStream($ms, [System.IO.Compression.CompressionMode]::Decompress)
+ }
+ $page = (New-Object System.IO.StreamReader($ms, (Get-Encoding $wc))).ReadToEnd()
+ }
+ $source = $url
+ if ($script) {
+ $page = Invoke-Command ([scriptblock]::Create($script -join "`r`n"))
+ $source = 'the output of script'
+ }
- if($ver -eq $expected_ver) {
- write-host "$ver" -f darkgreen
+ if ($jsonpath) {
+ # Return only a single value if regex is absent
+ $noregex = [String]::IsNullOrEmpty($regexp)
+ # If reverse is ON and regex is ON,
+ # Then reverse would have no effect because regex handles reverse
+ # on its own
+ # So in this case we have to disable reverse
+ $ver = json_path $page $jsonpath $null ($reverse -and $noregex) $noregex
+ if (!$ver) {
+ $ver = json_path_legacy $page $jsonpath
+ }
+ if (!$ver) {
+ next "couldn't find '$jsonpath' in $source"
+ continue
+ }
+ }
- if ($forceUpdate -and $json.autoupdate) {
- Write-Host "Forcing autoupdate!" -f DarkMagenta
- try {
- autoupdate $app $dir $json $ver $matches
- } catch {
- write-host -f darkred $_.exception.message
+ if ($xpath) {
+ $xml = [xml]$page
+ # Find all `significant namespace declarations` from the XML file
+ $nsList = $xml.SelectNodes("//namespace::*[not(. = ../../namespace::*)]")
+ # Then add them into the NamespaceManager
+ $nsmgr = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
+ $nsList | ForEach-Object {
+ 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 -replace 'ns:', '')' in $source"
+ continue
}
}
- } else {
- write-host "$ver" -f darkred -nonewline
- write-host " (scoop version is $expected_ver)" -NoNewline
- $update_available = (compare_versions $expected_ver $ver) -eq -1
- if ($json.autoupdate -and $update_available) {
- Write-Host " autoupdate available" -f Cyan
- } else {
- Write-Host ""
+ if ($jsonpath -and $regexp) {
+ $page = $ver
+ $ver = ''
+ }
+
+ if ($xpath -and $regexp) {
+ $page = $ver
+ $ver = ''
}
- if ($update -and $update_available -and $json.autoupdate) {
- try {
- autoupdate $app $dir $json $ver $matches
- } catch {
- write-host -f darkred $_.exception.message
+ if ($regexp) {
+ $re = New-Object System.Text.RegularExpressions.Regex($regexp)
+ if ($reverse) {
+ $match = $re.Matches($page) | Select-Object -Last 1
+ } else {
+ $match = $re.Matches($page) | Select-Object -First 1
+ }
+
+ if ($match -and $match.Success) {
+ $matchesHashtable = @{}
+ $re.GetGroupNames() | ForEach-Object { $matchesHashtable.Add($_, $match.Groups[$_].Value) }
+ $ver = $matchesHashtable['1']
+ if ($replace) {
+ $ver = $re.Replace($match.Value, $replace)
+ }
+ if (!$ver) {
+ $ver = $matchesHashtable['version']
+ }
+ } else {
+ next "couldn't match '$regexp' in $source"
+ continue
}
}
+
+ if (!$ver) {
+ next "couldn't find new version in $source"
+ continue
+ }
}
-}
-set_https_protocols $original
+ # Skip actual only if versions are same and there is no -f
+ if (($ver -eq $expected_ver) -and !$ForceUpdate -and $SkipUpdated) { continue }
-<#
-write-host "checking $(strip_ext (fname $_))..." -nonewline
-$expected_ver = $json.version
+ Write-Host "$app`: " -NoNewline
-$url = $json.checkver.url
-if(!$url) { $url = $json.homepage }
-
-$regexp = $json.checkver.re
-if(!$regexp) { $regexp = $json.checkver }
+ # version hasn't changed (step over if forced update)
+ if ($ver -eq $expected_ver -and !$ForceUpdate) {
+ Write-Host $ver -ForegroundColor DarkGreen
+ continue
+ }
-$page = $wc.downloadstring($url)
+ Write-Host $ver -ForegroundColor DarkRed -NoNewline
+ Write-Host " (scoop version is $expected_ver)" -NoNewline
+ $update_available = (Compare-Version -ReferenceVersion $ver -DifferenceVersion $expected_ver) -ne 0
-if($page -match $regexp) {
- $ver = $matches[1]
- if($ver -eq $expected_ver) {
- write-host "$ver" -f darkgreen
+ if ($json.autoupdate -and $update_available) {
+ Write-Host ' autoupdate available' -ForegroundColor Cyan
} else {
- write-host "$ver" -f darkred -nonewline
- write-host " (scoop version is $expected_ver)"
+ Write-Host ''
}
-} else {
- write-host "couldn't match '$regexp' in $url" -f darkred
+ # forcing an update implies updating, right?
+ if ($ForceUpdate) { $Update = $true }
+
+ if ($Update -and $json.autoupdate) {
+ if ($ForceUpdate) {
+ Write-Host 'Forcing autoupdate!' -ForegroundColor DarkMagenta
+ }
+ try {
+ Invoke-AutoUpdate $app $file $json $ver $matchesHashtable # 'autoupdate.ps1'
+ } catch {
+ if ($ThrowError) {
+ throw $_
+ } else {
+ error $_.Exception.Message
+ }
+ }
+ }
}
-#>
diff --git a/bin/describe.ps1 b/bin/describe.ps1
index 8502c7469f..5faa1c403c 100644
--- a/bin/describe.ps1
+++ b/bin/describe.ps1
@@ -1,50 +1,65 @@
-param($app, $dir)
+<#
+.SYNOPSIS
+ Search for application description on homepage.
+.PARAMETER App
+ Manifest name to search.
+ Placeholders are supported.
+.PARAMETER Dir
+ Where to search for manifest(s).
+#>
+param(
+ [String] $App = '*',
+ [Parameter(Mandatory = $true)]
+ [ValidateScript( {
+ if (!(Test-Path $_ -Type Container)) {
+ throw "$_ is not a directory!"
+ } else {
+ $true
+ }
+ })]
+ [String] $Dir
+)
-. "$psscriptroot\..\lib\core.ps1"
-. "$psscriptroot\..\lib\manifest.ps1"
-. "$psscriptroot\..\lib\description.ps1"
+. "$PSScriptRoot\..\lib\core.ps1"
+. "$PSScriptRoot\..\lib\manifest.ps1"
+. "$PSScriptRoot\..\lib\description.ps1"
+. "$PSScriptRoot\..\lib\download.ps1"
-if(!$dir) {
- $dir = "$psscriptroot\..\bucket"
-}
-$dir = resolve-path $dir
-
-$search = "*"
-if($app) { $search = $app }
+$Dir = Convert-Path $Dir
+$Queue = @()
-# get apps to check
-$apps = @()
-gci $dir "$search.json" | % {
- $json = parse_json "$dir\$_"
- $apps += ,@(($_ -replace '\.json$', ''), $json)
+Get-ChildItem $Dir -Filter "$App.json" -Recurse | ForEach-Object {
+ $manifest = parse_json $_.FullName
+ $Queue += , @($_.BaseName, $manifest)
}
-$apps |% {
- $app, $json = $_
- write-host "$app`: " -nonewline
+$Queue | ForEach-Object {
+ $name, $manifest = $_
+ Write-Host "$name`: " -NoNewline
- if(!$json.homepage) {
- write-host "`nNo homepage set." -fore red
+ if (!$manifest.homepage) {
+ Write-Host "`nNo homepage set." -ForegroundColor Red
return
}
# get description from homepage
try {
- $home_html = (new-object net.webclient).downloadstring($json.homepage)
+ $wc = New-Object Net.Webclient
+ $wc.Headers.Add('User-Agent', (Get-UserAgent))
+ $homepage = $wc.DownloadData($manifest.homepage)
+ $home_html = (Get-Encoding($wc)).GetString($homepage)
} catch {
- write-host "`n$($_.exception.message)" -fore red
+ Write-Host "`n$($_.Exception.Message)" -ForegroundColor Red
return
}
- $description, $descr_method = find_description $json.homepage $home_html
- if(!$description) {
- write-host -fore red "`nDescription not found ($($json.homepage))"
+ $description, $descr_method = find_description $manifest.homepage $home_html
+ if (!$description) {
+ Write-Host "`nDescription not found ($($manifest.homepage))" -ForegroundColor Red
return
}
$description = clean_description $description
- write-host "(found by $descr_method)"
- write-host " ""$description""" -fore green
-
+ Write-Host "(found by $descr_method)"
+ Write-Host " ""$description""" -ForegroundColor Green
}
-
diff --git a/bin/formatjson.ps1 b/bin/formatjson.ps1
index 3705245e16..e66c6f69a3 100644
--- a/bin/formatjson.ps1
+++ b/bin/formatjson.ps1
@@ -1,31 +1,44 @@
-# reformat manifest json
-param($path)
+<#
+.SYNOPSIS
+ Format manifest.
+.PARAMETER App
+ Manifest to format.
-. "$psscriptroot\..\lib\core.ps1"
-. "$psscriptroot\..\lib\manifest.ps1"
-. "$psscriptroot\..\lib\json.ps1"
+ Wildcards are supported.
+.PARAMETER Dir
+ Where to search for manifest(s).
+.EXAMPLE
+ PS BUCKETROOT> .\bin\formatjson.ps1
+ Format all manifests inside bucket directory.
+.EXAMPLE
+ PS BUCKETROOT> .\bin\formatjson.ps1 7zip
+ Format manifest '7zip' inside bucket directory.
+#>
+param(
+ [String] $App = '*',
+ [Parameter(Mandatory = $true)]
+ [ValidateScript( {
+ if (!(Test-Path $_ -Type Container)) {
+ throw "$_ is not a directory!"
+ } else {
+ $true
+ }
+ })]
+ [String] $Dir
+)
-if(!$path) { $path = "$psscriptroot\..\bucket" }
-$path = resolve-path $path
+. "$PSScriptRoot\..\lib\core.ps1"
+. "$PSScriptRoot\..\lib\manifest.ps1"
+. "$PSScriptRoot\..\lib\json.ps1"
-$dir = ""
-$type = Get-Item $path
-if ($type -is [System.IO.DirectoryInfo]) {
- $dir = "$path\"
- $files = Get-ChildItem $path "*.json"
-} elseif ($type -is [System.IO.FileInfo]) {
- $files = @($path)
-} else {
- Write-Error "unknown item"
- exit
-}
+$Dir = Convert-Path $Dir
-$files | % {
+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)
+ $json = $json -replace "`t", ' '
+ [System.IO.File]::WriteAllLines($file, $json)
}
diff --git a/bin/install.ps1 b/bin/install.ps1
index c479d71508..b7f35591e8 100644
--- a/bin/install.ps1
+++ b/bin/install.ps1
@@ -1,46 +1,2 @@
-#requires -v 3
-
-# remote install:
-# iex (new-object net.webclient).downloadstring('https://get.scoop.sh')
-$erroractionpreference='stop' # quit if anything goes wrong
-
-# show notification to change execution policy:
-if((get-executionpolicy) -gt 'RemoteSigned') {
- "PowerShell requires an execution policy of 'RemoteSigned' to run Scoop."
- "To make this change please run:"
- "'Set-ExecutionPolicy RemoteSigned -scope CurrentUser'"
- break
-}
-
-# get core functions
-$core_url = 'https://raw.github.com/lukesampson/scoop/master/lib/core.ps1'
-echo 'Initializing...'
-iex (new-object net.webclient).downloadstring($core_url)
-
-# prep
-if(installed 'scoop') {
- 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/lukesampson/scoop/archive/master.zip'
-$zipfile = "$dir\scoop.zip"
-echo 'Downloading...'
-dl $zipurl $zipfile
-
-'Extracting...'
-unzip $zipfile "$dir\_tmp"
-cp "$dir\_tmp\scoop-master\*" $dir -r -force
-rm "$dir\_tmp" -r -force
-rm $zipfile
-
-echo 'Creating shim...'
-shim "$dir\bin\scoop.ps1" $false
-
-ensure_robocopy_in_path
-ensure_scoop_in_path
-success 'Scoop was installed successfully!'
-echo "Type 'scoop help' for instructions."
+#Requires -Version 5
+Invoke-RestMethod https://get.scoop.sh | Invoke-Expression
diff --git a/bin/missing-checkver.ps1 b/bin/missing-checkver.ps1
index 17c14b28bc..3ba2d2d660 100644
--- a/bin/missing-checkver.ps1
+++ b/bin/missing-checkver.ps1
@@ -1,36 +1,52 @@
-# list manifests which do not specify a checkver regex
+<#
+.SYNOPSIS
+ Check if manifest contains checkver and autoupdate property.
+.PARAMETER App
+ Manifest name.
+ Wirldcard is supported.
+.PARAMETER Dir
+ Location of manifests.
+.PARAMETER SkipSupported
+ Manifests with checkver and autoupdate will not be presented.
+#>
param(
- [String]$dir,
- [Switch]$skipSupported = $false
+ [String] $App = '*',
+ [Parameter(Mandatory = $true)]
+ [ValidateScript( {
+ if (!(Test-Path $_ -Type Container)) {
+ throw "$_ is not a directory!"
+ } else {
+ $true
+ }
+ })]
+ [String] $Dir,
+ [Switch] $SkipSupported
)
-. "$psscriptroot\..\lib\core.ps1"
-. "$psscriptroot\..\lib\manifest.ps1"
+. "$PSScriptRoot\..\lib\core.ps1"
+. "$PSScriptRoot\..\lib\manifest.ps1"
-if(!$dir) { $dir = "$psscriptroot\..\bucket" }
-$dir = resolve-path $dir
+$Dir = Convert-Path $Dir
-write-host "[" -nonewline
-write-host -f green "C" -nonewline
-write-host "]heckver"
-write-host " | [" -nonewline
-write-host -f cyan "A" -nonewline
-write-host "]utoupdate"
-write-host " | |"
+Write-Host '[' -NoNewLine
+Write-Host 'C' -NoNewLine -ForegroundColor Green
+Write-Host ']heckver'
+Write-Host ' | [' -NoNewLine
+Write-Host 'A' -NoNewLine -ForegroundColor Cyan
+Write-Host ']utoupdate'
+Write-Host ' | |'
-gci $dir "*.json" | % {
- $json = parse_json "$dir\$_"
+Get-ChildItem $Dir -Filter "$App.json" -Recurse | ForEach-Object {
+ $json = parse_json $_.FullName
- if ($skipSupported -and $json.checkver -and $json.autoupdate) {
- return
- }
+ if ($SkipSupported -and $json.checkver -and $json.autoupdate) { return }
- write-host "[" -nonewline
- write-host -f green -nonewline $( If ($json.checkver) {"C"} Else {" "} )
- write-host "]" -nonewline
+ Write-Host '[' -NoNewLine
+ Write-Host $(if ($json.checkver) { 'C' } else { ' ' }) -NoNewLine -ForegroundColor Green
+ Write-Host ']' -NoNewLine
- write-host "[" -nonewline
- write-host -f cyan -nonewline $( If ($json.autoupdate) {"A"} Else {" "} )
- write-host "] " -nonewline
- write-host (strip_ext $_)
+ Write-Host '[' -NoNewLine
+ Write-Host $(if ($json.autoupdate) { 'A' } else { ' ' }) -NoNewLine -ForegroundColor Cyan
+ Write-Host '] ' -NoNewLine
+ Write-Host $_.BaseName
}
diff --git a/bin/refresh.ps1 b/bin/refresh.ps1
index 5654a01bf1..27a7beb95b 100644
--- a/bin/refresh.ps1
+++ b/bin/refresh.ps1
@@ -1,7 +1,7 @@
# for development, update the installed scripts to match local source
-. "$psscriptroot\..\lib\core.ps1"
+. "$PSScriptRoot\..\lib\core.ps1"
-$src = relpath ".."
+$src = "$PSScriptRoot\.."
$dest = ensure (versiondir 'scoop' 'current')
# make sure not running from the installed directory
@@ -10,10 +10,9 @@ if("$src" -eq "$dest") { abort "$(strip_ext $myinvocation.mycommand.name) is for
'copying files...'
$output = robocopy $src $dest /mir /njh /njs /nfl /ndl /xd .git tmp /xf .DS_Store last_updated
-$output | ? { $_ -ne "" }
+$output | Where-Object { $_ -ne "" }
-echo 'creating shim...'
+Write-Output 'creating shim...'
shim "$dest\bin\scoop.ps1" $false
-ensure_scoop_in_path
success 'scoop was refreshed!'
diff --git a/bin/scoop.ps1 b/bin/scoop.ps1
index 16bb84bc06..fd2fd41fa7 100644
--- a/bin/scoop.ps1
+++ b/bin/scoop.ps1
@@ -1,15 +1,53 @@
-#requires -v 3
-param($cmd)
+#Requires -Version 5
+Set-StrictMode -Off
-set-strictmode -off
+. "$PSScriptRoot\..\lib\core.ps1"
+. "$PSScriptRoot\..\lib\buckets.ps1"
+. "$PSScriptRoot\..\lib\commands.ps1"
+. "$PSScriptRoot\..\lib\help.ps1"
-. "$psscriptroot\..\lib\core.ps1"
-. (relpath '..\lib\commands')
+$subCommand = $Args[0]
-reset_aliases
+# for aliases where there's a local function, re-alias so the function takes precedence
+$aliases = Get-Alias | Where-Object { $_.Options -notmatch 'ReadOnly|AllScope' } | ForEach-Object { $_.Name }
+Get-ChildItem Function: | Where-Object -Property Name -In -Value $aliases | ForEach-Object {
+ Set-Alias -Name $_.Name -Value Local:$($_.Name) -Scope Script
+}
-$commands = commands
+switch ($subCommand) {
+ ({ $subCommand -in @($null, '-h', '--help', '/?') }) {
+ exec 'help'
+ }
+ ({ $subCommand -in @('-v', '--version') }) {
+ Write-Host 'Current Scoop version:'
+ if (Test-GitAvailable -and (Test-Path "$PSScriptRoot\..\.git") -and (get_config SCOOP_BRANCH 'master') -ne 'master') {
+ Invoke-Git -Path "$PSScriptRoot\.." -ArgumentList @('log', 'HEAD', '-1', '--oneline')
+ } else {
+ $version = Select-String -Pattern '^## \[(v[\d.]+)\].*?([\d-]+)$' -Path "$PSScriptRoot\..\CHANGELOG.md"
+ Write-Host $version.Matches.Groups[1].Value -ForegroundColor Cyan -NoNewline
+ Write-Host " - Released at $($version.Matches.Groups[2].Value)"
+ }
+ Write-Host ''
-if (@($null, '-h', '--help', '/?') -contains $cmd) { exec 'help' $args }
-elseif ($commands -contains $cmd) { exec $cmd $args }
-else { "scoop: '$cmd' isn't a scoop command. See 'scoop help'."; exit 1 }
+ Get-LocalBucket | ForEach-Object {
+ $bucketLoc = Find-BucketDirectory $_ -Root
+ if (Test-GitAvailable -and (Test-Path "$bucketLoc\.git")) {
+ Write-Host "'$_' bucket:"
+ Invoke-Git -Path $bucketLoc -ArgumentList @('log', 'HEAD', '-1', '--oneline')
+ Write-Host ''
+ }
+ }
+ }
+ ({ $subCommand -in (commands) }) {
+ [string[]]$arguments = $Args | Select-Object -Skip 1
+ if ($null -ne $arguments -and $arguments[0] -in @('-h', '--help', '/?')) {
+ exec 'help' @($subCommand)
+ } else {
+ exec $subCommand $arguments
+ }
+ }
+ default {
+ warn "scoop: '$subCommand' isn't a scoop command. See 'scoop help'."
+ exit 1
+ }
+}
diff --git a/bin/test.ps1 b/bin/test.ps1
index a32e23c195..3e2cc6fc55 100644
--- a/bin/test.ps1
+++ b/bin/test.ps1
@@ -1 +1 @@
-invoke-pester $psscriptroot\..\test
+. "$PSScriptRoot\..\test\bin\test.ps1"
diff --git a/bin/uninstall.ps1 b/bin/uninstall.ps1
index f520cf3760..2e2dc36ea8 100644
--- a/bin/uninstall.ps1
+++ b/bin/uninstall.ps1
@@ -1,74 +1,107 @@
-param($global)
+<#
+.SYNOPSIS
+ Uninstall ALL scoop applications and scoop itself.
+.PARAMETER global
+ Global applications will be uninstalled.
+.PARAMETER purge
+ Persisted data will be deleted.
+#>
+param(
+ [bool] $global,
+ [bool] $purge
+)
-. "$psscriptroot\..\lib\core.ps1"
-. "$psscriptroot\..\lib\install.ps1"
-. "$psscriptroot\..\lib\shortcuts.ps1"
-. "$psscriptroot\..\lib\versions.ps1"
-. "$psscriptroot\..\lib\manifest.ps1"
+. "$PSScriptRoot\..\lib\core.ps1"
+. "$PSScriptRoot\..\lib\system.ps1"
+. "$PSScriptRoot\..\lib\install.ps1"
+. "$PSScriptRoot\..\lib\shortcuts.ps1"
+. "$PSScriptRoot\..\lib\versions.ps1"
+. "$PSScriptRoot\..\lib\manifest.ps1"
-if($global -and !(is_admin)) {
- "ERROR: You need admin rights to uninstall globally."; exit 1
+if ($global -and !(is_admin)) {
+ error 'You need admin rights to uninstall globally.'
+ exit 1
}
-warn 'This will uninstall Scoop and all the programs that have been installed with Scoop!'
-$yn = read-host 'Are you sure? (yN)'
-if($yn -notlike 'y*') { exit }
+if ($purge) {
+ warn 'This will uninstall Scoop, all the programs that have been installed with Scoop and all persisted data!'
+} else {
+ warn 'This will uninstall Scoop and all the programs that have been installed with Scoop!'
+}
+$yn = Read-Host 'Are you sure? (yN)'
+if ($yn -notlike 'y*') { exit }
$errors = $false
+
+# Uninstall given app
function do_uninstall($app, $global) {
- $version = current_version $app $global
+ $version = Select-CurrentVersion -AppName $app -Global:$global
$dir = versiondir $app $version $global
$manifest = installed_manifest $app $version $global
$install = install_info $app $version $global
$architecture = $install.architecture
- echo "Uninstalling '$app'"
- run_uninstaller $manifest $architecture $dir
- rm_shims $manifest $global $architecture
+ Write-Output "Uninstalling '$app'"
+ Invoke-Installer -Path $dir -Manifest $manifest -ProcessorArchitecture $architecture -Uninstall
+ rm_shims $app $manifest $global $architecture
# If a junction was used during install, that will have been used
# as the reference directory. Othewise it will just be the version
# directory.
$refdir = unlink_current (appdir $app $global)
- env_rm_path $manifest $refdir $global
- env_rm $manifest $global
+ env_rm_path $manifest $refdir $global $architecture
+ env_rm $manifest $global $architecture
$appdir = appdir $app $global
try {
- rm -r -force $appdir -ea stop
+ Remove-Item $appdir -Recurse -Force -ErrorAction Stop
} catch {
$errors = $true
- warn "Couldn't remove $(friendly_path $appdir): $_.exception"
+ warn "Couldn't remove $(friendly_path $appdir): $_.Exception"
}
}
+
function rm_dir($dir) {
try {
- rm -r -force $dir -ea stop
+ Remove-Item $dir -Recurse -Force -ErrorAction Stop
} catch {
abort "Couldn't remove $(friendly_path $dir): $_"
}
}
-# run uninstallation for each app if necessary, continuing if there's
+# Remove all folders (except persist) inside given scoop directory.
+function keep_onlypersist($directory) {
+ Get-ChildItem $directory -Exclude 'persist' | ForEach-Object { rm_dir $_ }
+}
+
+# Run uninstallation for each app if necessary, continuing if there's
# a problem deleting a directory (which is quite likely)
-if($global) {
- installed_apps $true | % { # global apps
+if ($global) {
+ installed_apps $true | ForEach-Object { # global apps
do_uninstall $_ $true
}
}
-installed_apps $false | % { # local apps
+
+installed_apps $false | ForEach-Object { # local apps
do_uninstall $_ $false
}
-if($errors) {
- abort "Not all apps could be deleted. Try again or restart."
+if ($errors) {
+ abort 'Not all apps could be deleted. Try again or restart.'
}
-rm_dir $scoopdir
-if($global) { rm_dir $globaldir }
+if ($purge) {
+ rm_dir $scoopdir
+ if ($global) { rm_dir $globaldir }
+} else {
+ keep_onlypersist $scoopdir
+ if ($global) { keep_onlypersist $globaldir }
+}
-remove_from_path (shimdir $false)
-if($global) { remove_from_path (shimdir $true) }
+Remove-Path -Path (shimdir $global) -Global:$global
+if (get_config USE_ISOLATED_PATH) {
+ Remove-Path -Path ('%' + $scoopPathEnvVar + '%') -Global:$global
+}
-success "Scoop has been uninstalled."
+success 'Scoop has been uninstalled.'
diff --git a/bucket/7zip.json b/bucket/7zip.json
deleted file mode 100644
index a6e6120d18..0000000000
--- a/bucket/7zip.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "homepage": "http://www.7-zip.org/",
- "license": "http://www.7-zip.org/license.txt",
- "version": "16.04",
- "architecture": {
- "64bit": {
- "url": "http://7-zip.org/a/7z1604-x64.msi",
- "hash": "b3885b2f090f1e9b5cf2b9f802b07fe88e472d70d60732db9f830209ac296067"
- },
- "32bit": {
- "url": "http://7-zip.org/a/7z1604.msi",
- "hash": "d9b62c0ed0eb48d2df86d8b83394048414a2a4e1d64a50adb9abcff643471d20"
- }
- },
- "extract_dir": "Files/7-Zip",
- "bin": "7z.exe",
- "checkver": "Download 7-zip ([^\\ ]+)",
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "http://7-zip.org/a/7z$cleanVersion-x64.msi"
- },
- "32bit": {
- "url": "http://7-zip.org/a/7z$cleanVersion.msi"
- }
- }
- }
-}
diff --git a/bucket/ack.json b/bucket/ack.json
deleted file mode 100644
index 899d84b95c..0000000000
--- a/bucket/ack.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "homepage": "http://beyondgrep.com/",
- "license": "http://opensource.org/licenses/Artistic-2.0",
- "version": "2.18",
- "url": "http://beyondgrep.com/ack-2.18-single-file#/ack-single-file",
- "hash": "6e41057c8f50f661d800099471f769209480efa53b8a886969d7ec6db60a2208",
- "bin": "ack.bat",
- "depends": "perl",
- "pre_install": "Set-Content -Value '@perl.exe %~dp0ack-single-file %*' -Path $dir\\ack.bat",
- "checkver": {
- "url": "http://beyondgrep.com/install/",
- "re": "The current stable version of ack is version ([\\d.]+),"
- },
- "autoupdate": {
- "url": "http://beyondgrep.com/ack-$version-single-file#/ack-single-file"
- }
-}
diff --git a/bucket/acmesharp.json b/bucket/acmesharp.json
deleted file mode 100644
index 22ec8a56db..0000000000
--- a/bucket/acmesharp.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "version": "0.8.1.0",
- "homepage": "https://github.com/ebekker/ACMESharp",
- "url": "https://github.com/ebekker/ACMESharp/releases/download/v0.8.1.0-EA/ACME-posh.zip",
- "hash": "b1da3d39744ba5842bb3a3b97da9a5e4d4c22314b741baa0175e9d0c977ec3f1",
- "extract_dir": "Debug/ACMESharp",
- "psmodule": {
- "name": "ACMESharp"
- }
-}
diff --git a/bucket/adb.json b/bucket/adb.json
deleted file mode 100644
index b42b52393c..0000000000
--- a/bucket/adb.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "version": "25.0.5",
- "homepage": "https://developer.android.com/studio/releases/platform-tools.html",
- "url": "https://dl.google.com/android/repository/platform-tools_r25.0.5-windows.zip",
- "hash": "4e70c4bd999f7dd7f466266b9846dc8ac51c97c649ad7a71b42f3184d6e17ee3",
- "bin": [
- "platform-tools\\adb.exe",
- "platform-tools\\dmtracedump.exe",
- "platform-tools\\etc1tool.exe",
- "platform-tools\\fastboot.exe",
- "platform-tools\\hprof-conv.exe"
- ],
- "checkver": "([\\d.]+) \\(.*\\)",
- "autoupdate": {
- "url": "https://dl.google.com/android/repository/platform-tools_r$version-windows.zip"
- }
-}
diff --git a/bucket/ag.json b/bucket/ag.json
deleted file mode 100644
index e56a6dbee4..0000000000
--- a/bucket/ag.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "homepage": "http://geoff.greer.fm/ag/",
- "license": "Apache 2.0",
- "version": "0.29.1",
- "url": "https://kjkpub.s3.amazonaws.com/software/the_silver_searcher/rel/0.29.1-1641/ag.zip",
- "hash": "0f2643b925df66a56df82d419262c88c076ba257ab3a57c77291fce7b4479530",
- "bin": "ag.exe",
- "checkver": "the_silver_searcher-([\\d.]+).tar.gz"
-}
diff --git a/bucket/allure.json b/bucket/allure.json
deleted file mode 100644
index 17b0579e0c..0000000000
--- a/bucket/allure.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "homepage": "https://github.com/allure-framework/allure2",
- "version": "2.1.0",
- "license": "https://github.com/allure-framework/allure2/blob/master/LICENSE",
- "url": "https://dl.bintray.com/qameta/generic/io/qameta/allure/allure/2.1.0/allure-2.1.0.zip",
- "hash": "9a3ec0e52bacb7fe7f38fa720f01e2fde4784f204de6457f2896cd987d399c22",
- "extract_dir": "allure-2.1.0",
- "bin": "bin\\allure.bat",
- "env_set": {
- "ALLURE_HOME": "$dir"
- },
- "persist": [
- "config",
- "plugins"
- ],
- "checkver": "github",
- "autoupdate": {
- "url": "https://dl.bintray.com/qameta/generic/io/qameta/allure/allure/$version/allure-$version.zip",
- "extract_dir": "allure-$version",
- "hash": {
- "mode": "extract",
- "url": "$url.sha256"
- }
- }
-}
diff --git a/bucket/ant.json b/bucket/ant.json
deleted file mode 100644
index 3dd0f89d64..0000000000
--- a/bucket/ant.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "homepage": "http://ant.apache.org/",
- "version": "1.10.1",
- "license": "Apache 2.0",
- "url": "http://www-us.apache.org/dist/ant/binaries/apache-ant-1.10.1-bin.zip",
- "hash": "sha512:cf85d2b52ac379eaf83ae98544fd0317833a57811764cb1f5082f1ef046ba4f069bddf980f594ca00a93e1b37b4e646fdc8885a37651c5c9e8fc5d2b595256f6",
- "extract_dir": "apache-ant-1.10.1",
- "env_add_path": "bin",
- "env_set": {
- "ANT_HOME": "$dir"
- },
- "suggest": {
- "JDK": [
- "extras/oraclejdk",
- "openjdk"
- ]
- },
- "checkver": {
- "url": "https://ant.apache.org/bindownload.cgi",
- "re": "Currently, Apache Ant (?:[\\d.]+ and )?([\\d.]+) (?:is|are) the best"
- },
- "autoupdate": {
- "url": "http://www-us.apache.org/dist/ant/binaries/apache-ant-$version-bin.zip",
- "extract_dir": "apache-ant-$version",
- "hash": {
- "url": "$url.sha512"
- }
- }
-}
diff --git a/bucket/apache.json b/bucket/apache.json
deleted file mode 100644
index 802635973c..0000000000
--- a/bucket/apache.json
+++ /dev/null
@@ -1,56 +0,0 @@
-{
- "homepage": "https://www.apachelounge.com",
- "version": "2.4.25",
- "license": "Apache 2.0",
- "architecture": {
- "64bit": {
- "url": "https://www.apachelounge.com/download/VC14/binaries/httpd-2.4.25-win64-VC14.zip",
- "hash": "E03A43B53F00320DE27D9B7046F5E317D06268795592EF32353CE857D7AA4D76"
- },
- "32bit": {
- "url": "https://www.apachelounge.com/download/VC14/binaries/httpd-2.4.25-win32-VC14.zip",
- "hash": "7773F8B02E367D4F7853292DC2B4FCB4085F509C85D9851030CC1F3C453FD4D2"
- }
- },
- "extract_dir": "Apache24",
- "persist": [
- "htdocs",
- "conf"
- ],
- "bin": [
- "bin\\ab.exe",
- "bin\\abs.exe",
- "bin\\htcacheclean.exe",
- "bin\\htdbm.exe",
- "bin\\htdigest.exe",
- "bin\\htpasswd.exe",
- "bin\\httpd.exe",
- "bin\\httxt2dbm.exe",
- "bin\\logresolve.exe",
- "bin\\rotatelogs.exe"
- ],
- "post_install": "
-# set directory in httpd.conf
-$conf = \"$dir/conf/httpd.conf\"
-$root=(scoop which httpd | split-path -res -par | split-path -par) -replace '\\\\', '/';
-(gc $conf) | % { $_ -replace 'c:/Apache24', \"$root\" } | sc $conf
-",
- "checkver": {
- "url": "https://www.apachelounge.com/download/",
- "re": "Apache ([\\d.]+) Win32"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://www.apachelounge.com/download/VC14/binaries/httpd-$version-win64-VC14.zip"
- },
- "32bit": {
- "url": "https://www.apachelounge.com/download/VC14/binaries/httpd-$version-win32-VC14.zip"
- }
- },
- "hash": {
- "url": "$url.txt",
- "find": "SHA256-Checksum for: (?:$basename):\\s+([a-fA-F0-9]{64})"
- }
- }
-}
diff --git a/bucket/apex.json b/bucket/apex.json
deleted file mode 100644
index 568d75467e..0000000000
--- a/bucket/apex.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "homepage": "http://apex.run/",
- "license": "https://github.com/apex/apex/blob/master/LICENSE",
- "version": "0.13.1",
- "architecture": {
- "64bit": {
- "url": "https://github.com/apex/apex/releases/download/v0.13.1/apex_windows_amd64.exe#/apex.exe",
- "hash": "b7274c8eec1f367604c92204b4ddafa93b06b71561b1421c3b5086c7bea1b1b7"
- },
- "32bit": {
- "url": "https://github.com/apex/apex/releases/download/v0.13.1/apex_windows_386.exe#/apex.exe",
- "hash": "b7f866b5056cd6505a757af15e2004ff119d0e908fe1e88f64ccf2ec19ac0266"
- }
- },
- "extract_dir": "apex",
- "bin": "apex.exe",
- "checkver": {
- "github": "https://github.com/apex/apex"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://github.com/apex/apex/releases/download/v$version/apex_windows_amd64.exe#/apex.exe"
- },
- "32bit": {
- "url": "https://github.com/apex/apex/releases/download/v$version/apex_windows_386.exe#/apex.exe"
- }
- }
- }
-}
diff --git a/bucket/apngasm.json b/bucket/apngasm.json
deleted file mode 100644
index 67268b668f..0000000000
--- a/bucket/apngasm.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "homepage": "https://github.com/apngasm/apngasm",
- "version": "3.0.0",
- "url": "http://files.genshin.org/apngasm/apngasm-cli.7z",
- "hash": "cebb7eab13d56b5ade45ef50abd16bae4b63a5505192f032593ad67c1d1f2e2c",
- "bin": [
- [
- "apngasm-cli.exe",
- "apngasm"
- ]
- ]
-}
diff --git a/bucket/aria2.json b/bucket/aria2.json
deleted file mode 100644
index a44b1cc1d6..0000000000
--- a/bucket/aria2.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "homepage": "https://aria2.github.io/",
- "license": "GPL2 or later",
- "version": "1.32.0",
- "architecture": {
- "32bit": {
- "url": "https://github.com/aria2/aria2/releases/download/release-1.32.0/aria2-1.32.0-win-32bit-build1.zip",
- "hash": "39ae48b561a5e72576592b5776ea57fb04cbf43f67fad1433b0e90d54d251dc2",
- "extract_dir": "aria2-1.32.0-win-32bit-build1"
- },
- "64bit": {
- "url": "https://github.com/aria2/aria2/releases/download/release-1.32.0/aria2-1.32.0-win-64bit-build1.zip",
- "hash": "d42f733f18e400bbb7684feeec0f3a487ee73d248435404b4215166513ecb693",
- "extract_dir": "aria2-1.32.0-win-64bit-build1"
- }
- },
- "bin": "aria2c.exe",
- "checkver": "Download version ([^<]+)",
- "autoupdate": {
- "architecture": {
- "32bit": {
- "url": "https://github.com/aria2/aria2/releases/download/release-$version/aria2-$version-win-32bit-build1.zip",
- "extract_dir": "aria2-$version-win-32bit-build1"
- },
- "64bit": {
- "url": "https://github.com/aria2/aria2/releases/download/release-$version/aria2-$version-win-64bit-build1.zip",
- "extract_dir": "aria2-$version-win-64bit-build1"
- }
- }
- }
-}
diff --git a/bucket/autoit.json b/bucket/autoit.json
deleted file mode 100644
index 08c6949f5c..0000000000
--- a/bucket/autoit.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "homepage": "https://www.autoitscript.com/site/autoit/",
- "license": "https://www.autoitscript.com/autoit3/docs/license.htm",
- "version": "3.3.14.2",
- "url": "https://www.autoitscript.com/files/autoit3/autoit-v3.zip",
- "hash": "44a2ba6b723cbc5eec389ea07ac43d696aeff01f0f1a62788aed1d1ce992a886",
- "extract_dir": "install",
- "architecture": {
- "64bit": {
- "bin": [
- [
- "AutoIt3_x64.exe",
- "autoit"
- ]
- ]
- },
- "32bit": {
- "bin": [
- [
- "AutoIt3.exe",
- "autoit"
- ]
- ]
- }
- },
- "checkver": {
- "url": "https://www.autoitscript.com/site/autoit/downloads/",
- "re": "Latest version: v([\\d.]+)"
- },
- "autoupdate": {
- "url": "https://www.autoitscript.com/files/autoit3/autoit-v3.zip"
- }
-}
diff --git a/bucket/axel.json b/bucket/axel.json
deleted file mode 100644
index b2e4d3b3ca..0000000000
--- a/bucket/axel.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "version": "2.4",
- "url": "https://github.com/ghuntley/cygwin-axel/raw/master/release/axel-2.4.zip",
- "homepage": "https://github.com/ghuntley/cygwin-axel/",
- "hash": "3cce621da5f17ea03e4fcf51916dd4f8928759766f88b4ca5643131d2dd3fed2",
- "bin": "axel.exe"
-}
diff --git a/bucket/bfg.json b/bucket/bfg.json
deleted file mode 100644
index 2c01f98faf..0000000000
--- a/bucket/bfg.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "homepage": "https://rtyley.github.io/bfg-repo-cleaner/",
- "license": "GPL",
- "version": "1.12.15",
- "url": "https://repo1.maven.org/maven2/com/madgag/bfg/1.12.15/bfg-1.12.15.jar",
- "hash": "330af214a0fed320c591afc1046b0f31e8a438f290da09672973aeaa6411b09d",
- "suggest": {
- "JDK": [
- "extras/oraclejdk",
- "openjdk"
- ]
- },
- "bin": "bfg.ps1",
- "env_set": {
- "BFG_HOME": "$dir"
- },
- "pre_install": "
- $exe = 'java -jar $env:BFG_HOME\\bfg-$version.jar $args'
- write-output $exe | out-file -filepath $dir\\bfg.ps1
- ",
- "checkver": {
- "url": "https://search.maven.org/solrsearch/select/?q=g:com.madgag+AND+a:bfg",
- "jp": "$.response.docs[0].latestVersion"
- },
- "autoupdate": {
- "url": "https://repo1.maven.org/maven2/com/madgag/bfg/$version/bfg-$version.jar"
- }
-}
diff --git a/bucket/bochs.json b/bucket/bochs.json
deleted file mode 100644
index fdf344260b..0000000000
--- a/bucket/bochs.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "homepage": "http://bochs.sourceforge.net/",
- "version": "2.6.9",
- "license": "LGPL",
- "architecture": {
- "64bit": {
- "url": "https://sourceforge.net/projects/bochs/files/bochs/2.6.9/bochs-2.6.9-win64.zip",
- "hash": "01f185885794f7c6b4dab920d6c51685a44ed7c7e5205a806e54df4a61ae2cf9",
- "bin": [
- "bochs-win64.exe",
- "bochsdbg-win64.exe"
- ]
- },
- "32bit": {
- "url": "https://sourceforge.net/projects/bochs/files/bochs/2.6.9/bochs-p4-smp-2.6.9-win32.zip",
- "hash": "2c01495d55cc788105165c3f9f1d68699a884fdbbf7ecbb1d0df9b9641c0c5e9",
- "bin": [
- "bochs-p4-smp.exe",
- "bochsdbg-p4-smp.exe"
- ]
- }
- },
- "checkver": {
- "url": "http://bochs.sourceforge.net/getcurrent.html",
- "re": "Latest release:<\\/b> Bochs ([\\d.]+)"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://sourceforge.net/projects/bochs/files/bochs/$version/bochs-$version-win64.zip"
- },
- "32bit": {
- "url": "https://sourceforge.net/projects/bochs/files/bochs/$version/bochs-p4-smp-$version-win32.zip"
- }
- }
- }
-}
diff --git a/bucket/busybox.json b/bucket/busybox.json
deleted file mode 100644
index 530d6a2dc8..0000000000
--- a/bucket/busybox.json
+++ /dev/null
@@ -1,652 +0,0 @@
-{
- "homepage": "https://frippery.org/busybox",
- "version": "1.26.0-FRP-756",
- "license": "GPL2",
- "url": "https://frippery.org/files/busybox/busybox-w32-FRP-756-g9fa1e49.exe#/busybox.exe",
- "hash": "260c6e2ac8a71a12aca2decfb9475a05a64cbbd734406fa964b5ff2528d7cc85",
- "bin": [
- "busybox.exe",
- [
- "busybox.exe",
- "ar",
- "ar"
- ],
- [
- "busybox.exe",
- "ash",
- "ash"
- ],
- [
- "busybox.exe",
- "awk",
- "awk"
- ],
- [
- "busybox.exe",
- "base64",
- "base64"
- ],
- [
- "busybox.exe",
- "basename",
- "basename"
- ],
- [
- "busybox.exe",
- "bash",
- "bash",
- "-l"
- ],
- [
- "busybox.exe",
- "bunzip2",
- "bunzip2"
- ],
- [
- "busybox.exe",
- "bzcat",
- "bzcat"
- ],
- [
- "busybox.exe",
- "bzip2",
- "bzip2"
- ],
- [
- "busybox.exe",
- "cal",
- "cal"
- ],
- [
- "busybox.exe",
- "cat",
- "cat"
- ],
- [
- "busybox.exe",
- "catv",
- "catv"
- ],
- [
- "busybox.exe",
- "chmod",
- "chmod"
- ],
- [
- "busybox.exe",
- "cksum",
- "cksum"
- ],
- [
- "busybox.exe",
- "clear",
- "clear"
- ],
- [
- "busybox.exe",
- "cmp",
- "cmp"
- ],
- [
- "busybox.exe",
- "comm",
- "comm"
- ],
- [
- "busybox.exe",
- "cp",
- "cp"
- ],
- [
- "busybox.exe",
- "cpio",
- "cpio"
- ],
- [
- "busybox.exe",
- "cut",
- "cut"
- ],
- [
- "busybox.exe",
- "date",
- "date"
- ],
- [
- "busybox.exe",
- "dc",
- "dc"
- ],
- [
- "busybox.exe",
- "dd",
- "dd"
- ],
- [
- "busybox.exe",
- "df",
- "df"
- ],
- [
- "busybox.exe",
- "diff",
- "diff"
- ],
- [
- "busybox.exe",
- "dirname",
- "dirname"
- ],
- [
- "busybox.exe",
- "dos2unix",
- "dos2unix"
- ],
- [
- "busybox.exe",
- "dpkg-deb",
- "dpkg-deb"
- ],
- [
- "busybox.exe",
- "du",
- "du"
- ],
- [
- "busybox.exe",
- "echo",
- "echo"
- ],
- [
- "busybox.exe",
- "ed",
- "ed"
- ],
- [
- "busybox.exe",
- "egrep",
- "egrep"
- ],
- [
- "busybox.exe",
- "env",
- "env"
- ],
- [
- "busybox.exe",
- "expand",
- "expand"
- ],
- [
- "busybox.exe",
- "expr",
- "expr"
- ],
- [
- "busybox.exe",
- "false",
- "false"
- ],
- [
- "busybox.exe",
- "fgrep",
- "fgrep"
- ],
- [
- "busybox.exe",
- "find",
- "find"
- ],
- [
- "busybox.exe",
- "fold",
- "fold"
- ],
- [
- "busybox.exe",
- "ftpget",
- "ftpget"
- ],
- [
- "busybox.exe",
- "ftpput",
- "ftpput"
- ],
- [
- "busybox.exe",
- "getopt",
- "getopt"
- ],
- [
- "busybox.exe",
- "grep",
- "grep"
- ],
- [
- "busybox.exe",
- "groups",
- "groups"
- ],
- [
- "busybox.exe",
- "gunzip",
- "gunzip"
- ],
- [
- "busybox.exe",
- "gzip",
- "gzip"
- ],
- [
- "busybox.exe",
- "hd",
- "hd"
- ],
- [
- "busybox.exe",
- "head",
- "head"
- ],
- [
- "busybox.exe",
- "hexdump",
- "hexdump"
- ],
- [
- "busybox.exe",
- "id",
- "id"
- ],
- [
- "busybox.exe",
- "ipcalc",
- "ipcalc"
- ],
- [
- "busybox.exe",
- "kill",
- "kill"
- ],
- [
- "busybox.exe",
- "killall",
- "killall"
- ],
- [
- "busybox.exe",
- "less",
- "less"
- ],
- [
- "busybox.exe",
- "ln",
- "ln"
- ],
- [
- "busybox.exe",
- "logname",
- "logname"
- ],
- [
- "busybox.exe",
- "ls",
- "ls"
- ],
- [
- "busybox.exe",
- "lzcat",
- "lzcat"
- ],
- [
- "busybox.exe",
- "lzma",
- "lzma"
- ],
- [
- "busybox.exe",
- "lzop",
- "lzop"
- ],
- [
- "busybox.exe",
- "lzopcat",
- "lzopcat"
- ],
- [
- "busybox.exe",
- "man",
- "man"
- ],
- [
- "busybox.exe",
- "md5sum",
- "md5sum"
- ],
- [
- "busybox.exe",
- "mkdir",
- "mkdir"
- ],
- [
- "busybox.exe",
- "mktemp",
- "mktemp"
- ],
- [
- "busybox.exe",
- "mv",
- "mv"
- ],
- [
- "busybox.exe",
- "nc",
- "nc"
- ],
- [
- "busybox.exe",
- "od",
- "od"
- ],
- [
- "busybox.exe",
- "patch",
- "patch"
- ],
- [
- "busybox.exe",
- "pgrep",
- "pgrep"
- ],
- [
- "busybox.exe",
- "pidof",
- "pidof"
- ],
- [
- "busybox.exe",
- "printenv",
- "printenv"
- ],
- [
- "busybox.exe",
- "printf",
- "printf"
- ],
- [
- "busybox.exe",
- "ps",
- "ps"
- ],
- [
- "busybox.exe",
- "pwd",
- "pwd"
- ],
- [
- "busybox.exe",
- "rev",
- "rev"
- ],
- [
- "busybox.exe",
- "rm",
- "rm"
- ],
- [
- "busybox.exe",
- "rmdir",
- "rmdir"
- ],
- [
- "busybox.exe",
- "rpm2cpio",
- "rpm2cpio"
- ],
- [
- "busybox.exe",
- "sed",
- "sed"
- ],
- [
- "busybox.exe",
- "seq",
- "seq"
- ],
- [
- "busybox.exe",
- "sh",
- "sh"
- ],
- [
- "busybox.exe",
- "sha1sum",
- "sha1sum"
- ],
- [
- "busybox.exe",
- "sha256sum",
- "sha256sum"
- ],
- [
- "busybox.exe",
- "sha3sum",
- "sha3sum"
- ],
- [
- "busybox.exe",
- "sha512sum",
- "sha512sum"
- ],
- [
- "busybox.exe",
- "shuf",
- "shuf"
- ],
- [
- "busybox.exe",
- "sleep",
- "sleep"
- ],
- [
- "busybox.exe",
- "sort",
- "sort"
- ],
- [
- "busybox.exe",
- "split",
- "split"
- ],
- [
- "busybox.exe",
- "stat",
- "stat"
- ],
- [
- "busybox.exe",
- "strings",
- "strings"
- ],
- [
- "busybox.exe",
- "sum",
- "sum"
- ],
- [
- "busybox.exe",
- "tac",
- "tac"
- ],
- [
- "busybox.exe",
- "tail",
- "tail"
- ],
- [
- "busybox.exe",
- "tar",
- "tar"
- ],
- [
- "busybox.exe",
- "tee",
- "tee"
- ],
- [
- "busybox.exe",
- "test",
- "test"
- ],
- [
- "busybox.exe",
- "touch",
- "touch"
- ],
- [
- "busybox.exe",
- "tr",
- "tr"
- ],
- [
- "busybox.exe",
- "true",
- "true"
- ],
- [
- "busybox.exe",
- "truncate",
- "truncate"
- ],
- [
- "busybox.exe",
- "uname",
- "uname"
- ],
- [
- "busybox.exe",
- "uncompress",
- "uncompress"
- ],
- [
- "busybox.exe",
- "unexpand",
- "unexpand"
- ],
- [
- "busybox.exe",
- "uniq",
- "uniq"
- ],
- [
- "busybox.exe",
- "unix2dos",
- "unix2dos"
- ],
- [
- "busybox.exe",
- "unlink",
- "unlink"
- ],
- [
- "busybox.exe",
- "unlzma",
- "unlzma"
- ],
- [
- "busybox.exe",
- "unlzop",
- "unlzop"
- ],
- [
- "busybox.exe",
- "unxz",
- "unxz"
- ],
- [
- "busybox.exe",
- "unzip",
- "unzip"
- ],
- [
- "busybox.exe",
- "usleep",
- "usleep"
- ],
- [
- "busybox.exe",
- "uudecode",
- "uudecode"
- ],
- [
- "busybox.exe",
- "uuencode",
- "uuencode"
- ],
- [
- "busybox.exe",
- "vi",
- "vi"
- ],
- [
- "busybox.exe",
- "wc",
- "wc"
- ],
- [
- "busybox.exe",
- "wget",
- "wget"
- ],
- [
- "busybox.exe",
- "which",
- "which"
- ],
- [
- "busybox.exe",
- "whoami",
- "whoami"
- ],
- [
- "busybox.exe",
- "whois",
- "whois"
- ],
- [
- "busybox.exe",
- "xargs",
- "xargs"
- ],
- [
- "busybox.exe",
- "xz",
- "xz"
- ],
- [
- "busybox.exe",
- "xzcat",
- "xzcat"
- ],
- [
- "busybox.exe",
- "yes",
- "yes"
- ],
- [
- "busybox.exe",
- "zcat",
- "zcat"
- ]
- ],
- "post_install": "
- if(!(test-path ~/.profile)) {
- 'creating ~/.profile'
-@\"
-if [ -e ~/.bashrc ]
-then
- source ~/.bashrc
-fi
-\"@ | out-file -en oem ~/.profile
- }
- "
-}
diff --git a/bucket/bzip2.json b/bucket/bzip2.json
deleted file mode 100644
index 0f2cca63fc..0000000000
--- a/bucket/bzip2.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "version": "1.0.6",
- "homepage": "http://www.bzip.org/",
- "architecture": {
- "32bit": {
- "url": "https://github.com/philr/bzip2-windows/releases/download/v1.0.6/bzip2-1.0.6-win-x86.zip",
- "hash": "e9a6d5908e219def07ae6be73383112c5a571b74fbde9bed42ee7eb1523fd727"
- },
- "64bit": {
- "url": "https://github.com/philr/bzip2-windows/releases/download/v1.0.6/bzip2-1.0.6-win-x64.zip",
- "hash": "f5feefa49e7d3e87ba0ba731ed22b4b0e269f635bec2839827127a98d0a2e192"
- }
- },
- "bin": [
- "bunzip2.exe",
- "bzcat.exe",
- "bzip2.exe",
- "bzip2recover.exe"
- ],
- "pre_install": "cp $dir\\bzip2.exe $dir\\bunzip2.exe; cp $dir\\bzip2.exe $dir\\bzcat.exe",
- "checkver": "The current version is ([\\d.]+)"
-}
diff --git a/bucket/cacert.json b/bucket/cacert.json
deleted file mode 100644
index 399e6a7aa3..0000000000
--- a/bucket/cacert.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "version": "2017-01-18",
- "homepage": "https://curl.haxx.se/docs/caextract.html",
- "license": "MPL 2.0",
- "url": "https://curl.haxx.se/ca/cacert-2017-01-18.pem#/cacert.pem",
- "hash": "e62a07e61e5870effa81b430e1900778943c228bd7da1259dd6a955ee2262b47",
- "checkver": {
- "url": "https://curl.haxx.se/docs/caextract.html",
- "re": "cacert-([\\d-]{10}).pem"
- },
- "post_install": "if (Test-Path \"$(appdir curl)\") {cp \"$dir\\cacert.pem\" \"$(appdir curl)\\current\\bin\\curl-ca-bundle.crt\"}",
- "autoupdate": {
- "url": "https://curl.haxx.se/ca/cacert-$version.pem#/cacert.pem"
- }
-}
diff --git a/bucket/caddy.json b/bucket/caddy.json
deleted file mode 100644
index 32a7180799..0000000000
--- a/bucket/caddy.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "version": "0.10.3",
- "homepage": "http://caddyserver.com",
- "license": "https://github.com/mholt/caddy/blob/master/LICENSE.txt",
- "architecture": {
- "64bit": {
- "url": "https://github.com/mholt/caddy/releases/download/v0.10.3/caddy_v0.10.3_windows_amd64.zip",
- "hash": "28da9b257c288e819f24fb40fecf0b792fc325e274a5f1b4bbc45de20379f70b"
- },
- "32bit": {
- "url": "https://github.com/mholt/caddy/releases/download/v0.10.3/caddy_v0.10.3_windows_386.zip",
- "hash": "51d2de0ebebfa3519062772f144632de4b6d0348fcb3a394ed5a98e04ab24031"
- }
- },
- "bin": "caddy.exe",
- "checkver": {
- "github": "https://github.com/mholt/caddy"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://github.com/mholt/caddy/releases/download/v$version/caddy_v$version_windows_amd64.zip"
- },
- "32bit": {
- "url": "https://github.com/mholt/caddy/releases/download/v$version/caddy_v$version_windows_386.zip"
- }
- }
- }
-}
diff --git a/bucket/casperjs.json b/bucket/casperjs.json
deleted file mode 100644
index b4fa985ca9..0000000000
--- a/bucket/casperjs.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "version": "1.1.4",
- "license": "https://github.com/n1k0/casperjs/blob/master/LICENSE.md",
- "url": "https://github.com/casperjs/casperjs/archive/1.1.4.zip",
- "hash": "2d98eecf417f6034394c0ec2dcefb25f47e49342801b2ed21e85b21a4dd0eddc",
- "homepage": "http://casperjs.org/",
- "extract_dir": "casperjs-1.1.4",
- "bin": "bin\\casperjs.exe",
- "notes": "Requires an installation of phantomjs 1.x
-
- phantom19 is available in the versions bucket (scoop bucket add versions)",
- "checkver": {
- "github": "https://github.com/n1k0/casperjs"
- },
- "autoupdate": {
- "url": "https://github.com/casperjs/casperjs/archive/$version.zip",
- "extract_dir": "casperjs-$version"
- }
-}
diff --git a/bucket/cdrtools.json b/bucket/cdrtools.json
deleted file mode 100644
index 7d538541e3..0000000000
--- a/bucket/cdrtools.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "architecture": {
- "32bit": {
- "extract_dir": "win32"
- },
- "64bit": {
- "extract_dir": "win64"
- }
- },
- "autoupdate": {
- "url": "https://sourceforge.net/projects/tumagcc/files/schily-cdrtools-$version.7z"
- },
- "bin": [
- "btcflash.exe",
- "cdda2wav.exe",
- "cdrecord.exe",
- "devdump.exe",
- "isodebug.exe",
- "isodump.exe",
- "isoinfo.exe",
- "isovfy.exe",
- "mkhybrid.exe",
- "mkisofs.exe",
- "readcd.exe",
- "rscsi.exe",
- "scgcheck.exe",
- "scgskeleton.exe"
- ],
- "description": "Burn and read CDs, DVDs, and Blu-ray discs",
- "hash": "f534062cab7585b82bd764f02bc65fb0c7c27ac1615786bfc81c35880ce4acc6",
- "homepage": "https://sourceforge.net/projects/tumagcc/",
- "license": "CDDL-1.0/GPL-2.0/LGPL-2.1",
- "url": "https://sourceforge.net/projects/tumagcc/files/schily-cdrtools-3.01.7z",
- "version": "3.01"
-}
diff --git a/bucket/chromedriver.json b/bucket/chromedriver.json
deleted file mode 100644
index 22a3e3da45..0000000000
--- a/bucket/chromedriver.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "version": "2.29",
- "homepage": "https://sites.google.com/a/chromium.org/chromedriver/",
- "url": "https://chromedriver.storage.googleapis.com/2.29/chromedriver_win32.zip",
- "hash": "d04084021ddd87400e9eddbee8648c97d429f038f54fe06b279584eee441a4b1",
- "bin": "chromedriver.exe",
- "checkver": "Latest Release: ChromeDriver ([\\d.]+)",
- "autoupdate": {
- "url": "https://chromedriver.storage.googleapis.com/$version/chromedriver_win32.zip"
- }
-}
diff --git a/bucket/clink.json b/bucket/clink.json
deleted file mode 100644
index bab3c3d981..0000000000
--- a/bucket/clink.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "homepage": "https://mridgers.github.io/clink/",
- "url": "https://github.com/mridgers/clink/releases/download/0.4.8/clink_0.4.8.zip",
- "version": "0.4.8",
- "hash": "cc1e07c1000e95ebbe1c6480df53487261e6457a733b925e13665740c14e15aa",
- "extract_dir": "clink_0.4.8",
- "bin": [
- "clink.bat"
- ],
- "notes": [
- "Run 'clink inject' to start clink on the current cmd",
- "Run 'clink autorun' to auto start clink"
- ]
-}
diff --git a/bucket/cmake.json b/bucket/cmake.json
deleted file mode 100644
index b328f84a9f..0000000000
--- a/bucket/cmake.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "homepage": "https://cmake.org/",
- "version": "3.8.2",
- "license": "https://cmake.org/licensing/",
- "architecture": {
- "64bit": {
- "url": "https://cmake.org/files/v3.8/cmake-3.8.2-win64-x64.zip",
- "hash": "202c2416c964fb7199e5d7ce92336a44c7ba65d5ccca36246f41d7d09bd8ffe2",
- "extract_dir": "cmake-3.8.2-win64-x64"
- },
- "32bit": {
- "url": "https://cmake.org/files/v3.8/cmake-3.8.2-win32-x86.zip",
- "hash": "3fa45a8ad473a8e0579ec826b3355f864750a7455987ed425a9c6fdf4820b5f2",
- "extract_dir": "cmake-3.8.2-win32-x86"
- }
- },
- "bin": [
- "bin/cmake.exe",
- "bin/cmcldeps.exe",
- "bin/cpack.exe",
- "bin/ctest.exe",
- "bin/cmake-gui.exe"
- ],
- "checkver": {
- "re": "Latest\\s+Release\\s+\\(([\\d+.]+)\\)",
- "url": "https://cmake.org/download/"
- },
- "shortcuts": [
- [
- "bin/cmake-gui.exe",
- "cmake-gui"
- ]
- ],
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://cmake.org/files/v$majorVersion.$minorVersion/cmake-$version-win64-x64.zip",
- "extract_dir": "cmake-$version-win64-x64"
- },
- "32bit": {
- "url": "https://cmake.org/files/v$majorVersion.$minorVersion/cmake-$version-win32-x86.zip",
- "extract_dir": "cmake-$version-win32-x86"
- }
- }
- }
-}
diff --git a/bucket/cmder.json b/bucket/cmder.json
deleted file mode 100644
index 800513e7af..0000000000
--- a/bucket/cmder.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "homepage": "http://cmder.net",
- "version": "1.3.2",
- "license": "MIT",
- "persist": [
- "config"
- ],
- "url": "https://github.com/cmderdev/cmder/releases/download/v1.3.2/cmder_mini.zip",
- "hash": "477fb784b7b3f382f7de9cd40a4d46a86dc2286b8036e68ad188abebbaea4ad6",
- "bin": "Cmder.exe",
- "shortcuts": [
- [
- "Cmder.exe",
- "Cmder"
- ]
- ],
- "env_set": {
- "CMDER_ROOT": "$dir",
- "ConEmuDir": "$dir\\vendor\\conemu-maximus5"
- },
- "checkver": {
- "github": "https://github.com/cmderdev/cmder"
- },
- "autoupdate": {
- "url": "https://github.com/cmderdev/cmder/releases/download/v$version/cmder_mini.zip"
- }
-}
diff --git a/bucket/composer.json b/bucket/composer.json
deleted file mode 100644
index 79e1f07c0e..0000000000
--- a/bucket/composer.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "homepage": "https://getcomposer.org/",
- "license": "https://github.com/composer/composer/blob/master/LICENSE",
- "version": "1.4.2",
- "url": "https://getcomposer.org/download/1.4.2/composer.phar",
- "bin": "composer.ps1",
- "persist": "home",
- "env_set": {
- "COMPOSER_HOME": "$persist_dir\\home"
- },
- "env_add_path": "home\\vendor\\bin",
- "pre_install": "
- echo 'if($args -eq \"selfupdate\" -or $args -eq \"self-update\") { & scoop update composer }' | out-file $dir\\composer.ps1
- echo 'else { & php (join-path \"$psscriptroot\" \"composer.phar\") @args }' | out-file $dir\\composer.ps1 -append
- ",
- "post_install": "
- $och = \"$env:APPDATA\\Composer\"
- if(Test-Path $och) {
- Write-Host -F yellow \"Moving old 'COMPOSER_HOME' to '$persist_dir\\home'\"
- Move-Item -Force \"$och\\*\" \"$persist_dir\\home\"
- Remove-Item -Force \"$och\"
- }
- ",
- "suggest": {
- "PHP": [
- "php",
- "php-nts"
- ]
- },
- "notes": [
- "'composer selfupdate' is aliased to 'scoop update composer'"
- ],
- "hash": "6b1945c3ee477f12be508a5bb41a5025d57de5510bcf94855ae6a4d59f3d86f4",
- "checkver": {
- "github": "https://github.com/composer/composer"
- },
- "autoupdate": {
- "url": "https://getcomposer.org/download/$version/composer.phar"
- }
-}
diff --git a/bucket/concfg.json b/bucket/concfg.json
deleted file mode 100644
index 453cd381de..0000000000
--- a/bucket/concfg.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "homepage": "https://github.com/lukesampson/concfg",
- "version": "0.2016.11.01",
- "url": "https://github.com/lukesampson/concfg/archive/cb27880092e629e1152c41b122ab591c7ca50332.zip",
- "hash": "be624dc4e251ccab1a0479d2a55b27c2caac2beaa93bfafed10880f0eaacc4c1",
- "extract_dir": "concfg-cb27880092e629e1152c41b122ab591c7ca50332",
- "bin": "bin\\concfg.ps1"
-}
diff --git a/bucket/coreutils.json b/bucket/coreutils.json
deleted file mode 100644
index be06b43c0a..0000000000
--- a/bucket/coreutils.json
+++ /dev/null
@@ -1,65 +0,0 @@
-{
- "homepage": "http://www.mingw.org/wiki/msys",
- "license": "GPL2",
- "version": "5.97.3",
- "url": [
- "https://sourceforge.net/projects/mingw/files/MSYS/Base/msys-core/msys-1.0.13-2/msysCORE-1.0.13-2-msys-1.0.13-bin.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MSYS/Base/gettext/gettext-0.17-2/libintl-0.17-2-msys-dll-8.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MSYS/Base/libiconv/libiconv-1.13.1-2/libiconv-1.13.1-2-msys-1.0.13-dll-2.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MSYS/Base/termcap/termcap-0.20050421_1-2/libtermcap-0.20050421_1-2-msys-1.0.13-dll-0.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MSYS/Base/coreutils/coreutils-5.97-3/coreutils-5.97-3-msys-1.0.13-bin.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MSYS/Base/coreutils/coreutils-5.97-3/coreutils-5.97-3-msys.RELEASE_NOTES.txt"
- ],
- "hash": [
- "41c7d5561662e41da74951f373a08a95db40b27b1246227bbbc13abc44976ea7",
- "b533de0ee04dc4d53ca745210e41eb9437044ebd367c001f3615092e7214a4a3",
- "f13de6d2e3c428e7f9a7251c6b01d6f7569e20f7ac126c68c028eb5f542473bb",
- "62b58fe0880f0972fcc84a819265989b02439c1c5185870227bd25f870f7adb6",
- "f8c7990416ea16a74ac336dcfe0f596bc46b8724b2d58cf8a3509414220b2366",
- "256208bca7a86a10bc377bdccfe6fb8f1e1f1868d0d1952a6692ee9f1d985abd"
- ],
- "bin": [
- "bin\\basename.exe",
- "bin\\cat.exe",
- "bin\\chmod.exe",
- "bin\\comm.exe",
- "bin\\cp.exe",
- "bin\\cut.exe",
- "bin\\date.exe",
- "bin\\dirname.exe",
- "bin\\echo.exe",
- "bin\\env.exe",
- "bin\\expr.exe",
- "bin\\false.exe",
- "bin\\fold.exe",
- "bin\\head.exe",
- "bin\\id.exe",
- "bin\\install.exe",
- "bin\\join.exe",
- "bin\\ln.exe",
- "bin\\ls.exe",
- "bin\\md5sum.exe",
- "bin\\mkdir.exe",
- "bin\\msysmnt.exe",
- "bin\\mv.exe",
- "bin\\od.exe",
- "bin\\paste.exe",
- "bin\\printf.exe",
- "bin\\ps.exe",
- "bin\\pwd.exe",
- "bin\\rm.exe",
- "bin\\rmdir.exe",
- "bin\\sleep.exe",
- "bin\\sort.exe",
- "bin\\split.exe",
- "bin\\stty.exe",
- "bin\\tail.exe",
- "bin\\tee.exe",
- "bin\\touch.exe",
- "bin\\tr.exe",
- "bin\\true.exe",
- "bin\\uname.exe",
- "bin\\uniq.exe",
- "bin\\wc.exe"
- ]
-}
diff --git a/bucket/cowsay.json b/bucket/cowsay.json
deleted file mode 100644
index f6aba4a3d5..0000000000
--- a/bucket/cowsay.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "version": "0.2013.07.19",
- "homepage": "https://github.com/lukesampson/cowsay-psh",
- "url": "https://github.com/lukesampson/cowsay-psh/archive/master.zip",
- "extract_dir": "cowsay-psh-master",
- "bin": [
- "cowsay.ps1",
- "cowthink.ps1"
- ]
-}
diff --git a/bucket/csvtosql.json b/bucket/csvtosql.json
deleted file mode 100644
index cbec5da965..0000000000
--- a/bucket/csvtosql.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "version": "v0.1.1-alpha",
- "license": "https://raw.githubusercontent.com/deevus/CsvToSql/master/UNLICENSE.txt",
- "url": "https://github.com/deevus/CsvToSql/archive/v0.1.1-alpha.zip",
- "depends": "gow",
- "homepage": "https://github.com/deevus/CsvToSql",
- "hash": "eb248d286cf5fd06c8ff99d527759e153513396baf08f0398a6d34fa1cba1116",
- "bin": "ConvertCsvTo-Sql.ps1",
- "extract_dir": "CsvToSql-0.1.1-alpha"
-}
diff --git a/bucket/ctags.json b/bucket/ctags.json
deleted file mode 100644
index 73c4fbbeb6..0000000000
--- a/bucket/ctags.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "homepage": "http://ctags.sourceforge.net/",
- "version": "5.8",
- "url": "https://sourceforge.net/projects/ctags/files/ctags/5.8/ctags58.zip",
- "extract_dir": "ctags58",
- "bin": "ctags.exe",
- "hash": "e1f5909ec0c7a58fd2149139fa6a1dc532070a3d919dd183671c57a32f8b243d",
- "license": "GPL2",
- "checkver": "Version ([\\d.]+)"
-}
diff --git a/bucket/curl.json b/bucket/curl.json
deleted file mode 100644
index 2181041600..0000000000
--- a/bucket/curl.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
- "homepage": "https://curl.haxx.se/",
- "version": "7.54.0",
- "license": "MIT",
- "architecture": {
- "64bit": {
- "url": "https://dl.bintray.com/vszakats/generic/curl-7.54.0-win64-mingw.7z",
- "hash": "f7d3fd25979489614f8804f9df3b318b369b6b0e1a6860316b86e1386ad2ec8b",
- "extract_dir": "curl-7.54.0-win64-mingw"
- },
- "32bit": {
- "url": "https://dl.bintray.com/vszakats/generic/curl-7.54.0-win32-mingw.7z",
- "hash": "4ef9977ace6a3dfaad87eb4047c0cc0602cf78d70bcf7300671f80d15dfa3b7f",
- "extract_dir": "curl-7.54.0-win32-mingw"
- }
- },
- "bin": "bin\\curl.exe",
- "checkver": {
- "url": "https://curl.haxx.se/download.html",
- "re": "curl ([\\d.]+)"
- },
- "suggest": {
- "cacert": [
- "cacert"
- ]
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://dl.bintray.com/vszakats/generic/curl-$version-win64-mingw.7z",
- "extract_dir": "curl-$version-win64-mingw"
- },
- "32bit": {
- "url": "https://dl.bintray.com/vszakats/generic/curl-$version-win32-mingw.7z",
- "extract_dir": "curl-$version-win32-mingw"
- }
- },
- "hash": {
- "url": "https://api.bintray.com/search/file?subject=vszakats&repo=generic&name=$basename",
- "mode": "json",
- "jp": "$.[0].sha256"
- }
- }
-}
diff --git a/bucket/dart-sass.json b/bucket/dart-sass.json
deleted file mode 100644
index 661c40dc85..0000000000
--- a/bucket/dart-sass.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "homepage": "https://github.com/sass/dart-sass",
- "version": "1.0.0-alpha.9",
- "license": "https://raw.githubusercontent.com/sass/dart-sass/master/LICENSE",
- "architecture": {
- "64bit": {
- "url": "https://github.com/sass/dart-sass/releases/download/1.0.0-alpha.9/dart-sass-1.0.0-alpha.9-windows-x64.zip",
- "hash": "b7ce20f663b47ccad95a23525b8a2586d204a55dcece2ea41f22414ad47d2e7d"
- },
- "32bit": {
- "url": "https://github.com/sass/dart-sass/releases/download/1.0.0-alpha.9/dart-sass-1.0.0-alpha.9-windows-ia32.zip",
- "hash": "0380cb99b29f0526a834bb6740f7fb0bd410c5fb486ef933321a8d74e2469b6f"
- }
- },
- "extract_dir": "dart-sass",
- "bin": [
- "dart-sass.bat"
- ],
- "checkver": {
- "url": "https://github.com/sass/dart-sass/releases/latest",
- "re": "/releases/tag/(?:v)?([\\d\\w.-]+)"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://github.com/sass/dart-sass/releases/download/$version/dart-sass-$version-windows-x64.zip"
- },
- "32bit": {
- "url": "https://github.com/sass/dart-sass/releases/download/$version/dart-sass-$version-windows-ia32.zip"
- }
- }
- }
-}
diff --git a/bucket/dart.json b/bucket/dart.json
deleted file mode 100644
index ddac55e841..0000000000
--- a/bucket/dart.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "version": "1.23.0",
- "license": "BSD",
- "homepage": "https://www.dartlang.org/",
- "extract_dir": "dart-sdk",
- "env_add_path": [
- "bin"
- ],
- "architecture": {
- "64bit": {
- "url": "https://storage.googleapis.com/dart-archive/channels/stable/release/1.23.0/sdk/dartsdk-windows-x64-release.zip",
- "hash": "97f799cd84899d090d8619348c8daf96dc1c3b53f8bab059ba1bf1d4c82074c6"
- },
- "32bit": {
- "url": "https://storage.googleapis.com/dart-archive/channels/stable/release/1.23.0/sdk/dartsdk-windows-ia32-release.zip",
- "hash": "e154ab0ba06a0b47d6d080e4c7de74a78076daed2be908ff49bac1691ceff09e"
- }
- },
- "checkver": {
- "url": "https://storage.googleapis.com/dart-archive/channels/stable/release/latest/VERSION",
- "jp": "$.version"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://storage.googleapis.com/dart-archive/channels/stable/release/$version/sdk/dartsdk-windows-x64-release.zip"
- },
- "32bit": {
- "url": "https://storage.googleapis.com/dart-archive/channels/stable/release/$version/sdk/dartsdk-windows-ia32-release.zip"
- }
- },
- "hash": {
- "url": "$url.sha256sum"
- }
- }
-}
diff --git a/bucket/dd.json b/bucket/dd.json
deleted file mode 100644
index 0697dcff6d..0000000000
--- a/bucket/dd.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "homepage": "http://www.chrysocome.net/dd",
- "license": "http://www.chrysocome.net/gpl",
- "description": "Allows the flexible copying of data in a win32 environment",
- "version": "0.6beta3",
- "url": "http://www.chrysocome.net/downloads/dd-0.6beta3.zip",
- "hash": "c7a6a4cc4a107030b072fb479173d66e6d1d1098cf740c6da4e9378c16b81c17",
- "bin": "dd.exe"
-}
diff --git a/bucket/devd.json b/bucket/devd.json
deleted file mode 100644
index 4c03b23990..0000000000
--- a/bucket/devd.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "homepage": "http://corte.si/posts/devd/intro/index.html",
- "license": "https://github.com/cortesi/devd/blob/master/LICENSE",
- "version": "0.7",
- "url": "https://github.com/cortesi/devd/releases/download/v0.7/devd-0.7-windows64.zip",
- "hash": "b5a513c89f9fd6fed0984d7cc65bd5c8a1754e2304813135b44443a3ab30ded3",
- "extract_dir": "devd-0.7-windows64",
- "bin": "devd.exe",
- "checkver": {
- "github": "https://github.com/cortesi/devd"
- },
- "autoupdate": {
- "url": "https://github.com/cortesi/devd/releases/download/v$version/devd-$version-windows64.zip",
- "extract_dir": "devd-$version-windows64"
- }
-}
diff --git a/bucket/diffutils.json b/bucket/diffutils.json
deleted file mode 100644
index 6689299967..0000000000
--- a/bucket/diffutils.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "homepage": "http://www.msys2.org",
- "version": "3.5",
- "architecture": {
- "64bit": {
- "url": [
- "http://repo.msys2.org/msys/x86_64/diffutils-3.5-1-x86_64.pkg.tar.xz",
- "http://repo.msys2.org/msys/x86_64/msys2-runtime-2.7.0-1-x86_64.pkg.tar.xz",
- "http://repo.msys2.org/msys/x86_64/libiconv-1.14-2-x86_64.pkg.tar.xz",
- "http://repo.msys2.org/msys/x86_64/libintl-0.19.7-3-x86_64.pkg.tar.xz"
- ],
- "hash": [
- "6feba4594fe39180752213673510041d322be87977b573fc933141ddc8cb7f01",
- "13921128ec52d0cf14b5b5c518c21c7b937020075607c0b5d96fa49f8eea0bd2",
- "de1a5b4974b10ddcf35389c9ede615ed4ab93f86854e7355e66d1f39723ca3c8",
- "8bde823a82608b577c31c82759a8410bd503c5f7ae62843385310b2e4c24b48c"
- ]
- },
- "32bit": {
- "url": [
- "http://repo.msys2.org/msys/i686/diffutils-3.5-1-i686.pkg.tar.xz",
- "http://repo.msys2.org/msys/i686/msys2-runtime-2.7.0-1-i686.pkg.tar.xz",
- "http://repo.msys2.org/msys/i686/libiconv-1.14-2-i686.pkg.tar.xz",
- "http://repo.msys2.org/msys/i686/libintl-0.19.7-3-i686.pkg.tar.xz"
- ],
- "hash": [
- "3b60c994dfcf8fb8e3a61d1c4aab4b23102e16c5d9c5e080761d969bec414ebe",
- "86574f2e9afe9d295f329fb23feb35ec18505070b3682e76961d9c5910764388",
- "90502f67f38eb7d709498b9fb4a0e68f2afafafa1fad005e0dec8315d8191b79",
- "1285d5788987052e133e18b537d9825a7a3cd4ecb738d8cfd5feddc9886ba58a"
- ]
- }
- },
- "bin": [
- "usr\\bin\\cmp.exe",
- "usr\\bin\\diff.exe",
- "usr\\bin\\diff3.exe",
- "usr\\bin\\sdiff.exe"
- ]
-}
diff --git a/bucket/dig.json b/bucket/dig.json
deleted file mode 100644
index 8c9860c203..0000000000
--- a/bucket/dig.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "homepage": "https://www.isc.org/",
- "license": "https://www.isc.org/downloads/software-support-policy/isc-license/",
- "version": "9.11.0",
- "architecture": {
- "64bit": {
- "url": "ftp://ftp.isc.org/isc/bind9/9.11.0/BIND9.11.0.x64.zip",
- "hash": "2cbc44127bbc9d17ed7a2a23c9c1cd5a055c90dcffd8c3384e7f8efe39ed790f"
- },
- "32bit": {
- "url": "ftp://ftp.isc.org/isc/bind9/9.11.0/BIND9.11.0.x86.zip",
- "hash": "7b92b9e3f9fe4cca69feeed73305151f4bdc09c9cbb5858671da2b7fd8a05fe2"
- }
- },
- "bin": "dig.exe",
- "suggest": {
- "vcredist": [
- "extras/vcredist2012"
- ]
- }
-}
diff --git a/bucket/dnvm.json b/bucket/dnvm.json
deleted file mode 100644
index 0f3af43c33..0000000000
--- a/bucket/dnvm.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "version": "latest",
- "license": "Apache 2.0",
- "url": "https://raw.githubusercontent.com/aspnet/Home/danroth27/restorednvm/dnvm.ps1",
- "homepage": "https://github.com/aspnet/Home",
- "env_set": {
- "DNX_HOME": "$dir\\.dnx",
- "DNX_USER_HOME": "$dir\\.dnx"
- },
- "bin": "dnvm.ps1"
-}
diff --git a/bucket/docker-compose.json b/bucket/docker-compose.json
deleted file mode 100644
index 0e11e31ede..0000000000
--- a/bucket/docker-compose.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "homepage": "https://github.com/docker/compose",
- "version": "1.13.0",
- "license": "Apache",
- "architecture": {
- "64bit": {
- "url": "https://github.com/docker/compose/releases/download/1.13.0/docker-compose-Windows-x86_64.exe#/docker-compose.exe",
- "hash": "b933e653cd77f1d990d4dda598f1cc8fe8f128d66485569e828c0976602a8d5e"
- }
- },
- "bin": [
- [
- "docker-compose.exe",
- "docker-compose"
- ]
- ],
- "checkver": "github",
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://github.com/docker/compose/releases/download/$version/docker-compose-Windows-x86_64.exe#/docker-compose.exe"
- }
- }
- }
-}
diff --git a/bucket/docker-machine.json b/bucket/docker-machine.json
deleted file mode 100644
index f59fd7cf84..0000000000
--- a/bucket/docker-machine.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "homepage": "https://github.com/docker/machine",
- "version": "0.11.0",
- "license": "Apache",
- "architecture": {
- "64bit": {
- "url": "https://github.com/docker/machine/releases/download/v0.11.0/docker-machine-Windows-x86_64.exe#/docker-machine.exe",
- "hash": "540a98ad93f52dd1529a4803ef70a5847a97dc1a1f612cdf67201c26cf80c0cc"
- },
- "32bit": {
- "url": "https://github.com/docker/machine/releases/download/v0.11.0/docker-machine-Windows-i386.exe#/docker-machine.exe",
- "hash": "e4ebdb1ea127659e34513e43559e7d964ca365236f652df613ae8671682db44f"
- }
- },
- "bin": [
- [
- "docker-machine.exe",
- "docker-machine"
- ]
- ],
- "checkver": "github",
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://github.com/docker/machine/releases/download/v$version/docker-machine-Windows-x86_64.exe#/docker-machine.exe"
- },
- "32bit": {
- "url": "https://github.com/docker/machine/releases/download/v$version/docker-machine-Windows-i386.exe#/docker-machine.exe"
- }
- },
- "hash": {
- "url": "$baseurl/sha256sum.txt"
- }
- }
-}
diff --git a/bucket/docker.json b/bucket/docker.json
deleted file mode 100644
index 3e036614b2..0000000000
--- a/bucket/docker.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- "version": "17.05.0-ce",
- "license": "https://github.com/docker/docker/blob/master/LICENSE",
- "architecture": {
- "64bit": {
- "url": "https://get.docker.com/builds/Windows/x86_64/docker-17.05.0-ce.zip",
- "hash": "cbb0b47b511023a98dd0c83d76c1f30b315b8381b85b67be355eca4748229031"
- },
- "32bit": {
- "url": "https://get.docker.com/builds/Windows/i386/docker-17.05.0-ce.zip",
- "hash": "99820746a362466700718d33ee727b9aea993b9c2e05fb2c53ed606e9f6780f1"
- }
- },
- "homepage": "https://docker.com",
- "extract_dir": "docker",
- "bin": [
- "docker.exe"
- ],
- "checkver": {
- "url": "https://github.com/docker/docker/releases/latest",
- "re": "/releases/tag/(?:v)?([\\d\\w.-]+)"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://get.docker.com/builds/Windows/x86_64/docker-$version.zip"
- },
- "32bit": {
- "url": "https://get.docker.com/builds/Windows/i386/docker-$version.zip"
- }
- }
- },
- "notes": [
- "This is the docker client only. Until the docker daemon can run natively",
- "on Windows you will need a Virtual Machine such as Boot2Docker or",
- "Docker Machine",
- "",
- "Boot2Docker: https://github.com/boot2docker/windows-installer/releases/",
- "Docker Machine: http://docs.docker.com/machine/"
- ]
-}
diff --git a/bucket/dosbox.json b/bucket/dosbox.json
deleted file mode 100644
index c2a19a12ae..0000000000
--- a/bucket/dosbox.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "homepage": "https://www.dosbox.com/",
- "version": "0.74",
- "license": "GPL",
- "url": "https://sourceforge.net/projects/dosbox/files/dosbox/0.74/DOSBox0.74-win32-installer.exe",
- "hash": "c149cb85f732beb95bf6564d72bdfdd9306f7050edfd9d2cd475420efe3b84fc",
- "installer": {
- "args": [
- "/S",
- "/D=$dir"
- ]
- },
- "bin": [
- "DOSBox.exe",
- "SDL.dll",
- "SDL_net.dll"
- ],
- "checkver": "Latest version:\\s+]+>([\\d.]+)"
-}
diff --git a/bucket/dotnet.json b/bucket/dotnet.json
deleted file mode 100644
index c1d3ba2f5c..0000000000
--- a/bucket/dotnet.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "version": "1.1.1",
- "homepage": "https://www.microsoft.com/net/core#windows",
- "architecture": {
- "64bit": {
- "url": "https://go.microsoft.com/fwlink/?linkid=843454#/dl.7z",
- "hash": "e729afcf3cc69f17ec7968468b399c843b8b8327523e62c03450e4653115cf76"
- },
- "32bit": {
- "url": "https://go.microsoft.com/fwlink/?linkid=843458#/dl.7z",
- "hash": "3a8d7316dd774d54e27a332c5d1e73d7813fecd10b670249f480ae917226e444"
- }
- },
- "bin": "dotnet.exe"
-}
diff --git a/bucket/doxygen.json b/bucket/doxygen.json
deleted file mode 100644
index 70d5e60f36..0000000000
--- a/bucket/doxygen.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "homepage": "http://www.doxygen.nl/",
- "license": "GPL2",
- "version": "1.8.13",
- "architecture": {
- "64bit": {
- "url": "http://ftp.stack.nl/pub/users/dimitri/doxygen-1.8.13.windows.x64.bin.zip",
- "hash": "c59e92ab9f82e156723dd3efb9433948dcb84facc21d6efb50f4d6c2d7aa6c5c"
- },
- "32bit": {
- "url": "http://ftp.stack.nl/pub/users/dimitri/doxygen-1.8.13.windows.bin.zip",
- "hash": "215800d19d0e77fa400694af74685bbd3000463f0d7f18b6c7b743d2d6a1422f"
- }
- },
- "bin": [
- "doxygen.exe",
- "doxyindexer.exe",
- "doxysearch.cgi.exe"
- ],
- "checkver": {
- "url": "http://www.doxygen.nl/download.html",
- "re": "The latest version of doxygen is ([\\d.]+)"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "http://ftp.stack.nl/pub/users/dimitri/doxygen-$version.windows.x64.bin.zip"
- },
- "32bit": {
- "url": "http://ftp.stack.nl/pub/users/dimitri/doxygen-$version.windows.bin.zip"
- }
- }
- }
-}
diff --git a/bucket/editorconfig.json b/bucket/editorconfig.json
deleted file mode 100644
index c1eab73bf5..0000000000
--- a/bucket/editorconfig.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "version": "0.12.1",
- "extract_dir": "editorconfig-0.12.1-Windows-x86",
- "url": "https://excellmedia.dl.sourceforge.net/project/editorconfig/EditorConfig-C-Core/0.12.1/binary-Windows/editorconfig-0.12.1-Windows-x86.zip",
- "homepage": "http://editorconfig.org/",
- "hash": "aaf8977253dd72dd12aec2986c822498c1fa1fa96bf8a404b9facfbf9757ff3b",
- "bin": "bin/editorconfig.exe",
- "checkver": {
- "github": "https://github.com/editorconfig/editorconfig-core-c"
- },
- "autoupdate": {
- "url": "https://excellmedia.dl.sourceforge.net/project/editorconfig/EditorConfig-C-Core/$version/binary-Windows/editorconfig-$version-Windows-x86.zip",
- "extract_dir": "editorconfig-$version-Windows-x86"
- }
-}
diff --git a/bucket/elixir.json b/bucket/elixir.json
deleted file mode 100644
index 9d06541303..0000000000
--- a/bucket/elixir.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "homepage": "http://elixir-lang.org/",
- "version": "1.4.4",
- "depends": "erlang",
- "url": "https://github.com/elixir-lang/elixir/releases/download/v1.4.4/Precompiled.zip",
- "hash": "3fc2cc2ec39315d9894a81b9d167029e4a9cfa5bb22edb3d7e0e66971d4e43ed",
- "bin": [
- "bin\\elixir.bat",
- "bin\\elixirc.bat",
- "bin\\iex.bat",
- "bin\\mix.bat"
- ],
- "checkver": {
- "github": "https://github.com/elixir-lang/elixir"
- },
- "autoupdate": {
- "url": "https://github.com/elixir-lang/elixir/releases/download/v$version/Precompiled.zip"
- }
-}
diff --git a/bucket/erlang.json b/bucket/erlang.json
deleted file mode 100644
index ae413fe8f2..0000000000
--- a/bucket/erlang.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "homepage": "http://www.erlang.org",
- "version": "19.3",
- "license": "http://www.apache.org/licenses/LICENSE-2.0",
- "architecture": {
- "64bit": {
- "url": "http://erlang.org/download/otp_win64_19.3.exe",
- "hash": "e38074ec99da22a04bd00cda83d412e07294dbaf031c2369c195f712caa0cc70"
- },
- "32bit": {
- "url": "http://erlang.org/download/otp_win32_19.3.exe",
- "hash": "a33964be7e98304a331d294921bea31b45cefa365c5049cc1a3764980b1347cf"
- }
- },
- "bin": [
- "bin\\erl.exe",
- "bin\\erlc.exe",
- "bin\\escript.exe"
- ],
- "env_set": {
- "ERLANG_HOME": "$dir"
- },
- "installer": {
- "args": [
- "/S",
- "/D=$dir"
- ]
- },
- "uninstaller": {
- "file": "Uninstall.exe",
- "args": [
- "/S"
- ]
- },
- "checkver": {
- "url": "http://www.erlang.org/downloads",
- "re": "DOWNLOAD\\s+OTP ([\\d.]+)"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "http://erlang.org/download/otp_win64_$version.exe"
- },
- "32bit": {
- "url": "http://erlang.org/download/otp_win32_$version.exe"
- }
- }
- }
-}
diff --git a/bucket/eventstore.json b/bucket/eventstore.json
deleted file mode 100644
index ef68bdef13..0000000000
--- a/bucket/eventstore.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "homepage": "https://geteventstore.com/",
- "license": "BSD 3-Clause",
- "version": "4.0.1",
- "url": "http://download.geteventstore.com/binaries/EventStore-OSS-Win-v4.0.1.zip",
- "hash": "b341e3a7939316a06040e3910c76d01c32f2162781ab81a1bbe28da84bf007cc",
- "bin": [
- [
- "EventStore.ClusterNode.exe",
- "eventstore"
- ],
- "EventStore.ClusterNode.exe",
- "EventStore.PAdmin.exe",
- "EventStore.Query.exe",
- "EventStore.TestClient.exe"
- ],
- "checkver": {
- "url": "https://geteventstore.com/downloads/",
- "re": "Get\\s+Event\\s+Store\\s+(\\d+\\.\\d+\\.\\d+)\\s+for\\s+Windows"
- },
- "autoupdate": {
- "url": "http://download.geteventstore.com/binaries/EventStore-OSS-Win-v$version.zip"
- }
-}
diff --git a/bucket/exiftool.json b/bucket/exiftool.json
deleted file mode 100644
index f5f5055b9d..0000000000
--- a/bucket/exiftool.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "homepage": "http://www.sno.phy.queensu.ca/~phil/exiftool/index.html",
- "version": "10.54",
- "license": "http://dev.perl.org/licenses/",
- "url": "https://downloads.sourceforge.net/project/exiftool/exiftool-10.54.zip",
- "hash": "1d522f96a435fa52d0cfbd7865e567899eb7e79b488e12cb614f928847850c73",
- "bin": [
- [
- "exiftool(-k).exe",
- "exiftool"
- ]
- ],
- "checkver": "exiftool-([\\d.]+).zip",
- "autoupdate": {
- "url": "https://downloads.sourceforge.net/project/exiftool/exiftool-$version.zip"
- }
-}
diff --git a/bucket/far.json b/bucket/far.json
deleted file mode 100644
index 58907cd367..0000000000
--- a/bucket/far.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "homepage": "https://farmanager.com/",
- "version": "30b4949",
- "architecture": {
- "64bit": {
- "url": "https://farmanager.com/files/Far30b4949.x64.20170503.7z",
- "hash": "a1d924b3157d48c96a9496fd19b9a4a97ae811e2c2dc69a193cdaec33da150e8"
- },
- "32bit": {
- "url": "https://farmanager.com/files/Far30b4949.x86.20170503.7z",
- "hash": "c7ab55a6c83e8f547821f799e49f00c47bc7806dee8d265557172d31630711b9"
- }
- },
- "checkver": {
- "url": "https://farmanager.com/download.php",
- "re": "files/Far(?[b\\d]+).x64.(?\\d+).7z"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://farmanager.com/files/Far$version.x64.$matchDate.7z"
- },
- "32bit": {
- "url": "https://farmanager.com/files/Far$version.x86.$matchDate.7z"
- }
- }
- },
- "bin": "far.exe"
-}
diff --git a/bucket/ffmpeg.json b/bucket/ffmpeg.json
deleted file mode 100644
index 80920a2d3e..0000000000
--- a/bucket/ffmpeg.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "version": "20170601-bd1179e",
- "homepage": "https://ffmpeg.zeranoe.com/builds/",
- "license": "GPL3",
- "architecture": {
- "64bit": {
- "url": "https://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-20170601-bd1179e-win64-static.zip",
- "hash": "b549c2654432363d9b2c7dcebae8d2d10131640f007bca0a6c12881fc3864cdd",
- "extract_dir": "ffmpeg-20170601-bd1179e-win64-static"
- },
- "32bit": {
- "url": "https://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-20170601-bd1179e-win32-static.zip",
- "hash": "e5c2f27e9d0657d5ecb9476c8d7f63735e6da5c9f3eb60e2f738252b5de72ed0",
- "extract_dir": "ffmpeg-20170601-bd1179e-win32-static"
- }
- },
- "bin": [
- "bin\\ffmpeg.exe",
- "bin\\ffplay.exe",
- "bin\\ffprobe.exe"
- ],
- "checkver": "value=\"([\\d]{8}-[\\d\\w]+)\"",
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-$version-win64-static.zip",
- "extract_dir": "ffmpeg-$version-win64-static"
- },
- "32bit": {
- "url": "https://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-$version-win32-static.zip",
- "extract_dir": "ffmpeg-$version-win32-static"
- }
- }
- }
-}
diff --git a/bucket/figlet.json b/bucket/figlet.json
deleted file mode 100644
index fcf5c25d9e..0000000000
--- a/bucket/figlet.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "homepage": "https://github.com/lukesampson/figlet",
- "version": "1.0-go",
- "url": "https://github.com/lukesampson/figlet/releases/download/go-1.0-win/figlet-go-1.0-win.zip",
- "hash": "11ee1f4de608d147ab5b61ddb5967730e9b2c1e43f7d2c96582ee260c030e413",
- "bin": "figlet.exe"
-}
diff --git a/bucket/file.json b/bucket/file.json
deleted file mode 100644
index dd2802f385..0000000000
--- a/bucket/file.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "homepage": "http://gnuwin32.sourceforge.net/packages/file.htm",
- "version": "5.03",
- "license": "GPL2",
- "url": [
- "https://sourceforge.net/projects/gnuwin32/files/file/5.03/file-5.03-bin.zip",
- "https://sourceforge.net/projects/gnuwin32/files/file/5.03/file-5.03-dep.zip"
- ],
- "hash": [
- "dbd28e191c1bf7e3db08b983e603e79959295717f6fc1032ba97e7a8680c8cf9",
- "2dbf891e42c642e372e5b21b0528bb5ba3c5b6eeb9fb01fb1e9cc77f2f44a091"
- ],
- "bin": "bin\\file.exe"
-}
diff --git a/bucket/findutils.json b/bucket/findutils.json
deleted file mode 100644
index 33a2795568..0000000000
--- a/bucket/findutils.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "homepage": "http://www.mingw.org/wiki/msys",
- "version": "4.4.2",
- "license": "GPL2",
- "url": [
- "https://sourceforge.net/projects/mingw/files/MSYS/Base/msys-core/msys-1.0.13-2/msysCORE-1.0.13-2-msys-1.0.13-bin.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MSYS/Base/gettext/gettext-0.17-2/libintl-0.17-2-msys-dll-8.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MSYS/Base/libiconv/libiconv-1.13.1-2/libiconv-1.13.1-2-msys-1.0.13-dll-2.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MSYS/Base/findutils/findutils-4.4.2-2/findutils-4.4.2-2-msys-1.0.13-bin.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MSYS/Base/findutils/findutils-4.4.2-2/locate-4.4.2-2-msys-1.0.13-bin.tar.lzma"
- ],
- "hash": [
- "41c7d5561662e41da74951f373a08a95db40b27b1246227bbbc13abc44976ea7",
- "b533de0ee04dc4d53ca745210e41eb9437044ebd367c001f3615092e7214a4a3",
- "f13de6d2e3c428e7f9a7251c6b01d6f7569e20f7ac126c68c028eb5f542473bb",
- "779e819b7942dc070c45f4cba633e6a9ae4bfe8b506a3541f4ce86ad0595726d",
- "3fbb9826feae0698a58c8e1bbaa46caafb2bd07a63c59e33cd4478aee14ee147"
- ],
- "bin": [
- "bin\\find.exe",
- "bin\\oldfind.exe",
- "bin\\xargs.exe",
- "bin\\locate.exe"
- ]
-}
diff --git a/bucket/flatc.json b/bucket/flatc.json
deleted file mode 100644
index 96960d323f..0000000000
--- a/bucket/flatc.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "homepage": "https://google.github.io/flatbuffers/index.html",
- "license": "Apache2",
- "version": "1.6.0",
- "url": "https://github.com/google/flatbuffers/releases/download/v1.6.0/flatc_windows_exe.zip",
- "bin": "flatc.exe",
- "hash": "e4ac8cdfa5e90c92e77715e998b9210fa86128b84a38a0fe9fec04c5b5f941c9",
- "checkver": {
- "github": "https://github.com/google/flatbuffers"
- },
- "autoupdate": {
- "url": "https://github.com/google/flatbuffers/releases/download/v$version/flatc_windows_exe.zip"
- }
-}
diff --git a/bucket/flow.json b/bucket/flow.json
deleted file mode 100644
index 7a34bb1a65..0000000000
--- a/bucket/flow.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "version": "0.47.0",
- "license": "BSD",
- "url": "https://github.com/facebook/flow/releases/download/v0.47.0/flow-win64-v0.47.0.zip",
- "homepage": "https://flowtype.org/",
- "hash": "d0f2adbe449f678b5c565b102d2ff6f4953cc39d528ddc3e8e63a0e7e543c0dd",
- "bin": "flow.exe",
- "extract_dir": "flow",
- "checkver": {
- "github": "https://github.com/facebook/flow"
- },
- "autoupdate": {
- "url": "https://github.com/facebook/flow/releases/download/v$version/flow-win64-v$version.zip"
- }
-}
diff --git a/bucket/forge.json b/bucket/forge.json
deleted file mode 100644
index 74d661c49c..0000000000
--- a/bucket/forge.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "homepage": "http://forge.run",
- "version": "1.4.2",
- "url": "https://github.com/fsharp-editing/Forge/releases/download/1.4.2/forge.zip",
- "hash": "b977a69a55883a45342e65f940446fadc04895b78b2b92c4aabe3612a89af063",
- "bin": [
- "bin\\forge.exe"
- ],
- "checkver": {
- "github": "https://github.com/fsharp-editing/Forge"
- },
- "autoupdate": {
- "url": "https://github.com/fsharp-editing/Forge/releases/download/$version/forge.zip"
- }
-}
diff --git a/bucket/fossil.json b/bucket/fossil.json
deleted file mode 100644
index 1729ea794f..0000000000
--- a/bucket/fossil.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "homepage": "https://www.fossil-scm.org/",
- "version": "2.2",
- "license": "https://www.fossil-scm.org/index.html/doc/trunk/COPYRIGHT-BSD2.txt",
- "hash": "507b08fa84d944b08aa30aa1aadc23efea9b049e2848341f6c66e62baa753d05",
- "url": "https://www.fossil-scm.org/index.html/uv/fossil-w32-2.2.zip",
- "bin": "fossil.exe",
- "checkver": {
- "url": "https://www.fossil-scm.org/index.html/uv/download.html",
- "re": "Version ([\\d.]+)\""
- },
- "autoupdate": {
- "url": "https://www.fossil-scm.org/index.html/uv/fossil-w32-$version.zip"
- }
-}
diff --git a/bucket/fzf.json b/bucket/fzf.json
deleted file mode 100644
index d5b6eb9ac6..0000000000
--- a/bucket/fzf.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "homepage": "https://github.com/junegunn/fzf",
- "version": "0.16.7",
- "license": "MIT",
- "architecture": {
- "64bit": {
- "url": "https://github.com/junegunn/fzf-bin/releases/download/0.16.7/fzf-0.16.7-windows_amd64.zip",
- "hash": "f348c0ae94107206a09fb9e0282ee09c503ad4a15dc98dffebc69f373e7a21ab"
- },
- "32bit": {
- "url": "https://github.com/junegunn/fzf-bin/releases/download/0.16.7/fzf-0.16.7-windows_386.zip",
- "hash": "b14456762ad3bc29a124e9083b87becf14cd71aaf08a56aa5765eb87df332418"
- }
- },
- "bin": "fzf.exe",
- "checkver": {
- "github": "https://github.com/junegunn/fzf-bin"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://github.com/junegunn/fzf-bin/releases/download/$version/fzf-$version-windows_amd64.zip"
- },
- "32bit": {
- "url": "https://github.com/junegunn/fzf-bin/releases/download/$version/fzf-$version-windows_386.zip"
- }
- }
- }
-}
diff --git a/bucket/gawk.json b/bucket/gawk.json
deleted file mode 100644
index f2b088208f..0000000000
--- a/bucket/gawk.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "homepage": "http://www.mingw.org/wiki/MSYS",
- "version": "3.1.7",
- "license": "GPL3",
- "url": [
- "https://sourceforge.net/projects/mingw/files/MSYS/Base/gawk/gawk-3.1.7-2/gawk-3.1.7-2-msys-1.0.13-bin.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MSYS/Base/msys-core/msys-1.0.18-1/msysCORE-1.0.18-1-msys-1.0.18-bin.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MSYS/Base/gettext/gettext-0.18.1.1-1/libintl-0.18.1.1-1-msys-1.0.17-dll-8.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MSYS/Base/libiconv/libiconv-1.14-1/libiconv-1.14-1-msys-1.0.17-dll-2.tar.lzma"
- ],
- "hash": [
- "eb15478ea76e75b666ad7fc7049de21b9f487e0e1ea0e96d40953a477e91c3dd",
- "4e262a414f238773b311c8bb55a52e62743c06e0e55b319ca5b47e3e306464d5",
- "29db8c969661c511fbe2a341ab25c993c5f9c555842a75d6ddbcfa70dec16910",
- "196921e8c232259c8e6a6852b9ee8d9ab2d29a91419f0c8dc27ba6f034231683"
- ],
- "bin": [
- "bin\\awk.exe",
- "bin\\gawk.exe",
- "bin\\pgawk.exe"
- ]
-}
diff --git a/bucket/gcc.json b/bucket/gcc.json
deleted file mode 100644
index f8b4cec6b3..0000000000
--- a/bucket/gcc.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "homepage": "http://mingw-w64.org",
- "version": "6.3.0",
- "license": "GPL3",
- "architecture": {
- "64bit": {
- "url": "https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/6.3.0/threads-posix/seh/x86_64-6.3.0-release-posix-seh-rt_v5-rev1.7z",
- "hash": "2d0e72340ffa14916d4469db25c37889e477f8f1f49ba4f77155830ddc1dca89",
- "extract_dir": "mingw64"
- },
- "32bit": {
- "url": "https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/6.3.0/threads-posix/dwarf/i686-6.3.0-release-posix-dwarf-rt_v5-rev1.7z",
- "hash": "8f7381e8ed61c438d36d33ae2f514a7ca8065c44dcf6801847fd425f71a9ee1d",
- "extract_dir": "mingw32"
- }
- },
- "env_add_path": "bin",
- "notes": "The 64bit version is built with Structured Exception Handling (SEH), the 32bit is built with DWARF.
-Both 64bit and 32bit support Posix threading model"
-}
diff --git a/bucket/gdb.json b/bucket/gdb.json
deleted file mode 100644
index 01e1f58363..0000000000
--- a/bucket/gdb.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "homepage": "http://tdm-gcc.tdragon.net/",
- "version": "7.9.1",
- "architecture": {
- "64bit": {
- "url": "https://sourceforge.net/projects/tdm-gcc/files/GDB/gdb-7.9.1-tdm64-2.zip",
- "hash": "89186aa83143f47902b52f5673dd32421ec9c221e53e3227fd065a7e86c8c6f5",
- "extract_dir": "gdb64"
- },
- "32bit": {
- "url": "https://sourceforge.net/projects/tdm-gcc/files/GDB/gdb32-7.9.1-tdm-1.zip",
- "hash": "715604034bb269ecbfaf4577addac51b8ba798f93b2eca31cb21b114b7bc46e8",
- "extract_dir": "gdb32"
- }
- },
- "env_add_path": "bin"
-}
diff --git a/bucket/ghostscript.json b/bucket/ghostscript.json
deleted file mode 100644
index 70543e8f0e..0000000000
--- a/bucket/ghostscript.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
- "homepage": "http://www.ghostscript.com",
- "version": "9.21",
- "license": "http://www.gnu.org/licenses/agpl-3.0.html",
- "architecture": {
- "64bit": {
- "url": "https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs921/gs921w64.exe#/dl.7z",
- "hash": "41bf242d0e4303f329f4b67fc0c556885fe0a5d4012cf5c1e7ddc62a5d25aba9",
- "bin": [
- "bin\\gswin64.exe",
- "bin\\gswin64c.exe"
- ]
- },
- "32bit": {
- "url": "https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs921/gs921w32.exe#/dl.7z",
- "hash": "75f5983ac23fbc26760f1033062ec914e7dbafcb029e47e54e77a762ee934089",
- "bin": [
- "bin\\gswin32.exe",
- "bin\\gswin32c.exe"
- ]
- }
- },
- "env_add_path": [
- "bin",
- "lib"
- ],
- "checkver": {
- "url": "https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/latest",
- "re": "Ghostscript\\/GhostPDL ([\\d.]+)"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs$cleanVersion/gs$cleanVersionw64.exe#/dl.7z"
- },
- "32bit": {
- "url": "https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs$cleanVersion/gs$cleanVersionw32.exe#/dl.7z"
- }
- },
- "hash": {
- "url": "$baseurl/SHA256SUMS"
- }
- }
-}
diff --git a/bucket/gibo.json b/bucket/gibo.json
deleted file mode 100644
index 005f288697..0000000000
--- a/bucket/gibo.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "version": "1.0.4",
- "homepage": "https://github.com/simonwhitaker/gibo",
- "license": "https://github.com/simonwhitaker/gibo/blob/master/UNLICENSE",
- "description": "gibo (short for .gitignore boilerplates) is a shell script to help you easily access .gitignore boilerplates from github.com/github/gitignore.",
- "url": "https://github.com/simonwhitaker/gibo/archive/1.0.4.zip",
- "hash": "868144f463c82ede0159065940b893cd0b586d766b1349caa62faa2ec5d940fc",
- "extract_dir": "gibo-1.0.4",
- "bin": [
- "gibo.bat"
- ]
-}
diff --git a/bucket/git-lfs.json b/bucket/git-lfs.json
deleted file mode 100644
index 081e508f80..0000000000
--- a/bucket/git-lfs.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "homepage": "https://git-lfs.github.com/",
- "version": "2.1.1",
- "license": "MIT",
- "architecture": {
- "32bit": {
- "url": "https://github.com/github/git-lfs/releases/download/v2.1.1/git-lfs-windows-386-2.1.1.zip",
- "hash": "897571c2b8aa777d011e7c5496735e9dcb2da809faa741b113169a5cb04650bd",
- "extract_dir": "git-lfs-windows-386-2.1.1"
- },
- "64bit": {
- "url": "https://github.com/github/git-lfs/releases/download/v2.1.1/git-lfs-windows-amd64-2.1.1.zip",
- "hash": "0866259d6b097f8ff379326f798a93034b61952382011671b80ecf4cc733de57",
- "extract_dir": "git-lfs-windows-amd64-2.1.1"
- }
- },
- "depends": "git",
- "bin": "git-lfs.exe",
- "checkver": {
- "github": "https://github.com/github/git-lfs"
- },
- "autoupdate": {
- "architecture": {
- "32bit": {
- "url": "https://github.com/github/git-lfs/releases/download/v$version/git-lfs-windows-386-$version.zip",
- "extract_dir": "git-lfs-windows-386-$version"
- },
- "64bit": {
- "url": "https://github.com/github/git-lfs/releases/download/v$version/git-lfs-windows-amd64-$version.zip",
- "extract_dir": "git-lfs-windows-amd64-$version"
- }
- }
- }
-}
diff --git a/bucket/git-town.json b/bucket/git-town.json
deleted file mode 100644
index 6cf877351c..0000000000
--- a/bucket/git-town.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "homepage": "http://www.git-town.com/",
- "version": "4.1.0",
- "license": "MIT",
- "architecture": {
- "32bit": {
- "url": "https://github.com/Originate/git-town/releases/download/v4.1.0/git-town-windows-386.exe#/git-town.exe",
- "hash": "31b2b7dbde19c2502012be014d04e00e0f22d8e5484cac6713c2e2d3a40e1bf8"
- },
- "64bit": {
- "url": "https://github.com/Originate/git-town/releases/download/v4.1.0/git-town-windows-amd64.exe#/git-town.exe",
- "hash": "5ce7f41e77fe288fe5ab9929d225903d722f512caad0e3c64bca6c5118ab6ce7"
- }
- },
- "depends": "git",
- "bin": "git-town.exe",
- "checkver": {
- "github": "https://github.com/Originate/git-town"
- },
- "autoupdate": {
- "architecture": {
- "32bit": {
- "url": "https://github.com/Originate/git-town/releases/download/v$version/git-town-windows-386.exe#/git-town.exe"
- },
- "64bit": {
- "url": "https://github.com/Originate/git-town/releases/download/v$version/git-town-windows-amd64.exe#/git-town.exe"
- }
- }
- }
-}
diff --git a/bucket/git-up.json b/bucket/git-up.json
deleted file mode 100644
index 9d600c841b..0000000000
--- a/bucket/git-up.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "homepage": "https://github.com/msiemens/PyGitUp",
- "license": "https://github.com/msiemens/PyGitUp/blob/master/LICENCE",
- "version": "1.4.1",
- "url": "https://github.com/msiemens/PyGitUp/archive/v1.4.1.zip",
- "hash": "6e673c873d8d7fdb81537ae25ae57462f868e4a4348c9c5d12fb17d5f7a7a4a8",
- "extract_dir": "PyGitUp-1.4.1",
- "depends": "python",
- "post_install": "
- pushd $dir
- try {
- scoop reset python
- iex \"$(scoop which python) setup.py install\"
- }
- finally {
- popd
- }",
- "checkver": "github",
- "autoupdate": {
- "url": "https://github.com/msiemens/PyGitUp/archive/v$version.zip",
- "extract_dir": "PyGitUp-$version"
- }
-}
diff --git a/bucket/git-with-openssh.json b/bucket/git-with-openssh.json
deleted file mode 100644
index ff802c4ea5..0000000000
--- a/bucket/git-with-openssh.json
+++ /dev/null
@@ -1,47 +0,0 @@
-{
- "_comment": "Maintainers: when updating this manifest to a new version, you might like to also update git.json",
- "homepage": "https://git-for-windows.github.io/",
- "license": "GPL2",
- "version": "2.13.0.windows.1",
- "architecture": {
- "64bit": {
- "url": "https://github.com/git-for-windows/git/releases/download/v2.13.0.windows.1/PortableGit-2.13.0-64-bit.7z.exe#/dl.7z",
- "hash": "1d6008cb6fec817a302d4b59921423ba1f6db2677c6b519c20e9ca2cacc7c220"
- },
- "32bit": {
- "url": "https://github.com/git-for-windows/git/releases/download/v2.13.0.windows.1/PortableGit-2.13.0-32-bit.7z.exe#/dl.7z",
- "hash": "119c95b4416ca1100a4feee0d75ceaf3d41962b0038620c04a62dd787e80e5f2"
- }
- },
- "bin": [
- "cmd\\git.exe",
- "cmd\\gitk.exe",
- "cmd\\git-gui.exe",
- "git-bash.exe",
- "usr\\bin\\ssh.exe",
- "usr\\bin\\sshd.exe",
- "usr\\bin\\scp.exe",
- "usr\\bin\\sftp.exe",
- "usr\\bin\\ssh-add.exe",
- "usr\\bin\\ssh-agent.exe",
- "usr\\bin\\ssh-keygen.exe",
- "usr\\bin\\ssh-keyscan.exe"
- ],
- "post_install": [
- "git config --global credential.helper manager"
- ],
- "checkver": {
- "url": "https://github.com/git-for-windows/git/releases/latest",
- "re": "v(?[\\d\\w.]+)/PortableGit-(?[\\d.]+).*\\.exe"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://github.com/git-for-windows/git/releases/download/v$matchVersion/PortableGit-$matchShort-64-bit.7z.exe#/dl.7z"
- },
- "32bit": {
- "url": "https://github.com/git-for-windows/git/releases/download/v$matchVersion/PortableGit-$matchShort-32-bit.7z.exe#/dl.7z"
- }
- }
- }
-}
diff --git a/bucket/git.json b/bucket/git.json
deleted file mode 100644
index 5a427c12a6..0000000000
--- a/bucket/git.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "_comment": "Maintainers: when updating this manifest to a new version, you might like to also update git-with-openssh.json",
- "homepage": "https://git-for-windows.github.io/",
- "license": "GPL2",
- "version": "2.13.0.windows.1",
- "architecture": {
- "64bit": {
- "url": "https://github.com/git-for-windows/git/releases/download/v2.13.0.windows.1/PortableGit-2.13.0-64-bit.7z.exe#/dl.7z",
- "hash": "1d6008cb6fec817a302d4b59921423ba1f6db2677c6b519c20e9ca2cacc7c220"
- },
- "32bit": {
- "url": "https://github.com/git-for-windows/git/releases/download/v2.13.0.windows.1/PortableGit-2.13.0-32-bit.7z.exe#/dl.7z",
- "hash": "119c95b4416ca1100a4feee0d75ceaf3d41962b0038620c04a62dd787e80e5f2"
- }
- },
- "bin": [
- "cmd\\git.exe",
- "cmd\\gitk.exe",
- "cmd\\git-gui.exe",
- "git-bash.exe"
- ],
- "post_install": [
- "git config --global credential.helper manager"
- ],
- "notes": "To get Git to recognise OpenSSH, you will need to run
-
-scoop install openssh
-[environment]::setenvironmentvariable('GIT_SSH', (resolve-path (scoop which ssh)), 'USER')
-
-and then restart powershell.",
- "checkver": {
- "url": "https://github.com/git-for-windows/git/releases/latest",
- "re": "v(?[\\d\\w.]+)/PortableGit-(?[\\d.]+).*\\.exe"
- },
- "env_set": {
- "GIT_INSTALL_ROOT": "$dir"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://github.com/git-for-windows/git/releases/download/v$matchVersion/PortableGit-$matchShort-64-bit.7z.exe#/dl.7z"
- },
- "32bit": {
- "url": "https://github.com/git-for-windows/git/releases/download/v$matchVersion/PortableGit-$matchShort-32-bit.7z.exe#/dl.7z"
- }
- }
- }
-}
diff --git a/bucket/git19.json b/bucket/git19.json
deleted file mode 100644
index 3f56954e37..0000000000
--- a/bucket/git19.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "homepage": "https://git-for-windows.github.io/",
- "license": "GPL2",
- "version": "1.9.5-preview20150319",
- "url": "https://github.com/msysgit/msysgit/releases/download/Git-1.9.5-preview20150319/PortableGit-1.9.5-preview20150319.7z",
- "hash": "26261872847b18d171a197c8e4b3f4c0e60b4310c4b8ef1f4d9884950288aa7c",
- "bin": [
- "cmd\\git.exe",
- "cmd\\gitk.cmd"
- ],
- "post_install": [
- "git config --global credential.helper wincred"
- ]
-}
diff --git a/bucket/gitignore.json b/bucket/gitignore.json
deleted file mode 100644
index d42e1013a6..0000000000
--- a/bucket/gitignore.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "homepage": "https://github.com/lukesampson/psutils",
- "version": "0.2015.08.26",
- "url": "https://raw.githubusercontent.com/lukesampson/psutils/3c67dbf56a0e541bf928b9a8811dc4c627d8230c/gitignore.ps1",
- "hash": "9a08d37386219add0bf79fe6293ab02f5dfdce6ece95173c003bdb96a8016533",
- "bin": "gitignore.ps1"
-}
diff --git a/bucket/glide.json b/bucket/glide.json
deleted file mode 100644
index 287ca650bf..0000000000
--- a/bucket/glide.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "homepage": "https://glide.sh/",
- "license": "https://github.com/Masterminds/glide/blob/master/LICENSE",
- "version": "0.12.3",
- "architecture": {
- "64bit": {
- "url": "https://github.com/Masterminds/glide/releases/download/v0.12.3/glide-v0.12.3-windows-amd64.zip",
- "hash": "5F10BC68D533269315B510DEA924724A0989598C43228B1D69ED7308B2E80406",
- "extract_dir": "windows-amd64"
- },
- "32bit": {
- "url": "https://github.com/Masterminds/glide/releases/download/v0.12.3/glide-v0.12.3-windows-386.zip",
- "hash": "6A9082A55F1605EF75EA6862E4849D581D8883E9BF1A76872434928AEA71DE38",
- "extract_dir": "windows-386"
- }
- },
- "bin": "glide.exe",
- "checkver": {
- "github": "https://github.com/Masterminds/glide"
- }
-}
diff --git a/bucket/go.json b/bucket/go.json
deleted file mode 100644
index 1640a02941..0000000000
--- a/bucket/go.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "version": "1.8.3",
- "homepage": "https://golang.org",
- "license": "https://golang.org/LICENSE",
- "architecture": {
- "64bit": {
- "url": "https://storage.googleapis.com/golang/go1.8.3.windows-amd64.zip",
- "hash": "de026caef4c5b4a74f359737dcb2d14c67ca45c45093755d3b0d2e0ee3aafd96"
- },
- "32bit": {
- "url": "https://storage.googleapis.com/golang/go1.8.3.windows-386.zip",
- "hash": "9e2bfcb8110a3c56f23b91f859963269bc29fd114190fecfd0a539395272a1c7"
- }
- },
- "extract_dir": "go",
- "env_add_path": "bin",
- "env_set": {
- "GOROOT": "$dir"
- },
- "checkver": "Build version go([\\d\\.]+)\\.",
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://storage.googleapis.com/golang/go$version.windows-amd64.zip"
- },
- "32bit": {
- "url": "https://storage.googleapis.com/golang/go$version.windows-386.zip"
- }
- },
- "hash": {
- "url": "$url.sha256"
- }
- }
-}
diff --git a/bucket/gow.json b/bucket/gow.json
deleted file mode 100644
index 30cbc304c9..0000000000
--- a/bucket/gow.json
+++ /dev/null
@@ -1,138 +0,0 @@
-{
- "homepage": "https://github.com/bmatzelle/gow",
- "version": "0.8.0",
- "url": "https://github.com/bmatzelle/gow/releases/download/v0.8.0/Gow-0.8.0.exe#/dl.7z",
- "hash": "9b06e0f9471d61d1019bf4d133c0ed23a4ccee27b6b8758a922d681469b82e42",
- "checkver": {
- "url": "https://github.com/bmatzelle/gow/releases",
- "re": "Gow ([\\d.]+)"
- },
- "pre_install": "
- \"@cscript //NoLogo \"\"$dir\\bin\\gow.vbs\"\" %1\" | Set-Content -force \"$dir\\bin\\gow.bat\"
- ",
- "post_install": "
- # create etc directory (required by bash), if needed
- if (! (test-path \"$dir\\etc\")) { new-item -itemtype directory \"$dir\\etc\" }
- ",
- "bin": [
- "bin\\awk.exe",
- "bin\\basename.exe",
- "bin\\bash.exe",
- "bin\\bc.exe",
- "bin\\bison.exe",
- "bin\\bunzip2.exe",
- "bin\\bzip2.exe",
- "bin\\bzip2recover.exe",
- "bin\\cat.exe",
- "bin\\chgrp.exe",
- "bin\\chmod.exe",
- "bin\\chown.exe",
- "bin\\chroot.exe",
- "bin\\cksum.exe",
- "bin\\clear.bat",
- "bin\\cp.exe",
- "bin\\csplit.exe",
- "bin\\curl.exe",
- "bin\\cut.exe",
- "bin\\dc.exe",
- "bin\\dd.exe",
- "bin\\df.exe",
- "bin\\diff.exe",
- "bin\\diff3.exe",
- "bin\\dirname.exe",
- "bin\\dos2unix.exe",
- "bin\\du.exe",
- "bin\\egrep.exe",
- "bin\\env.exe",
- "bin\\expand.exe",
- "bin\\expr.exe",
- "bin\\factor.exe",
- "bin\\fgrep.exe",
- "bin\\flex.exe",
- "bin\\fmt.exe",
- "bin\\fold.exe",
- "bin\\gawk.exe",
- "bin\\gfind.exe",
- "bin\\gow.bat",
- "bin\\grep.exe",
- "bin\\gsar.exe",
- "bin\\gsort.exe",
- "bin\\gzip.exe",
- "bin\\head.exe",
- "bin\\hostid.exe",
- "bin\\hostname.exe",
- "bin\\id.exe",
- "bin\\indent.exe",
- "bin\\install.exe",
- "bin\\join.exe",
- "bin\\jwhois.exe",
- "bin\\less.exe",
- "bin\\lesskey.exe",
- "bin\\ln.exe",
- "bin\\ls.exe",
- "bin\\m4.exe",
- "bin\\make.exe",
- "bin\\md5sum.exe",
- "bin\\mkdir.exe",
- "bin\\mkfifo.exe",
- "bin\\mknod.exe",
- "bin\\mv.exe",
- "bin\\nano.exe",
- "bin\\ncftp.exe",
- "bin\\nl.exe",
- "bin\\od.exe",
- "bin\\pageant.exe",
- "bin\\paste.exe",
- "bin\\patch.exe",
- "bin\\pathchk.exe",
- "bin\\plink.exe",
- "bin\\pr.exe",
- "bin\\printenv.exe",
- "bin\\printf.exe",
- "bin\\pscp.exe",
- "bin\\psftp.exe",
- "bin\\putty.exe",
- "bin\\puttygen.exe",
- "bin\\pwd.exe",
- "bin\\rm.exe",
- "bin\\rmdir.exe",
- "bin\\scp.bat",
- "bin\\sdiff.exe",
- "bin\\sed.exe",
- "bin\\seq.exe",
- "bin\\sftp.bat",
- "bin\\sha1sum.exe",
- "bin\\shar.exe",
- "bin\\sleep.exe",
- "bin\\split.exe",
- "bin\\ssh.bat",
- "bin\\su.exe",
- "bin\\sum.exe",
- "bin\\sync.exe",
- "bin\\tac.exe",
- "bin\\tail.exe",
- "bin\\tar.exe",
- "bin\\tee.exe",
- "bin\\test.exe",
- "bin\\touch.exe",
- "bin\\tr.exe",
- "bin\\uname.exe",
- "bin\\unexpand.exe",
- "bin\\uniq.exe",
- "bin\\unix2dos.exe",
- "bin\\unlink.exe",
- "bin\\unrar.exe",
- "bin\\unshar.exe",
- "bin\\uudecode.exe",
- "bin\\uuencode.exe",
- "bin\\vim.exe",
- "bin\\wc.exe",
- "bin\\wget.exe",
- "bin\\whereis.bat",
- "bin\\which.exe",
- "bin\\whoami.exe",
- "bin\\xargs.exe",
- "bin\\yes.exe",
- "bin\\zip.exe"
- ]
-}
diff --git a/bucket/gpg.json b/bucket/gpg.json
deleted file mode 100644
index d2751bc72b..0000000000
--- a/bucket/gpg.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "version": "2.3.3",
- "license": "GNU",
- "url": "https://files.gpg4win.org/gpg4win-2.3.3.exe#/dl.7z",
- "hash": "5675770b85d49cb05fd3e4bdee7528e19991be508760eef86157d1fa01f0f254",
- "homepage": "https://www.gpg4win.org",
- "bin": [
- [
- "gpg2.exe",
- "gpg",
- ""
- ],
- "gpg2.exe"
- ],
- "checkver": {
- "url": "https://www.gpg4win.org/get-gpg4win.html",
- "re": "Download Gpg4win ([\\d.]+)"
- }
-}
diff --git a/bucket/gradle.json b/bucket/gradle.json
deleted file mode 100644
index d5a1ebd487..0000000000
--- a/bucket/gradle.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "homepage": "https://gradle.org",
- "version": "3.5",
- "license": "Apache 2.0",
- "hash": "0b7450798c190ff76b9f9a3d02e18b33d94553f708ebc08ebe09bdf99111d110",
- "url": "https://services.gradle.org/distributions/gradle-3.5-bin.zip",
- "extract_dir": "gradle-3.5",
- "bin": "bin\\gradle.bat",
- "suggest": {
- "JDK": [
- "extras/oraclejdk",
- "openjdk"
- ]
- },
- "checkver": {
- "url": "https://gradle.org/install",
- "re": "The current Gradle release is version ([\\d.]+)"
- },
- "autoupdate": {
- "url": "https://services.gradle.org/distributions/gradle-$version-bin.zip",
- "extract_dir": "gradle-$version"
- }
-}
diff --git a/bucket/grails.json b/bucket/grails.json
deleted file mode 100644
index 48ab797413..0000000000
--- a/bucket/grails.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "homepage": "https://grails.org/",
- "version": "3.2.10",
- "license": "Apache 2.0",
- "url": "https://github.com/grails/grails-core/releases/download/v3.2.10/grails-3.2.10.zip",
- "hash": "da9c45bf05822ca8cbd273099185888155e9c7c806980690d755a2f7bda9582b",
- "extract_dir": "grails-3.2.10",
- "bin": [
- "bin\\grails.bat"
- ],
- "env_set": {
- "GRAILS_HOME": "$dir"
- },
- "suggest": {
- "JDK": [
- "extras/oraclejdk",
- "openjdk"
- ]
- },
- "checkver": {
- "github": "https://github.com/grails/grails-core"
- },
- "autoupdate": {
- "url": "https://github.com/grails/grails-core/releases/download/v$version/grails-$version.zip",
- "extract_dir": "grails-$version"
- }
-}
diff --git a/bucket/graphviz.json b/bucket/graphviz.json
deleted file mode 100644
index 0628345b3b..0000000000
--- a/bucket/graphviz.json
+++ /dev/null
@@ -1,51 +0,0 @@
-{
- "homepage": "http://www.graphviz.org/",
- "version": "2.38",
- "license": "EPL",
- "url": "http://www.graphviz.org/pub/graphviz/stable/windows/graphviz-2.38.msi",
- "hash": "c794ea03bc2631fff468f4d97fa6726c536fc98ee579529779aa6f45e94e4f6d",
- "bin": [
- "bin/acyclic.exe",
- "bin/bcomps.exe",
- "bin/ccomps.exe",
- "bin/circo.exe",
- "bin/dijkstra.exe",
- "bin/dot.exe",
- "bin/dotty.exe",
- "bin/fc-cache.exe",
- "bin/fc-cat.exe",
- "bin/fc-list.exe",
- "bin/fc-match.exe",
- "bin/fdp.exe",
- "bin/gc.exe",
- "bin/gml2gv.exe",
- "bin/graphml2gv.exe",
- "bin/gv2gml.exe",
- "bin/gvcolor.exe",
- "bin/gvedit.exe",
- "bin/gvgen.exe",
- "bin/gvmap.exe",
- "bin/gvpack.exe",
- "bin/gvpr.exe",
- "bin/gxl2gv.exe",
- "bin/lefty.exe",
- "bin/lneato.exe",
- "bin/mingle.exe",
- "bin/mm2gv.exe",
- "bin/neato.exe",
- "bin/nop.exe",
- "bin/osage.exe",
- "bin/patchwork.exe",
- "bin/prune.exe",
- "bin/sccmap.exe",
- "bin/sfdp.exe",
- "bin/smyrna.exe",
- "bin/tred.exe",
- "bin/twopi.exe",
- "bin/unflatten.exe"
- ],
- "checkver": {
- "url": "http://www.graphviz.org/Download_windows.php",
- "re": "graphviz-([\\d.]+).msi"
- }
-}
diff --git a/bucket/grep.json b/bucket/grep.json
deleted file mode 100644
index facc3997f2..0000000000
--- a/bucket/grep.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "homepage": "http://gnuwin32.sourceforge.net/packages/grep.htm",
- "version": "2.5.4",
- "license": "GPL2",
- "url": [
- "https://sourceforge.net/projects/gnuwin32/files/grep/2.5.4/grep-2.5.4-bin.zip",
- "https://sourceforge.net/projects/gnuwin32/files/grep/2.5.4/grep-2.5.4-dep.zip"
- ],
- "hash": [
- "3fd98201561b5af3f54a7dacc4f88068f5b5edf19ccdfc981c3c9fc60ff73519",
- "2150e12da6631899842c28881a75889794d67b2bbc108341a26052f9bcb27584"
- ],
- "bin": "bin\\grep.exe"
-}
diff --git a/bucket/groovy.json b/bucket/groovy.json
deleted file mode 100644
index d95c14238d..0000000000
--- a/bucket/groovy.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "homepage": "http://www.groovy-lang.org/",
- "version": "2.4.11",
- "license": "Apache 2.0",
- "url": "https://dl.bintray.com/groovy/maven/apache-groovy-binary-2.4.11.zip",
- "hash": "4479a3653c565b173fc0d0e5e514a06f1c7d6f93926cbe0c5d8d29e5e4a0347c",
- "extract_dir": "groovy-2.4.11",
- "bin": [
- "bin\\grape.bat",
- "bin\\groovy.bat",
- "bin\\groovyc.bat",
- "bin\\groovyConsole.bat",
- "bin\\groovydoc.bat",
- "bin\\groovysh.bat",
- "bin\\java2groovy.bat",
- "bin\\startGroovy.bat"
- ],
- "env_set": {
- "GROOVY_HOME": "$dir"
- },
- "suggest": {
- "JDK": [
- "extras/oraclejdk",
- "openjdk"
- ]
- },
- "checkver": {
- "url": "http://www.groovy-lang.org/download.html",
- "re": "apache-groovy-binary-([\\d.]+).zip"
- },
- "autoupdate": {
- "url": "https://dl.bintray.com/groovy/maven/apache-groovy-binary-$version.zip",
- "extract_dir": "groovy-$version"
- }
-}
diff --git a/bucket/gzip.json b/bucket/gzip.json
deleted file mode 100644
index dbd725d612..0000000000
--- a/bucket/gzip.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "homepage": "http://www.mingw.org/wiki/msys",
- "version": "1.3.12",
- "license": "GPL2",
- "url": [
- "https://sourceforge.net/projects/mingw/files/MSYS/Base/gzip/gzip-1.3.12-2/gzip-1.3.12-2-msys-1.0.13-bin.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MSYS/Base/msys-core/msys-1.0.18-1/msysCORE-1.0.18-1-msys-1.0.18-bin.tar.lzma"
- ],
- "hash": [
- "ae0025264557c146044930e5085f1dffd479f2ff21492b1c2454efd689d287be",
- "4e262a414f238773b311c8bb55a52e62743c06e0e55b319ca5b47e3e306464d5"
- ],
- "bin": "bin\\gzip.exe"
-}
diff --git a/bucket/handbrake-cli.json b/bucket/handbrake-cli.json
deleted file mode 100644
index 8e4152d16b..0000000000
--- a/bucket/handbrake-cli.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "homepage": "https://handbrake.fr/",
- "license": "GPL-2.0",
- "version": "1.0.7",
- "architecture": {
- "64bit": {
- "hash": "152046b12d17c576d68eedecf5231001fafbc660c27ce52075b7a48d8ca91c8a",
- "url": "https://download.handbrake.fr/handbrake/releases/1.0.7/HandBrakeCLI-1.0.7-win-i686.zip"
- },
- "32bit": {
- "hash": "b00c00520705e05bfb42701b4121de8e56c9c283af2b30d42ce10b24823519e0",
- "url": "https://download.handbrake.fr/handbrake/releases/1.0.7/HandBrakeCLI-1.0.7-win-x86_64.zip"
- }
- },
- "bin": [
- "HandBrakeCLI.exe"
- ],
- "checkver": {
- "re": "Current\\s+Version:\\s+([\\d.]+)",
- "url": "https://handbrake.fr/downloads2.php"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://download.handbrake.fr/handbrake/releases/$version/HandBrakeCLI-$version-win-i686.zip"
- },
- "32bit": {
- "url": "https://download.handbrake.fr/handbrake/releases/$version/HandBrakeCLI-$version-win-x86_64.zip"
- }
- },
- "hash": {
- "find": "
$basename | .*\\s+.*\\s+.*
([a-fA-F0-9]{64})",
- "url": "https://handbrake.fr/checksums.php"
- }
- }
-}
diff --git a/bucket/hashcat.json b/bucket/hashcat.json
deleted file mode 100644
index dcd729b2ef..0000000000
--- a/bucket/hashcat.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "homepage": "https://hashcat.net/hashcat/",
- "license": "mit",
- "version": "3.5.0",
- "url": "https://hashcat.net/files/hashcat-3.5.0.7z",
- "extract_dir": "hashcat-3.5.0",
- "architecture": {
- "64bit": {
- "bin": [
- [
- "hashcat64.exe",
- "hashcat",
- ""
- ]
- ]
- },
- "32bit": {
- "bin": [
- [
- "hashcat32.exe",
- "hashcat",
- ""
- ]
- ]
- }
- },
- "hash": "0f3f1338325e1f46c1a622b30e9b90c4b54216d89e00b74816562e2659b2fc2a",
- "checkver": {
- "github": "https://github.com/hashcat/hashcat/"
- },
- "autoupdate": {
- "url": "https://hashcat.net/files/hashcat-$version.7z",
- "extract_dir": "hashcat-$version"
- }
-}
diff --git a/bucket/haskell.json b/bucket/haskell.json
deleted file mode 100644
index f5fbb068ef..0000000000
--- a/bucket/haskell.json
+++ /dev/null
@@ -1,47 +0,0 @@
-{
- "homepage": "https://www.haskell.org",
- "version": "8.0.2",
- "architecture": {
- "64bit": {
- "url": "https://haskell.org/platform/download/8.0.2/HaskellPlatform-8.0.2-minimal-x86_64-setup.exe",
- "hash": "5901fddb219a4d864ee3e21dc73434de0eeb98cbd27a50845b8a687e1c1cb8fa"
- },
- "32bit": {
- "url": "https://haskell.org/platform/download/8.0.2/HaskellPlatform-8.0.2-minimal-i386-setup.exe",
- "hash": "5be3feaf90977bbe769753c8295cafef40591c8f247808cf6b662ebab2839738"
- }
- },
- "installer": {
- "args": "/S /D=$dir"
- },
- "uninstaller": {
- "file": "Uninstall.exe",
- "args": "/S"
- },
- "bin": [
- "bin\\ghc.exe",
- "bin\\ghci.exe",
- "bin\\ghc-pkg.exe",
- "bin\\haddock.exe",
- "bin\\hp2ps.exe",
- "bin\\hpc.exe",
- "bin\\hsc2hs.exe",
- "bin\\runghc.exe",
- "bin\\runhaskell.exe",
- "lib\\extralibs\\bin\\cabal.exe"
- ],
- "checkver": {
- "url": "https://www.haskell.org/platform/windows.html",
- "re": "The latest version of the Haskell Platform for Windows is\\s+([\\d.]+)<\\/strong>"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://haskell.org/platform/download/$version/HaskellPlatform-$version-minimal-x86_64-setup.exe"
- },
- "32bit": {
- "url": "https://haskell.org/platform/download/$version/HaskellPlatform-$version-minimal-i386-setup.exe"
- }
- }
- }
-}
diff --git a/bucket/haxe.json b/bucket/haxe.json
deleted file mode 100644
index 305cdd8304..0000000000
--- a/bucket/haxe.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "homepage": "https://haxe.org/",
- "version": "3.4.2",
- "license": "https://haxe.org/foundation/open-source.html",
- "url": "https://github.com/HaxeFoundation/haxe/releases/download/3.4.2/haxe-3.4.2-win.zip",
- "hash": "8251bac3e58abebfd4f6618a8b036dc83ae7309a3e11d622ad4132f1442cc38d",
- "bin": [
- "haxe.exe",
- "haxelib.exe"
- ],
- "env_set": {
- "HAXEPATH": "$dir"
- },
- "depends": "neko",
- "checkver": {
- "github": "https://github.com/HaxeFoundation/haxe"
- },
- "autoupdate": {
- "url": "https://github.com/HaxeFoundation/haxe/releases/download/$version/haxe-$version-win.zip"
- }
-}
diff --git a/bucket/highlight.json b/bucket/highlight.json
deleted file mode 100644
index d9baf9833f..0000000000
--- a/bucket/highlight.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "homepage": "http://www.andre-simon.de/doku/highlight/en/highlight.php",
- "version": "3.35",
- "license": "GPL3",
- "architecture": {
- "64bit": {
- "url": "http://www.andre-simon.de/zip/highlight-3.35-x64.zip",
- "hash": "b63a88a3f3ea81965f46086df606eeedeffa20608107c7217f3d699ea5610957",
- "extract_dir": "highlight-3.35-x64"
- },
- "32bit": {
- "url": "http://www.andre-simon.de/zip/highlight-3.35.zip",
- "hash": "ea4c81ff647eeb0d19ebf07f576b4b5366dcd34c9a50d397555cae3dfc82c6ee",
- "extract_dir": "highlight-3.35"
- }
- },
- "bin": "highlight.exe"
-}
diff --git a/bucket/hub.json b/bucket/hub.json
deleted file mode 100644
index 9abb677854..0000000000
--- a/bucket/hub.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "homepage": "https://hub.github.com/",
- "version": "2.2.9",
- "license": "MIT",
- "architecture": {
- "64bit": {
- "url": "https://github.com/github/hub/releases/download/v2.2.9/hub-windows-amd64-2.2.9.zip",
- "hash": "dd90e977924c92f6685b66202cd108fbdcc946560964747cb8ca2a904316676f"
- },
- "32bit": {
- "url": "https://github.com/github/hub/releases/download/v2.2.9/hub-windows-386-2.2.9.zip",
- "hash": "fa8bdb2ddf0aac0bed23b166a35788e48922336fcaa1d0929818489f6c27342c"
- }
- },
- "bin": [
- "bin\\hub.exe"
- ],
- "checkver": {
- "github": "https://github.com/github/hub"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://github.com/github/hub/releases/download/v$version/hub-windows-amd64-$version.zip"
- },
- "32bit": {
- "url": "https://github.com/github/hub/releases/download/v$version/hub-windows-386-$version.zip"
- }
- }
- }
-}
diff --git a/bucket/hugo.json b/bucket/hugo.json
deleted file mode 100644
index 82adc61a4b..0000000000
--- a/bucket/hugo.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "version": "0.21",
- "license": "https://github.com/spf13/hugo/blob/master/LICENSE.md",
- "architecture": {
- "64bit": {
- "url": "https://github.com/spf13/hugo/releases/download/v0.21/hugo_0.21_windows-64bit.zip",
- "hash": "2a0ee080084d2fd1baea4d32ff02be7c0541c253dc07004cdaa026ff114c87c8"
- },
- "32bit": {
- "url": "https://github.com/spf13/hugo/releases/download/v0.21/hugo_0.21_windows-32bit.zip",
- "hash": "014b3030de2102bd4cbbfd37e6a9a342fe2c0aeba79f8f627ff1f7337d9d5916"
- }
- },
- "bin": "hugo.exe",
- "homepage": "https://gohugo.io",
- "checkver": {
- "github": "https://github.com/spf13/hugo"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://github.com/spf13/hugo/releases/download/v$version/hugo_$version_windows-64bit.zip"
- },
- "32bit": {
- "url": "https://github.com/spf13/hugo/releases/download/v$version/hugo_$version_windows-32bit.zip"
- }
- }
- }
-}
diff --git a/bucket/iconv.json b/bucket/iconv.json
deleted file mode 100644
index 1a9369f3f0..0000000000
--- a/bucket/iconv.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "homepage": "http://www.mingw.org/",
- "version": "1.14-3",
- "license": "GPLv3+",
- "url": [
- "https://sourceforge.net/projects/mingw/files/MinGW/Base/libiconv/libiconv-1.14-3/libiconv-1.14-3-mingw32-bin.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MinGW/Base/libiconv/libiconv-1.14-3/libiconv-1.14-3-mingw32-dll.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MinGW/Base/gettext/gettext-0.18.3.1-1/gettext-0.18.3.1-1-mingw32-dll.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MinGW/Base/gcc/Version4/gcc-4.8.1-4/gcc-core-4.8.1-4-mingw32-dll.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MinGW/Base/mpc/mpc-1.0.1-2/mpc-1.0.1-2-mingw32-dll.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MinGW/Base/mpfr/mpfr-3.1.2-2/mpfr-3.1.2-2-mingw32-dll.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MinGW/Base/gmp/gmp-5.1.2/gmp-5.1.2-1-mingw32-dll.tar.lzma"
- ],
- "hash": [
- "540592b29a5964a566127d3e976f0c0df8ffc1137788030c17a44750e7b02340",
- "fbdab03c19c6c50f15b58d02a3cb8c31e8d95baafaa67239f389b9023c7757fd",
- "3c1daf9fade6342de5bb00aacdf85155eb04b07ee3ffe4b1c33b99692329391f",
- "0dab5f923c5d289b8e7e22a3b16ebff5ff8b7c7c0d295ac71806d97ef87b8bee",
- "d0cd8770aee5df0f3008f2d11383ed3b9c918902ba43ac20374b91fb37a4e58c",
- "063e607c9a576a3ed62d3986f7263cff69cbb5f9e366b981ba36001c08c6a973",
- "7fe1d9de26875386c1fbce1f9a971d43c45644b2df3ead2c5ff0042053b5b75d"
- ],
- "bin": "bin\\iconv.exe"
-}
diff --git a/bucket/imagemagick.json b/bucket/imagemagick.json
deleted file mode 100644
index 82bb774d50..0000000000
--- a/bucket/imagemagick.json
+++ /dev/null
@@ -1,52 +0,0 @@
-{
- "homepage": "https://www.imagemagick.org/script/index.php",
- "license": "https://www.imagemagick.org/script/license.php",
- "version": "7.0.5-9",
- "architecture": {
- "64bit": {
- "url": "https://www.imagemagick.org/download/binaries/ImageMagick-7.0.5-9-portable-Q16-x64.zip",
- "hash": "390c561e5919f84c7a79070d6ed3cbddc99c57a247b683056f1d51830a346949"
- },
- "32bit": {
- "url": "https://www.imagemagick.org/download/binaries/ImageMagick-7.0.5-9-portable-Q16-x86.zip",
- "hash": "cda433f45f200fa60d72cdb0971b9e14d79dd7ee12c5b0cf46f8084ed8224a4e"
- }
- },
- "depends": [
- "ffmpeg"
- ],
- "env_add_path": ".",
- "bin": [
- "compare.exe",
- "composite.exe",
- "conjure.exe",
- "convert.exe",
- [
- "convert.exe",
- "imconvert"
- ],
- "dcraw.exe",
- "hp2xx.exe",
- "identify.exe",
- "IMDisplay.exe",
- "magick.exe",
- "mogrify.exe",
- "montage.exe",
- "stream.exe"
- ],
- "checkver": "The current release is ImageMagick ([0-9\\.p-]+)",
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://www.imagemagick.org/download/binaries/ImageMagick-$version-portable-Q16-x64.zip"
- },
- "32bit": {
- "url": "https://www.imagemagick.org/download/binaries/ImageMagick-$version-portable-Q16-x86.zip"
- }
- },
- "hash": {
- "mode": "rdf",
- "url": "https://www.imagemagick.org/download/binaries/digest.rdf"
- }
- }
-}
diff --git a/bucket/innounp.json b/bucket/innounp.json
deleted file mode 100644
index 237be05045..0000000000
--- a/bucket/innounp.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "homepage": "http://innounp.sourceforge.net",
- "version": "0.46",
- "url": "https://sourceforge.net/projects/innounp/files/innounp/innounp%200.46/innounp046.rar/",
- "hash": "3c056e2fc46ca9e92405f13ddf1f250cfe4bd66cb83b6647d87c74bc7242b121",
- "bin": "innounp.exe",
- "checkver": "Version\\s+([\\d.]+)\\s*
"
-}
diff --git a/bucket/invoke-build.json b/bucket/invoke-build.json
deleted file mode 100644
index b2c08dd9d7..0000000000
--- a/bucket/invoke-build.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "version": "3.3.11",
- "license": "Apache 2.0",
- "extract_dir": "tools",
- "url": "http://nuget.org/api/v2/package/Invoke-Build/3.3.11#/dl.7z",
- "homepage": "https://github.com/nightroman/Invoke-Build",
- "hash": "2988e439998fcc03023242c54ed219405b1c9e79b83d515b92bb1c3133535fee",
- "env_add_path": ".",
- "checkver": {
- "url": "https://github.com/nightroman/Invoke-Build/releases",
- "re": "releases/tag/v([\\d.]+)"
- },
- "autoupdate": {
- "url": "http://nuget.org/api/v2/package/Invoke-Build/$version#/dl.7z"
- }
-}
diff --git a/bucket/jetbrains-toolbox.json b/bucket/jetbrains-toolbox.json
deleted file mode 100644
index 1684dcab52..0000000000
--- a/bucket/jetbrains-toolbox.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "homepage": "https://jetbrains.com/",
- "version": "1.6.2",
- "license": "https://www.jetbrains.com/store/license.html",
- "url": "https://download.jetbrains.com/toolbox/jetbrains-toolbox-1.3.2421.exe",
- "hash": "e5b84aa2f36475f4ae3ccd7ef9428e4ecd7160ffd07728623909c6c35542e060",
- "installer": {
- "args": [
- "/S", "/D=$dir"
- ]
- },
- "uninstaller": {
- "file": "Uninstall.exe",
- "args": ["/S"]
- },
- "bin": [
- "jetbrains-toolbox.exe"
- ],
- "persist": "apps",
- "checkver": {
- "url": "https://data.services.jetbrains.com/products/releases?code=TBA&latest=true&type=release",
- "re": "jetbrains-toolbox-([\\d.]+).exe"
- },
- "autoupdate": {
- "url": "https://download.jetbrains.com/toolbox/jetbrains-toolbox-$version.exe",
- "hash": {
- "url": "$url.sha256"
- }
- },
- "post_install": "$las=\"$Env:LOCALAPPDATA\\Jetbrains\\Toolbox\\.settings.json\"; if(Test-Path \"$las\") {(gc \"$las\") -join \"`n\"| ConvertFrom-Json | Add-Member -Force @{install_location=\"$dir\";intellij_platform=($architecture -eq '64bit')} -P | ConvertToPrettyJson | sc \"$las\"}",
- "notes": "Set 'Install Location' to $dir to persist the installed apps"
-}
diff --git a/bucket/jq.json b/bucket/jq.json
deleted file mode 100644
index 8988756fb5..0000000000
--- a/bucket/jq.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "version": "1.5",
- "license": "http://creativecommons.org/licenses/by/3.0/",
- "architecture": {
- "32bit": {
- "url": "https://github.com/stedolan/jq/releases/download/jq-1.5/jq-win32.exe#/jq.exe"
- },
- "64bit": {
- "url": "https://github.com/stedolan/jq/releases/download/jq-1.5/jq-win64.exe#/jq.exe"
- }
- },
- "homepage": "http://stedolan.github.io/jq/",
- "bin": "jq.exe",
- "checkver": {
- "url": "https://github.com/stedolan/jq/releases/latest",
- "re": "/releases/tag/jq-([\\d.]+)"
- }
-}
diff --git a/bucket/julia.json b/bucket/julia.json
deleted file mode 100644
index aa341ebd67..0000000000
--- a/bucket/julia.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
- "homepage": "https://julialang.org",
- "version": "0.5.2",
- "license": "MIT",
- "architecture": {
- "64bit": {
- "url": "https://s3.amazonaws.com/julialang/bin/winnt/x64/0.5/julia-0.5.2-win64.exe#/dl.7z",
- "hash": "b581eba45150c8cb3b3befc139049ba10180a72bf5a83a2b537919d43d441d43"
- },
- "32bit": {
- "url": "https://s3.amazonaws.com/julialang/bin/winnt/x86/0.5/julia-0.5.2-win32.exe#/dl.7z",
- "hash": "1bc9663fbc5383a6d1167bdac831b11540e661cc45c2ad4042d1b8b94f24211c"
- }
- },
- "installer": {
- "file": "julia-installer.exe",
- "args": [
- "/S",
- "/D=$dir"
- ]
- },
- "uninstaller": {
- "file": "uninstall.exe",
- "args": "/S"
- },
- "env_set": {
- "JULIA_HOME": "$dir\\bin",
- "JULIA_EXE": "julia.exe",
- "JULIA": "$dir\\bin\\julia.exe",
- "JL_PRIVATE_LIB_DIR": "bin"
- },
- "bin": [
- [
- "bin\\julia.exe",
- "julia"
- ]
- ],
- "checkver": {
- "url": "http://julialang.org/downloads/",
- "re": "]+>Current Release \\(v([\\d.]+)\\)
"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://s3.amazonaws.com/julialang/bin/winnt/x64/$majorVersion.$minorVersion/julia-$version-win64.exe#/dl.7z"
- },
- "32bit": {
- "url": "https://s3.amazonaws.com/julialang/bin/winnt/x86/$majorVersion.$minorVersion/julia-$version-win32.exe#/dl.7z"
- }
- },
- "hash": {
- "url": "https://s3.amazonaws.com/julialang/bin/checksums/julia-$version.sha256"
- }
- }
-}
diff --git a/bucket/kotlin.json b/bucket/kotlin.json
deleted file mode 100644
index 60482ff765..0000000000
--- a/bucket/kotlin.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "homepage": "https://kotlinlang.org/",
- "version": "1.1.2",
- "license": "Apache 2.0",
- "url": "https://github.com/JetBrains/kotlin/releases/download/v1.1.2/kotlin-compiler-1.1.2.zip",
- "hash": "cb6d30b14adb0067477042e12c1d15e5a26cf80ef6a115e248ed4a89cbf6cf4e",
- "extract_dir": "kotlinc",
- "bin": [
- "bin\\kotlin.bat",
- "bin\\kotlinc.bat",
- "bin\\kotlinc-js.bat",
- "bin\\kotlinc-jvm.bat"
- ],
- "env_set": {
- "KOTLIN_HOME": "$dir"
- },
- "suggest": {
- "JDK": [
- "extras/oraclejdk",
- "openjdk"
- ]
- },
- "checkver": {
- "github": "https://github.com/JetBrains/kotlin"
- },
- "autoupdate": {
- "url": "https://github.com/JetBrains/kotlin/releases/download/v$version/kotlin-compiler-$version.zip"
- }
-}
diff --git a/bucket/kubectl.json b/bucket/kubectl.json
deleted file mode 100644
index a9ebfce7e6..0000000000
--- a/bucket/kubectl.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "homepage": "https://kubernetes.io/docs/user-guide/kubectl-overview/",
- "license": "https://github.com/kubernetes/kubernetes/blob/master/LICENSE",
- "version": "1.6.4",
- "architecture": {
- "64bit": {
- "url": "https://storage.googleapis.com/kubernetes-release/release/v1.6.4/kubernetes-client-windows-amd64.tar.gz",
- "hash": "sha1:025e840064dda24972e6598e8587cb36f43c63df"
- },
- "32bit": {
- "url": "https://storage.googleapis.com/kubernetes-release/release/v1.6.4/kubernetes-client-windows-386.tar.gz",
- "hash": "sha1:89c503298a4ccd96d5dc5315100603fe41357646"
- }
- },
- "extract_dir": "kubernetes\\client",
- "bin": [
- "bin\\kubectl.exe",
- "bin\\kubefed.exe"
- ],
- "checkver": {
- "url": "https://storage.googleapis.com/kubernetes-release/release/stable.txt",
- "re": "v([\\d.]+)"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://storage.googleapis.com/kubernetes-release/release/v$version/kubernetes-client-windows-amd64.tar.gz"
- },
- "32bit": {
- "url": "https://storage.googleapis.com/kubernetes-release/release/v$version/kubernetes-client-windows-386.tar.gz"
- }
- },
- "hash": {
- "url": "$url.sha1"
- }
- }
-}
diff --git a/bucket/kvm.json b/bucket/kvm.json
deleted file mode 100644
index e398f7cca9..0000000000
--- a/bucket/kvm.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "version": "latest",
- "license": "Apache 2.0",
- "url": [
- "https://raw.githubusercontent.com/aspnet/Home/master/kvm.ps1"
- ],
- "homepage": "https://github.com/aspnet/Home",
- "env_set": {
- "KRE_HOME": "$dir\\.k",
- "KRE_USER_HOME": "$dir\\.k"
- },
- "bin": "kvm.ps1",
- "post_install": "iex \"kvm upgrade\""
-}
diff --git a/bucket/latex.json b/bucket/latex.json
deleted file mode 100644
index 1edad6677a..0000000000
--- a/bucket/latex.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "homepage": "https://miktex.org",
- "version": "2.9.6326",
- "license": "https://miktex.org/copying",
- "url": "https://miktex.org/download/ctan/systems/win32/miktex/setup/miktex-portable-2.9.6326.exe#/dl.7z",
- "hash": "c6337c1f46010f747b13d741f7b22554aeb10ad468cc37af6c7ecbebdd0db26c",
- "env_add_path": "texmfs\\install\\miktex\\bin",
- "checkver": {
- "url": "https://miktex.org/portable",
- "re": "miktex-portable-([\\d.]+).exe"
- },
- "autoupdate": {
- "url": "https://miktex.org/download/ctan/systems/win32/miktex/setup/miktex-portable-$version.exe#/dl.7z"
- }
-}
diff --git a/bucket/leiningen.json b/bucket/leiningen.json
deleted file mode 100644
index 68edb1003d..0000000000
--- a/bucket/leiningen.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "version": "2.7.1",
- "license": "Eclipse Public License 1.0",
- "url": "https://raw.githubusercontent.com/technomancy/leiningen/150d98b7ae873001615e14f5ba3da601e8261b76/bin/lein.bat",
- "homepage": "https://github.com/technomancy/leiningen",
- "bin": "lein.bat",
- "hash": "32385e54b54ec99ac8a37792347ca4f1a3c7feb792066d7ffc8f1e4c5b7c7ad1",
- "notes": "The command 'lein self-install' is required to complete the installation",
- "checkver": "github"
-}
diff --git a/bucket/less.json b/bucket/less.json
deleted file mode 100644
index 48959f6e9b..0000000000
--- a/bucket/less.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "homepage": "http://gnuwin32.sourceforge.net/packages/less.htm",
- "version": "394",
- "license": "Simplified BSD",
- "url": [
- "https://sourceforge.net/projects/gnuwin32/files/less/394/less-394-bin.zip",
- "https://sourceforge.net/projects/gnuwin32/files/less/394/less-394-dep.zip"
- ],
- "hash": [
- "cd8233cb3caee8ccbbed6883443f44f2002218eceb4d697d38a0c40c2d181896",
- "4c3ae2878046ceb528956b2c7f995d6231087b99561e38c4c72c13d850159d2b"
- ],
- "bin": "bin\\less.exe"
-}
diff --git a/bucket/lessmsi.json b/bucket/lessmsi.json
deleted file mode 100644
index 1e70e93885..0000000000
--- a/bucket/lessmsi.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "homepage": "https://github.com/activescott/lessmsi/",
- "version": "1.6.1",
- "license": "https://github.com/activescott/lessmsi/raw/master/LICENSE",
- "hash": "540b8801e08ec39ba26a100c855898f455410cecbae4991afae7bb2b4df026c7",
- "url": "https://github.com/activescott/lessmsi/releases/download/v1.6.1/lessmsi-v1.6.1.zip",
- "bin": "lessmsi.exe",
- "checkver": {
- "github": "https://github.com/activescott/lessmsi"
- },
- "autoupdate": {
- "url": "https://github.com/activescott/lessmsi/releases/download/v$version/lessmsi-v$version.zip"
- }
-}
diff --git a/bucket/llvm.json b/bucket/llvm.json
deleted file mode 100644
index f0f6da64dc..0000000000
--- a/bucket/llvm.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "homepage": "http://www.llvm.org",
- "version": "4.0.0",
- "license": "University of Illinois/NCSA Open Source License",
- "architecture": {
- "32bit": {
- "url": "http://releases.llvm.org/4.0.0/LLVM-4.0.0-win32.exe",
- "hash": "aabe2a31182d9adce8146c86fe92e19d911b7cc1cb240cdb790f314c819c92e2"
- },
- "64bit": {
- "url": "http://releases.llvm.org/4.0.0/LLVM-4.0.0-win64.exe",
- "hash": "9bb800e42a4568c7a6e217dac1b613741ee9811eea2fa65ca8c20702728003e9"
- }
- },
- "installer": {
- "args": "/S /D=$dir"
- },
- "uninstaller": {
- "file": "Uninstall.exe",
- "args": "/S"
- },
- "env_add_path": "bin",
- "checkver": "\\/releases\\/download.html#([\\d.]+)",
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "http://releases.llvm.org/$version/LLVM-$version-win64.exe"
- },
- "32bit": {
- "url": "http://releases.llvm.org/$version/LLVM-$version-win32.exe"
- }
- }
- }
-}
diff --git a/bucket/ln.json b/bucket/ln.json
deleted file mode 100644
index 7c32833516..0000000000
--- a/bucket/ln.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "homepage": "https://github.com/lukesampson/psutils",
- "version": "0.2015.04.25",
- "url": "https://raw.githubusercontent.com/lukesampson/psutils/4e363db/ln.ps1",
- "hash": "81e9447d5d0108057c54380a8e49f6db9fa5806d2018e7b27bd68f3fb8332b98",
- "bin": "ln.ps1"
-}
diff --git a/bucket/lua.json b/bucket/lua.json
deleted file mode 100644
index ba34c63132..0000000000
--- a/bucket/lua.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "version": "5.1.5-51",
- "url": "https://github.com/rjpcomputing/luaforwindows/releases/download/v5.1.5-51/LuaForWindows_v5.1.5-51.exe",
- "homepage": "https://github.com/rjpcomputing/luaforwindows",
- "hash": "f56df460eb9717702297a29373334fe9b01bedc5cd24d1380bc29c352ade090b",
- "innosetup": true,
- "bin": [
- "lua.exe",
- "luac.exe"
- ],
- "depends": [
- "innounp"
- ],
- "checkver": {
- "url": "https://github.com/rjpcomputing/luaforwindows/releases/latest",
- "re": "/releases/tag/v([\\d.\\-]+)"
- }
-}
diff --git a/bucket/lynx.json b/bucket/lynx.json
deleted file mode 100644
index dc23082d07..0000000000
--- a/bucket/lynx.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "version": "v2.8.3",
- "extract_dir": "lynx_w32",
- "url": "http://www.vordweb.co.uk/standards/lynx_v283.zip",
- "homepage": "http://www.vordweb.co.uk/standards/download_lynx.htm",
- "hash": "552bc68afd2ff9a5de88f26d76f55dd8697cf6082c6afb01b3d1a9942f4d3ee0",
- "bin": "lynx.ps1",
- "pre_install": "
- \"$dir\\lynx.exe --cfg=$dir\\lynx.cfg\" | out-file -enc oem $dir\\lynx.ps1
- "
-}
diff --git a/bucket/mailsend.json b/bucket/mailsend.json
deleted file mode 100644
index aad49c6455..0000000000
--- a/bucket/mailsend.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "version": "1.19",
- "license": "https://github.com/muquit/mailsend/blob/master/COPYRIGHT",
- "url": "https://github.com/muquit/mailsend/releases/download/1.19/mailsend1.19.exe.zip",
- "homepage": "https://github.com/muquit/mailsend",
- "checkver": {
- "github": "https://github.com/muquit/mailsend"
- },
- "autoupdate": {
- "url": "https://github.com/muquit/mailsend/releases/download/$version/mailsend$version.exe.zip"
- },
- "hash": "87db23b8c9588353d12e19e953dddb17ed04b422f41bcfbaa8ad4e27057245b4",
- "bin": [
- [
- "mailsend1.19.exe",
- "mailsend"
- ]
- ]
-}
diff --git a/bucket/make.json b/bucket/make.json
deleted file mode 100644
index cc85734543..0000000000
--- a/bucket/make.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "homepage": "https://www.gnu.org/software/make/",
- "version": "4.2",
- "license": "GPLv3",
- "architecture": {
- "64bit": {
- "url": "ftp://ftp.equation.com/make/64/make.exe",
- "hash": "9a9a1bc6276739478bd62678099b00e07275bb3562d19d14991b72c6876cdfcc"
- },
- "32bit": {
- "url": "ftp://ftp.equation.com/make/32/make.exe",
- "hash": "9a9a1bc6276739478bd62678099b00e07275bb3562d19d14991b72c6876cdfcc"
- }
- },
- "bin": "make.exe",
- "checkver": {
- "url": "http://www.equation.com/servlet/equation.cmd?fa=make",
- "re": "to download 32-bit binary of version ([\\d.]+)"
- }
-}
diff --git a/bucket/mariadb.json b/bucket/mariadb.json
deleted file mode 100644
index 4529e4118f..0000000000
--- a/bucket/mariadb.json
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "homepage": "http://mariadb.org",
- "version": "10.2.6",
- "license": "GPL2",
- "architecture": {
- "64bit": {
- "url": "https://downloads.mariadb.org/f/mariadb-10.2.6/winx64-packages/mariadb-10.2.6-winx64.zip",
- "hash": "4065fc93af7e5f7f4267656adf17a8483a4e4beaf705b0e4da727d580f9e1962",
- "extract_dir": "mariadb-10.2.6-winx64"
- },
- "32bit": {
- "url": "https://downloads.mariadb.org/f/mariadb-10.2.6/win32-packages/mariadb-10.2.6-win32.zip",
- "hash": "cbaa89b391aaa44b98363e3b2c45f94da1b6faa5a7f5c4af9e2d421ebd252434",
- "extract_dir": "mariadb-10.2.6-win32"
- }
- },
- "bin": [
- "bin\\aria_chk.exe",
- "bin\\aria_dump_log.exe",
- "bin\\aria_ftdump.exe",
- "bin\\aria_pack.exe",
- "bin\\aria_read_log.exe",
- "bin\\innochecksum.exe",
- "bin\\myisamchk.exe",
- "bin\\myisamlog.exe",
- "bin\\myisampack.exe",
- "bin\\myisam_ftdump.exe",
- "bin\\mysql.exe",
- "bin\\mysqladmin.exe",
- "bin\\mysqlbinlog.exe",
- "bin\\mysqlcheck.exe",
- "bin\\mysqld.exe",
- "bin\\mysqldump.exe",
- "bin\\mysqlimport.exe",
- "bin\\mysqlshow.exe",
- "bin\\mysqlslap.exe",
- "bin\\mysqltest.exe",
- "bin\\mysqltest_embedded.exe",
- "bin\\mysql_client_test.exe",
- "bin\\mysql_client_test_embedded.exe",
- "bin\\mysql_embedded.exe",
- "bin\\mysql_install_db.exe",
- "bin\\mysql_plugin.exe",
- "bin\\mysql_tzinfo_to_sql.exe",
- "bin\\mysql_upgrade.exe",
- "bin\\mysql_upgrade_service.exe",
- "bin\\mysql_upgrade_wizard.exe",
- "bin\\my_print_defaults.exe"
- ],
- "persist": [
- "data"
- ],
- "checkver": {
- "url": "https://downloads.mariadb.org/",
- "re": "Download ([\\d.]+) Stable"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://downloads.mariadb.org/f/mariadb-$version/winx64-packages/mariadb-$version-winx64.zip",
- "extract_dir": "mariadb-$version-winx64"
- },
- "32bit": {
- "url": "https://downloads.mariadb.org/f/mariadb-$version/win32-packages/mariadb-$version-win32.zip",
- "extract_dir": "mariadb-$version-win32"
- }
- }
- }
-}
diff --git a/bucket/maven.json b/bucket/maven.json
deleted file mode 100644
index 3ebe59a55a..0000000000
--- a/bucket/maven.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "homepage": "https://maven.apache.org/",
- "version": "3.5.0",
- "license": "Apache 2.0",
- "url": "https://archive.apache.org/dist/maven/maven-3/3.5.0/binaries/apache-maven-3.5.0-bin.zip",
- "hash": "sha1:886393e7031d42c412a077c240af73d75e671d62",
- "extract_dir": "apache-maven-3.5.0",
- "env_add_path": "bin",
- "env_set": {
- "M2_HOME": "$dir"
- },
- "suggest": {
- "JDK": [
- "extras/oraclejdk",
- "openjdk"
- ]
- },
- "checkver": {
- "url": "https://maven.apache.org/download.cgi",
- "re": "Apache Maven ([\\d.]+) is the latest release"
- },
- "autoupdate": {
- "url": "https://archive.apache.org/dist/maven/maven-$majorVersion/$version/binaries/apache-maven-$version-bin.zip",
- "extract_dir": "apache-maven-$version",
- "hash": {
- "url": "$url.sha1"
- }
- }
-}
diff --git a/bucket/mediainfo.json b/bucket/mediainfo.json
deleted file mode 100644
index 1efdf65169..0000000000
--- a/bucket/mediainfo.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "version": "0.7.96",
- "homepage": "https://mediaarea.net/en/MediaInfo",
- "license": "BSD",
- "architecture": {
- "64bit": {
- "url": "https://mediaarea.net/download/binary/mediainfo/0.7.96/MediaInfo_CLI_0.7.96_Windows_x64.zip",
- "hash": "e8123ea19b9a2f8f1f2731a25cfdf2d0d692828a5d969e00d7d5c82af6782b49"
- },
- "32bit": {
- "url": "https://mediaarea.net/download/binary/mediainfo/0.7.96/MediaInfo_CLI_0.7.96_Windows_i386.zip",
- "hash": "dca3113a80f431d5f90b04aa3cfc0b8f41509d06c126a165dc9a7c2575eeaa95"
- }
- },
- "bin": "mediainfo.exe",
- "checkver": "version ([\\d.]+)",
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://mediaarea.net/download/binary/mediainfo/$version/MediaInfo_CLI_$version_Windows_x64.zip"
- },
- "32bit": {
- "url": "https://mediaarea.net/download/binary/mediainfo/$version/MediaInfo_CLI_$version_Windows_i386.zip"
- }
- }
- }
-}
diff --git a/bucket/mercurial.json b/bucket/mercurial.json
deleted file mode 100644
index 1d5b765071..0000000000
--- a/bucket/mercurial.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "homepage": "https://www.mercurial-scm.org/",
- "version": "4.2",
- "license": "http://www.gnu.org/licenses/gpl-2.0.txt",
- "architecture": {
- "64bit": {
- "url": "https://www.mercurial-scm.org/release/windows/Mercurial-4.2-x64.exe",
- "hash": "61d827b75ffe5ade60ec184a0f9ee6adb59ea640af8d7ab7c8d29d29cf64738d"
- },
- "32bit": {
- "url": "https://www.mercurial-scm.org/release/windows/Mercurial-4.2.exe",
- "hash": "42bc2eb4261a67af44a9cd6014641e86012fa90dbbb87999b7f7af193890cc1a"
- }
- },
- "innosetup": true,
- "bin": "hg.exe",
- "checkver": {
- "url": "https://www.mercurial-scm.org/wiki/WhatsNew",
- "re": "Mercurial\\s+([\\d.]+)\\s+\\([0-9\\-]+\\)"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://www.mercurial-scm.org/release/windows/Mercurial-$version-x64.exe"
- },
- "32bit": {
- "url": "https://www.mercurial-scm.org/release/windows/Mercurial-$version.exe"
- }
- }
- }
-}
diff --git a/bucket/metastore.json b/bucket/metastore.json
deleted file mode 100644
index 666cba7296..0000000000
--- a/bucket/metastore.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "bin": "metastore.exe",
- "checkver": {
- "re": "/releases/tag/([a-f0-9]+)\"",
- "url": "https://github.com/rasa/metastore/releases/latest"
- },
- "description": "Store and restore metadata from a filesystem",
- "hash": "93394fa2c43f60155f811cfa7c718d85aa4d0b61a9ce3267075ded716fdc7025",
- "homepage": "https://github.com/rasa/metastore",
- "license": "GPL-2.0",
- "url": "https://github.com/rasa/metastore/releases/download/95d4e2d/metastore.exe",
- "version": "95d4e2d"
-}
diff --git a/bucket/minikube.json b/bucket/minikube.json
deleted file mode 100644
index a81de3673a..0000000000
--- a/bucket/minikube.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "homepage": "https://kubernetes.io/docs/getting-started-guides/minikube/",
- "license": "https://github.com/kubernetes/minikube/blob/master/LICENSE",
- "version": "0.19.1",
- "architecture": {
- "64bit": {
- "url": "https://storage.googleapis.com/minikube/releases/v0.19.1/minikube-windows-amd64.exe",
- "hash": "6389e7026b4703cc88e3c542e36a3cbe1e2b4ffb8e676ebcf0d02a9fed7561f4"
- }
- },
- "bin": [
- [
- "minikube-windows-amd64.exe",
- "minikube"
- ]
- ],
- "checkver": {
- "github": "https://github.com/kubernetes/minikube"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://storage.googleapis.com/minikube/releases/v$version/minikube-windows-amd64.exe"
- }
- },
- "hash": {
- "url": "$url.sha256"
- }
- }
-}
diff --git a/bucket/minio-client.json b/bucket/minio-client.json
deleted file mode 100644
index 4901818eab..0000000000
--- a/bucket/minio-client.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "homepage": "https://minio.io/",
- "license": "https://github.com/minio/mc/blob/master/LICENSE",
- "version": "2017-04-03T18-35-01Z",
- "bin": "mc.exe",
- "architecture": {
- "64bit": {
- "url": "https://dl.minio.io/client/mc/release/windows-amd64/mc.RELEASE.2017-04-03T18-35-01Z#/mc.exe",
- "hash": "sha1:b3fa256eeb5395b1fa5f19b5be97f8428ad67ec2"
- },
- "32bit": {
- "url": "https://dl.minio.io/client/mc/release/windows-386/mc.RELEASE.2017-04-03T18-35-01Z#/mc.exe",
- "hash": "sha1:a36164d2bc280d719e7c51e763c2535ad5aa89d9"
- }
- },
- "suggest": {
- "minio": "minio"
- },
- "checkver": {
- "github": "https://github.com/minio/mc",
- "re": "releases/tag/RELEASE.([\\d-]+T[\\d-]+Z)"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://dl.minio.io/client/mc/release/windows-amd64/mc.RELEASE.$version#/mc.exe",
- "hash": {
- "url": "$baseurl/mc.shasum"
- }
- },
- "32bit": {
- "url": "https://dl.minio.io/client/mc/release/windows-386/mc.RELEASE.$version#/mc.exe",
- "hash": {
- "url": "$baseurl/mc.shasum"
- }
- }
- }
- }
-}
diff --git a/bucket/minio.json b/bucket/minio.json
deleted file mode 100644
index 29318aa46a..0000000000
--- a/bucket/minio.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "homepage": "https://minio.io/",
- "license": "https://github.com/minio/minio/blob/master/LICENSE",
- "version": "2017-05-05T01-14-51Z",
- "bin": "minio.exe",
- "architecture": {
- "64bit": {
- "url": "https://dl.minio.io/server/minio/release/windows-amd64/archive/minio.RELEASE.2017-05-05T01-14-51Z#/minio.exe",
- "hash": "37cc9319c3e60545bd8cd76108aaf0339be4d9d4977e7f48451224a2799f01e7"
- },
- "32bit": {
- "url": "https://dl.minio.io/server/minio/release/windows-386/archive/minio.RELEASE.2017-05-05T01-14-51Z#/minio.exe",
- "hash": "bc3911a985dd0c56c6f95fb9ffad04eea4736c4e3a8e054993006a9ebd66fcc2"
- }
- },
- "suggest": {
- "minio-client": "minio-client"
- },
- "checkver": {
- "github": "https://github.com/minio/minio",
- "re": "releases/tag/RELEASE.([\\d-]+T[\\d-]+Z)"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://dl.minio.io/server/minio/release/windows-amd64/archive/minio.RELEASE.$version#/minio.exe",
- "hash": {
- "url": "$baseurl/minio.RELEASE.$version.sha256sum"
- }
- },
- "32bit": {
- "url": "https://dl.minio.io/server/minio/release/windows-386/archive/minio.RELEASE.$version#/minio.exe",
- "hash": {
- "url": "$baseurl/minio.RELEASE.$version.sha256sum"
- }
- }
- }
- }
-}
diff --git a/bucket/minisign.json b/bucket/minisign.json
deleted file mode 100644
index a414d54a99..0000000000
--- a/bucket/minisign.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "homepage": "https://jedisct1.github.io/minisign/",
- "license": "https://github.com/jedisct1/minisign/blob/master/LICENSE",
- "version": "0.7",
- "url": "https://github.com/jedisct1/minisign/releases/download/0.7/minisign-win32.zip",
- "hash": "2a1cc74a608b24a3475b78b8943125e799c270cc8d0b940cceaec34e8f5e0e33",
- "extract_dir": "minisign-win32",
- "bin": "minisign.exe",
- "checkver": {
- "github": "https://github.com/jedisct1/minisign"
- },
- "autoupdate": {
- "url": "https://github.com/jedisct1/minisign/releases/download/$version/minisign-win32.zip"
- }
-}
diff --git a/bucket/modd.json b/bucket/modd.json
deleted file mode 100644
index 2b8736a815..0000000000
--- a/bucket/modd.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "homepage": "https://corte.si/posts/modd/announce/index.html",
- "license": "https://github.com/cortesi/modd/blob/master/LICENSE",
- "version": "0.4",
- "url": "https://github.com/cortesi/modd/releases/download/v0.4/modd-0.4-windows64.zip",
- "hash": "9d2f314a2fe8cfbc64a6e3657575e9de7d0410ff4cd12522b72663605ea2b03f",
- "extract_dir": "modd-0.4-windows64",
- "bin": "modd.exe",
- "checkver": {
- "github": "https://github.com/cortesi/modd"
- },
- "autoupdate": {
- "url": "https://github.com/cortesi/modd/releases/download/v$version/modd-$version-windows64.zip",
- "extract_dir": "modd-$version-windows64"
- }
-}
diff --git a/bucket/mongodb.json b/bucket/mongodb.json
deleted file mode 100644
index 446d429d2c..0000000000
--- a/bucket/mongodb.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "homepage": "https://www.mongodb.org",
- "version": "3.4.4",
- "license": "https://www.mongodb.org/about/licensing/",
- "architecture": {
- "64bit": {
- "url": "https://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2008plus-ssl-3.4.4-signed.msi",
- "hash": "73d1121a1fe58fe29c4fb7b6f4b79a4d33afa666f357960419ef83635396f977"
- }
- },
- "bin": [
- "MongoDB\\Server\\3.4\\bin\\bsondump.exe",
- "MongoDB\\Server\\3.4\\bin\\mongo.exe",
- "MongoDB\\Server\\3.4\\bin\\mongod.exe",
- "MongoDB\\Server\\3.4\\bin\\mongodump.exe",
- "MongoDB\\Server\\3.4\\bin\\mongoexport.exe",
- "MongoDB\\Server\\3.4\\bin\\mongofiles.exe",
- "MongoDB\\Server\\3.4\\bin\\mongoimport.exe",
- "MongoDB\\Server\\3.4\\bin\\mongooplog.exe",
- "MongoDB\\Server\\3.4\\bin\\mongoperf.exe",
- "MongoDB\\Server\\3.4\\bin\\mongorestore.exe",
- "MongoDB\\Server\\3.4\\bin\\mongos.exe",
- "MongoDB\\Server\\3.4\\bin\\mongostat.exe",
- "MongoDB\\Server\\3.4\\bin\\mongotop.exe"
- ],
- "post_install": "
- # create initial directories
- mkdir C:\\data
- mkdir C:\\data\\db
- ",
- "checkver": {
- "url": "https://www.mongodb.com/download-center",
- "re": "Current Stable Release \\(([\\d.]+)\\)"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2008plus-ssl-$version-signed.msi"
- }
- }
- }
-}
diff --git a/bucket/mono.json b/bucket/mono.json
deleted file mode 100644
index b0d4a79948..0000000000
--- a/bucket/mono.json
+++ /dev/null
@@ -1,106 +0,0 @@
-{
- "version": "4.8.0.495",
- "homepage": "http://www.mono-project.com/",
- "license": "https://raw.githubusercontent.com/mono/mono/master/LICENSE",
- "url": "https://download.mono-project.com/archive/4.8.0/windows-installer/mono-4.8.0.495-gtksharp-2.12.42-win32-1.msi",
- "hash": "7B30232DE859E87A05CAB1BDE3B2C4681225AA4C48B6ADFC740E642CBDD3A5A7",
- "extract_dir": "Mono",
- "bin": [
- "bin\\gdk-pixbuf-query-loaders.exe",
- "bin\\gspawn-win32-helper-console.exe",
- "bin\\gspawn-win32-helper.exe",
- "bin\\gtk-query-immodules-2.0.exe",
- "bin\\mono-boehm.exe",
- "bin\\mono-sgen.exe",
- "bin\\mono.exe",
- "bin\\monodis.exe",
- "bin\\monograph.exe",
- "bin\\monow.exe",
- "bin\\pango-querymodules.exe",
- "bin\\pkg-config.exe",
- "bin\\sgen-grep-binprot.exe",
- "bin\\al.bat",
- "bin\\al2.bat",
- "bin\\caspol.bat",
- "bin\\cccheck.bat",
- "bin\\ccrewrite.bat",
- "bin\\cert-sync.bat",
- "bin\\cert2spc.bat",
- "bin\\certmgr.bat",
- "bin\\chktrust.bat",
- "bin\\crlupdate.bat",
- "bin\\csharp.bat",
- "bin\\disco.bat",
- "bin\\dmcs.bat",
- "bin\\dtd2rng.bat",
- "bin\\dtd2xsd.bat",
- "bin\\fsharpc.bat",
- "bin\\fsharpi.bat",
- "bin\\fsharpiAnyCpu.bat",
- "bin\\gacutil.bat",
- "bin\\gacutil2.bat",
- "bin\\genxs.bat",
- "bin\\httpcfg.bat",
- "bin\\ikdasm.bat",
- "bin\\ilasm.bat",
- "bin\\installvst.bat",
- "bin\\ipy.bat",
- "bin\\ipy64.bat",
- "bin\\ipyw.bat",
- "bin\\ipyw64.bat",
- "bin\\ir.bat",
- "bin\\ir64.bat",
- "bin\\irw.bat",
- "bin\\irw64.bat",
- "bin\\lc.bat",
- "bin\\macpack.bat",
- "bin\\makecert.bat",
- "bin\\mconfig.bat",
- "bin\\mcs.bat",
- "bin\\mdbrebase.bat",
- "bin\\mdoc.bat",
- "bin\\mkbundle.bat",
- "bin\\mod.bat",
- "bin\\mono-api-html.bat",
- "bin\\mono-api-info.bat",
- "bin\\mono-cil-strip.bat",
- "bin\\mono-service.bat",
- "bin\\mono-service2.bat",
- "bin\\mono-shlib-cop.bat",
- "bin\\mono-symbolicate.bat",
- "bin\\mono-xmltool.bat",
- "bin\\monolinker.bat",
- "bin\\monop.bat",
- "bin\\monop2.bat",
- "bin\\mozroots.bat",
- "bin\\nuget.bat",
- "bin\\nunit-console.bat",
- "bin\\nunit-console2.bat",
- "bin\\nunit-console4.bat",
- "bin\\pdb2mdb.bat",
- "bin\\permview.bat",
- "bin\\resgen.bat",
- "bin\\resgen2.bat",
- "bin\\secutil.bat",
- "bin\\setmonopath.bat",
- "bin\\setreg.bat",
- "bin\\sgen.bat",
- "bin\\signcode.bat",
- "bin\\sn.bat",
- "bin\\soapsuds.bat",
- "bin\\sqlmetal.bat",
- "bin\\sqlsharp.bat",
- "bin\\svcutil.bat",
- "bin\\wsdl.bat",
- "bin\\wsdl2.bat",
- "bin\\xbuild.bat",
- "bin\\xsd.bat",
- "bin\\xsp.bat",
- "bin\\xsp2.bat",
- "bin\\xsp4.bat"
- ],
- "checkver": {
- "url": "http://www.mono-project.com/download/",
- "re": "The latest Mono release is:\\s+[^\\(]+\\(([\\d.]+)\\)"
- }
-}
diff --git a/bucket/mozjpeg.json b/bucket/mozjpeg.json
deleted file mode 100644
index c4948e55e0..0000000000
--- a/bucket/mozjpeg.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "homepage": "https://github.com/mozilla/mozjpeg",
- "version": "3.1",
- "license": "https://github.com/mozilla/mozjpeg/blob/master/LICENSE.txt",
- "url": "https://mozjpeg.codelove.de/bin/mozjpeg_3.1_x86.zip",
- "hash": "f8fd47f219823e7ee1fe6583bca8baca075d214081588f1fd66141f790cf0731",
- "bin": [
- "cjpeg.exe",
- [
- "cjpeg.exe",
- "mozjpeg"
- ],
- "djpeg.exe",
- "jpegtran.exe"
- ],
- "checkver": {
- "url": "https://mozjpeg.codelove.de/binaries.html",
- "re": "version ([\\d.]+)"
- }
-}
diff --git a/bucket/msys.json b/bucket/msys.json
deleted file mode 100644
index 06997f8afa..0000000000
--- a/bucket/msys.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "version": "rev13",
- "url": "https://sourceforge.net/projects/mingwbuilds/files/external-binary-packages/msys%2B7za%2Bwget%2Bsvn%2Bgit%2Bmercurial%2Bcvs-rev13.7z",
- "hash": "5f2ea0c4b714a7d7e704e83040397d0ba7ecaf925afa5512aada180a711ef770",
- "extract_dir": "msys",
- "bin": "msys.bat"
-}
diff --git a/bucket/mysql-workbench.json b/bucket/mysql-workbench.json
deleted file mode 100644
index d991fc14d4..0000000000
--- a/bucket/mysql-workbench.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "version": "6.3.9",
- "license": "GPL",
- "homepage": "https://dev.mysql.com/downloads/workbench/",
- "architecture": {
- "64bit": {
- "url": "https://cdn.mysql.com/Downloads/MySQLGUITools/mysql-workbench-community-6.3.9-winx64.msi",
- "extract_dir": "MySQL\\MySQL Workbench 6.3 CE",
- "hash": "md5:89773c47e3f43d247182a9c0270c2bc5"
- }
- },
- "checkver": "MySQL Workbench (?(?[\\d]+.[\\d]+).[\\d]+)",
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://cdn.mysql.com/Downloads/MySQLGUITools/mysql-workbench-community-$version-winx64.msi",
- "extract_dir": "MySQL\\MySQL Workbench $matchShort CE"
- }
- },
- "hash": {
- "url": "$url.md5"
- }
- },
- "bin": [
- "MySQLWorkbench.exe",
- "mysql.exe",
- "mysqldump.exe"
- ]
-}
diff --git a/bucket/mysql.json b/bucket/mysql.json
deleted file mode 100644
index 5817ba4d32..0000000000
--- a/bucket/mysql.json
+++ /dev/null
@@ -1,62 +0,0 @@
-{
- "homepage": "https://dev.mysql.com/downloads/mysql/",
- "version": "5.7.18",
- "license": "GPLv2",
- "architecture": {
- "64bit": {
- "url": "https://dev.mysql.com/get/mysql-5.7.18-winx64.zip",
- "hash": "6a3b2d070200ae4e29f8a08aceb1c76cca9beccb037de4f5ab120d657e781353",
- "extract_dir": "mysql-5.7.18-winx64"
- },
- "32bit": {
- "url": "https://dev.mysql.com/get/mysql-5.7.18-win32.zip",
- "hash": "a4313a35827477264479112040f029d34798ccf010b40ceb85c060aacc925039",
- "extract_dir": "mysql-5.7.18-win32"
- }
- },
- "bin": [
- "bin\\mysqld.exe",
- "bin\\mysql.exe",
- "bin\\mysqldump.exe",
- "bin\\mysqladmin.exe",
- "bin\\mysqlbinlog.exe",
- "bin\\mysqlcheck.exe",
- "bin\\mysqlimport.exe",
- "bin\\mysqlshow.exe",
- "bin\\mysqlslap.exe",
- "bin\\my_print_defaults.exe"
- ],
- "persist": [
- "data"
- ],
- "post_install": "
-#Initialize data directory (without generating root password)
-if (!(Test-Path \"$dir\\data\\auto.cnf\")) {
- mysqld --initialize-insecure
-}
-
-#Copy provided sample file to live file location
-cp $dir/my-default.ini $dir/my.ini
-
-#Output client configuration to my.ini file so no username is required when connecting
-echo \"\" | out-file \"$dir/my.ini\" -Encoding UTF8 -Append
-echo \"[client]\" | out-file \"$dir/my.ini\" -Encoding UTF8 -Append
-echo \"user=root\" | out-file \"$dir/my.ini\" -Encoding UTF8 -Append
-",
- "checkver": {
- "url": "https://dev.mysql.com/downloads/mysql/",
- "re": "MySQL Community Server ([\\d.]+)"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://dev.mysql.com/get/mysql-$version-winx64.zip",
- "extract_dir": "mysql-$version-winx64"
- },
- "32bit": {
- "url": "https://dev.mysql.com/get/mysql-$version-win32.zip",
- "extract_dir": "mysql-$version-win32"
- }
- }
- }
-}
diff --git a/bucket/nano.json b/bucket/nano.json
deleted file mode 100644
index ed54f8c4d7..0000000000
--- a/bucket/nano.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "homepage": "https://www.nano-editor.org/",
- "version": "2.5.3",
- "license": "GPL",
- "url": "https://www.nano-editor.org/dist/v2.5/NT/nano-2.5.3.zip",
- "hash": "c012456b9f29e488b0e9a688aa43a34326dd573f9e99765cbdac2b81a4bc1060",
- "bin": "nano-2.5.3-win32\\nano.exe",
- "checkver": "Latest Version\\s+([\\d.]+)"
-}
diff --git a/bucket/nasm.json b/bucket/nasm.json
deleted file mode 100644
index de2dafce2e..0000000000
--- a/bucket/nasm.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- "homepage": "http://www.nasm.us",
- "license": "BSD",
- "version": "2.13.01",
- "extract_dir": "nasm-2.13.01",
- "architecture": {
- "64bit": {
- "url": "http://www.nasm.us/pub/nasm/releasebuilds/2.13.01/win64/nasm-2.13.01-win64.zip",
- "hash": "8b368c5ed7f9deb33be90918e8c19b2fbf004fbe74b743e515674c75943d3362"
- },
- "32bit": {
- "url": "http://www.nasm.us/pub/nasm/releasebuilds/2.13.01/win32/nasm-2.13.01-win32.zip",
- "hash": "01b93a34af9511e30663409c5138531fc1a05d88eb54d52453138dc020646dc1"
- }
- },
- "bin": [
- "nasm.exe",
- "ndisasm.exe",
- "rdoff/ldrdf.exe",
- "rdoff/rdf2bin.exe",
- "rdoff/rdf2com.exe",
- "rdoff/rdf2ihx.exe",
- "rdoff/rdf2ith.exe",
- "rdoff/rdf2srec.exe",
- "rdoff/rdfdump.exe",
- "rdoff/rdflib.exe",
- "rdoff/rdx.exe"
- ],
- "checkver": "The latest stable version of NASM is\\s+.+\\/(?[\\d\\.]+)",
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "http://www.nasm.us/pub/nasm/releasebuilds/$version/win64/nasm-$version-win64.zip"
- },
- "32bit": {
- "url": "http://www.nasm.us/pub/nasm/releasebuilds/$version/win32/nasm-$version-win32.zip"
- }
- },
- "extract_dir": "nasm-$version"
- }
-}
diff --git a/bucket/neko.json b/bucket/neko.json
deleted file mode 100644
index 9684b1ec97..0000000000
--- a/bucket/neko.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "homepage": "http://nekovm.org/",
- "version": "2.1.0",
- "license": "https://github.com/HaxeFoundation/neko/blob/master/LICENSE",
- "url": "http://nekovm.org/media/neko-2.1.0-win.zip",
- "hash": "ad7f8ead8300cdbfdc062bcf7ba63b1b1993d975023cde2dfd61936950eddb0e",
- "extract_dir": "neko-2.1.0-win",
- "env_add_path": "./",
- "checkver": {
- "url": "http://nekovm.org/download",
- "re": "Neko ([\\d.]+)"
- },
- "autoupdate": {
- "url": "http://nekovm.org/media/neko-$version-win.zip",
- "extract_dir": "neko-$version-win"
- }
-}
diff --git a/bucket/netcat.json b/bucket/netcat.json
deleted file mode 100644
index 80fa73f26a..0000000000
--- a/bucket/netcat.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "architecture": {
- "32bit": {
- "bin": "nc.exe"
- },
- "64bit": {
- "bin": [
- [
- "nc64.exe",
- "nc"
- ]
- ]
- }
- },
- "autoupdate": {
- "url": "https://eternallybored.org/misc/netcat/netcat-win32-$version.zip"
- },
- "description": "Read and write from/to network connections",
- "hash": "413f85a1dbac60ab5516742d76beff4f4da22b8ef1a424f10f36ec77e6d274b1",
- "homepage": "https://eternallybored.org/misc/netcat/",
- "license": "GPL-2.0",
- "url": "https://eternallybored.org/misc/netcat/netcat-win32-1.12.zip",
- "version": "1.12"
-}
diff --git a/bucket/nginx.json b/bucket/nginx.json
deleted file mode 100644
index 4b977dd246..0000000000
--- a/bucket/nginx.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "homepage": "https://nginx.org",
- "version": "1.13.1",
- "license": "BSD",
- "url": "https://nginx.org/download/nginx-1.13.1.zip",
- "hash": "9e9e3fed629dc5d37c917cde3f2a4c31736a2e66fe874e72d9d17ac8e900f84d",
- "extract_dir": "nginx-1.13.1",
- "bin": "nginx.exe",
- "env_set": {
- "NGINX_HOME": "$dir"
- },
- "persist": [
- "conf",
- "html",
- "logs",
- "temp"
- ],
- "notes": "To use the correct configuration run 'nginx -p \"$env:NGINX_HOME\"' or 'nginx -p \"%NGINX_HOME%\"'",
- "checkver": {
- "url": "https://nginx.org/en/CHANGES",
- "re": "Changes with nginx ([\\d.]+)"
- },
- "autoupdate": {
- "url": "https://nginx.org/download/nginx-$version.zip",
- "extract_dir": "nginx-$version"
- }
-}
diff --git a/bucket/nikto.json b/bucket/nikto.json
deleted file mode 100644
index a47dea54a3..0000000000
--- a/bucket/nikto.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "homepage": "http://projects.giacomodrago.com/nikto-win/",
- "version": "2.1.5",
- "license": "GPL",
- "url": "http://projects.giacomodrago.com/nikto-win/nikto-2.1.5-win.7z",
- "hash": "c70506872670e7c0cb1b497d732a58e19f9e0934e8b32bf212334aed00fca173",
- "extract_dir": "nikto-2.1.5",
- "bin": "nikto.bat",
- "checkver": "Nikto ([\\d.]+)"
-}
diff --git a/bucket/nim.json b/bucket/nim.json
deleted file mode 100644
index 576c028c2d..0000000000
--- a/bucket/nim.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "homepage": "https://nim-lang.org/",
- "version": "0.17.0",
- "license": "MIT",
- "architecture": {
- "64bit": {
- "url": "https://nim-lang.org/download/nim-0.17.0_x64.zip",
- "hash": "0e0aea31338b433e75f9c197a6ec37a42f68aee4be6c91d813f3e053fef5a05c"
- },
- "32bit": {
- "url": "https://nim-lang.org/download/nim-0.17.0_x32.zip",
- "hash": "8fe344f6fb6242b4555878f4243844ea78edb22acf9cb23a91399ea543a5036b"
- }
- },
- "depends": "gcc",
- "extract_dir": "nim-0.17.0",
- "post_install": "
- # Copy Nimble package
- Copy-Item -Recurse $dir\\dist\\nimble\\src\\nimblepkg $dir\\bin
- ",
- "env_add_path": "bin",
- "checkver": {
- "url": "https://nim-lang.org/install_windows.html",
- "re": "nim-([\\d.]+)_x64"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://nim-lang.org/download/nim-$version_x64.zip"
- },
- "32bit": {
- "url": "https://nim-lang.org/download/nim-$version_x32.zip"
- }
- },
- "extract_dir": "nim-$version",
- "hash": {
- "url": "$url.sha256"
- }
- }
-}
diff --git a/bucket/ninja.json b/bucket/ninja.json
deleted file mode 100644
index 9b0b716a63..0000000000
--- a/bucket/ninja.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "homepage": "https://ninja-build.org/",
- "license": "Apache 2.0",
- "version": "1.7.2",
- "url": "https://github.com/ninja-build/ninja/releases/download/v1.7.2/ninja-win.zip",
- "hash": "95b36a597d33c1fe672829cfe47b5ab34b3a1a4c6bf628e5d150b6075df4ef50",
- "bin": [
- "ninja.exe"
- ],
- "checkver": {
- "github": "https://github.com/ninja-build/ninja"
- },
- "autoupdate": {
- "url": "https://github.com/ninja-build/ninja/releases/download/v$version/ninja-win.zip"
- }
-}
diff --git a/bucket/nircmd.json b/bucket/nircmd.json
deleted file mode 100644
index e6a62017bb..0000000000
--- a/bucket/nircmd.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "version": "2.81",
- "homepage": "http://www.nirsoft.net/utils/nircmd.html",
- "architecture": {
- "64bit": {
- "url": "http://www.nirsoft.net/utils/nircmd.zip",
- "hash": "f56a6166f8956c507cc2bfec71339f3c467c0421fe6d16fbe4c52a36d79ce0ea"
- },
- "32bit": {
- "url": "http://www.nirsoft.net/utils/nircmd-x64.zip",
- "hash": "37445b39e2fc437688164866c495bd28890ded5d0dbf71615bf92776e57c5189"
- }
- },
- "extract_dir": ".",
- "bin": "nircmdc.exe"
-}
diff --git a/bucket/nmap.json b/bucket/nmap.json
deleted file mode 100644
index e7f5b80dc7..0000000000
--- a/bucket/nmap.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "homepage": "https://nmap.org",
- "version": "7.31",
- "license": "https://svn.nmap.org/nmap/COPYING",
- "url": "https://nmap.org/dist/nmap-7.31-setup.exe",
- "hash": "A11E24D481C3CCBDC7AD30AF36F27B1557E5C94CCAC410BB0829EE82DCD3FD9E",
- "extract_dir": "nmap",
- "installer": {
- "args": "/S /D=$dir"
- },
- "uninstaller": {
- "file": "Uninstall.exe",
- "args": "/S"
- },
- "env_add_path": "bin",
- "bin": [
- "nmap.exe",
- "ncat.exe",
- "ndiff.exe",
- "zenmap.exe",
- "nping.exe"
- ],
- "shortcuts": [
- [
- "zenmap.exe",
- "Zenmap"
- ]
- ]
-}
diff --git a/bucket/nodejs-lts.json b/bucket/nodejs-lts.json
deleted file mode 100644
index f896140b50..0000000000
--- a/bucket/nodejs-lts.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "homepage": "http://nodejs.org",
- "version": "6.10.3",
- "license": "MIT",
- "architecture": {
- "64bit": {
- "url": "https://nodejs.org/dist/v6.10.3/node-v6.10.3-win-x64.7z",
- "hash": "86993d66c110592be3a4d4e78c5d386b17e1d8437cc6fa2a5a227369c1915a1e",
- "extract_dir": "node-v6.10.3-win-x64"
- },
- "32bit": {
- "url": "https://nodejs.org/dist/v6.10.3/node-v6.10.3-win-x86.7z",
- "hash": "d236ab5607a1cee6ef5f1a7ae1c1bfbe212218dd7d823ea2d57d12e3d3bf7cd8",
- "extract_dir": "node-v6.10.3-win-x86"
- }
- },
- "persist": [
- "bin",
- "cache"
- ],
- "env_add_path": [
- ".",
- "bin"
- ],
- "post_install": "
- # Set npm prefix to install modules inside bin and npm cache so they persist
- Set-Content -Value \"prefix=$persist_dir\\bin`ncache=$persist_dir\\cache\" -Path $dir\\node_modules\\npm\\npmrc
- ",
- "checkver": {
- "url": "https://nodejs.org/en/download/",
- "re": "LTS version: v([\\d.]+)"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://nodejs.org/dist/v$version/node-v$version-win-x64.7z",
- "extract_dir": "node-v$version-win-x64"
- },
- "32bit": {
- "url": "https://nodejs.org/dist/v$version/node-v$version-win-x86.7z",
- "extract_dir": "node-v$version-win-x86"
- }
- },
- "hash": {
- "url": "$baseurl/SHASUMS256.txt.asc"
- }
- }
-}
diff --git a/bucket/nodejs.json b/bucket/nodejs.json
deleted file mode 100644
index 48366d2832..0000000000
--- a/bucket/nodejs.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "homepage": "http://nodejs.org",
- "version": "8.0.0",
- "license": "MIT",
- "architecture": {
- "64bit": {
- "url": "https://nodejs.org/dist/v8.0.0/node-v8.0.0-win-x64.7z",
- "hash": "9bc84644228ab1e96dfb78eea4144c7c9732ccd33b44a4b8994fd232fafa19b5",
- "extract_dir": "node-v8.0.0-win-x64"
- },
- "32bit": {
- "url": "https://nodejs.org/dist/v8.0.0/node-v8.0.0-win-x86.7z",
- "hash": "4c4d1c21a56ab4da6a24543ee27bd2d22fbbf5fcae9ccc3422869ad45754809c",
- "extract_dir": "node-v8.0.0-win-x86"
- }
- },
- "persist": [
- "bin",
- "cache"
- ],
- "env_add_path": [
- ".",
- "bin"
- ],
- "post_install": "
- # Set npm prefix to install modules inside bin and npm cache so they persist
- Set-Content -Value \"prefix=$persist_dir\\bin`ncache=$persist_dir\\cache\" -Path $dir\\node_modules\\npm\\npmrc
- ",
- "checkver": {
- "url": "https://nodejs.org/en/download/current/",
- "re": "Current version: v([\\d.]+)"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://nodejs.org/dist/v$version/node-v$version-win-x64.7z",
- "extract_dir": "node-v$version-win-x64"
- },
- "32bit": {
- "url": "https://nodejs.org/dist/v$version/node-v$version-win-x86.7z",
- "extract_dir": "node-v$version-win-x86"
- }
- },
- "hash": {
- "url": "$baseurl/SHASUMS256.txt.asc"
- }
- }
-}
diff --git a/bucket/nssm.json b/bucket/nssm.json
deleted file mode 100644
index d733f8e3b0..0000000000
--- a/bucket/nssm.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "homepage": "https://nssm.cc",
- "version": "2.24",
- "url": "https://nssm.cc/release/nssm-2.24.zip",
- "hash": "727d1e42275c605e0f04aba98095c38a8e1e46def453cdffce42869428aa6743",
- "architecture": {
- "64bit": {
- "extract_dir": "nssm-2.24/win64"
- },
- "32bit": {
- "extract_dir": "nssm-2.24/win32"
- }
- },
- "bin": [
- "nssm.exe",
- [
- "nssm.exe",
- "service"
- ]
- ],
- "checkver": {
- "re": "[\\d.]+)-openjdk-(?[\\d.]+-[\\d]+)(?.*).x86_64.zip\\)"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://github.com/ojdkbuild/ojdkbuild/releases/download/$version/java-$matchShort-openjdk-$version$matchTail.x86_64.zip",
- "extract_dir": "java-$matchShort-openjdk-$version$matchTail.x86_64"
- }
- },
- "hash": {
- "url": "$url.sha256"
- }
- }
-}
diff --git a/bucket/openssh.json b/bucket/openssh.json
deleted file mode 100644
index 2f541a9c1f..0000000000
--- a/bucket/openssh.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "version": "5.4p1-1",
- "license": "http://www.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/LICENCE?rev=HEAD",
- "url": [
- "https://sourceforge.net/projects/mingw/files/MSYS/Extension/openssh/openssh-5.4p1-1/openssh-5.4p1-1-msys-1.0.13-bin.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MSYS/Extension/openssh/openssh-5.4p1-1/openssh-5.4p1-1-msys-1.0.13-lic.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MSYS/Base/msys-core/msys-1.0.13-2/msysCORE-1.0.13-2-msys-1.0.13-bin.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MSYS/Extension/zlib/zlib-1.2.3-2/zlib-1.2.3-2-msys-1.0.13-dll.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MSYS/Extension/minires/minires-1.02_1-2/libminires-1.02_1-2-msys-1.0.13-dll.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MSYS/Extension/openssl/openssl-1.0.0-1/libopenssl-1.0.0-1-msys-1.0.13-dll-100.tar.lzma"
- ],
- "hash": [
- "8c8e6a030a34c341394bb8b9f1760743468a8cc5e4244efc34f7ab3cd3e67b64",
- "edef96034d9ec958b9a58023bcfef54bb4f6b56c6df94c2cced178a675cc3a98",
- "41c7d5561662e41da74951f373a08a95db40b27b1246227bbbc13abc44976ea7",
- "4178940828b928b2d5a33042cc83fbb992b4bfb9ffeaef6dc3e555f2a6a8c0d1",
- "e42fbdcff71404a76306f3b8f0024f453aafa7fe7dd9dac43c82b2e8d33e23f1",
- "463ed0e62cc5ae102a8e2f4d30e665507cf8a3930f23668629eea48cb4dda71c"
- ],
- "bin": [
- "bin\\scp.exe",
- "bin\\sftp.exe",
- "bin\\slogin.exe",
- "bin\\ssh-add.exe",
- "bin\\ssh-agent.exe",
- "bin\\ssh-keygen.exe",
- "bin\\ssh-keyscan.exe",
- "bin\\ssh.exe"
- ]
-}
diff --git a/bucket/openssl.json b/bucket/openssl.json
deleted file mode 100644
index 00f98d7e98..0000000000
--- a/bucket/openssl.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "homepage": "https://slproweb.com/products/Win32OpenSSL.html",
- "version": "1.1.0f",
- "license": "https://www.openssl.org/source/license.html",
- "architecture": {
- "64bit": {
- "url": "https://slproweb.com/download/Win64OpenSSL-1_1_0f.exe",
- "hash": "sha512:fc91de3ee75f0aef586b7583080ec981f02d62be7bfbbdbd5abdd058df0f6264dff9587670e3266b6077761ab48166720bbe6560595f95830819655d0d615f8b"
- },
- "32bit": {
- "url": "https://slproweb.com/download/Win32OpenSSL-1_1_0f.exe",
- "hash": "sha512:c26a3f3947de5453459098bd042e74661999435060991d49ab207a62c10c7d0b9d26576532aeae943181c5d12c261df16a91bdfa341e5b8ffdcd2741d807ca88"
- }
- },
- "innosetup": true,
- "bin": "bin\\openssl.exe",
- "env_add_path": "bin",
- "env_set": {
- "OPENSSL_CONF": "$dir\\bin\\cnf\\openssl.cnf"
- },
- "checkver": "Win32 OpenSSL v([^\\s]+)",
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://slproweb.com/download/Win64OpenSSL-$underscoreVersion.exe"
- },
- "32bit": {
- "url": "https://slproweb.com/download/Win32OpenSSL-$underscoreVersion.exe"
- }
- },
- "hash": {
- "mode": "json",
- "jp": "$.files.$basename.sha512",
- "url": "$baseurl/win32_openssl_hashes.json"
- }
- }
-}
diff --git a/bucket/optipng.json b/bucket/optipng.json
deleted file mode 100644
index 1b100a41c0..0000000000
--- a/bucket/optipng.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "homepage": "http://optipng.sourceforge.net/",
- "version": "0.7.6",
- "license": "zlib",
- "url": "https://sourceforge.net/projects/optipng/files/OptiPNG/optipng-0.7.6/optipng-0.7.6-win32.zip",
- "hash": "0012ec30ee5292e1fd19e0f8c45de4cc291fb5872c5bc83355c17e0b6ce662f7",
- "extract_dir": "optipng-0.7.6-win32",
- "bin": "optipng.exe",
- "checkver": "([\\d.]+)<\\/b><\\/font> \\(stable\\)"
-}
diff --git a/bucket/packer.json b/bucket/packer.json
deleted file mode 100644
index aa3a15ac4f..0000000000
--- a/bucket/packer.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "homepage": "https://www.packer.io",
- "license": "Mozilla Public License 2.0",
- "version": "1.0.0",
- "architecture": {
- "64bit": {
- "url": "https://releases.hashicorp.com/packer/1.0.0/packer_1.0.0_windows_amd64.zip",
- "hash": "54b2c92548f0a4f434771703f083b6e0fbbf73a8bf81963fd43e429d2561a4e0"
- },
- "32bit": {
- "url": "https://releases.hashicorp.com/packer/1.0.0/packer_1.0.0_windows_386.zip",
- "hash": "445eae4ea9a1eaa42e62776c6917fd83c15f26df320afb77571e9c840152da3b"
- }
- },
- "bin": [
- "packer.exe"
- ],
- "checkver": {
- "url": "https://releases.hashicorp.com/packer/",
- "re": "packer_([\\d.]+)"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://releases.hashicorp.com/packer/$version/packer_$version_windows_amd64.zip"
- },
- "32bit": {
- "url": "https://releases.hashicorp.com/packer/$version/packer_$version_windows_386.zip"
- }
- },
- "hash": {
- "url": "$baseurl/packer_$version_SHA256SUMS"
- }
- }
-}
diff --git a/bucket/patch.json b/bucket/patch.json
deleted file mode 100644
index 938c505742..0000000000
--- a/bucket/patch.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "homepage": "http://www.mingw.org/wiki/MSYS",
- "version": "2.6.1",
- "url": [
- "https://sourceforge.net/projects/mingw/files/MSYS/Base/msys-core/msys-1.0.18-1/msysCORE-1.0.18-1-msys-1.0.18-bin.tar.lzma",
- "https://sourceforge.net/projects/mingw/files/MSYS/Extension/patch/patch-2.6.1-1/patch-2.6.1-1-msys-1.0.13-bin.tar.lzma"
- ],
- "hash": [
- "4e262a414f238773b311c8bb55a52e62743c06e0e55b319ca5b47e3e306464d5",
- "c8b7771304fb5e9fc33d8fca9045402f2e1bca055bf0b28127f3c3e85a254f67"
- ],
- "bin": "bin\\patch.exe"
-}
diff --git a/bucket/pciutils.json b/bucket/pciutils.json
deleted file mode 100644
index 8df4600e98..0000000000
--- a/bucket/pciutils.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "architecture": {
- "32bit": {
- "extract_dir": "pciutils-3.4.0-win32",
- "hash": "baba72451033904ff19072b091392caee1da75a4338cb5aff10c19e65621e340",
- "url": "https://eternallybored.org/misc/pciutils/releases/pciutils-3.4.0-win32.zip"
- },
- "64bit": {
- "extract_dir": "pciutils-3.4.0-win64",
- "hash": "d5a5201110643160ebd3cbe97461a5a978040806bed75172344860dbe9f2fbcb",
- "url": "https://eternallybored.org/misc/pciutils/releases/pciutils-3.4.0-win64.zip"
- }
- },
- "autoupdate": {
- "architecture": {
- "32bit": {
- "extract_dir": "pciutils-$version-win32",
- "url": "https://eternallybored.org/misc/pciutils/releases/pciutils-$version-win32.zip"
- },
- "64bit": {
- "extract_dir": "pciutils-$version-win64",
- "url": "https://eternallybored.org/misc/pciutils/releases/pciutils-$version-win64.zip"
- }
- }
- },
- "bin": [
- "lspci.exe",
- "setpci.exe"
- ],
- "checkver": "href=\"releases/pciutils-([\\d.]+)",
- "description": "Inspect and manipulate configuration of PCI devices",
- "homepage": "https://eternallybored.org/misc/pciutils/",
- "license": "GPL-2.0",
- "version": "3.4.0"
-}
diff --git a/bucket/pcregrep.json b/bucket/pcregrep.json
deleted file mode 100644
index 3c7d5d0ea1..0000000000
--- a/bucket/pcregrep.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "homepage": "http://pcre.org",
- "version": "10.20",
- "license": "BSD",
- "architecture": {
- "32bit": {
- "url": "https://github.com/rivy/PCRE/releases/download/10.20/pcre2grep-10.20-x32.zip",
- "hash": "a07c0d43132855bf350d85f71a9ee781d0e62721cd9053f1ff2894c52f4cfd85"
- },
- "64bit": {
- "url": "https://github.com/rivy/PCRE/releases/download/10.20/pcre2grep-10.20-x64.zip",
- "hash": "6b69d123b9e09e288f12e828f4a827e2bec59991e743802287c389fbbc99f54d"
- }
- },
- "bin": [
- "pcre2grep.exe",
- "pcre2test.exe",
- [
- "pcre2grep.exe",
- "pcregrep"
- ],
- [
- "pcre2test.exe",
- "pcretest"
- ]
- ],
- "checkver": {
- "github": "https://github.com/rivy/PCRE"
- }
-}
diff --git a/bucket/pdftk.json b/bucket/pdftk.json
deleted file mode 100644
index 66c6ca5e83..0000000000
--- a/bucket/pdftk.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "homepage": "https://www.pdflabs.com/tools/pdftk-server/",
- "version": "2.02",
- "license": "GPL",
- "url": "https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/pdftk_server-2.02-win-setup.exe",
- "hash": "cc8f6a43fc91026bb739ad0ad9a124c24750d6127662fb3638ec1d44403aabd2",
- "innosetup": true,
- "bin": "bin\\pdftk.exe",
- "checkver": "pdftk_server-([\\d.]+)-win-setup.exe"
-}
diff --git a/bucket/perl.json b/bucket/perl.json
deleted file mode 100644
index a87f66e996..0000000000
--- a/bucket/perl.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "homepage": "http://strawberryperl.com",
- "version": "5.26.0.1",
- "license": "GPL",
- "architecture": {
- "32bit": {
- "url": "http://strawberryperl.com/download/5.26.0.1/strawberry-perl-5.26.0.1-32bit-portable.zip",
- "hash": "e4f7530dc546e28684a0d0470e4ff47f16342c598b71f4014cbff77d2b3927b3"
- },
- "64bit": {
- "url": "http://strawberryperl.com/download/5.26.0.1/strawberry-perl-5.26.0.1-64bit-portable.zip",
- "hash": "17feff703fc6d0289efc1b1ba7c1309ac53a2efcdced1ddd3f00d7bd87913056"
- }
- },
- "post_install": "
- # enable standard idiomatic access to user's home directory
- ## remove HomeDir section from portable.perl (disables Portable.pm override of File::HomeDir)
- ## NOTE: conversion to byte[] avoids adding an extra trailing newline to the output file
- [byte[]][char[]]((Get-Content -raw $dir\\portable.perl) -replace \"(?ms)^HomeDir:.*?^(?=\\S)\",\"\") | Set-Content $dir\\portable.perl -encoding byte
- ",
- "env_add_path": [
- "perl\\site\\bin",
- "perl\\bin",
- "c\\bin"
- ],
- "checkver": "Recommended version:
\\s* $null }
- '' > $profile
- }
-
- $text = get-content $profile
- if (($text | sls 'pester') -eq $null) {
- $new_profile = @($text) + $import
- $new_profile > $profile
- success 'pester added to powershell profile.'
- }
- } else { warn 'no powershell profile found. the pester module will not be imported each session.' }
-
- 'importing pester for current session...'
- iex \"$import\"
- ",
- "checkver": "github",
- "autoupdate": {
- "url": "https://github.com/pester/pester/archive/$version.tar.gz",
- "extract_dir": "pester-$version"
- }
-}
diff --git a/bucket/phantomjs.json b/bucket/phantomjs.json
deleted file mode 100644
index f304c2551b..0000000000
--- a/bucket/phantomjs.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "homepage": "http://phantomjs.org/",
- "version": "2.1.1",
- "license": "BSD",
- "hash": "d9fb05623d6b26d3654d008eab3adafd1f6350433dfd16138c46161f42c7dcc8",
- "url": "https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-windows.zip",
- "extract_dir": "phantomjs-2.1.1-windows",
- "bin": "bin\\phantomjs.exe",
- "checkver": {
- "url": "http://phantomjs.org/download.html",
- "re": "phantomjs-([\\d.]+)-windows.zip"
- },
- "autoupdate": {
- "url": "https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-$version-windows.zip"
- }
-}
diff --git a/bucket/php-nts.json b/bucket/php-nts.json
deleted file mode 100644
index 8f0785ca11..0000000000
--- a/bucket/php-nts.json
+++ /dev/null
@@ -1,66 +0,0 @@
-{
- "homepage": "http://windows.php.net",
- "version": "7.1.5",
- "license": "http://www.php.net/license/",
- "architecture": {
- "64bit": {
- "url": "http://windows.php.net/downloads/releases/php-7.1.5-nts-Win32-VC14-x64.zip",
- "hash": "sha1:1eb36b0cec50aae4a3935db986ea6c38656fdd06"
- },
- "32bit": {
- "url": "http://windows.php.net/downloads/releases/php-7.1.5-nts-Win32-VC14-x86.zip",
- "hash": "sha1:cc9c1db26dd67f94173f92a6fce2a22bbefe0fcd"
- }
- },
- "bin": [
- "php.exe",
- "php-cgi.exe"
- ],
- "persist": [
- "cli",
- [
- "php.ini-production",
- "cli\\php.ini"
- ]
- ],
- "env_set": {
- "PHP_INI_SCAN_DIR": "$dir\\cli;$dir\\cli\\conf.d;"
- },
- "post_install": "
-# Copy ini scan dir from old location before persistent update
-if ((Test-Path \"$dir\\..\\conf\") -and !(Test-Path \"$dir\\cli\\conf.d\")) {
- Write-Host -ForegroundColor Cyan \"We are moving your php configuration to $dir\\cli\\conf.d\"
- Move-Item \"$dir\\..\\conf\" \"$dir\\cli\\conf.d\"
-}
-
-# Create directory for custom PHP configuration
-if (!(Test-Path \"$dir\\cli\\conf.d\")) {
- (New-Item -Type directory \"$dir\\cli\\conf.d\") | Out-Null
-}
-
-# Enable extensions to be found in installation-relative folder (the default is to search C:/php)
-(gc \"$dir\\cli\\php.ini\") | % { $_ -replace '; extension_dir = \"ext\"', 'extension_dir = \"ext\"' } | sc \"$dir\\cli\\php.ini\"
-",
- "checkver": {
- "url": "http://windows.php.net/download/",
- "re": ".*?\\(([\\d.]+)\\)
"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "http://windows.php.net/downloads/releases/php-$version-nts-Win32-VC14-x64.zip"
- },
- "32bit": {
- "url": "http://windows.php.net/downloads/releases/php-$version-nts-Win32-VC14-x86.zip"
- }
- },
- "hash": {
- "url": "$baseurl/sha1sum.txt"
- }
- },
- "suggest": {
- "vcredist": [
- "extras/vcredist2017"
- ]
- }
-}
diff --git a/bucket/php.json b/bucket/php.json
deleted file mode 100644
index 7332508141..0000000000
--- a/bucket/php.json
+++ /dev/null
@@ -1,66 +0,0 @@
-{
- "homepage": "http://windows.php.net",
- "version": "7.1.5",
- "license": "http://www.php.net/license/",
- "architecture": {
- "64bit": {
- "url": "http://windows.php.net/downloads/releases/php-7.1.5-Win32-VC14-x64.zip",
- "hash": "sha1:fbb252cc617fe6d64fc14e9cb8a75639b51bb800"
- },
- "32bit": {
- "url": "http://windows.php.net/downloads/releases/php-7.1.5-Win32-VC14-x86.zip",
- "hash": "sha1:615623145a671589b8012d4f0e9f26c9c955a773"
- }
- },
- "bin": [
- "php.exe",
- "php-cgi.exe"
- ],
- "persist": [
- "cli",
- [
- "php.ini-production",
- "cli\\php.ini"
- ]
- ],
- "env_set": {
- "PHP_INI_SCAN_DIR": "$dir\\cli;$dir\\cli\\conf.d;"
- },
- "post_install": "
-# Copy ini scan dir from old location before persistent update
-if ((Test-Path \"$dir\\..\\conf\") -and !(Test-Path \"$dir\\cli\\conf.d\")) {
- Write-Host -ForegroundColor Cyan \"We are moving your php configuration to $dir\\cli\\conf.d\"
- Move-Item \"$dir\\..\\conf\" \"$dir\\cli\\conf.d\"
-}
-
-# Create directory for custom PHP configuration
-if (!(Test-Path \"$dir\\cli\\conf.d\")) {
- (New-Item -Type directory \"$dir\\cli\\conf.d\") | Out-Null
-}
-
-# Enable extensions to be found in installation-relative folder (the default is to search C:/php)
-(gc \"$dir\\cli\\php.ini\") | % { $_ -replace '; extension_dir = \"ext\"', 'extension_dir = \"ext\"' } | sc \"$dir\\cli\\php.ini\"
-",
- "checkver": {
- "url": "http://windows.php.net/download/",
- "re": ".*?\\(([\\d.]+)\\)
"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "http://windows.php.net/downloads/releases/php-$version-Win32-VC14-x64.zip"
- },
- "32bit": {
- "url": "http://windows.php.net/downloads/releases/php-$version-Win32-VC14-x86.zip"
- }
- },
- "hash": {
- "url": "$baseurl/sha1sum.txt"
- }
- },
- "suggest": {
- "vcredist": [
- "extras/vcredist2017"
- ]
- }
-}
diff --git a/bucket/pkg-config.json b/bucket/pkg-config.json
deleted file mode 100644
index 46057e62ed..0000000000
--- a/bucket/pkg-config.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "version": "0.26-1",
- "license": "GNU GPL",
- "url": [
- "http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/pkg-config_0.26-1_win32.zip",
- "http://ftp.gnome.org/pub/gnome/binaries/win32/glib/2.28/glib_2.28.8-1_win32.zip",
- "http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/gettext-runtime_0.18.1.1-2_win32.zip"
- ],
- "homepage": "http://www.freedesktop.org/wiki/Software/pkg-config/",
- "hash": [
- "e919821da1a61af45ac9d924914bb72d92ba9ead956c82b9d89128b1b90d37c3",
- "0d485a8dd57494944128ac19b5b8dd52d6140eb16f102a43c835f060aaa49a19",
- "4c313b74dd63b81604168f1a8e714e1292e778f1ec0cb5bb85a2bcd9e8842cba"
- ],
- "extract_dir": [
- "bin",
- "bin",
- "bin"
- ],
- "bin": "pkg-config.exe"
-}
diff --git a/bucket/pngcrush.json b/bucket/pngcrush.json
deleted file mode 100644
index e7a735fa55..0000000000
--- a/bucket/pngcrush.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "homepage": "http://pmt.sourceforge.net/pngcrush/",
- "version": "1.8.11",
- "license": "libpng",
- "architecture": {
- "64bit": {
- "url": "https://sourceforge.net/projects/pmt/files/pngcrush-executables/1.8.11/pngcrush_1_8_11_w64.exe#/pngcrush.exe",
- "hash": "196f868188f2393dbea39d331402c7b0debc5192e30cd0185fd32c0739bfdb65"
- },
- "32bit": {
- "url": "https://sourceforge.net/projects/pmt/files/pngcrush-executables/1.8.11/pngcrush_1_8_11_w32.exe#/pngcrush.exe",
- "hash": "5fc06c1ba24aca793e7ef648b6dd3c5b2572e235e1ff13c64c23810adfdc2f50"
- }
- },
- "bin": [
- "pngcrush.exe"
- ],
- "checkver": {
- "url": "https://sourceforge.net/projects/pmt/files/pngcrush-executables/",
- "re": "title=\"([0-9\\.]+)\""
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://sourceforge.net/projects/pmt/files/pngcrush-executables/$version/pngcrush_$underscoreVersion_w64.exe#/pngcrush.exe"
- },
- "32bit": {
- "url": "https://sourceforge.net/projects/pmt/files/pngcrush-executables/$version/pngcrush_$underscoreVersion_w32.exe#/pngcrush.exe"
- }
- }
- }
-}
diff --git a/bucket/poppler.json b/bucket/poppler.json
deleted file mode 100644
index 34c3ef70a2..0000000000
--- a/bucket/poppler.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "autoupdate": {
- "url": "http://blog.alivate.com.au/wp-content/uploads/$matchDate/poppler-$version_x86.7z"
- },
- "bin": [
- "bin/pdfdetach.exe",
- "bin/pdffonts.exe",
- "bin/pdfimages.exe",
- "bin/pdfinfo.exe",
- "bin/pdfseparate.exe",
- "bin/pdftocairo.exe",
- "bin/pdftohtml.exe",
- "bin/pdftoppm.exe",
- "bin/pdftops.exe",
- "bin/pdftotext.exe",
- "bin/pdfunite.exe"
- ],
- "checkver": "Latest.*uploads/(?\\d{4}/\\d{2})/poppler-(?[\\d.]+)_x86.7z",
- "description": "PDF rendering library",
- "extract_dir": "poppler-0.51",
- "hash": "8c027037355f11d16fde2fe34823006c142c7460bd64a37da7b6b23327a15f13",
- "homepage": "http://blog.alivate.com.au/poppler-windows/",
- "license": "GPL-3.0",
- "url": "http://blog.alivate.com.au/wp-content/uploads/2017/01/poppler-0.51_x86.7z",
- "version": "0.51"
-}
diff --git a/bucket/postgresql.json b/bucket/postgresql.json
deleted file mode 100644
index 049a0986e4..0000000000
--- a/bucket/postgresql.json
+++ /dev/null
@@ -1,76 +0,0 @@
-{
- "homepage": "https://www.postgresql.org/",
- "version": "9.6.3",
- "license": "https://www.postgresql.org/about/licence/",
- "architecture": {
- "64bit": {
- "url": "https://get.enterprisedb.com/postgresql/postgresql-9.6.3-1-windows-x64-binaries.zip",
- "hash": "18b23b5811ed94e5653c1dc311d49e2ce8e93b9d45e33f4318d4b744fb758ee3"
- },
- "32bit": {
- "url": "https://get.enterprisedb.com/postgresql/postgresql-9.6.3-1-windows-binaries.zip",
- "hash": "675e360c78c96e498b3415258791ba2c8e3eb8d157f10b0f8189f20d0749417a"
- }
- },
- "extract_dir": "pgsql",
- "bin": [
- "bin\\clusterdb.exe",
- "bin\\createdb.exe",
- "bin\\createlang.exe",
- "bin\\createuser.exe",
- "bin\\dropdb.exe",
- "bin\\droplang.exe",
- "bin\\dropuser.exe",
- "bin\\ecpg.exe",
- "bin\\initdb.exe",
- "bin\\isolationtester.exe",
- "bin\\oid2name.exe",
- "bin\\pg_archivecleanup.exe",
- "bin\\pg_basebackup.exe",
- "bin\\pg_config.exe",
- "bin\\pg_controldata.exe",
- "bin\\pg_ctl.exe",
- "bin\\pg_dump.exe",
- "bin\\pg_dumpall.exe",
- "bin\\pg_isolation_regress.exe",
- "bin\\pg_isready.exe",
- "bin\\pg_receivexlog.exe",
- "bin\\pg_regress.exe",
- "bin\\pg_regress_ecpg.exe",
- "bin\\pg_resetxlog.exe",
- "bin\\pg_restore.exe",
- "bin\\pg_rewind.exe",
- "bin\\pg_standby.exe",
- "bin\\pg_test_fsync.exe",
- "bin\\pg_test_timing.exe",
- "bin\\pg_upgrade.exe",
- "bin\\pg_xlogdump.exe",
- "pgAdmin 4\\bin\\pgAdmin4.exe",
- [
- "pgAdmin 4\\bin\\pgAdmin4.exe",
- "pgadmin"
- ],
- "bin\\pgbench.exe",
- "bin\\postgres.exe",
- "bin\\psql.exe",
- "bin\\reindexdb.exe",
- "bin\\stackbuilder.exe",
- "bin\\vacuumdb.exe",
- "bin\\vacuumlo.exe",
- "bin\\zic.exe"
- ],
- "checkver": {
- "url": "https://www.enterprisedb.com/products-services-training/pgbindownload",
- "re": "Version ([\\d.]+)"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://get.enterprisedb.com/postgresql/postgresql-$version-1-windows-x64-binaries.zip"
- },
- "32bit": {
- "url": "https://get.enterprisedb.com/postgresql/postgresql-$version-1-windows-binaries.zip"
- }
- }
- }
-}
diff --git a/bucket/premake4.json b/bucket/premake4.json
deleted file mode 100644
index 35b6f5c96e..0000000000
--- a/bucket/premake4.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "homepage": "https://premake.github.io/download.html",
- "version": "4.4-b5",
- "license": "BSD 3-Clause",
- "url": "https://sourceforge.net/projects/premake/files/Premake/4.4/premake-4.4-beta5-windows.zip",
- "hash": "09614c122156617a2b7973cc9f686daa32e64e3e7335d38db887cfb8f6a8574d",
- "bin": [
- "premake4.exe"
- ]
-}
diff --git a/bucket/premake5.json b/bucket/premake5.json
deleted file mode 100644
index c5a4fa5735..0000000000
--- a/bucket/premake5.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "homepage": "https://premake.github.io/",
- "version": "5.0.0-alpha11",
- "license": "BSD 3-Clause",
- "url": "https://github.com/premake/premake-core/releases/download/v5.0.0-alpha11/premake-5.0.0-alpha11-windows.zip",
- "hash": "f37b9c86edf6cb790ea9ada87be9951638705be5a8594c5426d4de14986d2440",
- "bin": [
- "premake5.exe"
- ],
- "checkver": {
- "url": "https://github.com/premake/premake-core/releases/latest",
- "re": "/releases/tag/v(5[0-9.]+-?(alpha|beta)?([0-9.]+)?)"
- },
- "autoupdate": {
- "url": "https://github.com/premake/premake-core/releases/download/v$version/premake-$version-windows.zip"
- }
-}
diff --git a/bucket/psake.json b/bucket/psake.json
deleted file mode 100644
index 974c7d5322..0000000000
--- a/bucket/psake.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "version": "4.6.0",
- "url": "http://nuget.org/api/v2/package/psake/4.6.0#/dl.7z",
- "homepage": "https://github.com/psake/psake",
- "hash": "7086265CAC31078542D41F128AEA7E0F734CBD56511A322DD1A183B96849AD93",
- "bin": "psake.ps1",
- "extract_dir": "tools"
-}
diff --git a/bucket/psgithub.json b/bucket/psgithub.json
deleted file mode 100644
index 589bc7f5eb..0000000000
--- a/bucket/psgithub.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "version": "2017.01.22",
- "url": "https://github.com/pcgeek86/PSGitHub/archive/3e05a8faa50106c4f339696b0b08b065ae96bb7d.zip",
- "hash": "6f34c7041b1b8262fddf0d66cd7a165bbe78a0d40701a682b8ddd8c0d20f74b0",
- "extract_dir": "PSGitHub-3e05a8faa50106c4f339696b0b08b065ae96bb7d",
- "psmodule": {
- "name": "PSGitHub"
- }
-}
diff --git a/bucket/pshazz.json b/bucket/pshazz.json
deleted file mode 100644
index 9001d23635..0000000000
--- a/bucket/pshazz.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "version": "0.2017.03.22",
- "url": "https://github.com/lukesampson/pshazz/archive/fe10c46c35c0b50db962ea7a454dc646964200bb.zip",
- "extract_dir": "pshazz-fe10c46c35c0b50db962ea7a454dc646964200bb",
- "hash": "FB8BA76AACA276B507AF4524F59B2A30457283BE6541E7C87FEF3E8978AD0C8C",
- "bin": [
- "bin\\pshazz.ps1",
- "libexec\\askpass.exe"
- ],
- "installer": {
- "file": "bin\\install.ps1"
- }
-}
diff --git a/bucket/pt.json b/bucket/pt.json
deleted file mode 100644
index 1f2759a9c6..0000000000
--- a/bucket/pt.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "homepage": "https://github.com/monochromegane/the_platinum_searcher",
- "license": "MIT",
- "version": "2.1.5",
- "architecture": {
- "64bit": {
- "url": "https://github.com/monochromegane/the_platinum_searcher/releases/download/v2.1.5/pt_windows_amd64.zip",
- "hash": "0f02db8eba977bc50b743ed18b4ba8efb769b7ade5f8a5c84e869d44117924bb"
- },
- "32bit": {
- "url": "https://github.com/monochromegane/the_platinum_searcher/releases/download/v2.1.5/pt_windows_386.zip",
- "hash": "5756ebf64d3d65aa4ef7bb176f5170ea8abfd5e23bf349d7c64a408b2201732b"
- }
- },
- "bin": "pt.exe",
- "checkver": {
- "url": "https://github.com/monochromegane/the_platinum_searcher/releases/latest",
- "re": "/releases/tag/v([\\d.]+)"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://github.com/monochromegane/the_platinum_searcher/releases/download/v$version/pt_windows_amd64.zip"
- },
- "32bit": {
- "url": "https://github.com/monochromegane/the_platinum_searcher/releases/download/v$version/pt_windows_386.zip"
- }
- }
- }
-}
diff --git a/bucket/puppet.json b/bucket/puppet.json
deleted file mode 100644
index 01648dbc77..0000000000
--- a/bucket/puppet.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "homepage": "http://puppetlabs.com",
- "version": "3.8.7",
- "architecture": {
- "64bit": {
- "url": "https://downloads.puppetlabs.com/windows/puppet-3.8.7-x64.msi",
- "hash": "87b7fd29fb2e63fcc47352e8a662835b0329448fe017eb25be4329ef84f1914e"
- },
- "32bit": {
- "url": "https://downloads.puppetlabs.com/windows/puppet-3.8.7.msi",
- "hash": "6cddbc4341d285766d4b2ab9c1d5008036c5ea702146bc94423ca945160bc9ce"
- }
- },
- "bin": [
- "Puppet Labs/Puppet/bin\\facter.bat",
- "Puppet Labs/Puppet/bin\\hiera.bat",
- "Puppet Labs/Puppet/bin\\puppet.bat"
- ],
- "checkver": {
- "url": "https://downloads.puppetlabs.com/windows/?C=N;O=D",
- "re": "puppet-([\\d.]+)-x64.msi"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://downloads.puppetlabs.com/windows/puppet-$version-x64.msi"
- },
- "32bit": {
- "url": "https://downloads.puppetlabs.com/windows/puppet-$version.msi"
- }
- }
- }
-}
diff --git a/bucket/python-exp.json b/bucket/python-exp.json
deleted file mode 100644
index 51ba090088..0000000000
--- a/bucket/python-exp.json
+++ /dev/null
@@ -1,120 +0,0 @@
-{
- "homepage": "https://www.python.org/",
- "license": "https://docs.python.org/3/license.html",
- "version": "3.5.2",
- "architecture": {
- "64bit": {
- "url": [
- "https://www.python.org/ftp/python/3.5.2/amd64/core.msi",
- "https://www.python.org/ftp/python/3.5.2/amd64/core_d.msi",
- "https://www.python.org/ftp/python/3.5.2/amd64/core_pdb.msi",
- "https://www.python.org/ftp/python/3.5.2/amd64/dev.msi",
- "https://www.python.org/ftp/python/3.5.2/amd64/dev_d.msi",
- "https://www.python.org/ftp/python/3.5.2/amd64/doc.msi",
- "https://www.python.org/ftp/python/3.5.2/amd64/exe.msi",
- "https://www.python.org/ftp/python/3.5.2/amd64/exe_d.msi",
- "https://www.python.org/ftp/python/3.5.2/amd64/exe_pdb.msi",
- "https://www.python.org/ftp/python/3.5.2/amd64/lib.msi",
- "https://www.python.org/ftp/python/3.5.2/amd64/lib_d.msi",
- "https://www.python.org/ftp/python/3.5.2/amd64/lib_pdb.msi",
- "https://www.python.org/ftp/python/3.5.2/amd64/tcltk.msi",
- "https://www.python.org/ftp/python/3.5.2/amd64/tcltk_d.msi",
- "https://www.python.org/ftp/python/3.5.2/amd64/tcltk_pdb.msi",
- "https://www.python.org/ftp/python/3.5.2/amd64/test.msi",
- "https://www.python.org/ftp/python/3.5.2/amd64/test_d.msi",
- "https://www.python.org/ftp/python/3.5.2/amd64/test_pdb.msi",
- "https://www.python.org/ftp/python/3.5.2/amd64/tools.msi"
- ],
- "hash": [
- "d475e03012035d5cd6339b7e85fc2eac3b1952122e634c51c70828b01ccbfaa4",
- "69cd9e07f4e358d2e7a1e0e28fdf86df9d744269de7aa2484367b7819a0915f1",
- "aac91845c7a619821539092fb70465ca14f014290baa0cfe0548289816b86218",
- "dcd95fe9cdabcaeb389b7c3a0039520228b6e7222bdfa3895e1a7dc353e11fbe",
- "833e6a144f0a4fbadc218efd26efd0682b2b6508ed2a7ce98883d2cd7264ffbe",
- "ca822c1d4d761640cd5c246dd2ebd640216793a174c700c93005d2e47715f119",
- "84edf3bb2617f0f9b12ceb6a84a20e1c4659486a77b2e99f5632e805a4fbe430",
- "848640194435d2f4a6355e7849a5095f72eb3d2945a9a903a5f2c92041f0948d",
- "dba5c507fabb2b038038ad809e305bf53ea75d5e23ca314ce79aa6beaad7134c",
- "7e5d5f005ac774ff5ff10b5da50043effd3b02b82f7ebc858f3017abb46b3ba7",
- "d4b438debe65fb6775e95140cb620d0ba7889146d1a4a3d338484dc5df40a217",
- "f150660ce484f448bd524dee91a5a81cf6cfd0bcbdeecf23fe280a85cd486633",
- "1e1d4df1ad2f956fb98cc45d1c3767a53b61e8ce8911e279820e3ae9843a74d5",
- "b17a05cd1983bcac5560317fda0de6672e7a23d9e5e7ac702f32c96b19b4875c",
- "9bd4349b5cab68934cea3cee64e767fa2a15e73fc82d8dec52d55369807f32c6",
- "ba4a532790f3867dc7e5840332c57ca58bae63a0e38e54ae7ceed4cd1191abc2",
- "a27387d6ad010a3934e4e455830f505dece9ebf974a0e7b4effb61f3f6abc98a",
- "439d0b7eb9a109a233714575cb739d59e75c9afbda717bd5e9248788fd467cb5",
- "94195cbfad4762bec043be180336d44beddc0c7b2860a5c99ca29622995d44db"
- ]
- },
- "32bit": {
- "url": [
- "https://www.python.org/ftp/python/3.5.2/win32/core.msi",
- "https://www.python.org/ftp/python/3.5.2/win32/core_d.msi",
- "https://www.python.org/ftp/python/3.5.2/win32/core_pdb.msi",
- "https://www.python.org/ftp/python/3.5.2/win32/dev.msi",
- "https://www.python.org/ftp/python/3.5.2/win32/dev_d.msi",
- "https://www.python.org/ftp/python/3.5.2/win32/doc.msi",
- "https://www.python.org/ftp/python/3.5.2/win32/exe.msi",
- "https://www.python.org/ftp/python/3.5.2/win32/exe_d.msi",
- "https://www.python.org/ftp/python/3.5.2/win32/exe_pdb.msi",
- "https://www.python.org/ftp/python/3.5.2/win32/lib.msi",
- "https://www.python.org/ftp/python/3.5.2/win32/lib_d.msi",
- "https://www.python.org/ftp/python/3.5.2/win32/lib_pdb.msi",
- "https://www.python.org/ftp/python/3.5.2/win32/tcltk.msi",
- "https://www.python.org/ftp/python/3.5.2/win32/tcltk_d.msi",
- "https://www.python.org/ftp/python/3.5.2/win32/tcltk_pdb.msi",
- "https://www.python.org/ftp/python/3.5.2/win32/test.msi",
- "https://www.python.org/ftp/python/3.5.2/win32/test_d.msi",
- "https://www.python.org/ftp/python/3.5.2/win32/test_pdb.msi",
- "https://www.python.org/ftp/python/3.5.2/win32/tools.msi"
- ],
- "hash": [
- "5cd5a31ad787c60bae8689e2b044595f34b64a905ad0ea7616b45b27e80d3929",
- "9a65fd83cecb86ae9a3bbb559c89d167614b8fd100c6920cb523742f3ec9738a",
- "282f842c1ed0e3b416f21e0ad55a23bac8def8101eabd32936c5d7511f14ec70",
- "fe85794493301fe30ea4697b34a1ecf90987fe74dd194e1e98b86f073df2dca2",
- "a9a8424cb6af47389b38b1a8f2bdc0b0069b96182482e82d8e6a0064e8a582c4",
- "98d852f125ae888ebe34dfd9b9c6a0037746499f139a234747943e981969100f",
- "0f46e91bc3aec77190352bfa8e5f5447428d956b9a60ccd363e66ad60d19edc8",
- "1ee6ce5521886e0e089cece5897677d4abcdef10ef468c9c95d2bf16635f6718",
- "c414f015e75d04f75b7f5554617f376d556ca546a9e0df36679b4c5741750df8",
- "c7f1bc380c749ee211e84f454cc77f564468e5690eea2ad692ba52a24ca7f4bd",
- "989a68feb6702f75ed461237fef5abacd9487947ee05cd3a1f6ae700efefa050",
- "ef646287060e27554b8ce5090786b1fcb7a46984e82f54f3721bdd9620e7d34d",
- "692859f84d22cee8dfc7c6a333190d541b488e583098e1e0f9be78b8b8c65446",
- "7d85422a55828b88c000c058953380b0d24bfe0dc866d7ecc58f068f62849ddb",
- "600b89ecc08e46f7c85aff2da8f1db5adac9610382084538c3937537cd5cac79",
- "1cf142d5f463403eee633734e9d8db1be1bb1968d0f3c7dbb5f736d381e5899b",
- "aed7476a1ed4d59b70ee68376f47ec5372abbf5bd33a34e9190eeba6e2dd36e9",
- "22f3dc47003c320c71c0967b7b8ab3fb032d005f8b78116b49644a3c1001c97e",
- "ea5af6b1b1bec740709d2dcc00db78aaccdb3f4a83eafc46df3bf98cc6535e3b"
- ]
- }
- },
- "bin": [
- "python.exe",
- "pythonw.exe",
- [
- "python.exe",
- "python3"
- ]
- ],
- "post_install": "
- python -m ensurepip; cp (gcm pip3).path \"$(split-path (gcm pip3).path)/pip.exe\"
- $create_reg = {
- param($path, $value)
- $reg_base = \"Registry::HKEY_CURRENT_USER\\Software\"
- new-item -path \"$reg_base\\$path\" -force | out-null
- new-itemproperty -path \"$reg_base\\$path\" `
- -name \"(Default)\" -value \"$value\" -force | out-null
- }
- $create_reg.Invoke(\"Classes\\Python.File\\shell\\open\\command\", \"`\"$dir\\py.exe`\" `\"%1`\" %*\")
- $create_reg.Invoke(\"Classes\\.py\", \"Python.File\")
- $create_reg.Invoke(\"Python\\PythonCore\\3.5\\InstallPath\", \"$dir\")
- $create_reg.Invoke(\"Python\\PythonCore\\3.5\\PythonPath\", \"$dir;$dir\\Lib\\;$dir\\DLLs\\\")",
- "env_add_path": [
- "scripts"
- ],
- "checkver": "Latest: Python ([\\d.]+) - .*
"
-}
diff --git a/bucket/python.json b/bucket/python.json
deleted file mode 100644
index 33afda8633..0000000000
--- a/bucket/python.json
+++ /dev/null
@@ -1,56 +0,0 @@
-{
- "homepage": "https://www.python.org/",
- "license": "https://docs.python.org/3/license.html",
- "version": "3.6.1",
- "architecture": {
- "64bit": {
- "url": "https://www.python.org/ftp/python/3.6.1/python-3.6.1-amd64.exe#/py3.exe",
- "hash": "591922fbf5c4234b766dd672e539cba3d9a158e028e3c85c76bfec6ede56ded8"
- },
- "32bit": {
- "url": "https://www.python.org/ftp/python/3.6.1/python-3.6.1.exe#/py3.exe",
- "hash": "15dbc083264945ad1dcef8b0b712da41362f816f614acb60989541d8f426d845"
- }
- },
- "pre_install": "copy-item $dir\\py3.exe $dir\\uninstall.exe",
- "installer": {
- "args": [
- "/quiet",
- "InstallAllUsers=$(@{$true=1;$false=0}[$global])",
- "TargetDir=$dir",
- "AssociateFiles=0",
- "Shortcuts=0",
- "InstallLauncherAllUsers=$(@{$true=1;$false=0}[$global])"
- ]
- },
- "uninstaller": {
- "file": "uninstall.exe",
- "args": [
- "/uninstall",
- "/quiet",
- "InstallAllUsers=0"
- ]
- },
- "bin": [
- "python.exe",
- "pythonw.exe",
- [
- "python.exe",
- "python3"
- ]
- ],
- "env_add_path": [
- "scripts"
- ],
- "checkver": "Latest: Python ([\\d.]+) - .*
",
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://www.python.org/ftp/python/$version/python-$version-amd64.exe#/py3.exe"
- },
- "32bit": {
- "url": "https://www.python.org/ftp/python/$version/python-$version.exe#/py3.exe"
- }
- }
- }
-}
diff --git a/bucket/r.json b/bucket/r.json
deleted file mode 100644
index d9b5842592..0000000000
--- a/bucket/r.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "homepage": "https://www.r-project.org",
- "version": "3.4.0",
- "license": "GPL2",
- "architecture": {
- "64bit": {
- "url": "https://cran.rstudio.com/bin/windows/base/R-3.4.0-win.exe",
- "hash": "0064cc4c04b9935210f6b0a0d9b6e3bb41b022e279628549003cc95f26faddbe",
- "pre_install": "copy-item -recurse $dir\\bin\\x64 $dir\\bin\\curr_arch"
- },
- "32bit": {
- "url": "https://cran.rstudio.com/bin/windows/base/R-3.4.0-win.exe",
- "hash": "0064cc4c04b9935210f6b0a0d9b6e3bb41b022e279628549003cc95f26faddbe",
- "pre_install": "copy-item -recurse $dir\\bin\\i386 $dir\\bin\\curr_arch"
- }
- },
- "innosetup": true,
- "bin": [
- "bin\\curr_arch\\r.exe",
- "bin\\curr_arch\\rterm.exe",
- "bin\\curr_arch\\rscript.exe"
- ],
- "notes": "You'll need to type 'r.ps1' or 'r.cmd' to run R, because in Powershell 'r' runs the last command. Alternatively 'rterm' can be used to start the interactive R terminal session.
-
-You can remove Powershell's 'r' command with:
- rm alias:\\r
-
-... but this only affects your current session: if you'd like to remove it for all future sessions you need to add the command above to your Powershell profile.
-
-Annoying, right?! You might want to check out Pshazz (scoop install pshazz)--this has a plugin to remove some crazy aliases from Powershell, as well as many other improvements.
-",
- "checkver": {
- "url": "https://cran.rstudio.com/bin/windows/base/",
- "re": "R-([\\d.]+)"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://cran.rstudio.com/bin/windows/base/R-$version-win.exe"
- },
- "32bit": {
- "url": "https://cran.rstudio.com/bin/windows/base/R-$version-win.exe"
- }
- }
- }
-}
diff --git a/bucket/racket.json b/bucket/racket.json
deleted file mode 100644
index d7356aafb8..0000000000
--- a/bucket/racket.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "version": "6.9",
- "homepage": "https://racket-lang.org",
- "license": "LGPL",
- "architecture": {
- "64bit": {
- "url": "https://mirror.racket-lang.org/installers/6.9/racket-6.9-x86_64-win32.exe#/dl.7z",
- "hash": "023c6fe241657ab62bc02137284552cad39a6197bb6b47eb615d3cb9534436d9"
- },
- "32bit": {
- "url": "https://mirror.racket-lang.org/installers/6.9/racket-6.9-i386-win32.exe#/dl.7z",
- "hash": "3af77dab2746150cfca9ac98cd0c049fe978f6a105c7b1a6380dd69fe7097c84"
- }
- },
- "bin": [
- "racket.exe",
- "raco.exe"
- ],
- "shortcuts": [
- [
- "GRacket.exe",
- "GRacket"
- ],
- [
- "DrRacket.exe",
- "DrRacket"
- ]
- ],
- "checkver": {
- "url": "https://download.racket-lang.org/",
- "re": "Version ([\\d.]+)"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://mirror.racket-lang.org/installers/$version/racket-$version-x86_64-win32.exe#/dl.7z"
- },
- "32bit": {
- "url": "https://mirror.racket-lang.org/installers/$version/racket-$version-i386-win32.exe#/dl.7z"
- }
- }
- }
-}
diff --git a/bucket/radare2.json b/bucket/radare2.json
deleted file mode 100644
index dd4fbf2645..0000000000
--- a/bucket/radare2.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "version": "1.5.0",
- "license": "GPL2",
- "homepage": "https://www.radare.org/r/",
- "architecture": {
- "64bit": {
- "url": "http://cloud.radare.org/get/1.5.0/radare2-w64-1.5.0.zip",
- "hash": "5f2baec31d94ae216730c2dd6269607caad08ccb5812cafd5ee346cd6439e492",
- "extract_dir": "radare2-w64-1.5.0"
- }
- },
- "bin": [
- "rabin2.exe",
- "radare2.exe",
- "radiff2.exe",
- "rafind2.exe",
- "ragg2.exe",
- "rahash2.exe",
- "rarun2.exe",
- "rasm2.exe",
- "rax2.exe"
- ],
- "checkver": {
- "github": "https://github.com/radare/radare2"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "http://cloud.radare.org/get/$version/radare2-w64-$version.zip",
- "extract_dir": "radare2-w64-$version"
- }
- }
- }
-}
diff --git a/bucket/rancher-compose.json b/bucket/rancher-compose.json
deleted file mode 100644
index 0130452188..0000000000
--- a/bucket/rancher-compose.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "homepage": "https://rancher.com/",
- "version": "0.12.5",
- "architecture": {
- "32bit": {
- "url": "https://github.com/rancher/rancher-compose/releases/download/v0.12.5/rancher-compose-windows-386-v0.12.5.zip",
- "hash": "cc2d9c8a8389e80544aa11737af38ac34bb1b4dc803c8c25b027721216e48520"
- },
- "64bit": {
- "url": "https://github.com/rancher/rancher-compose/releases/download/v0.12.5/rancher-compose-windows-amd64-v0.12.5.zip",
- "hash": "465e651c5fedcdd91417a7e25bcab351c9e99732192263afbcb91496138ef7d9"
- }
- },
- "license": "Apache 2.0",
- "extract_dir": "rancher-compose-v0.12.5",
- "bin": [
- "rancher-compose.exe"
- ],
- "checkver": {
- "github": "https://github.com/rancher/rancher-compose"
- },
- "autoupdate": {
- "architecture": {
- "32bit": {
- "url": "https://github.com/rancher/rancher-compose/releases/download/v$version/rancher-compose-windows-386-v$version.zip"
- },
- "64bit": {
- "url": "https://github.com/rancher/rancher-compose/releases/download/v$version/rancher-compose-windows-amd64-v$version.zip"
- }
- },
- "extract_dir": "rancher-compose-v$version"
- }
-}
diff --git a/bucket/redis.json b/bucket/redis.json
deleted file mode 100644
index 1bbaf4a09d..0000000000
--- a/bucket/redis.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "homepage": "http://redis.io",
- "version": "3.2.100",
- "url": "https://github.com/MSOpenTech/redis/releases/download/win-3.2.100/Redis-x64-3.2.100.zip",
- "hash": "73775183186ebd1917353a8ae62303a328cedfff58164c9bf46e2b46977a9475",
- "bin": [
- "redis-benchmark.exe",
- "redis-check-aof.exe",
- "redis-cli.exe",
- "redis-server.exe"
- ],
- "checkver": {
- "url": "https://github.com/MSOpenTech/redis/releases/",
- "re": ">win-(\\d+\\.\\d+\\.\\d+)<"
- }
-}
diff --git a/bucket/resharper-clt.json b/bucket/resharper-clt.json
deleted file mode 100644
index 31fe449246..0000000000
--- a/bucket/resharper-clt.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "version": "2017.1.20170428.83814",
- "homepage": "https://www.jetbrains.com/resharper/download/index.html#section=resharper-clt",
- "license": "https://www.jetbrains.com/resharper/buy/command_line_license.html",
- "url": "https://download.jetbrains.com/resharper/JetBrains.ReSharper.CommandLineTools.2017.1.20170428.83814.zip",
- "hash": "561b92a71514b423883d77ced01d1e186b2eb9cc84ea66c697fa90fe883180a3",
- "bin": [
- "dupfinder.exe",
- "inspectcode.exe"
- ],
- "checkver": {
- "url": "https://data.services.jetbrains.com/products/releases?code=RSCLT&latest=true&type=release",
- "re": "JetBrains.ReSharper.CommandLineTools.([\\d.]+).zip"
- },
- "autoupdate": {
- "url": "https://download.jetbrains.com/resharper/JetBrains.ReSharper.CommandLineTools.$version.zip",
- "hash": {
- "url": "$url.sha256"
- }
- }
-}
diff --git a/bucket/rethinkdb.json b/bucket/rethinkdb.json
deleted file mode 100644
index 048d2e1541..0000000000
--- a/bucket/rethinkdb.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "homepage": "https://www.rethinkdb.com/",
- "license": "https://www.gnu.org/licenses/agpl-3.0.html",
- "version": "2.3.5",
- "architecture": {
- "64bit": {
- "url": "https://download.rethinkdb.com/windows/rethinkdb-2.3.5.zip",
- "hash": "afc431c0aaa6d8b05090f4c33bc527bab6d889555a9817789f155ac45bc51573"
- }
- },
- "bin": "rethinkdb.exe",
- "checkver": {
- "url": "https://rethinkdb.com/docs/install/windows/",
- "re": ""
- },
- "autoupdate": {
- "url": "https://download.rethinkdb.com/windows/rethinkdb-$version.zip"
- }
-}
diff --git a/bucket/rg.json b/bucket/rg.json
deleted file mode 100644
index d4a9dc6e42..0000000000
--- a/bucket/rg.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "homepage": "https://github.com/BurntSushi/ripgrep",
- "license": "MIT",
- "version": "0.5.2",
- "architecture": {
- "64bit": {
- "url": "https://github.com/BurntSushi/ripgrep/releases/download/0.5.2/ripgrep-0.5.2-x86_64-pc-windows-msvc.zip",
- "hash": "377e76c4877aeef3419438b95f7a9b08060a009aec96cc2cb7707a5518a7fa98"
- },
- "32bit": {
- "url": "https://github.com/BurntSushi/ripgrep/releases/download/0.5.2/ripgrep-0.5.2-i686-pc-windows-msvc.zip",
- "hash": "d9c0c7bfb2dd8203be8a56c8bea1eb704ac7f2e3e813f590cc8551c1d142d43e"
- }
- },
- "bin": "rg.exe",
- "checkver": "github",
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://github.com/BurntSushi/ripgrep/releases/download/$version/ripgrep-$version-x86_64-pc-windows-msvc.zip"
- },
- "32bit": {
- "url": "https://github.com/BurntSushi/ripgrep/releases/download/$version/ripgrep-$version-i686-pc-windows-msvc.zip"
- }
- }
- }
-}
diff --git a/bucket/rktools2k3.json b/bucket/rktools2k3.json
deleted file mode 100644
index da7a45ce3d..0000000000
--- a/bucket/rktools2k3.json
+++ /dev/null
@@ -1,96 +0,0 @@
-{
- "homepage": "https://github.com/kodybrown/rktools2k3",
- "version": "1.0",
- "url": "https://github.com/kodybrown/rktools2k3/archive/master.zip",
- "hash": "ca60a82f443988c66ba0e5c16816adaae826b21a29e5c8b9777699b172f9b4cd",
- "extract_dir": "rktools2k3-master",
- "bin": [
- "adlb.exe",
- "atmarp.exe",
- "cdburn.exe",
- "chklnks.exe",
- "chknic.exe",
- "compress.exe",
- "confdisk.exe",
- "consume.exe",
- "creatfil.exe",
- "custreasonedit.exe",
- "delprof.exe",
- "dh.exe",
- "diskraid.exe",
- "diskuse.exe",
- "dvdburn.exe",
- "empty.exe",
- "getcm.exe",
- "gpmonitor.exe",
- "gpotool.exe",
- "hlscan.exe",
- "ifmember.exe",
- "iniman.exe",
- "instcm.exe",
- "instexnt.exe",
- "instsrv.exe",
- "intfiltr.exe",
- "kernrate.exe",
- "klist.exe",
- "linkd.exe",
- "linkspeed.exe",
- "list.exe",
- "lockoutstatus.exe",
- "logtime.exe",
- "lsreport.exe",
- "lsview.exe",
- "memmonitor.exe",
- "memtriage.exe",
- "mibcc.exe",
- "mqcast.exe",
- "mqcatch.exe",
- "nlsinfo.exe",
- "now.exe",
- "ntimer.exe",
- "ntrights.exe",
- "oh.exe",
- "oleview.exe",
- "pathman.exe",
- "permcopy.exe",
- "perms.exe",
- "pfmon.exe",
- "pmon.exe",
- "printdriverinfo.exe",
- "qgrep.exe",
- "qtcp.exe",
- "rassrvmon.exe",
- "rcontrolad.exe",
- "regini.exe",
- "regview.exe",
- "remapkey.exe",
- "reportgen.exe",
- "robocopy.exe",
- "rpccfg.exe",
- "rpcdump.exe",
- "rpcping.exe",
- "rpings.exe",
- "rqc.exe",
- "rqs.exe",
- "setprinter.exe",
- "showacls.exe",
- "showperf.exe",
- "showpriv.exe",
- "sleep.exe",
- "sonar.exe",
- "splinfo.exe",
- "srvany.exe",
- "srvcheck.exe",
- "srvinfo.exe",
- "ssdformat.exe",
- "subinacl.exe",
- "tail.exe",
- "tccom.exe",
- "tcmon.exe",
- "timeit.exe",
- "timezone.exe",
- "tsctst.exe",
- "vadump.exe",
- "vfi.exe"
- ]
-}
diff --git a/bucket/rsync.json b/bucket/rsync.json
deleted file mode 100644
index db338eb183..0000000000
--- a/bucket/rsync.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "homepage": "https://www.itefix.net/cwrsync",
- "version": "5.5.0",
- "license": "https://www.itefix.net/content/cwrsync-licenseversion",
- "url": "https://www.itefix.net/dl/cwRsync_5.5.0_x86_Free.zip",
- "hash": "37e8ef21ac975d4ee86c9d3be40c8935e8b9d0ba84e9302fc106b9452296cb85",
- "extract_dir": "cwRsync_5.5.0_x86_Free",
- "bin": "bin\\rsync.exe",
- "checkver": {
- "url": "https://www.itefix.net/content/cwrsync-free-edition",
- "re": "cwRsync_([\\d.]+)_x86"
- },
- "autoupdate": {
- "url": "https://www.itefix.net/dl/cwRsync_$version_x86_Free.zip",
- "extract_dir": "cwRsync_$version_x86_Free",
- "hash": {
- "find": "SHA256:\\s+([a-fA-F0-9]{64})",
- "url": "https://www.itefix.net/content/cwrsync-free-edition"
- }
- }
-}
diff --git a/bucket/ruby.json b/bucket/ruby.json
deleted file mode 100644
index a4769c8ea2..0000000000
--- a/bucket/ruby.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "homepage": "http://rubyinstaller.org",
- "version": "2.3.3",
- "architecture": {
- "64bit": {
- "url": [
- "https://dl.bintray.com/oneclick/rubyinstaller/ruby-2.3.3-x64-mingw32.7z?direct#/dl.7z",
- "https://dl.bintray.com/oneclick/rubyinstaller/DevKit-mingw64-64-4.7.2-20130224-1432-sfx.exe#/dl2.7z"
- ],
- "hash": [
- "92b97ac3eb380f3f1b7b655a328668cf02b2846ad3c20135bd51f45f4c1cbfc8",
- "2ada04c7234199126c0f34f6ea7163a8f8dccb1e15814af175a189f6ac48b8ac"
- ],
- "extract_dir": "ruby-2.3.3-x64-mingw32"
- },
- "32bit": {
- "url": [
- "https://dl.bintray.com/oneclick/rubyinstaller/ruby-2.3.3-i386-mingw32.7z?direct#/dl.7z",
- "https://dl.bintray.com/oneclick/rubyinstaller/DevKit-mingw64-32-4.7.2-20130224-1151-sfx.exe#/dl2.7z"
- ],
- "hash": [
- "5022ef928f0296abede90f1cf4346250d69f6298c648cad6279938f64eca29fa",
- "61a06b5da06dd94343e591163ac0d43c544e9cd4df770f01275645b268b44dc7"
- ],
- "extract_dir": "ruby-2.3.3-i386-mingw32"
- }
- },
- "extract_to": [
- "",
- "devkit"
- ],
- "persist": "gems",
- "env_add_path": [
- "bin",
- "gems\\bin"
- ],
- "env_set": {
- "GEM_HOME": "$dir\\gems",
- "GEM_PATH": "$dir\\gems"
- },
- "post_install": "pushd $dir\\devkit;echo \"---`n- $dir\" | out-file config.yml -enc default; ruby dk.rb install;popd;",
- "checkver": {
- "url": "http://rubyinstaller.org/downloads/",
- "re": "ruby-([\\d.]+)-x64-mingw32.7z"
- }
-}
diff --git a/bucket/ruby19.json b/bucket/ruby19.json
deleted file mode 100644
index 22cb1fa3e4..0000000000
--- a/bucket/ruby19.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "homepage": "http://rubyinstaller.org",
- "version": "1.9.3-p551",
- "url": [
- "https://dl.bintray.com/oneclick/rubyinstaller/ruby-1.9.3-p551-i386-mingw32.7z?direct#/dl.7z",
- "https://dl.bintray.com/oneclick/rubyinstaller/DevKit-tdm-32-4.5.2-20111229-1559-sfx.exe#/dl2.7z"
- ],
- "hash": [
- "207fdb5b2f9436ad1ac27bf51918b913c14c443d1b83cd910cf5a59acaeab756",
- "6c3af5487dafda56808baf76edd262b2020b1b25ab86aabf972629f4a6a54491"
- ],
- "extract_dir": "ruby-1.9.3-p551-i386-mingw32",
- "extract_to": [
- "",
- "devkit"
- ],
- "env_add_path": "bin",
- "post_install": "pushd $dir\\devkit;ruby dk.rb init > $null;echo \"- $dir\" | out-file config.yml -a -enc default; ruby dk.rb install;popd;",
- "checkver": {
- "url": "https://bintray.com/package/generalTab?pkgPath=/oneclick/rubyinstaller/rubyinstaller",
- "re": "rubyinstaller/(1.9[\\d.]+-p[\\d]+)"
- }
-}
diff --git a/bucket/runat.json b/bucket/runat.json
deleted file mode 100644
index ef5a8d494e..0000000000
--- a/bucket/runat.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "homepage": "https://github.com/lukesampson/psutils",
- "version": "0.2017.04.16",
- "url": "https://raw.github.com/lukesampson/psutils/master/runat.ps1",
- "hash": "a1ec2649d74f01b075cce307883b84be613a145b408d3abd183f21caa0b4218b",
- "bin": "runat.ps1"
-}
diff --git a/bucket/rust-msvc.json b/bucket/rust-msvc.json
deleted file mode 100644
index 20b557ee2e..0000000000
--- a/bucket/rust-msvc.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "homepage": "http://www.rust-lang.org",
- "version": "1.17.0",
- "license": "MIT/Apache 2.0",
- "architecture": {
- "64bit": {
- "url": "https://static.rust-lang.org/dist/rust-1.17.0-x86_64-pc-windows-msvc.msi",
- "hash": "c35e316a6af11883a45eb66a3a6f942fe2ce8ac5fb754f266a2ab60b4dbb7fd3"
- },
- "32bit": {
- "url": "https://static.rust-lang.org/dist/rust-1.17.0-i686-pc-windows-msvc.msi",
- "hash": "866efbced7bff47b328be4cd7ab0b8536b91eb5b822cee535e8d1e9a4cbdac04"
- }
- },
- "bin": [
- "Rust\\bin\\rustc.exe",
- "Rust\\bin\\rustdoc.exe",
- "Rust\\bin\\cargo.exe"
- ],
- "checkver": {
- "url": "https://github.com/rust-lang/rust/releases",
- "re": "([\\d.]+)"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://static.rust-lang.org/dist/rust-$version-x86_64-pc-windows-msvc.msi"
- },
- "32bit": {
- "url": "https://static.rust-lang.org/dist/rust-$version-i686-pc-windows-msvc.msi"
- }
- }
- }
-}
diff --git a/bucket/rust.json b/bucket/rust.json
deleted file mode 100644
index afda3c5ab9..0000000000
--- a/bucket/rust.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "homepage": "http://www.rust-lang.org",
- "version": "1.17.0",
- "license": "MIT/Apache 2.0",
- "architecture": {
- "64bit": {
- "url": "https://static.rust-lang.org/dist/rust-1.17.0-x86_64-pc-windows-gnu.msi",
- "hash": "15a642324b658bbf91f8b4b1446fe28cfaf7806542366015d0b5faf7971bdb36"
- },
- "32bit": {
- "url": "https://static.rust-lang.org/dist/rust-1.17.0-i686-pc-windows-gnu.msi",
- "hash": "43bc9018b8d0f96614447f51cab6c7c84516e65081c98a4d5a08596f7c3da8ce"
- }
- },
- "bin": [
- "Rust\\bin\\rustc.exe",
- "Rust\\bin\\rustdoc.exe",
- "Rust\\bin\\cargo.exe"
- ],
- "checkver": {
- "url": "https://github.com/rust-lang/rust/releases",
- "re": "([\\d.]+)"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://static.rust-lang.org/dist/rust-$version-x86_64-pc-windows-gnu.msi"
- },
- "32bit": {
- "url": "https://static.rust-lang.org/dist/rust-$version-i686-pc-windows-gnu.msi"
- }
- }
- }
-}
diff --git a/bucket/say.json b/bucket/say.json
deleted file mode 100644
index 07bc54e053..0000000000
--- a/bucket/say.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "homepage": "https://github.com/lukesampson/psutils",
- "version": "0.2013.09.08",
- "url": [
- "https://raw.github.com/lukesampson/psutils/3554f2db73/say.ps1",
- "https://raw.github.com/lukesampson/psutils/2938900e58/getopt.ps1"
- ],
- "hash": [
- "75e0013ed0a60b47646f6190b523fc6986177f7360e5352a22806d7e6143bb62",
- "452e61d92dd0eb4e4d6fe5fcd70f30b8c4f36cc9e3b618a7816ec45768d21262"
- ],
- "bin": "say.ps1"
-}
diff --git a/bucket/sbcl.json b/bucket/sbcl.json
deleted file mode 100644
index 4a7b20ac71..0000000000
--- a/bucket/sbcl.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "homepage": "http://www.sbcl.org/",
- "version": "1.3.15",
- "license": "http://www.sbcl.org/history.html",
- "architecture": {
- "64bit": {
- "url": "https://sourceforge.net/projects/sbcl/files/sbcl/1.3.15/sbcl-1.3.15-x86-64-windows-binary.msi",
- "hash": "33BFFC8BCC5E0846A262F4BA3D635A23B47E0BC9180E5FCE6E03FEBD3BA65010"
- },
- "32bit": {
- "url": "https://sourceforge.net/projects/sbcl/files/sbcl/1.3.15/sbcl-1.3.15-x86-windows-binary.msi",
- "hash": "D6984C2C0F3B57402A0F22D8399C9891F8E7F194655B7950CD37B6032BDBDC43"
- }
- },
- "env_set": {
- "SBCL_HOME": "$dir\\PFiles\\Steel Bank Common Lisp\\1.3.15"
- },
- "bin": [
- "PFiles\\Steel Bank Common Lisp\\1.3.15\\sbcl.exe"
- ],
- "checkver": ">SBCL ([\\d.]+)<",
- "notes": "Please restart your command line for SBCL_HOME to take effect. Please consider installing http://www.quicklisp.org/"
-}
diff --git a/bucket/sbt.json b/bucket/sbt.json
deleted file mode 100644
index 1007f0fabf..0000000000
--- a/bucket/sbt.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "homepage": "http://www.scala-sbt.org/",
- "version": "0.13.15",
- "license": "BSD",
- "url": "https://dl.bintray.com/sbt/native-packages/sbt/0.13.15/sbt-0.13.15.zip",
- "hash": "18b106d09b2874f2a538c6e1f6b20c565885b2a8051428bd6d630fb92c1c0f96",
- "extract_dir": "sbt",
- "bin": [
- "bin\\sbt.bat"
- ],
- "checkver": {
- "url": "http://www.scala-sbt.org/download.html",
- "re": "/sbt-([\\d.]+).zip"
- },
- "autoupdate": {
- "url": "https://dl.bintray.com/sbt/native-packages/sbt/$version/sbt-$version.zip",
- "extract_dir": "sbt"
- }
-}
diff --git a/bucket/scala.json b/bucket/scala.json
deleted file mode 100644
index 87a74dc268..0000000000
--- a/bucket/scala.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "homepage": "https://www.scala-lang.org/",
- "version": "2.12.2",
- "license": "BSD 3-Clause",
- "url": "https://downloads.typesafe.com/scala/2.12.2/scala-2.12.2.zip",
- "hash": "695eda7dfd29bc4ab0de8fa64d1ed9bc0db266e6bc9c66a7de9c29b4cd51c4cf",
- "extract_dir": "scala-2.12.2",
- "bin": [
- "bin\\fsc.bat",
- "bin\\scala.bat",
- "bin\\scalac.bat",
- "bin\\scaladoc.bat",
- "bin\\scalap.bat"
- ],
- "env_set": {
- "SCALA_HOME": "$dir"
- },
- "suggest": {
- "JDK": [
- "extras/oraclejdk",
- "openjdk"
- ]
- },
- "checkver": {
- "url": "https://www.scala-lang.org/download/",
- "re": "Download Scala ([\\d.]+)"
- },
- "autoupdate": {
- "url": "https://downloads.typesafe.com/scala/$version/scala-$version.zip",
- "extract_dir": "scala-$version"
- }
-}
diff --git a/bucket/scholdoc.json b/bucket/scholdoc.json
deleted file mode 100644
index 1233a9a2f3..0000000000
--- a/bucket/scholdoc.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "version": "0.1.3-alpha",
- "license": "",
- "extract_dir": "Scholdoc",
- "url": "http://scholarlymarkdown.com/scholdoc-distribution/windows/scholdoc-0.1.3-alpha-windows.msi",
- "homepage": "http://scholdoc.scholarlymarkdown.com/",
- "hash": "e58036686c3c05db4a50d5fabd875eaa33aff2b0dd4d930c6bc2067c2bcd2b86",
- "bin": "scholdoc.exe",
- "checkver": "Current stable version:<\\/strong> ([\\d.]+)"
-}
diff --git a/bucket/scriptcs.json b/bucket/scriptcs.json
deleted file mode 100644
index 3d28cb4314..0000000000
--- a/bucket/scriptcs.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "homepage": "http://scriptcs.net/",
- "version": "0.17.1",
- "license": "Apache 2.0",
- "url": "http://chocolatey.org/api/v2/package/ScriptCs/0.17.1?fn=/dl.zip",
- "hash": "4b6de155f6c5811311df060b626098a771e8534d2d6e3ce51ea99da5e2ec0783",
- "extract_dir": "tools",
- "bin": "scriptcs.exe",
- "checkver": {
- "github": "https://github.com/scriptcs/scriptcs"
- },
- "autoupdate": {
- "url": "http://chocolatey.org/api/v2/package/ScriptCs/$version?fn=/dl.zip"
- }
-}
diff --git a/bucket/sed.json b/bucket/sed.json
deleted file mode 100644
index c493e6796d..0000000000
--- a/bucket/sed.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "homepage": "http://gnuwin32.sourceforge.net/packages/sed.htm",
- "version": "4.2.1",
- "license": "GPL2",
- "url": [
- "https://sourceforge.net/projects/gnuwin32/files/sed/4.2.1/sed-4.2.1-bin.zip",
- "https://sourceforge.net/projects/gnuwin32/files/sed/4.2.1/sed-4.2.1-dep.zip"
- ],
- "hash": [
- "ae1651ffb461d69a7c51c76867a859d8addf802b85678834c0ebb402ef79b3cd",
- "53e2e84db3e6c5855fd8013e1b79ccbd53b6bae7e7e4d59c0d18bb1dd5d18961"
- ],
- "bin": "bin\\sed.exe"
-}
diff --git a/bucket/shasum.json b/bucket/shasum.json
deleted file mode 100644
index 2357648d5e..0000000000
--- a/bucket/shasum.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "homepage": "https://github.com/lukesampson/psutils",
- "version": "0.2013.09.29",
- "url": [
- "https://raw.github.com/lukesampson/psutils/4fa05b1c9b/shasum.ps1",
- "https://raw.github.com/lukesampson/psutils/4fa05b1c9b/getopt.ps1"
- ],
- "hash": [
- "002ed0928a9d80f2d603e8de12bcd922fcdff5acfc4c6f6c67c2e2ace8728b08",
- "452e61d92dd0eb4e4d6fe5fcd70f30b8c4f36cc9e3b618a7816ec45768d21262"
- ],
- "bin": "shasum.ps1"
-}
diff --git a/bucket/sliksvn.json b/bucket/sliksvn.json
deleted file mode 100644
index c2386d8b5d..0000000000
--- a/bucket/sliksvn.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "homepage": "http://sliksvn.com/",
- "version": "1.9.5",
- "architecture": {
- "64bit": {
- "url": "https://sliksvn.com/pub/Slik-Subversion-1.9.5-x64.msi",
- "hash": "88761da80eb5e97d6b2c3eb7caf2f68c2ecb275b363ede10d816c3d789b1ceac"
- },
- "32bit": {
- "url": "https://sliksvn.com/pub/Slik-Subversion-1.9.5-win32.msi",
- "hash": "a04c48ad09c987fd729ab96edcbe02342dcc8c9aeb9ed2e3108ad8cc104daa3b"
- }
- },
- "extract_dir": "SlikSvn",
- "bin": [
- "bin\\svn.exe",
- "bin\\svnadmin.exe",
- "bin\\svnauthz-validate.exe",
- "bin\\svndumpfilter.exe",
- "bin\\svnlook.exe",
- "bin\\svnmucc.exe",
- "bin\\svn-populate-node-origins-index.exe",
- "bin\\svnrdump.exe",
- "bin\\svnserve.exe",
- "bin\\svnsync.exe",
- "bin\\svnversion.exe"
- ],
- "checkver": {
- "url": "https://sliksvn.com/download/",
- "re": "SVN ([\\d.]+), 64 bit"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://sliksvn.com/pub/Slik-Subversion-$version-x64.msi"
- },
- "32bit": {
- "url": "https://sliksvn.com/pub/Slik-Subversion-$version-win32.msi"
- }
- }
- }
-}
diff --git a/bucket/smartmontools.json b/bucket/smartmontools.json
deleted file mode 100644
index b066a21742..0000000000
--- a/bucket/smartmontools.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "bin": [
- "bin/runcmdu.exe",
- "bin/smartctl.exe",
- "bin/smartctl-nc.exe",
- "bin/smartd.exe",
- "bin/update-smart-drivedb.exe",
- "bin/wtssendmsg.exe"
- ],
- "checkver": {
- "re": ">Download\\s+smartmontools-([\\d.\\-]+)\\.",
- "url": "https://sourceforge.net/projects/smartmontools/files/smartmontools/"
- },
- "description": "Read SMART data from disks",
- "hash": "564ff79214af60c4ab0d222ae61781624ca56278bc777963ebe0f19f87f04e3f",
- "homepage": "https://www.smartmontools.org/",
- "installer": {
- "args": [
- "/S",
- "/D=$dir"
- ]
- },
- "license": "GPL-2.0",
- "url": "https://sourceforge.net/projects/smartmontools/files/smartmontools/6.5/smartmontools-6.5-1.win32-setup.exe",
- "version": "6.5-1"
-}
diff --git a/bucket/sonarqube.json b/bucket/sonarqube.json
deleted file mode 100644
index bf9b003b54..0000000000
--- a/bucket/sonarqube.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "homepage": "https://www.sonarqube.org",
- "version": "6.3.1",
- "license": "GNU Lesser GPL License, Version 3",
- "url": "https://sonarsource.bintray.com/Distribution/sonarqube/sonarqube-6.3.1.zip",
- "hash": "f160cb4cc7e748761fe89685336d0b7f6e2d00689c3e4ecfcf567460a7106505",
- "bin": [
- "bin\\windows-x86-64\\StartSonar.bat"
- ],
- "extract_dir": "sonarqube-6.3.1",
- "suggest": {
- "JDK": [
- "extras/oraclejdk",
- "openjdk"
- ]
- },
- "checkver": {
- "re": "https://sonarsource.bintray.com/Distribution/sonarqube/sonarqube-([\\d\\.]+).zip"
- },
- "autoupdate": {
- "url": "https://sonarsource.bintray.com/Distribution/sonarqube/sonarqube-$version.zip",
- "extract_dir": "sonarqube-$version"
- }
-}
diff --git a/bucket/sqlite.json b/bucket/sqlite.json
deleted file mode 100644
index dc2e3bcc43..0000000000
--- a/bucket/sqlite.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "homepage": "https://www.sqlite.org/",
- "version": "3190200",
- "license": "Public Domain",
- "url": "https://www.sqlite.org/2017/sqlite-tools-win32-x86-3190200.zip",
- "hash": "c43e36dcdc5c40a522afd55281df5441fb31ee32ae37cecaead60cafd548db2b",
- "extract_dir": "sqlite-tools-win32-x86-3190200",
- "bin": [
- "sqlite3.exe",
- "sqldiff.exe",
- "sqlite3_analyzer.exe"
- ],
- "checkver": {
- "url": "https://www.sqlite.org/download.html",
- "re": "sqlite-tools-win32-x86-(\\d+).zip"
- },
- "autoupdate": {
- "url": "https://www.sqlite.org/2017/sqlite-tools-win32-x86-$version.zip",
- "extract_dir": "sqlite-tools-win32-x86-$version"
- }
-}
diff --git a/bucket/srvman.json b/bucket/srvman.json
deleted file mode 100644
index 44d7c1c794..0000000000
--- a/bucket/srvman.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "homepage": "http://tools.sysprogs.org/srvman/",
- "version": "1.0",
- "url": "http://sysprogs.com/files/srvman/srvman-1.0.zip",
- "hash": "7f0075c5b544af189416845077a45edeedd1d48e37e702abb22b41b120e80bcd",
- "architecture": {
- "64bit": {
- "extract_dir": "x64"
- },
- "32bit": {
- "extract_dir": "x86"
- }
- },
- "bin": [
- "srvman.exe",
- [
- "srvman.exe",
- "service"
- ]
- ],
- "checkver": "The latest version[^<]+"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://releases.hashicorp.com/terraform/$version/terraform_$version_windows_amd64.zip"
- },
- "32bit": {
- "url": "https://releases.hashicorp.com/terraform/$version/terraform_$version_windows_386.zip"
- }
- },
- "hash": {
- "url": "$baseurl/terraform_$version_SHA256SUMS"
- }
- }
-}
diff --git a/bucket/tesseract.json b/bucket/tesseract.json
deleted file mode 100644
index e6d3f79714..0000000000
--- a/bucket/tesseract.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "homepage": "https://github.com/UB-Mannheim/tesseract/wiki",
- "license": "Apache-2.0",
- "version": "3.05.01",
- "url": "http://digi.bib.uni-mannheim.de/tesseract/tesseract-ocr-setup-3.05.01.exe#/dl.7z",
- "hash": "d4c9d3613ee9531cd093692636b58bc87f87a29a188783dbeb03b127e66fa6ba",
- "bin": [
- "ambiguous_words.exe",
- "classifier_tester.exe",
- "cntraining.exe",
- "combine_tessdata.exe",
- "dawg2wordlist.exe",
- "mftraining.exe",
- "set_unicharset_properties.exe",
- "shapeclustering.exe",
- "tesseract.exe",
- "text2image.exe",
- "unicharset_extractor.exe",
- "wordlist2dawg.exe"
- ],
- "persist": [
- "tessdata"
- ],
- "notes": "Language data files can be downloaded from https://github.com/tesseract-ocr/tessdata",
- "checkver": {
- "re": "tesseract-ocr-setup-(?3.[\\d\\w.-]+).exe",
- "url": "https://github.com/UB-Mannheim/tesseract/wiki"
- },
- "autoupdate": {
- "url": "http://digi.bib.uni-mannheim.de/tesseract/tesseract-ocr-setup-$version.exe#/dl.7z"
- }
-}
diff --git a/bucket/thrift.json b/bucket/thrift.json
deleted file mode 100644
index fb56c24c42..0000000000
--- a/bucket/thrift.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "homepage": "https://thrift.apache.org/",
- "version": "0.10.0",
- "license": "Apache License v2.0",
- "url": "https://www-us.apache.org/dist/thrift/0.10.0/thrift-0.10.0.exe#/thrift.exe",
- "hash": "85aca25c5193c48ec6cc1c0a4c40fac5ea3fde2192c2ffaaad92a9b56d7a8f9a",
- "bin": "thrift.exe",
- "checkver": "Apache\\s+Thrift\\s+v([\\d.]+)",
- "autoupdate": {
- "url": "https://www-us.apache.org/dist/thrift/$version/thrift-$version.exe#/thrift.exe"
- }
-}
diff --git a/bucket/tidy.json b/bucket/tidy.json
deleted file mode 100644
index fbc55ed102..0000000000
--- a/bucket/tidy.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "architecture": {
- "32bit": {
- "hash": "3a4d634113ebf41c13a397cd201b5b84ccf41f9d34829eb57114fd098f1a47a4",
- "url": "https://github.com/htacg/tidy-html5/releases/download/5.4.0/tidy-5.4.0-win32.zip"
- },
- "64bit": {
- "hash": "b01d8382ef6da124298e797a4dcc0ca24060aa29fb5fd1b384b598600a1d78fe",
- "url": "https://github.com/htacg/tidy-html5/releases/download/5.4.0/tidy-5.4.0-win64.zip"
- }
- },
- "autoupdate": {
- "architecture": {
- "32bit": {
- "url": "https://github.com/htacg/tidy-html5/releases/download/$version/tidy-$version-win32.zip"
- },
- "64bit": {
- "url": "https://github.com/htacg/tidy-html5/releases/download/$version/tidy-$version-win64.zip"
- }
- }
- },
- "bin": "tidy.exe",
- "checkver": {
- "github": "https://github.com/htacg/tidy-html5"
- },
- "description": "Tidy HTML and XML files",
- "extract_dir": "bin",
- "homepage": "http://www.html-tidy.org/",
- "license": "http://www.html-tidy.org/documentation/#license",
- "version": "5.4.0"
-}
diff --git a/bucket/time.json b/bucket/time.json
deleted file mode 100644
index 9dac601be6..0000000000
--- a/bucket/time.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "homepage": "https://github.com/lukesampson/psutils",
- "version": "2013-08-10",
- "url": "https://raw.github.com/lukesampson/psutils/598331a7e2b6d4bb60d8a458f8212d349b383e7c/time.ps1",
- "hash": "66f8e31d76d0c1e8bf89bd5f73f6404c384ddcf0bd2069c5a40c331fbca4a63b",
- "bin": [
- "time.ps1",
- [
- "time.ps1",
- "timecmd"
- ]
- ]
-}
diff --git a/bucket/touch.json b/bucket/touch.json
deleted file mode 100644
index cd5aed4aa2..0000000000
--- a/bucket/touch.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "homepage": "https://github.com/lukesampson/psutils",
- "version": "2013-07-02",
- "url": "https://raw.github.com/lukesampson/psutils/767c019fc81f60a990342103cbf75db6703d3593/touch.ps1",
- "hash": "1cedd53b77583d94264274ca8617f4ff5da535fc15d29274d3b12e5f72f7c2f5",
- "bin": "touch.ps1"
-}
diff --git a/bucket/transmission-cli.json b/bucket/transmission-cli.json
deleted file mode 100644
index 8c47065655..0000000000
--- a/bucket/transmission-cli.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "version": "2.92",
- "homepage": "https://transmissionbt.com/",
- "license": "https://github.com/transmission/transmission/blob/master/COPYING",
- "architecture": {
- "64bit": {
- "url": "https://github.com/transmission/transmission/releases/download/2.92/transmission-2.92-x64.msi",
- "hash": "8cee6436e79d48409d76a85bbb1bb506c8c76c8f686551b9e7e13b9a2ca2299d"
- },
- "32bit": {
- "url": "https://github.com/transmission/transmission/releases/download/2.92/transmission-2.92-x86.msi",
- "hash": "f8bfaba603036d35f74bbd5d27ea5bc51fe58d991af48228c290323e406bef00"
- }
- },
- "extract_dir": "PFiles\\Transmission",
- "bin": [
- "transmission-create.exe",
- "transmission-daemon.exe",
- "transmission-edit.exe",
- "transmission-remote.exe",
- "transmission-show.exe"
- ],
- "checkver": {
- "github": "https://github.com/transmission/transmission"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://github.com/transmission/transmission/releases/download/$version/transmission-$version-x64.msi"
- },
- "32bit": {
- "url": "https://github.com/transmission/transmission/releases/download/$version/transmission-$version-x86.msi"
- }
- }
- }
-}
diff --git a/bucket/unar.json b/bucket/unar.json
deleted file mode 100644
index 4ffdc7ffcf..0000000000
--- a/bucket/unar.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "homepage": "https://unarchiver.c3.cx/commandline",
- "license": "GPL2.1",
- "version": "1.8.1",
- "url": [
- "http://unarchiver.c3.cx/downloads/unar1.8.1_win.zip"
- ],
- "hash": [
- "2fa1ea5ddc2b2615b94b2d00cd19fcbf9165cffb5346e83d3b2643e7a55c1e95"
- ],
- "extract_dir": ".",
- "bin": [
- "lsar.exe",
- "unar.exe"
- ]
-}
diff --git a/bucket/unbound.json b/bucket/unbound.json
deleted file mode 100644
index 1ef7a90ef0..0000000000
--- a/bucket/unbound.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "homepage": "https://unbound.net/",
- "version": "1.6.2",
- "license": "BSD",
- "architecture": {
- "64bit": {
- "url": "https://unbound.net/downloads/unbound-1.6.2.zip",
- "hash": "f109ee38b2f7f34043555dda54f3af017c5164c47a12d977594ee56557b059f8"
- },
- "32bit": {
- "url": "https://unbound.net/downloads/unbound-1.6.2-w32.zip",
- "hash": "46cef0c2d47b4d622f4a83456f677ddb124498a69011d14c97e2c8251e00be7d"
- }
- },
- "bin": [
- "unbound.ps1",
- "create_unbound_ad_servers.cmd",
- "unbound_cache.cmd",
- "unbound-control-setup.cmd"
- ],
- "persist": "service.conf",
- "suggest": {
- "openssl": ["openssl", "openssl10x"],
- "wget": ["wget"]
- },
- "checkver": {
- "url": "https://unbound.net/download.html",
- "re": "\\(currently ([\\d.]+)\\)"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://unbound.net/downloads/unbound-$version.zip"
- },
- "32bit": {
- "url": "https://unbound.net/downloads/unbound-$version-w32.zip"
- }
- },
- "hash": {
- "url": "$url.sha256"
- }
- },
- "pre_install": "echo \"if (`$args.count -eq 0) {`n `t`Start-Process -WorkingDirectory `\"`$psscriptroot`\" -f unbound.exe -a '-c service.conf'-WindowStyle Hidden`n`tWrite-Host -F Green `\"Unbound started in background.``nRun 'ps -n unbound' to show the processes``nRun 'kill -n unbound' to stop the processes`\"`n} else {`n`t& `$psscriptroot @args `n}\" | out-file $dir\\unbound.ps1",
- "post_install": "
- (gc \"$dir\\create_unbound_ad_servers.cmd\").Replace('C:\\Program Files (x86)', (convert-path \"$dir\\..\")).replace('%prefix%\\Unbound', '%prefix%\\current') | sc \"$dir\\create_unbound_ad_servers.cmd\"
- (gc \"$dir\\unbound_cache.cmd\").Replace('C:\\Program Files (x86)', (convert-path \"$dir\\..\")).replace('%prefix%\\Unbound', '%prefix%\\current') | sc \"$dir\\unbound_cache.cmd\"
- (gc \"$dir\\unbound-control-setup.cmd\").Replace('C:\\Program Files', (convert-path \"$dir\\..\")).replace('%prefix%\\Unbound', '%prefix%\\current') | sc \"$dir\\unbound-control-setup.cmd\"
- "
-}
diff --git a/bucket/unrar.json b/bucket/unrar.json
deleted file mode 100644
index 9f15706a3f..0000000000
--- a/bucket/unrar.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "bin": "UnRAR.exe",
- "checkver": {
- "re": "WinRAR\\s+x86\\s+\\(32\\s+bit\\)\\s+([\\d.]+)<",
- "url": "http://www.rarlab.com/download.htm"
- },
- "description": "Uncompress RAR files",
- "hash": "27293c101577320fafefc691af98d762361c23e62817ca340ce04a7bba892173",
- "homepage": "http://www.rarlab.com/",
- "installer": {
- "args": [
- "-s",
- "-d$dir"
- ]
- },
- "license": "Freeware",
- "url": "http://www.rarlab.com/rar/unrarw32.exe",
- "version": "5.40"
-}
diff --git a/bucket/unzip.json b/bucket/unzip.json
deleted file mode 100644
index d2ec16bccf..0000000000
--- a/bucket/unzip.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "bin": [
- "SFXWiz32.exe",
- "unzipsfx.exe",
- "unzip.exe",
- "funzip.exe",
- [
- "unzip.exe",
- "zipinfo",
- "-Z"
- ]
- ],
- "description": "Unzip compression utility",
- "hash": "7869ee36346b47701ef01efd0bc2889f970266b66c80b30f74303d50bf7fa33d",
- "homepage": "http://www.info-zip.org/",
- "license": "http://www.info-zip.org/pub/infozip/license.html",
- "pre_install": "& \"$dir\\unz600xn.exe\" -d \"$dir\" -o",
- "url": "ftp://ftp.info-zip.org/pub/infozip/win32/unz600xn.exe",
- "version": "6.00"
-}
diff --git a/bucket/upx.json b/bucket/upx.json
deleted file mode 100644
index 401a5ac7b7..0000000000
--- a/bucket/upx.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "homepage": "https://upx.github.io/",
- "version": "3.94",
- "url": "https://github.com/upx/upx/releases/download/v3.94/upx394w.zip",
- "hash": "74308db1183436576d011bfcc3e7c99c836fb052de7b7eb0539026366453d6e8",
- "extract_dir": "upx394w",
- "bin": "upx.exe",
- "license": "GPL2",
- "checkver": {
- "github": "https://github.com/upx/upx"
- },
- "autoupdate": {
- "url": "https://github.com/upx/upx/releases/download/v$version/upx$cleanVersionw.zip",
- "extract_dir": "upx$cleanVersionw"
- }
-}
diff --git a/bucket/vagrant.json b/bucket/vagrant.json
deleted file mode 100644
index af5273e4e1..0000000000
--- a/bucket/vagrant.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "homepage": "https://www.vagrantup.com/",
- "version": "1.9.5",
- "license": "MIT",
- "url": "https://releases.hashicorp.com/vagrant/1.9.5/vagrant_1.9.5.msi",
- "hash": "8ce945cd01d1273b628aa101e035716c246dfbddad29cccc8d96c873f77d386b",
- "extract_dir": "HashiCorp/Vagrant",
- "bin": "bin\\vagrant.exe",
- "checkver": {
- "url": "https://releases.hashicorp.com/vagrant/",
- "re": "vagrant_([\\d.]+)"
- },
- "autoupdate": {
- "url": "https://releases.hashicorp.com/vagrant/$version/vagrant_$version.msi",
- "hash": {
- "url": "$baseurl/vagrant_$version_SHA256SUMS"
- }
- }
-}
diff --git a/bucket/vault.json b/bucket/vault.json
deleted file mode 100644
index 0740d90204..0000000000
--- a/bucket/vault.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "homepage": "https://www.vaultproject.io",
- "license": "Mozilla Public License 2.0",
- "version": "0.7.2",
- "architecture": {
- "64bit": {
- "url": "https://releases.hashicorp.com/vault/0.7.2/vault_0.7.2_windows_amd64.zip",
- "hash": "718139c6f4bd918d5f94cd380b7b8db4664915d8d64acba0792a31ba102025a8"
- },
- "32bit": {
- "url": "https://releases.hashicorp.com/vault/0.7.2/vault_0.7.2_windows_386.zip",
- "hash": "0ed812c3a16720058c6e92a9a552ccc5d73c6d8d6fbd89e372a19e57a7b0a185"
- }
- },
- "bin": [
- "vault.exe"
- ],
- "checkver": {
- "url": "https://releases.hashicorp.com/vault/",
- "re": "vault_([\\d.]+)"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://releases.hashicorp.com/vault/$version/vault_$version_windows_amd64.zip"
- },
- "32bit": {
- "url": "https://releases.hashicorp.com/vault/$version/vault_$version_windows_386.zip"
- }
- },
- "hash": {
- "url": "$baseurl/vault_$version_SHA256SUMS"
- }
- }
-}
diff --git a/bucket/vim.json b/bucket/vim.json
deleted file mode 100644
index 8c6f166742..0000000000
--- a/bucket/vim.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "homepage": "http://www.vim.org",
- "license": "http://vimdoc.sourceforge.net/htmldoc/uganda.html#license",
- "version": "8.0.0606",
- "architecture": {
- "32bit": {
- "url": "https://github.com/vim/vim-win32-installer/releases/download/v8.0.0606/gvim_8.0.0606_x86.zip",
- "hash": "74ead5b6cb0c7e072201871909b7588706795c196862ae2f4150e58d7749d4d4"
- },
- "64bit": {
- "url": "https://github.com/vim/vim-win32-installer/releases/download/v8.0.0606/gvim_8.0.0606_x64.zip",
- "hash": "0e997f3f6882d72f2c43c16e6ce7717d9c972ce490797217bbbd8ccc204ffa4b"
- }
- },
- "extract_dir": "vim\\vim80",
- "bin": [
- "vim.exe",
- "gvim.exe"
- ],
- "post_install": "if(!(test-path ~\\.vimrc)) {
- cp \"$dir\\vimrc_example.vim\" ~\\.vimrc
- \"set shell=$((gcm powershell).path)\\ -executionpolicy\\ bypass\" | out-file ~\\.vimrc -append -encoding ascii
- echo '~/.vimrc was created with your shell set to Powershell.'
- } else { echo '~/.vimrc exists, skipping' }",
- "checkver": {
- "github": "https://github.com/vim/vim-win32-installer"
- },
- "env_set": {
- "VIM": "$dir"
- },
- "autoupdate": {
- "architecture": {
- "32bit": {
- "url": "https://github.com/vim/vim-win32-installer/releases/download/v$version/gvim_$version_x86.zip",
- "extract_dir": "vim\\vim$majorVersion$minorVersion"
- },
- "64bit": {
- "url": "https://github.com/vim/vim-win32-installer/releases/download/v$version/gvim_$version_x64.zip",
- "extract_dir": "vim\\vim$majorVersion$minorVersion"
- }
- }
- },
- "suggest": {
- "vimtutor": "vimtutor"
- }
-}
diff --git a/bucket/vimtutor.json b/bucket/vimtutor.json
deleted file mode 100644
index 89934d5228..0000000000
--- a/bucket/vimtutor.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "version": "3653063",
- "license": "https://github.com/lukesampson/psutils/blob/master/LICENSE",
- "url": "https://raw.github.com/lukesampson/psutils/3653063/vimtutor.ps1",
- "homepage": "https://github.com/lukesampson/psutils",
- "hash": "f6081071fa95a6f49c049e9d2aed2d2a2632ec47635b4b497a97bab5f5add498",
- "bin": "vimtutor.ps1",
- "suggest": {
- "vim": "vim"
- }
-}
diff --git a/bucket/webp.json b/bucket/webp.json
deleted file mode 100644
index 631f70e157..0000000000
--- a/bucket/webp.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "homepage": "https://developers.google.com/speed/webp/",
- "license": "BSD",
- "version": "0.6.0",
- "architecture": {
- "64bit": {
- "url": "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-0.6.0-windows-x64.zip",
- "hash": "6cd710b4d547033812ab5f74f268c9faa3d86efa8e92f86b3d5f74f8dafd03ed",
- "extract_dir": "libwebp-0.6.0-windows-x64",
- "bin": [
- "bin\\anim_diff.exe",
- "bin\\cwebp.exe",
- "bin\\dwebp.exe",
- "bin\\gif2webp.exe",
- "bin\\vwebp.exe",
- "bin\\webpmux.exe"
- ]
- },
- "32bit": {
- "url": "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-0.6.0-windows-x86.zip",
- "hash": "0e1d562f760411244c5ce9c6ec7f92fe3f2bccee4ee7f744d9c45b4f16c6ae8f",
- "extract_dir": "libwebp-0.6.0-windows-x86",
- "bin": [
- "bin\\anim_diff.exe",
- "bin\\cwebp.exe",
- "bin\\dwebp.exe",
- "bin\\gif2webp.exe",
- "bin\\vwebp.exe",
- "bin\\webpmux.exe"
- ]
- }
- },
- "checkver": {
- "url": "https://developers.google.com/speed/webp/download",
- "re": "\\/libwebp-([\\d].+)-windows-x86.zip"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$version-windows-x64.zip",
- "extract_dir": "libwebp-$version-windows-x64"
- },
- "32bit": {
- "url": "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$version-windows-x86.zip",
- "extract_dir": "libwebp-$version-windows-x86"
- }
- }
- }
-}
diff --git a/bucket/wget.json b/bucket/wget.json
deleted file mode 100644
index e41a9c123f..0000000000
--- a/bucket/wget.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "homepage": "https://eternallybored.org/misc/wget/",
- "license": "GPL3",
- "version": "1.19.1",
- "architecture": {
- "64bit": {
- "url": [
- "https://eternallybored.org/misc/wget/releases/wget-1.19.1-win64.zip"
- ],
- "hash": [
- "61320a3a2f123dd8fd4a8baf65db4063a97622448dc1bf3fcf1284eebe449a1d"
- ]
- },
- "32bit": {
- "url": [
- "https://eternallybored.org/misc/wget/releases/wget-1.19.1-win32.zip"
- ],
- "hash": [
- "745801b57fee4514c131b142346a4332351e90fbc7f696f6a3e02c361cccc27f"
- ]
- }
- },
- "bin": "wget.exe",
- "depends": "cacert",
- "post_install": "\"ca_certificate=$(appdir cacert)\\current\\cacert.pem\" | out-file $dir\\wget.ini -encoding default",
- "checkver": "GNU Wget ([\\d.]+) for Windows",
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://eternallybored.org/misc/wget/releases/wget-$version-win64.zip"
- },
- "32bit": {
- "url": "https://eternallybored.org/misc/wget/releases/wget-$version-win32.zip"
- }
- }
- }
-}
diff --git a/bucket/which.json b/bucket/which.json
deleted file mode 100644
index 23bcc59be0..0000000000
--- a/bucket/which.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "homepage": "http://gnuwin32.sourceforge.net/packages/which.htm",
- "version": "2.20",
- "license": "GPL2",
- "url": [
- "https://sourceforge.net/projects/gnuwin32/files/which/2.20/which-2.20-bin.zip"
- ],
- "hash": [
- "035ec15541649f75459fb81f02406c72e1129fc9041b308160938ae712a603a4"
- ],
- "bin": "bin\\which.exe"
-}
diff --git a/bucket/wkhtmltopdf.json b/bucket/wkhtmltopdf.json
deleted file mode 100644
index 25a98e7a4e..0000000000
--- a/bucket/wkhtmltopdf.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "architecture": {
- "32bit": {
- "hash": "6883d1456201bc9d421cb7dd32a99458be3d56631ea4f292e51b3c1aecbe2723",
- "installer": {
- "args": [
- "/S",
- "/D=$dir"
- ]
- },
- "url": "http://download.gna.org/wkhtmltopdf/0.12/0.12.4/wkhtmltox-0.12.4_msvc2015-win32.exe"
- },
- "64bit": {
- "hash": "14a5996adc77dc606944dbc0dc682bff104cd38cc1bec19253444cb87f259797",
- "installer": {
- "args": [
- "/S",
- "/D=$dir"
- ]
- },
- "url": "http://download.gna.org/wkhtmltopdf/0.12/0.12.4/wkhtmltox-0.12.4_msvc2015-win64.exe"
- }
- },
- "bin": [
- "bin\\wkhtmltoimage.exe",
- "bin\\wkhtmltopdf.exe"
- ],
- "checkver": {
- "re": "The\\s+current\\s+stable\\s+series\\s+is\\s+([\\d.]+)",
- "url": "http://wkhtmltopdf.org/downloads.html"
- },
- "description": "Render HTML into PDF",
- "homepage": "http://wkhtmltopdf.org/",
- "license": "LGPL-3.0",
- "uninstaller": {
- "args": [
- "/S"
- ],
- "file": "Uninstall.exe"
- },
- "version": "0.12.4"
-}
diff --git a/bucket/x264-10bit.json b/bucket/x264-10bit.json
deleted file mode 100644
index 99a23dedcd..0000000000
--- a/bucket/x264-10bit.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "architecture": {
- "32bit": {
- "hash": "c7fdf90a677b6934a26de868c97b53c49a5c26bd32532fff168264611c1bb687",
- "url": "http://download.videolan.org/pub/x264/binaries/win32/x264-10b-r2762-90a61ec.exe"
- },
- "64bit": {
- "hash": "077c1ea1cf96591b20846067e787aecaba626dad6ca7252442c736d9877efdc8",
- "url": "http://download.videolan.org/pub/x264/binaries/win64/x264-10b-r2762-90a61ec.exe"
- }
- },
- "bin": [
- [
- "x264-10b-r2762-90a61ec.exe",
- "x264-10b"
- ]
- ],
- "description": "H.264/MPEG-4 AVC video encoder (10 bit)",
- "homepage": "https://www.videolan.org/developers/x264.html",
- "license": "GPL-2.0",
- "notes": "Version 0.148.2762 (90a61ec) was released on 2017-01-30",
- "version": "17.01.30"
-}
diff --git a/bucket/x264.json b/bucket/x264.json
deleted file mode 100644
index 2193db3822..0000000000
--- a/bucket/x264.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "architecture": {
- "32bit": {
- "hash": "c7fdf90a677b6934a26de868c97b53c49a5c26bd32532fff168264611c1bb687",
- "url": "http://download.videolan.org/pub/x264/binaries/win32/x264-r2762-90a61ec.exe"
- },
- "64bit": {
- "hash": "e493de4c1524472cffb921197e12cb908171fb0d67809a20e0e9876e0f9233c5",
- "url": "http://download.videolan.org/pub/x264/binaries/win64/x264-r2762-90a61ec.exe"
- }
- },
- "bin": [
- [
- "x264-r2762-90a61ec.exe",
- "x264-8b"
- ],
- [
- "x264-r2762-90a61ec.exe",
- "x264"
- ]
- ],
- "description": "H.264/MPEG-4 AVC video encoder (8 bit)",
- "homepage": "https://www.videolan.org/developers/x264.html",
- "license": "GPL-2.0",
- "notes": "Version 0.148.2762 (90a61ec) was released on 2017-01-30",
- "version": "17.01.30"
-}
diff --git a/bucket/xming.json b/bucket/xming.json
deleted file mode 100644
index cb6acf0419..0000000000
--- a/bucket/xming.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "homepage": "http://www.straightrunning.com/XmingNotes/",
- "version": "6.9.0.31",
- "description": "Run X GUI applications on bash subsystem or linux VM, and have them rendered on Windows Desktop. http://www.pcworld.com/article/3055403/windows/windows-10s-bash-shell-can-run-graphical-linux-applications-with-this-trick.html",
- "url": "https://downloads.sourceforge.net/project/xming/Xming-mesa/6.9.0.31/Xming-mesa-6-9-0-31-setup.exe?r=scoop",
- "hash": "md5:E580DEBBF6110CFC4D8FCD20BEB541C1",
- "innosetup": true,
- "bin": [
- "XLaunch.exe"
- ]
-}
diff --git a/bucket/xmlstarlet.json b/bucket/xmlstarlet.json
deleted file mode 100644
index e128c6f135..0000000000
--- a/bucket/xmlstarlet.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "autoupdate": {
- "extract_dir": "xmlstarlet-$version",
- "url": "https://sourceforge.net/projects/xmlstar/files/xmlstarlet/$version/xmlstarlet-$version-win32.zip"
- },
- "bin": "xml.exe",
- "checkver": {
- "re": "/files/latest/download\\?source=files\"\\s+title=\"/xmlstarlet/([\\d.]+)",
- "url": "https://sourceforge.net/projects/xmlstar/files/"
- },
- "description": "Transform, query, validate, and edit XML files",
- "extract_dir": "xmlstarlet-1.6.1",
- "hash": "4ee3d767d9126308d6bcf7b7290e85614a83fe51a9d84e765b9b7f4359f79fce",
- "homepage": "http://xmlstar.sourceforge.net/",
- "license": "MIT",
- "url": "https://sourceforge.net/projects/xmlstar/files/xmlstarlet/1.6.1/xmlstarlet-1.6.1-win32.zip",
- "version": "1.6.1"
-}
diff --git a/bucket/xsv.json b/bucket/xsv.json
deleted file mode 100644
index 4d0d328911..0000000000
--- a/bucket/xsv.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "homepage": "https://github.com/BurntSushi/xsv",
- "license": "Unlicense",
- "version": "0.12.1",
- "architecture": {
- "64bit": {
- "url": "https://github.com/BurntSushi/xsv/releases/download/0.12.1/xsv-0.12.1-x86_64-pc-windows-msvc.zip",
- "hash": "1fa9d184f8b57a46f352181558519d7a99cccb4e0b37204b2ed81c9f00ac6ef5"
- },
- "32bit": {
- "url": "https://github.com/BurntSushi/xsv/releases/download/0.12.1/xsv-0.12.1-i686-pc-windows-msvc.zip",
- "hash": "d7307dac418bf669d0b3be67f1d3f10af53c4b3613847b50588766eb9d1baf69"
- }
- },
- "bin": "xsv.exe",
- "checkver": {
- "github": "https://github.com/BurntSushi/xsv"
- },
- "autoupdate": {
- "architecture": {
- "64bit": {
- "url": "https://github.com/BurntSushi/xsv/releases/download/$version/xsv-$version-x86_64-pc-windows-msvc.zip"
- },
- "32bit": {
- "url": "https://github.com/BurntSushi/xsv/releases/download/$version/xsv-$version-i686-pc-windows-msvc.zip"
- }
- }
- }
-}
diff --git a/bucket/xz.json b/bucket/xz.json
deleted file mode 100644
index 87ee080f90..0000000000
--- a/bucket/xz.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "homepage": "http://tukaani.org/xz/",
- "license": "http://tukaani.org/xz/#licensing",
- "version": "5.2.3",
- "url": "http://tukaani.org/xz/xz-5.2.3-windows.zip",
- "hash": "afe73c260e38fdebdd14c9eaab71c19b206ff74cebbdc744b0fa35b77b243220",
- "architecture": {
- "64bit": {
- "bin": [
- "bin_x86-64\\lzmadec.exe",
- "bin_x86-64\\lzmainfo.exe",
- "bin_x86-64\\xz.exe",
- "bin_x86-64\\xzdec.exe"
- ]
- },
- "32bit": {
- "bin": [
- "bin_i686\\lzmadec.exe",
- "bin_i686\\lzmainfo.exe",
- "bin_i686\\xz.exe",
- "bin_i686\\xzdec.exe"
- ]
- }
- },
- "checkver": "Stable<\\/h3>\\s+
\\s+([\\d.]+) was released",
- "autoupdate": {
- "url": "http://tukaani.org/xz/xz-$version-windows.zip"
- }
-}
diff --git a/bucket/yarn.json b/bucket/yarn.json
deleted file mode 100644
index 99d828d90c..0000000000
--- a/bucket/yarn.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "homepage": "https://yarnpkg.com/",
- "license": "BSD",
- "version": "0.24.6",
- "suggest": {
- "Node.js": [
- "nodejs",
- "nodejs-lts"
- ],
- "NVM": [
- "nvm"
- ]
- },
- "url": "https://yarnpkg.com/downloads/0.24.6/yarn-0.24.6.msi",
- "hash": "00f1aab358abe90eaaeb66c31fdf7342822dfba96a781e6995ffb0d4c68ad330",
- "persist": [
- "cache",
- "bin"
- ],
- "post_install": "
- yarn config set cache \"$persist_dir\\cache\"
- yarn config set prefix \"$persist_dir\\bin\"
- ",
- "env_add_path": [
- "bin",
- "Yarn\\bin"
- ],
- "checkver": {
- "url": "https://yarnpkg.com/latest-version",
- "re": "([\\d.]+)"
- },
- "autoupdate": {
- "url": "https://yarnpkg.com/downloads/$version/yarn-$version.msi"
- }
-}
diff --git a/bucket/youtube-dl.json b/bucket/youtube-dl.json
deleted file mode 100644
index 5bc24c2b80..0000000000
--- a/bucket/youtube-dl.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "homepage": "https://rg3.github.io/youtube-dl/",
- "license": "Public Domain",
- "version": "2017.05.29",
- "url": "https://github.com/rg3/youtube-dl/releases/download/2017.05.29/youtube-dl.exe",
- "hash": "7faf6bc95683c2004ab9be91b822bae18043f21fc96535af523fcc2932bd9730",
- "bin": "youtube-dl.exe",
- "depends": [
- "ffmpeg"
- ],
- "checkver": {
- "github": "https://github.com/rg3/youtube-dl"
- },
- "autoupdate": {
- "url": "https://github.com/rg3/youtube-dl/releases/download/$version/youtube-dl.exe",
- "hash": {
- "url": "$baseurl/SHA2-256SUMS"
- }
- }
-}
diff --git a/bucket/zip.json b/bucket/zip.json
deleted file mode 100644
index b88463c273..0000000000
--- a/bucket/zip.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "architecture": {
- "32bit": {
- "hash": "f8bbc1821d50400245107ce8cfa4a6c7b524387b58bbd6cbe9c20094e82c3bb5",
- "url": "ftp://ftp.info-zip.org/pub/infozip/win32/zip300xn.zip"
- },
- "64bit": {
- "hash": "ed29893fcd7f8b2afb2ead0461663584b740b5d064d4e1c87084107941197a7b",
- "url": "ftp://ftp.info-zip.org/pub/infozip/win32/zip300xn-x64.zip"
- }
- },
- "bin": [
- "zip.exe",
- "zipcloak.exe",
- "zipnote.exe",
- "zipsplit.exe"
- ],
- "description": "Zip compression utilities",
- "homepage": "http://www.info-zip.org/",
- "license": "http://www.info-zip.org/pub/infozip/license.html",
- "pre_install": "Add-Type -assembly 'system.io.compression.filesystem'; [io.compression.zipfile]::ExtractToDirectory(\"$dir\\$fname\", \"$dir\")",
- "version": "3.0"
-}
diff --git a/buckets.json b/buckets.json
index cfa1c50dcd..6d5b13712c 100644
--- a/buckets.json
+++ b/buckets.json
@@ -1,7 +1,12 @@
{
- "extras": "https://github.com/lukesampson/scoop-extras.git",
- "versions": "https://github.com/scoopinstaller/versions",
- "nightlies": "https://github.com/scoopinstaller/nightlies",
- "nirsoft": "https://github.com/kodybrown/scoop-nirsoft",
- "php": "https://github.com/nueko/scoop-php.git"
+ "main": "https://github.com/ScoopInstaller/Main",
+ "extras": "https://github.com/ScoopInstaller/Extras",
+ "versions": "https://github.com/ScoopInstaller/Versions",
+ "nirsoft": "https://github.com/ScoopInstaller/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",
+ "java": "https://github.com/ScoopInstaller/Java",
+ "games": "https://github.com/Calinou/scoop-games"
}
diff --git a/lib/autoupdate.ps1 b/lib/autoupdate.ps1
index d108dae5d6..711f2fd6e5 100644
--- a/lib/autoupdate.ps1
+++ b/lib/autoupdate.ps1
@@ -1,66 +1,107 @@
-<#
-TODO
- - add a github release autoupdate type
- - tests (single arch, without hashes etc.)
- - clean up
-#>
-. "$psscriptroot\..\lib\json.ps1"
-
-. "$psscriptroot/core.ps1"
-. "$psscriptroot/json.ps1"
-
-function find_hash_in_rdf([String] $url, [String] $filename) {
- Write-Host -f DarkYellow "RDF URL: $url"
- Write-Host -f DarkYellow "File: $filename"
-
- $data = ""
+# Must included with 'json.ps1'
+
+function format_hash([String] $hash) {
+ $hash = $hash.toLower()
+
+ if ($hash -like 'sha256:*') {
+ $hash = $hash.Substring(7) # Remove prefix 'sha256:'
+ }
+
+ switch ($hash.Length) {
+ 32 { $hash = "md5:$hash" } # md5
+ 40 { $hash = "sha1:$hash" } # sha1
+ 64 { $hash = $hash } # sha256
+ 128 { $hash = "sha512:$hash" } # sha512
+ default { $hash = $null }
+ }
+ return $hash
+}
+
+function find_hash_in_rdf([String] $url, [String] $basename) {
+ $xml = $null
try {
# Download and parse RDF XML file
- $wc = new-object net.webclient
- $wc.headers.add('Referer', (strip_filename $url))
- [xml]$data = $wc.downloadstring($url)
- } catch [system.net.webexception] {
- write-host -f darkred $_
- write-host -f darkred "URL $url is not valid"
+ $wc = New-Object Net.Webclient
+ $wc.Headers.Add('Referer', (strip_filename $url))
+ $wc.Headers.Add('User-Agent', (Get-UserAgent))
+ $data = $wc.DownloadData($url)
+ [xml]$xml = (Get-Encoding($wc)).GetString($data)
+ } catch [System.Net.WebException] {
+ Write-Host $_ -ForegroundColor DarkRed
+ Write-Host "URL $url is not valid" -ForegroundColor DarkRed
return $null
}
# Find file content
- $digest = $data.RDF.Content | ? { [String]$_.about -eq $filename }
+ $digest = $xml.RDF.Content | Where-Object { [String]$_.about -eq $basename }
return format_hash $digest.sha256
}
-function find_hash_in_textfile([String] $url, [String] $basename, [String] $regex) {
+function find_hash_in_textfile([String] $url, [Hashtable] $substitutions, [String] $regex) {
$hashfile = $null
+ $templates = @{
+ '$md5' = '([a-fA-F0-9]{32})'
+ '$sha1' = '([a-fA-F0-9]{40})'
+ '$sha256' = '([a-fA-F0-9]{64})'
+ '$sha512' = '([a-fA-F0-9]{128})'
+ '$checksum' = '([a-fA-F0-9]{32,128})'
+ '$base64' = '([a-zA-Z0-9+\/=]{24,88})'
+ }
+
try {
- $wc = new-object net.webclient
- $wc.headers.add('Referer', (strip_filename $url))
- $hashfile = $wc.downloadstring($url)
+ $wc = New-Object Net.Webclient
+ $wc.Headers.Add('Referer', (strip_filename $url))
+ $wc.Headers.Add('User-Agent', (Get-UserAgent))
+ $data = $wc.DownloadData($url)
+ $ms = New-Object System.IO.MemoryStream
+ $ms.Write($data, 0, $data.Length)
+ $ms.Seek(0, 0) | Out-Null
+ if ($data[0] -eq 0x1F -and $data[1] -eq 0x8B) {
+ $ms = New-Object System.IO.Compression.GZipStream($ms, [System.IO.Compression.CompressionMode]::Decompress)
+ }
+ $hashfile = (New-Object System.IO.StreamReader($ms, (Get-Encoding $wc))).ReadToEnd()
} catch [system.net.webexception] {
- write-host -f darkred $_
- write-host -f darkred "URL $url is not valid"
+ Write-Host $_ -ForegroundColor DarkRed
+ Write-Host "URL $url is not valid" -ForegroundColor DarkRed
return
}
- # find single line hash in $hashfile (will be overridden by $regex)
if ($regex.Length -eq 0) {
- $normalRegex = "^([a-fA-F0-9]+)$"
- } else {
- $normalRegex = $regex
+ $regex = '^\s*([a-fA-F0-9]+)\s*$'
}
- $normalRegex = substitute $normalRegex @{'$basename' = [regex]::Escape($basename)}
- if ($hashfile -match $normalRegex) {
- $hash = $matches[1]
+ $regex = substitute $regex $templates $false
+ $regex = substitute $regex $substitutions $true
+ if ($hashfile -match $regex) {
+ debug $regex
+ $hash = $matches[1] -replace '\s', ''
+ }
+
+ # convert base64 encoded hash values
+ if ($hash -match '^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})$') {
+ $base64 = $matches[0]
+ if (!($hash -match '^[a-fA-F0-9]+$') -and $hash.Length -notin @(32, 40, 64, 128)) {
+ try {
+ $hash = ([System.Convert]::FromBase64String($base64) | ForEach-Object { $_.ToString('x2') }) -join ''
+ } catch {
+ $hash = $hash
+ }
+ }
}
- # find hash with filename in $hashfile (will be overridden by $regex)
- if ($hash.Length -eq 0 -and $regex.Length -eq 0) {
- $filenameRegex = "([a-fA-F0-9]+)\s+\*?(?:`$basename)"
- $filenameRegex = substitute $filenameRegex @{'$basename' = [regex]::Escape($basename)}
+ # find hash with filename in $hashfile
+ if ($hash.Length -eq 0) {
+ $filenameRegex = "([a-fA-F0-9]{32,128})[\x20\t]+.*`$basename(?:\s|$)|`$basename[\x20\t]+.*?([a-fA-F0-9]{32,128})"
+ $filenameRegex = substitute $filenameRegex $substitutions $true
if ($hashfile -match $filenameRegex) {
+ debug $filenameRegex
+ $hash = $matches[1]
+ }
+ $metalinkRegex = ']+>([a-fA-F0-9]{64})'
+ if ($hashfile -match $metalinkRegex) {
+ debug $metalinkRegex
$hash = $matches[1]
}
}
@@ -68,220 +109,521 @@ function find_hash_in_textfile([String] $url, [String] $basename, [String] $rege
return format_hash $hash
}
-function find_hash_in_json([String] $url, [String] $basename, [String] $jsonpath) {
+function find_hash_in_json([String] $url, [Hashtable] $substitutions, [String] $jsonpath) {
$json = $null
try {
- $wc = new-object net.webclient
- $wc.headers.add('Referer', (strip_filename $url))
- $json = $wc.downloadstring($url) | convertfrom-json -ea stop
+ $wc = New-Object Net.Webclient
+ $wc.Headers.Add('Referer', (strip_filename $url))
+ $wc.Headers.Add('User-Agent', (Get-UserAgent))
+ $data = $wc.DownloadData($url)
+ $ms = New-Object System.IO.MemoryStream
+ $ms.Write($data, 0, $data.Length)
+ $ms.Seek(0, 0) | Out-Null
+ if ($data[0] -eq 0x1F -and $data[1] -eq 0x8B) {
+ $ms = New-Object System.IO.Compression.GZipStream($ms, [System.IO.Compression.CompressionMode]::Decompress)
+ }
+ $json = (New-Object System.IO.StreamReader($ms, (Get-Encoding $wc))).ReadToEnd()
+ } catch [System.Net.WebException] {
+ Write-Host $_ -ForegroundColor DarkRed
+ Write-Host "URL $url is not valid" -ForegroundColor DarkRed
+ return
+ }
+ debug $jsonpath
+ $hash = json_path $json $jsonpath $substitutions
+ if (!$hash) {
+ $hash = json_path_legacy $json $jsonpath $substitutions
+ }
+ return format_hash $hash
+}
+
+function find_hash_in_xml([String] $url, [Hashtable] $substitutions, [String] $xpath) {
+ $xml = $null
+
+ try {
+ $wc = New-Object Net.Webclient
+ $wc.Headers.Add('Referer', (strip_filename $url))
+ $wc.Headers.Add('User-Agent', (Get-UserAgent))
+ $data = $wc.DownloadData($url)
+ $ms = New-Object System.IO.MemoryStream
+ $ms.Write($data, 0, $data.Length)
+ $ms.Seek(0, 0) | Out-Null
+ if ($data[0] -eq 0x1F -and $data[1] -eq 0x8B) {
+ $ms = New-Object System.IO.Compression.GZipStream($ms, [System.IO.Compression.CompressionMode]::Decompress)
+ }
+ $xml = [xml]((New-Object System.IO.StreamReader($ms, (Get-Encoding $wc))).ReadToEnd())
} catch [system.net.webexception] {
- write-host -f darkred $_
- write-host -f darkred "URL $url is not valid"
+ Write-Host $_ -ForegroundColor DarkRed
+ Write-Host "URL $url is not valid" -ForegroundColor DarkRed
+ return
+ }
+
+ # Replace placeholders
+ if ($substitutions) {
+ $xpath = substitute $xpath $substitutions
+ }
+
+ # Find all `significant namespace declarations` from the XML file
+ $nsList = $xml.SelectNodes('//namespace::*[not(. = ../../namespace::*)]')
+ # Then add them into the NamespaceManager
+ $nsmgr = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
+ $nsList | ForEach-Object {
+ $nsmgr.AddNamespace($_.LocalName, $_.Value)
+ }
+
+ debug $xpath
+ debug $nsmgr
+ # Getting hash from XML, using XPath
+ $hash = $xml.SelectSingleNode($xpath, $nsmgr).'#text'
+ return format_hash $hash
+}
+
+function find_hash_in_headers([String] $url) {
+ $hash = $null
+
+ try {
+ $req = [System.Net.WebRequest]::Create($url)
+ $req.Referer = (strip_filename $url)
+ $req.AllowAutoRedirect = $false
+ $req.UserAgent = (Get-UserAgent)
+ $req.Timeout = 2000
+ $req.Method = 'HEAD'
+ $res = $req.GetResponse()
+ if (([int]$res.StatusCode -ge 300) -and ([int]$res.StatusCode -lt 400)) {
+ if ($res.Headers['Digest'] -match 'SHA-256=([^,]+)' -or $res.Headers['Digest'] -match 'SHA=([^,]+)' -or $res.Headers['Digest'] -match 'MD5=([^,]+)') {
+ $hash = ([System.Convert]::FromBase64String($matches[1]) | ForEach-Object { $_.ToString('x2') }) -join ''
+ debug $hash
+ }
+ }
+ $res.Close()
+ } catch [System.Net.WebException] {
+ Write-Host $_ -ForegroundColor DarkRed
+ Write-Host "URL $url is not valid" -ForegroundColor DarkRed
return
}
- $hash = json_path $json $jsonpath $basename
return format_hash $hash
}
function get_hash_for_app([String] $app, $config, [String] $version, [String] $url, [Hashtable] $substitutions) {
$hash = $null
- <#
- TODO implement more hashing types
- `extract` Should be able to extract from origin page source (checkver)
- `rdf` Find hash from a RDF Xml file
- `download` Last resort, download the real file and hash it
- #>
$hashmode = $config.mode
- $basename = url_remote_filename($url)
+ $basename = [System.Web.HttpUtility]::UrlDecode((url_remote_filename($url)))
+
+ $substitutions = $substitutions.Clone()
+ $substitutions.Add('$url', (strip_fragment $url))
+ $substitutions.Add('$baseurl', (strip_filename (strip_fragment $url)).TrimEnd('/'))
+ $substitutions.Add('$basename', $basename)
+ $substitutions.Add('$urlNoExt', (strip_ext (strip_fragment $url)))
+ $substitutions.Add('$basenameNoExt', (strip_ext $basename))
+
+ debug $substitutions
+
+ $hashfile_url = substitute $config.url $substitutions
+ debug $hashfile_url
+ if ($hashfile_url) {
+ Write-Host 'Searching hash for ' -ForegroundColor DarkYellow -NoNewline
+ Write-Host $basename -ForegroundColor Green -NoNewline
+ Write-Host ' in ' -ForegroundColor DarkYellow -NoNewline
+ Write-Host $hashfile_url -ForegroundColor Green
+ }
+
+ if ($hashmode.Length -eq 0 -and $config.url.Length -ne 0) {
+ $hashmode = 'extract'
+ }
+
+ $jsonpath = ''
+ if ($config.jp) {
+ $jsonpath = $config.jp
+ $hashmode = 'json'
+ }
+ if ($config.jsonpath) {
+ $jsonpath = $config.jsonpath
+ $hashmode = 'json'
+ }
+ $regex = ''
+ if ($config.find) {
+ $regex = $config.find
+ }
+ if ($config.regex) {
+ $regex = $config.regex
+ }
- $hashfile_url = substitute $config.url @{
- '$url' = (strip_fragment $url);
- '$baseurl' = (strip_filename (strip_fragment $url)).TrimEnd('/')
- '$basename' = $basename
+ $xpath = ''
+ if ($config.xpath) {
+ $xpath = $config.xpath
+ $hashmode = 'xpath'
}
- $hashfile_url = substitute $hashfile_url $substitutions
- write-host -f yellow $hashfile_url
- if($hashmode.Length -eq 0 -and $config.url.Length -ne 0) {
- $hashmode = "extract"
+ if (!$hashfile_url -and $url -match '^(?:.*fosshub.com\/).*(?:\/|\?dwl=)(?.*)$') {
+ $hashmode = 'fosshub'
}
- if ($hashmode -eq "extract") {
- $hash = find_hash_in_textfile $hashfile_url $basename $config.find
+ if (!$hashfile_url -and $url -match '(?:downloads\.)?sourceforge.net\/projects?\/(?[^\/]+)\/(?:files\/)?(?.*)') {
+ $hashmode = 'sourceforge'
}
- if ($hashmode -eq "json") {
- $hash = find_hash_in_json $hashfile_url $basename $config.jp
+ if (!$hashfile_url -and $url -match 'https:\/\/github\.com\/(?[^\/]+)\/(?[^\/]+)\/releases\/download\/[^\/]+\/[^\/]+') {
+ $hashmode = 'github'
}
- if ($hashmode -eq "rdf") {
- $hash = find_hash_in_rdf $hashfile_url $basename
+ switch ($hashmode) {
+ 'extract' {
+ $hash = find_hash_in_textfile $hashfile_url $substitutions $regex
+ }
+ 'json' {
+ $hash = find_hash_in_json $hashfile_url $substitutions $jsonpath
+ }
+ 'xpath' {
+ $hash = find_hash_in_xml $hashfile_url $substitutions $xpath
+ }
+ 'rdf' {
+ $hash = find_hash_in_rdf $hashfile_url $basename
+ }
+ 'metalink' {
+ $hash = find_hash_in_headers $url
+ if (!$hash) {
+ $hash = find_hash_in_textfile "$url.meta4" $substitutions
+ }
+ }
+ 'fosshub' {
+ $hash = find_hash_in_textfile $url $substitutions ($matches.filename + '.*?"sha256":"([a-fA-F0-9]{64})"')
+ }
+ 'sourceforge' {
+ # change the URL because downloads.sourceforge.net doesn't have checksums
+ $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})"'
+ }
+ 'github' {
+ $hashfile_url = "https://api.github.com/repos/$($matches['owner'])/$($matches['repo'])/releases"
+ $hash = find_hash_in_json $hashfile_url $substitutions ("$..assets[?(@.browser_download_url == '" + $url + "')].digest")
+ }
}
- if($hash) {
+ if ($hash) {
# got one!
+ Write-Host 'Found: ' -ForegroundColor DarkYellow -NoNewline
+ Write-Host $hash -ForegroundColor Green -NoNewline
+ Write-Host ' using ' -ForegroundColor DarkYellow -NoNewline
+ Write-Host "$((Get-Culture).TextInfo.ToTitleCase($hashmode)) Mode" -ForegroundColor Green
return $hash
- } elseif($hashfile_url) {
- write-host -f DarkYellow "Could not find hash in $hashfile_url"
+ } elseif ($hashfile_url) {
+ Write-Host -f DarkYellow "Could not find hash in $hashfile_url"
}
- Write-Host "Download files to compute hashes!" -f DarkYellow
+ Write-Host 'Downloading ' -ForegroundColor DarkYellow -NoNewline
+ Write-Host $basename -ForegroundColor Green -NoNewline
+ Write-Host ' to compute hashes!' -ForegroundColor DarkYellow
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"
+ Write-Host $_ -ForegroundColor DarkRed
+ Write-Host "URL $url is not valid" -ForegroundColor DarkRed
return $null
}
- $file = fullpath (cache_path $app $version $url)
- return compute_hash $file "sha256"
+ $file = cache_path $app $version $url
+ $hash = (Get-FileHash -Path $file -Algorithm SHA256).Hash.ToLower()
+ Write-Host 'Computed hash: ' -ForegroundColor DarkYellow -NoNewline
+ Write-Host $hash -ForegroundColor Green
+ return $hash
}
-function update_manifest_with_new_version($json, [String] $version, [String] $url, [String] $hash, $architecture = $null) {
- $json.version = $version
-
- if ($architecture -eq $null) {
- if ($json.url -is [System.Array]) {
- $json.url[0] = $url
- $json.hash[0] = $hash
- } else {
- $json.url = $url
- $json.hash = $hash
+function Update-ManifestProperty {
+ <#
+ .SYNOPSIS
+ Update propert(y|ies) in manifest
+ .DESCRIPTION
+ Update selected propert(y|ies) to given version in manifest.
+ .PARAMETER Manifest
+ Manifest to be updated
+ .PARAMETER Property
+ Selected propert(y|ies) to be updated
+ .PARAMETER AppName
+ Software name
+ .PARAMETER Version
+ Given software version
+ .PARAMETER Substitutions
+ Hashtable of internal substitutable variables
+ .OUTPUTS
+ System.Boolean
+ Flag that indicate if there are any changed properties
+ #>
+ [CmdletBinding(SupportsShouldProcess = $true)]
+ [OutputType([Boolean])]
+ param (
+ [Parameter(Mandatory = $true, Position = 1)]
+ [PSCustomObject]
+ $Manifest,
+ [Parameter(ValueFromPipeline = $true, Position = 2)]
+ [String[]]
+ $Property,
+ [String]
+ $AppName,
+ [String]
+ $Version,
+ [Alias('Matches')]
+ [HashTable]
+ $Substitutions
+ )
+ begin {
+ $hasManifestChanged = $false
+ }
+ process {
+ foreach ($currentProperty in $Property) {
+ if ($currentProperty -eq 'hash') {
+ # Update hash
+ if ($Manifest.hash) {
+ # Global
+ $newURL = substitute $Manifest.autoupdate.url $Substitutions
+ $newHash = HashHelper -AppName $AppName -Version $Version -HashExtraction $Manifest.autoupdate.hash -URL $newURL -Substitutions $Substitutions
+ $Manifest.hash, $hasPropertyChanged = PropertyHelper -Property $Manifest.hash -Value $newHash
+ $hasManifestChanged = $hasManifestChanged -or $hasPropertyChanged
+ } else {
+ # Arch-spec
+ $Manifest.architecture | Get-Member -MemberType NoteProperty | ForEach-Object {
+ $arch = $_.Name
+ $newURL = substitute (arch_specific 'url' $Manifest.autoupdate $arch) $Substitutions
+ $newHash = HashHelper -AppName $AppName -Version $Version -HashExtraction (arch_specific 'hash' $Manifest.autoupdate $arch) -URL $newURL -Substitutions $Substitutions
+ $Manifest.architecture.$arch.hash, $hasPropertyChanged = PropertyHelper -Property $Manifest.architecture.$arch.hash -Value $newHash
+ $hasManifestChanged = $hasManifestChanged -or $hasPropertyChanged
+ }
+ }
+ } elseif ($Manifest.$currentProperty -and $Manifest.autoupdate.$currentProperty) {
+ # Update other property (global)
+ $autoupdateProperty = $Manifest.autoupdate.$currentProperty
+ $newValue = substitute $autoupdateProperty $Substitutions
+ if (($autoupdateProperty.GetType().Name -eq 'Object[]') -and ($autoupdateProperty.Length -eq 1)) {
+ # Make sure it's an array
+ $newValue = , $newValue
+ }
+ $Manifest.$currentProperty, $hasPropertyChanged = PropertyHelper -Property $Manifest.$currentProperty -Value $newValue
+ $hasManifestChanged = $hasManifestChanged -or $hasPropertyChanged
+ } elseif ($Manifest.architecture) {
+ # Update other property (arch-spec)
+ $Manifest.architecture | Get-Member -MemberType NoteProperty | ForEach-Object {
+ $arch = $_.Name
+ if ($Manifest.architecture.$arch.$currentProperty -and ($Manifest.autoupdate.architecture.$arch.$currentProperty -or $Manifest.autoupdate.$currentProperty)) {
+ $autoupdateProperty = @(arch_specific $currentProperty $Manifest.autoupdate $arch)
+ $newValue = substitute $autoupdateProperty $Substitutions
+ if (($autoupdateProperty.GetType().Name -eq 'Object[]') -and ($autoupdateProperty.Length -eq 1)) {
+ # Make sure it's an array
+ $newValue = , $newValue
+ }
+ $Manifest.architecture.$arch.$currentProperty, $hasPropertyChanged = PropertyHelper -Property $Manifest.architecture.$arch.$currentProperty -Value $newValue
+ $hasManifestChanged = $hasManifestChanged -or $hasPropertyChanged
+ }
+ }
+ }
}
- } else {
- # If there are multiple urls we replace the first one
- if ($json.architecture.$architecture.url -is [System.Array]) {
- $json.architecture.$architecture.url[0] = $url
- $json.architecture.$architecture.hash[0] = $hash
- } else {
- $json.architecture.$architecture.url = $url
- $json.architecture.$architecture.hash = $hash
+ }
+ end {
+ if ($Version -ne '' -and $Manifest.version -ne $Version) {
+ $Manifest.version = $Version
+ $hasManifestChanged = $true
}
+ return $hasManifestChanged
}
}
-function update_manifest_prop([String] $prop, $json, [Hashtable] $substitutions) {
- # first try the global property
- if ($json.$prop -and $json.autoupdate.$prop) {
- $json.$prop = substitute $json.autoupdate.$prop $substitutions
- }
-
- # check if there are architecture specific variants
- if ($json.architecture) {
- $json.architecture | Get-Member -MemberType NoteProperty | % {
- $architecture = $_.Name
+function Get-VersionSubstitution {
+ param (
+ [String]
+ $Version,
+ [Hashtable]
+ $CustomMatches
+ )
- if ($json.architecture.$architecture.$prop) {
- $json.architecture.$architecture.$prop = substitute (arch_specific $prop $json.autoupdate $architecture) $substitutions
+ $firstPart = $Version.Split('-') | Select-Object -First 1
+ $lastPart = $Version.Split('-') | Select-Object -Last 1
+ $versionVariables = @{
+ '$version' = $Version
+ '$dotVersion' = ($Version -replace '[._-]', '.')
+ '$underscoreVersion' = ($Version -replace '[._-]', '_')
+ '$dashVersion' = ($Version -replace '[._-]', '-')
+ '$cleanVersion' = ($Version -replace '[._-]', '')
+ '$majorVersion' = $firstPart.Split('.') | Select-Object -First 1
+ '$minorVersion' = $firstPart.Split('.') | Select-Object -Skip 1 -First 1
+ '$patchVersion' = $firstPart.Split('.') | Select-Object -Skip 2 -First 1
+ '$buildVersion' = $firstPart.Split('.') | Select-Object -Skip 3 -First 1
+ '$preReleaseVersion' = $lastPart
+ }
+ if ($Version -match '(?\d+\.\d+(?:\.\d+)?)(?.*)') {
+ $versionVariables.Add('$matchHead', $Matches['head'])
+ $versionVariables.Add('$matchTail', $Matches['tail'])
+ }
+ if ($CustomMatches) {
+ $CustomMatches.GetEnumerator() | ForEach-Object {
+ if ($_.Name -ne '0') {
+ $versionVariables.Add('$match' + (Get-Culture).TextInfo.ToTitleCase($_.Name), $_.Value)
}
}
}
+ return $versionVariables
}
-function get_version_substitutions([String] $version, [Hashtable] $matches) {
- $firstPart = $version.Split('-') | Select-Object -first 1
- $lastPart = $version.Split('-') | Select-Object -last 1
- $versionVariables = @{
- '$version' = $version;
- '$underscoreVersion' = ($version -replace "\.", "_");
- '$cleanVersion' = ($version -replace "\.", "");
- '$majorVersion' = $firstPart.Split('.') | Select-Object -first 1;
- '$minorVersion' = $firstPart.Split('.') | Select-Object -skip 1 -first 1;
- '$patchVersion' = $firstPart.Split('.') | Select-Object -skip 2 -first 1;
- '$buildVersion' = $firstPart.Split('.') | Select-Object -skip 3 -first 1;
- '$preReleaseVersion' = $lastPart;
- }
- if($matches) {
- $matches.Remove(0)
- $matches.GetEnumerator() | % {
- $versionVariables.Add('$match' + (Get-Culture).TextInfo.ToTitleCase($_.Name), $_.Value)
- }
+function Invoke-AutoUpdate {
+ param (
+ [String]
+ $AppName,
+ [String]
+ $Path,
+ [PSObject]
+ $Manifest,
+ [String]
+ $Version,
+ [Hashtable]
+ $CustomMatches
+ )
+
+ Write-Host "Autoupdating $AppName" -ForegroundColor DarkCyan
+ $substitutions = Get-VersionSubstitution $Version $CustomMatches
+
+ # update properties
+ $updatedProperties = @(@($Manifest.autoupdate.PSObject.Properties.Name) -ne 'architecture')
+ if ($Manifest.autoupdate.architecture) {
+ $updatedProperties += $Manifest.autoupdate.architecture.PSObject.Properties | ForEach-Object { $_.Value.PSObject.Properties.Name }
}
- return $versionVariables
-}
+ if ($updatedProperties -contains 'url') {
+ $updatedProperties += 'hash'
+ }
+ $updatedProperties = $updatedProperties | Select-Object -Unique
+ debug [$updatedProperties]
+ $hasChanged = Update-ManifestProperty -Manifest $Manifest -Property $updatedProperties -AppName $AppName -Version $Version -Substitutions $substitutions
-function autoupdate([String] $app, $dir, $json, [String] $version, [Hashtable] $matches) {
- Write-Host -f DarkCyan "Autoupdating $app"
- $has_changes = $false
- $has_errors = $false
- [Bool]$valid = $true
- $substitutions = get_version_substitutions $version $matches
-
- if ($json.url) {
- # create new url
- $url = substitute $json.autoupdate.url $substitutions
- $valid = $true
-
- if($valid) {
- # create hash
- $hash = get_hash_for_app $app $json.autoupdate.hash $version $url $substitutions
- if ($hash -eq $null) {
- $valid = $false
- Write-Host -f DarkRed "Could not find hash!"
+ if ($hasChanged) {
+ # write file
+ Write-Host "Writing updated $AppName manifest" -ForegroundColor DarkGreen
+ # Accept unusual Unicode characters
+ # '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($Path, (ConvertToPrettyJson $Manifest))
+ # notes
+ $note = "`nUpdating note:"
+ if ($Manifest.autoupdate.note) {
+ $note += "`nno-arch: $($Manifest.autoupdate.note)"
+ $hasNote = $true
+ }
+ if ($Manifest.autoupdate.architecture) {
+ '64bit', '32bit', 'arm64' | ForEach-Object {
+ if ($Manifest.autoupdate.architecture.$_.note) {
+ $note += "`n$_-arch: $($Manifest.autoupdate.architecture.$_.note)"
+ $hasNote = $true
+ }
}
}
-
- # write changes to the json object
- if ($valid) {
- $has_changes = $true
- update_manifest_with_new_version $json $version $url $hash
- } else {
- $has_errors = $true
- throw "Could not update $app"
+ if ($hasNote) {
+ Write-Host $note -ForegroundColor DarkYellow
}
} else {
- $json.architecture | Get-Member -MemberType NoteProperty | % {
- $valid = $true
- $architecture = $_.Name
-
- # create new url
- $url = substitute (arch_specific "url" $json.autoupdate $architecture) $substitutions
- $valid = $true
-
- if($valid) {
- # create hash
- $hash = get_hash_for_app $app (arch_specific "hash" $json.autoupdate $architecture) $version $url $substitutions
- if ($hash -eq $null) {
- $valid = $false
- Write-Host -f DarkRed "Could not find hash!"
+ # This if-else branch may not be in use.
+ Write-Host "No updates for $AppName" -ForegroundColor DarkGray
+ }
+}
+
+## Helper Functions
+
+function PropertyHelper {
+ <#
+ .SYNOPSIS
+ Helper of updating property
+ .DESCRIPTION
+ Update manifest property (String, Array or PSCustomObject).
+ .PARAMETER Property
+ Property to be updated
+ .PARAMETER Value
+ New property values
+ Update line by line
+ .OUTPUTS
+ System.Object[]
+ The first element is new property, the second element is change flag
+ #>
+ param (
+ [Object]$Property,
+ [Object]$Value
+ )
+ $hasChanged = $false
+ if (@($Property).Length -lt @($Value).Length) {
+ $Property = $Value
+ $hasChanged = $true
+ } else {
+ switch ($Property.GetType().Name) {
+ 'String' {
+ $Value = $Value -as [String]
+ if ($null -ne $Value) {
+ $Property = $Value
+ $hasChanged = $true
}
}
-
- # write changes to the json object
- if ($valid) {
- $has_changes = $true
- update_manifest_with_new_version $json $version $url $hash $architecture
- } else {
- $has_errors = $true
- throw "Could not update $app $architecture"
+ 'Object[]' {
+ $Value = @($Value)
+ for ($i = 0; $i -lt $Value.Length; $i++) {
+ $Property[$i], $hasItemChanged = PropertyHelper -Property $Property[$i] -Value $Value[$i]
+ $hasChanged = $hasChanged -or $hasItemChanged
+ }
+ }
+ 'PSCustomObject' {
+ if ($Value -is [PSObject]) {
+ foreach ($name in $Property.PSObject.Properties.Name) {
+ if ($Value.$name) {
+ $Property.$name, $hasItemChanged = PropertyHelper -Property $Property.$name -Value $Value.$name
+ $hasChanged = $hasChanged -or $hasItemChanged
+ }
+ }
+ }
}
}
}
+ return $Property, $hasChanged
+}
- # update properties
- update_manifest_prop "extract_dir" $json $substitutions
-
- # update license
- update_manifest_prop "license" $json $substitutions
-
- if ($has_changes -and !$has_errors) {
- # write file
- Write-Host -f DarkGreen "Writing updated $app manifest"
-
- $path = join-path $dir "$app.json"
-
- $file_content = $json | ConvertToPrettyJson
- [System.IO.File]::WriteAllLines($path, $file_content)
-
- # notes
- if ($json.autoupdate.note) {
- Write-Host ""
- Write-Host -f DarkYellow $json.autoupdate.note
+function HashHelper {
+ <#
+ .SYNOPSIS
+ Helper of getting file hash(es)
+ .DESCRIPTION
+ Extract or calculate file hash(es).
+ If hash extraction templates are less then URLs, the last template will be reused for the rest URLs.
+ .PARAMETER AppName
+ Software name
+ .PARAMETER Version
+ Given software version
+ .PARAMETER HashExtraction
+ Hash extraction template(s)
+ .PARAMETER URL
+ New download URL(s), used to calculate hash locally (fallback)
+ .PARAMETER Substitutions
+ Hashtable of internal substitutable variables
+ .OUTPUTS
+ System.String
+ Hash value (single URL)
+ System.String[]
+ Hash values (multi URLs)
+ #>
+ param (
+ [String]
+ $AppName,
+ [String]
+ $Version,
+ [PSObject[]]
+ $HashExtraction,
+ [String[]]
+ $URL,
+ [HashTable]
+ $Substitutions
+ )
+ $hash = @()
+ for ($i = 0; $i -lt $URL.Length; $i++) {
+ if ($null -eq $HashExtraction) {
+ $currentHashExtraction = $null
+ } else {
+ $currentHashExtraction = $HashExtraction[$i], $HashExtraction[-1] | Select-Object -First 1
+ }
+ $hash += get_hash_for_app $AppName $currentHashExtraction $Version $URL[$i] $Substitutions
+ if ($null -eq $hash[$i]) {
+ throw "Could not update $AppName, hash for $(url_remote_filename $URL[$i]) failed!"
}
- } else {
- Write-Host -f DarkGray "No updates for $app"
}
+ return $hash
}
diff --git a/lib/buckets.ps1 b/lib/buckets.ps1
index 589be6e454..87bc02d287 100644
--- a/lib/buckets.ps1
+++ b/lib/buckets.ps1
@@ -1,15 +1,43 @@
$bucketsdir = "$scoopdir\buckets"
+function Find-BucketDirectory {
+ <#
+ .DESCRIPTION
+ Return full path for bucket with given name.
+ Main bucket will be returned as default.
+ .PARAMETER Name
+ Name of bucket.
+ .PARAMETER Root
+ Root folder of bucket repository will be returned instead of 'bucket' subdirectory (if exists).
+ #>
+ param(
+ [string] $Name = 'main',
+ [switch] $Root
+ )
+
+ # Handle info passing empty string as bucket ($install.bucket)
+ if (($null -eq $Name) -or ($Name -eq '')) {
+ $Name = 'main'
+ }
+ $bucket = "$bucketsdir\$Name"
+
+ if ((Test-Path "$bucket\bucket") -and !$Root) {
+ $bucket = "$bucket\bucket"
+ }
+
+ return $bucket
+}
+
function bucketdir($name) {
- if(!$name) { return relpath "..\bucket" } # main bucket
+ Show-DeprecatedWarning $MyInvocation 'Find-BucketDirectory'
- "$bucketsdir\$name"
+ return Find-BucketDirectory $name
}
function known_bucket_repos {
- $dir = versiondir 'scoop' 'current'
- $json = "$dir\buckets.json"
- gc $json -raw | convertfrom-json -ea stop
+ $json = "$PSScriptRoot\..\buckets.json"
+
+ return Get-Content $json -Raw | ConvertFrom-Json -ErrorAction stop
}
function known_bucket_repo($name) {
@@ -17,28 +45,173 @@ function known_bucket_repo($name) {
$buckets.$name
}
+function known_buckets {
+ known_bucket_repos | ForEach-Object { $_.PSObject.Properties | Select-Object -Expand 'name' }
+}
+
function apps_in_bucket($dir) {
- gci $dir | ? { $_.name.endswith('.json') } | % { $_ -replace '.json$', '' }
+ return (Get-ChildItem $dir -Filter '*.json' -Recurse).BaseName
+}
+
+function Get-LocalBucket {
+ <#
+ .SYNOPSIS
+ List all local buckets.
+ #>
+ $bucketNames = [System.Collections.Generic.List[String]](Get-ChildItem -Path $bucketsdir -Directory).Name
+ if ($null -eq $bucketNames) {
+ return @() # Return a zero-length list instead of $null.
+ } else {
+ $knownBuckets = known_buckets
+ for ($i = $knownBuckets.Count - 1; $i -ge 0 ; $i--) {
+ $name = $knownBuckets[$i]
+ if ($bucketNames.Contains($name)) {
+ [void]$bucketNames.Remove($name)
+ $bucketNames.Insert(0, $name)
+ }
+ }
+ return $bucketNames
+ }
}
function buckets {
+ Show-DeprecatedWarning $MyInvocation 'Get-LocalBucket'
+
+ return Get-LocalBucket
+}
+
+function Convert-RepositoryUri {
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory, Position = 0, ValueFromPipeline = $true)]
+ [AllowEmptyString()]
+ [String] $Uri
+ )
+
+ process {
+ # https://git-scm.com/docs/git-clone#_git_urls
+ # https://regex101.com/r/xGmwRr/1
+ if ($Uri -match '(?:@|/{1,3})(?:www\.|.*@)?(?[^/]+?)(?::\d+)?[:/](?.+)/(?.+?)(?:\.git)?/?$') {
+ $Matches.provider, $Matches.user, $Matches.repo -join '/'
+ } else {
+ error "$Uri is not a valid Git URL!"
+ error "Please see https://git-scm.com/docs/git-clone#_git_urls for valid ones."
+ return $null
+ }
+ }
+}
+
+function list_buckets {
$buckets = @()
- if(test-path $bucketsdir) {
- gci $bucketsdir | % { $buckets += $_.name }
+ Get-LocalBucket | ForEach-Object {
+ $bucket = [Ordered]@{ Name = $_ }
+ $path = Find-BucketDirectory $_ -Root
+ if ((Test-Path (Join-Path $path '.git')) -and (Get-Command git -ErrorAction SilentlyContinue)) {
+ $bucket.Source = Invoke-Git -Path $path -ArgumentList @('config', 'remote.origin.url')
+ $bucket.Updated = Invoke-Git -Path $path -ArgumentList @('log', '--format=%aD', '-n', '1') | Get-Date
+ } else {
+ $bucket.Source = friendly_path $path
+ $bucket.Updated = (Get-Item "$path\bucket" -ErrorAction SilentlyContinue).LastWriteTime
+ }
+ $bucket.Manifests = Get-ChildItem "$path\bucket" -Force -Recurse -ErrorAction SilentlyContinue |
+ Measure-Object | Select-Object -ExpandProperty Count
+ $buckets += [PSCustomObject]$bucket
}
- $buckets
+ ,$buckets
}
-function find_manifest($app, $bucket) {
- if ($bucket) {
- $manifest = manifest $app $bucket
- if ($manifest) { return $manifest, $bucket }
- return $null
+function add_bucket($name, $repo) {
+ if (!(Test-GitAvailable)) {
+ error "Git is required for buckets. Run 'scoop install git' and try again."
+ return 1
}
- $buckets = @($null) + @(buckets) # null for main bucket
- foreach($bucket in $buckets) {
- $manifest = manifest $app $bucket
- if($manifest) { return $manifest, $bucket }
+ $dir = Find-BucketDirectory $name -Root
+ if (Test-Path $dir) {
+ warn "The '$name' bucket already exists. To add this bucket again, first remove it by running 'scoop bucket rm $name'."
+ return 2
}
+
+ $uni_repo = Convert-RepositoryUri -Uri $repo
+ if ($null -eq $uni_repo) {
+ return 1
+ }
+ foreach ($bucket in Get-LocalBucket) {
+ if (Test-Path -Path "$bucketsdir\$bucket\.git") {
+ $remote = Invoke-Git -Path "$bucketsdir\$bucket" -ArgumentList @('config', '--get', 'remote.origin.url')
+ if ((Convert-RepositoryUri -Uri $remote) -eq $uni_repo) {
+ warn "Bucket $bucket already exists for $repo"
+ return 2
+ }
+ }
+ }
+
+ Write-Host 'Checking repo... ' -NoNewline
+ $out = Invoke-Git -ArgumentList @('ls-remote', $repo) 2>&1
+ if ($LASTEXITCODE -ne 0) {
+ error "'$repo' doesn't look like a valid git repository`n`nError given:`n$out"
+ return 1
+ }
+ ensure $bucketsdir | Out-Null
+ $dir = ensure $dir
+ $out = Invoke-Git -ArgumentList @('clone', $repo, $dir, '-q')
+ if ($LASTEXITCODE -ne 0) {
+ error "Failed to clone '$repo' to '$dir'.`n`nError given:`n$out`n`nPlease check the repository URL or network connection and try again."
+ Remove-Item $dir -Recurse -Force -ErrorAction SilentlyContinue
+ return 1
+ }
+ Write-Host 'OK'
+ if (get_config USE_SQLITE_CACHE) {
+ info 'Updating cache...'
+ Set-ScoopDB -Path (Get-ChildItem (Find-BucketDirectory $name) -Filter '*.json' -Recurse).FullName
+ }
+ success "The $name bucket was added successfully."
+ return 0
+}
+
+function rm_bucket($name) {
+ $dir = Find-BucketDirectory $name -Root
+ if (!(Test-Path $dir)) {
+ error "'$name' bucket not found."
+ return 1
+ }
+
+ Remove-Item $dir -Recurse -Force -ErrorAction Stop
+ if (get_config USE_SQLITE_CACHE) {
+ info 'Updating cache...'
+ Remove-ScoopDBItem -Bucket $name
+ }
+ success "The $name bucket was removed successfully."
+ return 0
+}
+
+function new_issue_msg($app, $bucket, $title, $body) {
+ $app, $manifest, $bucket, $url = Get-Manifest "$bucket/$app"
+ $url = known_bucket_repo $bucket
+ $bucket_path = "$bucketsdir\$bucket"
+
+ if (Test-Path $bucket_path) {
+ $remote = Invoke-Git -Path $bucket_path -ArgumentList @('config', '--get', 'remote.origin.url')
+ # Support ssh and http syntax
+ # git@PROVIDER:USER/REPO.git
+ # https://PROVIDER/USER/REPO.git
+ $remote -match '(@|:\/\/)(?.+)[:/](?.*)\/(?.*)(\.git)?$' | Out-Null
+ $url = "https://$($Matches.Provider)/$($Matches.User)/$($Matches.Repo)"
+ }
+
+ if (!$url) { return 'Please contact the bucket maintainer!' }
+
+ # Print only github repositories
+ if ($url -like '*github*') {
+ $title = [System.Web.HttpUtility]::UrlEncode("$app@$($manifest.version): $title")
+ $body = [System.Web.HttpUtility]::UrlEncode($body)
+ $url = $url -replace '\.git$', ''
+ $url = "$url/issues/new?title=$title"
+ if ($body) {
+ $url += "&body=$body"
+ }
+ }
+
+ $msg = "`nPlease try again or create a new issue by using the following link and paste your console output:"
+ return "$msg`n$url"
}
diff --git a/lib/commands.ps1 b/lib/commands.ps1
index 522eb5b1be..6812aebd52 100644
--- a/lib/commands.ps1
+++ b/lib/commands.ps1
@@ -1,30 +1,32 @@
+# Description: Functions for managing commands and aliases.
+
+## Functions for commands
+
function command_files {
- (gci (relpath '..\libexec')) `
- + (gci "$scoopdir\shims") `
- | where { $_.name -match 'scoop-.*?\.ps1$' }
+ (Get-ChildItem "$PSScriptRoot\..\libexec") + (Get-ChildItem "$scoopdir\shims") |
+ Where-Object 'scoop-.*?\.ps1$' -Property Name -Match
}
function commands {
- command_files | % { command_name $_ }
+ command_files | ForEach-Object { command_name $_ }
}
function command_name($filename) {
- $filename.name | sls 'scoop-(.*?)\.ps1$' | % { $_.matches[0].groups[1].value }
+ $filename.name | Select-String 'scoop-(.*?)\.ps1$' | ForEach-Object { $_.matches[0].groups[1].value }
}
function command_path($cmd) {
- $cmd_path = relpath "..\libexec\scoop-$cmd.ps1"
+ $cmd_path = "$PSScriptRoot\..\libexec\scoop-$cmd.ps1"
# built in commands
if (!(Test-Path $cmd_path)) {
# get path from shim
$shim_path = "$scoopdir\shims\scoop-$cmd.ps1"
- $line = ((gc $shim_path) | where { $_.startswith('$path') })
- if($line) {
- iex -command "$line"
+ $line = ((Get-Content $shim_path) | Where-Object { $_.startswith('$path') })
+ if ($line) {
+ Invoke-Command ([scriptblock]::Create($line)) -NoNewScope
$cmd_path = $path
- }
- else { $cmd_path = $shim_path }
+ } else { $cmd_path = $shim_path }
}
$cmd_path
@@ -35,3 +37,92 @@ function exec($cmd, $arguments) {
& $cmd_path @arguments
}
+
+## Functions for aliases
+
+function add_alias {
+ param(
+ [ValidateNotNullOrEmpty()]
+ [string]$name,
+ [ValidateNotNullOrEmpty()]
+ [string]$command,
+ [string]$description
+ )
+
+ $aliases = get_config ALIAS ([PSCustomObject]@{})
+ if ($aliases.$name) {
+ abort "Alias '$name' already exists."
+ }
+
+ $alias_script_name = "scoop-$name"
+ $shimdir = shimdir $false
+ if (Test-Path "$shimdir\$alias_script_name.ps1") {
+ abort "File '$alias_script_name.ps1' already exists in shims directory."
+ }
+ $script = @(
+ "# Summary: $description",
+ "$command"
+ ) -join "`n"
+ try {
+ $script | Out-UTF8File "$shimdir\$alias_script_name.ps1"
+ } catch {
+ abort $_.Exception
+ }
+
+ # Add the new alias to the config.
+ $aliases | Add-Member -MemberType NoteProperty -Name $name -Value $alias_script_name
+ set_config ALIAS $aliases | Out-Null
+}
+
+function rm_alias {
+ param(
+ [ValidateNotNullOrEmpty()]
+ [string]$name
+ )
+
+ $aliases = get_config ALIAS ([PSCustomObject]@{})
+ if (!$aliases.$name) {
+ abort "Alias '$name' doesn't exist."
+ }
+
+ info "Removing alias '$name'..."
+ if (Test-Path "$(shimdir $false)\scoop-$name.ps1") {
+ Remove-Item "$(shimdir $false)\scoop-$name.ps1"
+ }
+ $aliases.PSObject.Properties.Remove($name)
+ set_config ALIAS $aliases | Out-Null
+}
+
+function list_aliases {
+ param(
+ [bool]$verbose
+ )
+
+ $aliases = get_config ALIAS ([PSCustomObject]@{})
+ $alias_info = $aliases.PSObject.Properties.Name | Where-Object { $_ } | ForEach-Object {
+ # Mark the alias as , if the alias script file does NOT exist.
+ if (!(Test-Path "$(shimdir $false)\scoop-$_.ps1")) {
+ [PSCustomObject]@{
+ Name = $_
+ Command = ''
+ }
+ return
+ }
+ $content = Get-Content (command_path $_)
+ [PSCustomObject]@{
+ Name = $_
+ Command = ($content | Select-Object -Skip 1).Trim()
+ Summary = (summary $content).Trim()
+ }
+ }
+ if (!$alias_info) {
+ info 'No alias found.'
+ return
+ }
+ $alias_info = $alias_info | Sort-Object Name
+ $properties = @('Name', 'Command')
+ if ($verbose) {
+ $properties += 'Summary'
+ }
+ $alias_info | Select-Object $properties
+}
diff --git a/lib/config.ps1 b/lib/config.ps1
deleted file mode 100644
index 1ad8b369a9..0000000000
--- a/lib/config.ps1
+++ /dev/null
@@ -1,86 +0,0 @@
-$cfgpath = "~/.scoop"
-
-function hashtable($obj) {
- $h = @{ }
- $obj.psobject.properties | % {
- $h[$_.name] = hashtable_val $_.value
- }
- return $h
-}
-
-function hashtable_val($obj) {
- if($obj -eq $null) { return $null }
- if($obj -is [array]) {
- $arr = @()
- $obj | % {
- $val = hashtable_val $_
- if($val -is [array]) {
- $arr += ,@($val)
- } else {
- $arr += $val
- }
- }
- return ,$arr
- }
- if($obj.gettype().name -eq 'pscustomobject') { # -is is unreliable
- return hashtable $obj
- }
- return $obj # assume primitive
-}
-
-function load_cfg {
- if(!(test-path $cfgpath)) { return $null }
-
- try {
- hashtable (gc $cfgpath -raw | convertfrom-json -ea stop)
- } catch {
- write-host "ERROR loading $cfgpath`: $($_.exception.message)"
- }
-}
-
-function get_config($name) {
- return $cfg.$name
-}
-
-function set_config($name, $val) {
- if(!$cfg) {
- $cfg = @{ $name = $val }
- } else {
- $cfg.$name = $val
- }
-
- if($val -eq $null) {
- $cfg.remove($name)
- }
-
- convertto-json $cfg | out-file $cfgpath -encoding utf8
-}
-
-$cfg = load_cfg
-
-# setup proxy
-# note: '@' and ':' in password must be escaped, e.g. 'p@ssword' -> p\@ssword'
-$p = get_config 'proxy'
-if($p) {
- try {
- $cred, $address = $p -split '(?
+ param($Invocation, [String] $New)
+
+ warn ('"{0}" will be deprecated. Please change your code/manifest to use "{1}"' -f $Invocation.MyCommand.Name, $New)
+ Write-Host " -> $($Invocation.PSCommandPath):$($Invocation.ScriptLineNumber):$($Invocation.OffsetInLine)" -ForegroundColor DarkGray
+}
+
+function load_cfg($file) {
+ if(!(Test-Path $file)) {
+ return $null
+ }
+
+ try {
+ # ReadAllLines will detect the encoding of the file automatically
+ # Ref: https://docs.microsoft.com/en-us/dotnet/api/system.io.file.readalllines?view=netframework-4.5
+ $content = [System.IO.File]::ReadAllLines($file)
+ return ($content | ConvertFrom-Json -ErrorAction Stop)
+ } catch {
+ Write-Host "ERROR loading $file`: $($_.exception.message)"
+ }
+}
+
+function get_config($name, $default) {
+ $name = $name.ToLowerInvariant()
+ if($null -eq $scoopConfig.$name -and $null -ne $default) {
+ return $default
+ }
+ return $scoopConfig.$name
+}
+
+function set_config {
+ Param (
+ [ValidateNotNullOrEmpty()]
+ $name,
+ $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
+ }
+
+ if ($value -eq [bool]::TrueString -or $value -eq [bool]::FalseString) {
+ $value = [System.Convert]::ToBoolean($value)
+ }
+
+ # Initialize config's change
+ Complete-ConfigChange -Name $name -Value $value
+
+ if ($null -eq $scoopConfig.$name) {
+ $scoopConfig | Add-Member -MemberType NoteProperty -Name $name -Value $value
+ } else {
+ $scoopConfig.$name = $value
+ }
+
+ if ($null -eq $value) {
+ $scoopConfig.PSObject.Properties.Remove($name)
+ }
+
+ # Save config with UTF8NoBOM encoding
+ ConvertTo-Json $scoopConfig | Out-UTF8File -FilePath $configFile
+ return $scoopConfig
+}
+
+function Complete-ConfigChange {
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory, Position = 0)]
+ [string]
+ $Name,
+ [Parameter(Mandatory, Position = 1)]
+ [AllowEmptyString()]
+ [string]
+ $Value
+ )
+
+ if ($Name -eq 'use_isolated_path') {
+ $oldValue = get_config USE_ISOLATED_PATH
+ if ($Value -eq $oldValue) {
+ return
+ } else {
+ $currPathEnvVar = $scoopPathEnvVar
+ }
+ . "$PSScriptRoot\..\lib\system.ps1"
+
+ if ($Value -eq $false -or $Value -eq '') {
+ info 'Turn off Scoop isolated path... This may take a while, please wait.'
+ $movedPath = Get-EnvVar -Name $currPathEnvVar
+ if ($movedPath) {
+ Add-Path -Path $movedPath -Quiet
+ Remove-Path -Path ('%' + $currPathEnvVar + '%') -Quiet
+ Set-EnvVar -Name $currPathEnvVar -Quiet
+ }
+ if (is_admin) {
+ $movedPath = Get-EnvVar -Name $currPathEnvVar -Global
+ if ($movedPath) {
+ Add-Path -Path $movedPath -Global -Quiet
+ Remove-Path -Path ('%' + $currPathEnvVar + '%') -Global -Quiet
+ Set-EnvVar -Name $currPathEnvVar -Global -Quiet
+ }
+ }
+ } else {
+ $newPathEnvVar = if ($Value -eq $true) {
+ 'SCOOP_PATH'
+ } else {
+ $Value.ToUpperInvariant()
+ }
+ info "Turn on Scoop isolated path ('$newPathEnvVar')... This may take a while, please wait."
+ $movedPath = Remove-Path -Path "$scoopdir\apps\*" -TargetEnvVar $currPathEnvVar -Quiet -PassThru
+ if ($movedPath) {
+ Add-Path -Path $movedPath -TargetEnvVar $newPathEnvVar -Quiet
+ Add-Path -Path ('%' + $newPathEnvVar + '%') -Quiet
+ if ($currPathEnvVar -ne 'PATH') {
+ Remove-Path -Path ('%' + $currPathEnvVar + '%') -Quiet
+ Set-EnvVar -Name $currPathEnvVar -Quiet
+ }
+ }
+ if (is_admin) {
+ $movedPath = Remove-Path -Path "$globaldir\apps\*" -TargetEnvVar $currPathEnvVar -Global -Quiet -PassThru
+ if ($movedPath) {
+ Add-Path -Path $movedPath -TargetEnvVar $newPathEnvVar -Global -Quiet
+ Add-Path -Path ('%' + $newPathEnvVar + '%') -Global -Quiet
+ if ($currPathEnvVar -ne 'PATH') {
+ Remove-Path -Path ('%' + $currPathEnvVar + '%') -Global -Quiet
+ Set-EnvVar -Name $currPathEnvVar -Global -Quiet
+ }
+ }
+ }
+ }
+ }
+
+ if ($Name -eq 'use_sqlite_cache' -and $Value -eq $true) {
+ if ((Get-DefaultArchitecture) -eq 'arm64') {
+ abort 'SQLite cache is not supported on ARM64 platform.'
+ }
+ . "$PSScriptRoot\..\lib\database.ps1"
+ . "$PSScriptRoot\..\lib\manifest.ps1"
+ info 'Initializing SQLite cache in progress... This may take a while, please wait.'
+ Set-ScoopDB
+ }
+}
+
+function Invoke-Git {
+ [CmdletBinding()]
+ [OutputType([String])]
+ param(
+ [Parameter(Mandatory = $false, Position = 0)]
+ [Alias('PSPath', 'Path')]
+ [ValidateNotNullOrEmpty()]
+ [String]
+ $WorkingDirectory,
+ [Parameter(Mandatory = $true, Position = 1)]
+ [Alias('Args')]
+ [String[]]
+ $ArgumentList
+ )
+
+ $proxy = get_config PROXY
+ $git = Get-HelperPath -Helper Git
+
+ if ($WorkingDirectory) {
+ $ArgumentList = @('-C', $WorkingDirectory) + $ArgumentList
+ }
+
+ if([String]::IsNullOrEmpty($proxy) -or $proxy -eq 'none') {
+ return & $git @ArgumentList
+ }
+
+ if($ArgumentList -Match '\b(clone|checkout|pull|fetch|ls-remote)\b') {
+ $j = Start-Job -ScriptBlock {
+ # convert proxy setting for git
+ $proxy = $using:proxy
+ if ($proxy -and $proxy.StartsWith('currentuser@')) {
+ $proxy = $proxy.Replace('currentuser@', ':@')
+ }
+ $env:HTTPS_PROXY = $proxy
+ $env:HTTP_PROXY = $proxy
+ & $using:git @using:ArgumentList
+ }
+ $o = $j | Receive-Job -Wait -AutoRemoveJob
+ return $o
+ }
+
+ return & $git @ArgumentList
+}
+
+function Invoke-GitLog {
+ [CmdletBinding()]
+ Param (
+ [Parameter(Mandatory, ValueFromPipeline)]
+ [String]$Path,
+ [Parameter(Mandatory, ValueFromPipeline)]
+ [String]$CommitHash,
+ [String]$Name = ''
+ )
+ Process {
+ if ($Name) {
+ if ($Name.Length -gt 12) {
+ $Name = "$($Name.Substring(0, 10)).."
+ }
+ $Name = "%Cgreen$($Name.PadRight(12, ' ').Substring(0, 12))%Creset "
+ }
+ Invoke-Git -Path $Path -ArgumentList @('--no-pager', 'log', '--color', '--no-decorate', "--grep='^(chore)'", '--invert-grep', '--abbrev=12', "--format=tformat: * %C(yellow)%h%Creset %<|(72,trunc)%s $Name%C(cyan)%cr%Creset", "$CommitHash..HEAD")
+ }
+}
# helper functions
function coalesce($a, $b) { if($a) { return $a } $b }
-function format($str, $hash) {
- $hash.keys | % { set-variable $_ $hash[$_] }
- $executionContext.invokeCommand.expandString($str)
-}
function is_admin {
$admin = [security.principal.windowsbuiltinrole]::administrator
$id = [security.principal.windowsidentity]::getcurrent()
@@ -32,9 +290,39 @@ function is_admin {
}
# messages
-function abort($msg) { write-host $msg -f darkred; exit 1 }
-function error($msg) { write-host $msg -f darkred }
-function warn($msg) { write-host $msg -f darkyellow }
+function abort($msg, [int] $exit_code=1) { write-host $msg -f red; exit $exit_code }
+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') {
+ return
+ }
+
+ $prefix = "DEBUG[$(Get-Date -UFormat %s)]"
+ $param = $MyInvocation.Line.Replace($MyInvocation.InvocationName, '').Trim()
+ $msg = $obj | Out-String -Stream
+
+ if($null -eq $obj -or $null -eq $msg) {
+ Write-Host "$prefix $param = " -f DarkCyan -NoNewline
+ Write-Host '$null' -f DarkYellow -NoNewline
+ Write-Host " -> $($MyInvocation.PSCommandPath):$($MyInvocation.ScriptLineNumber):$($MyInvocation.OffsetInLine)" -f DarkGray
+ return
+ }
+
+ if($msg.GetType() -eq [System.Object[]]) {
+ Write-Host "$prefix $param ($($obj.GetType()))" -f DarkCyan -NoNewline
+ Write-Host " -> $($MyInvocation.PSCommandPath):$($MyInvocation.ScriptLineNumber):$($MyInvocation.OffsetInLine)" -f DarkGray
+ $msg | Where-Object { ![String]::IsNullOrWhiteSpace($_) } |
+ Select-Object -Skip 2 | # Skip headers
+ ForEach-Object {
+ Write-Host "$prefix $param.$($_)" -f DarkCyan
+ }
+ } else {
+ Write-Host "$prefix $param = $($msg.Trim())" -f DarkCyan -NoNewline
+ Write-Host " -> $($MyInvocation.PSCommandPath):$($MyInvocation.ScriptLineNumber):$($MyInvocation.OffsetInLine)" -f DarkGray
+ }
+}
function success($msg) { write-host $msg -f darkgreen }
function filesize($length) {
@@ -49,6 +337,9 @@ function filesize($length) {
} elseif($length -gt $kb) {
"{0:n1} KB" -f ($length / $kb)
} else {
+ if ($null -eq $length) {
+ $length = 0
+ }
"$($length) B"
}
}
@@ -57,25 +348,245 @@ function filesize($length) {
function basedir($global) { if($global) { return $globaldir } $scoopdir }
function appsdir($global) { "$(basedir $global)\apps" }
function shimdir($global) { "$(basedir $global)\shims" }
+function modulesdir($global) { "$(basedir $global)\modules" }
function appdir($app, $global) { "$(appsdir $global)\$app" }
function versiondir($app, $version, $global) { "$(appdir $app $global)\$version" }
+
+function currentdir($app, $global) {
+ if (get_config NO_JUNCTION) {
+ $version = Select-CurrentVersion -App $app -Global:$global
+ } else {
+ $version = 'current'
+ }
+ "$(appdir $app $global)\$version"
+}
+
function persistdir($app, $global) { "$(basedir $global)\persist\$app" }
function usermanifestsdir { "$(basedir)\workspace" }
function usermanifest($app) { "$(usermanifestsdir)\$app.json" }
-function cache_path($app, $version, $url) { "$cachedir\$app#$version#$($url -replace '[^\w\.\-]+', '_')" }
+function cache_path($app, $version, $url) {
+ $underscoredUrl = $url -replace '[^\w\.\-]+', '_'
+ $filePath = Join-Path $cachedir "$app#$version#$underscoredUrl"
+
+ # NOTE: Scoop cache files migration. Remove this 6 months after the feature ships.
+ if (Test-Path $filePath) {
+ return $filePath
+ }
+
+ $urlStream = [System.IO.MemoryStream]::new([System.Text.Encoding]::UTF8.GetBytes($url))
+ $sha = (Get-FileHash -Algorithm SHA256 -InputStream $urlStream).Hash.ToLower().Substring(0, 7)
+ $extension = [System.IO.Path]::GetExtension($url)
+ $filePath = $filePath -replace "$underscoredUrl", "$sha$extension"
+
+ return $filePath
+}
# apps
function sanitary_path($path) { return [regex]::replace($path, "[/\\?:*<>|]", "") }
-function installed($app, $global=$null) {
- if($global -eq $null) { return (installed $app $true) -or (installed $app $false) }
- return is_directory (appdir $app $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
+ # "dependency". So we need to extract the bucket from the name and only give the app
+ # name to is_directory
+ $app = ($app -split '/|\\')[-1]
+ return $null -ne (Select-CurrentVersion -AppName $app -Global:$global)
}
function installed_apps($global) {
$dir = appsdir $global
- if(test-path $dir) {
- gci $dir | where { $_.psiscontainer -and $_.name -ne 'scoop' } | % { $_.name }
+ if (Test-Path $dir) {
+ Get-ChildItem $dir | Where-Object { $_.psiscontainer -and $_.name -ne 'scoop' } | ForEach-Object { $_.name }
+ }
+}
+
+# check whether the app failed to install
+function failed($app, $global) {
+ $app = ($app -split '/|\\')[-1]
+ $appPath = appdir $app $global
+ $hasCurrent = (get_config NO_JUNCTION) -or (Test-Path "$appPath\current")
+ return (Test-Path $appPath) -and !($hasCurrent -and (installed $app $global))
+}
+
+function file_path($app, $file) {
+ Show-DeprecatedWarning $MyInvocation 'Get-AppFilePath'
+ Get-AppFilePath -App $app -File $file
+}
+
+function Get-AppFilePath {
+ [CmdletBinding()]
+ [OutputType([String])]
+ param(
+ [Parameter(Mandatory = $true, Position = 0)]
+ [String]
+ $App,
+ [Parameter(Mandatory = $true, Position = 1)]
+ [String]
+ $File
+ )
+
+ # normal path to file
+ $Path = "$(currentdir $App $false)\$File"
+ if (Test-Path $Path) {
+ return $Path
+ }
+
+ # global path to file
+ $Path = "$(currentdir $App $true)\$File"
+ if (Test-Path $Path) {
+ return $Path
+ }
+
+ # not found
+ return $null
+}
+
+Function Test-CommandAvailable {
+ param (
+ [String]$Name
+ )
+ Return [Boolean](Get-Command $Name -ErrorAction Ignore)
+}
+
+Function Test-GitAvailable {
+ return [Boolean](Get-HelperPath -Helper Git)
+}
+
+function Get-HelperPath {
+ [CmdletBinding()]
+ [OutputType([String])]
+ param(
+ [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
+ [ValidateSet('Git', '7zip', 'Lessmsi', 'Innounp', 'Dark', 'Aria2')]
+ [String]
+ $Helper
+ )
+ begin {
+ $HelperPath = $null
+ }
+ process {
+ switch ($Helper) {
+ 'Git' {
+ $internalgit = (Get-AppFilePath 'git' 'mingw64\bin\git.exe'), (Get-AppFilePath 'git' 'mingw32\bin\git.exe') | Where-Object { $_ -ne $null }
+ if ($internalgit) {
+ $HelperPath = $internalgit
+ } else {
+ $HelperPath = (Get-Command git -CommandType Application -TotalCount 1 -ErrorAction Ignore).Source
+ }
+ }
+ '7zip' { $HelperPath = Get-AppFilePath '7zip' '7z.exe' }
+ 'Lessmsi' { $HelperPath = Get-AppFilePath 'lessmsi' 'lessmsi.exe' }
+ 'Innounp' {
+ $HelperPath = Get-AppFilePath 'innounp-unicode' 'innounp.exe'
+ if ([String]::IsNullOrEmpty($HelperPath)) {
+ $HelperPath = Get-AppFilePath 'innounp' 'innounp.exe'
+ }
+ }
+ 'Dark' {
+ $HelperPath = Get-AppFilePath 'wixtoolset' 'wix.exe'
+ if ([String]::IsNullOrEmpty($HelperPath)) {
+ $HelperPath = Get-AppFilePath 'dark' 'dark.exe'
+ }
+ }
+ 'Aria2' { $HelperPath = Get-AppFilePath 'aria2' 'aria2c.exe' }
+ }
+
+ return $HelperPath
+ }
+}
+
+function Get-CommandPath {
+ [CmdletBinding()]
+ [OutputType([String])]
+ param(
+ [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
+ [String]
+ $Command
+ )
+
+ begin {
+ $userShims = shimdir $false
+ $globalShims = shimdir $true
+ }
+
+ process {
+ try {
+ $comm = Get-Command $Command -ErrorAction Stop
+ } catch {
+ return $null
+ }
+ $commandPath = if ($comm.Path -like "$userShims\scoop-*.ps1") {
+ # Scoop aliases
+ $comm.Source
+ } elseif ($comm.Path -like "$userShims*" -or $comm.Path -like "$globalShims*") {
+ Get-ShimTarget ($comm.Path -replace '\.exe$', '.shim')
+ } elseif ($comm.CommandType -eq 'Application') {
+ $comm.Source
+ } elseif ($comm.CommandType -eq 'Alias') {
+ Get-CommandPath $comm.ResolvedCommandName
+ } else {
+ $null
+ }
+ return $commandPath
+ }
+}
+
+function Test-HelperInstalled {
+ [CmdletBinding()]
+ param(
+ [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
+ [ValidateSet('7zip', 'Lessmsi', 'Innounp', 'Dark', 'Aria2')]
+ [String]
+ $Helper
+ )
+
+ return ![String]::IsNullOrWhiteSpace((Get-HelperPath -Helper $Helper))
+}
+
+function app_status($app, $global) {
+ $status = @{}
+ $status.installed = installed $app $global
+ $status.version = Select-CurrentVersion -AppName $app -Global:$global
+ $status.latest_version = $status.version
+
+ $install_info = install_info $app $status.version $global
+
+ $status.failed = failed $app $global
+ $status.hold = ($install_info.hold -eq $true)
+
+ $deprecated_dir = (Find-BucketDirectory -Name $install_info.bucket -Root) + "\deprecated"
+ $status.deprecated = (Get-ChildItem $deprecated_dir -Filter "$(sanitary_path $app).json" -Recurse).FullName
+
+ $manifest = manifest $app $install_info.bucket $install_info.url
+ $status.removed = (!$manifest)
+ if ($manifest.version) {
+ $status.latest_version = $manifest.version
}
+
+ $status.outdated = $false
+ if ($status.version -and $status.latest_version) {
+ 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)
+ }
+ }
+
+ $status.missing_deps = @()
+ $deps = @($manifest.depends) | Where-Object {
+ if ($null -eq $_) {
+ return $null
+ } else {
+ $app, $bucket, $null = parse_app $_
+ return !(installed $app)
+ }
+ }
+ if ($deps) {
+ $status.missing_deps += , $deps
+ }
+ return $status
}
+
function appname_from_url($url) {
(split-path $url -leaf) -replace '.json$', ''
}
@@ -85,70 +596,208 @@ function fname($path) { split-path $path -leaf }
function strip_ext($fname) { $fname -replace '\.[^\.]*$', '' }
function strip_filename($path) { $path -replace [regex]::escape((fname $path)) }
function strip_fragment($url) { $url -replace (new-object uri $url).fragment }
-
-function url_filename($url) {
- (split-path $url -leaf).split('?') | Select-Object -First 1
+function ensure($dir) {
+ if (!(Test-Path -Path $dir)) {
+ New-Item -Path $dir -ItemType Directory | Out-Null
+ }
+ Convert-Path -Path $dir
}
-# Unlike url_filename which can be tricked by appending a
-# URL fragment (e.g. #/dl.7z, useful for coercing a local filename),
-# this function extracts the original filename from the URL.
-function url_remote_filename($url) {
- split-path (new-object uri $url).absolutePath -leaf
+function Get-AbsolutePath {
+ <#
+ .SYNOPSIS
+ Get absolute path
+ .DESCRIPTION
+ Get absolute path, even if not existed
+ .PARAMETER Path
+ Path to manipulate
+ .OUTPUTS
+ System.String
+ Absolute path, may or maynot existed
+ #>
+ [CmdletBinding()]
+ [OutputType([string])]
+ param (
+ [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
+ [string]
+ $Path
+ )
+ process {
+ return $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Path)
+ }
}
-function ensure($dir) { if(!(test-path $dir)) { mkdir $dir > $null }; resolve-path $dir }
-function fullpath($path) { # should be ~ rooted
- $executionContext.sessionState.path.getUnresolvedProviderPathFromPSPath($path)
+function fullpath($path) {
+ Show-DeprecatedWarning $MyInvocation 'Get-AbsolutePath'
+ return Get-AbsolutePath -Path $path
}
-function relpath($path) { "$($myinvocation.psscriptroot)\$path" } # relative to calling script
function friendly_path($path) {
- $h = "$home"; if(!$h.endswith('\')) { $h += '\' }
- if($h -eq '\') { return $path }
- return "$path" -replace ([regex]::escape($h)), "~\"
+ $h = (Get-PSProvider 'FileSystem').Home
+ if (!$h.EndsWith('\')) {
+ $h += '\'
+ }
+ if ($h -eq '\') {
+ return $path
+ } else {
+ return $path -replace ([Regex]::Escape($h)), '~\'
+ }
}
function is_local($path) {
- ($path -notmatch '^https?://') -and (test-path $path)
+ ($path -notmatch '^https?://') -and (Test-Path $path)
}
# operations
-function dl($url,$to) {
- $wc = new-object system.net.webClient
- $wc.headers.add('User-Agent', 'Scoop/1.0')
- $wc.headers.add('Referer', (strip_filename $url))
- $wc.downloadFile($url,$to)
-}
-function env($name,$global,$val='__get') {
- $target = 'User'; if($global) {$target = 'Machine'}
- if($val -eq '__get') { [environment]::getEnvironmentVariable($name,$target) }
- else { [environment]::setEnvironmentVariable($name,$val,$target) }
+function run($exe, $arg, $msg, $continue_exit_codes) {
+ Show-DeprecatedWarning $MyInvocation 'Invoke-ExternalCommand'
+ Invoke-ExternalCommand -FilePath $exe -ArgumentList $arg -Activity $msg -ContinueExitCodes $continue_exit_codes
}
-function unzip($path,$to) {
- if(!(test-path $path)) { abort "can't find $path to unzip"}
- try { add-type -assembly "System.IO.Compression.FileSystem" -ea stop }
- catch { unzip_old $path $to; return } # for .net earlier than 4.5
- try {
- [io.compression.zipfile]::extracttodirectory($path,$to)
- } catch [system.io.pathtoolongexception] {
- # try to fall back to 7zip if path is too long
- if(7zip_installed) {
- extract_7zip $path $to $false
- return
+function Invoke-ExternalCommand {
+ [CmdletBinding(DefaultParameterSetName = "Default")]
+ [OutputType([Boolean])]
+ param (
+ [Parameter(Mandatory = $true, Position = 0)]
+ [Alias("Path")]
+ [ValidateNotNullOrEmpty()]
+ [String]
+ $FilePath,
+ [Parameter(Position = 1)]
+ [Alias("Args")]
+ [String[]]
+ $ArgumentList,
+ [Parameter(ParameterSetName = "UseShellExecute")]
+ [Switch]
+ $RunAs,
+ [Parameter(ParameterSetName = "UseShellExecute")]
+ [Switch]
+ $Quiet,
+ [Alias("Msg")]
+ [String]
+ $Activity,
+ [Alias("cec")]
+ [Hashtable]
+ $ContinueExitCodes,
+ [Parameter(ParameterSetName = "Default")]
+ [Alias("Log")]
+ [String]
+ $LogPath
+ )
+ if ($Activity) {
+ Write-Host "$Activity " -NoNewline
+ }
+ $Process = New-Object System.Diagnostics.Process
+ $Process.StartInfo.FileName = $FilePath
+ $Process.StartInfo.UseShellExecute = $false
+ if ($LogPath) {
+ if ($FilePath -match '^msiexec(.exe)?$') {
+ $ArgumentList += "/lwe `"$LogPath`""
+ } else {
+ $redirectToLogFile = $true
+ $Process.StartInfo.RedirectStandardOutput = $true
+ $Process.StartInfo.RedirectStandardError = $true
+ }
+ }
+ if ($RunAs) {
+ $Process.StartInfo.UseShellExecute = $true
+ $Process.StartInfo.Verb = 'RunAs'
+ }
+ if ($Quiet) {
+ $Process.StartInfo.UseShellExecute = $true
+ $Process.StartInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
+ }
+ if ($ArgumentList.Length -gt 0) {
+ # Remove existing double quotes and split arguments
+ # '(?<=(? '$filename')$(if ($shim_app) { ' installed from ' + $shim_app })"
+}
- if($arg) {
- write-output "`$args = '$($arg -join "', '")', `$args" | out-file $shim -encoding utf8 -append
- }
- write-output 'if($myinvocation.expectingInput) { $input | & $path @args } else { & $path @args }' | out-file $shim -encoding utf8 -append
+function shim($path, $global, $name, $arg) {
+ if (!(Test-Path $path)) { abort "Can't shim '$(fname $path)': couldn't find '$path'." }
+ $abs_shimdir = ensure (shimdir $global)
+ Add-Path -Path $abs_shimdir -Global:$global
+ if (!$name) { $name = strip_ext (fname $path) }
- if($path -match '\.exe$') {
+ $shim = "$abs_shimdir\$($name.tolower())"
+
+ # convert to relative path
+ $resolved_path = Convert-Path $path
+ Push-Location $abs_shimdir
+ $relative_path = Resolve-Path -Relative $resolved_path
+ Pop-Location
+
+ if ($path -match '\.(exe|com)$') {
# for programs with no awareness of any shell
- $shim_exe = "$(strip_ext($shim)).shim"
- cp "$(versiondir 'scoop' 'current')\supporting\shimexe\shim.exe" "$(strip_ext($shim)).exe" -force
- write-output "path = $(resolve-path $path)" | out-file $shim_exe -encoding utf8
- if($arg) {
- write-output "args = $arg" | out-file $shim_exe -encoding utf8 -append
+ warn_on_overwrite "$shim.shim" $path
+ Copy-Item (get_shim_path) "$shim.exe" -Force
+ Write-Output "path = `"$resolved_path`"" | Out-UTF8File "$shim.shim"
+ if ($arg) {
+ Write-Output "args = $arg" | Out-UTF8File "$shim.shim" -Append
+ }
+
+ $target_subsystem = Get-PESubsystem $resolved_path
+ if ($target_subsystem -eq 2) { # we only want to make shims GUI
+ Write-Output "Making $shim.exe a GUI binary."
+ Set-PESubsystem "$shim.exe" $target_subsystem | Out-Null
}
- } elseif($path -match '\.((bat)|(cmd))$') {
+ } elseif ($path -match '\.(bat|cmd)$') {
# shim .bat, .cmd so they can be used by programs with no awareness of PSH
- $shim_cmd = "$(strip_ext($shim)).cmd"
- "@`"$(resolve-path $path)`" $arg %*" | out-file $shim_cmd -encoding ascii
- } elseif($path -match '\.ps1$') {
+ warn_on_overwrite "$shim.cmd" $path
+ @(
+ "@rem $resolved_path",
+ "@`"$resolved_path`" $arg %*"
+ ) -join "`r`n" | Out-UTF8File "$shim.cmd"
+
+ warn_on_overwrite $shim $path
+ @(
+ "#!/bin/sh",
+ "# $resolved_path",
+ "MSYS2_ARG_CONV_EXCL=/C cmd.exe /C `"$resolved_path`" $arg `"$@`""
+ ) -join "`n" | Out-UTF8File $shim -NoNewLine
+ } elseif ($path -match '\.ps1$') {
+ # if $path points to another drive resolve-path prepends .\ which could break shims
+ warn_on_overwrite "$shim.ps1" $path
+ $ps1text = if ($relative_path -match '^(\.\\)?\w:.*$') {
+ @(
+ "# $resolved_path",
+ "`$path = `"$path`"",
+ "if (`$MyInvocation.ExpectingInput) { `$input | & `$path $arg @args } else { & `$path $arg @args }",
+ "exit `$LASTEXITCODE"
+ )
+ } else {
+ @(
+ "# $resolved_path",
+ "`$path = Join-Path `$PSScriptRoot `"$relative_path`"",
+ "if (`$MyInvocation.ExpectingInput) { `$input | & `$path $arg @args } else { & `$path $arg @args }",
+ "exit `$LASTEXITCODE"
+ )
+ }
+ $ps1text -join "`r`n" | Out-UTF8File "$shim.ps1"
+
# make ps1 accessible from cmd.exe
- $shim_cmd = "$(strip_ext($shim)).cmd"
+ warn_on_overwrite "$shim.cmd" $path
+ @(
+ "@rem $resolved_path",
+ "@echo off",
+ "where /q pwsh.exe",
+ "if %errorlevel% equ 0 (",
+ " pwsh -noprofile -ex unrestricted -file `"$resolved_path`" $arg %*",
+ ") else (",
+ " powershell -noprofile -ex unrestricted -file `"$resolved_path`" $arg %*",
+ ")"
+ ) -join "`r`n" | Out-UTF8File "$shim.cmd"
-"@echo off
-setlocal enabledelayedexpansion
-set args=%*
-:: replace problem characters in arguments
-set args=%args:`"='%
-set args=%args:(=``(%
-set args=%args:)=``)%
-set invalid=`"='
-if !args! == !invalid! ( set args= )
-powershell -noprofile -ex unrestricted `"& '$(resolve-path $path)' %args%;exit `$lastexitcode`"" | out-file $shim_cmd -encoding ascii
- }
-}
+ warn_on_overwrite $shim $path
+ @(
+ "#!/bin/sh",
+ "# $resolved_path",
+ "if command -v pwsh.exe > /dev/null 2>&1; then",
+ " pwsh.exe -noprofile -ex unrestricted -file `"$resolved_path`" $arg `"$@`"",
+ "else",
+ " powershell.exe -noprofile -ex unrestricted -file `"$resolved_path`" $arg `"$@`"",
+ "fi"
+ ) -join "`n" | Out-UTF8File $shim -NoNewLine
+ } elseif ($path -match '\.jar$') {
+ warn_on_overwrite "$shim.cmd" $path
+ @(
+ "@rem $resolved_path",
+ "@pushd $(Split-Path $resolved_path -Parent)",
+ "@java -jar `"$resolved_path`" $arg %*",
+ "@popd"
+ ) -join "`r`n" | Out-UTF8File "$shim.cmd"
-function ensure_in_path($dir, $global) {
- $path = env 'PATH' $global
- $dir = fullpath $dir
- if($path -notmatch [regex]::escape($dir)) {
- write-output "Adding $(friendly_path $dir) to $(if($global){'global'}else{'your'}) path."
+ warn_on_overwrite $shim $path
+ @(
+ "#!/bin/sh",
+ "# $resolved_path",
+ "if [ `$WSL_INTEROP ]",
+ 'then',
+ " cd `$(wslpath -u '$(Split-Path $resolved_path -Parent)')",
+ 'else',
+ " cd `$(cygpath -u '$(Split-Path $resolved_path -Parent)')",
+ 'fi',
+ "java.exe -jar `"$resolved_path`" $arg `"$@`""
+ ) -join "`n" | Out-UTF8File $shim -NoNewLine
+ } elseif ($path -match '\.py$') {
+ warn_on_overwrite "$shim.cmd" $path
+ @(
+ "@rem $resolved_path",
+ "@python `"$resolved_path`" $arg %*"
+ ) -join "`r`n" | Out-UTF8File "$shim.cmd"
- env 'PATH' $global "$dir;$path" # for future sessions...
- $env:PATH = "$dir;$env:PATH" # for this session
- }
-}
+ warn_on_overwrite $shim $path
+ @(
+ '#!/bin/sh',
+ "# $resolved_path",
+ "python.exe `"$resolved_path`" $arg `"$@`""
+ ) -join "`n" | Out-UTF8File $shim -NoNewLine
+ } else {
+ warn_on_overwrite "$shim.cmd" $path
+ $quoted_arg = if ($arg.Count -gt 0) { $arg | ForEach-Object { "`"$_`"" } }
+ @(
+ "@rem $resolved_path",
+ '@echo off',
+ 'bash -c "command -v wslpath >/dev/null"',
+ 'if %errorlevel% equ 0 (',
+ " bash `"`$(wslpath -u '$resolved_path')`" $quoted_arg %*",
+ ') else (',
+ " set args=$quoted_arg %*",
+ ' setlocal enabledelayedexpansion',
+ ' if not "!args!"=="" set args=!args:"=""!',
+ " bash -c `"`$(cygpath -u '$resolved_path') !args!`"",
+ ')'
+ ) -join "`r`n" | Out-UTF8File "$shim.cmd"
-function ensure_architecture($architecture_opt) {
- switch($architecture_opt) {
- '' { return default_architecture }
- { @('32bit','64bit') -contains $_ } { return $_ }
- default { abort "Invalid architecture: '$architecture'."}
+ warn_on_overwrite $shim $path
+ @(
+ '#!/bin/sh',
+ "# $resolved_path",
+ "if [ `$WSL_INTEROP ]",
+ 'then',
+ " `"`$(wslpath -u '$resolved_path')`" $arg `"$@`"",
+ 'else',
+ " `"`$(cygpath -u '$resolved_path')`" $arg `"$@`"",
+ 'fi'
+ ) -join "`n" | Out-UTF8File $shim -NoNewLine
}
}
-function strip_path($orig_path, $dir) {
- $stripped = [string]::join(';', @( $orig_path.split(';') | ? { $_ -and $_ -ne $dir } ))
- return ($stripped -ne $orig_path), $stripped
+function get_shim_path() {
+ $shim_version = get_config SHIM 'kiennq'
+ $shim_path = switch ($shim_version) {
+ 'scoopcs' { "$(versiondir 'scoop' 'current')\supporting\shims\scoopcs\shim.exe" }
+ '71' { "$(versiondir 'scoop' 'current')\supporting\shims\71\shim.exe" }
+ 'kiennq' { "$(versiondir 'scoop' 'current')\supporting\shims\kiennq\shim.exe" }
+ 'default' { "$(versiondir 'scoop' 'current')\supporting\shims\scoopcs\shim.exe" }
+ default { warn "Unknown shim version: '$shim_version'" }
+ }
+ return $shim_path
}
-function remove_from_path($dir,$global) {
- $dir = fullpath $dir
-
- # future sessions
- $was_in_path, $newpath = strip_path (env 'path' $global) $dir
- if($was_in_path) {
- write-output "Removing $(friendly_path $dir) from your path."
- env 'path' $global $newpath
+function Get-DefaultArchitecture {
+ $arch = get_config DEFAULT_ARCHITECTURE
+ $system = if (${env:ProgramFiles(Arm)}) {
+ 'arm64'
+ } elseif ([System.Environment]::Is64BitOperatingSystem) {
+ '64bit'
+ } else {
+ '32bit'
}
-
- # current session
- $was_in_path, $newpath = strip_path $env:PATH $dir
- if($was_in_path) { $env:PATH = $newpath }
+ 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 ensure_scoop_in_path($global) {
- $abs_shimdir = ensure (shimdir $global)
- # be aggressive (b-e-aggressive) and install scoop first in the path
- ensure_in_path $abs_shimdir $global
+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'" }
+ }
}
-function ensure_robocopy_in_path {
- if(!(gcm robocopy -ea ignore)) {
- shim "C:\Windows\System32\Robocopy.exe" $false
+function Confirm-InstallationStatus {
+ [CmdletBinding()]
+ [OutputType([Object[]])]
+ param(
+ [Parameter(Mandatory = $true)]
+ [String[]]
+ $Apps,
+ [Switch]
+ $Global
+ )
+ $Installed = @()
+ $Apps | Select-Object -Unique | Where-Object { $_ -ne 'scoop' } | ForEach-Object {
+ $App, $null, $null = parse_app $_
+ if ($Global) {
+ if (Test-Path (appdir $App $true)) {
+ $Installed += , @($App, $true)
+ } elseif (Test-Path (appdir $App $false)) {
+ error "'$App' isn't installed globally, but it may be installed locally."
+ warn "Try again without the --global (or -g) flag instead."
+ } else {
+ error "'$App' isn't installed."
+ }
+ } else {
+ if (Test-Path (appdir $App $false)) {
+ $Installed += , @($App, $false)
+ } elseif (Test-Path (appdir $App $true)) {
+ error "'$App' isn't installed locally, but it may be installed globally."
+ warn "Try again with the --global (or -g) flag instead."
+ } else {
+ error "'$App' isn't installed."
+ }
+ }
+ if (failed $App $Global) {
+ error "'$App' isn't installed correctly."
+ }
}
+ return , $Installed
}
function wraptext($text, $width) {
- if(!$width) { $width = $host.ui.rawui.windowsize.width };
+ if(!$width) { $width = $host.ui.rawui.buffersize.width };
$width -= 1 # be conservative: doesn't seem to print the last char
- $text -split '\r?\n' | % {
+ $text -split '\r?\n' | ForEach-Object {
$line = ''
- $_ -split ' ' | % {
+ $_ -split ' ' | ForEach-Object {
if($line.length -eq 0) { $line = $_ }
elseif($line.length + $_.length + 1 -le $width) { $line += " $_" }
else { $lines += ,$line; $line = $_ }
@@ -290,109 +1141,171 @@ function pluralize($count, $singular, $plural) {
if($count -eq 1) { $singular } else { $plural }
}
-# for dealing with user aliases
-$default_aliases = @{
- 'cp' = 'copy-item'
- 'echo' = 'write-output'
- 'gc' = 'get-content'
- 'gci' = 'get-childitem'
- 'gcm' = 'get-command'
- 'gm' = 'get-member'
- 'iex' = 'invoke-expression'
- 'ls' = 'get-childitem'
- 'mkdir' = { new-item -type directory @args }
- 'mv' = 'move-item'
- 'rm' = 'remove-item'
- 'sc' = 'set-content'
- 'select' = 'select-object'
- 'sls' = 'select-string'
-}
-
-function reset_alias($name, $value) {
- if($existing = get-alias $name -ea ignore |? { $_.options -match 'readonly' }) {
- if($existing.definition -ne $value) {
- write-host "Alias $name is read-only; can't reset it." -f darkyellow
- }
- return # already set
+# convert list of apps to list of ($app, $global) tuples
+function applist($apps, $global) {
+ if(!$apps) { return @() }
+ return ,@($apps | ForEach-Object { ,@($_, $global) })
+}
+
+function parse_app([string]$app) {
+ if ($app -match '^(?:(?[a-zA-Z0-9-_.]+)/)?(?.*\.json|[a-zA-Z0-9-_.]+)(?:@(?.*))?$') {
+ return $Matches['app'], $Matches['bucket'], $Matches['version']
+ } else {
+ return $app, $null, $null
}
- if($value -is [scriptblock]) {
- new-item -path function: -name "script:$name" -value $value | out-null
- return
+}
+
+function show_app($app, $bucket, $version) {
+ if($bucket) {
+ $app = "$bucket/$app"
+ }
+ if($version) {
+ $app = "$app@$version"
}
+ return $app
+}
- set-alias $name $value -scope script -option allscope
+function is_scoop_outdated() {
+ $now = [System.DateTime]::Now
+ 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
+ }
}
-function reset_aliases() {
- # for aliases where there's a local function, re-alias so the function takes precedence
- $aliases = get-alias |? { $_.options -notmatch 'readonly|allscope' } |% { $_.name }
- get-childitem function: | % {
- $fn = $_.name
- if($aliases -contains $fn) {
- set-alias $fn local:$fn -scope script
+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 /'."
}
-
- # set default aliases
- $default_aliases.keys | % { reset_alias $_ $default_aliases[$_] }
+ set_config HOLD_UPDATE_UNTIL $null | Out-Null
+ return $false
}
-function app($app) {
- $app = [string]$app
- if($app -notmatch '^((ht)|f)tps?://') {
- if($app -match '([a-zA-Z0-9-]+)/([a-zA-Z0-9-]+)') {
- return $matches[2], $matches[1]
+function substitute($entity, [Hashtable] $params, [Bool]$regexEscape = $false) {
+ if ($null -ne $entity) {
+ $newentity = $entity.PSObject.Copy()
+ switch ($entity.GetType().Name) {
+ 'String' {
+ $params.GetEnumerator() | ForEach-Object {
+ if ($regexEscape -eq $false -or $null -eq $_.Value) {
+ $newentity = $newentity.Replace($_.Name, $_.Value)
+ } else {
+ $newentity = $newentity.Replace($_.Name, [Regex]::Escape($_.Value))
+ }
+ }
+ }
+ 'Object[]' {
+ $newentity = $entity | ForEach-Object { , (substitute $_ $params $regexEscape) }
+ }
+ 'PSCustomObject' {
+ $newentity.PSObject.Properties | ForEach-Object { $_.Value = substitute $_.Value $params $regexEscape }
+ }
}
}
-
- $app, $null
+ return $newentity
}
-function is_app_with_specific_version([String] $app) {
- $appWithVersion = get_app_with_version $app
- $appWithVersion.version -ne 'latest'
+function Out-UTF8File {
+ param(
+ [Parameter(Mandatory = $True, Position = 0)]
+ [Alias("Path")]
+ [String] $FilePath,
+ [Switch] $Append,
+ [Switch] $NoNewLine,
+ [Parameter(ValueFromPipeline = $True)]
+ [PSObject] $InputObject
+ )
+ process {
+ if ($Append) {
+ [System.IO.File]::AppendAllText($FilePath, $InputObject)
+ } else {
+ if (!$NoNewLine) {
+ # Ref: https://stackoverflow.com/questions/5596982
+ # Performance Note: `WriteAllLines` throttles memory usage while
+ # `WriteAllText` needs to keep the complete string in memory.
+ [System.IO.File]::WriteAllLines($FilePath, $InputObject)
+ } else {
+ # However `WriteAllText` does not add ending newline.
+ [System.IO.File]::WriteAllText($FilePath, $InputObject)
+ }
+ }
+ }
}
-function get_app_with_version([String] $app) {
- $segments = $app -split '@'
- $name = $segments[0]
- $version = $segments[1];
+##################
+# Core Bootstrap #
+##################
- return @{
- "app" = $name;
- "version" = if ($version) { $version } else { 'latest' }
- }
-}
+# Note: Github disabled TLS 1.0 support on 2018-02-23. Need to enable TLS 1.2
+# for all communication with api.github.com
+Optimize-SecurityProtocol
-function substitute([String] $str, [Hashtable] $params) {
- $params.GetEnumerator() | % {
- $str = $str.Replace($_.Name, $_.Value)
+# Load Scoop config
+$configHome = $env:XDG_CONFIG_HOME, "$env:USERPROFILE\.config" | Select-Object -First 1
+$configFile = "$configHome\scoop\config.json"
+# Check if it's the expected install path for scoop: /apps/scoop/current
+$coreRoot = Split-Path $PSScriptRoot
+$pathExpected = ($coreRoot -replace '\\','/') -like '*apps/scoop/current*'
+if ($pathExpected) {
+ # Portable config is located in root directory:
+ # .\current\scoop\apps\\config.json <- a reversed path
+ # Imagine `/apps/scoop/current/` in a reversed format,
+ # and the directory tree:
+ #
+ # ```
+ # :
+ # ├─apps
+ # ├─buckets
+ # ├─cache
+ # ├─persist
+ # ├─shims
+ # ├─config.json
+ # ```
+ $configPortablePath = Get-AbsolutePath "$coreRoot\..\..\..\config.json"
+ if (Test-Path $configPortablePath) {
+ $configFile = $configPortablePath
}
- return $str
}
+$scoopConfig = load_cfg $configFile
-function format_hash([String] $hash) {
- switch ($hash.Length)
- {
- 32 { $hash = "md5:$hash" } # md5
- 40 { $hash = "sha1:$hash" } # sha1
- 64 { $hash = $hash } # sha256
- 128 { $hash = "sha512:$hash" } # sha512
- default { $hash = $null }
- }
- return $hash
-}
+# Scoop root directory
+$scoopdir = $env:SCOOP, (get_config ROOT_PATH), "$PSScriptRoot\..\..\..\..", "$([System.Environment]::GetFolderPath('UserProfile'))\scoop" | Where-Object { $_ } | Select-Object -First 1 | Get-AbsolutePath
-function handle_special_urls($url)
-{
- # FossHub.com
- if($url -match "^(.*fosshub.com\/)(?.*)\/(?.*)$") {
- # create an url to request to request the expiring url
- $name = $matches['name'] -replace '.html',''
- $filename = $matches['filename']
- # the key is a random 24 chars long hex string, so lets use ' SCOOPSCOOP ' :)
- $url = "https://www.fosshub.com/gensLink/$name/$filename/2053434f4f5053434f4f5020"
- $url = (Invoke-WebRequest -Uri $url | Select-Object -ExpandProperty Content)
- }
- return $url
+# Scoop global apps directory
+$globaldir = $env:SCOOP_GLOBAL, (get_config GLOBAL_PATH), "$([System.Environment]::GetFolderPath('CommonApplicationData'))\scoop" | Where-Object { $_ } | Select-Object -First 1 | Get-AbsolutePath
+
+# 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 CACHE_PATH), "$scoopdir\cache" | Where-Object { $_ } | Select-Object -First 1 | Get-AbsolutePath
+
+# Scoop apps' PATH Environment Variable
+$scoopPathEnvVar = switch (get_config USE_ISOLATED_PATH) {
+ { $_ -is [string] } { $_.ToUpperInvariant() }
+ $true { 'SCOOP_PATH' }
+ default { 'PATH' }
}
+
+# OS information
+$WindowsBuild = [System.Environment]::OSVersion.Version.Build
diff --git a/lib/database.ps1 b/lib/database.ps1
new file mode 100644
index 0000000000..912db11c31
--- /dev/null
+++ b/lib/database.ps1
@@ -0,0 +1,390 @@
+# Description: Functions for interacting with the Scoop database cache
+
+<#
+.SYNOPSIS
+ Get SQLite .NET driver
+.DESCRIPTION
+ Download and extract the SQLite .NET driver from NuGet.
+.PARAMETER Version
+ System.String
+ The version of the SQLite .NET driver to download.
+.INPUTS
+ None
+.OUTPUTS
+ System.Boolean
+ True if the SQLite .NET driver was successfully downloaded and extracted, otherwise false.
+#>
+function Get-SQLite {
+ param (
+ [string]$Version = '1.0.118'
+ )
+ # Install SQLite
+ try {
+ Write-Host "Downloading SQLite $Version..." -ForegroundColor DarkYellow
+ $sqlitePkgPath = "$env:TEMP\sqlite.zip"
+ $sqliteTempPath = "$env:TEMP\sqlite"
+ $sqlitePath = "$PSScriptRoot\..\supporting\sqlite"
+ Invoke-WebRequest -Uri "https://api.nuget.org/v3-flatcontainer/stub.system.data.sqlite.core.netframework/$version/stub.system.data.sqlite.core.netframework.$version.nupkg" -OutFile $sqlitePkgPath
+ Write-Host "Extracting SQLite $Version..." -ForegroundColor DarkYellow -NoNewline
+ Expand-Archive -Path $sqlitePkgPath -DestinationPath $sqliteTempPath -Force
+ New-Item -Path $sqlitePath -ItemType Directory -Force | Out-Null
+ Move-Item -Path "$sqliteTempPath\build\net451\*", "$sqliteTempPath\lib\net451\System.Data.SQLite.dll" -Destination $sqlitePath -Force
+ Remove-Item -Path $sqlitePkgPath, $sqliteTempPath -Recurse -Force
+ Write-Host ' Done' -ForegroundColor DarkYellow
+ return $true
+ } catch {
+ return $false
+ }
+}
+
+<#
+.SYNOPSIS
+ Open Scoop SQLite database.
+.DESCRIPTION
+ Open Scoop SQLite database connection and create the necessary tables if not exists.
+.INPUTS
+ None
+.OUTPUTS
+ System.Data.SQLite.SQLiteConnection
+ The SQLite database connection if **PassThru** is used.
+#>
+function Open-ScoopDB {
+ # Load System.Data.SQLite
+ if (!('System.Data.SQLite.SQLiteConnection' -as [Type])) {
+ try {
+ if (!(Test-Path -Path "$PSScriptRoot\..\supporting\sqlite\System.Data.SQLite.dll")) {
+ Get-SQLite | Out-Null
+ }
+ Add-Type -Path "$PSScriptRoot\..\supporting\sqlite\System.Data.SQLite.dll"
+ } catch {
+ throw "Scoop's Database cache requires the ADO.NET driver:`n`thttp://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki"
+ }
+ }
+ $dbPath = Join-Path $scoopdir 'scoop.db'
+ $db = New-Object -TypeName System.Data.SQLite.SQLiteConnection
+ $db.ConnectionString = "Data Source=$dbPath"
+ $db.ParseViaFramework = $true # Allow UNC path
+ $db.Open()
+ $tableCommand = $db.CreateCommand()
+ $tableCommand.CommandText = "CREATE TABLE IF NOT EXISTS 'app' (
+ name TEXT NOT NULL COLLATE NOCASE,
+ description TEXT NOT NULL,
+ version TEXT NOT NULL,
+ bucket VARCHAR NOT NULL,
+ manifest JSON NOT NULL,
+ binary TEXT,
+ shortcut TEXT,
+ dependency TEXT,
+ suggest TEXT,
+ PRIMARY KEY (name, version, bucket)
+ )"
+ $tableCommand.CommandType = [System.Data.CommandType]::Text
+ $tableCommand.ExecuteNonQuery() | Out-Null
+ $tableCommand.Dispose()
+ return $db
+}
+
+<#
+.SYNOPSIS
+ Set Scoop database item(s).
+.DESCRIPTION
+ Insert or replace item(s) into the Scoop SQLite database.
+.PARAMETER InputObject
+ System.Object[]
+ The database item(s) to insert or replace.
+.INPUTS
+ System.Object[]
+.OUTPUTS
+ None
+#>
+function Set-ScoopDBItem {
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory, Position = 0, ValueFromPipeline)]
+ [psobject[]]
+ $InputObject
+ )
+
+ begin {
+ $db = Open-ScoopDB
+ $dbTrans = $db.BeginTransaction()
+ # TODO Support [hashtable]$InputObject
+ $colName = @($InputObject | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name)
+ $dbQuery = "INSERT OR REPLACE INTO app ($($colName -join ', ')) VALUES ($('@' + ($colName -join ', @')))"
+ $dbCommand = $db.CreateCommand()
+ $dbCommand.CommandText = $dbQuery
+ $dbCommand.CommandType = [System.Data.CommandType]::Text
+ }
+ process {
+ foreach ($item in $InputObject) {
+ $item.PSObject.Properties | ForEach-Object {
+ $dbCommand.Parameters.AddWithValue("@$($_.Name)", $_.Value) | Out-Null
+ }
+ $dbCommand.ExecuteNonQuery() | Out-Null
+ }
+ }
+ end {
+ try {
+ $dbTrans.Commit()
+ } catch {
+ $dbTrans.Rollback()
+ throw $_
+ } finally {
+ $dbCommand.Dispose()
+ $dbTrans.Dispose()
+ $db.Dispose()
+ }
+ }
+}
+
+<#
+.SYNOPSIS
+ Set Scoop app database item(s).
+.DESCRIPTION
+ Insert or replace Scoop app(s) into the database.
+.PARAMETER Path
+ System.String
+ The path to the bucket.
+.PARAMETER CommitHash
+ System.String
+ The commit hash to compare with the HEAD.
+.INPUTS
+ None
+.OUTPUTS
+ None
+#>
+function Set-ScoopDB {
+ [CmdletBinding()]
+ param (
+ [Parameter(Position = 0, ValueFromPipeline)]
+ [string[]]
+ $Path
+ )
+
+ begin {
+ $list = [System.Collections.Generic.List[psobject]]::new()
+ $arch = Get-DefaultArchitecture
+ }
+ process {
+ if ($Path.Count -eq 0) {
+ $bucketPath = Get-LocalBucket | ForEach-Object { Find-BucketDirectory $_ }
+ $Path = (Get-ChildItem $bucketPath -Filter '*.json' -Recurse).FullName
+ }
+ $Path | ForEach-Object {
+ $manifestRaw = [System.IO.File]::ReadAllText($_)
+ $manifest = ConvertFrom-Json $manifestRaw -ErrorAction SilentlyContinue
+ if ($null -ne $manifest.version) {
+ $list.Add([pscustomobject]@{
+ name = $($_ -replace '.*[\\/]([^\\/]+)\.json$', '$1')
+ description = if ($manifest.description) { $manifest.description } else { '' }
+ version = $manifest.version
+ bucket = $($_ -replace '.*buckets[\\/]([^\\/]+)(?:[\\/].*)', '$1')
+ manifest = $manifestRaw
+ binary = $(
+ $result = @()
+ @(arch_specific 'bin' $manifest $arch) | ForEach-Object {
+ if ($_ -is [System.Array]) {
+ $result += "$($_[1]).$($_[0].Split('.')[-1])"
+ } else {
+ $result += $_
+ }
+ }
+ $result -replace '.*?([^\\/]+)?(\.(exe|bat|cmd|ps1|jar|py))$', '$1' -join ' | '
+ )
+ shortcut = $(
+ $result = @()
+ @(arch_specific 'shortcuts' $manifest $arch) | ForEach-Object {
+ $result += $_[1]
+ }
+ $result -replace '.*?([^\\/]+$)', '$1' -join ' | '
+ )
+ dependency = $manifest.depends -join ' | '
+ suggest = $(
+ $suggest_output = @()
+ $manifest.suggest.PSObject.Properties | ForEach-Object {
+ $suggest_output += $_.Value -join ' | '
+ }
+ $suggest_output -join ' | '
+ )
+ })
+ }
+ }
+ }
+ end {
+ if ($list.Count -ne 0) {
+ Set-ScoopDBItem $list
+ }
+ }
+}
+
+<#
+.SYNOPSIS
+ Select Scoop database item(s).
+.DESCRIPTION
+ Select item(s) from the Scoop SQLite database.
+ The pattern is matched against the name, binaries, and shortcuts columns for apps.
+.PARAMETER Pattern
+ System.String
+ The pattern to search for. If is an empty string, all items will be returned.
+.PARAMETER From
+ System.String[]
+ The fields to search from.
+.INPUTS
+ System.String
+.OUTPUTS
+ System.Data.DataTable
+ The selected database item(s).
+#>
+function Select-ScoopDBItem {
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory, Position = 0, ValueFromPipeline)]
+ [AllowEmptyString()]
+ [string]
+ $Pattern,
+ [Parameter(Mandatory, Position = 1)]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $From
+ )
+
+ begin {
+ $db = Open-ScoopDB
+ $dbAdapter = New-Object -TypeName System.Data.SQLite.SQLiteDataAdapter
+ $result = New-Object System.Data.DataTable
+ $dbQuery = "SELECT * FROM app WHERE $(($From -join ' LIKE @Pattern OR ') + ' LIKE @Pattern')"
+ $dbQuery = "SELECT * FROM ($($dbQuery + ' ORDER BY version DESC')) GROUP BY name, bucket"
+ $dbCommand = $db.CreateCommand()
+ $dbCommand.CommandText = $dbQuery
+ $dbCommand.CommandType = [System.Data.CommandType]::Text
+ $dbAdapter.SelectCommand = $dbCommand
+ }
+ process {
+ $dbCommand.Parameters.AddWithValue('@Pattern', $(if ($Pattern -eq '') { '%' } else { '%' + $Pattern + '%' })) | Out-Null
+ [void]$dbAdapter.Fill($result)
+ }
+ end {
+ $dbAdapter.Dispose()
+ $db.Dispose()
+ return $result
+ }
+}
+
+<#
+.SYNOPSIS
+ Get Scoop database item.
+.DESCRIPTION
+ Get item from the Scoop SQLite database.
+.PARAMETER Name
+ System.String
+ The name of the item to get.
+.PARAMETER Bucket
+ System.String
+ The bucket of the item to get.
+.PARAMETER Version
+ System.String
+ The version of the item to get. If not provided, the latest version will be returned.
+.INPUTS
+ System.String
+.OUTPUTS
+ System.Data.DataTable
+ The selected database item.
+#>
+function Get-ScoopDBItem {
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory, Position = 0, ValueFromPipeline)]
+ [string]
+ $Name,
+ [Parameter(Mandatory, Position = 1)]
+ [string]
+ $Bucket,
+ [Parameter(Position = 2)]
+ [string]
+ $Version
+ )
+
+ begin {
+ $db = Open-ScoopDB
+ $dbAdapter = New-Object -TypeName System.Data.SQLite.SQLiteDataAdapter
+ $result = New-Object System.Data.DataTable
+ $dbQuery = 'SELECT * FROM app WHERE name = @Name AND bucket = @Bucket'
+ if ($Version) {
+ $dbQuery += ' AND version = @Version'
+ } else {
+ $dbQuery += ' ORDER BY version DESC LIMIT 1'
+ }
+ $dbCommand = $db.CreateCommand()
+ $dbCommand.CommandText = $dbQuery
+ $dbCommand.CommandType = [System.Data.CommandType]::Text
+ $dbAdapter.SelectCommand = $dbCommand
+ }
+ process {
+ $dbCommand.Parameters.AddWithValue('@Name', $Name) | Out-Null
+ $dbCommand.Parameters.AddWithValue('@Bucket', $Bucket) | Out-Null
+ $dbCommand.Parameters.AddWithValue('@Version', $Version) | Out-Null
+ [void]$dbAdapter.Fill($result)
+ }
+ end {
+ $dbAdapter.Dispose()
+ $db.Dispose()
+ return $result
+ }
+}
+
+<#
+.SYNOPSIS
+ Remove Scoop database item(s).
+.DESCRIPTION
+ Remove item(s) from the Scoop SQLite database.
+.PARAMETER Name
+ System.String
+ The name of the item to remove.
+.PARAMETER Bucket
+ System.String
+ The bucket of the item to remove.
+.INPUTS
+ System.String
+.OUTPUTS
+ None
+#>
+function Remove-ScoopDBItem {
+ [CmdletBinding()]
+ param (
+ [Parameter(Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)]
+ [string]
+ $Name,
+ [Parameter(Mandatory, Position = 1, ValueFromPipelineByPropertyName)]
+ [string]
+ $Bucket
+ )
+
+ begin {
+ $db = Open-ScoopDB
+ $dbTrans = $db.BeginTransaction()
+ $dbQuery = 'DELETE FROM app WHERE bucket = @Bucket'
+ $dbCommand = $db.CreateCommand()
+ $dbCommand.CommandText = $dbQuery
+ $dbCommand.CommandType = [System.Data.CommandType]::Text
+ }
+ process {
+ $dbCommand.Parameters.AddWithValue('@Bucket', $Bucket) | Out-Null
+ if ($Name) {
+ $dbCommand.CommandText = $dbQuery + ' AND name = @Name'
+ $dbCommand.Parameters.AddWithValue('@Name', $Name) | Out-Null
+ }
+ $dbCommand.ExecuteNonQuery() | Out-Null
+ }
+ end {
+ try {
+ $dbTrans.Commit()
+ } catch {
+ $dbTrans.Rollback()
+ throw $_
+ } finally {
+ $dbCommand.Dispose()
+ $dbTrans.Dispose()
+ $db.Dispose()
+ }
+ }
+}
diff --git a/lib/decompress.ps1 b/lib/decompress.ps1
index cf85842d7c..3f174bf0c3 100644
--- a/lib/decompress.ps1
+++ b/lib/decompress.ps1
@@ -1,33 +1,354 @@
-function 7zip_installed { cmd_available '7z' }
+# Description: Functions for decompressing archives or installers
-function requires_7zip($manifest, $architecture) {
- foreach($dlurl in @(url $manifest $architecture)) {
- if(file_requires_7zip $dlurl) { return $true }
+function Invoke-Extraction {
+ param (
+ [string]
+ $Path,
+ [string[]]
+ $Name,
+ [psobject]
+ $Manifest,
+ [Alias('Arch', 'Architecture')]
+ [string]
+ $ProcessorArchitecture
+ )
+
+ $uri = @(url $Manifest $ProcessorArchitecture)
+ # 'extract_dir' and 'extract_to' are paired
+ $extractDir = @(extract_dir $Manifest $ProcessorArchitecture)
+ $extractTo = @(extract_to $Manifest $ProcessorArchitecture)
+ $extracted = 0
+
+ for ($i = 0; $i -lt $Name.Length; $i++) {
+ # work out extraction method, if applicable
+ $extractFn = $null
+ switch -regex ($Name[$i]) {
+ '\.zip$' {
+ if ((Test-HelperInstalled -Helper 7zip) -or ((get_config USE_EXTERNAL_7ZIP) -and (Test-CommandAvailable 7z))) {
+ $extractFn = 'Expand-7zipArchive'
+ } else {
+ $extractFn = 'Expand-ZipArchive'
+ }
+ continue
+ }
+ '\.msi$' {
+ $extractFn = 'Expand-MsiArchive'
+ continue
+ }
+ '\.exe$' {
+ if ($Manifest.innosetup) {
+ $extractFn = 'Expand-InnoArchive'
+ }
+ continue
+ }
+ { Test-7zipRequirement -Uri $_ } {
+ $extractFn = 'Expand-7zipArchive'
+ continue
+ }
+ }
+ if ($extractFn) {
+ $fnArgs = @{
+ Path = Join-Path $Path $Name[$i]
+ DestinationPath = Join-Path $Path $extractTo[$extracted]
+ ExtractDir = $extractDir[$extracted]
+ }
+ Write-Host 'Extracting ' -NoNewline
+ Write-Host $(url_remote_filename $uri[$i]) -ForegroundColor Cyan -NoNewline
+ Write-Host ' ... ' -NoNewline
+ & $extractFn @fnArgs -Removal
+ Write-Host 'done.' -ForegroundColor Green
+ $extracted++
+ }
}
}
-function requires_lessmsi ($manifest, $architecture) {
- $useLessMsi = get_config MSIEXTRACT_USE_LESSMSI
- if (!$useLessMsi) { return $false }
+function Expand-7zipArchive {
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
+ [String]
+ $Path,
+ [Parameter(Position = 1)]
+ [String]
+ $DestinationPath = (Split-Path $Path),
+ [String]
+ $ExtractDir,
+ [Parameter(ValueFromRemainingArguments = $true)]
+ [String]
+ $Switches,
+ [ValidateSet('All', 'Skip', 'Rename')]
+ [String]
+ $Overwrite,
+ [Switch]
+ $Removal
+ )
+ 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 '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"
+ $DestinationPath = $DestinationPath.TrimEnd('\')
+ $ArgList = @('x', $Path, "-o$DestinationPath", '-xr!*.nsis', '-y')
+ $IsTar = ((strip_ext $Path) -match '\.tar$') -or ($Path -match '\.t[abgpx]z2?$')
+ if (!$IsTar -and $ExtractDir) {
+ $ArgList += "-ir!$ExtractDir\*"
+ }
+ if ($Switches) {
+ $ArgList += (-split $Switches)
+ }
+ switch ($Overwrite) {
+ 'All' { $ArgList += '-aoa' }
+ 'Skip' { $ArgList += '-aos' }
+ 'Rename' { $ArgList += '-aou' }
+ }
+ $Status = Invoke-ExternalCommand $7zPath $ArgList -LogPath $LogPath
+ if (!$Status) {
+ abort "Failed to extract files from $Path.`nLog file:`n $(friendly_path $LogPath)`n$(new_issue_msg $app $bucket 'decompress error')"
+ }
+ if ($IsTar) {
+ # Check for tar
+ $Status = Invoke-ExternalCommand $7zPath @('l', $Path) -LogPath $LogPath
+ if ($Status) {
+ # get inner tar file name
+ $TarFile = (Select-String -Path $LogPath -Pattern '[^ ]*tar$').Matches.Value
+ Expand-7zipArchive -Path "$DestinationPath\$TarFile" -DestinationPath $DestinationPath -ExtractDir $ExtractDir -Removal
+ } else {
+ abort "Failed to list files in $Path.`nNot a 7-Zip supported archive file."
+ }
+ }
+ if (!$IsTar -and $ExtractDir) {
+ movedir "$DestinationPath\$ExtractDir" $DestinationPath | Out-Null
+ # Remove temporary directory if it is empty
+ $ExtractDirTopPath = [string] "$DestinationPath\$($ExtractDir -replace '[\\/].*')"
+ if ((Get-ChildItem -Path $ExtractDirTopPath -Force -ErrorAction Ignore).Count -eq 0) {
+ Remove-Item -Path $ExtractDirTopPath -Recurse -Force -ErrorAction Ignore
+ }
+ }
+ if (Test-Path $LogPath) {
+ Remove-Item $LogPath -Force
+ }
+ if ($Removal) {
+ if (($Path -replace '.*\.([^\.]*)$', '$1') -eq '001') {
+ # Remove splitted 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 original archive file
+ Remove-Item $Path -Force
+ }
+ }
+}
- $(url $manifest $architecture |? {
- $_ -match '\.(msi)$'
- } | measure | select -exp count) -gt 0
+function Expand-ZstdArchive {
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
+ [String]
+ $Path,
+ [Parameter(Position = 1)]
+ [String]
+ $DestinationPath = (Split-Path $Path),
+ [String]
+ $ExtractDir,
+ [Parameter(ValueFromRemainingArguments = $true)]
+ [String]
+ $Switches,
+ [Switch]
+ $Removal
+ )
+ # TODO: Remove this function after 2024/12/31
+ Show-DeprecatedWarning $MyInvocation 'Expand-7zipArchive'
+ Expand-7zipArchive -Path $Path -DestinationPath $DestinationPath -ExtractDir $ExtractDir -Switches $Switches -Removal:$Removal
}
-function file_requires_7zip($fname) {
- $fname -match '\.((gz)|(tar)|(tgz)|(lzma)|(bz)|(7z)|(rar)|(iso)|(xz)|(lzh))$'
+function Expand-MsiArchive {
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
+ [String]
+ $Path,
+ [Parameter(Position = 1)]
+ [String]
+ $DestinationPath = (Split-Path $Path),
+ [String]
+ $ExtractDir,
+ [Parameter(ValueFromRemainingArguments = $true)]
+ [String]
+ $Switches,
+ [Switch]
+ $Removal
+ )
+ $DestinationPath = $DestinationPath.TrimEnd('\')
+ if ($ExtractDir) {
+ $OriDestinationPath = $DestinationPath
+ $DestinationPath = "$DestinationPath\_tmp"
+ }
+ if ((get_config USE_LESSMSI)) {
+ $MsiPath = Get-HelperPath -Helper Lessmsi
+ $ArgList = @('x', $Path, "$DestinationPath\")
+ } else {
+ $MsiPath = 'msiexec.exe'
+ $ArgList = @('/a', $Path, '/qn', "TARGETDIR=$DestinationPath\SourceDir")
+ }
+ $LogPath = "$(Split-Path $Path)\msi.log"
+ if ($Switches) {
+ $ArgList += (-split $Switches)
+ }
+ $Status = Invoke-ExternalCommand $MsiPath $ArgList -LogPath $LogPath
+ if (!$Status) {
+ abort "Failed to extract files from $Path.`nLog file:`n $(friendly_path $LogPath)`n$(new_issue_msg $app $bucket 'decompress error')"
+ }
+ if ($ExtractDir -and (Test-Path "$DestinationPath\SourceDir")) {
+ movedir "$DestinationPath\SourceDir\$ExtractDir" $OriDestinationPath | Out-Null
+ Remove-Item $DestinationPath -Recurse -Force
+ } elseif ($ExtractDir) {
+ movedir "$DestinationPath\$ExtractDir" $OriDestinationPath | Out-Null
+ Remove-Item $DestinationPath -Recurse -Force
+ } elseif (Test-Path "$DestinationPath\SourceDir") {
+ movedir "$DestinationPath\SourceDir" $DestinationPath | Out-Null
+ }
+ if (($DestinationPath -ne (Split-Path $Path)) -and (Test-Path "$DestinationPath\$(fname $Path)")) {
+ Remove-Item "$DestinationPath\$(fname $Path)" -Force
+ }
+ if (Test-Path $LogPath) {
+ Remove-Item $LogPath -Force
+ }
+ if ($Removal) {
+ # Remove original archive file
+ Remove-Item $Path -Force
+ }
}
-function extract_7zip($path, $to, $recurse) {
- $output = 7z x "$path" -o"$to" -y
- if($lastexitcode -ne 0) { abort "Exit code was $lastexitcode." }
+function Expand-InnoArchive {
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
+ [String]
+ $Path,
+ [Parameter(Position = 1)]
+ [String]
+ $DestinationPath = (Split-Path $Path),
+ [String]
+ $ExtractDir,
+ [Parameter(ValueFromRemainingArguments = $true)]
+ [String]
+ $Switches,
+ [Switch]
+ $Removal
+ )
+ $LogPath = "$(Split-Path $Path)\innounp.log"
+ $ArgList = @('-x', "-d$DestinationPath", $Path, '-y')
+ switch -Regex ($ExtractDir) {
+ '^[^{].*' { $ArgList += "-c{app}\$ExtractDir" }
+ '^{.*' { $ArgList += "-c$ExtractDir" }
+ Default { $ArgList += '-c{app}' }
+ }
+ if ($Switches) {
+ $ArgList += (-split $Switches)
+ }
+ $Status = Invoke-ExternalCommand (Get-HelperPath -Helper Innounp) $ArgList -LogPath $LogPath
+ if (!$Status) {
+ abort "Failed to extract files from $Path.`nLog file:`n $(friendly_path $LogPath)`n$(new_issue_msg $app $bucket 'decompress error')"
+ }
+ if (Test-Path $LogPath) {
+ Remove-Item $LogPath -Force
+ }
+ if ($Removal) {
+ # Remove original archive file
+ Remove-Item $Path -Force
+ }
+}
+
+function Expand-ZipArchive {
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
+ [String]
+ $Path,
+ [Parameter(Position = 1)]
+ [String]
+ $DestinationPath = (Split-Path $Path),
+ [String]
+ $ExtractDir,
+ [Switch]
+ $Removal
+ )
+ if ($ExtractDir) {
+ $OriDestinationPath = $DestinationPath
+ $DestinationPath = "$DestinationPath\_tmp"
+ }
+ # Disable progress bar to gain performance
+ $oldProgressPreference = $ProgressPreference
+ $global:ProgressPreference = 'SilentlyContinue'
+
+ # 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
- # check for tar
- $tar = (split-path $path -leaf) -replace '\.[^\.]*$', ''
- if($tar -match '\.tar$') {
- if(test-path "$to\$tar") { extract_7zip "$to\$tar" $to $true }
+ $global:ProgressPreference = $oldProgressPreference
+ if ($ExtractDir) {
+ movedir "$DestinationPath\$ExtractDir" $OriDestinationPath | Out-Null
+ Remove-Item $DestinationPath -Recurse -Force
+ }
+ if ($Removal) {
+ # Remove original archive file
+ Remove-Item $Path -Force
}
+}
- if($recurse) { rm $path } # clean up intermediate files
+function Expand-DarkArchive {
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
+ [String]
+ $Path,
+ [Parameter(Position = 1)]
+ [String]
+ $DestinationPath = (Split-Path $Path),
+ [Parameter(ValueFromRemainingArguments = $true)]
+ [String]
+ $Switches,
+ [Switch]
+ $Removal
+ )
+ $LogPath = "$(Split-Path $Path)\dark.log"
+ $DarkPath = Get-HelperPath -Helper Dark
+ if ((Split-Path $DarkPath -Leaf) -eq 'wix.exe') {
+ $ArgList = @('burn', 'extract', $Path, '-out', $DestinationPath, '-outba', "$DestinationPath\UX")
+ } else {
+ $ArgList = @('-nologo', '-x', $DestinationPath, $Path)
+ }
+ if ($Switches) {
+ $ArgList += (-split $Switches)
+ }
+ $Status = Invoke-ExternalCommand $DarkPath $ArgList -LogPath $LogPath
+ if (!$Status) {
+ abort "Failed to extract files from $Path.`nLog file:`n $(friendly_path $LogPath)`n$(new_issue_msg $app $bucket 'decompress error')"
+ }
+ if (Test-Path "$DestinationPath\WixAttachedContainer") {
+ Rename-Item "$DestinationPath\WixAttachedContainer" 'AttachedContainer' -ErrorAction Ignore
+ } else {
+ if (Test-Path "$DestinationPath\AttachedContainer\a0") {
+ $Xml = [xml](Get-Content -Raw "$DestinationPath\UX\manifest.xml" -Encoding utf8)
+ $Xml.BurnManifest.UX.Payload | ForEach-Object {
+ Rename-Item "$DestinationPath\UX\$($_.SourcePath)" $_.FilePath -ErrorAction Ignore
+ }
+ $Xml.BurnManifest.Payload | ForEach-Object {
+ Rename-Item "$DestinationPath\AttachedContainer\$($_.SourcePath)" $_.FilePath -ErrorAction Ignore
+ }
+ }
+ }
+ if (Test-Path $LogPath) {
+ Remove-Item $LogPath -Force
+ }
+ if ($Removal) {
+ # Remove original archive file
+ Remove-Item $Path -Force
+ }
}
diff --git a/lib/depends.ps1 b/lib/depends.ps1
index 12edcea3f2..3a38ca2b23 100644
--- a/lib/depends.ps1
+++ b/lib/depends.ps1
@@ -1,58 +1,158 @@
-# resolve dependencies for the supplied apps, and sort into the correct order
-function install_order($apps, $arch) {
- $res = @()
- foreach($app in $apps) {
- foreach($dep in deps $app $arch) {
- if($res -notcontains $dep) { $res += $dep}
- }
- if($res -notcontains $app) { $res += $app }
- }
- return $res
-}
-
-# http://www.electricmonk.nl/docs/dependency_resolving_algorithm/dependency_resolving_algorithm.html
-function deps($app, $arch) {
- $resolved = new-object collections.arraylist
- dep_resolve $app $arch $resolved @()
+function Get-Dependency {
+ <#
+ .SYNOPSIS
+ Get app's dependencies (with apps attached at the end).
+ .PARAMETER AppName
+ App's name
+ .PARAMETER Architecture
+ App's architecture
+ .PARAMETER Resolved
+ List of resolved dependencies (internal use)
+ .PARAMETER Unresolved
+ List of unresolved dependencies (internal use)
+ .OUTPUTS
+ [Object[]]
+ List of app's dependencies
+ .NOTES
+ When pipeline input is used, the output will have duplicate items, and should be filtered by 'Select-Object -Unique'.
+ ALgorithm: http://www.electricmonk.nl/docs/dependency_resolving_algorithm/dependency_resolving_algorithm.html
+ #>
+ [CmdletBinding()]
+ [OutputType([Object[]])]
+ param (
+ [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
+ [PSObject]
+ $AppName,
+ [Parameter(Mandatory = $true, Position = 1)]
+ [String]
+ $Architecture,
+ [String[]]
+ $Resolved = @(),
+ [String[]]
+ $Unresolved = @()
+ )
+ process {
+ $AppName, $manifest, $bucket, $url = Get-Manifest $AppName
+ $Unresolved += $AppName
- if($resolved.count -eq 1) { return @() } # no dependencies
- return $resolved[0..($resolved.count - 2)]
-}
-
-function dep_resolve($app, $arch, $resolved, $unresolved) {
- $unresolved += $app
+ if (!$manifest) {
+ if (((Get-LocalBucket) -notcontains $bucket) -and $bucket) {
+ warn "Bucket '$bucket' not added. Add it with $(if($bucket -in (known_buckets)) { "'scoop bucket add $bucket' or " })'scoop bucket add $bucket '."
+ }
+ abort "Couldn't find manifest for '$AppName'$(if($bucket) { " from '$bucket' bucket" } elseif($url) { " at '$url'" })."
+ }
- $query = $app
- $app, $bucket = app $query
- $null, $manifest, $null, $null = locate $app $bucket
- if(!$manifest) { abort "Couldn't find manifest for '$query'." }
+ $deps = @(Get-InstallationHelper $manifest $Architecture) + @($manifest.depends) | Select-Object -Unique
- $deps = @(install_deps $manifest $arch) + @(runtime_deps $manifest) | select -uniq
+ foreach ($dep in $deps) {
+ if ($Resolved -notcontains $dep) {
+ if ($Unresolved -contains $dep) {
+ abort "Circular dependency detected: '$AppName' -> '$dep'."
+ }
+ $Resolved, $Unresolved = Get-Dependency $dep $Architecture -Resolved $Resolved -Unresolved $Unresolved
+ }
+ }
- foreach($dep in $deps) {
- if($resolved -notcontains $dep) {
- if($unresolved -contains $dep) {
- abort "Circular dependency detected: '$app' -> '$dep'."
+ $Unresolved = $Unresolved -ne $AppName
+ if ($bucket) {
+ $Resolved += "$bucket/$AppName"
+ } else {
+ if ($url) {
+ $Resolved += $url
+ } else {
+ $Resolved += $AppName
}
- dep_resolve $dep $arch $resolved $unresolved
+ }
+ if ($Unresolved.Length -eq 0) {
+ return $Resolved
+ } else {
+ return $Resolved, $Unresolved
}
}
- $resolved.add($app) > $null
- $unresolved = $unresolved -ne $app # remove from unresolved
}
-function runtime_deps($manifest) {
- if($manifest.depends) { return $manifest.depends }
+function Get-InstallationHelper {
+ <#
+ .SYNOPSIS
+ Get helpers that used in installation
+ .PARAMETER Manifest
+ App's manifest
+ .PARAMETER Architecture
+ Architecture of the app
+ .PARAMETER All
+ If true, return all helpers, otherwise return only helpers that are not already installed
+ .OUTPUTS
+ [Object[]]
+ List of helpers
+ #>
+ [CmdletBinding()]
+ [OutputType([Object[]])]
+ param (
+ [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
+ [PSObject]
+ $Manifest,
+ [Parameter(Mandatory = $true, Position = 1)]
+ [String]
+ $Architecture,
+ [Switch]
+ $All
+ )
+ begin {
+ $helper = @()
+ }
+ process {
+ $url = arch_specific 'url' $Manifest $Architecture
+ $pre_install = arch_specific 'pre_install' $Manifest $Architecture
+ $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 USE_EXTERNAL_7ZIP)) {
+ $helper += '7zip'
+ }
+ 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 *')) {
+ $helper += 'innounp'
+ }
+ if ($script -like '*Expand-DarkArchive *') {
+ $helper += 'dark'
+ }
+ if (!$All) {
+ '7zip', 'lessmsi', 'innounp', 'dark' | ForEach-Object {
+ if (Test-HelperInstalled -Helper $_) {
+ $helper = $helper -ne $_
+ }
+ }
+ }
+ }
+ end {
+ return $helper
+ }
}
-function install_deps($manifest, $arch) {
- $deps = @()
-
- if((requires_7zip $manifest $arch) -and !(7zip_installed)) {
- $deps += "7zip"
- }
- if(requires_lessmsi $manifest $arch) { $deps += "lessmsi" }
- if($manifest.innosetup) { $deps += "innounp" }
+function Test-7zipRequirement {
+ [CmdletBinding()]
+ [OutputType([Boolean])]
+ param (
+ [Parameter(Mandatory = $true)]
+ [AllowNull()]
+ [String[]]
+ $Uri
+ )
+ return ($Uri | Where-Object {
+ $_ -match '\.(001|7z|bz(ip)?2?|gz|img|iso|lzma|lzh|nupkg|rar|tar|t[abgpx]z2?|t?zst|xz)(\.[^\d.]+)?$'
+ }).Count -gt 0
+}
- $deps
+function Test-LessmsiRequirement {
+ [CmdletBinding()]
+ [OutputType([Boolean])]
+ param (
+ [Parameter(Mandatory = $true)]
+ [AllowNull()]
+ [String[]]
+ $Uri
+ )
+ return ($Uri | Where-Object { $_ -match '\.msi$' }).Count -gt 0
}
diff --git a/lib/description.ps1 b/lib/description.ps1
index d9dd527951..ef1da13589 100644
--- a/lib/description.ps1
+++ b/lib/description.ps1
@@ -16,7 +16,10 @@ function find_description($url, $html, $redir = $false) {
# check redirect
$refresh = meta_refresh $meta $url
if($refresh -and !$redir) {
- $html = (new-object net.webclient).downloadstring($refresh)
+ $wc = New-Object Net.Webclient
+ $wc.Headers.Add('User-Agent', (Get-UserAgent))
+ $data = $wc.DownloadData($refresh)
+ $html = (Get-Encoding($wc)).GetString($data)
return find_description $refresh $html $true
}
@@ -47,10 +50,10 @@ function clean_description($description) {
function meta_tags($html) {
$tags = @()
$meta = ([regex]']+>').matches($html)
- $meta |% {
+ $meta | ForEach-Object {
$attrs = ([regex]'([\w-]+)="([^"]+)"').matches($_.value)
$hash = @{}
- $attrs |% {
+ $attrs | ForEach-Object {
$hash[$_.groups[1].value] = $_.groups[2].value
}
$tags += $hash
@@ -60,7 +63,7 @@ function meta_tags($html) {
function meta_content($tags, $attribute, $search) {
if(!$tags) { return }
- return $tags |? { $_[$attribute] -eq $search } |% { $_['content'] }
+ return $tags | Where-Object { $_[$attribute] -eq $search } | ForEach-Object { $_['content'] }
}
# Looks for a redirect URL in a refresh tag.
@@ -107,7 +110,9 @@ function strip_html($html) {
$charset = $matches[1]
try {
$encoding = [text.encoding]::getencoding($charset)
- } catch { }
+ } catch {
+ Write-Warning "Unknown charset"
+ }
if($encoding) {
$html = ([regex]'(\d+);?').replace($html, {
param($m)
diff --git a/lib/diagnostic.ps1 b/lib/diagnostic.ps1
index aec2fc914a..e4cc97e6a2 100644
--- a/lib/diagnostic.ps1
+++ b/lib/diagnostic.ps1
@@ -3,23 +3,21 @@ Diagnostic tests.
Return $true if the test passed, otherwise $false.
Use 'warn' to highlight the issue, and follow up with the recommended actions to rectify.
#>
-
-
function check_windows_defender($global) {
- $defender = get-service -name WinDefend -errorAction SilentlyContinue
- if($defender -and $defender.status) {
- if($defender.status -eq [system.serviceprocess.servicecontrollerstatus]::running) {
- $hasGetMpPreference = gcm get-mppreference -errorAction SilentlyContinue
- if($hasGetMpPreference) {
+ $defender = Get-Service -Name WinDefend -ErrorAction SilentlyContinue
+ if (Test-CommandAvailable Get-MpPreference) {
+ if ((Get-MpPreference).DisableRealtimeMonitoring) { return $true }
+ if ($defender -and $defender.Status) {
+ if ($defender.Status -eq [System.ServiceProcess.ServiceControllerStatus]::Running) {
$installPath = $scoopdir;
- if($global) { $installPath = $globaldir; }
-
- $exclusionPath = (Get-MpPreference).exclusionPath
- if(!($exclusionPath -contains $installPath)) {
- warn "Windows Defender may slow down or disrupt installs with realtime scanning."
- write-host " Consider running:"
- write-host " sudo Add-MpPreference -ExclusionPath '$installPath'"
- write-host " (Requires 'sudo' command. Run 'scoop install sudo' if you don't have it.)"
+ if ($global) { $installPath = $globaldir; }
+
+ $exclusionPath = (Get-MpPreference).ExclusionPath
+ if (!($exclusionPath -contains $installPath)) {
+ info "Windows Defender may slow down or disrupt installs with realtime scanning."
+ Write-Host " Consider running:"
+ Write-Host " sudo Add-MpPreference -ExclusionPath '$installPath'"
+ Write-Host " (Requires 'sudo' command. Run 'scoop install sudo' if you don't have it.)"
return $false
}
}
@@ -27,3 +25,45 @@ function check_windows_defender($global) {
}
return $true
}
+
+function check_main_bucket {
+ if ((Get-LocalBucket) -notcontains 'main') {
+ warn 'Main bucket is not added.'
+ Write-Host " run 'scoop bucket add main'"
+
+ return $false
+ }
+
+ return $true
+}
+
+function check_long_paths {
+ if ([System.Environment]::OSVersion.Version.Major -lt 10 -or [System.Environment]::OSVersion.Version.Build -lt 1607) {
+ warn 'This version of Windows does not support configuration of LongPaths.'
+ return $false
+ }
+ $key = Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -ErrorAction SilentlyContinue -Name 'LongPathsEnabled'
+ if (!$key -or ($key.LongPathsEnabled -eq 0)) {
+ warn 'LongPaths support is not enabled.'
+ Write-Host " You can enable it by running:"
+ Write-Host " sudo Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' -Value 1"
+ Write-Host " (Requires 'sudo' command. Run 'scoop install sudo' if you don't have it.)"
+ return $false
+ }
+
+ 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
+}
diff --git a/lib/download.ps1 b/lib/download.ps1
new file mode 100644
index 0000000000..70641cca7f
--- /dev/null
+++ b/lib/download.ps1
@@ -0,0 +1,769 @@
+# Description: Functions for downloading files
+
+## Meta downloader
+
+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.' }
+
+ # can be multiple urls: if there are, then installer should go first to make 'installer.args' section work
+ $urls = @(script:url $manifest $architecture)
+
+ # can be multiple cookies: they will be used for all HTTP requests.
+ $cookies = $manifest.cookie
+
+ # download first
+ if (Test-Aria2Enabled) {
+ Invoke-CachedAria2Download $app $version $manifest $architecture $dir $cookies $use_cache $check_hash
+ } else {
+ foreach ($url in $urls) {
+ $fname = url_filename $url
+
+ try {
+ Invoke-CachedDownload $app $version $url "$dir\$fname" $cookies $use_cache
+ } catch {
+ Write-Host -ForegroundColor DarkRed $_
+ abort "URL $url is not valid"
+ }
+
+ if ($check_hash) {
+ $manifest_hash = hash_for_url $manifest $url $architecture
+ $ok, $err = check_hash "$dir\$fname" $manifest_hash $(show_app $app $bucket)
+ if (!$ok) {
+ error $err
+ $cached = cache_path $app $version $url
+ if (Test-Path $cached) {
+ # rm cached file
+ Remove-Item -Force $cached
+ }
+ if ($url.Contains('sourceforge.net')) {
+ Write-Host -ForegroundColor Yellow 'SourceForge.net is known for causing hash validation fails. Please try again before opening a ticket.'
+ }
+ abort $(new_issue_msg $app $bucket 'hash check failed')
+ }
+ }
+ }
+ }
+
+ return $urls.ForEach({ url_filename $_ })
+}
+
+## [System.Net] downloader
+
+function Invoke-CachedDownload ($app, $version, $url, $to, $cookies = $null, $use_cache = $true) {
+ $cached = cache_path $app $version $url
+
+ if (!(Test-Path $cached) -or !$use_cache) {
+ ensure $cachedir | Out-Null
+ Start-Download $url "$cached.download" $cookies
+ Move-Item "$cached.download" $cached -Force
+ } else { Write-Host "Loading $(url_remote_filename $url) from cache" }
+
+ if (!($null -eq $to)) {
+ if ($use_cache) {
+ Copy-Item $cached $to
+ } else {
+ Move-Item $cached $to -Force
+ }
+ }
+}
+
+function Start-Download ($url, $to, $cookies) {
+ $progress = [console]::isoutputredirected -eq $false -and
+ $host.name -ne 'Windows PowerShell ISE Host'
+
+ try {
+ $url = handle_special_urls $url
+ Invoke-Download $url $to $cookies $progress
+ } catch {
+ $e = $_.exception
+ if ($e.Response.StatusCode -eq 'Unauthorized') {
+ warn 'Token might be misconfigured.'
+ }
+ if ($e.innerexception) { $e = $e.innerexception }
+ throw $e
+ }
+}
+
+function Invoke-Download ($url, $to, $cookies, $progress) {
+ # download with filesize and progress indicator
+ $reqUrl = ($url -split '#')[0]
+ $wreq = [Net.WebRequest]::Create($reqUrl)
+ if ($wreq -is [Net.HttpWebRequest]) {
+ $wreq.UserAgent = Get-UserAgent
+ if (-not ($url -match 'sourceforge\.net' -or $url -match 'portableapps\.com')) {
+ $wreq.Referer = strip_filename $url
+ }
+ if ($url -match 'api\.github\.com/repos') {
+ $wreq.Accept = 'application/octet-stream'
+ $wreq.Headers['Authorization'] = "Bearer $(Get-GitHubToken)"
+ $wreq.Headers['X-GitHub-Api-Version'] = '2022-11-28'
+ }
+ if ($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
+ }
+ }
+ }
+
+ try {
+ $wres = $wreq.GetResponse()
+ } catch [System.Net.WebException] {
+ $exc = $_.Exception
+ $handledCodes = @(
+ [System.Net.HttpStatusCode]::MovedPermanently, # HTTP 301
+ [System.Net.HttpStatusCode]::Found, # HTTP 302
+ [System.Net.HttpStatusCode]::SeeOther, # HTTP 303
+ [System.Net.HttpStatusCode]::TemporaryRedirect # HTTP 307
+ )
+
+ # Only handle redirection codes
+ $redirectRes = $exc.Response
+ if ($handledCodes -notcontains $redirectRes.StatusCode) {
+ throw $exc
+ }
+
+ # Get the new location of the file
+ if ((-not $redirectRes.Headers) -or ($redirectRes.Headers -notcontains 'Location')) {
+ throw $exc
+ }
+
+ $newUrl = $redirectRes.Headers['Location']
+ info "Following redirect to $newUrl..."
+
+ # Handle manual file rename
+ if ($url -like '*#/*') {
+ $null, $postfix = $url -split '#/'
+ $newUrl = "$newUrl`#/$postfix"
+ }
+
+ Invoke-Download $newUrl $to $cookies $progress
+ return
+ }
+
+ $total = $wres.ContentLength
+ if ($total -eq -1 -and $wreq -is [net.ftpwebrequest]) {
+ $total = ftp_file_size($url)
+ }
+
+ if ($progress -and ($total -gt 0)) {
+ [console]::CursorVisible = $false
+ function Trace-DownloadProgress ($read) {
+ Write-DownloadProgress $read $total $url
+ }
+ } else {
+ Write-Host "Downloading $url ($(filesize $total))..."
+ function Trace-DownloadProgress {
+ #no op
+ }
+ }
+
+ try {
+ $s = $wres.getresponsestream()
+ $fs = [io.file]::openwrite($to)
+ $buffer = New-Object byte[] 2048
+ $totalRead = 0
+ $sw = [diagnostics.stopwatch]::StartNew()
+
+ 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()
+ Trace-DownloadProgress $totalRead
+ }
+ }
+ $sw.stop()
+ Trace-DownloadProgress $totalRead
+ } finally {
+ if ($progress) {
+ [console]::CursorVisible = $true
+ Write-Host
+ }
+ if ($fs) {
+ $fs.close()
+ }
+ if ($s) {
+ $s.close()
+ }
+ $wres.close()
+ }
+}
+
+function Format-DownloadProgress ($url, $read, $total, $console) {
+ $filename = url_remote_filename $url
+
+ # calculate current percentage done
+ $p = [math]::Round($read / $total * 100, 0)
+
+ # pre-generate LHS and RHS of progress string
+ # so we know how much space we have
+ $left = "$filename ($(filesize $total))"
+ $right = [string]::Format('{0,3}%', $p)
+
+ # calculate remaining width for progress bar
+ $midwidth = $console.BufferSize.Width - ($left.Length + $right.Length + 8)
+
+ # calculate how many characters are completed
+ $completed = [math]::Abs([math]::Round(($p / 100) * $midwidth, 0) - 1)
+
+ # generate dashes to symbolise completed
+ if ($completed -gt 1) {
+ $dashes = [string]::Join('', ((1..$completed) | ForEach-Object { '=' }))
+ }
+
+ # this is why we calculate $completed - 1 above
+ $dashes += switch ($p) {
+ 100 { '=' }
+ default { '>' }
+ }
+
+ # the remaining characters are filled with spaces
+ $spaces = switch ($dashes.Length) {
+ $midwidth { [string]::Empty }
+ default {
+ [string]::Join('', ((1..($midwidth - $dashes.Length)) | ForEach-Object { ' ' }))
+ }
+ }
+
+ "$left [$dashes$spaces] $right"
+}
+
+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 = $(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
+ Write-Host
+ $left = 0
+ $top = $top + 1
+ if ($top -gt $console.CursorPosition.Y) { $top = $console.CursorPosition.Y }
+ }
+ }
+
+ Write-Host $(Format-DownloadProgress $url $read $total $console) -NoNewline
+ [console]::SetCursorPosition($left, $top)
+}
+
+## Aria2 downloader
+
+function Test-Aria2Enabled {
+ return (Test-HelperInstalled -Helper Aria2) -and (get_config 'aria2-enabled' $true)
+}
+
+function aria_exit_code($exitcode) {
+ $codes = @{
+ 0 = 'All downloads were successful'
+ 1 = 'An unknown error occurred'
+ 2 = 'Timeout'
+ 3 = 'Resource was not found'
+ 4 = 'Aria2 saw the specified number of "resource not found" error. See --max-file-not-found option'
+ 5 = 'Download aborted because download speed was too slow. See --lowest-speed-limit option'
+ 6 = 'Network problem occurred.'
+ 7 = 'There were unfinished downloads. This error is only reported if all finished downloads were successful and there were unfinished downloads in a queue when aria2 exited by pressing Ctrl-C by an user or sending TERM or INT signal'
+ 8 = 'Remote server did not support resume when resume was required to complete download'
+ 9 = 'There was not enough disk space available'
+ 10 = 'Piece length was different from one in .aria2 control file. See --allow-piece-length-change option'
+ 11 = 'Aria2 was downloading same file at that moment'
+ 12 = 'Aria2 was downloading same info hash torrent at that moment'
+ 13 = 'File already existed. See --allow-overwrite option'
+ 14 = 'Renaming file failed. See --auto-file-renaming option'
+ 15 = 'Aria2 could not open existing file'
+ 16 = 'Aria2 could not create new file or truncate existing file'
+ 17 = 'File I/O error occurred'
+ 18 = 'Aria2 could not create directory'
+ 19 = 'Name resolution failed'
+ 20 = 'Aria2 could not parse Metalink document'
+ 21 = 'FTP command failed'
+ 22 = 'HTTP response header was bad or unexpected'
+ 23 = 'Too many redirects occurred'
+ 24 = 'HTTP authorization failed'
+ 25 = 'Aria2 could not parse bencoded file (usually ".torrent" file)'
+ 26 = '".torrent" file was corrupted or missing information that aria2 needed'
+ 27 = 'Magnet URI was bad'
+ 28 = 'Bad/unrecognized option was given or unexpected option argument was given'
+ 29 = 'The remote server was unable to handle the request due to a temporary overloading or maintenance'
+ 30 = 'Aria2 could not parse JSON-RPC request'
+ 31 = 'Reserved. Not used'
+ 32 = 'Checksum validation failed'
+ }
+ if ($null -eq $codes[$exitcode]) {
+ return 'An unknown error occurred'
+ }
+ return $codes[$exitcode]
+}
+
+function get_filename_from_metalink($file) {
+ $bytes = get_magic_bytes_pretty $file ''
+ # check if file starts with ' p\@ssword'
+ $proxy = get_config PROXY
+ if (!$proxy) {
+ return
+ }
+ try {
+ $credentials, $address = $proxy -split '(?'."
+ }
+ $ret
+}
+
+### URL handling
+
+function handle_special_urls($url) {
+ # FossHub.com
+ if ($url -match '^(?:.*fosshub.com\/)(?.*)(?:\/|\?dwl=)(?.*)$') {
+ $Body = @{
+ projectUri = $Matches.name
+ fileName = $Matches.filename
+ source = 'CF'
+ isLatestVersion = $true
+ }
+ if ((Invoke-RestMethod -Uri $url) -match '"p":"(?[a-f0-9]{24}).*?"r":"(?[a-f0-9]{24})') {
+ $Body.Add('projectId', $Matches.pid)
+ $Body.Add('releaseId', $Matches.rid)
+ }
+ $url = Invoke-RestMethod -Method Post -Uri 'https://api.fosshub.com/download/' -ContentType 'application/json' -Body (ConvertTo-Json $Body -Compress)
+ if ($null -eq $url.error) {
+ $url = $url.data.url
+ }
+ }
+
+ # Sourceforge.net
+ if ($url -match '(?:downloads\.)?sourceforge.net\/projects?\/(?[^\/]+)\/(?:files\/)?(?.*?)(?:$|\/download|\?)') {
+ # Reshapes the URL to avoid redirections
+ $url = "https://downloads.sourceforge.net/project/$($matches['project'])/$($matches['file'])"
+ }
+
+ # Github.com
+ if ($url -match 'github.com/(?[^/]+)/(?[^/]+)/releases/download/(?[^/]+)/(?[^/#]+)(?.*)' -and ($token = Get-GitHubToken)) {
+ $headers = @{ 'Authorization' = "token $token" }
+ $privateUrl = "https://api.github.com/repos/$($Matches.owner)/$($Matches.repo)"
+ $assetUrl = "https://api.github.com/repos/$($Matches.owner)/$($Matches.repo)/releases/tags/$($Matches.tag)"
+
+ if ((Invoke-RestMethod -Uri $privateUrl -Headers $headers).Private) {
+ $url = ((Invoke-RestMethod -Uri $assetUrl -Headers $headers).Assets | Where-Object -Property Name -EQ -Value $Matches.file).Url, $Matches.filename -join ''
+ }
+ }
+
+ return $url
+}
+
+### Remote file information
+
+function download_json($url) {
+ $githubtoken = Get-GitHubToken
+ $authheader = @{}
+ if ($githubtoken) {
+ $authheader = @{'Authorization' = "token $githubtoken" }
+ }
+ $ProgressPreference = 'SilentlyContinue'
+ $result = Invoke-WebRequest $url -UseBasicParsing -Headers $authheader | Select-Object -ExpandProperty content | ConvertFrom-Json
+ $ProgressPreference = 'Continue'
+ $result
+}
+
+function get_magic_bytes($file) {
+ if (!(Test-Path $file)) {
+ return ''
+ }
+
+ if ((Get-Command Get-Content).parameters.ContainsKey('AsByteStream')) {
+ # PowerShell Core (6.0+) '-Encoding byte' is replaced by '-AsByteStream'
+ return Get-Content $file -AsByteStream -TotalCount 8
+ } else {
+ return Get-Content $file -Encoding byte -TotalCount 8
+ }
+}
+
+function get_magic_bytes_pretty($file, $glue = ' ') {
+ if (!(Test-Path $file)) {
+ return ''
+ }
+
+ return (get_magic_bytes $file | ForEach-Object { $_.ToString('x2') }) -join $glue
+}
+
+Function Get-RemoteFileSize ($Uri) {
+ $response = Invoke-WebRequest -Uri $Uri -Method HEAD -UseBasicParsing
+ if (!$response.Headers.StatusCode) {
+ $response.Headers.'Content-Length' | ForEach-Object { [int]$_ }
+ }
+}
+
+function ftp_file_size($url) {
+ $request = [net.ftpwebrequest]::create($url)
+ $request.method = [net.webrequestmethods+ftp]::getfilesize
+ $request.getresponse().contentlength
+}
+
+function url_filename($url) {
+ (Split-Path $url -Leaf).split('?') | Select-Object -First 1
+}
+
+function url_remote_filename($url) {
+ # Unlike url_filename which can be tricked by appending a
+ # URL fragment (e.g. #/dl.7z, useful for coercing a local filename),
+ # this function extracts the original filename from the URL.
+ $uri = (New-Object URI $url)
+ $basename = Split-Path $uri.PathAndQuery -Leaf
+ If ($basename -match '.*[?=]+([\w._-]+)') {
+ $basename = $matches[1]
+ }
+ If (($basename -notlike '*.*') -or ($basename -match '^[v.\d]+$')) {
+ $basename = Split-Path $uri.AbsolutePath -Leaf
+ }
+ If (($basename -notlike '*.*') -and ($uri.Fragment -ne '')) {
+ $basename = $uri.Fragment.Trim('/', '#')
+ }
+ return $basename
+}
+
+### Hash-related functions
+
+function hash_for_url($manifest, $url, $arch) {
+ $hashes = @(hash $manifest $arch) | Where-Object { $_ -ne $null }
+
+ if ($hashes.length -eq 0) { return $null }
+
+ $urls = @(script:url $manifest $arch)
+
+ $index = [array]::IndexOf($urls, $url)
+ if ($index -eq -1) { abort "Couldn't find hash in manifest for '$url'." }
+
+ @($hashes)[$index]
+}
+
+function check_hash($file, $hash, $app_name) {
+ # returns (ok, err)
+ if (!$hash) {
+ warn "Warning: No hash in manifest. SHA256 for '$(fname $file)' is:`n $((Get-FileHash -Path $file -Algorithm SHA256).Hash.ToLower())"
+ return $true, $null
+ }
+
+ Write-Host 'Checking hash of ' -NoNewline
+ Write-Host $(url_remote_filename $url) -ForegroundColor Cyan -NoNewline
+ Write-Host ' ... ' -NoNewline
+ $algorithm, $expected = get_hash $hash
+ if ($null -eq $algorithm) {
+ return $false, "Hash type '$algorithm' isn't supported."
+ }
+
+ $actual = (Get-FileHash -Path $file -Algorithm $algorithm).Hash.ToLower()
+ $expected = $expected.ToLower()
+
+ if ($actual -ne $expected) {
+ $msg = "Hash check failed!`n"
+ $msg += "App: $app_name`n"
+ $msg += "URL: $url`n"
+ if (Test-Path $file) {
+ $msg += "First bytes: $((get_magic_bytes_pretty $file ' ').ToUpper())`n"
+ }
+ if ($expected -or $actual) {
+ $msg += "Expected: $expected`n"
+ $msg += "Actual: $actual"
+ }
+ return $false, $msg
+ }
+ Write-Host 'ok.' -f Green
+ return $true, $null
+}
+
+function get_hash([String] $multihash) {
+ $type, $hash = $multihash -split ':'
+ if (!$hash) {
+ # no type specified, assume sha256
+ $type, $hash = 'sha256', $multihash
+ }
+
+ if (@('md5', 'sha1', 'sha256', 'sha512') -notcontains $type) {
+ return $null, "Hash type '$type' isn't supported."
+ }
+
+ return $type, $hash.ToLower()
+}
+
+# Setup proxy globally
+setup_proxy
diff --git a/lib/getopt.ps1 b/lib/getopt.ps1
index d53d9cbb3d..2de3ac6c0a 100644
--- a/lib/getopt.ps1
+++ b/lib/getopt.ps1
@@ -8,7 +8,12 @@
# array of strings that are long-form options. options that take
# a parameter should end with '='
# returns @(opts hash, remaining_args array, error string)
-function getopt($argv, $shortopts, $longopts) {
+# 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([String[]]$argv, [String]$shortopts, [String[]]$longopts) {
$opts = @{}; $rem = @()
function err($msg) {
@@ -16,27 +21,31 @@ function getopt($argv, $shortopts, $longopts) {
}
function regex_escape($str) {
- return [regex]::escape($str)
+ return [Regex]::Escape($str)
}
- # ensure these are arrays
- $argv = @($argv)
- $longopts = @($longopts)
-
- for($i = 0; $i -lt $argv.length; $i++) {
+ for ($i = 0; $i -lt $argv.Length; $i++) {
$arg = $argv[$i]
+ if ($null -eq $arg) { continue }
# don't try to parse array arguments
- if($arg -is [array]) { $rem += ,$arg; continue }
- if($arg -is [int]) { $rem += $arg; continue }
+ if ($arg -is [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 | ? { $_ -match "^$name=?$" }
+ $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]
@@ -46,14 +55,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]
@@ -68,6 +77,5 @@ function getopt($argv, $shortopts, $longopts) {
$rem += $arg
}
}
-
$opts, $rem
}
diff --git a/lib/git.ps1 b/lib/git.ps1
deleted file mode 100644
index a04ee3a384..0000000000
--- a/lib/git.ps1
+++ /dev/null
@@ -1,28 +0,0 @@
-function git_proxy_cmd {
- $proxy = $(scoop config proxy)
- $cmd = "git $($args |% { "$_ " })"
- if($proxy) {
- $cmd = "SET HTTPS_PROXY=$proxy&&SET HTTP_PROXY=$proxy&&$cmd"
- }
- cmd /c $cmd
-}
-
-function git_clone {
- git_proxy_cmd clone $args
-}
-
-function git_ls_remote {
- git_proxy_cmd ls-remote $args
-}
-
-function git_pull {
- git_proxy_cmd pull $args
-}
-
-function git_fetch {
- git_proxy_cmd fetch $args
-}
-
-function git_log {
- git_proxy_cmd log $args
-}
diff --git a/lib/help.ps1 b/lib/help.ps1
index 330f199648..a964084143 100644
--- a/lib/help.ps1
+++ b/lib/help.ps1
@@ -1,16 +1,16 @@
function usage($text) {
- $text | sls '(?m)^# Usage: ([^\n]*)$' | % { "Usage: " + $_.matches[0].groups[1].value }
+ $text | Select-String '(?m)^# Usage: ([^\n]*)$' | ForEach-Object { "Usage: " + $_.matches[0].groups[1].value }
}
function summary($text) {
- $text | sls '(?m)^# Summary: ([^\n]*)$' | % { $_.matches[0].groups[1].value }
+ $text | Select-String '(?m)^# Summary: ([^\n]*)$' | ForEach-Object { $_.matches[0].groups[1].value }
}
-function help($text) {
- $help_lines = $text | sls '(?ms)^# Help:(.(?!^[^#]))*' | % { $_.matches[0].value; }
+function scoop_help($text) {
+ $help_lines = $text | Select-String '(?ms)^# Help:(.(?!^[^#]))*' | ForEach-Object { $_.matches[0].value; }
$help_lines -replace '(?ms)^#\s?(Help: )?', ''
}
function my_usage { # gets usage for the calling script
- usage (gc $myInvocation.PSCommandPath -raw)
+ usage (Get-Content $myInvocation.PSCommandPath -raw)
}
diff --git a/lib/install.ps1 b/lib/install.ps1
index 182e954070..56cfdac924 100644
--- a/lib/install.ps1
+++ b/lib/install.ps1
@@ -1,66 +1,78 @@
-. "$psscriptroot/autoupdate.ps1"
-. "$psscriptroot/buckets.ps1"
-
-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) {
- $app, $bucket = app $app
- $app, $manifest, $bucket, $url = locate $app $bucket
- $use_cache = $true
- $check_hash = $true
+function install_app($app, $architecture, $global, $suggested, $use_cache = $true, $check_hash = $true) {
+ $app, $manifest, $bucket, $url = Get-Manifest $app
- if(!$manifest) {
- abort "Couldn't find manifest for '$app'$(if($url) { " at the URL $url" })."
+ if (!$manifest) {
+ abort "Couldn't find manifest for '$app'$(if ($bucket) { " from '$bucket' bucket" } elseif ($url) { " at '$url'" })."
}
$version = $manifest.version
- if(!$version) { abort "Manifest doesn't specify a version." }
- if($version -match '[^\w\.\-_]') {
+ if (!$version) { abort "Manifest doesn't specify a version." }
+ if ($version -match '[^\w\.\-\+_]') {
abort "Manifest version has unsupported character '$($matches[0])'."
}
$is_nightly = $version -eq 'nightly'
if ($is_nightly) {
- $version = nightly_version $(get-date)
+ $version = nightly_version
$check_hash = $false
}
- write-output "Installing '$app' ($version)."
+ $architecture = Get-SupportedArchitecture $manifest $architecture
+ if ($null -eq $architecture) {
+ error "'$app' doesn't support current architecture!"
+ return
+ }
+
+ if ((get_config SHOW_MANIFEST $false) -and ($MyInvocation.ScriptName -notlike '*scoop-update*')) {
+ Write-Host "Manifest: $app.json"
+ $style = get_config CAT_STYLE
+ if ($style) {
+ $manifest | ConvertToPrettyJson | bat --no-paging --style $style --language json
+ } else {
+ $manifest | ConvertToPrettyJson
+ }
+ $answer = Read-Host -Prompt 'Continue installation? [Y/n]'
+ if (($answer -eq 'n') -or ($answer -eq 'N')) {
+ return
+ }
+ }
+ Write-Output "Installing '$app' ($version) [$architecture]$(if ($bucket) { " from '$bucket' bucket" } else { " from '$url'" })"
$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 $architecture $dir $use_cache $check_hash
- unpack_inno $fname $manifest $dir
- pre_install $manifest $architecture
- run_installer $fname $manifest $architecture $dir $global
+ $fname = Invoke-ScoopDownload $app $version $manifest $bucket $architecture $dir $use_cache $check_hash
+ Invoke-Extraction -Path $dir -Name $fname -Manifest $manifest -ProcessorArchitecture $architecture
+ Invoke-HookScript -HookType 'pre_install' -Manifest $manifest -ProcessorArchitecture $architecture
+
+ Invoke-Installer -Path $dir -Name $fname -Manifest $manifest -ProcessorArchitecture $architecture -AppName $app -Global:$global
ensure_install_dir_not_in_path $dir $global
$dir = link_current $dir
create_shims $manifest $dir $global $architecture
create_startmenu_shortcuts $manifest $dir $global $architecture
install_psmodule $manifest $dir $global
- if($global) { ensure_scoop_in_path $global } # can assume local scoop is in path
- env_add_path $manifest $dir $global
- env_set $manifest $dir $global
+ env_add_path $manifest $dir $global $architecture
+ env_set $manifest $global $architecture
# persist data
persist_data $manifest $original_dir $persist_dir
+ persist_permission $manifest $global
- # env_ensure_home $manifest $global (see comment for env_ensure_home)
- post_install $manifest $architecture
+ Invoke-HookScript -HookType 'post_install' -Manifest $manifest -ProcessorArchitecture $architecture
# save info for uninstall
save_installed_manifest $app $bucket $dir $url
save_install_info @{ 'architecture' = $architecture; 'url' = $url; 'bucket' = $bucket } $dir
- if($manifest.suggest) {
+ if ($manifest.suggest) {
$suggested[$app] = $manifest.suggest
}
@@ -69,664 +81,178 @@ function install_app($app, $architecture, $global, $suggested) {
show_notes $manifest $dir $original_dir $persist_dir
}
-function locate($app, $bucket) {
- $manifest, $url = $null, $null
-
- # check if app is a url
- if($app -match '^((ht)|f)tps?://') {
- $url = $app
- $app = appname_from_url $url
- $manifest = url_manifest $url
- } else {
- # check buckets
- $manifest, $bucket = find_manifest $app $bucket
-
- if(!$manifest) {
- # couldn't find app in buckets: check if it's a local path
- $path = $app
- if(!$path.endswith('.json')) { $path += '.json' }
- if(test-path $path) {
- $url = "$(resolve-path $path)"
- $app = appname_from_url $url
- $manifest, $bucket = url_manifest $url
- }
- }
- }
-
- return $app, $manifest, $bucket, $url
-}
-
-function dl_with_cache($app, $version, $url, $to, $cookies = $null, $use_cache = $true) {
- $cached = fullpath (cache_path $app $version $url)
-
- if(!(test-path $cached) -or !$use_cache) {
- $null = ensure $cachedir
- do_dl $url "$cached.download" $cookies
- Move-Item "$cached.download" $cached -force
- } else { write-host "Loading $(url_remote_filename $url) from cache"}
-
- if (!($to -eq $null)) {
- Copy-Item $cached $to
- }
-}
-
-function use_any_https_protocol() {
- $original = "$([System.Net.ServicePointManager]::SecurityProtocol)"
- $available = [string]::join(', ', [Enum]::GetNames([System.Net.SecurityProtocolType]))
-
- # use whatever protocols are available that the server supports
- set_https_protocols $available
-
- return $original
-}
-
-function set_https_protocols($protocols) {
- try {
- [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType] $protocols
- } catch {
- [System.Net.ServicePointManager]::SecurityProtocol = "Tls,Tls11,Tls12"
- }
-}
-
-function do_dl($url, $to, $cookies) {
- $original_protocols = use_any_https_protocol
- $progress = [console]::isoutputredirected -eq $false
-
- try {
- $url = handle_special_urls $url
- dl $url $to $cookies $progress
- } catch {
- $e = $_.exception
- if($e.innerexception) { $e = $e.innerexception }
- throw $e
- } finally {
- set_https_protocols $original_protocols
- }
-}
-
-# download with filesize and progress indicator
-function dl($url, $to, $cookies, $progress) {
- $wreq = [net.webrequest]::create($url)
- if($wreq -is [net.httpwebrequest]) {
- $wreq.useragent = 'Scoop/1.0'
- $wreq.referer = strip_filename $url
- if($cookies) {
- $wreq.headers.add('Cookie', (cookie_header $cookies))
- }
- }
-
- $wres = $wreq.getresponse()
- $total = $wres.ContentLength
- if($total -eq -1 -and $wreq -is [net.ftpwebrequest]) {
- $total = ftp_file_size($url)
- }
-
- if ($progress -and ($total -gt 0)) {
- [console]::CursorVisible = $false
- function dl_onProgress($read) {
- dl_progress $read $total $url
- }
- } else {
- write-host "Downloading $url ($(filesize $total))..."
- function dl_onProgress {
- #no op
- }
- }
-
- try {
- $s = $wres.getresponsestream()
- $fs = [io.file]::openwrite($to)
- $buffer = new-object byte[] 2048
- $totalRead = 0
- $sw = [diagnostics.stopwatch]::StartNew()
-
- dl_onProgress $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
- }
- }
- $sw.stop()
- dl_onProgress $totalRead
- } finally {
- if ($progress) {
- [console]::CursorVisible = $true
- write-host
- }
- if ($fs) {
- $fs.close()
- }
- if ($s) {
- $s.close();
- }
- $wres.close()
- }
-}
-
-function dl_progress_output($url, $read, $total, $console) {
- $filename = url_remote_filename $url
-
- # calculate current percentage done
- $p = [math]::Round($read / $total * 100, 0)
-
- # pre-generate LHS and RHS of progress string
- # so we know how much space we have
- $left = "$filename ($(filesize $total))"
- $right = [string]::Format("{0,3}%", $p)
-
- # calculate remaining width for progress bar
- $midwidth = $console.BufferSize.Width - ($left.Length + $right.Length + 8)
-
- # calculate how many characters are completed
- $completed = [math]::Abs([math]::Round(($p / 100) * $midwidth, 0) - 1)
-
- # generate dashes to symbolise completed
- if ($completed -gt 1) {
- $dashes = [string]::Join("", ((1..$completed) | ForEach-Object {"="}))
- }
-
- # this is why we calculate $completed - 1 above
- $dashes += switch($p) {
- 100 {"="}
- default {">"}
- }
-
- # the remaining characters are filled with spaces
- $spaces = switch($dashes.Length) {
- $midwidth {[string]::Empty}
- default {
- [string]::Join("", ((1..($midwidth - $dashes.Length)) | ForEach-Object {" "}))
- }
- }
-
- "$left [$dashes$spaces] $right"
-}
-
-function dl_progress($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
- if (($left + $maxOutputLength) -gt $width) {
- # not enough room to print progress on this line
- # print on new line
- write-host
- $left = 0
- $top = $top + 1
- }
- }
-
- write-host $(dl_progress_output $url $read $total $console) -nonewline
- [console]::SetCursorPosition($left, $top)
-}
-
-function dl_urls($app, $version, $manifest, $architecture, $dir, $use_cache = $true, $check_hash = $true) {
- # we only want to show this warning once
- if(!$use_cache) { warn "Cache is being ignored." }
-
- # can be multiple urls: if there are, then msi or installer should go last,
- # so that $fname is set properly
- $urls = @(url $manifest $architecture)
-
- # can be multiple cookies: they will be used for all HTTP requests.
- $cookies = $manifest.cookie
-
- $fname = $null
-
- # extract_dir and extract_to in manifest are like queues: for each url that
- # needs to be extracted, will get the next dir from the queue
- $extract_dirs = @(extract_dir $manifest $architecture)
- $extract_tos = @(extract_to $manifest $architecture)
- $extracted = 0;
-
- $data = @{}
-
- # download first
- foreach($url in $urls) {
- $data.$url = @{
- "fname" = url_filename $url
- }
- $fname = $data.$url.fname
-
- try {
- dl_with_cache $app $version $url "$dir\$fname" $cookies $use_cache
- } catch {
- write-host -f darkred $_
- abort "URL $url is not valid"
- }
- }
-
- foreach($url in $urls) {
- $fname = $data.$url.fname
-
- if($check_hash) {
- $ok, $err = check_hash "$dir\$fname" $url $manifest $architecture
- if(!$ok) {
- # rm cached
- $cached = cache_path $app $version $url
- if(test-path $cached) { rm -force $cached }
- abort $err
- }
- }
-
- $extract_dir = $extract_dirs[$extracted]
- $extract_to = $extract_tos[$extracted]
-
- # work out extraction method, if applicable
- $extract_fn = $null
- if($fname -match '\.zip$') { # unzip
- $extract_fn = 'unzip'
- } elseif($fname -match '\.msi$') {
- # check manifest doesn't use deprecated install method
- $msi = msi $manifest $architecture
- if(!$msi) {
- $useLessMsi = get_config MSIEXTRACT_USE_LESSMSI
- if ($useLessMsi -eq $true) {
- $extract_fn, $extract_dir = lessmsi_config $extract_dir
- }
- else {
- $extract_fn = 'extract_msi'
+function is_in_dir($dir, $check) {
+ $check -match "^$([regex]::Escape("$dir"))([/\\]|$)"
+}
+
+function Invoke-Installer {
+ [CmdletBinding()]
+ param (
+ [string]
+ $Path,
+ [string[]]
+ $Name,
+ [psobject]
+ $Manifest,
+ [Alias('Arch', 'Architecture')]
+ [ValidateSet('32bit', '64bit', 'arm64')]
+ [string]
+ $ProcessorArchitecture,
+ [string]
+ $AppName,
+ [switch]
+ $Global,
+ [switch]
+ $Uninstall
+ )
+ $type = if ($Uninstall) { 'uninstaller' } else { 'installer' }
+ $installer = arch_specific $type $Manifest $ProcessorArchitecture
+ if ($installer.file -or $installer.args) {
+ # Installer filename is either explicit defined ('installer.file') or file name in the first URL
+ if (!$Name) {
+ $Name = url_filename @(url $manifest $architecture)
+ }
+ $progName = "$Path\$(coalesce $installer.file $Name[0])"
+ if (!(is_in_dir $Path $progName)) {
+ abort "Error in manifest: $((Get-Culture).TextInfo.ToTitleCase($type)) $progName is outside the app directory."
+ } elseif (!(Test-Path $progName)) {
+ abort "$((Get-Culture).TextInfo.ToTitleCase($type)) $progName is missing."
+ }
+ $substitutions = @{
+ '$dir' = $Path
+ '$global' = $Global
+ '$version' = $Manifest.version
+ }
+ $fnArgs = substitute $installer.args $substitutions
+ if ($progName.EndsWith('.ps1')) {
+ & $progName @fnArgs
+ } else {
+ $status = Invoke-ExternalCommand $progName -ArgumentList $fnArgs -Activity "Running $type ..."
+ if (!$status) {
+ if ($Uninstall) {
+ abort 'Uninstallation aborted.'
+ } else {
+ abort "Installation aborted. You might need to run 'scoop uninstall $AppName' before trying again."
}
- } else {
- warn "MSI install is deprecated. If you maintain this manifest, please refer to the manifest reference docs."
- }
- } elseif(file_requires_7zip $fname) { # 7zip
- if(!(7zip_installed)) {
- warn "Aborting. You'll need to run 'scoop uninstall $app' to clean up."
- abort "7-zip is required. You can install it with 'scoop install 7zip'."
- }
- $extract_fn = 'extract_7zip'
- }
-
- if($extract_fn) {
- write-host "Extracting... " -nonewline
- $null = mkdir "$dir\_tmp"
- & $extract_fn "$dir\$fname" "$dir\_tmp"
- rm "$dir\$fname"
- if ($extract_to) {
- $null = mkdir "$dir\$extract_to" -force
}
- # fails if zip contains long paths (e.g. atom.json)
- #cp "$dir\_tmp\$extract_dir\*" "$dir\$extract_to" -r -force -ea stop
- movedir "$dir\_tmp\$extract_dir" "$dir\$extract_to"
-
- if(test-path "$dir\_tmp") { # might have been moved by movedir
- try {
- rm -r -force "$dir\_tmp" -ea stop
- } catch [system.io.pathtoolongexception] {
- cmd /c "rmdir /s /q $dir\_tmp"
- } catch [system.unauthorizedaccessexception] {
- warn "Couldn't remove $dir\_tmp: unauthorized access."
- }
+ # Don't remove installer if "keep" flag is set to true
+ if (!$installer.keep) {
+ Remove-Item $progName
}
-
- write-host "done."
-
- $extracted++
}
}
-
- $fname # returns the last downloaded file
-}
-
-function lessmsi_config ($extract_dir) {
- $extract_fn = 'extract_lessmsi'
- if ($extract_dir) {
- $extract_dir = join-path SourceDir $extract_dir
- }
- else {
- $extract_dir = "SourceDir"
- }
-
- $extract_fn, $extract_dir
+ Invoke-HookScript -HookType $type -Manifest $Manifest -ProcessorArchitecture $ProcessorArchitecture
}
-function cookie_header($cookies) {
- if(!$cookies) { return }
+function Invoke-HookScript {
+ [CmdletBinding()]
+ param(
+ [Parameter(Mandatory = $true)]
+ [ValidateSet('installer', 'pre_install', 'post_install', 'uninstaller', 'pre_uninstall', 'post_uninstall')]
+ [String] $HookType,
+ [Parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [PSCustomObject] $Manifest,
+ [Parameter(Mandatory = $true)]
+ [Alias('Arch', 'Architecture')]
+ [ValidateSet('32bit', '64bit', 'arm64')]
+ [string]
+ $ProcessorArchitecture
+ )
- $vals = $cookies.psobject.properties | % {
- "$($_.name)=$($_.value)"
+ $script = arch_specific $HookType $Manifest $ProcessorArchitecture
+ if ($HookType -in @('installer', 'uninstaller')) {
+ $script = $script.script
}
-
- [string]::join(';', $vals)
-}
-
-function is_in_dir($dir, $check) {
- $check = "$(fullpath $check)"
- $dir = "$(fullpath $dir)"
- $check -match "^$([regex]::escape("$dir"))(\\|`$)"
-}
-
-function ftp_file_size($url) {
- $request = [net.ftpwebrequest]::create($url)
- $request.method = [net.webrequestmethods+ftp]::getfilesize
- $request.getresponse().contentlength
-}
-
-# hashes
-function hash_for_url($manifest, $url, $arch) {
- $hashes = @(hash $manifest $arch) | ? { $_ -ne $null };
-
- if($hashes.length -eq 0) { return $null }
-
- $urls = @(url $manifest $arch)
-
- $index = [array]::indexof($urls, $url)
- if($index -eq -1) { abort "Couldn't find hash in manifest for '$url'." }
-
- @($hashes)[$index]
-}
-
-# returns (ok, err)
-function check_hash($file, $url, $manifest, $arch) {
- $hash = hash_for_url $manifest $url $arch
- if(!$hash) {
- warn "Warning: No hash in manifest. SHA256 is:`n $(compute_hash (fullpath $file) 'sha256')"
- return $true
- }
-
- write-host "Checking hash of $(url_remote_filename $url)... " -nonewline
- $type, $expected = $hash.split(':')
- if(!$expected) {
- # no type specified, assume sha256
- $type, $expected = 'sha256', $type
- }
-
- if(@('md5','sha1','sha256', 'sha512') -notcontains $type) {
- return $false, "Hash type '$type' isn't supported."
- }
-
- $actual = compute_hash (fullpath $file) $type
-
- if($actual -ne $expected) {
- return $false, "Hash check failed for '$url'.`nExpected:`n $($expected)`nActual:`n $($actual)"
- }
- write-host "ok."
- return $true
-}
-
-function compute_hash($file, $algname) {
- $alg = [system.security.cryptography.hashalgorithm]::create($algname)
- $fs = [system.io.file]::openread($file)
- try {
- $hexbytes = $alg.computehash($fs) | % { $_.tostring('x2') }
- [string]::join('', $hexbytes)
- } finally {
- $fs.dispose()
- $alg.dispose()
- }
-}
-
-function cmd_available($cmd) {
- try { gcm $cmd -ea stop | out-null } catch { return $false }
- $true
-}
-
-# for dealing with installers
-function args($config, $dir, $global) {
- if($config) { return $config | % { (format $_ @{'dir'=$dir;'global'=$global}) } }
- @()
-}
-
-function run($exe, $arg, $msg, $continue_exit_codes) {
- if($msg) { write-host "$msg " -nonewline }
- try {
- #Allow null/no arguments to be passed
- $parameters = @{ }
- if ($arg)
- {
- $parameters.arg = $arg;
- }
-
- $proc = start-process $exe -wait -ea stop -passthru @parameters
-
-
- if($proc.exitcode -ne 0) {
- if($continue_exit_codes -and ($continue_exit_codes.containskey($proc.exitcode))) {
- warn $continue_exit_codes[$proc.exitcode]
- return $true
- }
- write-host "Exit code was $($proc.exitcode)."; return $false
- }
- } catch {
- write-host -f darkred $_.exception.tostring()
- return $false
- }
- if($msg) { write-host "done." }
- return $true
-}
-
-function unpack_inno($fname, $manifest, $dir) {
- if(!$manifest.innosetup) { return }
-
- write-host "Unpacking innosetup... " -nonewline
- innounp -x -d"$dir\_scoop_unpack" "$dir\$fname" > "$dir\innounp.log"
- if($lastexitcode -ne 0) {
- abort "Failed to unpack innosetup file. See $dir\innounp.log"
- }
-
- gci "$dir\_scoop_unpack\{app}" -r | mv -dest "$dir" -force
-
- rmdir -r -force "$dir\_scoop_unpack"
-
- rm "$dir\$fname"
- write-host "done."
-}
-
-function run_installer($fname, $manifest, $architecture, $dir, $global) {
- # MSI or other installer
- $msi = msi $manifest $architecture
- $installer = installer $manifest $architecture
-
- if($msi) {
- install_msi $fname $dir $msi
- } elseif($installer) {
- install_prog $fname $dir $installer $global
- }
-}
-
-# deprecated (see also msi_installed)
-function install_msi($fname, $dir, $msi) {
- $msifile = "$dir\$(coalesce $msi.file "$fname")"
- if(!(is_in_dir $dir $msifile)) {
- abort "Error in manifest: MSI file $msifile is outside the app directory."
- }
- if(!($msi.code)) { abort "Error in manifest: Couldn't find MSI code."}
- if(msi_installed $msi.code) { abort "The MSI package is already installed on this system." }
-
- $logfile = "$dir\install.log"
-
- $arg = @("/i `"$msifile`"", '/norestart', "/lvp `"$logfile`"", "TARGETDIR=`"$dir`"",
- "INSTALLDIR=`"$dir`"") + @(args $msi.args $dir)
-
- if($msi.silent) { $arg += '/qn', 'ALLUSERS=2', 'MSIINSTALLPERUSER=1' }
- else { $arg += '/qb-!' }
-
- $continue_exit_codes = @{ 3010 = "a restart is required to complete installation" }
-
- $installed = run 'msiexec' $arg "Running installer..." $continue_exit_codes
- if(!$installed) {
- abort "Installation aborted. You might need to run 'scoop uninstall $app' before trying again."
- }
- rm $logfile
- rm $msifile
-}
-
-function extract_msi($path, $to) {
- $logfile = "$(split-path $path)\msi.log"
- $ok = run 'msiexec' @('/a', "`"$path`"", '/qn', "TARGETDIR=`"$to`"", "/lwe `"$logfile`"")
- if(!$ok) { abort "Failed to extract files from $path.`nLog file:`n $(friendly_path $logfile)" }
- if(test-path $logfile) { rm $logfile }
-}
-
-function extract_lessmsi($path, $to) {
- iex "lessmsi x `"$path`" `"$to\`""
-}
-
-# deprecated
-# get-wmiobject win32_product is slow and checks integrity of each installed program,
-# so this uses the [wmi] type accelerator instead
-# http://blogs.technet.com/b/heyscriptingguy/archive/2011/12/14/use-powershell-to-find-and-uninstall-software.aspx
-function msi_installed($code) {
- $path = "hklm:\software\microsoft\windows\currentversion\uninstall\$code"
- if(!(test-path $path)) { return $false }
- $key = gi $path
- $name = $key.getvalue('displayname')
- $version = $key.getvalue('displayversion')
- $classkey = "IdentifyingNumber=`"$code`",Name=`"$name`",Version=`"$version`""
- try { $wmi = [wmi]"Win32_Product.$classkey"; $true } catch { $false }
-}
-
-function install_prog($fname, $dir, $installer, $global) {
- $prog = "$dir\$(coalesce $installer.file "$fname")"
- if(!(is_in_dir $dir $prog)) {
- abort "Error in manifest: Installer $prog is outside the app directory."
- }
- $arg = @(args $installer.args $dir $global)
-
- if($prog.endswith('.ps1')) {
- & $prog @arg
- } else {
- $installed = run $prog $arg "Running installer..."
- if(!$installed) {
- abort "Installation aborted. You might need to run 'scoop uninstall $app' before trying again."
- }
-
- # Don't remove installer if "keep" flag is set to true
- if(!($installer.keep -eq "true")) {
- rm $prog
- }
- }
-}
-
-function run_uninstaller($manifest, $architecture, $dir) {
- $msi = msi $manifest $architecture
- $uninstaller = uninstaller $manifest $architecture
-
- if($msi -or $uninstaller) {
- $exe = $null; $arg = $null; $continue_exit_codes = @{}
-
- if($msi) {
- $code = $msi.code
- $exe = "msiexec";
- $arg = @("/norestart", "/x $code")
- if($msi.silent) {
- $arg += '/qn', 'ALLUSERS=2', 'MSIINSTALLPERUSER=1'
- } else {
- $arg += '/qb-!'
- }
-
- $continue_exit_codes.1605 = 'not installed, skipping'
- $continue_exit_codes.3010 = 'restart required'
- } elseif($uninstaller) {
- $exe = "$dir\$($uninstaller.file)"
- $arg = args $uninstaller.args
- if(!(is_in_dir $dir $exe)) {
- warn "Error in manifest: Installer $exe is outside the app directory, skipping."
- $exe = $null;
- } elseif(!(test-path $exe)) {
- warn "Uninstaller $exe is missing, skipping."
- $exe = $null;
- }
- }
-
- if($exe) {
- if($exe.endswith('.ps1')) {
- & $exe @arg
- } else {
- $uninstalled = run $exe $arg "Running uninstaller..." $continue_exit_codes
- if(!$uninstalled) { abort "Uninstallation aborted." }
- }
- }
+ if ($script) {
+ Write-Host "Running $HookType script..." -NoNewline
+ Invoke-Command ([scriptblock]::Create($script -join "`r`n"))
+ Write-Host 'done.' -ForegroundColor Green
}
}
# get target, name, arguments for shim
function shim_def($item) {
- if($item -is [array]) { return $item }
+ if ($item -is [array]) { return $item }
return $item, (strip_ext (fname $item)), $null
}
function create_shims($manifest, $dir, $global, $arch) {
$shims = @(arch_specific 'bin' $manifest $arch)
- $shims | ?{ $_ -ne $null } | % {
+ $shims | Where-Object { $_ -ne $null } | ForEach-Object {
$target, $name, $arg = shim_def $_
- write-output "Creating shim for '$name'."
+ Write-Output "Creating shim for '$name'."
- # check valid bin
- $bin = "$dir\$target"
- if(!(is_in_dir $dir $bin)) {
- abort "Error in manifest: bin '$target' is outside the app directory."
+ if (Test-Path "$dir\$target" -PathType leaf) {
+ $bin = "$dir\$target"
+ } elseif (Test-Path $target -PathType leaf) {
+ $bin = $target
+ } else {
+ $bin = (Get-Command $target).Source
}
- if(!(test-path $bin)) { abort "Can't shim '$target': File doesn't exist."}
+ if (!$bin) { abort "Can't shim '$target': File doesn't exist." }
- shim "$dir\$target" $global $name $arg
+ shim $bin $global $name (substitute $arg @{ '$dir' = $dir; '$original_dir' = $original_dir; '$persist_dir' = $persist_dir })
}
}
-function rm_shim($name, $shimdir) {
- $shim = "$shimdir\$name.ps1"
-
- if(!(test-path $shim)) { # handle no shim from failed install
- warn "Shim for '$name' is missing. Skipping."
- } else {
- write-output "Removing shim for '$name'."
- rm $shim
- }
-
- # other shim types might be present
- '.exe', '.shim', '.cmd' | % {
- if(test-path "$shimdir\$name$_") { rm "$shimdir\$name$_" }
+function rm_shim($name, $shimdir, $app) {
+ '', '.shim', '.cmd', '.ps1' | ForEach-Object {
+ $shimPath = "$shimdir\$name$_"
+ $altShimPath = "$shimPath.$app"
+ if ($app -and (Test-Path -Path $altShimPath -PathType Leaf)) {
+ Write-Output "Removing shim '$name$_.$app'."
+ Remove-Item $altShimPath
+ } elseif (Test-Path -Path $shimPath -PathType Leaf) {
+ Write-Output "Removing shim '$name$_'."
+ Remove-Item $shimPath
+ $oldShims = Get-Item -Path "$shimPath.*" -Exclude '*.shim', '*.cmd', '*.ps1'
+ if ($null -eq $oldShims) {
+ if ($_ -eq '.shim') {
+ Write-Output "Removing shim '$name.exe'."
+ Remove-Item -Path "$shimdir\$name.exe"
+ }
+ } else {
+ (@($oldShims) | Sort-Object -Property LastWriteTimeUtc)[-1] | Rename-Item -NewName { $_.Name -replace '\.[^.]*$', '' }
+ }
+ }
}
}
-function rm_shims($manifest, $global, $arch) {
+function rm_shims($app, $manifest, $global, $arch) {
$shims = @(arch_specific 'bin' $manifest $arch)
- $shims | ?{ $_ -ne $null } | % {
+ $shims | Where-Object { $_ -ne $null } | ForEach-Object {
$target, $name, $null = shim_def $_
$shimdir = shimdir $global
- rm_shim $name $shimdir
+ rm_shim $name $shimdir $app
}
}
-# Gets the path for the 'current' directory junction for
-# the specified version directory.
-function current_dir($versiondir) {
- $parent = split-path $versiondir
- return "$parent\current"
-}
-
-
# Creates or updates the directory junction for [app]/current,
# pointing to the specified version directory for the app.
#
# Returns the 'current' junction directory if in use, otherwise
# the version directory.
function link_current($versiondir) {
- if(get_config NO_JUNCTIONS) { return $versiondir }
+ if (get_config NO_JUNCTION) { return $versiondir.ToString() }
- $currentdir = current_dir $versiondir
+ $currentdir = "$(Split-Path $versiondir)\current"
- write-host "Linking $(friendly_path $currentdir) => $(friendly_path $versiondir)"
+ Write-Host "Linking $(friendly_path $currentdir) => $(friendly_path $versiondir)"
- if($currentdir -eq $versiondir) {
+ if ($currentdir -eq $versiondir) {
abort "Error: Version 'current' is not allowed!"
}
- if(test-path $currentdir) {
+ if (Test-Path $currentdir) {
# remove the junction
- cmd /c rmdir $currentdir
+ attrib -R /L $currentdir
+ Remove-Item $currentdir -Recurse -Force -ErrorAction Stop
}
- cmd /c mklink /j $currentdir $versiondir | out-null
+ New-DirectoryJunction $currentdir $versiondir | Out-Null
attrib $currentdir +R /L
return $currentdir
}
@@ -737,17 +263,17 @@ 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 }
- $currentdir = current_dir $versiondir
+ if (get_config NO_JUNCTION) { return $versiondir.ToString() }
+ $currentdir = "$(Split-Path $versiondir)\current"
- if(test-path $currentdir) {
- write-host "Unlinking $(friendly_path $currentdir)"
+ if (Test-Path $currentdir) {
+ Write-Host "Unlinking $(friendly_path $currentdir)"
# remove read-only attribute on link
attrib $currentdir -R /L
# remove the junction
- cmd /c rmdir $currentdir
+ Remove-Item $currentdir -Recurse -Force -ErrorAction Stop
return $currentdir
}
return $versiondir
@@ -755,18 +281,18 @@ function unlink_current($versiondir) {
# to undo after installers add to path so that scoop manifest can keep track of this instead
function ensure_install_dir_not_in_path($dir, $global) {
- $path = (env 'path' $global)
+ $path = (Get-EnvVar -Name 'PATH' -Global:$global)
$fixed, $removed = find_dir_or_subdir $path "$dir"
- if($removed) {
- $removed | % { "Installer added '$(friendly_path $_)' to path. Removing."}
- env 'path' $global $fixed
+ if ($removed) {
+ $removed | ForEach-Object { "Installer added '$(friendly_path $_)' to path. Removing." }
+ Set-EnvVar -Name 'PATH' -Value $fixed -Global:$global
}
- if(!$global) {
- $fixed, $removed = find_dir_or_subdir (env 'path' $true) "$dir"
- if($removed) {
- $removed | % { warn "Installer added '$_' to system path. You might want to remove this manually (requires admin permission)."}
+ if (!$global) {
+ $fixed, $removed = find_dir_or_subdir (Get-EnvVar -Name 'PATH' -Global) "$dir"
+ if ($removed) {
+ $removed | ForEach-Object { warn "Installer added '$_' to system path. You might want to remove this manually (requires admin permission)." }
}
}
}
@@ -775,117 +301,70 @@ function find_dir_or_subdir($path, $dir) {
$dir = $dir.trimend('\')
$fixed = @()
$removed = @()
- $path.split(';') | % {
- if($_) {
- if(($_ -eq $dir) -or ($_ -like "$dir\*")) { $removed += $_ }
+ $path.split(';') | ForEach-Object {
+ if ($_) {
+ if (($_ -eq $dir) -or ($_ -like "$dir\*")) { $removed += $_ }
else { $fixed += $_ }
}
}
return [string]::join(';', $fixed), $removed
}
-function env_add_path($manifest, $dir, $global) {
- $manifest.env_add_path | ? { $_ } | % {
- $path_dir = join-path $dir $_
-
- if(!(is_in_dir $dir $path_dir)) {
- abort "Error in manifest: env_add_path '$_' is outside the app directory."
+function env_add_path($manifest, $dir, $global, $arch) {
+ $env_add_path = arch_specific 'env_add_path' $manifest $arch
+ $dir = $dir.TrimEnd('\')
+ if ($env_add_path) {
+ if (get_config USE_ISOLATED_PATH) {
+ Add-Path -Path ('%' + $scoopPathEnvVar + '%') -Global:$global
}
- add_first_in_path $path_dir $global
+ $path = $env_add_path.Where({ $_ }).ForEach({ Join-Path $dir $_ | Get-AbsolutePath }).Where({ is_in_dir $dir $_ })
+ Add-Path -Path $path -TargetEnvVar $scoopPathEnvVar -Global:$global -Force
}
}
-function add_first_in_path($dir, $global) {
- $dir = fullpath $dir
-
- # future sessions
- $null, $currpath = strip_path (env 'path' $global) $dir
- env 'path' $global "$dir;$currpath"
-
- # this session
- $null, $env:PATH = strip_path $env:PATH $dir
- $env:PATH = "$dir;$env:PATH"
-}
-
-function env_rm_path($manifest, $dir, $global) {
- # remove from path
- $manifest.env_add_path | ? { $_ } | % {
- $path_dir = join-path $dir $_
-
- remove_from_path $path_dir $global
+function env_rm_path($manifest, $dir, $global, $arch) {
+ $env_add_path = arch_specific 'env_add_path' $manifest $arch
+ $dir = $dir.TrimEnd('\')
+ if ($env_add_path) {
+ $path = $env_add_path.Where({ $_ }).ForEach({ Join-Path $dir $_ | Get-AbsolutePath }).Where({ is_in_dir $dir $_ })
+ Remove-Path -Path $path -Global:$global # TODO: Remove after forced isolating Scoop path
+ Remove-Path -Path $path -TargetEnvVar $scoopPathEnvVar -Global:$global
}
}
-function env_set($manifest, $dir, $global) {
- if($manifest.env_set) {
- $manifest.env_set | gm -member noteproperty | % {
- $name = $_.name;
- $val = format $manifest.env_set.$($_.name) @{ "dir" = $dir }
- env $name $global $val
- sc env:\$name $val
- }
- }
-}
-function env_rm($manifest, $global) {
- if($manifest.env_set) {
- $manifest.env_set | gm -member noteproperty | % {
- $name = $_.name
- env $name $global $null
- if(test-path env:\$name) { rm env:\$name }
+function env_set($manifest, $global, $arch) {
+ $env_set = arch_specific 'env_set' $manifest $arch
+ if ($env_set) {
+ $env_set | Get-Member -MemberType NoteProperty | ForEach-Object {
+ $name = $_.Name
+ $val = $ExecutionContext.InvokeCommand.ExpandString($env_set.$($name))
+ Set-EnvVar -Name $name -Value $val -Global:$global
+ Set-Content env:\$name $val
}
}
}
-
-# UNNECESSARY? Re-evaluate after 3-Jun-2017
-# Supposedly some MSYS programs require %HOME% to be set, but I can't
-# find any examples.
-# Shims used to set %HOME% for the session, but this was removed.
-# This function remains in case we need to support this functionality again
-# (e.g. env_ensure_home in manifests). But if no problems arise by 3-Jun-2017,
-# it's probably safe to delete this, and the call to it install_app
-function env_ensure_home($manifest, $global) {
- if($manifest.env_ensure_home -eq $true) {
- if($global){
- if(!(env 'HOME' $true)) {
- env 'HOME' $true $env:ALLUSERSPROFILE
- $env:HOME = $env:ALLUSERSPROFILE # current session
- }
- } else {
- if(!(env 'HOME' $false)) {
- env 'HOME' $false $env:USERPROFILE
- $env:HOME = $env:USERPROFILE # current session
- }
+function env_rm($manifest, $global, $arch) {
+ $env_set = arch_specific 'env_set' $manifest $arch
+ if ($env_set) {
+ $env_set | Get-Member -MemberType NoteProperty | ForEach-Object {
+ $name = $_.Name
+ Set-EnvVar -Name $name -Value $null -Global:$global
+ if (Test-Path env:\$name) { Remove-Item env:\$name }
}
}
}
-function pre_install($manifest, $arch) {
- $pre_install = arch_specific 'pre_install' $manifest $arch
- if($pre_install) {
- write-output "Running pre-install script..."
- iex $pre_install
- }
-}
-
-function post_install($manifest, $arch) {
- $post_install = arch_specific 'post_install' $manifest $arch
- if($post_install) {
- write-output "Running post-install script..."
- iex $post_install
- }
-}
-
function show_notes($manifest, $dir, $original_dir, $persist_dir) {
- if($manifest.notes) {
- write-output "Notes"
- write-output "-----"
- write-output (wraptext (substitute $manifest.notes @{ '$dir' = $dir; '$original_dir' = $original_dir; '$persist_dir' = $persist_dir}))
+ if ($manifest.notes) {
+ Write-Output 'Notes'
+ Write-Output '-----'
+ Write-Output (wraptext (substitute $manifest.notes @{ '$dir' = $dir; '$original_dir' = $original_dir; '$persist_dir' = $persist_dir }))
}
}
function all_installed($apps, $global) {
- $apps | ? {
- $app, $null = app $_
+ $apps | Where-Object {
+ $app, $null, $null = parse_app $_
installed $app $global
}
}
@@ -894,24 +373,29 @@ function all_installed($apps, $global) {
function prune_installed($apps, $global) {
$installed = @(all_installed $apps $global)
- $uninstalled = $apps | ? { $installed -notcontains $_ }
+ $uninstalled = $apps | Where-Object { $installed -notcontains $_ }
return @($uninstalled), @($installed)
}
-# check whether the app failed to install
-function failed($app, $global) {
- $ver = current_version $app $global
- if(!$ver) { return $false }
- $info = install_info $app $ver $global
- if(!$info) { return $true }
- return $false
-}
-
-function ensure_none_failed($apps, $global) {
- foreach($app in $apps) {
- if(failed $app $global) {
- abort "'$app' install failed previously. Please uninstall it and try again."
+function ensure_none_failed($apps) {
+ foreach ($app in $apps) {
+ $app = ($app -split '/|\\')[-1] -replace '\.json$', ''
+ foreach ($global in $true, $false) {
+ if ($global) {
+ $instArgs = @('--global')
+ } else {
+ $instArgs = @()
+ }
+ if (failed $app $global) {
+ if (installed $app $global) {
+ info "Repair previous failed installation of $app."
+ & "$PSScriptRoot\..\libexec\scoop-reset.ps1" $app @instArgs
+ } else {
+ warn "Purging previous failed installation of $app."
+ & "$PSScriptRoot\..\libexec\scoop-uninstall.ps1" $app @instArgs
+ }
+ }
}
}
}
@@ -919,23 +403,23 @@ function ensure_none_failed($apps, $global) {
function show_suggestions($suggested) {
$installed_apps = (installed_apps $true) + (installed_apps $false)
- foreach($app in $suggested.keys) {
- $features = $suggested[$app] | get-member -type noteproperty |% { $_.name }
- foreach($feature in $features) {
+ foreach ($app in $suggested.keys) {
+ $features = $suggested[$app] | Get-Member -type noteproperty | ForEach-Object { $_.name }
+ foreach ($feature in $features) {
$feature_suggestions = $suggested[$app].$feature
$fulfilled = $false
- foreach($suggestion in $feature_suggestions) {
- $suggested_app, $bucket = app $suggestion
+ foreach ($suggestion in $feature_suggestions) {
+ $suggested_app, $bucket, $null = parse_app $suggestion
- if($installed_apps -contains $suggested_app) {
- $fulfilled = $true;
- break;
+ if ($installed_apps -contains $suggested_app) {
+ $fulfilled = $true
+ break
}
}
- if(!$fulfilled) {
- write-host "'$app' suggests installing '$([string]::join("' or '", $feature_suggestions))'."
+ if (!$fulfilled) {
+ Write-Host "'$app' suggests installing '$([string]::join("' or '", $feature_suggestions))'."
}
}
}
@@ -952,7 +436,7 @@ function persist_def($persist) {
}
if (!$target) {
- $target = fname($source)
+ $target = $source
}
return $source, $target
@@ -960,42 +444,119 @@ function persist_def($persist) {
function persist_data($manifest, $original_dir, $persist_dir) {
$persist = $manifest.persist
- if($persist) {
+ if ($persist) {
$persist_dir = ensure $persist_dir
if ($persist -is [String]) {
- $persist = @($persist);
+ $persist = @($persist)
}
- $persist | % {
+ $persist | ForEach-Object {
$source, $target = persist_def $_
- write-host "Persisting $source"
+ Write-Host "Persisting $source"
- # add base paths
- $source = fullpath "$dir\$source"
- $target = fullpath "$persist_dir\$target"
+ $source = $source.TrimEnd('/').TrimEnd('\\')
- if (!(test-path $target)) {
- # If we do not have data in the store we move the original
- if (test-path $source) {
- Move-Item $source $target
- } else {
- # if there is no source we create an empty directory
- $target = ensure $target
+ $source = "$dir\$source"
+ $target = "$persist_dir\$target"
+
+ # if we have had persist data in the store, just create link and go
+ if (Test-Path $target) {
+ # if there is also a source data, rename it (to keep a original backup)
+ if (Test-Path $source) {
+ Move-Item -Force $source "$source.original"
}
- } elseif (test-path $source) {
- # (re)move original (keep a copy)
- Move-Item $source "$source.original"
+ # we don't have persist data in the store, move the source to target, then create link
+ } elseif (Test-Path $source) {
+ # ensure target parent folder exist
+ ensure (Split-Path -Path $target) | Out-Null
+ Move-Item $source $target
+ # we don't have neither source nor target data! we need to create an empty target,
+ # but we can't make a judgement that the data should be a file or directory...
+ # so we create a directory by default. to avoid this, use pre_install
+ # to create the source file before persisting (DON'T use post_install)
+ } else {
+ $target = New-Object System.IO.DirectoryInfo($target)
+ ensure $target | Out-Null
}
# create link
if (is_directory $target) {
- cmd /c "mklink /j `"$source`" `"$target`"" | out-null
- attrib "$source" +R /L
+ # target is a directory, create junction
+ New-DirectoryJunction $source $target | Out-Null
+ attrib $source +R /L
} else {
- cmd /c "mklink /h `"$source`" `"$target`"" | out-null
+ # target is a file, create hard link
+ New-Item -Path $source -ItemType HardLink -Value $target | Out-Null
+ }
+ }
+ }
+}
+
+function unlink_persist_data($manifest, $dir) {
+ $persist = $manifest.persist
+ # unlink all junction / hard link in the directory
+ if ($persist) {
+ @($persist) | ForEach-Object {
+ $source, $null = persist_def $_
+ $source = Get-Item "$dir\$source" -ErrorAction SilentlyContinue
+ if ($source.LinkType) {
+ $source_path = $source.FullName
+ # directory (junction)
+ if ($source -is [System.IO.DirectoryInfo]) {
+ # remove read-only attribute on the link
+ attrib -R /L $source_path
+ # remove the junction
+ Remove-Item -Path $source_path -Recurse -Force -ErrorAction SilentlyContinue
+ } else {
+ # remove the hard link
+ Remove-Item -Path $source_path -Force -ErrorAction SilentlyContinue
+ }
}
}
}
}
+
+# check whether write permission for Users usergroup is set to global persist dir, if not then set
+function persist_permission($manifest, $global) {
+ if ($global -and $manifest.persist -and (is_admin)) {
+ $path = persistdir $null $global
+ $user = New-Object System.Security.Principal.SecurityIdentifier 'S-1-5-32-545'
+ $target_rule = New-Object System.Security.AccessControl.FileSystemAccessRule($user, 'Write', 'ObjectInherit', 'none', 'Allow')
+ $acl = Get-Acl -Path $path
+ $acl.SetAccessRule($target_rule)
+ $acl | Set-Acl -Path $path
+ }
+}
+
+# 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\*" } | Out-String
+
+ if ($running_processes) {
+ 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 "The following instances of `"$app`" are still running. Close them and try again."
+ Write-Host $running_processes
+ return $true
+ }
+ } else {
+ return $false
+ }
+}
+
+# wrapper function to create junction links
+# Required to handle docker/for-win#12240
+function New-DirectoryJunction($source, $target) {
+ # test if this script is being executed inside a docker container
+ if (Get-Service -Name cexecsvc -ErrorAction SilentlyContinue) {
+ cmd.exe /d /c "mklink /j `"$source`" `"$target`""
+ } else {
+ New-Item -Path $source -ItemType Junction -Value $target
+ }
+}
diff --git a/lib/json.ps1 b/lib/json.ps1
index fa697dcc2e..d6fd3621b5 100644
--- a/lib/json.ps1
+++ b/lib/json.ps1
@@ -1,24 +1,30 @@
# Convert objects to pretty json
# Only needed until PowerShell ConvertTo-Json will be improved https://github.com/PowerShell/PowerShell/issues/2736
-Function ConvertToPrettyJson {
- [cmdletbinding()]
+# https://github.com/PowerShell/PowerShell/issues/2736 was fixed in pwsh
+# Still needed in normal powershell
+
+function ConvertToPrettyJson {
+ [CmdletBinding()]
Param (
- [parameter(Mandatory, ValueFromPipeline)]
+ [Parameter(Mandatory, ValueFromPipeline)]
$data
)
- Process {
+ Process {
+ $data = normalize_values $data
+
+ # convert to string
[String]$json = $data | ConvertTo-Json -Depth 8 -Compress
- [String]$output = ""
+ [String]$output = ''
# state
- [String]$buffer = ""
+ [String]$buffer = ''
[Int]$depth = 0
[Bool]$inString = $false
# configuration
- [String]$indent = " " * 4
+ [String]$indent = ' ' * 4
[Bool]$unescapeString = $true
[String]$eol = "`r`n"
@@ -26,13 +32,12 @@ Function ConvertToPrettyJson {
# read current char
$buffer = $json.Substring($i, 1)
- #
- $objectStart = !$inString -and $buffer.Equals("{")
- $objectEnd = !$inString -and $buffer.Equals("}")
- $arrayStart = !$inString -and $buffer.Equals("[")
- $arrayEnd = !$inString -and $buffer.Equals("]")
- $colon = !$inString -and $buffer.Equals(":")
- $comma = !$inString -and $buffer.Equals(",")
+ $objectStart = !$inString -and $buffer.Equals('{')
+ $objectEnd = !$inString -and $buffer.Equals('}')
+ $arrayStart = !$inString -and $buffer.Equals('[')
+ $arrayEnd = !$inString -and $buffer.Equals(']')
+ $colon = !$inString -and $buffer.Equals(':')
+ $comma = !$inString -and $buffer.Equals(',')
$quote = $buffer.Equals('"')
$escape = $buffer.Equals('\')
@@ -76,37 +81,71 @@ Function ConvertToPrettyJson {
# add whitespace and newlines after the content
if ($colon) {
- $output += " "
+ $output += ' '
} elseif ($comma -or $arrayStart -or $objectStart) {
$output += $eol
$output += $indent * $depth
}
}
- $output
+ return $output
}
}
-function json_path([Object] $json, [String] $jsonpath, [String] $basename) {
- $result = $json
- $isJsonPath = $jsonpath.StartsWith("`$")
- $jsonpath.split(".") | ForEach-Object {
+function json_path([String] $json, [String] $jsonpath, [Hashtable] $substitutions, [Boolean] $reverse, [Boolean] $single) {
+ Add-Type -Path "$PSScriptRoot\..\supporting\validator\bin\Newtonsoft.Json.dll"
+ if ($null -ne $substitutions) {
+ $jsonpath = substitute $jsonpath $substitutions ($jsonpath -like "*=~*")
+ }
+ try {
+ $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
+ }
+ try {
+ $result = $obj.SelectTokens($jsonpath, $true)
+ if ($reverse) {
+ # Return versions in reverse order
+ $result = [System.Linq.Enumerable]::Reverse($result)
+ }
+ if ([System.Linq.Enumerable]::Count($result) -eq 1 -or $single) {
+ # Extract First value
+ $result = [System.Linq.Enumerable]::First($result)
+ # Convert first value to string
+ $result = $result.ToString()
+ } else {
+ $result = [Newtonsoft.Json.JsonConvert]::SerializeObject($result)
+ }
+ return $result
+ } catch [Exception] {
+ Write-Host $_ -ForegroundColor DarkRed
+ }
+
+ return $null
+}
+
+function json_path_legacy([String] $json, [String] $jsonpath, [Hashtable] $substitutions) {
+ $result = $json | ConvertFrom-Json -ea stop
+ $isJsonPath = $jsonpath.StartsWith('$')
+ $jsonpath.split('.') | ForEach-Object {
$el = $_
- # substitute the base filename into the jsonpath
- if($el.Contains("`$basename")) {
- $el = $el.Replace("`$basename", $basename)
+ # substitute the basename and version varibales into the jsonpath
+ if ($null -ne $substitutions) {
+ $el = substitute $el $substitutions
}
# skip $ if it's jsonpath format
- if($el -eq "`$" -and $isJsonPath) {
+ if ($el -eq '$' -and $isJsonPath) {
return
}
# array detection
- if($el -match "^(?\w+)?\[(?\d+)\]$") {
+ if ($el -match '^(?\w+)?\[(?\d+)\]$') {
$property = $matches['property']
- if($property) {
+ if ($property) {
$result = $result.$property[$matches['index']]
} else {
$result = $result[$matches['index']]
@@ -118,3 +157,58 @@ function json_path([Object] $json, [String] $jsonpath, [String] $basename) {
}
return $result
}
+
+function normalize_values([psobject] $json) {
+ # Iterate Through Manifest Properties
+ $json.PSObject.Properties | ForEach-Object {
+ # Recursively edit psobjects
+ # If the values is psobjects, its not normalized
+ # For example if manifest have architecture and it's architecture have array with single value it's not formatted.
+ # @see https://github.com/ScoopInstaller/Scoop/pull/2642#issue-220506263
+ if ($_.Value -is [System.Management.Automation.PSCustomObject]) {
+ $_.Value = normalize_values $_.Value
+ }
+
+ # Process String Values
+ if ($_.Value -is [String]) {
+
+ # Split on new lines
+ [Array] $parts = ($_.Value -split '\r?\n').Trim()
+
+ # Replace with string array if result is multiple lines
+ if ($parts.Count -gt 1) {
+ $_.Value = $parts
+ }
+ }
+
+ # Convert single value array into string
+ if ($_.Value -is [Array]) {
+ # Array contains only 1 element String or Array
+ if ($_.Value.Count -eq 1) {
+ # Array
+ if ($_.Value[0] -is [Array]) {
+ $_.Value = $_.Value
+ } else {
+ # String
+ $_.Value = $_.Value[0]
+ }
+ } else {
+ # Array of Arrays
+ $resulted_arrs = @()
+ foreach ($element in $_.Value) {
+ if ($element.Count -eq 1) {
+ $resulted_arrs += $element
+ } else {
+ $resulted_arrs += , $element
+ }
+ }
+
+ $_.Value = $resulted_arrs
+ }
+ }
+
+ # Process other values as needed...
+ }
+
+ return $json
+}
diff --git a/lib/manifest.ps1 b/lib/manifest.ps1
index b8c09c9da9..29c898b6a7 100644
--- a/lib/manifest.ps1
+++ b/lib/manifest.ps1
@@ -1,36 +1,130 @@
-. "$psscriptroot/core.ps1"
-. "$psscriptroot/autoupdate.ps1"
-
function manifest_path($app, $bucket) {
- "$(bucketdir $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 }
- gc $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) {
$str = $null
try {
- $str = (new-object net.webclient).downloadstring($url)
+ $wc = New-Object Net.Webclient
+ $wc.Headers.Add('User-Agent', (Get-UserAgent))
+ $data = $wc.DownloadData($url)
+ $str = (Get-Encoding($wc)).GetString($data)
} catch [system.management.automation.methodinvocationexception] {
warn "error: $($_.exception.innerexception.message)"
} catch {
throw
}
- if(!$str) { return $null }
- $str | convertfrom-json
+ if (!$str) { return $null }
+ try {
+ $str | ConvertFrom-Json -ErrorAction Stop
+ } catch {
+ warn "Error parsing JSON at '$url'."
+ }
+}
+
+function Get-Manifest($app) {
+ $bucket, $manifest, $url = $null
+ $app = $app.TrimStart('/')
+ # check if app is a URL or UNC path
+ if ($app -match '^(ht|f)tps?://|\\\\') {
+ $url = $app
+ $app = appname_from_url $url
+ $manifest = url_manifest $url
+ } else {
+ # Check if the manifest is already installed
+ if (installed $app) {
+ $global = installed $app $true
+ $ver = Select-CurrentVersion -AppName $app -Global:$global
+ if (!$ver) {
+ $app, $bucket, $ver = parse_app $app
+ $ver = Select-CurrentVersion -AppName $app -Global:$global
+ }
+ $install_info_path = "$(versiondir $app $ver $global)\install.json"
+ if (Test-Path $install_info_path) {
+ $install_info = parse_json $install_info_path
+ $bucket = $install_info.bucket
+ if (!$bucket) {
+ $url = $install_info.url
+ if ($url -match '^(ht|f)tps?://|\\\\') {
+ $manifest = url_manifest $url
+ }
+ if (!$manifest) {
+ if (Test-Path $url) {
+ $manifest = parse_json $url
+ } else {
+ # Fallback to installed manifest
+ $manifest = installed_manifest $app $ver $global
+ }
+ }
+ } else {
+ $manifest = manifest $app $bucket
+ if (!$manifest) {
+ $deprecated_dir = (Find-BucketDirectory -Name $bucket -Root) + '\deprecated'
+ $manifest = parse_json (Get-ChildItem $deprecated_dir -Filter "$(sanitary_path $app).json" -Recurse).FullName
+ }
+ }
+ }
+ } else {
+ $app, $bucket, $version = parse_app $app
+ if ($bucket) {
+ $manifest = manifest $app $bucket
+ } else {
+ $matched_buckets = @()
+ foreach ($tekcub in Get-LocalBucket) {
+ $current_manifest = manifest $app $tekcub
+ if (!$manifest -and $current_manifest) {
+ $manifest = $current_manifest
+ $bucket = $tekcub
+ }
+ if ($current_manifest) {
+ $matched_buckets += $tekcub
+ }
+ }
+ }
+ if (!$manifest) {
+ # couldn't find app in buckets: check if it's a local path
+ if (Test-Path $app) {
+ $url = Convert-Path $app
+ $app = appname_from_url $url
+ $manifest = parse_json $url
+ } else {
+ if (($app -match '\\/') -or $app.EndsWith('.json')) { $url = $app }
+ $app = appname_from_url $app
+ }
+ }
+ }
+ }
+
+ if ($matched_buckets.Length -gt 1) {
+ warn "Multiple buckets contain manifest '$app', the current selection is '$bucket/$app'."
+ }
+
+ return $app, $manifest, $bucket, $url
}
function manifest($app, $bucket, $url) {
- if($url) { return url_manifest $url }
+ if ($url) { return url_manifest $url }
parse_json (manifest_path $app $bucket)
}
function save_installed_manifest($app, $bucket, $dir, $url) {
- if($url) { (new-object net.webclient).downloadstring($url) > "$dir\manifest.json" }
- else { cp (manifest_path $app $bucket) "$dir\manifest.json" }
+ if ($url) {
+ $wc = New-Object Net.Webclient
+ $wc.Headers.Add('User-Agent', (Get-UserAgent))
+ $data = $wc.DownloadData($url)
+ (Get-Encoding($wc)).GetString($data) | Out-UTF8File "$dir\manifest.json"
+ } else {
+ Copy-Item (manifest_path $app $bucket) "$dir\manifest.json"
+ }
}
function installed_manifest($app, $version, $global) {
@@ -38,51 +132,75 @@ function installed_manifest($app, $version, $global) {
}
function save_install_info($info, $dir) {
- $nulls = $info.keys | ? { $info[$_] -eq $null }
- $nulls | % { $info.remove($_) } # strip null-valued
+ $nulls = $info.keys | Where-Object { $null -eq $info[$_] }
+ $nulls | ForEach-Object { $info.remove($_) } # strip null-valued
- $info | convertto-json | out-file "$dir\install.json"
+ $file_content = $info | ConvertToPrettyJson # in 'json.ps1'
+ [System.IO.File]::WriteAllLines("$dir\install.json", $file_content)
}
function install_info($app, $version, $global) {
$path = "$(versiondir $app $version $global)\install.json"
- if(!(test-path $path)) { return $null }
+ if (!(Test-Path $path)) { return $null }
parse_json $path
}
-function default_architecture {
- if([intptr]::size -eq 8) { return "64bit" }
- "32bit"
-}
-
function arch_specific($prop, $manifest, $architecture) {
- if($manifest.architecture) {
+ if ($manifest.architecture) {
$val = $manifest.architecture.$architecture.$prop
- if($val) { return $val } # else fallback to generic prop
+ if ($val) { return $val } # else fallback to generic prop
}
- if($manifest.$prop) { return $manifest.$prop }
+ if ($manifest.$prop) { return $manifest.$prop }
}
-function generate_user_manifest($app, $version) {
+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
+ }
+}
- $null, $manifest, $bucket, $null = locate $app
+function generate_user_manifest($app, $bucket, $version) {
+ # 'autoupdate.ps1' 'buckets.ps1' 'manifest.ps1'
+ $app, $manifest, $bucket, $null = Get-Manifest "$bucket/$app"
if ("$($manifest.version)" -eq "$version") {
return manifest_path $app $bucket
}
warn "Given version ($version) does not match manifest ($($manifest.version))"
warn "Attempting to generate manifest for '$app' ($version)"
+ ensure (usermanifestsdir) | Out-Null
+ $manifest_path = "$(usermanifestsdir)\$app.json"
+
+ if (get_config USE_SQLITE_CACHE) {
+ $cached_manifest = (Get-ScoopDBItem -Name $app -Bucket $bucket -Version $version).manifest
+ if ($cached_manifest) {
+ $cached_manifest | Out-UTF8File $manifest_path
+ return $manifest_path
+ }
+ }
+
if (!($manifest.autoupdate)) {
abort "'$app' does not have autoupdate capability`r`ncouldn't find manifest for '$app@$version'"
}
- ensure $(usermanifestsdir) | out-null
try {
- autoupdate $app "$(resolve-path $(usermanifestsdir))" $manifest $version $(New-Object HashTable)
- return "$(resolve-path $(usermanifest $app))"
+ Invoke-AutoUpdate $app $manifest_path $manifest $version $(@{ })
+ return $manifest_path
} catch {
- write-host -f darkred "Could not install $app@$version"
+ Write-Host -ForegroundColor DarkRed "Could not install $app@$version"
}
return $null
@@ -91,7 +209,6 @@ function generate_user_manifest($app, $version) {
function url($manifest, $arch) { arch_specific 'url' $manifest $arch }
function installer($manifest, $arch) { arch_specific 'installer' $manifest $arch }
function uninstaller($manifest, $arch) { arch_specific 'uninstaller' $manifest $arch }
-function msi($manifest, $arch) { arch_specific 'msi' $manifest $arch }
function hash($manifest, $arch) { arch_specific 'hash' $manifest $arch }
-function extract_dir($manifest, $arch) { arch_specific 'extract_dir' $manifest $arch}
-function extract_to($manifest, $arch) { arch_specific 'extract_to' $manifest $arch}
+function extract_dir($manifest, $arch) { arch_specific 'extract_dir' $manifest $arch }
+function extract_to($manifest, $arch) { arch_specific 'extract_to' $manifest $arch }
diff --git a/lib/psmodules.ps1 b/lib/psmodules.ps1
index 1c27fe7e7c..9d0cb7ce8a 100644
--- a/lib/psmodules.ps1
+++ b/lib/psmodules.ps1
@@ -1,57 +1,54 @@
-$modulesdir = "$scoopdir\modules"
-
function install_psmodule($manifest, $dir, $global) {
$psmodule = $manifest.psmodule
- if(!$psmodule) { return }
+ if (!$psmodule) { return }
- if($global) {
- abort "Installing PowerShell modules globally is not implemented!"
- }
+ $targetdir = ensure (modulesdir $global)
- $modulesdir = ensure $modulesdir
- ensure_in_psmodulepath $modulesdir $global
+ ensure_in_psmodulepath $targetdir $global
$module_name = $psmodule.name
- if(!$module_name) {
+ if (!$module_name) {
abort "Invalid manifest: The 'name' property is missing from 'psmodule'."
- return
}
- $linkfrom = "$modulesdir\$module_name"
- write-host "Installing PowerShell module '$module_name'"
+ $linkfrom = "$targetdir\$module_name"
+ Write-Host "Installing PowerShell module '$module_name'"
- write-host "Linking $(friendly_path $linkfrom) => $(friendly_path $dir)"
+ Write-Host "Linking $(friendly_path $linkfrom) => $(friendly_path $dir)"
- if(test-path $linkfrom) {
+ if (Test-Path $linkfrom) {
warn "$(friendly_path $linkfrom) already exists. It will be replaced."
- cmd /c rmdir $linkfrom
+ Remove-Item -Path $linkfrom -Force -Recurse -ErrorAction SilentlyContinue
}
- cmd /c mklink /j $linkfrom $dir | out-null
+ New-DirectoryJunction $linkfrom $dir | Out-Null
}
function uninstall_psmodule($manifest, $dir, $global) {
$psmodule = $manifest.psmodule
- if(!$psmodule) { return }
+ if (!$psmodule) { return }
$module_name = $psmodule.name
- write-host "Uninstalling PowerShell module '$module_name'."
+ Write-Host "Uninstalling PowerShell module '$module_name'."
- $linkfrom = "$modulesdir\$module_name"
- if(test-path $linkfrom) {
- write-host "Removing $(friendly_path $linkfrom)"
- $linkfrom = resolve-path $linkfrom
- cmd /c rmdir $linkfrom
+ $targetdir = modulesdir $global
+
+ $linkfrom = "$targetdir\$module_name"
+ if (Test-Path $linkfrom) {
+ Write-Host "Removing $(friendly_path $linkfrom)"
+ $linkfrom = Convert-Path $linkfrom
+ Remove-Item -Path $linkfrom -Force -Recurse -ErrorAction SilentlyContinue
}
}
function ensure_in_psmodulepath($dir, $global) {
- $path = env 'psmodulepath' $global
- $dir = fullpath $dir
- if($path -notmatch [regex]::escape($dir)) {
- write-output "Adding $(friendly_path $dir) to $(if($global){'global'}else{'your'}) PowerShell module path."
+ $path = Get-EnvVar -Name 'PSModulePath' -Global:$global
+ if (!$global -and $null -eq $path) {
+ $path = "$env:USERPROFILE\Documents\WindowsPowerShell\Modules"
+ }
+ if ($path -notmatch [Regex]::Escape($dir)) {
+ Write-Output "Adding $(friendly_path $dir) to $(if($global){'global'}else{'your'}) PowerShell module path."
- env 'psmodulepath' $global "$dir;$path" # for future sessions...
- $env:psmodulepath = "$dir;$env:psmodulepath" # for this session
+ Set-EnvVar -Name 'PSModulePath' -Value "$dir;$path" -Global:$global
}
}
diff --git a/lib/shortcuts.ps1 b/lib/shortcuts.ps1
index e10dbe7ede..edb6357480 100644
--- a/lib/shortcuts.ps1
+++ b/lib/shortcuts.ps1
@@ -1,59 +1,72 @@
# Creates shortcut for the app in the start menu
function create_startmenu_shortcuts($manifest, $dir, $global, $arch) {
$shortcuts = @(arch_specific 'shortcuts' $manifest $arch)
- $shortcuts | ?{ $_ -ne $null } | % {
- $target = $_.item(0)
+ $shortcuts | Where-Object { $_ -ne $null } | ForEach-Object {
+ $target = [System.IO.Path]::Combine($dir, $_.item(0))
+ $target = New-Object System.IO.FileInfo($target)
$name = $_.item(1)
- startmenu_shortcut "$dir\$target" $name $global
+ $arguments = ''
+ $icon = $null
+ if ($_.length -ge 3) {
+ $arguments = $_.item(2)
+ }
+ if ($_.length -ge 4) {
+ $icon = [System.IO.Path]::Combine($dir, $_.item(3))
+ $icon = New-Object System.IO.FileInfo($icon)
+ }
+ $arguments = (substitute $arguments @{ '$dir' = $dir; '$original_dir' = $original_dir; '$persist_dir' = $persist_dir })
+ startmenu_shortcut $target $name $arguments $icon $global
}
}
function shortcut_folder($global) {
- if($global) {
- "$([environment]::getfolderpath('commonstartmenu'))\Programs\Scoop Apps"
- return
+ if ($global) {
+ $startmenu = 'CommonStartMenu'
+ } else {
+ $startmenu = 'StartMenu'
}
- "$([environment]::getfolderpath('startmenu'))\Programs\Scoop Apps"
+ return Convert-Path (ensure ([System.IO.Path]::Combine([Environment]::GetFolderPath($startmenu), 'Programs', 'Scoop Apps')))
}
-function startmenu_shortcut($target, $shortcutName, $global) {
- if(!(Test-Path $target)) {
+function startmenu_shortcut([System.IO.FileInfo] $target, $shortcutName, $arguments, [System.IO.FileInfo]$icon, $global) {
+ if (!$target.Exists) {
Write-Host -f DarkRed "Creating shortcut for $shortcutName ($(fname $target)) failed: Couldn't find $target"
return
}
+ if ($icon -and !$icon.Exists) {
+ Write-Host -f DarkRed "Creating shortcut for $shortcutName ($(fname $target)) failed: Couldn't find icon $icon"
+ return
+ }
+
$scoop_startmenu_folder = shortcut_folder $global
- if(!(Test-Path $scoop_startmenu_folder)) {
- New-Item $scoop_startmenu_folder -type Directory
+ $subdirectory = [System.IO.Path]::GetDirectoryName($shortcutName)
+ if ($subdirectory) {
+ $subdirectory = ensure $([System.IO.Path]::Combine($scoop_startmenu_folder, $subdirectory))
}
+
$wsShell = New-Object -ComObject WScript.Shell
$wsShell = $wsShell.CreateShortcut("$scoop_startmenu_folder\$shortcutName.lnk")
- $wsShell.TargetPath = "$target"
+ $wsShell.TargetPath = $target.FullName
+ $wsShell.WorkingDirectory = $target.DirectoryName
+ if ($arguments) {
+ $wsShell.Arguments = $arguments
+ }
+ if ($icon -and $icon.Exists) {
+ $wsShell.IconLocation = $icon.FullName
+ }
$wsShell.Save()
- write-host "Creating shortcut for $shortcutName ($(fname $target))"
+ Write-Host "Creating shortcut for $shortcutName ($(fname $target))"
}
# Removes the Startmenu shortcut if it exists
function rm_startmenu_shortcuts($manifest, $global, $arch) {
$shortcuts = @(arch_specific 'shortcuts' $manifest $arch)
- $shortcuts | ?{ $_ -ne $null } | % {
+ $shortcuts | Where-Object { $_ -ne $null } | ForEach-Object {
$name = $_.item(1)
- $shortcut = "$(shortcut_folder $global)\$name.lnk"
- write-host "Removing shortcut $(friendly_path $shortcut)"
- if(Test-Path -Path $shortcut) {
- Remove-Item $shortcut
- }
- # 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
- }
+ $shortcut = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath("$(shortcut_folder $global)\$name.lnk")
+ Write-Host "Removing shortcut $(friendly_path $shortcut)"
+ if (Test-Path -Path $shortcut) {
+ Remove-Item $shortcut
}
}
}
diff --git a/lib/system.ps1 b/lib/system.ps1
new file mode 100644
index 0000000000..692cb40275
--- /dev/null
+++ b/lib/system.ps1
@@ -0,0 +1,176 @@
+# System-related functions
+
+## Environment Variables
+
+function Publish-EnvVar {
+ if (-not ('Win32.NativeMethods' -as [Type])) {
+ Add-Type -Namespace Win32 -Name NativeMethods -MemberDefinition @'
+[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+public static extern IntPtr SendMessageTimeout(
+ IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam,
+ uint fuFlags, uint uTimeout, out UIntPtr lpdwResult
+);
+'@
+ }
+
+ $HWND_BROADCAST = [IntPtr] 0xffff
+ $WM_SETTINGCHANGE = 0x1a
+ $result = [UIntPtr]::Zero
+
+ [Win32.NativeMethods]::SendMessageTimeout($HWND_BROADCAST,
+ $WM_SETTINGCHANGE,
+ [UIntPtr]::Zero,
+ 'Environment',
+ 2,
+ 5000,
+ [ref] $result
+ ) | Out-Null
+}
+
+function Get-EnvVar {
+ param(
+ [string]$Name,
+ [switch]$Global
+ )
+
+ $registerKey = if ($Global) {
+ Get-Item -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager'
+ } else {
+ Get-Item -Path 'HKCU:'
+ }
+ $envRegisterKey = $registerKey.OpenSubKey('Environment')
+ $registryValueOption = [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames
+ $envRegisterKey.GetValue($Name, $null, $registryValueOption)
+}
+
+function Set-EnvVar {
+ param(
+ [string]$Name,
+ [string]$Value,
+ [switch]$Global
+ )
+
+ $registerKey = if ($Global) {
+ Get-Item -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager'
+ } else {
+ Get-Item -Path 'HKCU:'
+ }
+ $envRegisterKey = $registerKey.OpenSubKey('Environment', $true)
+ if ($null -eq $Value -or $Value -eq '') {
+ if ($envRegisterKey.GetValue($Name)) {
+ $envRegisterKey.DeleteValue($Name)
+ }
+ } else {
+ $registryValueKind = if ($Value.Contains('%')) {
+ [Microsoft.Win32.RegistryValueKind]::ExpandString
+ } elseif ($envRegisterKey.GetValue($Name)) {
+ $envRegisterKey.GetValueKind($Name)
+ } else {
+ [Microsoft.Win32.RegistryValueKind]::String
+ }
+ $envRegisterKey.SetValue($Name, $Value, $registryValueKind)
+ }
+ Publish-EnvVar
+}
+
+function Split-PathLikeEnvVar {
+ param(
+ [string[]]$Pattern,
+ [string]$Path
+ )
+
+ if ($null -eq $Path -and $Path -eq '') {
+ return $null, $null
+ } else {
+ $splitPattern = $Pattern.Split(';', [System.StringSplitOptions]::RemoveEmptyEntries)
+ $splitPath = $Path.Split(';', [System.StringSplitOptions]::RemoveEmptyEntries)
+ $inPath = @()
+ foreach ($p in $splitPattern) {
+ $inPath += $splitPath.Where({ $_ -like $p })
+ $splitPath = $splitPath.Where({ $_ -notlike $p })
+ }
+ return ($inPath -join ';'), ($splitPath -join ';')
+ }
+}
+
+function Add-Path {
+ param(
+ [string[]]$Path,
+ [string]$TargetEnvVar = 'PATH',
+ [switch]$Global,
+ [switch]$Force,
+ [switch]$Quiet
+ )
+
+ # future sessions
+ $inPath, $strippedPath = Split-PathLikeEnvVar $Path (Get-EnvVar -Name $TargetEnvVar -Global:$Global)
+ if (!$inPath -or $Force) {
+ if (!$Quiet) {
+ $Path | ForEach-Object {
+ Write-Host "Adding $(friendly_path $_) to $(if ($Global) {'global'} else {'your'}) path."
+ }
+ }
+ Set-EnvVar -Name $TargetEnvVar -Value ((@($Path) + $strippedPath) -join ';') -Global:$Global
+ }
+ # current session
+ $inPath, $strippedPath = Split-PathLikeEnvVar $Path $env:PATH
+ if (!$inPath -or $Force) {
+ $env:PATH = (@($Path) + $strippedPath) -join ';'
+ }
+}
+
+function Remove-Path {
+ param(
+ [string[]]$Path,
+ [string]$TargetEnvVar = 'PATH',
+ [switch]$Global,
+ [switch]$Quiet,
+ [switch]$PassThru
+ )
+
+ # future sessions
+ $inPath, $strippedPath = Split-PathLikeEnvVar $Path (Get-EnvVar -Name $TargetEnvVar -Global:$Global)
+ if ($inPath) {
+ if (!$Quiet) {
+ $Path | ForEach-Object {
+ Write-Host "Removing $(friendly_path $_) from $(if ($Global) {'global'} else {'your'}) path."
+ }
+ }
+ Set-EnvVar -Name $TargetEnvVar -Value $strippedPath -Global:$Global
+ }
+ # current session
+ $inSessionPath, $strippedPath = Split-PathLikeEnvVar $Path $env:PATH
+ if ($inSessionPath) {
+ $env:PATH = $strippedPath
+ }
+ if ($PassThru) {
+ return $inPath
+ }
+}
+
+## Deprecated functions
+
+function env($name, $global, $val) {
+ if ($PSBoundParameters.ContainsKey('val')) {
+ Show-DeprecatedWarning $MyInvocation 'Set-EnvVar'
+ Set-EnvVar -Name $name -Value $val -Global:$global
+ } else {
+ Show-DeprecatedWarning $MyInvocation 'Get-EnvVar'
+ Get-EnvVar -Name $name -Global:$global
+ }
+}
+
+function strip_path($orig_path, $dir) {
+ Show-DeprecatedWarning $MyInvocation 'Split-PathLikeEnvVar'
+ Split-PathLikeEnvVar -Pattern @($dir) -Path $orig_path
+}
+
+function add_first_in_path($dir, $global) {
+ Show-DeprecatedWarning $MyInvocation 'Add-Path'
+ Add-Path -Path $dir -Global:$global -Force
+}
+
+function remove_from_path($dir, $global) {
+ Show-DeprecatedWarning $MyInvocation 'Remove-Path'
+ Remove-Path -Path $dir -Global:$global
+}
diff --git a/lib/unix.ps1 b/lib/unix.ps1
deleted file mode 100644
index e38cd840bb..0000000000
--- a/lib/unix.ps1
+++ /dev/null
@@ -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, (Join-Path $env:HOME "scoop") | select -first 1
-$globaldir = $env:SCOOP_GLOBAL, "/usr/local/scoop" | select -first 1
-$cachedir = $env:SCOOP_CACHE, (Join-Path $scoopdir "cache") | select -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 -first 1
-}
diff --git a/lib/versions.ps1 b/lib/versions.ps1
index 92ba6eff9f..6a55fb9cc0 100644
--- a/lib/versions.ps1
+++ b/lib/versions.ps1
@@ -1,53 +1,296 @@
-# versions
-function latest_version($app, $bucket, $url) {
- (manifest $app $bucket $url).version
-}
-function current_version($app, $global) {
- @(versions $app $global)[-1]
+function Get-LatestVersion {
+ <#
+ .SYNOPSIS
+ Get latest version of app from manifest
+ .PARAMETER AppName
+ App's name
+ .PARAMETER Bucket
+ Bucket which the app belongs to
+ .PARAMETER Uri
+ Remote app manifest's URI
+ #>
+ [OutputType([String])]
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
+ [Alias('App')]
+ [String]
+ $AppName,
+ [Parameter(Position = 1)]
+ [String]
+ $Bucket,
+ [Parameter(Position = 2)]
+ [String]
+ $Uri
+ )
+ process {
+ return (manifest $AppName $Bucket $Uri).version
+ }
}
-function versions($app, $global) {
- $appdir = appdir $app $global
- if(!(test-path $appdir)) { return @() }
- sort_versions (gci $appdir -dir -attr !reparsePoint | % { $_.name })
+function Select-CurrentVersion { # 'manifest.ps1'
+ <#
+ .SYNOPSIS
+ Select current version of installed app, from 'current\manifest.json' or modified time of version directory
+ .PARAMETER AppName
+ App's name
+ .PARAMETER Global
+ Globally installed application
+ #>
+ [OutputType([String])]
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
+ [Alias('App')]
+ [String]
+ $AppName,
+ [Parameter(Position = 1)]
+ [Switch]
+ $Global
+ )
+ process {
+ $currentPath = "$(appdir $AppName $Global)\current"
+ if (!(get_config NO_JUNCTION)) {
+ $currentVersion = (parse_json "$currentPath\manifest.json").version
+ if ($currentVersion -eq 'nightly') {
+ $currentVersion = (Get-Item $currentPath).Target | Split-Path -Leaf
+ }
+ }
+ if ($null -eq $currentVersion) {
+ $installedVersion = Get-InstalledVersion -AppName $AppName -Global:$Global
+ if ($installedVersion) {
+ $currentVersion = @($installedVersion)[-1]
+ } else {
+ $currentVersion = $null
+ }
+ }
+ return $currentVersion
+ }
}
-function version($ver) {
- $ver -split '[\.-]' | % {
- $num = $_ -as [int]
- if($num) { $num } else { $_ }
+function Get-InstalledVersion {
+ <#
+ .SYNOPSIS
+ Get all installed version of app, by checking version directories' 'install.json'
+ .PARAMETER AppName
+ App's name
+ .PARAMETER Global
+ Globally installed application
+ .NOTES
+ Versions are sorted from oldest to newest, i.e., latest installed version is the last one in the output array.
+ If no installed version found, empty array will be returned.
+ #>
+ [OutputType([Object[]])]
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
+ [Alias('App')]
+ [String]
+ $AppName,
+ [Parameter(Position = 1)]
+ [Switch]
+ $Global
+ )
+ process {
+ $appPath = appdir $AppName $Global
+ if (Test-Path $appPath) {
+ $versions = @((Get-ChildItem "$appPath\*\install.json" | Sort-Object -Property LastWriteTimeUtc).Directory.Name)
+ return $versions | Where-Object { ($_ -ne 'current') -and ($_ -notlike '_*.old*') }
+ } else {
+ return @()
+ }
}
+ # Deprecated
+ # sort_versions (Get-ChildItem $appPath -dir -attr !reparsePoint | Where-Object { $null -ne $(Get-ChildItem $_.FullName) } | ForEach-Object { $_.Name })
}
-function compare_versions($a, $b) {
- $ver_a = @(version $a)
- $ver_b = @(version $b)
- for($i=0;$i -lt $ver_a.length;$i++) {
- if($i -gt $ver_b.length) { return 1; }
+function Compare-Version {
+ <#
+ .SYNOPSIS
+ Compare versions, mainly according to SemVer's rules
+ .PARAMETER ReferenceVersion
+ Specifies a version used as a reference for comparison
+ .PARAMETER DifferenceVersion
+ Specifies the version that are compared to the reference version
+ .PARAMETER Delimiter
+ Specifies the delimiter of versions
+ .OUTPUTS
+ System.Int32
+ '0' if DifferenceVersion is equal to ReferenceVersion,
+ '1' if DifferenceVersion is greater then ReferenceVersion,
+ '-1' if DifferenceVersion is less then ReferenceVersion
+ #>
+ [OutputType([Int32])]
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory = $true, Position = 0)]
+ [AllowEmptyString()]
+ [String]
+ $ReferenceVersion,
+ [Parameter(Mandatory = $true, Position = 1, ValueFromPipeline = $true)]
+ [AllowEmptyString()]
+ [String]
+ $DifferenceVersion,
+ [String]
+ $Delimiter = '-'
+ )
+ process {
+ # Use '+' sign as post-release, see https://github.com/ScoopInstaller/Scoop/pull/3721#issuecomment-553718093
+ $ReferenceVersion, $DifferenceVersion = @($ReferenceVersion, $DifferenceVersion) -replace '\+', '-'
- # don't try to compare int to string
- if($ver_b[$i] -is [string] -and $ver_a[$i] -isnot [string]) {
- $ver_a[$i] = "$($ver_a[$i])"
+ # Return 0 if versions are equal
+ if ($DifferenceVersion -eq $ReferenceVersion) {
+ return 0
}
- if($ver_a[$i] -gt $ver_b[$i]) { return 1; }
- if($ver_a[$i] -lt $ver_b[$i]) { return -1; }
+ # Preprocess versions (split, convert and separate)
+ $splitReferenceVersion = @(SplitVersion -Version $ReferenceVersion -Delimiter $Delimiter)
+ $splitDifferenceVersion = @(SplitVersion -Version $DifferenceVersion -Delimiter $Delimiter)
+
+ # Nightly versions are always equal unless UPDATE_NIGHTLY is $true
+ if ($splitReferenceVersion[0] -eq 'nightly' -and $splitDifferenceVersion[0] -eq 'nightly') {
+ 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++) {
+ # '1.1-alpha' is less then '1.1'
+ if ($i -ge $splitReferenceVersion.Length) {
+ if ($splitDifferenceVersion[$i] -match 'alpha|beta|rc|pre') {
+ return -1
+ } else {
+ return 1
+ }
+ }
+ # '1.1' is greater then '1.1-beta'
+ if ($i -ge $splitDifferenceVersion.Length) {
+ if ($splitReferenceVersion[$i] -match 'alpha|beta|rc|pre') {
+ return 1
+ } else {
+ return -1
+ }
+ }
+
+ # If some parts of versions have '.', compare them with delimiter '.'
+ if (($splitReferenceVersion[$i] -match '\.') -or ($splitDifferenceVersion[$i] -match '\.')) {
+ $Result = Compare-Version -ReferenceVersion $splitReferenceVersion[$i] -DifferenceVersion $splitDifferenceVersion[$i] -Delimiter '.'
+ # If the parts are equal, continue to next part, otherwise return
+ if ($Result -ne 0) {
+ return $Result
+ } else {
+ continue
+ }
+ }
+
+ # If some parts of versions have '_', compare them with delimiter '_'
+ if (($splitReferenceVersion[$i] -match '_') -or ($splitDifferenceVersion[$i] -match '_')) {
+ $Result = Compare-Version -ReferenceVersion $splitReferenceVersion[$i] -DifferenceVersion $splitDifferenceVersion[$i] -Delimiter '_'
+ # If the parts are equal, continue to next part, otherwise return
+ if ($Result -ne 0) {
+ return $Result
+ } else {
+ continue
+ }
+ }
+
+ # Don't try to compare [Long] to [String]
+ if ($null -ne $splitReferenceVersion[$i] -and $null -ne $splitDifferenceVersion[$i]) {
+ if ($splitReferenceVersion[$i] -is [String] -and $splitDifferenceVersion[$i] -isnot [String]) {
+ $splitDifferenceVersion[$i] = "$($splitDifferenceVersion[$i])"
+ }
+ if ($splitDifferenceVersion[$i] -is [String] -and $splitReferenceVersion[$i] -isnot [String]) {
+ $splitReferenceVersion[$i] = "$($splitReferenceVersion[$i])"
+ }
+ }
+
+ # Compare [String] or [Long]
+ if ($splitDifferenceVersion[$i] -gt $splitReferenceVersion[$i]) {
+ return 1
+ }
+ if ($splitDifferenceVersion[$i] -lt $splitReferenceVersion[$i]) {
+ return -1
+ }
+ }
}
- if($ver_b.length -gt $ver_a.length) { return -1 }
- return 0
}
+# Helper function
+function SplitVersion {
+ <#
+ .SYNOPSIS
+ Split version by Delimiter, convert number string to number, and separate letters from numbers
+ .PARAMETER Version
+ Specifies a version
+ .PARAMETER Delimiter
+ Specifies the delimiter of version (Literal)
+ #>
+ [OutputType([Object[]])]
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
+ [AllowEmptyString()]
+ [String]
+ $Version,
+ [String]
+ $Delimiter = '-'
+ )
+ process {
+ $Version = $Version -replace '[a-zA-Z]+', "$Delimiter$&$Delimiter"
+ return ($Version -split [Regex]::Escape($Delimiter) -ne '' | ForEach-Object { if ($_ -match '^\d+$') { [Long]$_ } else { $_ } })
+ }
+}
+
+# Deprecated
+# Not used anymore in scoop core
function qsort($ary, $fn) {
- if($ary -eq $null) { return @() }
- if(!($ary -is [array])) { return @($ary) }
+ warn '"qsort" is deprecated. Please avoid using it anymore.'
+ if ($null -eq $ary) { return @() }
+ if (!($ary -is [array])) { return @($ary) }
$pivot = $ary[0]
- $rem = $ary[1..($ary.length-1)]
+ $rem = $ary[1..($ary.length - 1)]
- $lesser = qsort ($rem | where { (& $fn $_ $pivot) -lt 0 }) $fn
+ $lesser = qsort ($rem | Where-Object { (& $fn $pivot $_) -lt 0 }) $fn
- $greater = qsort ($rem | where { (& $fn $_ $pivot) -ge 0 }) $fn
+ $greater = qsort ($rem | Where-Object { (& $fn $pivot $_) -ge 0 }) $fn
return @() + $lesser + @($pivot) + $greater
}
-function sort_versions($versions) { qsort $versions compare_versions }
+
+# Deprecated
+# Not used anymore in scoop core
+function sort_versions($versions) {
+ warn '"sort_versions" is deprecated. Please avoid using it anymore.'
+ qsort $versions Compare-Version
+}
+
+function compare_versions($a, $b) {
+ Show-DeprecatedWarning $MyInvocation 'Compare-Version'
+ # Please note the parameters' sequence
+ return Compare-Version -ReferenceVersion $b -DifferenceVersion $a
+}
+
+function latest_version($app, $bucket, $url) {
+ Show-DeprecatedWarning $MyInvocation 'Get-LatestVersion'
+ return Get-LatestVersion -AppName $app -Bucket $bucket -Uri $url
+}
+
+function current_version($app, $global) {
+ Show-DeprecatedWarning $MyInvocation 'Select-CurrentVersion'
+ return Select-CurrentVersion -AppName $app -Global:$global
+}
+
+function versions($app, $global) {
+ Show-DeprecatedWarning $MyInvocation 'Get-InstalledVersion'
+ return Get-InstalledVersion -AppName $app -Global:$global
+}
diff --git a/libexec/scoop-alias.ps1 b/libexec/scoop-alias.ps1
index 0b4cea1d0d..677b9337f7 100644
--- a/libexec/scoop-alias.ps1
+++ b/libexec/scoop-alias.ps1
@@ -1,97 +1,68 @@
-# Usage: scoop alias add|list|rm []
+# Usage: scoop alias [options] []
# Summary: Manage scoop aliases
-# Help: Add, remove or list Scoop aliases
+# Help: Available subcommands: add, rm, list.
#
-# Aliases are custom Scoop subcommands that can be created to make common tasks
-# easier.
+# Aliases are custom Scoop subcommands that can be created to make common tasks easier.
#
-# To add an Alias:
-# scoop alias add
+# To add an alias:
#
-# e.g.:
-# scoop alias add rm 'scoop uninstall $args[0]' "Uninstalls an app"
-
-param($opt, $name, $command, $description)
-
-. "$psscriptroot\..\lib\core.ps1"
-. "$psscriptroot\..\lib\help.ps1"
-. "$psscriptroot\..\lib\config.ps1"
-. "$psscriptroot\..\lib\install.ps1"
-
-$script:config_alias = "alias"
-
-function init_alias_config {
- $aliases = get_config $script:config_alias
- if(!$aliases) {
- $aliases = @{}
- }
-
- $aliases
-}
-
-function add_alias($name, $command) {
- if(!$command) {
- abort "Can't create an empty alias."
- }
-
- # get current aliases from config
- $aliases = init_alias_config
- if($aliases.containskey($name)) {
- abort "Alias $name already exists."
- }
-
- $alias_file = "scoop-$name"
-
- # generate script
- $shimdir = shimdir $false
- $script =
-@"
-# Summary: $description
-$command
-"@
- $script | out-file "$shimdir\$alias_file.ps1" -encoding utf8
-
- # add alias to config
- $aliases += @{ $name = $alias_file }
- set_config $script:config_alias $aliases
-}
-
-function rm_alias($name) {
- $aliases = init_alias_config
- if(!$name) {
- abort "Which alias should be removed?"
- }
-
- if($aliases.containskey($name)) {
- "Removing alias $name..."
-
- rm_shim $aliases.get_item($name) (shimdir $false)
-
- $aliases.remove($name)
- set_config $script:config_alias $aliases
- }
- else { abort "Alias $name doesn't exist." }
+# scoop alias add []
+#
+# e.g.,
+#
+# scoop alias add rm 'scoop uninstall $args[0]' 'Uninstall an app'
+# scoop alias add upgrade 'scoop update *' 'Update all apps, just like "brew" or "apt"'
+#
+# To remove an alias:
+#
+# scoop alias rm
+#
+# To list all aliases:
+#
+# scoop alias list [-v|--verbose]
+#
+# Options:
+# -v, --verbose Show alias description and table headers (works only for "list")
+
+param($SubCommand)
+
+. "$PSScriptRoot\..\lib\getopt.ps1"
+
+$SubCommands = @('add', 'rm', 'list')
+if ($SubCommand -notin $SubCommands) {
+ if (!$SubCommand) {
+ error ' missing'
+ } else {
+ error "'$SubCommand' is not one of available subcommands: $($SubCommands -join ', ')"
+ }
+ my_usage
+ exit 1
}
-function list_aliases {
- $aliases = @{}
-
- (init_alias_config).getenumerator() |% {
- $summary = summary (gc (command_path $_.name) -raw)
- if(!($summary)) { $summary = '' }
- $aliases.add("$($_.name) ", $summary)
- }
-
- if(!$aliases.count) {
- warn "No aliases founds."
- }
-
- $aliases.getenumerator() | sort name | ft -hidetablehead -autosize -wrap
+$opt, $other, $err = getopt $Args 'v' 'verbose'
+if ($err) { "scoop alias: $err"; exit 1 }
+
+$name, $command, $description = $other
+$verbose = $opt.v -or $opt.verbose
+
+switch ($SubCommand) {
+ 'add' {
+ if (!$name -or !$command) {
+ error " and must be specified for subcommand 'add'"
+ exit 1
+ }
+ add_alias $name $command $description
+ }
+ 'rm' {
+ if (!$name) {
+ error " must be specified for subcommand 'rm'"
+ exit 1
+ }
+ rm_alias $name
+ }
+ 'list' {
+ list_aliases $verbose
+ }
}
-switch($opt) {
- "add" { add_alias $name $command }
- "rm" { rm_alias $name }
- "list" { list_aliases }
- default { my_usage; exit 1 }
-}
+exit 0
diff --git a/libexec/scoop-bucket.ps1 b/libexec/scoop-bucket.ps1
index 51ca6a5db4..d3b7728559 100644
--- a/libexec/scoop-bucket.ps1
+++ b/libexec/scoop-bucket.ps1
@@ -10,7 +10,7 @@
# scoop bucket add []
#
# e.g.:
-# scoop bucket add extras https://github.com/lukesampson/scoop-extras.git
+# scoop bucket add extras https://github.com/ScoopInstaller/Extras.git
#
# Since the 'extras' bucket is known to Scoop, this can be shortened to:
# scoop bucket add extras
@@ -19,68 +19,62 @@
# scoop bucket known
param($cmd, $name, $repo)
-. "$psscriptroot\..\lib\core.ps1"
-. "$psscriptroot\..\lib\buckets.ps1"
-. "$psscriptroot\..\lib\help.ps1"
-. "$psscriptroot\..\lib\git.ps1"
+if (get_config NO_JUNCTION) {
+ . "$PSScriptRoot\..\lib\versions.ps1"
+}
-reset_aliases
+if (get_config USE_SQLITE_CACHE) {
+ . "$PSScriptRoot\..\lib\manifest.ps1"
+ . "$PSScriptRoot\..\lib\database.ps1"
+}
-$usage_add = "usage: scoop bucket add []"
-$usage_rm = "usage: scoop bucket rm "
+$usage_add = 'usage: scoop bucket add []'
+$usage_rm = 'usage: scoop bucket rm '
-function add_bucket($name, $repo) {
- if(!$name) { " missing"; $usage_add; exit 1 }
- if(!$repo) {
- $repo = known_bucket_repo $name
- if(!$repo) { "Unknown bucket '$name'. Try specifying ."; $usage_add; exit 1 }
+switch ($cmd) {
+ 'add' {
+ if (!$name) {
+ ' missing'
+ $usage_add
+ exit 1
+ }
+ if (!$repo) {
+ $repo = known_bucket_repo $name
+ if (!$repo) {
+ "Unknown bucket '$name'. Try specifying ."
+ $usage_add
+ exit 1
+ }
+ }
+ $status = add_bucket $name $repo
+ exit $status
}
-
- $git = try { gcm 'git' -ea stop } catch { $null }
- if(!$git) {
- abort "Git is required for buckets. Run 'scoop install git'."
+ 'rm' {
+ if (!$name) {
+ ' missing'
+ $usage_rm
+ exit 1
+ }
+ $status = rm_bucket $name
+ exit $status
}
-
- $dir = bucketdir $name
- if(test-path $dir) {
- abort "The '$name' bucket already exists. Use 'scoop bucket rm $name' to remove it."
+ 'list' {
+ $buckets = list_buckets
+ if (!$buckets.Length) {
+ warn "No bucket found. Please run 'scoop bucket add main' to add the default 'main' bucket."
+ exit 2
+ } else {
+ $buckets
+ exit 0
+ }
}
-
- write-host 'Checking repo... ' -nonewline
- $out = git_ls_remote $repo 2>&1
- if($lastexitcode -ne 0) {
- abort "'$repo' doesn't look like a valid git repository`n`nError given:`n$out"
+ 'known' {
+ known_buckets
+ exit 0
}
- write-host 'ok'
-
- ensure $bucketsdir > $null
- $dir = ensure $dir
- git_clone "$repo" "`"$dir`""
- success "The $name bucket was added successfully."
-}
-
-function rm_bucket($name) {
- if(!$name) { " missing"; $usage_rm; exit 1 }
- $dir = bucketdir $name
- if(!(test-path $dir)) {
- abort "'$name' bucket not found."
+ default {
+ "scoop bucket: cmd '$cmd' not supported"
+ my_usage
+ exit 1
}
-
- rm $dir -r -force -ea stop
-}
-
-function list_buckets {
- buckets
-}
-
-function known_buckets {
- known_bucket_repos |% { $_.psobject.properties | select -expand 'name' }
-}
-
-switch($cmd) {
- "add" { add_bucket $name $repo }
- "rm" { rm_bucket $name }
- "list" { list_buckets }
- "known" { known_buckets }
- default { "scoop bucket: cmd '$cmd' not supported"; my_usage; exit 1 }
}
diff --git a/libexec/scoop-cache.ps1 b/libexec/scoop-cache.ps1
index 2eff0d3c76..30e8354fca 100644
--- a/libexec/scoop-cache.ps1
+++ b/libexec/scoop-cache.ps1
@@ -1,4 +1,4 @@
-# Usage: scoop cache show|rm [app]
+# Usage: scoop cache show|rm [app(s)]
# Summary: Show or clear the download cache
# Help: Scoop caches downloads so you don't need to download the same files
# when you uninstall and re-install the same version of an app.
@@ -10,38 +10,63 @@
#
# To clear everything in your cache, use:
# scoop cache rm *
-param($cmd, $app)
+# You can also use the `-a/--all` switch in place of `*` here
-. "$psscriptroot\..\lib\help.ps1"
-
-reset_aliases
+param($cmd)
function cacheinfo($file) {
- $app, $version, $url = $file.name -split '#'
- $size = filesize $file.length
- return new-object psobject -prop @{ app=$app; version=$version; url=$url; size=$size }
+ $app, $version, $url = $file.Name -split '#'
+ New-Object PSObject -Property @{ Name = $app; Version = $version; Length = $file.Length }
}
-switch($cmd) {
- 'rm' {
- if(!$app) { 'ERROR: missing'; my_usage; exit 1 }
- rm "$scoopdir\cache\$app#*"
+function cacheshow($app) {
+ if (!$app -or $app -eq '*') {
+ $app = '.*?'
+ } else {
+ $app = '(' + ($app -join '|') + ')'
}
- 'show' {
- $files = @(gci "$scoopdir\cache" | ? { $_.name -match "^$app" })
- $total_length = ($files | measure length -sum).sum -as [double]
+ $files = @(Get-ChildItem $cachedir | Where-Object -Property Name -Value "^$app#" -Match)
+ $totalLength = ($files | Measure-Object -Property Length -Sum).Sum
+
+ $files | ForEach-Object { cacheinfo $_ } | Select-Object Name, Version, Length
+
+ Write-Host "Total: $($files.Length) $(pluralize $files.Length 'file' 'files'), $(filesize $totalLength)" -ForegroundColor Yellow
+}
- $f_app = @{ expression={"$($_.app) ($($_.version))" }}
- $f_url = @{ expression={$_.url};alignment='right'}
- $f_size = @{ expression={$_.size}; alignment='right'}
+function cacheremove($app) {
+ if (!$app) {
+ 'ERROR: missing'
+ my_usage
+ exit 1
+ } elseif ($app -eq '*' -or $app -eq '-a' -or $app -eq '--all') {
+ $files = @(Get-ChildItem $cachedir)
+ } else {
+ $app = '(' + ($app -join '|') + ')'
+ $files = @(Get-ChildItem $cachedir | Where-Object -Property Name -Value "^$app#" -Match)
+ }
+ $totalLength = ($files | Measure-Object -Property Length -Sum).Sum
+ $files | ForEach-Object {
+ $curr = cacheinfo $_
+ Write-Host "Removing $($_.Name)..."
+ Remove-Item $_.FullName
+ if(Test-Path "$cachedir\$($curr.Name).txt") {
+ Remove-Item "$cachedir\$($curr.Name).txt"
+ }
+ }
- $files | % { cacheinfo $_ } | ft $f_size, $f_app, $f_url -auto -hide
+ Write-Host "Deleted: $($files.Length) $(pluralize $files.Length 'file' 'files'), $(filesize $totalLength)" -ForegroundColor Yellow
+}
- "Total: $($files.length) $(pluralize $files.length 'file' 'files'), $(filesize $total_length)"
+switch($cmd) {
+ 'rm' {
+ cacheremove $Args
+ }
+ 'show' {
+ cacheshow $Args
}
default {
- "cache '$cmd' not supported"; my_usage; exit 1
+ cacheshow (@($cmd) + $Args)
}
}
diff --git a/libexec/scoop-cat.ps1 b/libexec/scoop-cat.ps1
new file mode 100644
index 0000000000..fc85fced92
--- /dev/null
+++ b/libexec/scoop-cat.ps1
@@ -0,0 +1,29 @@
+# Usage: scoop cat
+# 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)
+
+. "$PSScriptRoot\..\lib\json.ps1" # 'ConvertToPrettyJson'
+. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
+. "$PSScriptRoot\..\lib\manifest.ps1" # 'Get-Manifest'
+. "$PSScriptRoot\..\lib\download.ps1" # 'Get-UserAgent'
+
+if (!$app) { error ' missing'; my_usage; exit 1 }
+
+$null, $manifest, $bucket, $url = Get-Manifest $app
+
+if ($manifest) {
+ $style = get_config CAT_STYLE
+ if ($style) {
+ $manifest | ConvertToPrettyJson | bat --no-paging --style $style --language json
+ } else {
+ $manifest | ConvertToPrettyJson
+ }
+} else {
+ abort "Couldn't find manifest for '$app'$(if($bucket) { " from '$bucket' bucket" } elseif($url) { " at '$url'" })."
+}
+
+exit $exitCode
diff --git a/libexec/scoop-checkup.ps1 b/libexec/scoop-checkup.ps1
index efadcf02d5..32b0ef4a5a 100644
--- a/libexec/scoop-checkup.ps1
+++ b/libexec/scoop-checkup.ps1
@@ -3,17 +3,56 @@
# Help: Performs a series of diagnostic tests to try to identify things that may
# cause problems with Scoop.
-. "$psscriptroot\..\lib\core.ps1"
-. "$psscriptroot\..\lib\diagnostic.ps1"
+. "$PSScriptRoot\..\lib\diagnostic.ps1"
$issues = 0
+$defenderIssues = 0
-$issues += !(check_windows_defender $false)
-$issues += !(check_windows_defender $true)
+$adminPrivileges = ([System.Security.Principal.WindowsPrincipal] [System.Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
-if($issues) {
- warn "`nFound $issues potential $(pluralize $issues problem problems)."
+if ($adminPrivileges -and $env:USERNAME -ne 'WDAGUtilityAccount') {
+ $defenderIssues += !(check_windows_defender $false)
+ $defenderIssues += !(check_windows_defender $true)
+}
+
+$issues += !(check_main_bucket)
+$issues += !(check_long_paths)
+$issues += !(Get-WindowsDeveloperModeStatus)
+
+if (!(Test-HelperInstalled -Helper 7zip) -and !(get_config USE_EXTERNAL_7ZIP)) {
+ warn "'7-Zip' is not installed! It's required for unpacking most programs. Please Run 'scoop install 7zip'."
+ $issues++
+}
+
+if (!(Test-HelperInstalled -Helper Innounp)) {
+ warn "'Inno Setup Unpacker' is not installed! It's required for unpacking InnoSetup files. Please run 'scoop install innounp'."
+ $issues++
+}
+
+if (!(Test-HelperInstalled -Helper Dark)) {
+ warn "'dark' is not installed! It's required for unpacking installers created with the WiX Toolset. Please run 'scoop install dark' or 'scoop install wixtoolset'."
+ $issues++
+}
+
+$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 '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 'root_path' variable in '~/.config/scoop/config.json' to another Drive."
+ $issues++
+}
+
+if ($issues) {
+ warn "Found $issues potential $(pluralize $issues problem problems)."
+} elseif ($defenderIssues) {
+ info "Found $defenderIssues performance $(pluralize $defenderIssues problem problems)."
+ warn "Security is more important than performance, in most cases."
} else {
success "No problems identified!"
}
+exit 0
diff --git a/libexec/scoop-cleanup.ps1 b/libexec/scoop-cleanup.ps1
new file mode 100644
index 0000000000..6ce40a211f
--- /dev/null
+++ b/libexec/scoop-cleanup.ps1
@@ -0,0 +1,88 @@
+# Usage: scoop cleanup [options]
+# Summary: Cleanup apps by removing old versions
+# Help: 'scoop cleanup' cleans Scoop apps by removing old versions.
+# 'scoop cleanup ' cleans up the old versions of that app if said versions exist.
+#
+# You can use '*' in place of or `-a`/`--all` switch to cleanup all apps.
+#
+# Options:
+# -a, --all Cleanup all apps (alternative to '*')
+# -g, --global Cleanup a globally installed app
+# -k, --cache Remove outdated download cache
+
+. "$PSScriptRoot\..\lib\getopt.ps1"
+. "$PSScriptRoot\..\lib\manifest.ps1" # 'Select-CurrentVersion' (indirectly)
+. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
+. "$PSScriptRoot\..\lib\install.ps1" # persist related
+
+$opt, $apps, $err = getopt $args 'agk' 'all', 'global', 'cache'
+if ($err) { "scoop cleanup: $err"; exit 1 }
+$global = $opt.g -or $opt.global
+$cache = $opt.k -or $opt.cache
+$all = $opt.a -or $opt.all
+
+if (!$apps -and !$all) { 'ERROR: missing'; my_usage; exit 1 }
+
+if ($global -and !(is_admin)) {
+ 'ERROR: you need admin rights to cleanup global apps'; exit 1
+}
+
+function cleanup($app, $global, $verbose, $cache) {
+ $current_version = Select-CurrentVersion -AppName $app -Global:$global
+ if ($cache) {
+ Remove-Item "$cachedir\$app#*" -Exclude "$app#$current_version#*"
+ }
+ $appDir = appdir $app $global
+ $versions = Get-ChildItem $appDir -Name
+ $versions = $versions | Where-Object { $current_version -ne $_ -and $_ -ne 'current' }
+ if (!$versions) {
+ if ($verbose) { success "$app is already clean" }
+ return
+ }
+
+ Write-Host -f yellow "Removing $app`:" -NoNewline
+ $versions | ForEach-Object {
+ $version = $_
+ Write-Host " $version" -NoNewline
+ $dir = versiondir $app $version $global
+ # unlink all potential old link before doing recursive Remove-Item
+ unlink_persist_data (installed_manifest $app $version $global) $dir
+ Remove-Item $dir -ErrorAction Stop -Recurse -Force
+ }
+ $leftVersions = Get-ChildItem $appDir
+ if ($leftVersions.Length -eq 1 -and $leftVersions.Name -eq 'current' -and $leftVersions.LinkType) {
+ attrib $leftVersions.FullName -R /L
+ Remove-Item $leftVersions.FullName -ErrorAction Stop -Force
+ $leftVersions = $null
+ }
+ if (!$leftVersions) {
+ Remove-Item $appDir -ErrorAction Stop -Force
+ }
+ Write-Host ''
+}
+
+if ($apps -or $all) {
+ if ($apps -eq '*' -or $all) {
+ $verbose = $false
+ $apps = applist (installed_apps $false) $false
+ if ($global) {
+ $apps += applist (installed_apps $true) $true
+ }
+ } else {
+ $verbose = $true
+ $apps = Confirm-InstallationStatus $apps -Global:$global
+ }
+
+ # $apps is now a list of ($app, $global) tuples
+ $apps | ForEach-Object { cleanup @_ $verbose $cache }
+
+ if ($cache) {
+ Remove-Item "$cachedir\*.download" -ErrorAction Ignore
+ }
+
+ if (!$verbose) {
+ success 'Everything is shiny now!'
+ }
+}
+
+exit 0
diff --git a/libexec/scoop-config.ps1 b/libexec/scoop-config.ps1
index 3cae6646a3..6007bd6434 100644
--- a/libexec/scoop-config.ps1
+++ b/libexec/scoop-config.ps1
@@ -1,6 +1,10 @@
# Usage: scoop config [rm] name [value]
# Summary: Get or set configuration values
-# Help: The scoop configuration file is saved at ~/.scoop.
+# Help: The scoop configuration file is saved at ~/.config/scoop/config.json.
+#
+# To get all configuration settings:
+#
+# scoop config
#
# To get a configuration setting:
#
@@ -17,28 +21,160 @@
# Settings
# --------
#
+# use_external_7zip: $true|$false
+# External 7zip (from path) will be used for archives extraction.
+#
+# use_lessmsi: $true|$false
+# Prefer lessmsi utility over native msiexec.
+#
+# use_sqlite_cache: $true|$false
+# Use SQLite database for caching. This is useful for speeding up 'scoop search' and 'scoop shim' commands.
+#
+# 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
+# Git repository containining scoop source code.
+# This configuration is useful for custom forks.
+#
+# 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')
+#
# proxy: [username:password@]host:port
+# By default, Scoop will use the proxy settings from Internet Options, but with anonymous authentication.
+#
+# * To use the credentials for the current logged-in user, use 'currentuser' in place of username:password
+# * To use the system proxy settings configured in Internet Options, use 'default' in place of host:port
+# * 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)
+#
+# 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 by system.
+#
+# debug: $true|$false
+# Additional and detailed output will be shown.
+#
+# force_update: $true|$false
+# Force apps updating to bucket's version.
+#
+# show_update_log: $true|$false
+# Do not show changed commits on 'scoop update'
+#
+# 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.
+#
+# root_path: $Env:UserProfile\scoop
+# Path to Scoop root directory.
+#
+# global_path: $Env:ProgramData\scoop
+# Path to Scoop root directory for global apps.
+#
+# cache_path:
+# For downloads, defaults to 'cache' folder under Scoop root directory.
#
-# By default, Scoop will use the proxy settings from Internet Options, but with anonymous authentication.
+# gh_token:
+# GitHub API token used to make authenticated requests.
+# This is essential for checkver and similar functions to run without
+# incurring rate limits and download from private repositories.
#
-# * To use the credentials for the current logged-in user, use 'currentuser' in place of username:password
-# * To use the system proxy settings configured in Internet Options, use 'default' in place of host:port
-# * 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)
+# virustotal_api_key:
+# API key used for uploading/scanning files using virustotal.
+# See: 'https://support.virustotal.com/hc/en-us/articles/115002088769-Please-give-me-an-API-key'
+#
+# cat_style:
+# When set to a non-empty string, Scoop will use 'bat' to display the manifest for
+# the `scoop cat` command and while doing manifest review. This requires 'bat' to be
+# installed (run `scoop install bat` to install it), otherwise errors will be thrown.
+# The accepted values are the same as ones passed to the --style flag of 'bat'.
+#
+# ignore_running_processes: $true|$false
+# When set to $false (default), Scoop would stop its procedure immediately if it detects
+# any target app process is running. Procedure here refers to reset/uninstall/update.
+# When set to $true, Scoop only displays a warning message and continues procedure.
+#
+# private_hosts:
+# Array of private hosts that need additional authentication.
+# 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.
+#
+# use_isolated_path: $true|$false|[string]
+# When set to $true, Scoop will use `SCOOP_PATH` environment variable to store apps' `PATH`s.
+# When set to arbitrary non-empty string, Scoop will use that string as the environment variable name instead.
+# This is useful when you want to isolate Scoop from the system `PATH`.
+#
+# ARIA2 configuration
+# -------------------
+#
+# aria2-enabled: $true|$false
+# Aria2c will be used for downloading of artifacts.
+#
+# aria2-warning-enabled: $true|$false
+# Disable Aria2c warning which is shown while downloading.
+#
+# aria2-retry-wait: 2
+# Number of seconds to wait between retries.
+# See: 'https://aria2.github.io/manual/en/html/aria2c.html#cmdoption-retry-wait'
+#
+# aria2-split: 5
+# Number of connections used for downlaod.
+# See: 'https://aria2.github.io/manual/en/html/aria2c.html#cmdoption-s'
+#
+# aria2-max-connection-per-server: 5
+# The maximum number of connections to one server for each download.
+# See: 'https://aria2.github.io/manual/en/html/aria2c.html#cmdoption-x'
+#
+# aria2-min-split-size: 5M
+# Downloaded files will be splitted by this configured size and downloaded using multiple connections.
+# See: 'https://aria2.github.io/manual/en/html/aria2c.html#cmdoption-k'
+#
+# aria2-options:
+# Array of additional aria2 options.
+# See: 'https://aria2.github.io/manual/en/html/aria2c.html#options'
param($name, $value)
-. "$psscriptroot\..\lib\config.ps1"
-. "$psscriptroot\..\lib\help.ps1"
-
-reset_aliases
-
-if(!$name) { my_usage; exit 1 }
-
-if($name -like 'rm') {
- set_config $value $null
-} elseif($value) {
- set_config $name $value
+if (!$name) {
+ $scoopConfig
+} elseif ($name -like '--help') {
+ my_usage
+} elseif ($name -like 'rm') {
+ set_config $value $null | Out-Null
+ Write-Host "'$value' has been removed"
+} elseif ($null -ne $value) {
+ set_config $name $value | Out-Null
+ Write-Host "'$name' has been set to '$value'"
} else {
- get_config $name $value
+ $value = get_config $name
+ if($null -eq $value) {
+ Write-Host "'$name' is not set"
+ } else {
+ if ($value -is [System.DateTime]) {
+ $value.ToString('o')
+ } else {
+ $value
+ }
+ }
}
+
+exit 0
diff --git a/libexec/scoop-create.ps1 b/libexec/scoop-create.ps1
index 5f06e35e2a..6c40e96c5e 100644
--- a/libexec/scoop-create.ps1
+++ b/libexec/scoop-create.ps1
@@ -11,29 +11,28 @@ function create_manifest($url) {
$url_parts = $null
try {
$url_parts = parse_url $url
- }
- catch {
+ } catch {
abort "Error: $url is not a valid URL"
}
- $name = choose_item $url_parts "App name"
+ $name = choose_item $url_parts 'App name'
$name = if ($name.Length -gt 0) {
$name
- }
- else {
- file_name ($url_parts | select-object -last 1)
+ } else {
+ file_name ($url_parts | Select-Object -Last 1)
}
- $manifest.version = choose_item $url_parts "Version"
+ $manifest.version = choose_item $url_parts 'Version'
- $manifest | convertto-json | out-file -filepath "$name.json" -encoding utf8
- $manifest_path = join-path $pwd "$name.json"
- write-host "Created '$manifest_path'."
+ $manifest | ConvertTo-Json | Out-File -FilePath "$name.json" -Encoding ASCII
+ $manifest_path = Join-Path $pwd "$name.json"
+ Write-Host "Created '$manifest_path'."
}
function new_manifest() {
- @{ "homepage" = ""; "license" = ""; "version" = ""; "url" = "";
- "hash" = ""; "extract_dir" = ""; "bin" = ""; "depends" = "" }
+ @{ 'homepage' = ''; 'license' = ''; 'version' = ''; 'url' = '';
+ 'hash' = ''; 'extract_dir' = ''; 'bin' = ''; 'depends' = ''
+ }
}
function file_name($segment) {
@@ -41,27 +40,28 @@ function file_name($segment) {
}
function parse_url($url) {
- $uri = new-object Uri $url
- $uri.pathandquery.substring(1).split("/")
+ $uri = New-Object Uri $url
+ $uri.pathandquery.substring(1).split('/')
}
function choose_item($list, $query) {
for ($i = 0; $i -lt $list.count; $i++) {
$item = $list[$i]
- write-host "$($i + 1)) $item"
+ Write-Host "$($i + 1)) $item"
}
- $sel = read-host $query
+ $sel = Read-Host $query
if ($sel.trim() -match '^[0-9+]$') {
- return $list[$sel-1]
+ return $list[$sel - 1]
}
$sel
}
if (!$url) {
- scoop help create
-}
-else {
+ & "$PSScriptRoot\scoop-help.ps1" create
+} else {
create_manifest $url
}
+
+exit 0
diff --git a/libexec/scoop-depends.ps1 b/libexec/scoop-depends.ps1
index 3b1f3b9149..25ed614ca3 100644
--- a/libexec/scoop-depends.ps1
+++ b/libexec/scoop-depends.ps1
@@ -1,25 +1,37 @@
# Usage: scoop depends
-# Summary: List dependencies for an app
+# Summary: List dependencies for an app, in the order they'll be installed
-. "$psscriptroot\..\lib\depends.ps1"
-. "$psscriptroot\..\lib\install.ps1"
-. "$psscriptroot\..\lib\manifest.ps1"
-. "$psscriptroot\..\lib\buckets.ps1"
-. "$psscriptroot\..\lib\getopt.ps1"
-. "$psscriptroot\..\lib\decompress.ps1"
-. "$psscriptroot\..\lib\config.ps1"
-. "$psscriptroot\..\lib\help.ps1"
-
-reset_aliases
+. "$PSScriptRoot\..\lib\getopt.ps1"
+. "$PSScriptRoot\..\lib\depends.ps1" # 'Get-Dependency'
+. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
+. "$PSScriptRoot\..\lib\manifest.ps1" # 'Get-Manifest' (indirectly)
+. "$PSScriptRoot\..\lib\download.ps1" # 'Get-UserAgent'
$opt, $apps, $err = getopt $args 'a:' 'arch='
$app = $apps[0]
-if(!$app) { " missing"; my_usage; exit 1 }
+if(!$app) { error ' missing'; my_usage; exit 1 }
+
+$architecture = Get-DefaultArchitecture
+try {
+ $architecture = Format-ArchitectureString ($opt.a + $opt.arch)
+} catch {
+ abort "ERROR: $_"
+}
-$architecture = ensure_architecture ($opt.a + $opt.arch)
+$deps = @()
+Get-Dependency $app $architecture | ForEach-Object {
+ $dep = [ordered]@{}
-$deps = @(deps $app $architecture)
-if($deps) {
- $deps[($deps.length - 1)..0]
+ $app, $null, $bucket, $url = Get-Manifest $_
+ if (!$url) {
+ $bucket, $app = $_ -split '/'
+ }
+ $dep.Source = if ($url) { $url } else { $bucket }
+ $dep.Name = $app
+
+ $deps += [PSCustomObject]$dep
}
+$deps
+
+exit 0
diff --git a/libexec/scoop-download.ps1 b/libexec/scoop-download.ps1
new file mode 100644
index 0000000000..996cb4e8e6
--- /dev/null
+++ b/libexec/scoop-download.ps1
@@ -0,0 +1,143 @@
+# Usage: scoop download [options]
+# Summary: Download apps in the cache folder and verify hashes
+# 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
+#
+# To download an app from a manifest on your computer
+# scoop download path\to\app.json
+#
+# Options:
+# -f, --force Force download (overwrite cache)
+# -s, --skip-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\versions.ps1" # 'Select-CurrentVersion'
+. "$PSScriptRoot\..\lib\manifest.ps1" # 'generate_user_manifest' 'Get-Manifest'
+. "$PSScriptRoot\..\lib\download.ps1"
+if (get_config USE_SQLITE_CACHE) {
+ . "$PSScriptRoot\..\lib\database.ps1"
+}
+
+$opt, $apps, $err = getopt $args 'fsua:' 'force', 'skip-hash-check', 'no-update-scoop', 'arch='
+if ($err) { error "scoop download: $err"; exit 1 }
+
+$check_hash = !($opt.s -or $opt.'skip-hash-check')
+$use_cache = !($opt.f -or $opt.force)
+$architecture = Get-DefaultArchitecture
+try {
+ $architecture = Format-ArchitectureString ($opt.a + $opt.arch)
+} catch {
+ abort "ERROR: $_"
+}
+
+if (!$apps) { error ' missing'; my_usage; exit 1 }
+
+if (is_scoop_outdated) {
+ if ($opt.u -or $opt.'no-update-scoop') {
+ warn "Scoop is out of date."
+ } else {
+ & "$PSScriptRoot\scoop-update.ps1"
+ }
+}
+
+# we only want to show this warning once
+if(!$use_cache) { warn "Cache is being ignored." }
+
+foreach ($curr_app in $apps) {
+ # Prevent leaking variables from previous iteration
+ $bucket = $version = $app = $manifest = $url = $null
+
+ $app, $bucket, $version = parse_app $curr_app
+ $app, $manifest, $bucket, $url = Get-Manifest "$bucket/$app"
+
+ info "Downloading '$app'$(if ($version) { " ($version)" }) [$architecture]$(if ($bucket) { " from $bucket bucket" })"
+
+ # Generate manifest if there is different version in manifest
+ if (($null -ne $version) -and ($manifest.version -ne $version)) {
+ $generated = generate_user_manifest $app $bucket $version
+ if ($null -eq $generated) {
+ error 'Manifest cannot be generated with provided version'
+ continue
+ }
+ $manifest = parse_json($generated)
+ }
+
+ if(!$manifest) {
+ error "Couldn't find manifest for '$app'$(if($bucket) { " from '$bucket' bucket" } elseif($url) { " at '$url'" })."
+ continue
+ }
+ $version = $manifest.version
+ if(!$version) {
+ error "Manifest doesn't specify a version."
+ continue
+ }
+ if($version -match '[^\w\.\-\+_]') {
+ error "Manifest version has unsupported character '$($matches[0])'."
+ continue
+ }
+
+ $curr_check_hash = $check_hash
+ if ($version -eq 'nightly') {
+ $version = nightly_version
+ $curr_check_hash = $false
+ }
+
+ $architecture = Get-SupportedArchitecture $manifest $architecture
+ if ($null -eq $architecture) {
+ error "'$app' doesn't support current architecture!"
+ continue
+ }
+
+ if(Test-Aria2Enabled) {
+ Invoke-CachedAria2Download $app $version $manifest $architecture $cachedir $manifest.cookie $use_cache $curr_check_hash
+ } else {
+ foreach($url in script:url $manifest $architecture) {
+ try {
+ Invoke-CachedDownload $app $version $url $null $manifest.cookie $use_cache
+ } catch {
+ write-host -f darkred $_
+ error "URL $url is not valid"
+ $dl_failure = $true
+ continue
+ }
+
+ if($curr_check_hash) {
+ $manifest_hash = hash_for_url $manifest $url $architecture
+ $cached = cache_path $app $version $url
+ $ok, $err = check_hash $cached $manifest_hash (show_app $app $bucket)
+
+ if(!$ok) {
+ error $err
+ if(test-path $cached) {
+ # rm cached file
+ Remove-Item -force $cached
+ }
+ if ($url -like '*sourceforge.net*') {
+ warn 'SourceForge.net is known for causing hash validation fails. Please try again before opening a ticket.'
+ }
+ error (new_issue_msg $app $bucket "hash check failed")
+ continue
+ }
+ } else {
+ info "Skipping hash verification."
+ }
+ }
+ }
+
+ if (!$dl_failure) {
+ success "'$app' ($version) was downloaded successfully!"
+ }
+}
+
+exit 0
diff --git a/libexec/scoop-export.ps1 b/libexec/scoop-export.ps1
index 0154c607e7..8eff8db0c5 100644
--- a/libexec/scoop-export.ps1
+++ b/libexec/scoop-export.ps1
@@ -1,46 +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\core.ps1"
-. "$psscriptroot\..\lib\versions.ps1"
-. "$psscriptroot\..\lib\manifest.ps1"
-. "$psscriptroot\..\lib\buckets.ps1"
+. "$PSScriptRoot\..\lib\json.ps1" # 'ConvertToPrettyJson'
-reset_aliases
+$export = @{}
-$local = installed_apps $false | % { @{ name = $_; global = $false } }
-$global = installed_apps $true | % { @{ name = $_; global = $true } }
-
-$apps = @($local) + @($global)
-$count = 0
-
-# json
-# echo "{["
-
-if($apps) {
- $apps | sort { $_.name } | ? { !$query -or ($_.name -match $query) } | % {
- $app = $_.name
- $global = $_.global
- $ver = current_version $app $global
- $global_display = $null; if($global) { $global_display = '*global*'}
-
- # 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"
-
- $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
diff --git a/libexec/scoop-help.ps1 b/libexec/scoop-help.ps1
index 6eaed2c5ba..54ed8a9319 100644
--- a/libexec/scoop-help.ps1
+++ b/libexec/scoop-help.ps1
@@ -2,49 +2,43 @@
# Summary: Show help for a command
param($cmd)
-. "$psscriptroot\..\lib\core.ps1"
-. "$psscriptroot\..\lib\commands.ps1"
-. "$psscriptroot\..\lib\help.ps1"
-
-reset_aliases
-
function print_help($cmd) {
- $file = gc (command_path $cmd) -raw
+ $file = Get-Content (command_path $cmd) -Raw
$usage = usage $file
- $summary = summary $file
- $help = help $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 | % {
- $command = command_name $_
- $summary = summary (gc (command_path $command) -raw)
- if(!($summary)) { $summary = '' }
- $commands.add("$command ", $summary) # add padding
+ command_files | ForEach-Object {
+ $command = [ordered]@{}
+ $command.Command = command_name $_
+ $command.Summary = summary (Get-Content (command_path $command.Command))
+ $commands += [PSCustomObject]$command
}
- $commands.getenumerator() | sort name | ft -hidetablehead -autosize -wrap
+ $commands
}
$commands = commands
if(!($cmd)) {
- "Usage: scoop []
+ Write-Host "Usage: scoop []
-Some useful commands are:"
+Available commands are listed below.
+
+Type 'scoop help ' to get more help for a specific command."
print_summaries
- "Type 'scoop help ' 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
-
diff --git a/libexec/scoop-hold.ps1 b/libexec/scoop-hold.ps1
new file mode 100644
index 0000000000..504f20a849
--- /dev/null
+++ b/libexec/scoop-hold.ps1
@@ -0,0 +1,71 @@
+# Usage: scoop hold
+# Summary: Hold an app to disable updates
+# Help: To hold a user-scoped app:
+# scoop hold
+#
+# To hold a global app:
+# scoop hold -g
+#
+# Options:
+# -g, --global Hold globally installed apps
+
+. "$PSScriptRoot\..\lib\getopt.ps1"
+. "$PSScriptRoot\..\lib\json.ps1" # 'save_install_info' (indirectly)
+. "$PSScriptRoot\..\lib\manifest.ps1" # 'install_info' 'Select-CurrentVersion' (indirectly)
+. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
+
+$opt, $apps, $err = getopt $args 'g' 'global'
+if ($err) { "scoop hold: $err"; exit 1 }
+
+$global = $opt.g -or $opt.global
+
+if (!$apps) {
+ my_usage
+ exit 1
+}
+
+if ($global -and !(is_admin)) {
+ error 'You need admin rights to hold a global app.'
+ exit 1
+}
+
+foreach ($app in $apps) {
+
+ 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())."
+ continue
+ }
+ if (!(installed $app $global)) {
+ if ($global) {
+ error "'$app' is not installed globally."
+ } else {
+ error "'$app' is not installed."
+ }
+ continue
+ }
+
+ if (get_config NO_JUNCTION) {
+ $version = Select-CurrentVersion -App $app -Global:$global
+ } else {
+ $version = 'current'
+ }
+ $dir = versiondir $app $version $global
+ $json = install_info $app $version $global
+ if (!$json) {
+ error "Failed to hold '$app'."
+ continue
+ }
+ $install = @{}
+ $json | Get-Member -MemberType Properties | ForEach-Object { $install.Add($_.Name, $json.($_.Name)) }
+ if ($install.hold) {
+ info "'$app' is already held."
+ continue
+ }
+ $install.hold = $true
+ save_install_info $install $dir
+ success "$app is now held and can not be updated anymore."
+}
+
+exit $exitcode
diff --git a/libexec/scoop-home.ps1 b/libexec/scoop-home.ps1
index 3533c9de06..b1bd94e356 100644
--- a/libexec/scoop-home.ps1
+++ b/libexec/scoop-home.ps1
@@ -2,24 +2,24 @@
# Summary: Opens the app homepage
param($app)
-. "$psscriptroot\..\lib\core.ps1"
-. "$psscriptroot\..\lib\help.ps1"
-. "$psscriptroot\..\lib\manifest.ps1"
-. "$psscriptroot\..\lib\buckets.ps1"
+. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
+. "$PSScriptRoot\..\lib\manifest.ps1" # 'Get-Manifest'
+. "$PSScriptRoot\..\lib\download.ps1" # 'Get-UserAgent'
-reset_aliases
-
-if($app) {
- $manifest, $bucket = find_manifest $app
- if($manifest) {
- if([string]::isnullorempty($manifest.homepage)) {
+if ($app) {
+ $null, $manifest, $bucket, $null = Get-Manifest $app
+ if ($manifest) {
+ if ($manifest.homepage) {
+ Start-Process $manifest.homepage
+ } else {
abort "Could not find homepage in manifest for '$app'."
}
- start $manifest.homepage
- }
- else {
+ } else {
abort "Could not find manifest for '$app'."
}
-} else { my_usage }
+} else {
+ my_usage
+ exit 1
+}
exit 0
diff --git a/libexec/scoop-import.ps1 b/libexec/scoop-import.ps1
new file mode 100644
index 0000000000..383e78578e
--- /dev/null
+++ b/libexec/scoop-import.ps1
@@ -0,0 +1,65 @@
+# Usage: scoop import
+# 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) {
+ $instArgs = @()
+ $holdArgs = @()
+ $info = $item.Info -Split ', '
+ if ('Global install' -in $info) {
+ $instArgs += '--global'
+ $holdArgs += '--global'
+ }
+ if ('64bit' -in $info -and '64bit' -ne $def_arch) {
+ $instArgs += '--arch', '64bit'
+ } elseif ('32bit' -in $info -and '32bit' -ne $def_arch) {
+ $instArgs += '--arch', '32bit'
+ } elseif ('arm64' -in $info -and 'arm64' -ne $def_arch) {
+ $instArgs += '--arch', 'arm64'
+ }
+
+ $app = if ($item.Source -in $bucket_names) {
+ "$($item.Source)/$($item.Name)"
+ } elseif ($item.Source -eq '') {
+ "$($item.Name)@$($item.Version)"
+ } else {
+ $item.Source
+ }
+
+ & "$PSScriptRoot\scoop-install.ps1" $app @instArgs
+
+ if ('Held package' -in $info) {
+ & "$PSScriptRoot\scoop-hold.ps1" $item.Name @holdArgs
+ }
+}
diff --git a/libexec/scoop-info.ps1 b/libexec/scoop-info.ps1
new file mode 100644
index 0000000000..1322e33a63
--- /dev/null
+++ b/libexec/scoop-info.ps1
@@ -0,0 +1,285 @@
+# Usage: scoop info [options]
+# Summary: Display information about an app
+# Help: Options:
+# -v, --verbose Show full paths and URLs
+
+. "$PSScriptRoot\..\lib\getopt.ps1"
+. "$PSScriptRoot\..\lib\manifest.ps1" # 'Get-Manifest'
+. "$PSScriptRoot\..\lib\versions.ps1" # 'Get-InstalledVersion', 'Select-CurrentVersion'
+. "$PSScriptRoot\..\lib\download.ps1" # 'Get-RemoteFileSize'
+
+$opt, $app, $err = getopt $args 'v' 'verbose'
+$original_app = $app
+if ($err) { error "scoop info: $err"; exit 1 }
+$verbose = $opt.v -or $opt.verbose
+
+if (!$app) { my_usage; exit 1 }
+
+$app, $manifest, $bucket, $url = Get-Manifest $app
+
+if (!$manifest) {
+ abort "Could not find manifest for '$(show_app $app)' in local buckets."
+}
+
+$global = installed $app $true
+$status = app_status $app $global
+$install = install_info $app $status.version $global
+$status.installed = ($bucket -and $install.bucket -eq $bucket) -or (installed $app)
+$version_output = $manifest.version
+$manifest_file = if ($bucket) {
+ manifest_path $app $bucket
+} else {
+ $url
+}
+
+# Standalone and Source detection
+if ((Test-Path $original_app) -or ($original_app -match '^(ht|f)tps?://|\\\\')) {
+ $standalone = $true
+ if (Test-Path $original_app) {
+ $original_app = (Get-AbsolutePath "$original_app")
+ }
+ if ($install.url) {
+ if (Test-Path $install.url) {
+ $install_url = (Get-AbsolutePath $install.url)
+ } else {
+ $install_url = $install.url
+ }
+ }
+ if ($original_app -eq $install_url) {
+ $same_source = $true
+ }
+}
+
+if ($verbose) {
+ $dir = currentdir $app $global
+ $original_dir = versiondir $app $manifest.version $global
+ $persist_dir = persistdir $app $global
+} else {
+ $dir, $original_dir, $persist_dir = '', '', ''
+}
+
+if ($status.installed) {
+ $manifest_file = manifest_path $app $install.bucket
+ if ($install.url) {
+ $manifest_file = $install.url
+ }
+ if ($status.deprecated) {
+ $manifest_file = $status.deprecated
+ } elseif ($standalone -and !$same_source) {
+ $version_output = $manifest.version
+ } elseif ($status.version -eq $manifest.version) {
+ $version_output = $status.version
+ } else {
+ $version_output = "$($status.version) (Update to $($manifest.version) available)"
+ }
+
+}
+
+$item = [ordered]@{ Name = $app }
+if ($status.deprecated) {
+ $item.Name += ' (DEPRECATED)'
+}
+if ($manifest.description) {
+ $item.Description = $manifest.description
+}
+$item.Version = $version_output
+
+$item.Source = if ($standalone) {
+ $original_app
+} else {
+ if ($install.bucket) {
+ $install.bucket
+ } elseif ($install.url) {
+ $install.url
+ } else {
+ $bucket
+ }
+}
+
+if ($manifest.homepage) {
+ $item.Website = $manifest.homepage.TrimEnd('/')
+}
+# Show license
+if ($manifest.license) {
+ $item.License = if ($manifest.license.identifier -and $manifest.license.url) {
+ if ($verbose) { "$($manifest.license.identifier) ($($manifest.license.url))" } else { $manifest.license.identifier }
+ } elseif ($manifest.license -match '^((ht)|f)tps?://') {
+ $manifest.license
+ } elseif ($manifest.license -match '[|,]') {
+ if ($verbose) {
+ "$($manifest.license) ($(($manifest.license -Split '\||,' | ForEach-Object { "https://spdx.org/licenses/$_.html" }) -join ', '))"
+ } else {
+ $manifest.license
+ }
+ } else {
+ if ($verbose) { "$($manifest.license) (https://spdx.org/licenses/$($manifest.license).html)" } else { $manifest.license }
+ }
+}
+
+if ($manifest.depends) {
+ $item.Dependencies = $manifest.depends -join ' | '
+}
+
+if (Test-Path $manifest_file) {
+ if (Get-Command git -ErrorAction Ignore) {
+ $gitinfo = (Invoke-Git -Path (Split-Path $manifest_file) -ArgumentList @('log', '-1', '-s', '--format=%aD#%an', $manifest_file) 2> $null) -Split '#'
+ }
+ if ($gitinfo) {
+ $item.'Updated at' = $gitinfo[0] | Get-Date
+ $item.'Updated by' = $gitinfo[1]
+ } else {
+ $item.'Updated at' = (Get-Item $manifest_file).LastWriteTime
+ $item.'Updated by' = (Get-Acl $manifest_file).Owner.Split('\')[-1]
+ }
+}
+
+# Manifest file
+if ($verbose) { $item.Manifest = $manifest_file }
+
+if ($status.installed) {
+ # Show installed versions
+ if (!$standalone -or $same_source) {
+ $installed_output = @()
+ Get-InstalledVersion -AppName $app -Global:$global | ForEach-Object {
+ $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.FullName -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.FullName -Recurse -File | 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 (cache_path $app $manifest.version $url)) {
+ $cached = ' (latest version is cached)'
+ } else {
+ $cached = $null
+ }
+
+ $urlLength = Get-RemoteFileSize $url
+ $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)
+if ($binaries) {
+ $binary_output = @()
+ $binaries | ForEach-Object {
+ if ($_ -is [System.Array]) {
+ $binary_output += "$($_[1]).$($_[0].Split('.')[-1])"
+ } else {
+ $binary_output += $_
+ }
+ }
+ $item.Binaries = $binary_output -join ' | '
+}
+$shortcuts = @(arch_specific 'shortcuts' $manifest $install.architecture)
+if ($shortcuts) {
+ $shortcut_output = @()
+ $shortcuts | ForEach-Object {
+ $shortcut_output += $_[1]
+ }
+ $item.Shortcuts = $shortcut_output -join ' | '
+}
+$env_set = arch_specific 'env_set' $manifest $install.architecture
+if ($env_set) {
+ $env_vars = @()
+ $env_set | Get-Member -member noteproperty | ForEach-Object {
+ $env_vars += "$($_.name) = $(substitute $env_set.$($_.name) @{ '$dir' = $dir })"
+ }
+ $item.Environment = $env_vars -join "`n"
+}
+$env_add_path = arch_specific 'env_add_path' $manifest $install.architecture
+if ($env_add_path) {
+ $env_path = @()
+ $env_add_path | Where-Object { $_ } | ForEach-Object {
+ $env_path += if ($_ -eq '.') {
+ $dir
+ } else {
+ "$dir\$_"
+ }
+ }
+ $item.'Path Added' = $env_path -join "`n"
+}
+
+if ($manifest.suggest) {
+ $suggest_output = @()
+ $manifest.suggest.PSObject.Properties | ForEach-Object {
+ $suggest_output += $_.Value -join ' | '
+ }
+ $item.Suggestions = $suggest_output -join ' | '
+}
+
+if ($manifest.notes) {
+ # Show notes
+ $item.Notes = (substitute $manifest.notes @{ '$dir' = $dir; '$original_dir' = $original_dir; '$persist_dir' = $persist_dir }) -join "`n"
+}
+
+[PSCustomObject]$item
+
+exit 0
diff --git a/libexec/scoop-install.ps1 b/libexec/scoop-install.ps1
index bb0e46f56e..0fadcff09d 100644
--- a/libexec/scoop-install.ps1
+++ b/libexec/scoop-install.ps1
@@ -3,102 +3,136 @@
# 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.github.com/lukesampson/scoop/master/bucket/runat.json
+# scoop install https://raw.githubusercontent.com/ScoopInstaller/Main/master/bucket/runat.json
+#
+# To install a different version of the app from a URL:
+# scoop install https://raw.githubusercontent.com/ScoopInstaller/Main/master/bucket/neovim.json@0.9.0
#
# To install an app from a manifest on your computer
# scoop install \path\to\app.json
#
-# When installing from your computer, you can leave the .json extension off if you like.
+# To install an app from a manifest on your computer
+# scoop install \path\to\app.json@version
#
# Options:
-# -a, --arch <32bit|64bit> Use the specified architecture, if the app supports it
-# -i, --independent Don't install dependencies automatically
-# -g, --global Install the app globally
-
-. "$psscriptroot\..\lib\core.ps1"
-. "$psscriptroot\..\lib\manifest.ps1"
-. "$psscriptroot\..\lib\buckets.ps1"
-. "$psscriptroot\..\lib\decompress.ps1"
-. "$psscriptroot\..\lib\install.ps1"
-. "$psscriptroot\..\lib\shortcuts.ps1"
-. "$psscriptroot\..\lib\psmodules.ps1"
-. "$psscriptroot\..\lib\versions.ps1"
-. "$psscriptroot\..\lib\help.ps1"
-. "$psscriptroot\..\lib\getopt.ps1"
-. "$psscriptroot\..\lib\depends.ps1"
-. "$psscriptroot\..\lib\config.ps1"
-
-reset_aliases
-
-function ensure_not_installed($app, $global) {
- if(installed $app $global) {
- $global_flag = $null;
- if($global){ $global_flag = ' --global' }
-
- $version = @(versions $app $global)[-1]
- if(!(install_info $app $version $global)) {
- abort "It looks like a previous installation of $app failed.`nRun 'scoop uninstall $app$global_flag' before retrying the install."
- }
- abort "'$app' ($version) is already installed.`nUse 'scoop update $app$global_flag' to install a new version."
- }
+# -g, --global Install the app globally
+# -i, --independent Don't install dependencies automatically
+# -k, --no-cache Don't use the download cache
+# -s, --skip-hash-check Skip hash validation (use with caution!)
+# -u, --no-update-scoop Don't update Scoop before installing 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' 'manifest.ps1' (indirectly)
+. "$PSScriptRoot\..\lib\autoupdate.ps1" # 'generate_user_manifest' (indirectly)
+. "$PSScriptRoot\..\lib\manifest.ps1" # 'generate_user_manifest' 'Get-Manifest' 'Select-CurrentVersion' (indirectly)
+. "$PSScriptRoot\..\lib\system.ps1"
+. "$PSScriptRoot\..\lib\install.ps1"
+. "$PSScriptRoot\..\lib\download.ps1"
+. "$PSScriptRoot\..\lib\decompress.ps1"
+. "$PSScriptRoot\..\lib\shortcuts.ps1"
+. "$PSScriptRoot\..\lib\psmodules.ps1"
+. "$PSScriptRoot\..\lib\versions.ps1"
+. "$PSScriptRoot\..\lib\depends.ps1"
+if (get_config USE_SQLITE_CACHE) {
+ . "$PSScriptRoot\..\lib\database.ps1"
}
-$opt, $apps, $err = getopt $args 'gia:' 'global', 'independent', 'arch='
-if($err) { "scoop install: $err"; exit 1 }
+$opt, $apps, $err = getopt $args 'giksua:' 'global', 'independent', 'no-cache', 'skip-hash-check', 'no-update-scoop', 'arch='
+if ($err) { "scoop install: $err"; exit 1 }
$global = $opt.g -or $opt.global
+$check_hash = !($opt.s -or $opt.'skip-hash-check')
$independent = $opt.i -or $opt.independent
-$architecture = ensure_architecture ($opt.a + $opt.arch)
+$use_cache = !($opt.k -or $opt.'no-cache')
+$architecture = Get-DefaultArchitecture
+try {
+ $architecture = Format-ArchitectureString ($opt.a + $opt.arch)
+} catch {
+ abort "ERROR: $_"
+}
-if(!$apps) { 'ERROR: missing'; my_usage; exit 1 }
+if (!$apps) { error ' missing'; my_usage; exit 1 }
-if($global -and !(is_admin)) {
- 'ERROR: you need admin rights to install global apps'; exit 1
+if ($global -and !(is_admin)) {
+ abort 'ERROR: you need admin rights to install global apps'
}
-if($apps.length -eq 1) {
- ensure_not_installed $apps $global
+if (is_scoop_outdated) {
+ if ($opt.u -or $opt.'no-update-scoop') {
+ warn "Scoop is out of date."
+ } else {
+ & "$PSScriptRoot\scoop-update.ps1"
+ }
+}
+
+ensure_none_failed $apps
+
+if ($apps.length -eq 1) {
+ $app, $null, $version = parse_app $apps
+ if ($app.EndsWith('.json')) {
+ $app = [System.IO.Path]::GetFileNameWithoutExtension($app)
+ }
+ $curVersion = Select-CurrentVersion -AppName $app -Global:$global
+ if ($null -eq $version -and $curVersion) {
+ warn "'$app' ($curVersion) is already installed.`nUse 'scoop update $app$(if ($global) { ' --global' })' to install a new version."
+ exit 0
+ }
}
# get any specific versions that we need to handle first
-$specific_versions = $apps | Where-Object { is_app_with_specific_version $_ }
+$specific_versions = $apps | Where-Object {
+ $null, $null, $version = parse_app $_
+ return $null -ne $version
+}
# compare object does not like nulls
-if ($specific_versions.length -gt 0) {
+if ($specific_versions.Count -gt 0) {
$difference = Compare-Object -ReferenceObject $apps -DifferenceObject $specific_versions -PassThru
} else {
$difference = $apps
}
$specific_versions_paths = $specific_versions | ForEach-Object {
- $appWithVersion = get_app_with_version $_
- $name = $appWithVersion.app
- $version = $appWithVersion.version
-
- if (installed_manifest $name $version) {
- abort "'$name' ($version) is already installed.`nUse 'scoop update $name$global_flag' to install a new version."
+ $app, $bucket, $version = parse_app $_
+ if (installed_manifest $app $version) {
+ warn "'$app' ($version) is already installed.`nUse 'scoop update $app$(if ($global) { ' --global' })' to install a new version."
+ continue
}
- generate_user_manifest $name $version
+ generate_user_manifest $app $bucket $version
}
-$apps = @(($specific_versions_paths + $difference) | Where-Object { $_ } | Sort-Object -Unique)
+$apps = @((@($specific_versions_paths) + $difference) | Where-Object { $_ } | Select-Object -Unique)
# remember which were explictly requested so that we can
# differentiate after dependencies are added
$explicit_apps = $apps
-if(!$independent) {
- $apps = install_order $apps $architecture # adds dependencies
+if (!$independent) {
+ $apps = $apps | Get-Dependency -Architecture $architecture | Select-Object -Unique # adds dependencies
}
-ensure_none_failed $apps $global
+ensure_none_failed $apps
$apps, $skip = prune_installed $apps $global
-$skip | ? { $explicit_apps -contains $_} | % { warn "$_ is already installed. Skipping." }
+$skip | Where-Object { $explicit_apps -contains $_ } | ForEach-Object {
+ $app, $null, $null = parse_app $_
+ $version = Select-CurrentVersion -AppName $app -Global:$global
+ warn "'$app' ($version) is already installed. Skipping."
+}
-$suggested = @{};
-$apps | % { install_app $_ $architecture $global $suggested }
+$suggested = @{ };
+if ((Test-Aria2Enabled) -and (get_config 'aria2-warning-enabled' $true)) {
+ warn "Scoop uses 'aria2c' for multi-connection downloads."
+ warn "Should it cause issues, run 'scoop config aria2-enabled false' to disable it."
+ warn "To disable this warning, run 'scoop config aria2-warning-enabled false'."
+}
+$apps | ForEach-Object { install_app $_ $architecture $global $suggested $use_cache $check_hash }
show_suggestions $suggested
diff --git a/libexec/scoop-list.ps1 b/libexec/scoop-list.ps1
index 222c182ee2..f757146d47 100644
--- a/libexec/scoop-list.ps1
+++ b/libexec/scoop-list.ps1
@@ -3,32 +3,62 @@
# Help: Lists all installed apps, or the apps matching the supplied query.
param($query)
-. "$psscriptroot\..\lib\core.ps1"
-. "$psscriptroot\..\lib\versions.ps1"
-. "$psscriptroot\..\lib\manifest.ps1"
-. "$psscriptroot\..\lib\buckets.ps1"
+. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
+. "$PSScriptRoot\..\lib\manifest.ps1" # 'parse_json' 'Select-CurrentVersion' (indirectly)
+. "$PSScriptRoot\..\lib\download.ps1" # 'Get-UserAgent'
-reset_aliases
+$defaultArchitecture = Get-DefaultArchitecture
+if (-not (Get-FormatData ScoopApps)) {
+ Update-FormatData "$PSScriptRoot\..\supporting\formats\ScoopTypes.Format.ps1xml"
+}
-$local = installed_apps $false | % { @{ name = $_ } }
-$global = installed_apps $true | % { @{ name = $_; global = $true } }
+$local = installed_apps $false | ForEach-Object { @{ name = $_ } }
+$global = installed_apps $true | ForEach-Object { @{ name = $_; global = $true } }
$apps = @($local) + @($global)
+if (-not $apps) {
+ Write-Host "There aren't any apps installed."
+ exit 1
+}
-if($apps) {
- echo "Installed apps$(if($query) { `" matching '$query'`"}):
-"
- $apps | sort { $_.name } | ? { !$query -or ($_.name -match $query) } | % {
- $app = $_.name
- $global = $_.global
- $ver = current_version $app $global
- $global_display = $null; if($global) { $global_display = '*global*'}
+$list = @()
+Write-Host "Installed apps$(if($query) { `" matching '$query'`"}):"
+$apps | Where-Object { !$query -or ($_.name -match $query) } | ForEach-Object {
+ $app = $_.name
+ $global = $_.global
+ $item = @{}
+ $ver = Select-CurrentVersion -AppName $app -Global:$global
+ $item.Name = $app
+ $item.Version = $ver
- " $app ($ver) $global_display"
+ $install_info_path = "$(versiondir $app $ver $global)\install.json"
+ $updated = (Get-Item (appdir $app $global)).LastWriteTime
+ $install_info = $null
+ if (Test-Path $install_info_path) {
+ $install_info = parse_json $install_info_path
+ $updated = (Get-Item $install_info_path).LastWriteTime
}
- ""
- exit 0
-} else {
- "There aren't any apps installed."
- exit 1
+
+ $item.Source = if ($install_info.bucket) {
+ $install_info.bucket
+ } elseif ($install_info.url) {
+ if ($install_info.url -eq (usermanifest $app)) { '' }
+ else { $install_info.url }
+ }
+ $item.Updated = $updated
+
+ $info = @()
+ if ((app_status $app $global).deprecated) { $info += 'Deprecated package'}
+ if ($global) { $info += 'Global install' }
+ if (failed $app $global) { $info += 'Install failed' }
+ if ($install_info.hold) { $info += 'Held package' }
+ if ($install_info.architecture -and $defaultArchitecture -ne $install_info.architecture) {
+ $info += $install_info.architecture
+ }
+ $item.Info = $info -join ', '
+
+ $list += [PSCustomObject]$item
}
+
+$list | Add-Member -TypeName 'ScoopApps' -PassThru
+exit 0
diff --git a/libexec/scoop-prefix.ps1 b/libexec/scoop-prefix.ps1
new file mode 100644
index 0000000000..c16cda574a
--- /dev/null
+++ b/libexec/scoop-prefix.ps1
@@ -0,0 +1,23 @@
+# Usage: scoop prefix
+# Summary: Returns the path to the specified app
+param($app)
+
+. "$PSScriptRoot\..\lib\versions.ps1" # 'currentdir' (indirectly)
+
+if (!$app) {
+ my_usage
+ exit 1
+}
+
+$app_path = currentdir $app $false
+if (!(Test-Path $app_path)) {
+ $app_path = currentdir $app $true
+}
+
+if (Test-Path $app_path) {
+ Write-Output $app_path
+} else {
+ abort "Could not find app path for '$app'."
+}
+
+exit 0
diff --git a/libexec/scoop-reset.ps1 b/libexec/scoop-reset.ps1
index 9af60b68ab..512540e8e6 100644
--- a/libexec/scoop-reset.ps1
+++ b/libexec/scoop-reset.ps1
@@ -3,47 +3,92 @@
# 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.
-param($app)
+#
+# You can use '*' in place of or `-a`/`--all` switch to reset all apps.
-. "$psscriptroot\..\lib\core.ps1"
-. "$psscriptroot\..\lib\manifest.ps1"
-. "$psscriptroot\..\lib\help.ps1"
-. "$psscriptroot\..\lib\install.ps1"
-. "$psscriptroot\..\lib\versions.ps1"
-. "$psscriptroot\..\lib\config.ps1"
-. "$psscriptroot\..\lib\shortcuts.ps1"
+. "$PSScriptRoot\..\lib\getopt.ps1"
+. "$PSScriptRoot\..\lib\manifest.ps1" # 'Select-CurrentVersion' (indirectly)
+. "$PSScriptRoot\..\lib\system.ps1" # 'env_add_path' (indirectly)
+. "$PSScriptRoot\..\lib\install.ps1"
+. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
+. "$PSScriptRoot\..\lib\shortcuts.ps1"
-reset_aliases
+$opt, $apps, $err = getopt $args 'a' 'all'
+if($err) { "scoop reset: $err"; exit 1 }
+$all = $opt.a -or $opt.all
-if(!$app) { 'ERROR: missing'; my_usage; exit 1 }
+if(!$apps -and !$all) { error ' missing'; my_usage; exit 1 }
-$appWithVersion = get_app_with_version $app
-$app = $appWithVersion.app;
-$version = $appWithVersion.version;
+if($apps -eq '*' -or $all) {
+ $local = installed_apps $false | ForEach-Object { ,@($_, $false) }
+ $global = installed_apps $true | ForEach-Object { ,@($_, $true) }
+ $apps = @($local) + @($global)
+}
+$apps | ForEach-Object {
+ ($app, $global) = $_
-if(!(installed $app)) { abort "'$app' isn't installed" }
+ $app, $bucket, $version = parse_app $app
-if ($version -eq 'latest') {
- $version = current_version $app
-}
+ if(($global -eq $null) -and (installed $app $true)) {
+ # set global flag when running reset command on specific app
+ $global = $true
+ }
-$manifest = installed_manifest $app $version
-# if this is null we know the version they're resetting to
-# is not installed
-if ($manifest -eq $null) {
- abort "'$app ($version)' isn't installed"
-}
+ if($app -eq 'scoop') {
+ # skip scoop
+ return
+ }
+
+ if(!(installed $app)) {
+ error "'$app' isn't installed"
+ return
+ }
+
+ if ($null -eq $version) {
+ $version = Select-CurrentVersion -AppName $app -Global:$global
+ }
-"Resetting $app ($version)."
+ $manifest = installed_manifest $app $version $global
+ # if this is null we know the version they're resetting to
+ # is not installed
+ if ($manifest -eq $null) {
+ error "'$app ($version)' isn't installed"
+ return
+ }
-$dir = resolve-path (versiondir $app $version)
+ if($global -and !(is_admin)) {
+ warn "'$app' ($version) is a global app. You need admin rights to reset it. Skipping."
+ return
+ }
-$install = install_info $app $version
-$architecture = $install.architecture
+ write-host "Resetting $app ($version)."
+
+ $dir = Convert-Path (versiondir $app $version $global)
+ $original_dir = $dir
+ $persist_dir = persistdir $app $global
+
+ #region Workaround for #2952
+ if (test_running_process $app $global) {
+ return
+ }
+ #endregion Workaround for #2952
+
+ $install = install_info $app $version $global
+ $architecture = $install.architecture
+
+ $dir = link_current $dir
+ create_shims $manifest $dir $global $architecture
+ create_startmenu_shortcuts $manifest $dir $global $architecture
+ # unset all potential old env before re-adding
+ env_rm_path $manifest $dir $global $architecture
+ env_rm $manifest $global $architecture
+ env_add_path $manifest $dir $global $architecture
+ env_set $manifest $global $architecture
+ # unlink all potential old link before re-persisting
+ unlink_persist_data $manifest $original_dir
+ persist_data $manifest $original_dir $persist_dir
+ persist_permission $manifest $global
+}
-$dir = link_current $dir
-create_shims $manifest $dir $false $architecture
-create_startmenu_shortcuts $manifest $dir $false
-env_add_path $manifest $dir
-env_set $manifest $dir
+exit 0
diff --git a/libexec/scoop-search.ps1 b/libexec/scoop-search.ps1
index 21ba3ebe9e..d94b18660d 100644
--- a/libexec/scoop-search.ps1
+++ b/libexec/scoop-search.ps1
@@ -1,75 +1,131 @@
-# Usage: scoop search [query]
+# Usage: scoop search
# Summary: Search available apps
# Help: Searches for apps that are available to install.
#
# If used with [query], shows app names that match the query.
+# - With 'use_sqlite_cache' enabled, [query] is partially matched against app names, binaries, and shortcuts.
+# - Without 'use_sqlite_cache', [query] can be a regular expression to match against app names and binaries.
# Without [query], shows all the available apps.
param($query)
-. "$psscriptroot\..\lib\core.ps1"
-. "$psscriptroot\..\lib\buckets.ps1"
-. "$psscriptroot\..\lib\manifest.ps1"
-. "$psscriptroot\..\lib\versions.ps1"
-reset_aliases
+. "$PSScriptRoot\..\lib\manifest.ps1" # 'manifest'
+. "$PSScriptRoot\..\lib\versions.ps1" # 'Get-LatestVersion'
+. "$PSScriptRoot\..\lib\download.ps1"
+
+$list = [System.Collections.Generic.List[PSCustomObject]]::new()
function bin_match($manifest, $query) {
- if(!$manifest.bin) { return $false }
- foreach($bin in $manifest.bin) {
+ if (!$manifest.bin) { return $false }
+ $bins = foreach ($bin in $manifest.bin) {
$exe, $alias, $args = $bin
- $fname = split-path $exe -leaf -ea stop
+ $fname = Split-Path $exe -Leaf -ErrorAction Stop
- if((strip_ext $fname) -match $query) { return $fname }
- if($alias -match $query) { return $alias }
+ 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 (bucketdir $bucket) | % {
- @{ name = $_ }
+function bin_match_json($json, $query) {
+ [System.Text.Json.JsonElement]$bin = [System.Text.Json.JsonElement]::new()
+ if (!$json.RootElement.TryGetProperty('bin', [ref] $bin)) { return $false }
+ $bins = @()
+ if ($bin.ValueKind -eq [System.Text.Json.JsonValueKind]::String -and [System.IO.Path]::GetFileNameWithoutExtension($bin) -match $query) {
+ $bins += [System.IO.Path]::GetFileName($bin)
+ } elseif ($bin.ValueKind -eq [System.Text.Json.JsonValueKind]::Array) {
+ foreach ($subbin in $bin.EnumerateArray()) {
+ if ($subbin.ValueKind -eq [System.Text.Json.JsonValueKind]::String -and [System.IO.Path]::GetFileNameWithoutExtension($subbin) -match $query) {
+ $bins += [System.IO.Path]::GetFileName($subbin)
+ } elseif ($subbin.ValueKind -eq [System.Text.Json.JsonValueKind]::Array) {
+ if ([System.IO.Path]::GetFileNameWithoutExtension($subbin[0]) -match $query) {
+ $bins += [System.IO.Path]::GetFileName($subbin[0])
+ } elseif ($subbin.GetArrayLength() -ge 2 -and $subbin[1] -match $query) {
+ $bins += $subbin[1]
+ }
+ }
+ }
}
- if($query) {
- try {
- $query = new-object regex $query, 'IgnoreCase'
+ if ($bins) { return $bins }
+ else { return $false }
+}
+
+function search_bucket($bucket, $query) {
+ $apps = Get-ChildItem (Find-BucketDirectory $bucket) -Filter '*.json' -Recurse
+
+ $apps | ForEach-Object {
+ $filepath = $_.FullName
+
+ $json = try {
+ [System.Text.Json.JsonDocument]::Parse([System.IO.File]::ReadAllText($filepath))
} catch {
- abort "Invalid regular expression: $($_.exception.innerexception.message)"
+ debug "Failed to parse manifest file: $filepath (error: $_)"
+ return
}
- $apps = $apps | ? {
- if($_.name -match $query) { return $true }
- $bin = bin_match (manifest $_.name $bucket) $query
- if($bin) {
- $_.bin = $bin; return $true;
+ $name = $_.BaseName
+
+ if ($name -match $query) {
+ $list.Add([PSCustomObject]@{
+ Name = $name
+ Version = $json.RootElement.GetProperty('version')
+ Source = $bucket
+ Binaries = ''
+ })
+ } else {
+ $bin = bin_match_json $json $query
+ if ($bin) {
+ $list.Add([PSCustomObject]@{
+ Name = $name
+ Version = $json.RootElement.GetProperty('version')
+ Source = $bucket
+ Binaries = $bin -join ' | '
+ })
}
}
}
- $apps | % { $_.version = (latest_version $_.name $bucket); $_ }
-}
-
-function download_json($url) {
- $progressPreference = 'silentlycontinue'
- $result = invoke-webrequest $url -UseBasicParsing | select -exp 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
+# fallback function for PowerShell 5
+function search_bucket_legacy($bucket, $query) {
+ $apps = Get-ChildItem (Find-BucketDirectory $bucket) -Filter '*.json' -Recurse
+
+ $apps | ForEach-Object {
+ $manifest = [System.IO.File]::ReadAllText($_.FullName) | ConvertFrom-Json -ErrorAction Continue
+ $name = $_.BaseName
+
+ if ($name -match $query) {
+ $list.Add([PSCustomObject]@{
+ Name = $name
+ Version = $manifest.Version
+ Source = $bucket
+ Binaries = ''
+ })
+ } else {
+ $bin = bin_match $manifest $query
+ if ($bin) {
+ $list.Add([PSCustomObject]@{
+ Name = $name
+ Version = $manifest.Version
+ Source = $bucket
+ Binaries = $bin -join ' | '
+ })
+ }
+ }
+ }
}
function search_remote($bucket, $query) {
- $repo = known_bucket_repo $bucket
-
- $uri = [system.uri]($repo)
- if ($uri.absolutepath -match '/([a-zA-Z0-9]*)/([a-zA-Z0-9-]*)(.git|/)?') {
- $user = $matches[1]
- $repo_name = $matches[2]
+ $uri = [System.Uri](known_bucket_repo $bucket)
+ if ($uri.AbsolutePath -match '/([a-zA-Z0-9]*)/([a-zA-Z0-9-]*)(?:.git|/)?') {
+ $user = $Matches[1]
+ $repo_name = $Matches[2]
$api_link = "https://api.github.com/repos/$user/$repo_name/git/trees/HEAD?recursive=1"
- $result = download_json $api_link | select -exp tree |? {
- $_.path -match "(($query[a-zA-Z0-9-]*).json)"
- } |% { $matches[2] }
+ $result = download_json $api_link | Select-Object -ExpandProperty tree |
+ Where-Object -Value "^bucket/(.*$query.*)\.json$" -Property Path -Match |
+ ForEach-Object { $Matches[1] }
}
$result
@@ -77,45 +133,71 @@ function search_remote($bucket, $query) {
function search_remotes($query) {
$buckets = known_bucket_repos
- $names = $buckets | get-member -m noteproperty | select -exp name
+ $names = $buckets | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty name
- $results = $names |? { !(test-path $(bucketdir $_)) } |% {
- @{"bucket" = $_; "results" = (search_remote $_ $query)}
- } |? { $_.results }
+ $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 ')"
- ""
+ Write-Host "Results from other known buckets...
+(add them using 'scoop bucket add ')"
}
- $results |% {
- "'$($_.bucket)'' bucket:"
- $_.results |% { " $_" }
- ""
+ $remote_list = @()
+ $results | ForEach-Object {
+ $bucket = $_.bucket
+ $_.results | ForEach-Object {
+ $item = [ordered]@{}
+ $item.Name = $_
+ $item.Source = $bucket
+ $remote_list += [PSCustomObject]$item
+ }
}
+ $remote_list
}
-@($null) + @(buckets) | % { # $null is main bucket
- $res = search_bucket $_ $query
- $local_results = $local_results -or $res
- if($res) {
- $name = "$_"
- if(!$_) { $name = "main" }
-
- "'$name' bucket:"
- $res | % {
- $item = " $($_.name) ($($_.version))"
- if($_.bin) { $item += " --> includes '$($_.bin)'" }
- $item
+if (get_config USE_SQLITE_CACHE) {
+ . "$PSScriptRoot\..\lib\database.ps1"
+ Select-ScoopDBItem $query -From @('name', 'binary', 'shortcut') |
+ Select-Object -Property name, version, bucket, binary |
+ ForEach-Object {
+ $list.Add([PSCustomObject]@{
+ Name = $_.name
+ Version = $_.version
+ Source = $_.bucket
+ Binaries = $_.binary
+ })
+ }
+} else {
+ try {
+ $query = New-Object Regex $query, 'IgnoreCase'
+ } catch {
+ abort "Invalid regular expression: $($_.Exception.InnerException.Message)"
+ }
+
+ $jsonTextAvailable = [System.AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { [System.IO.Path]::GetFileNameWithoutExtension($_.Location) -eq 'System.Text.Json' }
+
+ Get-LocalBucket | ForEach-Object {
+ if ($jsonTextAvailable) {
+ search_bucket $_ $query
+ } else {
+ search_bucket_legacy $_ $query
}
- ""
}
}
-if (!$local_results -and !(github_ratelimit_reached)) {
+if ($list.Count -gt 0) {
+ Write-Host 'Results from local buckets...'
+ $list
+}
+
+if ($list.Count -eq 0 -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
}
diff --git a/libexec/scoop-shim.ps1 b/libexec/scoop-shim.ps1
new file mode 100644
index 0000000000..877b65b2e9
--- /dev/null
+++ b/libexec/scoop-shim.ps1
@@ -0,0 +1,240 @@
+# Usage: scoop shim [...] [options] [other_args]
+# Summary: Manipulate Scoop shims
+# Help: Available subcommands: add, rm, list, info, alter.
+#
+# To add a custom shim, use the 'add' subcommand:
+#
+# scoop shim add [...]
+#
+# To remove shims, use the 'rm' subcommand: (CAUTION: this could remove shims added by an app manifest)
+#
+# scoop shim rm [...]
+#
+# To list all shims or matching shims, use the 'list' subcommand:
+#
+# scoop shim list [...]
+#
+# To show a shim's information, use the 'info' subcommand:
+#
+# scoop shim info
+#
+# To alternate a shim's target source, use the 'alter' subcommand:
+#
+# scoop shim alter
+#
+# Options:
+# -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)
+
+. "$PSScriptRoot\..\lib\getopt.ps1"
+. "$PSScriptRoot\..\lib\install.ps1" # for rm_shim
+. "$PSScriptRoot\..\lib\system.ps1" # 'Add-Path' (indirectly)
+
+if ($SubCommand -notin @('add', 'rm', 'list', 'info', 'alter')) {
+ if (!$SubCommand) {
+ error ' 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 " must be specified for subcommand '$SubCommand'"
+ my_usage
+ exit 1
+}
+
+if (-not (Get-FormatData ScoopShims)) {
+ Update-FormatData "$PSScriptRoot\..\supporting\formats\ScoopTypes.Format.ps1xml"
+}
+
+$localShimDir = shimdir $false
+$globalShimDir = shimdir $true
+
+function Get-ShimInfo($ShimPath) {
+ $info = [Ordered]@{}
+ $info.Name = strip_ext (fname $ShimPath)
+ $info.Path = $ShimPath -replace 'shim$', 'exe'
+ $info.Source = (get_app_name_from_shim $ShimPath) -replace '^$', 'External'
+ $info.Type = if ($ShimPath.EndsWith('.ps1')) { 'ExternalScript' } else { 'Application' }
+ $altShims = Get-Item -Path "$ShimPath.*" -Exclude '*.shim', '*.cmd', '*.ps1'
+ if ($altShims) {
+ $info.Alternatives = (@($info.Source) + ($altShims | ForEach-Object { $_.Extension.Remove(0, 1) } | Select-Object -Unique)) -join ' '
+ }
+ $info.IsGlobal = $ShimPath.StartsWith("$globalShimDir")
+ $info.IsHidden = !((Get-Command -Name $info.Name).Path -eq $info.Path)
+ [PSCustomObject]$info
+}
+
+function Get-ShimPath($ShimName, $Global) {
+ '.shim', '.ps1' | ForEach-Object {
+ $shimPath = Join-Path (shimdir $Global) "$ShimName$_"
+ if (Test-Path -LiteralPath $shimPath) {
+ return $shimPath
+ }
+ }
+}
+
+switch ($SubCommand) {
+ 'add' {
+ if ($other.Length -lt 2 -or $other[1] -eq '') {
+ error " 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)
+ if (!$commandPath) {
+ $exCommand = Get-Command $shortPath -ErrorAction SilentlyContinue
+ if ($exCommand -and $exCommand.CommandType -eq 'Application') {
+ $commandPath = $exCommand.Path
+ } # TODO - add support for more command types: Alias, Cmdlet, ExternalScript, Filter, Function, Script, and Workflow
+ }
+ }
+ if ($commandPath -and (Test-Path $commandPath)) {
+ Write-Host "Adding $(if ($global) { 'global' } else { 'local' }) shim " -NoNewline
+ Write-Host $shimName -ForegroundColor Cyan -NoNewline
+ Write-Host '...'
+ shim $commandPath $global $shimName $commandArgs
+ } else {
+ Write-Host "ERROR: Command path does not exist: " -ForegroundColor Red -NoNewline
+ Write-Host $($other[1]) -ForegroundColor Cyan
+ exit 3
+ }
+ }
+ 'rm' {
+ $failed = @()
+ $other | ForEach-Object {
+ if (Get-ShimPath $_ $global) {
+ rm_shim $_ (shimdir $global)
+ } else {
+ $failed += $_
+ }
+ }
+ if ($failed) {
+ $failed | ForEach-Object {
+ Write-Host "ERROR: $(if ($global) { 'Global' } else {'Local' }) shim not found: " -ForegroundColor Red -NoNewline
+ Write-Host $_ -ForegroundColor Cyan
+ }
+ exit 3
+ }
+ }
+ 'list' {
+ $other = @($other) -ne '*'
+ # Validate all given patterns before matching.
+ $other | ForEach-Object {
+ try {
+ $pattern = $_
+ [void][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 { !$pattern -or ($_.BaseName -match $pattern) } |
+ Select-Object -ExpandProperty FullName
+ }
+ $shims.ForEach({ Get-ShimInfo $_ }) | Add-Member -TypeName 'ScoopShims' -PassThru
+ }
+ 'info' {
+ $shimName = $other[0]
+ $shimPath = Get-ShimPath $shimName $global
+ if ($shimPath) {
+ Get-ShimInfo $shimPath
+ } else {
+ 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"
+ exit 2
+ }
+ exit 3
+ }
+ }
+ 'alter' {
+ $shimName = $other[0]
+ $shimPath = Get-ShimPath $shimName $global
+ if ($shimPath) {
+ $shimInfo = Get-ShimInfo $shimPath
+ if ($null -eq $shimInfo.Alternatives) {
+ 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])."
+ }
+ $selected = $Host.UI.PromptForChoice("Alternatives of '$shimName' command", "Please choose one that provides '$shimName' as default:", $altApps, 0)
+ if ($selected -eq 0) {
+ 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 ' from ' -NoNewline
+ Write-Host $newApp -ForegroundColor DarkYellow -NoNewline
+ Write-Host ' as default...' -NoNewline
+ $pathNoExt = strip_ext $shimPath
+ '', '.shim', '.cmd', '.ps1' | ForEach-Object {
+ $oldShimPath = "$pathNoExt$_"
+ $newShimPath = "$oldShimPath.$newApp"
+ if (Test-Path -Path $oldShimPath -PathType Leaf) {
+ Rename-Item -Path $oldShimPath -NewName "$oldShimPath.$($shimInfo.Source)" -Force
+ if (Test-Path -Path $newShimPath -PathType Leaf) {
+ Rename-Item -Path $newShimPath -NewName $oldShimPath -Force
+ }
+ }
+ }
+ Write-Host 'done.'
+ }
+ } else {
+ 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"
+ exit 2
+ }
+ exit 3
+ }
+ }
+}
+
+exit 0
diff --git a/libexec/scoop-status.ps1 b/libexec/scoop-status.ps1
index 39f6c516c2..cc34ddac9f 100644
--- a/libexec/scoop-status.ps1
+++ b/libexec/scoop-status.ps1
@@ -1,105 +1,85 @@
# 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\core.ps1"
-. "$psscriptroot\..\lib\manifest.ps1"
-. "$psscriptroot\..\lib\buckets.ps1"
-. "$psscriptroot\..\lib\versions.ps1"
-. "$psscriptroot\..\lib\depends.ps1"
-. "$psscriptroot\..\lib\config.ps1"
-. "$psscriptroot\..\lib\git.ps1"
-
-reset_aliases
+. "$PSScriptRoot\..\lib\manifest.ps1" # 'manifest' 'parse_json' "install_info"
+. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
+. "$PSScriptRoot\..\lib\download.ps1" # 'Get-UserAgent'
# check if scoop needs updating
-$currentdir = fullpath $(versiondir 'scoop' 'current')
+$currentdir = versiondir 'scoop' 'current'
$needs_update = $false
-
-if(test-path "$currentdir\.git") {
- pushd $currentdir
- git_fetch -q origin
- $commits = $(git log "HEAD..origin/$(scoop config SCOOP_BRANCH)" --oneline)
- if($commits) { $needs_update = $true }
- popd
-}
-else {
- $needs_update = $true
+$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($needs_update) {
- "Scoop is out of date. Run 'scoop update' to get the latest changes."
+function Test-UpdateStatus($repopath) {
+ if (Test-Path "$repopath\.git") {
+ Invoke-Git -Path $repopath -ArgumentList @('fetch', '-q', 'origin')
+ $script:network_failure = 128 -eq $LASTEXITCODE
+ $branch = Invoke-Git -Path $repopath -ArgumentList @('branch', '--show-current')
+ $commits = Invoke-Git -Path $repopath -ArgumentList @('log', "HEAD..origin/$branch", '--oneline')
+ if ($commits) { return $true }
+ else { return $false }
+ } else {
+ return $true
+ }
}
-else { "Scoop is up to date."}
-
-$failed = @()
-$old = @()
-$removed = @()
-$missing_deps = @()
-
-$true, $false | % { # local and global apps
- $global = $_
- $dir = appsdir $global
- if(!(test-path $dir)) { return }
-
- gci $dir | ? name -ne 'scoop' | % {
- $app = $_.name
- $version = current_version $app $global
- if($version) {
- $install_info = install_info $app $version $global
- }
-
- if(!$install_info -or !$version) {
- $failed += @{ $app = $version }; return
- }
- $manifest = manifest $app $install_info.bucket $install_info.url
- if(!$manifest) { $removed += @{ $app = $version }; return }
-
- if((compare_versions $manifest.version $version) -gt 0) {
- $old += @{ $app = @($version, $manifest.version) }
- }
-
- $deps = @(runtime_deps $manifest) | ? { !(installed $_) }
- if($deps) {
- $missing_deps += ,(@($app) + @($deps))
+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($old) {
- "Updates are available for:"
- $old.keys | % {
- $versions = $old.$_
- " $_`: $($versions[0]) -> $($versions[1])"
- }
+if ($needs_update) {
+ warn "Scoop out of date. Run 'scoop update' to get the latest changes."
+} elseif ($bucket_needs_update) {
+ warn "Scoop bucket(s) out of date. Run 'scoop update' to get the latest changes."
+} elseif (!$script:network_failure -and !$no_remotes) {
+ success 'Scoop is up to date.'
}
-if($removed) {
- "These app manifests have been removed:"
- $removed.keys | % {
- " $_"
- }
-}
+$true, $false | ForEach-Object { # local and global apps
+ $global = $_
+ $dir = appsdir $global
+ if (!(Test-Path $dir)) { return }
-if($failed) {
- "These apps failed to install:"
- $failed.keys | % {
- " $_"
+ Get-ChildItem $dir | Where-Object name -NE 'scoop' | ForEach-Object {
+ $app = $_.name
+ $status = app_status $app $global
+ if (!$status.outdated -and !$status.failed -and !$status.deprecated -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.deprecated) { $info += 'Deprecated' }
+ if ($status.removed) { $info += 'Manifest removed' }
+ $item.Info = $info -join ', '
+ $list += [PSCustomObject]$item
}
}
-if($missing_deps) {
- "Missing runtime dependencies:"
- $missing_deps | % {
- $app, $deps = $_
- " '$app' requires '$([string]::join("', '", $deps))'"
- }
+if ($list.Length -eq 0 -and !$needs_update -and !$bucket_needs_update -and !$script:network_failure) {
+ success 'Everything is ok!'
}
-if(!$old -and !$removed -and !$failed -and !$missing_deps) {
- success "Everything is ok!"
-}
+$list | Add-Member -TypeName ScoopStatus -PassThru
exit 0
diff --git a/libexec/scoop-unhold.ps1 b/libexec/scoop-unhold.ps1
new file mode 100644
index 0000000000..4e2413a340
--- /dev/null
+++ b/libexec/scoop-unhold.ps1
@@ -0,0 +1,71 @@
+# Usage: scoop unhold
+# Summary: Unhold an app to enable updates
+# Help: To unhold a user-scoped app:
+# scoop unhold
+#
+# To unhold a global app:
+# scoop unhold -g
+#
+# Options:
+# -g, --global Unhold globally installed apps
+
+. "$PSScriptRoot\..\lib\getopt.ps1"
+. "$PSScriptRoot\..\lib\json.ps1" # 'save_install_info' (indirectly)
+. "$PSScriptRoot\..\lib\manifest.ps1" # 'install_info' 'Select-CurrentVersion' (indirectly)
+. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
+
+$opt, $apps, $err = getopt $args 'g' 'global'
+if ($err) { "scoop unhold: $err"; exit 1 }
+
+$global = $opt.g -or $opt.global
+
+if (!$apps) {
+ my_usage
+ exit 1
+}
+
+if ($global -and !(is_admin)) {
+ error 'You need admin rights to unhold a global app.'
+ exit 1
+}
+
+$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."
+ } else {
+ error "'$app' is not installed."
+ }
+ return
+ }
+
+ if (get_config NO_JUNCTION){
+ $version = Select-CurrentVersion -App $app -Global:$global
+ } else {
+ $version = 'current'
+ }
+ $dir = versiondir $app $version $global
+ $json = install_info $app $version $global
+ if (!$json) {
+ error "Failed to unhold '$app'"
+ continue
+ }
+ $install = @{}
+ $json | Get-Member -MemberType Properties | ForEach-Object { $install.Add($_.Name, $json.($_.Name)) }
+ if (!$install.hold) {
+ info "'$app' is not held."
+ continue
+ }
+ $install.hold = $null
+ save_install_info $install $dir
+ success "$app is no longer held and can be updated again."
+}
+
+exit $exitcode
diff --git a/libexec/scoop-uninstall.ps1 b/libexec/scoop-uninstall.ps1
index a8bb504d7d..5bdd57e5d1 100644
--- a/libexec/scoop-uninstall.ps1
+++ b/libexec/scoop-uninstall.ps1
@@ -5,119 +5,138 @@
# Options:
# -g, --global Uninstall a globally installed app
# -p, --purge Remove all persistent data
-. "$psscriptroot\..\lib\core.ps1"
-. "$psscriptroot\..\lib\manifest.ps1"
-. "$psscriptroot\..\lib\help.ps1"
-. "$psscriptroot\..\lib\install.ps1"
-. "$psscriptroot\..\lib\shortcuts.ps1"
-. "$psscriptroot\..\lib\psmodules.ps1"
-. "$psscriptroot\..\lib\versions.ps1"
-. "$psscriptroot\..\lib\getopt.ps1"
-. "$psscriptroot\..\lib\config.ps1"
-
-reset_aliases
+
+. "$PSScriptRoot\..\lib\getopt.ps1"
+. "$PSScriptRoot\..\lib\manifest.ps1" # 'Get-Manifest' 'Select-CurrentVersion' (indirectly)
+. "$PSScriptRoot\..\lib\system.ps1"
+. "$PSScriptRoot\..\lib\install.ps1"
+. "$PSScriptRoot\..\lib\shortcuts.ps1"
+. "$PSScriptRoot\..\lib\psmodules.ps1"
+. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
# options
$opt, $apps, $err = getopt $args 'gp' 'global', 'purge'
-if($err) { "scoop uninstall: $err"; exit 1 }
+
+if ($err) {
+ error "scoop uninstall: $err"
+ exit 1
+}
+
$global = $opt.g -or $opt.global
$purge = $opt.p -or $opt.purge
-if(!$apps) { 'ERROR: missing'; my_usage; exit 1 }
+if (!$apps) {
+ error ' missing'
+ my_usage
+ exit 1
+}
-if($global -and !(is_admin)) {
- 'ERROR: You need admin rights to uninstall global apps.'; exit 1
+if ($global -and !(is_admin)) {
+ error 'You need admin rights to uninstall global apps.'
+ exit 1
}
-foreach($app in $apps) {
-
- if(!(installed $app $global)) {
- if($app -ne 'scoop') {
- if(installed $app (!$global)) {
- function wh($g) { if($g) { "globally" } else { "for your account" } }
- write-host "'$app' isn't installed $(wh $global), but it is installed $(wh (!$global))." -f darkred
- "Try uninstalling $(if($global) { 'without' } else { 'with' }) the --global (or -g) flag instead."
- exit 1
- } else {
- error "'$app' isn't installed."
- continue
- }
- }
- }
+if ($apps -eq 'scoop') {
+ & "$PSScriptRoot\..\bin\uninstall.ps1" $global $purge
+ exit
+}
- if($app -eq 'scoop') {
- & "$psscriptroot\..\bin\uninstall.ps1" $global; exit
- }
+$apps = Confirm-InstallationStatus $apps -Global:$global
+if (!$apps) { exit 0 }
- $version = current_version $app $global
- "Uninstalling '$app' ($version)."
+:app_loop foreach ($_ in $apps) {
+ ($app, $global) = $_
- $dir = versiondir $app $version $global
- $persist_dir = persistdir $app $global
+ $version = Select-CurrentVersion -AppName $app -Global:$global
+ $appDir = appdir $app $global
+ if ($version) {
+ Write-Host "Uninstalling '$app' ($version)."
- try {
- test-path $dir -ea stop | out-null
- } catch [unauthorizedaccessexception] {
- error "Access denied: $dir. You might need to restart."
- continue
- }
+ $dir = versiondir $app $version $global
+ $persist_dir = persistdir $app $global
+
+ $manifest = installed_manifest $app $version $global
+ $install = install_info $app $version $global
+ $architecture = $install.architecture
+
+ Invoke-HookScript -HookType 'pre_uninstall' -Manifest $manifest -Arch $architecture
+
+ #region Workaround for #2952
+ if (test_running_process $app $global) {
+ continue
+ }
+ #endregion Workaround for #2952
- $manifest = installed_manifest $app $version $global
- $install = install_info $app $version $global
- $architecture = $install.architecture
+ try {
+ Test-Path $dir -ErrorAction Stop | Out-Null
+ } catch [UnauthorizedAccessException] {
+ error "Access denied: $dir. You might need to restart."
+ continue
+ }
- run_uninstaller $manifest $architecture $dir
- rm_shims $manifest $global $architecture
- rm_startmenu_shortcuts $manifest $global $architecture
+ Invoke-Installer -Path $dir -Manifest $manifest -ProcessorArchitecture $architecture -Global $global -Uninstall
+ rm_shims $app $manifest $global $architecture
+ rm_startmenu_shortcuts $manifest $global $architecture
- # If a junction was used during install, that will have been used
- # as the reference directory. Otherwise it will just be the version
- # directory.
- $refdir = unlink_current $dir
+ # If a junction was used during install, that will have been used
+ # as the reference directory. Otherwise it will just be the version
+ # directory.
+ $refdir = unlink_current $dir
- uninstall_psmodule $manifest $refdir $global
+ uninstall_psmodule $manifest $refdir $global
- env_rm_path $manifest $refdir $global
- env_rm $manifest $global
+ env_rm_path $manifest $refdir $global $architecture
+ env_rm $manifest $global $architecture
- try {
- rm -r $dir -ea stop -force
- } catch {
- error "Couldn't remove '$(friendly_path $dir)'; it may be in use."
- continue
- }
+ try {
+ # unlink all potential old link before doing recursive Remove-Item
+ unlink_persist_data $manifest $dir
+ Remove-Item $dir -Recurse -Force -ErrorAction Stop
+ } catch {
+ if (Test-Path $dir) {
+ error "Couldn't remove '$(friendly_path $dir)'; it may be in use."
+ continue
+ }
+ }
+ Invoke-HookScript -HookType 'post_uninstall' -Manifest $manifest -Arch $architecture
+ }
# remove older versions
- $old = @(versions $app $global)
- foreach($oldver in $old) {
- write-host "Removing older version ($oldver)."
- $dir = versiondir $app $oldver $global
+ $oldVersions = @(Get-ChildItem $appDir -Name -Exclude 'current')
+ foreach ($version in $oldVersions) {
+ Write-Host "Removing older version ($version)."
+ $dir = versiondir $app $version $global
try {
- rm -r -force -ea stop $dir
+ # unlink all potential old link before doing recursive Remove-Item
+ unlink_persist_data $manifest $dir
+ Remove-Item $dir -Recurse -Force -ErrorAction Stop
} catch {
error "Couldn't remove '$(friendly_path $dir)'; it may be in use."
- continue
+ continue app_loop
}
}
-
- if(@(versions $app).length -eq 0) {
- $appdir = appdir $app $global
+ if (Test-Path ($currentDir = Join-Path $appDir 'current')) {
+ attrib $currentDir -R /L
+ Remove-Item $currentDir -ErrorAction Stop -Force
+ }
+ if (!(Get-ChildItem $appDir)) {
try {
# if last install failed, the directory seems to be locked and this
# will throw an error about the directory not existing
- rm -r $appdir -ea stop -force
+ Remove-Item $appdir -Recurse -Force -ErrorAction Stop
} catch {
- if((test-path $appdir)) { throw } # only throw if the dir still exists
+ if ((Test-Path $appdir)) { throw } # only throw if the dir still exists
}
}
# purge persistant data
if ($purge) {
+ Write-Host 'Removing persisted data.'
$persist_dir = persistdir $app $global
if (Test-Path $persist_dir) {
try {
- rm -r $persist_dir -ea stop -force
+ Remove-Item $persist_dir -Recurse -Force -ErrorAction Stop
} catch {
error "Couldn't remove '$(friendly_path $persist_dir)'; it may be in use."
continue
@@ -127,4 +146,5 @@ foreach($app in $apps) {
success "'$app' was uninstalled."
}
+
exit 0
diff --git a/libexec/scoop-update.ps1 b/libexec/scoop-update.ps1
index 51c1198a7e..9d41906eca 100644
--- a/libexec/scoop-update.ps1
+++ b/libexec/scoop-update.ps1
@@ -6,219 +6,463 @@
# You can use '*' in place of to update all apps.
#
# Options:
-# --global, -g Update a globally installed app
-# --force, -f Force update even when there isn't a newer version
-# --no-cache, -k Don't use the download cache
-# --independent, -i Don't install dependencies automatically
-# --quiet, -q Hide extraneous messages
-. "$psscriptroot\..\lib\core.ps1"
-. "$psscriptroot\..\lib\shortcuts.ps1"
-. "$psscriptroot\..\lib\psmodules.ps1"
-. "$psscriptroot\..\lib\decompress.ps1"
-. "$psscriptroot\..\lib\manifest.ps1"
-. "$psscriptroot\..\lib\buckets.ps1"
-. "$psscriptroot\..\lib\versions.ps1"
-. "$psscriptroot\..\lib\getopt.ps1"
-. "$psscriptroot\..\lib\depends.ps1"
-. "$psscriptroot\..\lib\config.ps1"
-. "$psscriptroot\..\lib\git.ps1"
-. "$psscriptroot\..\lib\install.ps1"
-
-reset_aliases
-
-$opt, $apps, $err = getopt $args 'gfkqi' 'global','force', 'no-cache', 'quiet', 'independent'
-if($err) { "scoop update: $err"; exit 1 }
+# -f, --force Force update even when there isn't a newer version
+# -g, --global Update a globally installed app
+# -i, --independent Don't install dependencies automatically
+# -k, --no-cache Don't use the download cache
+# -s, --skip-hash-check Skip hash validation (use with caution!)
+# -q, --quiet Hide extraneous messages
+# -a, --all Update all apps (alternative to '*')
+
+. "$PSScriptRoot\..\lib\getopt.ps1"
+. "$PSScriptRoot\..\lib\json.ps1" # 'save_install_info' in 'manifest.ps1' (indirectly)
+. "$PSScriptRoot\..\lib\system.ps1"
+. "$PSScriptRoot\..\lib\shortcuts.ps1"
+. "$PSScriptRoot\..\lib\psmodules.ps1"
+. "$PSScriptRoot\..\lib\decompress.ps1"
+. "$PSScriptRoot\..\lib\manifest.ps1"
+. "$PSScriptRoot\..\lib\versions.ps1"
+. "$PSScriptRoot\..\lib\depends.ps1"
+. "$PSScriptRoot\..\lib\install.ps1"
+. "$PSScriptRoot\..\lib\download.ps1"
+if (get_config USE_SQLITE_CACHE) {
+ . "$PSScriptRoot\..\lib\database.ps1"
+}
+
+$opt, $apps, $err = getopt $args 'gfiksqa' 'global', 'force', 'independent', 'no-cache', 'skip-hash-check', 'quiet', 'all'
+if ($err) { "scoop update: $err"; exit 1 }
$global = $opt.g -or $opt.global
$force = $opt.f -or $opt.force
+$check_hash = !($opt.s -or $opt.'skip-hash-check')
$use_cache = !($opt.k -or $opt.'no-cache')
$quiet = $opt.q -or $opt.quiet
$independent = $opt.i -or $opt.independent
+$all = $opt.a -or $opt.all
-function update_scoop() {
- # check for git
- $git = try { gcm git -ea stop } catch { $null }
- if(!$git) { abort "Scoop uses Git to update itself. Run 'scoop install git' and try again." }
+# load config
+$configRepo = get_config SCOOP_REPO
+if (!$configRepo) {
+ $configRepo = 'https://github.com/ScoopInstaller/Scoop'
+ set_config SCOOP_REPO $configRepo | Out-Null
+}
- "Updating Scoop..."
- $currentdir = fullpath $(versiondir 'scoop' 'current')
- if(!(test-path "$currentdir\.git")) {
- # load config
- $repo = $(scoop config SCOOP_REPO)
- if(!$repo) {
- $repo = "https://github.com/lukesampson/scoop"
- scoop config SCOOP_REPO "$repo"
- }
+# Find current update channel from config
+$configBranch = get_config SCOOP_BRANCH
+if (!$configBranch) {
+ $configBranch = 'master'
+ set_config SCOOP_BRANCH $configBranch | Out-Null
+}
- $branch = $(scoop config SCOOP_BRANCH)
- if(!$branch) {
- $branch = "master"
- scoop config SCOOP_BRANCH "$branch"
- }
+if (($PSVersionTable.PSVersion.Major) -lt 5) {
+ # check powershell version
+ Write-Output 'PowerShell 5 or later is required to run Scoop.'
+ 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 Sync-Scoop {
+ [CmdletBinding()]
+ Param (
+ [Switch]$Log
+ )
+ # Test if Scoop Core is hold
+ if (Test-ScoopCoreOnHold) {
+ return
+ }
- $newdir = fullpath $(versiondir 'scoop' 'new')
+ # check for git
+ if (!(Test-GitAvailable)) { abort "Scoop uses Git to update itself. Run 'scoop install git' and try again." }
+
+ Write-Host 'Updating Scoop...'
+ $currentdir = versiondir 'scoop' 'current'
+ if (!(Test-Path "$currentdir\.git")) {
+ $newdir = "$currentdir\..\new"
+ $olddir = "$currentdir\..\old"
# get git scoop
- git_clone -q $repo --branch $branch --single-branch "`"$newdir`""
+ Invoke-Git -ArgumentList @('clone', '-q', $configRepo, '--branch', $configBranch, '--single-branch', $newdir)
# check if scoop was successful downloaded
- if(!(test-path "$newdir")) {
- abort 'Scoop update failed.'
+ if (!(Test-Path "$newdir\bin\scoop.ps1")) {
+ Remove-Item $newdir -Force -Recurse
+ abort "Scoop download failed. If this appears several times, try removing SCOOP_REPO by 'scoop config rm SCOOP_REPO'"
+ } else {
+ # replace non-git scoop with the git version
+ try {
+ Rename-Item $currentdir 'old' -ErrorAction Stop
+ Rename-Item $newdir 'current' -ErrorAction Stop
+ } catch {
+ Write-Warning $_
+ abort "Scoop update failed. Folder in use. Please rename folders $currentdir to ``old`` and $newdir to ``current``."
+ }
+ }
+ } else {
+ if (Test-Path "$currentdir\..\old") {
+ Remove-Item "$currentdir\..\old" -Recurse -Force -ErrorAction SilentlyContinue
+ }
+
+ $previousCommit = Invoke-Git -Path $currentdir -ArgumentList @('rev-parse', 'HEAD')
+ $currentRepo = Invoke-Git -Path $currentdir -ArgumentList @('config', 'remote.origin.url')
+ $currentBranch = Invoke-Git -Path $currentdir -ArgumentList @('branch')
+
+ $isRepoChanged = !($currentRepo -match $configRepo)
+ $isBranchChanged = !($currentBranch -match "\*\s+$configBranch")
+
+ # Stash uncommitted changes
+ if (Invoke-Git -Path $currentdir -ArgumentList @('diff', 'HEAD', '--name-only')) {
+ if (get_config AUTOSTASH_ON_CONFLICT) {
+ warn 'Uncommitted changes detected. Stashing...'
+ Invoke-Git -Path $currentdir -ArgumentList @('stash', 'push', '-m', "WIP at $([System.DateTime]::Now.ToString('o'))", '-u', '-q')
+ } else {
+ warn 'Uncommitted changes detected. Update aborted.'
+ return
+ }
+ }
+
+ # Change remote url if the repo is changed
+ if ($isRepoChanged) {
+ Invoke-Git -Path $currentdir -ArgumentList @('config', 'remote.origin.url', $configRepo)
+ }
+
+ # Fetch and reset local repo if the repo or the branch is changed
+ if ($isRepoChanged -or $isBranchChanged) {
+ # Reset git fetch refs, so that it can fetch all branches (GH-3368)
+ Invoke-Git -Path $currentdir -ArgumentList @('config', 'remote.origin.fetch', '+refs/heads/*:refs/remotes/origin/*')
+ # fetch remote branch
+ Invoke-Git -Path $currentdir -ArgumentList @('fetch', '--force', 'origin', "refs/heads/$configBranch`:refs/remotes/origin/$configBranch", '-q')
+ # checkout and track the branch
+ Invoke-Git -Path $currentdir -ArgumentList @('checkout', '-B', $configBranch, '-t', "origin/$configBranch", '-q')
+ # reset branch HEAD
+ Invoke-Git -Path $currentdir -ArgumentList @('reset', '--hard', "origin/$configBranch", '-q')
+ } else {
+ Invoke-Git -Path $currentdir -ArgumentList @('pull', '-q')
}
- # replace non-git scoop with the git version
- rm -r -force $currentdir -ea stop
- mv $newdir $currentdir
- }
- else {
- pushd $currentdir
- git_pull -q
$res = $lastexitcode
- if($res -ne 0) {
+ if ($Log) {
+ Invoke-GitLog -Path $currentdir -CommitHash $previousCommit
+ }
+
+ if ($res -ne 0) {
abort 'Update failed.'
}
- popd
}
- ensure_scoop_in_path
shim "$currentdir\bin\scoop.ps1" $false
+}
- @(buckets) | % {
- "Updating '$_' bucket..."
- pushd (bucketdir $_)
- git_pull -q
- popd
+function Sync-Bucket {
+ Param (
+ [Switch]$Log
+ )
+ Write-Host 'Updating Buckets...'
+
+ if (!(Test-Path (Join-Path (Find-BucketDirectory 'main' -Root) '.git'))) {
+ info "Converting 'main' bucket to git repo..."
+ $status = rm_bucket 'main'
+ if ($status -ne 0) {
+ abort "Failed to remove local 'main' bucket."
+ }
+ $status = add_bucket 'main' (known_bucket_repo 'main')
+ if ($status -ne 0) {
+ abort "Failed to add remote 'main' bucket."
+ }
+ }
+
+
+ $buckets = Get-LocalBucket | ForEach-Object {
+ $path = Find-BucketDirectory $_ -Root
+ return @{
+ name = $_
+ valid = Test-Path (Join-Path $path '.git')
+ path = $path
+ }
+ }
+
+ $buckets | Where-Object { !$_.valid } | ForEach-Object { Write-Host "'$($_.name)' is not a git repository. Skipped." }
+
+ $updatedFiles = [System.Collections.ArrayList]::Synchronized([System.Collections.ArrayList]::new())
+ $removedFiles = [System.Collections.ArrayList]::Synchronized([System.Collections.ArrayList]::new())
+ if ($PSVersionTable.PSVersion.Major -ge 7) {
+ # Parallel parameter is available since PowerShell 7
+ $buckets | Where-Object { $_.valid } | ForEach-Object -ThrottleLimit 5 -Parallel {
+ . "$using:PSScriptRoot\..\lib\core.ps1"
+ . "$using:PSScriptRoot\..\lib\buckets.ps1"
+
+ $name = $_.name
+ $bucketLoc = $_.path
+ $innerBucketLoc = Find-BucketDirectory $name
+
+ $previousCommit = Invoke-Git -Path $bucketLoc -ArgumentList @('rev-parse', 'HEAD')
+ Invoke-Git -Path $bucketLoc -ArgumentList @('pull', '-q')
+ if ($using:Log) {
+ Invoke-GitLog -Path $bucketLoc -Name $name -CommitHash $previousCommit
+ }
+ if (get_config USE_SQLITE_CACHE) {
+ Invoke-Git -Path $bucketLoc -ArgumentList @('diff', '--name-status', $previousCommit) | ForEach-Object {
+ $status, $file = $_ -split '\s+', 2
+ $filePath = Join-Path $bucketLoc $file
+ if ($filePath -match "^$([regex]::Escape($innerBucketLoc)).*\.json$") {
+ switch ($status) {
+ { $_ -in 'A', 'M', 'R' } {
+ [void]($using:updatedFiles).Add($filePath)
+ }
+ 'D' {
+ [void]($using:removedFiles).Add([pscustomobject]@{
+ Name = ([System.IO.FileInfo]$file).BaseName
+ Bucket = $name
+ })
+ }
+ }
+ }
+ }
+ }
+ }
+ } else {
+ $buckets | Where-Object { $_.valid } | ForEach-Object {
+ $name = $_.name
+ $bucketLoc = $_.path
+ $innerBucketLoc = Find-BucketDirectory $name
+
+ $previousCommit = Invoke-Git -Path $bucketLoc -ArgumentList @('rev-parse', 'HEAD')
+ Invoke-Git -Path $bucketLoc -ArgumentList @('pull', '-q')
+ if ($Log) {
+ Invoke-GitLog -Path $bucketLoc -Name $name -CommitHash $previousCommit
+ }
+ if (get_config USE_SQLITE_CACHE) {
+ Invoke-Git -Path $bucketLoc -ArgumentList @('diff', '--name-status', $previousCommit) | ForEach-Object {
+ $status, $file = $_ -split '\s+', 2
+ $filePath = Join-Path $bucketLoc $file
+ if ($filePath -match "^$([regex]::Escape($innerBucketLoc)).*\.json$") {
+ switch ($status) {
+ { $_ -in 'A', 'M', 'R' } {
+ [void]($updatedFiles).Add($filePath)
+ }
+ 'D' {
+ [void]($removedFiles).Add([pscustomobject]@{
+ Name = ([System.IO.FileInfo]$file).BaseName
+ Bucket = $name
+ })
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if ((get_config USE_SQLITE_CACHE) -and ($updatedFiles.Count -gt 0 -or $removedFiles.Count -gt 0)) {
+ info 'Updating cache...'
+ Set-ScoopDB -Path $updatedFiles
+ $removedFiles | Remove-ScoopDBItem
}
- success 'Scoop was updated successfully!'
}
-function update($app, $global, $quiet = $false, $independent, $suggested) {
- $old_version = current_version $app $global
+function update($app, $global, $quiet = $false, $independent, $suggested, $use_cache = $true, $check_hash = $true) {
+ $old_version = Select-CurrentVersion -AppName $app -Global:$global
$old_manifest = installed_manifest $app $old_version $global
$install = install_info $app $old_version $global
- $check_hash = $true
# re-use architecture, bucket and url from first install
- $architecture = ensure_architecture $install.architecture
+ $architecture = Format-ArchitectureString $install.architecture
$bucket = $install.bucket
- $url = $install.url
-
- if(!$independent) {
- # check dependencies
- $deps = @(deps $app $architecture) | ? { !(installed $_) }
- $deps | % { install_app $_ $architecture $global $suggested }
+ if ($null -eq $bucket) {
+ $bucket = 'main'
}
+ $url = $install.url
- $version = latest_version $app $bucket $url
+ $manifest = manifest $app $bucket $url
+ $version = $manifest.version
$is_nightly = $version -eq 'nightly'
- if($is_nightly) {
- $version = nightly_version $(get-date) $quiet
+ if ($is_nightly) {
+ $version = nightly_version $quiet
$check_hash = $false
}
- if(!$force -and ($old_version -eq $version)) {
+ if (!$force -and ($old_version -eq $version)) {
if (!$quiet) {
warn "The latest version of '$app' ($version) is already installed."
- "Run 'scoop update' to check for new versions."
}
return
}
- if(!$version) { abort "No manifest available for '$app'." } # installed from a custom bucket/no longer supported
+ if (!$version) {
+ # installed from a custom bucket/no longer supported
+ error "No manifest available for '$app'."
+ return
+ }
- $manifest = manifest $app $bucket $url
+ Write-Host "Updating '$app' ($old_version -> $version)"
- "Updating '$app' ($old_version -> $version)"
+ #region Workaround for #2952
+ if (test_running_process $app $global) {
+ Write-Host 'Running process detected, skip updating.'
+ return
+ }
+ #endregion Workaround for #2952
+
+ # region Workaround
+ # Workaround for https://github.com/ScoopInstaller/Scoop/issues/2220 until install is refactored
+ # Remove and replace whole region after proper fix
+ Write-Host 'Downloading new version'
+ if (Test-Aria2Enabled) {
+ Invoke-CachedAria2Download $app $version $manifest $architecture $cachedir $manifest.cookie $true $check_hash
+ } else {
+ $urls = script:url $manifest $architecture
+
+ foreach ($url in $urls) {
+ Invoke-CachedDownload $app $version $url $null $manifest.cookie $true
+
+ if ($check_hash) {
+ $manifest_hash = hash_for_url $manifest $url $architecture
+ $source = cache_path $app $version $url
+ $ok, $err = check_hash $source $manifest_hash $(show_app $app $bucket)
+
+ if (!$ok) {
+ error $err
+ if (Test-Path $source) {
+ # rm cached file
+ Remove-Item -Force $source
+ }
+ if ($url.Contains('sourceforge.net')) {
+ Write-Host -f yellow 'SourceForge.net is known for causing hash validation fails. Please try again before opening a ticket.'
+ }
+ abort $(new_issue_msg $app $bucket 'hash check failed')
+ }
+ }
+ }
+ }
+ # There is no need to check hash again while installing
+ $check_hash = $false
+ # endregion Workaround
$dir = versiondir $app $old_version $global
+ $persist_dir = persistdir $app $global
- "Uninstalling '$app' ($old_version)"
- run_uninstaller $old_manifest $architecture $dir
- rm_shims $old_manifest $global $architecture
- env_rm_path $old_manifest $dir $global
- env_rm $old_manifest $global
+ Invoke-HookScript -HookType 'pre_uninstall' -Manifest $old_manifest -Arch $architecture
+
+ Write-Host "Uninstalling '$app' ($old_version)"
+ Invoke-Installer -Path $dir -Manifest $old_manifest -ProcessorArchitecture $architecture -Uninstall
+ rm_shims $app $old_manifest $global $architecture
# If a junction was used during install, that will have been used
# as the reference directory. Otherwise it will just be the version
# directory.
$refdir = unlink_current $dir
+ uninstall_psmodule $old_manifest $refdir $global
+ env_rm_path $old_manifest $refdir $global $architecture
+ env_rm $old_manifest $global $architecture
- # note: keep the old dir in case it contains user files
-
- install_app $app $architecture $global $suggested
-<#
- "Installing '$app' ($version)"
- $dir = ensure (versiondir $app $version $global)
-
- # save info for uninstall
- save_installed_manifest $app $bucket $dir $url
- save_install_info @{ 'architecture' = $architecture; 'url' = $url; 'bucket' = $bucket } $dir
-
- if($manifest.suggest) {
- $suggested[$app] = $manifest.suggest
+ if ($force -and ($old_version -eq $version)) {
+ if (!(Test-Path "$dir/../_$version.old")) {
+ Move-Item "$dir" "$dir/../_$version.old"
+ } else {
+ $i = 1
+ While (Test-Path "$dir/../_$version.old($i)") {
+ $i++
+ }
+ Move-Item "$dir" "$dir/../_$version.old($i)"
+ }
}
- $fname = dl_urls $app $version $manifest $architecture $dir $use_cache $check_hash
- unpack_inno $fname $manifest $dir
- pre_install $manifest $architecture
- run_installer $fname $manifest $architecture $dir $global
- ensure_install_dir_not_in_path $dir
- $dir = link_current $dir
- create_shims $manifest $dir $global $architecture
- env_add_path $manifest $dir $global
- env_set $manifest $dir $global
- post_install $manifest $architecture
+ Invoke-HookScript -HookType 'post_uninstall' -Manifest $old_manifest -Arch $architecture
- success "'$app' was updated from $old_version to $version."
-
- show_notes $manifest
-#>
-}
-
-function ensure_all_installed($apps, $global) {
- $app = $apps | ? { !(installed $_ $global) } | select -first 1 # just get the first one that's not installed
- if($app) {
- if(installed $app (!$global)) {
- function wh($g) { if($g) { "globally" } else { "for your account" } }
- write-host "'$app' isn't installed $(wh $global), but it is installed $(wh (!$global))." -f darkred
- "Try updating $(if($global) { 'without' } else { 'with' }) the --global (or -g) flag instead."
- exit 1
- } else {
- abort "'$app' isn't installed."
- }
+ if ($bucket) {
+ # add bucket name it was installed from
+ $app = "$bucket/$app"
+ }
+ if ($install.url) {
+ # use the url of the install json if the application was installed through url
+ $app = $install.url
}
-}
-# convert list of apps to list of ($app, $global) tuples
-function applist($apps, $global) {
- return ,@($apps |% { ,@($_, $global) })
+ if ($independent) {
+ install_app $app $architecture $global $suggested $use_cache $check_hash
+ } else {
+ # Also add missing dependencies
+ $apps = @(Get-Dependency $app $architecture) -ne $app
+ ensure_none_failed $apps
+ $apps.Where({ !(installed $_) }) + $app | ForEach-Object { install_app $_ $architecture $global $suggested $use_cache $check_hash }
+ }
}
-if(!$apps) {
- if($global) {
- "scoop update: --global is invalid when is not specified."; exit 1
+if (-not ($apps -or $all)) {
+ if ($global) {
+ error 'scoop update: --global is invalid when is not specified.'
+ exit 1
}
if (!$use_cache) {
- "scoop update: --no-cache is invalid when is not specified."; exit 1
+ error 'scoop update: --no-cache is invalid when is not specified.'
+ exit 1
}
- update_scoop
+ Sync-Scoop -Log:$show_update_log
+ Sync-Bucket -Log:$show_update_log
+ set_config LAST_UPDATE ([System.DateTime]::Now.ToString('o')) | Out-Null
+ success 'Scoop was updated successfully!'
} else {
- if($global -and !(is_admin)) {
+ if ($global -and !(is_admin)) {
'ERROR: You need admin rights to update global apps.'; exit 1
}
- if($apps -eq '*') {
+ $outdated = @()
+ $updateScoop = $null -ne ($apps | Where-Object { $_ -eq 'scoop' }) -or (is_scoop_outdated)
+ $apps = $apps | Where-Object { $_ -ne 'scoop' }
+ $apps_param = $apps
+
+ if ($updateScoop) {
+ Sync-Scoop -Log:$show_update_log
+ Sync-Bucket -Log:$show_update_log
+ set_config LAST_UPDATE ([System.DateTime]::Now.ToString('o')) | Out-Null
+ success 'Scoop was updated successfully!'
+ }
+
+ if ($apps_param -eq '*' -or $all) {
$apps = applist (installed_apps $false) $false
- if($global) {
+ if ($global) {
$apps += applist (installed_apps $true) $true
}
} else {
- ensure_all_installed $apps $global
- $apps = applist $apps $global
+ if ($apps_param) {
+ $apps = Confirm-InstallationStatus $apps_param -Global:$global
+ }
}
+ if ($apps) {
+ $apps | ForEach-Object {
+ ($app, $global) = $_
+ $status = app_status $app $global
+ if ($status.installed -and ($force -or $status.outdated)) {
+ if (!$status.hold) {
+ $outdated += applist $app $global
+ Write-Host -f yellow ("$app`: $($status.version) -> $($status.latest_version){0}" -f ('', ' (global)')[$global])
+ } else {
+ warn "'$app' is held to version $($status.version)"
+ }
+ } elseif ($apps_param -ne '*' -and !$all) {
+ if ($status.installed) {
+ ensure_none_failed $app
+ Write-Host "$app`: $($status.version) (latest version)" -ForegroundColor Green
+ } else {
+ info 'Please reinstall it or fix the manifest.'
+ }
+ }
+ }
- $suggested = @{};
+ if ($outdated -and ((Test-Aria2Enabled) -and (get_config 'aria2-warning-enabled' $true))) {
+ warn "Scoop uses 'aria2c' for multi-connection downloads."
+ warn "Should it cause issues, run 'scoop config aria2-enabled false' to disable it."
+ warn "To disable this warning, run 'scoop config aria2-warning-enabled false'."
+ }
+ if ($outdated.Length -gt 1) {
+ Write-Host -f DarkCyan "Updating $($outdated.Length) outdated apps:"
+ } elseif ($outdated.Length -eq 0) {
+ Write-Host -f Green "Latest versions for all apps are installed! For more information try 'scoop status'"
+ } else {
+ Write-Host -f DarkCyan 'Updating one outdated app:'
+ }
+ }
- # $apps is now a list of ($app, $global) tuples
- $apps | % { update @_ $quiet $independent $suggested }
+ $suggested = @{}
+ # $outdated is a list of ($app, $global) tuples
+ $outdated | ForEach-Object { update @_ $quiet $independent $suggested $use_cache $check_hash }
}
exit 0
diff --git a/libexec/scoop-virustotal.ps1 b/libexec/scoop-virustotal.ps1
new file mode 100644
index 0000000000..8fe63359cf
--- /dev/null
+++ b/libexec/scoop-virustotal.ps1
@@ -0,0 +1,385 @@
+# Usage: scoop virustotal [* | app1 app2 ...] [options]
+# 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 '*' 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:
+#
+# scoop config virustotal_api_key
+#
+# Exit codes:
+# 0 -> success
+# 1 -> problem parsing arguments
+# 2 -> at least one package was marked unsafe by VirusTotal
+# 4 -> at least one exception was raised while looking for info
+# 8 -> at least one package couldn't be queried because the manifest couldn't be found
+# 16 -> VirusTotal API key is not configured
+# Note: the exit codes (2, 4 & 8) may be combined, e.g. 6 -> exit codes
+# 2 & 4 combined
+#
+# Options:
+# -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.
+# -n, --no-depends By default, all dependencies are checked too. This flag avoids it.
+# -u, --no-update-scoop Don't update Scoop before checking if it's outdated
+# -p, --passthru Return reports as objects
+
+. "$PSScriptRoot\..\lib\getopt.ps1"
+. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
+. "$PSScriptRoot\..\lib\manifest.ps1" # 'Get-Manifest'
+. "$PSScriptRoot\..\lib\json.ps1" # 'json_path'
+. "$PSScriptRoot\..\lib\download.ps1" # 'hash_for_url'
+. "$PSScriptRoot\..\lib\depends.ps1" # 'Get-Dependency'
+
+$opt, $apps, $err = getopt $args 'asnup' @('all', 'scan', 'no-depends', 'no-update-scoop', 'passthru')
+if ($err) { "scoop virustotal: $err"; exit 1 }
+$all = $apps -eq '*' -or $opt.a -or $opt.all
+if (!$apps -and !$all) { my_usage; exit 1 }
+$architecture = Get-DefaultArchitecture
+
+if (is_scoop_outdated) {
+ if ($opt.u -or $opt.'no-update-scoop') {
+ warn 'Scoop is out of date.'
+ } else {
+ & "$PSScriptRoot\scoop-update.ps1"
+ }
+}
+
+if ($all) {
+ $apps = (installed_apps $false) + (installed_apps $true)
+}
+
+if (!$opt.n -and !$opt.'no-depends') {
+ $apps = $apps | Get-Dependency -Architecture $architecture | Select-Object -Unique
+}
+
+$_ERR_UNSAFE = 2
+$_ERR_EXCEPTION = 4
+$_ERR_NO_INFO = 8
+$_ERR_NO_API_KEY = 16
+
+$exit_code = 0
+
+# Global 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" +
+ " scoop config virustotal_api_key ") $_ERR_NO_API_KEY
+}
+
+# Global flag to explain only once about sleep between requests
+$explained_rate_limit_sleeping = $False
+
+# Requests counter to slow down requests submitted to VirusTotal as
+# script execution progresses
+$requests = 0
+
+Function ConvertTo-VirusTotalUrlId ($url) {
+ $url_id = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($url))
+ $url_id = $url_id -replace '\+', '-'
+ $url_id = $url_id -replace '/', '_'
+ $url_id = $url_id -replace '=', ''
+ $url_id
+}
+
+Function Get-VirusTotalResultByHash ($hash, $url, $app) {
+ $hash = $hash.ToLower()
+ $api_url = "https://www.virustotal.com/api/v3/files/$hash"
+ $headers = @{}
+ $headers.Add('Accept', 'application/json')
+ $headers.Add('x-apikey', $api_key)
+ $response = Invoke-WebRequest -Uri $api_url -Method GET -Headers $headers -UseBasicParsing
+ $result = $response.Content
+ $stats = json_path $result '$.data.attributes.last_analysis_stats'
+ [int]$malicious = json_path $stats '$.malicious'
+ [int]$suspicious = json_path $stats '$.suspicious'
+ [int]$timeout = json_path $stats '$.timeout'
+ [int]$undetected = json_path $stats '$.undetected'
+ [int]$unsafe = $malicious + $suspicious
+ [int]$total = $unsafe + $undetected
+ [int]$fileSize = json_path $result '$.data.attributes.size'
+ $report_hash = json_path $result '$.data.attributes.sha256'
+ $report_url = "https://www.virustotal.com/gui/file/$report_hash"
+ if ($total -eq 0) {
+ info "$app`: Analysis in progress."
+ [PSCustomObject] @{
+ 'App.Name' = $app
+ 'App.Url' = $url
+ 'App.Hash' = $hash
+ 'App.HashType' = $null
+ 'App.Size' = filesize $fileSize
+ 'FileReport.Url' = $report_url
+ 'FileReport.Hash' = $report_hash
+ 'UrlReport.Url' = $null
+ }
+ } else {
+ $vendorResults = (ConvertFrom-Json((json_path $result '$.data.attributes.last_analysis_results'))).PSObject.Properties.Value
+ switch ($unsafe) {
+ 0 {
+ success "$app`: $unsafe/$total, see $report_url"
+ }
+ 1 {
+ warn "$app`: $unsafe/$total, see $report_url"
+ }
+ 2 {
+ warn "$app`: $unsafe/$total, see $report_url"
+ }
+ Default {
+ warn "$([char]0x1b)[31m$app`: $unsafe/$total, see $report_url$([char]0x1b)[0m"
+ }
+ }
+ $maliciousResults = $vendorResults |
+ Where-Object -Property category -EQ 'malicious' |
+ Select-Object -ExpandProperty engine_name
+ $suspiciousResults = $vendorResults |
+ Where-Object -Property category -EQ 'suspicious' |
+ Select-Object -ExpandProperty engine_name
+ [PSCustomObject] @{
+ 'App.Name' = $app
+ 'App.Url' = $url
+ 'App.Hash' = $hash
+ 'App.HashType' = $null
+ 'App.Size' = filesize $fileSize
+ 'FileReport.Url' = $report_url
+ 'FileReport.Hash' = $report_hash
+ 'FileReport.Malicious' = if ($maliciousResults) { $maliciousResults } else { 0 }
+ 'FileReport.Suspicious' = if ($suspiciousResults) { $suspiciousResults } else { 0 }
+ 'FileReport.Timeout' = $timeout
+ 'FileReport.Undetected' = $undetected
+ 'UrlReport.Url' = $null
+ }
+ }
+ if ($unsafe -gt 0) {
+ $Script:exit_code = $exit_code -bor $_ERR_UNSAFE
+ }
+}
+
+Function Get-VirusTotalResultByUrl ($url, $app) {
+ $id = ConvertTo-VirusTotalUrlId $url
+ $api_url = "https://www.virustotal.com/api/v3/urls/$id"
+ $headers = @{}
+ $headers.Add('Accept', 'application/json')
+ $headers.Add('x-apikey', $api_key)
+ $response = Invoke-WebRequest -Uri $api_url -Method GET -Headers $headers -UseBasicParsing
+ $result = $response.Content
+ $id = json_path $result '$.data.id'
+ $hash = json_path $result '$.data.attributes.last_http_response_content_sha256' 6>$null
+ $last_analysis_date = json_path $result '$.data.attributes.last_analysis_date' 6>$null
+ $url_report_url = "https://www.virustotal.com/gui/url/$id"
+ info "$app`: Url report found."
+ if (!$hash) {
+ if (!$last_analysis_date) {
+ info "$app`: Analysis in progress."
+ } else {
+ info "$app`: Related file report not found."
+ warn "$app`: Manual file upload is required (instead of url submission)."
+ }
+ [PSCustomObject] @{
+ 'App.Name' = $app
+ 'App.Url' = $url
+ 'App.Hash' = $null
+ 'App.HashType' = $null
+ 'FileReport.Url' = $null
+ 'UrlReport.Url' = $url_report_url
+ 'UrlReport.Hash' = $null
+ }
+ } else {
+ info "$app`: Related file report found."
+ [PSCustomObject] @{
+ 'App.Name' = $app
+ 'App.Url' = $url
+ 'App.Hash' = $null
+ 'App.HashType' = $null
+ 'FileReport.Url' = $null
+ 'UrlReport.Url' = $url_report_url
+ 'UrlReport.Hash' = $hash
+ }
+ }
+}
+
+# Submit-ToVirusTotal
+# - $url: where file to check can be downloaded
+# - $app: Name of the application (used for reporting)
+# - $do_scan: [boolean flag] whether to actually submit to VirusTotal
+# This is a parameter instead of conditionnally calling
+# the function to consolidate the warning message
+# - $retrying: [boolean] Optional, for internal use to retry
+# submitting the file after a delay if the rate limit is
+# exceeded, without risking an infinite loop (as stack
+# overflow) if the submission keeps failing.
+Function Submit-ToVirusTotal ($url, $app, $do_scan, $retrying = $False) {
+ if (!$do_scan) {
+ warn "$app`: not found`: you can manually submit $url"
+ return
+ }
+
+ try {
+ $requests += 1
+
+ $encoded_url = [System.Web.HttpUtility]::UrlEncode($url)
+ $api_url = 'https://www.virustotal.com/api/v3/urls'
+ $content_type = 'application/x-www-form-urlencoded'
+ $headers = @{}
+ $headers.Add('Accept', 'application/json')
+ $headers.Add('x-apikey', $api_key)
+ $headers.Add('Content-Type', $content_type)
+ $body = "url=$encoded_url"
+ $result = Invoke-WebRequest -Uri $api_url -Method POST -Headers $headers -ContentType $content_type -Body $body -UseBasicParsing
+ if ($result.StatusCode -eq 200) {
+ $id = ((json_path $result '$.data.id') -split '-')[1]
+ $url_report_url = "https://www.virustotal.com/gui/url/$id"
+ $fileSize = Get-RemoteFileSize $url
+ if ($fileSize -gt 80000000) {
+ info "$app`: Remote file size: $(filesize $fileSize). Large files might require manual file upload instead of url submission."
+ }
+ info "$app`: Analysis in progress."
+ [PSCustomObject] @{
+ 'App.Name' = $app
+ 'App.Url' = $url
+ 'App.Size' = filesize $fileSize
+ 'FileReport.Url' = $null
+ 'UrlReport.Url' = $url_report_url
+ }
+ return
+ }
+
+ # EAFP: submission failed -> sleep, then retry
+ if (!$retrying) {
+ if (!$explained_rate_limit_sleeping) {
+ $explained_rate_limit_sleeping = $True
+ info "Sleeping 60+ seconds between requests due to VirusTotal's 4/min limit"
+ }
+ Start-Sleep -s (60 + $requests)
+ Submit-ToVirusTotal $url $app $do_scan $True
+ } else {
+ warn "$app`: VirusTotal submission of $url failed`:`n" +
+ "`tAPI returned $($result.StatusCode) after retrying"
+ }
+ } catch [Exception] {
+ warn "$app`: VirusTotal submission failed`: $($_.Exception.Message)"
+ return
+ }
+}
+
+$reports = $apps | ForEach-Object {
+ $app = $_
+ $null, $manifest, $bucket, $null = Get-Manifest $app
+ if (!$manifest) {
+ $exit_code = $exit_code -bor $_ERR_NO_INFO
+ warn "$app`: manifest not found"
+ return
+ }
+
+ [int]$index = 0
+ $urls = script:url $manifest $architecture
+ $urls | ForEach-Object {
+ $url = $_
+ $index++
+ if ($urls.GetType().IsArray) {
+ info "$app`: url $index"
+ }
+ $hash = hash_for_url $manifest $url $architecture
+
+ try {
+ $isHashUnsupported = $false
+ if ($hash -match '(?[^:]+):(?.*)') {
+ $algo = $matches.algo
+ $hash = $matches.hash
+ if ($matches.algo -inotin 'md5', 'sha1', 'sha256') {
+ $hash = $null
+ $isHashUnsupported = $true
+ warn "$app`: Unsupported hash $($matches.algo). Will search by url instead."
+ }
+ } elseif ($hash) {
+ $algo = 'sha256'
+ }
+ if ($hash) {
+ $file_report = Get-VirusTotalResultByHash $hash $url $app
+ $file_report.'App.HashType' = $algo
+ $file_report
+ return
+ } elseif (!$isHashUnsupported) {
+ warn "$app`: Hash not found. Will search by url instead."
+ }
+ } catch [Exception] {
+ $exit_code = $exit_code -bor $_ERR_EXCEPTION
+ if ($_.Exception.Response.StatusCode -eq 404) {
+ $file_report_not_found = $true
+ warn "$app`: File report not found. Will search by url instead."
+ } else {
+ if ($_.Exception.Response.StatusCode -in 204, 429) {
+ abort "$app`: VirusTotal request failed`: $($_.Exception.Message)" $exit_code
+ }
+ warn "$app`: VirusTotal request failed`: $($_.Exception.Message)"
+ return
+ }
+ }
+
+ try {
+ $url_report = Get-VirusTotalResultByUrl $url $app
+ $url_report.'App.Hash' = $hash
+ $url_report.'App.HashType' = $algo
+ if ($url_report.'UrlReport.Hash' -and ($file_report_not_found -eq $true) -and $hash) {
+ if ($algo -eq 'sha256') {
+ if ($url_report.'UrlReport.Hash' -eq $hash) {
+ warn "$app`: Manual file upload is required (instead of url submission) for $url"
+ } else {
+ error "$app`: Hash not matched for $url"
+ }
+ } else {
+ error "$app`: Hash not matched or manual file upload is required (instead of url submission) for $url"
+ }
+ $url_report
+ return
+ }
+ if (!$url_report.'UrlReport.Hash') {
+ $url_report
+ return
+ }
+ } catch [Exception] {
+ $exit_code = $exit_code -bor $_ERR_EXCEPTION
+ if ($_.Exception.Response.StatusCode -eq 404) {
+ warn "$app`: Url report not found. Will submit $url"
+ Submit-ToVirusTotal $url $app ($opt.scan -or $opt.s)
+ return
+ } else {
+ if ($_.Exception.Response.StatusCode -in 204, 429) {
+ abort "$app`: VirusTotal request failed`: $($_.Exception.Message)" $exit_code
+ }
+ warn "$app`: VirusTotal request failed`: $($_.Exception.Message)"
+ return
+ }
+ }
+
+ try {
+ $file_report = Get-VirusTotalResultByHash $url_report.'UrlReport.Hash' $url $app
+ $file_report.'App.Hash' = $hash
+ $file_report.'App.HashType' = $algo
+ $file_report.'UrlReport.Url' = $url_report.'UrlReport.Url'
+ $file_report
+ warn "$app`: Unable to check hash match for $url"
+ } catch [Exception] {
+ $exit_code = $exit_code -bor $_ERR_EXCEPTION
+ if ($_.Exception.Response.StatusCode -eq 404) {
+ warn "$app`: File report not found for unknown reason. Manual file upload is required (instead of url submission)."
+ $url_report
+ } else {
+ if ($_.Exception.Response.StatusCode -in 204, 429) {
+ abort "$app`: VirusTotal request failed`: $($_.Exception.Message)" $exit_code
+ }
+ warn "$app`: VirusTotal request failed`: $($_.Exception.Message)"
+ return
+ }
+ }
+ }
+}
+if ($opt.p -or $opt.'passthru') {
+ $reports
+}
+
+exit $exit_code
diff --git a/libexec/scoop-which.ps1 b/libexec/scoop-which.ps1
index c6a10eaaab..677b034376 100644
--- a/libexec/scoop-which.ps1
+++ b/libexec/scoop-which.ps1
@@ -1,38 +1,20 @@
# Usage: scoop which
-# Summary: Locate a program path
-# Help: Finds the path to a program that was installed with Scoop
+# Summary: Locate a shim/executable (similar to 'which' on Linux)
+# Help: Locate the path to a shim/executable that was installed with Scoop (similar to 'which' on Linux)
param($command)
-. "$psscriptroot\..\lib\core.ps1"
-. "$psscriptroot\..\lib\help.ps1"
-reset_aliases
-
-if(!$command) { 'ERROR: missing'; my_usage; exit 1 }
-
-try { $gcm = gcm "$command" -ea stop } catch { } #
-if(!$gcm) { [console]::error.writeline("'$command' not found"); exit 3 }
-
-$path = "$($gcm.path)"
-$usershims = "$(resolve-path $(shimdir $false))"
-$globalshims = fullpath (shimdir $true) # don't resolve: may not exist
-
-if($path.endswith(".ps1") -and ($path -like "$usershims*" -or $path -like "$globalshims*")) {
- $shimtext = gc $path
-
- $exepath = ($shimtext |? { $_.startswith('$path') }).split(' ') | select -Last 1 | iex
+if (!$command) {
+ error ' missing'
+ my_usage
+ exit 1
+}
- if(![system.io.path]::ispathrooted($exepath)) {
- # Expand relative path
- $exepath = resolve-path (join-path (split-path $path) $exepath)
- }
+$path = Get-CommandPath $command
- friendly_path $exepath
-} elseif($gcm.commandtype -eq 'Alias') {
- scoop which $gcm.resolvedcommandname
-} else {
- [console]::error.writeline("Not a scoop shim.")
- $path
+if ($null -eq $path) {
+ warn "'$command' not found, not a scoop shim, or a broken shim."
exit 2
+} else {
+ friendly_path $path
+ exit 0
}
-
-exit 0
diff --git a/schema.json b/schema.json
index 1fd2b651ba..6c24d4da20 100644
--- a/schema.json
+++ b/schema.json
@@ -1,12 +1,16 @@
{
"$id": "http://scoop.sh/draft/schema#",
- "$schema": "http://json-schema.org/draft-04/schema#",
+ "$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"definitions": {
"hashPattern": {
"pattern": "^([a-fA-F0-9]{64}|(sha1|sha256|sha512|md5):([a-fA-F0-9]{32}|[a-fA-F0-9]{40}|[a-fA-F0-9]{64}|[a-fA-F0-9]{128}))$",
"type": "string"
},
+ "jsonPathPattern": {
+ "pattern": "^\\$[.\\[].*$",
+ "type": "string"
+ },
"hash": {
"anyOf": [
{
@@ -26,11 +30,22 @@
"additionalProperties": false,
"properties": {
"find": {
+ "format": "regex",
+ "type": "string",
+ "description": "Same as 'regex'"
+ },
+ "regex": {
"format": "regex",
"type": "string"
},
"jp": {
- "pattern": "^\\$\\..*$",
+ "$ref": "#/definitions/jsonPathPattern",
+ "description": "Same as 'jsonpath'"
+ },
+ "jsonpath": {
+ "$ref": "#/definitions/jsonPathPattern"
+ },
+ "xpath": {
"type": "string"
},
"mode": {
@@ -38,7 +53,11 @@
"download",
"extract",
"json",
- "rdf"
+ "xpath",
+ "rdf",
+ "metalink",
+ "fosshub",
+ "sourceforge"
]
},
"type": {
@@ -69,6 +88,21 @@
},
"type": "object"
},
+ "hashExtractionOrArrayOfHashExtractions": {
+ "anyOf": [
+ {
+ "$ref": "#/definitions/hashExtraction"
+ },
+ {
+ "items": {
+ "$ref": "#/definitions/hashExtraction"
+ },
+ "minItems": 1,
+ "type": "array",
+ "uniqueItems": false
+ }
+ ]
+ },
"architecture": {
"additionalProperties": false,
"properties": {
@@ -78,6 +112,12 @@
"checkver": {
"$ref": "#/definitions/checkver"
},
+ "env_add_path": {
+ "$ref": "#/definitions/stringOrArrayOfStrings"
+ },
+ "env_set": {
+ "type": "object"
+ },
"extract_dir": {
"$ref": "#/definitions/stringOrArrayOfStrings"
},
@@ -87,18 +127,20 @@
"installer": {
"$ref": "#/definitions/installer"
},
- "msi": {
- "$ref": "#/definitions/stringOrArrayOfStrings",
- "description": "Deprecated"
- },
"post_install": {
"$ref": "#/definitions/stringOrArrayOfStrings"
},
+ "post_uninstall": {
+ "$ref": "#/definitions/stringOrArrayOfStrings"
+ },
"pre_install": {
"$ref": "#/definitions/stringOrArrayOfStrings"
},
+ "pre_uninstall": {
+ "$ref": "#/definitions/stringOrArrayOfStrings"
+ },
"shortcuts": {
- "$ref": "#/definitions/arrayOfArrayOfStrings"
+ "$ref": "#/definitions/shortcutsArray"
},
"uninstaller": {
"$ref": "#/definitions/uninstaller"
@@ -120,62 +162,122 @@
"minItems": 1,
"type": "array"
},
+ "shortcutsArray": {
+ "items": {
+ "items": {
+ "type": "string"
+ },
+ "minItems": 2,
+ "maxItems": 4,
+ "type": "array"
+ },
+ "minItems": 1,
+ "type": "array"
+ },
+ "autoupdateArch": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "bin": {
+ "$ref": "#/definitions/stringOrArrayOfStringsOrAnArrayOfArrayOfStrings"
+ },
+ "env_add_path": {
+ "$ref": "#/definitions/stringOrArrayOfStrings"
+ },
+ "env_set": {
+ "type": "object"
+ },
+ "extract_dir": {
+ "$ref": "#/definitions/stringOrArrayOfStrings"
+ },
+ "hash": {
+ "$ref": "#/definitions/hashExtractionOrArrayOfHashExtractions"
+ },
+ "installer": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "file": {
+ "type": "string"
+ }
+ }
+ },
+ "shortcuts": {
+ "$ref": "#/definitions/shortcutsArray"
+ },
+ "url": {
+ "$ref": "#/definitions/autoupdateUriOrArrayOfAutoupdateUris"
+ }
+ }
+ },
"autoupdate": {
+ "type": "object",
"additionalProperties": false,
"properties": {
"architecture": {
+ "type": "object",
"additionalProperties": false,
"properties": {
"32bit": {
- "additionalProperties": false,
- "properties": {
- "extract_dir": {
- "type": "string"
- },
- "url": {
- "format": "uri",
- "type": "string"
- },
- "hash": {
- "$ref": "#/definitions/hashExtraction"
- }
- },
- "type": "object"
+ "$ref": "#/definitions/autoupdateArch"
},
"64bit": {
- "additionalProperties": false,
- "properties": {
- "extract_dir": {
- "type": "string"
- },
- "url": {
- "format": "uri",
- "type": "string"
- },
- "hash": {
- "$ref": "#/definitions/hashExtraction"
- }
- },
- "type": "object"
+ "$ref": "#/definitions/autoupdateArch"
+ },
+ "arm64": {
+ "$ref": "#/definitions/autoupdateArch"
}
- },
+ }
+ },
+ "bin": {
+ "$ref": "#/definitions/stringOrArrayOfStringsOrAnArrayOfArrayOfStrings"
+ },
+ "env_add_path": {
+ "$ref": "#/definitions/stringOrArrayOfStrings"
+ },
+ "env_set": {
"type": "object"
},
"extract_dir": {
- "type": "string"
+ "$ref": "#/definitions/stringOrArrayOfStrings"
},
"hash": {
- "$ref": "#/definitions/hashExtraction"
+ "$ref": "#/definitions/hashExtractionOrArrayOfHashExtractions"
},
- "note": {
+ "installer": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "file": {
+ "type": "string"
+ }
+ }
+ },
+ "license": {
+ "$ref": "#/definitions/license"
+ },
+ "notes": {
"$ref": "#/definitions/stringOrArrayOfStrings"
},
+ "persist": {
+ "$ref": "#/definitions/stringOrArrayOfStringsOrAnArrayOfArrayOfStrings"
+ },
+ "psmodule": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "name": {
+ "type": "string"
+ }
+ }
+ },
+ "shortcuts": {
+ "$ref": "#/definitions/shortcutsArray"
+ },
"url": {
- "format": "uri",
- "type": "string"
+ "$ref": "#/definitions/autoupdateUriOrArrayOfAutoupdateUris"
}
- },
- "type": "object"
+ }
},
"checkver": {
"anyOf": [
@@ -191,6 +293,11 @@
"type": "string"
},
"re": {
+ "format": "regex",
+ "type": "string",
+ "description": "Same as 'regex'"
+ },
+ "regex": {
"format": "regex",
"type": "string"
},
@@ -199,8 +306,48 @@
"type": "string"
},
"jp": {
- "pattern": "^\\$\\..*$",
+ "$ref": "#/definitions/jsonPathPattern",
+ "description": "Same as 'jsonpath'"
+ },
+ "jsonpath": {
+ "$ref": "#/definitions/jsonPathPattern"
+ },
+ "xpath": {
+ "type": "string"
+ },
+ "reverse": {
+ "description": "Reverse the order of regex matches",
+ "type": "boolean"
+ },
+ "replace": {
+ "description": "Allows rearrange the regexp matches",
+ "type": "string"
+ },
+ "useragent": {
"type": "string"
+ },
+ "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"
@@ -220,8 +367,11 @@
"file": {
"type": "string"
},
+ "script": {
+ "$ref": "#/definitions/stringOrArrayOfStrings"
+ },
"keep": {
- "type": "string"
+ "type": "boolean"
}
},
"type": "object"
@@ -261,10 +411,22 @@
},
"file": {
"type": "string"
+ },
+ "script": {
+ "$ref": "#/definitions/stringOrArrayOfStrings"
}
},
- "required": [
- "file"
+ "oneOf": [
+ {
+ "required": [
+ "file"
+ ]
+ },
+ {
+ "required": [
+ "script"
+ ]
+ }
],
"type": "object"
},
@@ -290,12 +452,86 @@
"uniqueItems": true
}
]
+ },
+ "autoupdateUriOrArrayOfAutoupdateUris": {
+ "anyOf": [
+ {
+ "format": "uri",
+ "type": "string"
+ },
+ {
+ "items": {
+ "format": "uri",
+ "type": "string"
+ },
+ "minItems": 1,
+ "type": "array",
+ "uniqueItems": true
+ }
+ ]
+ },
+ "licenseIdentifiers": {
+ "type": "string",
+ "description": "License identifier based on SPDX License List https://spdx.org/licenses/",
+ "examples": [
+ "Apache-2.0",
+ "BSD-3-Clause",
+ "Freeware",
+ "GPL-2.0-only",
+ "GPL-2.0-or-later",
+ "GPL-3.0-only",
+ "GPL-3.0-or-later",
+ "ISC",
+ "LGPL-2.0-only",
+ "LGPL-2.0-or-later",
+ "LGPL-2.1-only",
+ "LGPL-2.1-or-later",
+ "LGPL-3.0-only",
+ "LGPL-3.0-or-later",
+ "MIT",
+ "MS-PL",
+ "Proprietary",
+ "Public Domain",
+ "Shareware",
+ "Unlicense"
+ ]
+ },
+ "license": {
+ "anyOf": [
+ {
+ "$ref": "#/definitions/licenseIdentifiers"
+ },
+ {
+ "additionalProperties": false,
+ "properties": {
+ "url": {
+ "format": "uri",
+ "type": "string"
+ },
+ "identifier": {
+ "$ref": "#/definitions/licenseIdentifiers"
+ }
+ },
+ "required": [
+ "identifier"
+ ],
+ "type": "object"
+ }
+ ]
}
},
"properties": {
+ "$schema": {
+ "type": "string",
+ "format": "uri"
+ },
"_comment": {
- "description": "Undocumented: only found in scoop/git* and 6 manifests in scoop-extras",
- "type": "string"
+ "description": "Deprecated. Use ## instead.",
+ "$ref": "#/definitions/stringOrArrayOfStrings"
+ },
+ "##": {
+ "description": "A comment.",
+ "$ref": "#/definitions/stringOrArrayOfStrings"
},
"architecture": {
"additionalProperties": false,
@@ -305,6 +541,9 @@
},
"64bit": {
"$ref": "#/definitions/architecture"
+ },
+ "arm64": {
+ "$ref": "#/definitions/architecture"
}
},
"type": "object"
@@ -322,14 +561,13 @@
"$ref": "#/definitions/checkver"
},
"cookie": {
- "description": "Undocumented: only found in scoop-extras/oraclejdk*",
+ "description": "Undocumented: Found at https://github.com/se35710/scoop-java/search?l=JSON&q=cookie",
"type": "object"
},
"depends": {
"$ref": "#/definitions/stringOrArrayOfStrings"
},
"description": {
- "description": "Undocumented: only found in scoop/gibo",
"type": "string"
},
"env_add_path": {
@@ -342,8 +580,7 @@
"$ref": "#/definitions/stringOrArrayOfStrings"
},
"extract_to": {
- "$ref": "#/definitions/stringOrArrayOfStrings",
- "description": "Undocumented: only found in scoop/ruby*"
+ "$ref": "#/definitions/stringOrArrayOfStrings"
},
"hash": {
"$ref": "#/definitions/hash"
@@ -353,18 +590,14 @@
"type": "string"
},
"innosetup": {
- "description": "Undocumented: only found in 6 manifests in scoop",
+ "description": "True if the installer InnoSetup based. Found in https://github.com/ScoopInstaller/Main/search?l=JSON&q=innosetup",
"type": "boolean"
},
"installer": {
"$ref": "#/definitions/installer"
},
"license": {
- "type": "string"
- },
- "msi": {
- "$ref": "#/definitions/stringOrArrayOfStrings",
- "description": "Deprecated"
+ "$ref": "#/definitions/license"
},
"notes": {
"$ref": "#/definitions/stringOrArrayOfStrings"
@@ -372,9 +605,15 @@
"post_install": {
"$ref": "#/definitions/stringOrArrayOfStrings"
},
+ "post_uninstall": {
+ "$ref": "#/definitions/stringOrArrayOfStrings"
+ },
"pre_install": {
"$ref": "#/definitions/stringOrArrayOfStrings"
},
+ "pre_uninstall": {
+ "$ref": "#/definitions/stringOrArrayOfStrings"
+ },
"psmodule": {
"additionalProperties": false,
"properties": {
@@ -385,7 +624,7 @@
"type": "object"
},
"shortcuts": {
- "$ref": "#/definitions/arrayOfArrayOfStrings"
+ "$ref": "#/definitions/shortcutsArray"
},
"suggest": {
"additionalProperties": false,
@@ -403,12 +642,42 @@
"$ref": "#/definitions/uriOrArrayOfUris"
},
"version": {
- "pattern": "^[\\w\\.\\-_]+$",
+ "pattern": "^[\\w\\.\\-+_]+$",
"type": "string"
}
},
+ "if": {
+ "properties": {
+ "architecture": {
+ "properties": {
+ "64bit": {
+ "properties": {
+ "url": false
+ }
+ },
+ "32bit": {
+ "properties": {
+ "url": false
+ }
+ },
+ "arm64": {
+ "properties": {
+ "url": false
+ }
+ }
+ }
+ }
+ }
+ },
+ "then": {
+ "required": [
+ "url"
+ ]
+ },
"required": [
- "version"
+ "version",
+ "homepage",
+ "license"
],
"title": "scoop app manifest schema",
"type": "object"
diff --git a/scoop.sublime-project b/scoop.sublime-project
deleted file mode 100644
index f41c68ec72..0000000000
--- a/scoop.sublime-project
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "folders":
- [
- {
- "path": ".",
- "file_exclude_patterns": [ "*.git*", "*.sublime-*"],
- "folder_exclude_patterns": [ "tmp" ]
- }
- ],
- "settings": {
- "default_line_ending": "windows",
- "tab_size": 4
- }
-}
diff --git a/supporting/formats/ScoopTypes.Format.ps1xml b/supporting/formats/ScoopTypes.Format.ps1xml
new file mode 100644
index 0000000000..ba423f9553
--- /dev/null
+++ b/supporting/formats/ScoopTypes.Format.ps1xml
@@ -0,0 +1,93 @@
+
+
+
+
+ ScoopAppsType
+
+ ScoopApps
+
+
+
+
+
+
+ Name
+
+
+ Version
+
+
+ Source
+
+
+ Updated
+ yyyy-MM-dd HH:mm:ss
+
+
+ Info
+
+
+
+
+
+
+
+ ScoopShimsType
+
+ ScoopShims
+
+
+
+
+
+
+ Name
+
+
+ Source
+
+
+ Alternatives
+
+
+ IsGlobal
+
+
+ IsHidden
+
+
+
+
+
+
+
+ ScoopStatusType
+
+ ScoopStatus
+
+
+
+
+
+
+ Name
+
+
+ Installed Version
+
+
+ Latest Version
+
+
+ Missing Dependencies
+
+
+ Info
+
+
+
+
+
+
+
+
diff --git a/supporting/shimexe/build.ps1 b/supporting/shimexe/build.ps1
deleted file mode 100644
index 07d2062b55..0000000000
--- a/supporting/shimexe/build.ps1
+++ /dev/null
@@ -1,5 +0,0 @@
-$fwdir = gci C:\Windows\Microsoft.NET\Framework\ -dir | sort -desc | select -first 1
-
-pushd $psscriptroot
-& "$($fwdir.fullname)\csc.exe" /nologo shim.cs
-popd
diff --git a/supporting/shimexe/shim.cs b/supporting/shimexe/shim.cs
deleted file mode 100644
index e2231c96f1..0000000000
--- a/supporting/shimexe/shim.cs
+++ /dev/null
@@ -1,149 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-using System.Runtime.InteropServices;
-
-namespace shim {
-
- class Program {
- [DllImport("kernel32.dll", SetLastError=true)]
- static extern bool CreateProcess(string lpApplicationName,
- string lpCommandLine, IntPtr lpProcessAttributes,
- IntPtr lpThreadAttributes, bool bInheritHandles,
- uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory,
- [In] ref STARTUPINFO lpStartupInfo,
- out PROCESS_INFORMATION lpProcessInformation);
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
- struct STARTUPINFO {
- public Int32 cb;
- public string lpReserved;
- public string lpDesktop;
- public string lpTitle;
- public Int32 dwX;
- public Int32 dwY;
- public Int32 dwXSize;
- public Int32 dwYSize;
- public Int32 dwXCountChars;
- public Int32 dwYCountChars;
- public Int32 dwFillAttribute;
- public Int32 dwFlags;
- public Int16 wShowWindow;
- public Int16 cbReserved2;
- public IntPtr lpReserved2;
- public IntPtr hStdInput;
- public IntPtr hStdOutput;
- public IntPtr hStdError;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- internal struct PROCESS_INFORMATION {
- public IntPtr hProcess;
- public IntPtr hThread;
- public int dwProcessId;
- public int dwThreadId;
- }
-
- [DllImport("kernel32.dll", SetLastError=true)]
- static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);
- const UInt32 INFINITE = 0xFFFFFFFF;
-
- [DllImport("kernel32.dll", SetLastError=true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- static extern bool CloseHandle(IntPtr hObject);
-
- [DllImport("kernel32.dll", SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- static extern bool GetExitCodeProcess(IntPtr hProcess, out uint lpExitCode);
-
- static int Main(string[] args) {
- var exe = Assembly.GetExecutingAssembly().Location;
- var dir = Path.GetDirectoryName(exe);
- var name = Path.GetFileNameWithoutExtension(exe);
-
- var configPath = Path.Combine(dir, name + ".shim");
- if(!File.Exists(configPath)) {
- Console.Error.WriteLine("Couldn't find " + Path.GetFileName(configPath) + " in " + dir);
- return 1;
- }
-
- var config = Config(configPath);
- var path = Get(config, "path");
- var add_args = Get(config, "args");
-
- var si = new STARTUPINFO();
- var pi = new PROCESS_INFORMATION();
-
- // create command line
- var cmd_args = add_args ?? "";
- var pass_args = GetArgs(Environment.CommandLine);
- if(!string.IsNullOrEmpty(pass_args)) {
- if(!string.IsNullOrEmpty(cmd_args)) cmd_args += " ";
- cmd_args += pass_args;
- }
- if(!string.IsNullOrEmpty(cmd_args)) cmd_args = " " + cmd_args;
- var cmd = "\"" + path + "\"" + cmd_args;
-
- if(!CreateProcess(null, cmd, IntPtr.Zero, IntPtr.Zero,
- bInheritHandles: true,
- dwCreationFlags: 0,
- lpEnvironment: IntPtr.Zero, // inherit parent
- lpCurrentDirectory: null, // inherit parent
- lpStartupInfo: ref si,
- lpProcessInformation: out pi)) {
-
- return Marshal.GetLastWin32Error();
- }
-
- WaitForSingleObject(pi.hProcess, INFINITE);
-
- uint exit_code = 0;
- GetExitCodeProcess(pi.hProcess, out exit_code);
-
- // Close process and thread handles.
- CloseHandle(pi.hProcess);
- CloseHandle(pi.hThread);
-
- return (int)exit_code;
- }
-
- // now uses GetArgs instead
- static string Serialize(string[] args) {
- return string.Join(" ", args.Select(a => a.Contains(' ') ? '"' + a + '"' : a));
- }
-
- // strips the program name from the command line, returns just the arguments
- static string GetArgs(string cmdLine) {
- if(cmdLine.StartsWith("\"")) {
- var endQuote = cmdLine.IndexOf("\" ", 1);
- if(endQuote < 0) return "";
- return cmdLine.Substring(endQuote + 1);
- }
- var space = cmdLine.IndexOf(' ');
- if(space < 0 || space == cmdLine.Length - 1) return "";
- return cmdLine.Substring(space + 1);
- }
-
- static string Get(Dictionary dic, string key) {
- string value = null;
- dic.TryGetValue(key, out value);
- return value;
- }
-
- static Dictionary Config(string path) {
- var config = new Dictionary(StringComparer.OrdinalIgnoreCase);
- foreach(var line in File.ReadAllLines(path)) {
- var m = Regex.Match(line, @"([^=]+)=(.*)");
- if(m.Success) {
- config[m.Groups[1].Value.Trim()] = m.Groups[2].Value.Trim();
- }
- }
- return config;
- }
- }
-}
diff --git a/supporting/shimexe/shim.exe b/supporting/shimexe/shim.exe
deleted file mode 100644
index fdbe7a3e47..0000000000
Binary files a/supporting/shimexe/shim.exe and /dev/null differ
diff --git a/supporting/shims/71/checksum.sha256 b/supporting/shims/71/checksum.sha256
new file mode 100644
index 0000000000..37a3bd1111
--- /dev/null
+++ b/supporting/shims/71/checksum.sha256
@@ -0,0 +1 @@
+70d4690b8ac3b3f715f537cdea6e07a39fda4bc0347bf6b958e4f3ff2f0e04d4 shim.exe
diff --git a/supporting/shims/71/checksum.sha512 b/supporting/shims/71/checksum.sha512
new file mode 100644
index 0000000000..116bcee6e8
--- /dev/null
+++ b/supporting/shims/71/checksum.sha512
@@ -0,0 +1 @@
+ecde07b32192846c4885cf4d2208eedc170765ea115ae49b81509fed0ce474e21064100bb2f3d815ee79f1c12463d32ef013d4182647eae71855cd18e4196176 shim.exe
diff --git a/supporting/shims/71/shim.exe b/supporting/shims/71/shim.exe
new file mode 100644
index 0000000000..a812637075
Binary files /dev/null and b/supporting/shims/71/shim.exe differ
diff --git a/supporting/shims/kiennq/checksum.sha256 b/supporting/shims/kiennq/checksum.sha256
new file mode 100644
index 0000000000..527e378ce5
--- /dev/null
+++ b/supporting/shims/kiennq/checksum.sha256
@@ -0,0 +1 @@
+140e3801d8adeda639a21b14e62b93a4c7d26b7a758421f43c82be59753be49b *shim.exe
diff --git a/supporting/shims/kiennq/checksum.sha512 b/supporting/shims/kiennq/checksum.sha512
new file mode 100644
index 0000000000..18d66978c3
--- /dev/null
+++ b/supporting/shims/kiennq/checksum.sha512
@@ -0,0 +1 @@
+59d9da9f9714003b915bcafbe1b41f53b121dde206ecc23984f62273e957766eece8d64ffc53011c328d3a2ad627aa0f4f7c39bbec8e7b64d0d2ee7b7e771423 *shim.exe
diff --git a/supporting/shims/kiennq/shim.exe b/supporting/shims/kiennq/shim.exe
new file mode 100644
index 0000000000..bb12009124
Binary files /dev/null and b/supporting/shims/kiennq/shim.exe differ
diff --git a/supporting/shims/kiennq/version.txt b/supporting/shims/kiennq/version.txt
new file mode 100644
index 0000000000..d95827c3d9
--- /dev/null
+++ b/supporting/shims/kiennq/version.txt
@@ -0,0 +1 @@
+v3.1.2
diff --git a/supporting/shims/scoopcs/checksum.sha256 b/supporting/shims/scoopcs/checksum.sha256
new file mode 100644
index 0000000000..71456d0529
--- /dev/null
+++ b/supporting/shims/scoopcs/checksum.sha256
@@ -0,0 +1 @@
+0116068768fc992fc536738396b33db3dafe6b0cf0e6f54f6d1aa8b0331f3cec *shim.exe
diff --git a/supporting/shims/scoopcs/checksum.sha512 b/supporting/shims/scoopcs/checksum.sha512
new file mode 100644
index 0000000000..56bcb421f2
--- /dev/null
+++ b/supporting/shims/scoopcs/checksum.sha512
@@ -0,0 +1 @@
+d734c528e9f20581ed3c7aa71a458f7dff7e2780fa0c319ccb9c813cd8dbf656bd7e550b81d2aa3ee8775bff9a4e507bc0b25f075697405adca0f47d37835848 *shim.exe
diff --git a/supporting/shims/scoopcs/shim.exe b/supporting/shims/scoopcs/shim.exe
new file mode 100644
index 0000000000..9df58e1de1
Binary files /dev/null and b/supporting/shims/scoopcs/shim.exe differ
diff --git a/supporting/shims/scoopcs/version.txt b/supporting/shims/scoopcs/version.txt
new file mode 100644
index 0000000000..9084fa2f71
--- /dev/null
+++ b/supporting/shims/scoopcs/version.txt
@@ -0,0 +1 @@
+1.1.0
diff --git a/supporting/validator/Newtonsoft.Json.Schema.dll b/supporting/validator/Newtonsoft.Json.Schema.dll
deleted file mode 100644
index 9d13bce43c..0000000000
Binary files a/supporting/validator/Newtonsoft.Json.Schema.dll and /dev/null differ
diff --git a/supporting/validator/Newtonsoft.Json.dll b/supporting/validator/Newtonsoft.Json.dll
deleted file mode 100644
index 20dae627a5..0000000000
Binary files a/supporting/validator/Newtonsoft.Json.dll and /dev/null differ
diff --git a/supporting/validator/Scoop.Validator.cs b/supporting/validator/Scoop.Validator.cs
index 2d75a0765c..e233dfcdfc 100644
--- a/supporting/validator/Scoop.Validator.cs
+++ b/supporting/validator/Scoop.Validator.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Schema;
@@ -83,6 +84,16 @@ public bool Validate(string file)
public bool Validate()
{
+ if (!this.SchemaFile.Exists)
+ {
+ Console.WriteLine("ERROR: Please provide schema.json!");
+ return false;
+ }
+ if (!this.ManifestFile.Exists)
+ {
+ Console.WriteLine("ERROR: Please provide manifest.json!");
+ return false;
+ }
this.Errors.Clear();
try
{
@@ -108,19 +119,44 @@ public bool Validate()
this.Manifest.IsValid(this.Schema, out validationErrors);
- if (validationErrors.Count > 0)
+ if (validationErrors.Count == 0)
{
- foreach (ValidationError error in validationErrors)
- {
- this.Errors.Add(String.Format("{0}{1}: {2}", (this.CI ? " [*] " : ""), this.ManifestFile.Name, error.Message));
- foreach (ValidationError childError in error.ChildErrors)
- {
- this.Errors.Add(String.Format((this.CI ? " [^] {0}{1}" : "{0}^ {1}"), new String(' ', this.ManifestFile.Name.Length + 2), childError.Message));
- }
- }
+ return true;
}
+ traverseErrors(validationErrors, this.CI ? 3 : 1);
return (this.Errors.Count == 0);
}
+
+ public void traverseErrors(IList errors, int level = 1) {
+ if(errors == null) {
+ return;
+ }
+ foreach (ValidationError error in errors)
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Insert(sb.Length, " ", level * 2);
+ sb.Insert(sb.Length, this.CI ? "[*] " : "- ");
+ sb.AppendFormat("Error: {0}\n", error.Message);
+
+ sb.Insert(sb.Length, " ", level * 2);
+ sb.Insert(sb.Length, this.CI ? " [^] " : " ");
+ sb.AppendFormat("Line: {0}:{1}:{2}\n", this.ManifestFile.FullName, error.LineNumber, error.LinePosition);
+
+ sb.Insert(sb.Length, " ", level * 2);
+ sb.Insert(sb.Length, this.CI ? " [^] " : " ");
+ sb.AppendFormat("Path: {0}/{1}", error.SchemaId, error.ErrorType);
+
+ if(!this.CI) {
+ sb.Insert(sb.Length, "\n");
+ }
+
+ this.Errors.Add(sb.ToString());
+
+ if(error.ChildErrors != null || error.ChildErrors.Count > 0) {
+ traverseErrors(error.ChildErrors, level + 1);
+ }
+ }
+ }
}
}
diff --git a/supporting/validator/Scoop.Validator.dll b/supporting/validator/Scoop.Validator.dll
deleted file mode 100644
index be1576328d..0000000000
Binary files a/supporting/validator/Scoop.Validator.dll and /dev/null differ
diff --git a/supporting/validator/bin/Newtonsoft.Json.Schema.dll b/supporting/validator/bin/Newtonsoft.Json.Schema.dll
new file mode 100644
index 0000000000..766b9a1871
Binary files /dev/null and b/supporting/validator/bin/Newtonsoft.Json.Schema.dll differ
diff --git a/supporting/validator/bin/Newtonsoft.Json.dll b/supporting/validator/bin/Newtonsoft.Json.dll
new file mode 100644
index 0000000000..341d08fc8b
Binary files /dev/null and b/supporting/validator/bin/Newtonsoft.Json.dll differ
diff --git a/supporting/validator/bin/Scoop.Validator.dll b/supporting/validator/bin/Scoop.Validator.dll
new file mode 100644
index 0000000000..ccf13bb0ff
Binary files /dev/null and b/supporting/validator/bin/Scoop.Validator.dll differ
diff --git a/supporting/validator/bin/checksum.sha256 b/supporting/validator/bin/checksum.sha256
new file mode 100644
index 0000000000..c7db79ce23
--- /dev/null
+++ b/supporting/validator/bin/checksum.sha256
@@ -0,0 +1,4 @@
+e1e27af7b07eeedf5ce71a9255f0422816a6fc5849a483c6714e1b472044fa9d *Newtonsoft.Json.dll
+7496d5349a123a6e3696085662b2ff17b156ccdb0e30e0c396ac72d2da36ce1c *Newtonsoft.Json.Schema.dll
+83b1006443e8c340ca4c631614fc2ce0d5cb9a28c851e3b59724299f58b1397f *Scoop.Validator.dll
+87f8f8db2202a3fbef6f431d0b7e20cec9d32095c441927402041f3c4076c1b6 *validator.exe
diff --git a/supporting/validator/bin/checksum.sha512 b/supporting/validator/bin/checksum.sha512
new file mode 100644
index 0000000000..c145b03a06
--- /dev/null
+++ b/supporting/validator/bin/checksum.sha512
@@ -0,0 +1,4 @@
+56eb7f070929b239642dab729537dde2c2287bdb852ad9e80b5358c74b14bc2b2dded910d0e3b6304ea27eb587e5f19db0a92e1cbae6a70fb20b4ef05057e4ac *Newtonsoft.Json.dll
+78b12beb1e67ac4f6efa0fcba57b4b34ea6a31d8b369934d6b6a6617386ef9939ea453ac262916e5857ce0359eb809424ea33c676a87a8fdfd77a59b2ce96db0 *Newtonsoft.Json.Schema.dll
+e9da4370aee4df47eedcf15d9749712eee513e5a9115b808617ddfcfde5bc47a0410edfb57508fcf51033c0be967611b2fd2c2ba944de7290c020cc67f77ac57 *Scoop.Validator.dll
+58a0c37e98cac17822c7756bf6686a5fb74e711b8d986d13bd2f689f6b3b1f485fcd908d92cbc6a162a0e5974c2c5a43de57d15f1996be0aa405e41ec2ec8393 *validator.exe
diff --git a/supporting/validator/bin/validator.exe b/supporting/validator/bin/validator.exe
new file mode 100644
index 0000000000..7671654a59
Binary files /dev/null and b/supporting/validator/bin/validator.exe differ
diff --git a/supporting/validator/build.ps1 b/supporting/validator/build.ps1
index 26e0161cba..d5aaa89046 100644
--- a/supporting/validator/build.ps1
+++ b/supporting/validator/build.ps1
@@ -1,8 +1,27 @@
-$fwdir = gci C:\Windows\Microsoft.NET\Framework\ -dir | sort -desc | select -first 1
+Param([Switch]$Fast)
+Push-Location $PSScriptRoot
+. "$PSScriptRoot\..\..\lib\core.ps1"
+. "$PSScriptRoot\..\..\lib\install.ps1"
-pushd $psscriptroot
-& nuget restore -solutiondirectory .
-gci $psscriptroot\packages\Newtonsoft.*\lib\net40\*.dll -file | % { copy-item $_ $psscriptroot }
-& "$($fwdir.fullname)\csc.exe" /platform:anycpu /nologo /optimize /target:library /reference:Newtonsoft.Json.dll,Newtonsoft.Json.Schema.dll Scoop.Validator.cs
-& "$($fwdir.fullname)\csc.exe" /platform:anycpu /nologo /optimize /target:exe /reference:Scoop.Validator.dll,Newtonsoft.Json.dll,Newtonsoft.Json.Schema.dll validator.cs
-popd
+if (!$Fast) {
+ Write-Host 'Install dependencies ...'
+ & "$PSScriptRoot\install.ps1"
+}
+
+$output = "$PSScriptRoot\bin"
+if (!$Fast) {
+ Get-ChildItem "$PSScriptRoot\packages\Newtonsoft.*\lib\net45\*.dll" -File | ForEach-Object { Copy-Item $_ $output }
+}
+Write-Output 'Compiling Scoop.Validator.cs ...'
+& "$PSScriptRoot\packages\Microsoft.Net.Compilers.Toolset\tasks\net472\csc.exe" -deterministic -platform:anycpu -nologo -optimize -target:library -reference:"$output\Newtonsoft.Json.dll" -reference:"$output\Newtonsoft.Json.Schema.dll" -out:"$output\Scoop.Validator.dll" Scoop.Validator.cs
+Write-Output 'Compiling validator.cs ...'
+& "$PSScriptRoot\packages\Microsoft.Net.Compilers.Toolset\tasks\net472\csc.exe" -deterministic -platform:anycpu -nologo -optimize -target:exe -reference:"$output\Scoop.Validator.dll" -reference:"$output\Newtonsoft.Json.dll" -reference:"$output\Newtonsoft.Json.Schema.dll" -out:"$output\validator.exe" validator.cs
+
+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 {
+ "$((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
diff --git a/supporting/validator/install.ps1 b/supporting/validator/install.ps1
new file mode 100644
index 0000000000..8c5ec99222
--- /dev/null
+++ b/supporting/validator/install.ps1
@@ -0,0 +1,8 @@
+# https://github.com/edymtt/nugetstandalone
+$destinationFolder = "$PSScriptRoot\packages"
+if ((Test-Path -Path $destinationFolder)) {
+ Remove-Item -Path $destinationFolder -Recurse | Out-Null
+}
+
+New-Item $destinationFolder -Type Directory | Out-Null
+nuget install packages.config -o $destinationFolder -ExcludeVersion
diff --git a/supporting/validator/packages.config b/supporting/validator/packages.config
index 729db5cb22..09c665d668 100644
--- a/supporting/validator/packages.config
+++ b/supporting/validator/packages.config
@@ -1,5 +1,7 @@
-
+
-
-
+
+
+
diff --git a/supporting/validator/update.ps1 b/supporting/validator/update.ps1
new file mode 100644
index 0000000000..80a59863bf
--- /dev/null
+++ b/supporting/validator/update.ps1
@@ -0,0 +1,10 @@
+# https://github.com/edymtt/nugetstandalone
+$destinationFolder = "$PSScriptRoot\packages"
+if (!(Test-Path -Path $destinationFolder)) {
+ Write-Host -f Red "Run .\install.ps1 first!"
+ exit 1
+}
+
+nuget update packages.config -r $destinationFolder
+Remove-Item $destinationFolder -Force -Recurse | Out-Null
+nuget install packages.config -o $destinationFolder -ExcludeVersion
diff --git a/supporting/validator/validator.cs b/supporting/validator/validator.cs
index 287d8f6d6c..4b0c735ce5 100644
--- a/supporting/validator/validator.cs
+++ b/supporting/validator/validator.cs
@@ -1,5 +1,8 @@
using System;
+using System.Collections;
+using System.Collections.Generic;
using System.IO;
+using System.Linq;
namespace Scoop
{
@@ -7,27 +10,54 @@ public class Program
{
public static int Main(string[] args)
{
- bool ci = (args.Length == 3 && args[2] == "-ci");
- bool valid = false;
+ bool ci = String.Format("{0}", Environment.GetEnvironmentVariable("CI")).ToLower() == "true";
+ bool valid = true;
if (args.Length < 2)
{
- Console.WriteLine("Usage: validator.exe schema.json manifest.json");
+ Console.WriteLine("Usage: validator.exe [...]");
return 1;
}
- Scoop.Validator validator = new Scoop.Validator(args[0], ci);
- valid = validator.Validate(args[1]);
- if (valid)
- {
- Console.WriteLine("Yay! {0} validates against the schema!", Path.GetFileName(args[1]));
+ IList manifests = args.ToList();
+ String schema = manifests.First();
+ manifests.RemoveAt(0);
+ String combinedArgs = String.Join("", manifests);
+ if(combinedArgs.Contains("*") || combinedArgs.Contains("?")) {
+ try {
+ var path = new Uri(Path.Combine(Directory.GetCurrentDirectory(), combinedArgs)).LocalPath;
+ var drive = Path.GetPathRoot(path);
+ var pattern = path.Replace(drive, "");
+ manifests = Directory.GetFiles(drive, pattern).ToList();
+ } catch (System.ArgumentException ex) {
+ Console.WriteLine("Invalid path provided! ({0})", ex.Message);
+ return 1;
+ }
}
- else
- {
- foreach (var error in validator.Errors)
+
+ Scoop.Validator validator = new Scoop.Validator(schema, ci);
+ foreach(var manifest in manifests) {
+ if (validator.Validate(manifest))
+ {
+ if(ci) {
+ Console.WriteLine(" [+] {0} validates against the schema!", Path.GetFileName(manifest));
+ } else {
+ Console.WriteLine("- {0} validates against the schema!", Path.GetFileName(manifest));
+ }
+ }
+ else
{
- Console.WriteLine(error);
+ if(ci) {
+ Console.WriteLine(" [-] {0} has {1} Error{2}!", Path.GetFileName(manifest), validator.Errors.Count, validator.Errors.Count > 1 ? "s" : "");
+ } else {
+ Console.WriteLine("- {0} has {1} Error{2}!", Path.GetFileName(manifest), validator.Errors.Count, validator.Errors.Count > 1 ? "s" : "");
+ }
+ valid = false;
+ foreach (var error in validator.Errors)
+ {
+ Console.WriteLine(error);
+ }
}
}
diff --git a/supporting/validator/validator.csproj b/supporting/validator/validator.csproj
new file mode 100644
index 0000000000..5d3dde0b8f
--- /dev/null
+++ b/supporting/validator/validator.csproj
@@ -0,0 +1,57 @@
+
+
+
+
+
+ Debug
+ AnyCPU
+ {8EB9B38A-1BAB-4D89-B4CB-ACE5E7C1073B}
+ Exe
+ Scoop.Validator
+ Scoop.Validator
+ v4.5.0
+ 512
+ true
+
+
+
+ packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll
+ True
+
+
+ packages\Newtonsoft.Json.Schema.4.0.1\lib\net45\Newtonsoft.Json.Schema.dll
+ True
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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}.
+
+
+
+
diff --git a/supporting/validator/validator.exe b/supporting/validator/validator.exe
deleted file mode 100644
index 13ffadfd0a..0000000000
Binary files a/supporting/validator/validator.exe and /dev/null differ
diff --git a/test/00-Project.Tests.ps1 b/test/00-Project.Tests.ps1
deleted file mode 100644
index 07ce170e2c..0000000000
--- a/test/00-Project.Tests.ps1
+++ /dev/null
@@ -1,211 +0,0 @@
-$repo_dir = (Get-Item $MyInvocation.MyCommand.Path).directory.parent.FullName
-
-$repo_files = @( Get-ChildItem $repo_dir -file -recurse -force )
-
-$project_file_exclusions = @(
- $([regex]::Escape($repo_dir)+'(\\|/).git(\\|/).*$'),
- '.sublime-workspace$',
- '.DS_Store$',
- 'supporting(\\|/)validator(\\|/)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")"
- }
- }
-
-}
-
-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)$' }
- )
-
- $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)
- {
- $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)
- {
- $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)
- {
- $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")"
- }
- }
-
-}
diff --git a/test/Import-Bucket-Tests.ps1 b/test/Import-Bucket-Tests.ps1
new file mode 100644
index 0000000000..96890a0a74
--- /dev/null
+++ b/test/Import-Bucket-Tests.ps1
@@ -0,0 +1,52 @@
+#Requires -Version 5.1
+#Requires -Modules @{ ModuleName = 'BuildHelpers'; ModuleVersion = '2.0.1' }
+#Requires -Modules @{ ModuleName = 'Pester'; ModuleVersion = '5.2.0' }
+param(
+ [String] $BucketPath = $MyInvocation.PSScriptRoot
+)
+
+. "$PSScriptRoot\Scoop-00File.Tests.ps1" -TestPath $BucketPath
+
+Describe 'Manifest validates against the schema' {
+ BeforeDiscovery {
+ $bucketDir = if (Test-Path "$BucketPath\bucket") {
+ "$BucketPath\bucket"
+ } else {
+ $BucketPath
+ }
+ if ($env:CI -eq $true) {
+ Set-BuildEnvironment -Force
+ $manifestFiles = @(Get-GitChangedFile -Path $bucketDir -Include '*.json' -Commit $env:BHCommitHash)
+ } else {
+ $manifestFiles = (Get-ChildItem $bucketDir -Filter '*.json' -Recurse).FullName
+ }
+ }
+ 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 $_
+ 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
+ }
+ }
+ }
+ }
+}
diff --git a/test/Scoop-00File.Tests.ps1 b/test/Scoop-00File.Tests.ps1
new file mode 100644
index 0000000000..4ce5c57ef0
--- /dev/null
+++ b/test/Scoop-00File.Tests.ps1
@@ -0,0 +1,188 @@
+param(
+ [String] $TestPath = "$PSScriptRoot\.."
+)
+
+BeforeDiscovery {
+ $project_file_exclusions = @(
+ '[\\/]\.git[\\/]',
+ '\.sublime-workspace$',
+ '\.DS_Store$',
+ 'supporting(\\|/)validator(\\|/)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")"
+ }
+ }
+
+}
diff --git a/test/Scoop-00Linting.Tests.ps1 b/test/Scoop-00Linting.Tests.ps1
new file mode 100644
index 0000000000..45fbf3611c
--- /dev/null
+++ b/test/Scoop-00Linting.Tests.ps1
@@ -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)"
+ }
+ }
+ }
+ }
+}
diff --git a/test/Scoop-Alias.Tests.ps1 b/test/Scoop-Alias.Tests.ps1
deleted file mode 100644
index e8ca8bcf0d..0000000000
--- a/test/Scoop-Alias.Tests.ps1
+++ /dev/null
@@ -1,55 +0,0 @@
-. "$psscriptroot\..\libexec\scoop-alias.ps1" | out-null
-
-reset_aliases
-
-describe "add_alias" {
- mock shimdir { "TestDrive:\shim" }
- mock set_config { }
- mock get_config { @{} }
-
- $shimdir = shimdir
- mkdir $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!"'
- iex $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
- $alias_file | should exist
-
- add_alias "rm" "test"
- $alias_file | should contain ""
- }
- }
-}
-
-describe "rm_alias" {
- mock shimdir { "TestDrive:\shim" }
- mock set_config { }
- mock get_config { @{} }
-
- $shimdir = shimdir
- mkdir $shimdir
-
- context "alias exists" {
- 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
- }
- }
-}
diff --git a/test/Scoop-Commands.Tests.ps1 b/test/Scoop-Commands.Tests.ps1
new file mode 100644
index 0000000000..05d5d1d153
--- /dev/null
+++ b/test/Scoop-Commands.Tests.ps1
@@ -0,0 +1,45 @@
+BeforeAll {
+ . "$PSScriptRoot\Scoop-TestLib.ps1"
+ . "$PSScriptRoot\..\lib\core.ps1"
+ . "$PSScriptRoot\..\lib\commands.ps1"
+}
+
+Describe 'Manipulate Alias' -Tag 'Scoop' {
+ BeforeAll {
+ Mock shimdir { "$TestDrive\shims" }
+ Mock set_config {}
+ Mock get_config { @{} }
+
+ $shimdir = shimdir
+ ensure $shimdir
+ }
+
+ It 'Creates a new alias if it does not exist' {
+ $alias_script = "$shimdir\scoop-rm.ps1"
+ $alias_script | Should -Not -Exist
+
+ add_alias 'rm' '"hello, world!"'
+ & $alias_script | Should -Be 'hello, world!'
+ }
+
+ It 'Skips an existing alias' {
+ $alias_script = "$shimdir\scoop-rm.ps1"
+ Mock abort {}
+ New-Item $alias_script -Type File -Force
+ $alias_script | Should -Exist
+
+ add_alias 'rm' '"test"'
+ Should -Invoke -CommandName abort -Times 1 -ParameterFilter { $msg -eq "File 'scoop-rm.ps1' already exists in shims directory." }
+ }
+
+ It 'Removes an existing alias' {
+ $alias_script = "$shimdir\scoop-rm.ps1"
+ $alias_script | Should -Exist
+ Mock get_config { @(@{'rm' = 'scoop-rm' }) }
+ Mock info {}
+
+ rm_alias 'rm'
+ $alias_script | Should -Not -Exist
+ Should -Invoke -CommandName info -Times 1 -ParameterFilter { $msg -eq "Removing alias 'rm'..." }
+ }
+}
diff --git a/test/Scoop-Config.Tests.ps1 b/test/Scoop-Config.Tests.ps1
index 967aaaddca..9826af82a2 100644
--- a/test/Scoop-Config.Tests.ps1
+++ b/test/Scoop-Config.Tests.ps1
@@ -1,17 +1,78 @@
-. "$psscriptroot\..\lib\core.ps1"
-. "$psscriptroot\..\lib\config.ps1"
+BeforeAll {
+ . "$PSScriptRoot\Scoop-TestLib.ps1"
+ . "$PSScriptRoot\..\lib\core.ps1"
+}
+
+Describe 'config' -Tag 'Scoop' {
+ BeforeAll {
+ $configFile = [IO.Path]::GetTempFileName()
+ $unicode = [Regex]::Unescape('\u4f60\u597d\u3053\u3093\u306b\u3061\u306f') # 你好こんにちは
+ }
+
+ AfterAll {
+ Remove-Item -Path $configFile -Force
+ }
+
+ It 'load_cfg should return null if config file does not exist' {
+ load_cfg $configFile | Should -Be $null
+ }
+
+ It 'set_config should be able to save typed values correctly' {
+ # number
+ $scoopConfig = set_config 'one' 1
+ $scoopConfig.one | Should -BeExactly 1
-describe "hashtable" {
- $json = '{ "one": 1, "two": [ { "a": "a" }, "b", 2 ], "three": { "four": 4 } }'
+ # boolean
+ $scoopConfig = set_config 'two' $true
+ $scoopConfig.two | Should -BeTrue
+ $scoopConfig = set_config 'three' $false
+ $scoopConfig.three | Should -BeFalse
- it "converts pscustomobject to hashtable" {
- $obj = convertfrom-json $json
- $ht = hashtable $obj
+ # underline key
+ $scoopConfig = set_config 'under_line' 'four'
+ $scoopConfig.under_line | Should -BeExactly 'four'
+
+ # string
+ $scoopConfig = set_config 'five' 'not null'
+
+ # datetime
+ $scoopConfig = set_config 'time' ([System.DateTime]::Parse('2019-03-18T15:22:09.3930000+00:00', $null, [System.Globalization.DateTimeStyles]::AdjustToUniversal))
+ $scoopConfig.time | Should -BeOfType [System.DateTime]
+
+ # non-ASCII
+ $scoopConfig = set_config 'unicode' $unicode
+ $scoopConfig.unicode | Should -Be $unicode
+ }
+
+ It 'load_cfg should return PSObject if config file exist' {
+ $scoopConfig = load_cfg $configFile
+ $scoopConfig | Should -Not -BeNullOrEmpty
+ $scoopConfig | Should -BeOfType [System.Management.Automation.PSObject]
+ $scoopConfig.one | Should -BeExactly 1
+ $scoopConfig.two | Should -BeTrue
+ $scoopConfig.three | Should -BeFalse
+ $scoopConfig.under_line | Should -BeExactly 'four'
+ $scoopConfig.five | Should -Be 'not null'
+ $scoopConfig.time | Should -BeOfType [System.DateTime]
+ $scoopConfig.time | Should -Be ([System.DateTime]::Parse('2019-03-18T15:22:09.3930000+00:00', $null, [System.Globalization.DateTimeStyles]::AdjustToUniversal))
+ $scoopConfig.unicode | Should -Be $unicode
+ }
+
+ It 'get_config should return exactly the same values' {
+ $scoopConfig = load_cfg $configFile
+ (get_config 'one') | Should -BeExactly 1
+ (get_config 'two') | Should -BeTrue
+ (get_config 'three') | Should -BeFalse
+ (get_config 'under_line') | Should -BeExactly 'four'
+ (get_config 'five') | Should -Be 'not null'
+ (get_config 'time') | Should -BeOfType [System.DateTime]
+ (get_config 'time') | Should -Be ([System.DateTime]::Parse('2019-03-18T15:22:09.3930000+00:00', $null, [System.Globalization.DateTimeStyles]::AdjustToUniversal))
+ (get_config 'unicode') | Should -Be $unicode
+ }
- $ht.one | should beexactly 1
- $ht.two[0].a | should be "a"
- $ht.two[1] | should be "b"
- $ht.two[2] | should beexactly 2
- $ht.three.four | should beexactly 4
+ It 'set_config should remove a value if being set to $null' {
+ $scoopConfig = load_cfg $configFile
+ $scoopConfig = set_config 'five' $null
+ $scoopConfig.five | Should -BeNullOrEmpty
}
}
diff --git a/test/Scoop-Core.Tests.ps1 b/test/Scoop-Core.Tests.ps1
index 008dfd0b99..d1cc9defe3 100644
--- a/test/Scoop-Core.Tests.ps1
+++ b/test/Scoop-Core.Tests.ps1
@@ -1,240 +1,395 @@
-. "$psscriptroot\..\lib\core.ps1"
-. "$psscriptroot\..\lib\install.ps1"
-. "$psscriptroot\..\lib\unix.ps1"
-. "$psscriptroot\Scoop-TestLib.ps1"
+BeforeAll {
+ . "$PSScriptRoot\Scoop-TestLib.ps1"
+ . "$PSScriptRoot\..\lib\core.ps1"
+ . "$PSScriptRoot\..\lib\system.ps1"
+ . "$PSScriptRoot\..\lib\install.ps1"
+}
-$repo_dir = (Get-Item $MyInvocation.MyCommand.Path).directory.parent.FullName
-$isUnix = is_unix
+Describe 'Get-AppFilePath' -Tag 'Scoop' {
+ BeforeAll {
+ $working_dir = setup_working 'is_directory'
+ Mock currentdir { 'local' } -Verifiable -ParameterFilter { $global -eq $false }
+ Mock currentdir { 'global' } -Verifiable -ParameterFilter { $global -eq $true }
+ }
-describe "is_directory" {
- beforeall {
- $working_dir = setup_working "is_directory"
+ It 'should return locally installed program' {
+ Mock Test-Path { $true } -Verifiable -ParameterFilter { $Path -eq 'local\i_am_a_file.txt' }
+ Mock Test-Path { $false } -Verifiable -ParameterFilter { $Path -eq 'global\i_am_a_file.txt' }
+ Get-AppFilePath -App 'is_directory' -File 'i_am_a_file.txt' | Should -Be 'local\i_am_a_file.txt'
}
- it "is_directory recognize directories" {
- is_directory "$working_dir\i_am_a_directory" | Should be $true
+ It 'should return globally installed program' {
+ Mock Test-Path { $false } -Verifiable -ParameterFilter { $Path -eq 'local\i_am_a_file.txt' }
+ Mock Test-Path { $true } -Verifiable -ParameterFilter { $Path -eq 'global\i_am_a_file.txt' }
+ Get-AppFilePath -App 'is_directory' -File 'i_am_a_file.txt' | Should -Be 'global\i_am_a_file.txt'
}
- it "is_directory recognize files" {
- is_directory "$working_dir\i_am_a_file.txt" | Should be $false
+
+ It 'should return null if program is not installed' {
+ Get-AppFilePath -App 'is_directory' -File 'i_do_not_exist' | Should -BeNullOrEmpty
}
- it "is_directory is falsey on unknown path" {
- is_directory "$working_dir\i_do_not_exist" | Should be $false
+ It 'should throw if parameter is wrong or missing' {
+ { Get-AppFilePath -App 'is_directory' -File } | Should -Throw
+ { Get-AppFilePath -App -File 'i_am_a_file.txt' } | Should -Throw
+ { Get-AppFilePath -App -File } | Should -Throw
}
}
-describe "movedir" {
- $extract_dir = "subdir"
- $extract_to = $null
-
- beforeall {
- $working_dir = setup_working "movedir"
+Describe 'Get-HelperPath' -Tag 'Scoop' {
+ BeforeAll {
+ $working_dir = setup_working 'is_directory'
+ }
+ It 'should return path if program is installed' {
+ Mock Get-AppFilePath { '7zip\current\7z.exe' }
+ Get-HelperPath -Helper 7zip | Should -Be '7zip\current\7z.exe'
}
- it "moves directories with no spaces in path" -skip:$isUnix {
- $dir = "$working_dir\user"
- movedir "$dir\_tmp\$extract_dir" "$dir\$extract_to"
-
- "$dir\test.txt" | should contain "this is the one"
- "$dir\_tmp\$extract_dir" | should not exist
+ It 'should return null if program is not installed' {
+ Mock Get-AppFilePath { $null }
+ Get-HelperPath -Helper 7zip | Should -BeNullOrEmpty
}
- it "moves directories with spaces in path" -skip:$isUnix {
- $dir = "$working_dir\user with space"
- movedir "$dir\_tmp\$extract_dir" "$dir\$extract_to"
+ It 'should throw if parameter is wrong or missing' {
+ { Get-HelperPath -Helper } | Should -Throw
+ { Get-HelperPath -Helper Wrong } | Should -Throw
+ }
+}
- "$dir\test.txt" | should contain "this is the one"
- "$dir\_tmp\$extract_dir" | should not exist
- # test trailing \ in from dir
- movedir "$dir\_tmp\$null" "$dir\another"
- "$dir\another\test.txt" | should contain "testing"
- "$dir\_tmp" | should not exist
+Describe 'Test-HelperInstalled' -Tag 'Scoop' {
+ It 'should return true if program is installed' {
+ Mock Get-HelperPath { '7z.exe' }
+ Test-HelperInstalled -Helper 7zip | Should -BeTrue
}
- it "moves directories with quotes in path" -skip:$isUnix {
- $dir = "$working_dir\user with 'quote"
- movedir "$dir\_tmp\$extract_dir" "$dir\$extract_to"
+ It 'should return false if program is not installed' {
+ Mock Get-HelperPath { $null }
+ Test-HelperInstalled -Helper 7zip | Should -BeFalse
+ }
- "$dir\test.txt" | should contain "this is the one"
- "$dir\_tmp\$extract_dir" | should not exist
+ It 'should throw if parameter is wrong or missing' {
+ { Test-HelperInstalled -Helper } | Should -Throw
+ { Test-HelperInstalled -Helper Wrong } | Should -Throw
}
}
-describe "unzip_old" {
- beforeall {
- $working_dir = setup_working "unzip_old"
+Describe 'Test-CommandAvailable' -Tag 'Scoop' {
+ It 'should return true if command exists' {
+ Test-CommandAvailable 'Write-Host' | Should -BeTrue
}
- function test-unzip($from) {
- $to = strip_ext $from
+ It "should return false if command doesn't exist" {
+ Test-CommandAvailable 'Write-ThisWillProbablyNotExist' | Should -BeFalse
+ }
+
+ It 'should throw if parameter is wrong or missing' {
+ { Test-CommandAvailable } | Should -Throw
+ }
+}
- if(is_unix) {
- unzip_old ($from -replace '\\','/') ($to -replace '\\','/')
- } else {
- unzip_old ($from -replace '/','\') ($to -replace '/','\')
- }
- $to
+Describe 'is_directory' -Tag 'Scoop' {
+ BeforeAll {
+ $working_dir = setup_working 'is_directory'
}
- context "zip file size is zero bytes" {
- $zerobyte = "$working_dir\zerobyte.zip"
- $zerobyte | should exist
+ It 'is_directory recognize directories' {
+ is_directory "$working_dir\i_am_a_directory" | Should -Be $true
+ }
+ It 'is_directory recognize files' {
+ is_directory "$working_dir\i_am_a_file.txt" | Should -Be $false
+ }
- it "unzips file with zero bytes without error" -skip:$isUnix {
- # some combination of pester, COM (used within unzip_old), and Win10 causes a bugged return value from test-unzip
- # `$to = test-unzip $zerobyte` * RETURN_VAL has a leading space and complains of $null usage when used in PoSH functions
- $to = ([string](test-unzip $zerobyte)).trimStart()
+ It 'is_directory is falsey on unknown path' {
+ is_directory "$working_dir\i_do_not_exist" | Should -Be $false
+ }
+}
- $to | should not match '^\s'
- $to | should not be NullOrEmpty
+Describe 'movedir' -Tag 'Scoop', 'Windows' {
+ BeforeAll {
+ $working_dir = setup_working 'movedir'
+ $extract_dir = 'subdir'
+ $extract_to = $null
+ }
- $to | should exist
+ It 'moves directories with no spaces in path' {
+ $dir = "$working_dir\user"
+ movedir "$dir\_tmp\$extract_dir" "$dir\$extract_to"
- (gci $to).count | should be 0
- }
+ "$dir\test.txt" | Should -FileContentMatch 'this is the one'
+ "$dir\_tmp\$extract_dir" | Should -Not -Exist
}
- context "zip file is small in size" {
- $small = "$working_dir\small.zip"
- $small | should exist
+ It 'moves directories with spaces in path' {
+ $dir = "$working_dir\user with space"
+ movedir "$dir\_tmp\$extract_dir" "$dir\$extract_to"
- it "unzips file which is small in size" -skip:$isUnix {
- # some combination of pester, COM (used within unzip_old), and Win10 causes a bugged return value from test-unzip
- # `$to = test-unzip $small` * RETURN_VAL has a leading space and complains of $null usage when used in PoSH functions
- $to = ([string](test-unzip $small)).trimStart()
+ "$dir\test.txt" | Should -FileContentMatch 'this is the one'
+ "$dir\_tmp\$extract_dir" | Should -Not -Exist
- $to | should not match '^\s'
- $to | should not be NullOrEmpty
+ # test trailing \ in from dir
+ movedir "$dir\_tmp\$null" "$dir\another"
+ "$dir\another\test.txt" | Should -FileContentMatch 'testing'
+ "$dir\_tmp" | Should -Not -Exist
+ }
- $to | should exist
+ It 'moves directories with quotes in path' {
+ $dir = "$working_dir\user with 'quote"
+ movedir "$dir\_tmp\$extract_dir" "$dir\$extract_to"
- # these don't work for some reason on appveyor
- #join-path $to "empty" | should exist
- #(gci $to).count | should be 1
- }
+ "$dir\test.txt" | Should -FileContentMatch 'this is the one'
+ "$dir\_tmp\$extract_dir" | Should -Not -Exist
}
}
-describe "shim" {
- beforeall {
- $working_dir = setup_working "shim"
+Describe 'shim' -Tag 'Scoop', 'Windows' {
+ BeforeAll {
+ $working_dir = setup_working 'shim'
$shimdir = shimdir
- $(ensure_in_path $shimdir) | out-null
+ Add-Path $shimdir
}
- it "links a file onto the user's path" -skip:$isUnix {
- { 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
- { shim-test } | should throw
-
- shim "$working_dir\shim-test.ps1" $false "shim-test"
- { get-command "shim-test" -ea stop } | should not throw
- { get-command "shim-test.ps1" -ea stop } | should not throw
- { get-command "shim-test.cmd" -ea stop } | should not throw
- shim-test | should be "Hello, world!"
+ 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
+ { shim-test } | Should -Throw
+
+ shim "$working_dir\shim-test.ps1" $false 'shim-test'
+ { Get-Command 'shim-test' -ea stop } | Should -Not -Throw
+ { Get-Command 'shim-test.ps1' -ea stop } | Should -Not -Throw
+ { Get-Command 'shim-test.cmd' -ea stop } | Should -Not -Throw
+ 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 {
- rm_shim "shim-test" $shimdir
+ AfterEach {
+ rm_shim 'shim-test' $shimdir
}
}
-describe "rm_shim" {
- beforeall {
- $working_dir = setup_working "shim"
+Describe 'rm_shim' -Tag 'Scoop', 'Windows' {
+ BeforeAll {
+ $working_dir = setup_working 'shim'
$shimdir = shimdir
- $(ensure_in_path $shimdir) | out-null
+ Add-Path $shimdir
}
- it "removes shim from path" -skip:$isUnix {
- shim "$working_dir\shim-test.ps1" $false "shim-test"
+ It 'removes shim from path' {
+ shim "$working_dir\shim-test.ps1" $false 'shim-test'
- rm_shim "shim-test" $shimdir
+ rm_shim 'shim-test' $shimdir
- { 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
- { shim-test } | should throw
+ { 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
+ { shim-test } | Should -Throw
}
}
-describe "ensure_robocopy_in_path" {
- $shimdir = shimdir $false
- mock versiondir { $repo_dir }
-
- beforeall {
- reset_aliases
+Describe 'get_app_name_from_shim' -Tag 'Scoop', 'Windows' {
+ BeforeAll {
+ $working_dir = setup_working 'shim'
+ $shimdir = shimdir
+ Add-Path $shimdir
+ Mock appsdir { $working_dir }
}
- context "robocopy is not in path" {
- it "shims robocopy when not on path" -skip:$isUnix {
- mock gcm { $false }
- gcm robocopy | should be $false
+ It 'returns empty string if file does not exist' {
+ get_app_name_from_shim 'non-existent-file' | Should -Be ''
+ }
- ensure_robocopy_in_path
+ 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'
+ $shim_path1 = (Get-Command 'shim-test1.ps1').Path
+ get_app_name_from_shim "$shim_path1" | Should -Be 'mockapp'
+ ensure "$working_dir/mockapp/1.0.0/"
+ Write-Output '' | Out-File "$working_dir/mockapp/1.0.0/mockapp2.ps1"
+ shim "$working_dir/mockapp/1.0.0/mockapp2.ps1" $false 'shim-test2'
+ $shim_path2 = (Get-Command 'shim-test2.ps1').Path
+ get_app_name_from_shim "$shim_path2" | Should -Be 'mockapp'
+ }
- "$shimdir/robocopy.ps1" | should exist
- "$shimdir/robocopy.exe" | should exist
+ 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 ''
+ }
- # clean up
- rm_shim robocopy $(shimdir $false) | out-null
+ AfterAll {
+ if (Get-Command 'shim-test1' -ErrorAction SilentlyContinue) {
+ rm_shim 'shim-test1' $shimdir -ErrorAction SilentlyContinue
}
+ if (Get-Command 'shim-test2' -ErrorAction SilentlyContinue) {
+ rm_shim 'shim-test2' $shimdir -ErrorAction SilentlyContinue
+ }
+ Remove-Item -Force -Recurse -ErrorAction SilentlyContinue "$working_dir/mockapp"
+ Remove-Item -Force -ErrorAction SilentlyContinue "$working_dir/moch-shim.ps1"
}
+}
- context "robocopy is in path" {
- it "does not shim robocopy when it is in path" -skip:$isUnix {
- mock gcm { $true }
- ensure_robocopy_in_path
+Describe 'cache_path' -Tag 'Scoop' {
+ It 'returns the correct cache path for a given input' {
+ $url = 'https://example.com/git.zip'
+ $ret = cache_path 'git' '2.44.0' $url
+ $inputStream = [System.IO.MemoryStream]::new([System.Text.Encoding]::UTF8.GetBytes($url))
+ $sha = (Get-FileHash -Algorithm SHA256 -InputStream $inputStream).Hash.ToLower().Substring(0, 7)
+ $ret | Should -Be "$cachedir\git#2.44.0#$sha.zip"
+ }
- "$shimdir/robocopy.ps1" | should not exist
- "$shimdir/robocopy.exe" | should not exist
- }
+ # # NOTE: Remove this 6 months after the feature ships.
+ It 'returns the old format cache path for a given input' {
+ Mock Test-Path { $true }
+ $ret = cache_path 'git' '2.44.0' 'https://example.com/git.zip'
+ $ret | Should -Be "$cachedir\git#2.44.0#https_example.com_git.zip"
}
}
-describe 'sanitary_path' {
- it 'removes invalid path characters from a string' {
- $path = 'test?.json'
- $valid_path = sanitary_path $path
+Describe 'sanitary_path' -Tag 'Scoop' {
+ It 'removes invalid path characters from a string' {
+ $path = 'test?.json'
+ $valid_path = sanitary_path $path
+
+ $valid_path | Should -Be 'test.json'
+ }
+}
- $valid_path | should be "test.json"
- }
+Describe 'app' -Tag 'Scoop' {
+ It 'parses the bucket name from an app query' {
+ $query = 'C:\test.json'
+ $app, $bucket, $version = parse_app $query
+ $app | Should -Be 'C:\test.json'
+ $bucket | Should -BeNullOrEmpty
+ $version | Should -BeNullOrEmpty
+
+ $query = 'test.json'
+ $app, $bucket, $version = parse_app $query
+ $app | Should -Be 'test.json'
+ $bucket | Should -BeNullOrEmpty
+ $version | Should -BeNullOrEmpty
+
+ $query = '.\test.json'
+ $app, $bucket, $version = parse_app $query
+ $app | Should -Be '.\test.json'
+ $bucket | Should -BeNullOrEmpty
+ $version | Should -BeNullOrEmpty
+
+ $query = '..\test.json'
+ $app, $bucket, $version = parse_app $query
+ $app | Should -Be '..\test.json'
+ $bucket | Should -BeNullOrEmpty
+ $version | Should -BeNullOrEmpty
+
+ $query = '\\share\test.json'
+ $app, $bucket, $version = parse_app $query
+ $app | Should -Be '\\share\test.json'
+ $bucket | Should -BeNullOrEmpty
+ $version | Should -BeNullOrEmpty
+
+ $query = 'https://example.com/test.json'
+ $app, $bucket, $version = parse_app $query
+ $app | Should -Be 'https://example.com/test.json'
+ $bucket | Should -BeNullOrEmpty
+ $version | Should -BeNullOrEmpty
+
+ $query = 'test'
+ $app, $bucket, $version = parse_app $query
+ $app | Should -Be 'test'
+ $bucket | Should -BeNullOrEmpty
+ $version | Should -BeNullOrEmpty
+
+ $query = 'extras/enso'
+ $app, $bucket, $version = parse_app $query
+ $app | Should -Be 'enso'
+ $bucket | Should -Be 'extras'
+ $version | Should -BeNullOrEmpty
+
+ $query = 'test-app'
+ $app, $bucket, $version = parse_app $query
+ $app | Should -Be 'test-app'
+ $bucket | Should -BeNullOrEmpty
+ $version | Should -BeNullOrEmpty
+
+ $query = 'test-bucket/test-app'
+ $app, $bucket, $version = parse_app $query
+ $app | Should -Be 'test-app'
+ $bucket | Should -Be 'test-bucket'
+ $version | Should -BeNullOrEmpty
+
+ $query = 'test-bucket/test-app@1.8.0'
+ $app, $bucket, $version = parse_app $query
+ $app | Should -Be 'test-app'
+ $bucket | Should -Be 'test-bucket'
+ $version | Should -Be '1.8.0'
+
+ $query = 'test-bucket/test-app@1.8.0-rc2'
+ $app, $bucket, $version = parse_app $query
+ $app | Should -Be 'test-app'
+ $bucket | Should -Be 'test-bucket'
+ $version | Should -Be '1.8.0-rc2'
+
+ $query = 'test-bucket/test_app'
+ $app, $bucket, $version = parse_app $query
+ $app | Should -Be 'test_app'
+ $bucket | Should -Be 'test-bucket'
+ $version | Should -BeNullOrEmpty
+
+ $query = 'test-bucket/test_app@1.8.0'
+ $app, $bucket, $version = parse_app $query
+ $app | Should -Be 'test_app'
+ $bucket | Should -Be 'test-bucket'
+ $version | Should -Be '1.8.0'
+
+ $query = 'test-bucket/test_app@1.8.0-rc2'
+ $app, $bucket, $version = parse_app $query
+ $app | Should -Be 'test_app'
+ $bucket | Should -Be 'test-bucket'
+ $version | Should -Be '1.8.0-rc2'
+ }
}
-describe 'app' {
- it 'parses the bucket name from an app query' {
- $query = "test"
- $app, $bucket = app $query
- $app | should be "test"
- $bucket | should be $null
-
- $query = "extras/enso"
- $app, $bucket = app $query
- $app | should be "enso"
- $bucket | should be "extras"
-
- $query = "test-app"
- $app, $bucket = app $query
- $app | should be "test-app"
- $bucket | should be $null
-
- $query = "test-bucket/test-app"
- $app, $bucket = app $query
- $app | should be "test-app"
- $bucket | should be "test-bucket"
+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'"
}
}
diff --git a/test/Scoop-Decompress.Tests.ps1 b/test/Scoop-Decompress.Tests.ps1
new file mode 100644
index 0000000000..e635492cec
--- /dev/null
+++ b/test/Scoop-Decompress.Tests.ps1
@@ -0,0 +1,263 @@
+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"
+}
+
+Describe 'Decompression function' -Tag 'Scoop', 'Windows', 'Decompress' {
+
+ BeforeAll {
+ $working_dir = setup_working 'decompress'
+
+ function test_extract($extract_fn, $from, $removal) {
+ $to = (strip_ext $from) -replace '\.tar$', ''
+ & $extract_fn ($from -replace '/', '\') ($to -replace '/', '\') -Removal:$removal -ExtractDir $args[0]
+ return $to
+ }
+
+ }
+ Context 'Decompression test cases should exist' {
+ BeforeAll {
+ $testcases = "$working_dir\TestCases.zip"
+ }
+ It 'Test cases should exist and hash should match' {
+ $testcases | Should -Exist
+ (Get-FileHash -Path $testcases -Algorithm SHA256).Hash.ToLower() | Should -Be '591072faabd419b77932b7023e5899b4e05c0bf8e6859ad367398e6bfe1eb203'
+ }
+ It 'Test cases should be extracted correctly' {
+ { Microsoft.PowerShell.Archive\Expand-Archive -Path $testcases -DestinationPath $working_dir } | Should -Not -Throw
+ }
+ }
+
+ Context '7zip extraction' {
+
+ BeforeAll {
+ if ($env:CI) {
+ Mock Get-AppFilePath { (Get-Command 7z.exe).Path }
+ } elseif (!(installed 7zip)) {
+ scoop install 7zip
+ }
+ $test1 = "$working_dir\7ZipTest1.7z"
+ $test2 = "$working_dir\7ZipTest2.tgz"
+ $test3 = "$working_dir\7ZipTest3.tar.bz2"
+ $test4 = "$working_dir\7ZipTest4.tar.gz"
+ $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"
+ $test7 = "$working_dir\NSISTest.exe"
+ }
+
+ AfterEach {
+ Remove-Item -Path $to -Recurse -Force
+ }
+
+ It 'extract normal compressed file' {
+ $to = test_extract 'Expand-7zipArchive' $test1
+ $to | Should -Exist
+ "$to\empty" | Should -Exist
+ (Get-ChildItem $to).Count | Should -Be 4
+ }
+
+ It 'extract "extract_dir" correctly' {
+ $to = test_extract 'Expand-7zipArchive' $test1 $false 'tmp'
+ $to | Should -Exist
+ "$to\empty" | Should -Exist
+ (Get-ChildItem $to).Count | Should -Be 1
+ }
+
+ It 'extract "extract_dir" with spaces correctly' {
+ $to = test_extract 'Expand-7zipArchive' $test1 $false 'tmp 2'
+ $to | Should -Exist
+ "$to\empty" | Should -Exist
+ (Get-ChildItem $to).Count | Should -Be 1
+ }
+
+ It 'extract "extract_dir" with nested folder with same name' {
+ $to = test_extract 'Expand-7zipArchive' $test1 $false 'keep\sub'
+ $to | Should -Exist
+ "$to\keep\empty" | Should -Exist
+ (Get-ChildItem $to).Count | Should -Be 1
+ (Get-ChildItem "$to\keep").Count | Should -Be 1
+ }
+
+ It 'extract nested compressed file' {
+ # file ext: tgz
+ $to = test_extract 'Expand-7zipArchive' $test2
+ $to | Should -Exist
+ "$to\empty" | Should -Exist
+ (Get-ChildItem $to).Count | Should -Be 1
+
+ # file ext: tar.bz2
+ $to = test_extract 'Expand-7zipArchive' $test3
+ $to | Should -Exist
+ "$to\empty" | Should -Exist
+ (Get-ChildItem $to).Count | Should -Be 1
+ }
+
+ 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, ...)' {
+ $to = test_extract 'Expand-7zipArchive' $test5_1
+ $to | Should -Exist
+ "$to\empty" | Should -Exist
+ (Get-ChildItem $to).Count | Should -Be 1
+ }
+
+ 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 'extract NSIS installer' {
+ $to = test_extract 'Expand-7zipArchive' $test7
+ $to | Should -Exist
+ "$to\empty" | Should -Exist
+ (Get-ChildItem $to).Count | Should -Be 1
+ }
+
+ It 'self-extract NSIS installer' {
+ $to = "$working_dir\NSIS Test"
+ $null = Invoke-ExternalCommand -FilePath $test7 -ArgumentList @('/S', '/NCRC', "/D=$to")
+ $to | Should -Exist
+ "$to\empty" | Should -Exist
+ (Get-ChildItem $to).Count | Should -Be 1
+ }
+
+ It 'works with "-Removal" switch ($removal param)' {
+ $test1 | Should -Exist
+ $to = test_extract 'Expand-7zipArchive' $test1 $true
+ $to | Should -Exist
+ $test1 | Should -Not -Exist
+ $test5_1 | Should -Exist
+ $test5_2 | Should -Exist
+ $test5_3 | Should -Exist
+ $to = test_extract 'Expand-7zipArchive' $test5_1 $true
+ $to | Should -Exist
+ $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
+ $to = test_extract 'Expand-7zipArchive' $test6_1 $true
+ $to | Should -Exist
+ $test6_1 | Should -Not -Exist
+ $test6_2 | Should -Not -Exist
+ $test6_3 | Should -Not -Exist
+ }
+ }
+
+ Context 'msi extraction' {
+
+ BeforeAll {
+ if ($env:CI) {
+ Mock Get-AppFilePath { $env:SCOOP_LESSMSI_PATH }
+ } elseif (!(installed lessmsi)) {
+ scoop install lessmsi
+ }
+ Copy-Item "$working_dir\MSITest.msi" "$working_dir\MSI Test.msi"
+ $test1 = "$working_dir\MSITest.msi"
+ $test2 = "$working_dir\MSI Test.msi"
+ $test3 = "$working_dir\MSITestNull.msi"
+ }
+
+ It 'extract normal MSI file using msiexec' {
+ Mock get_config { $false }
+ $to = test_extract 'Expand-MsiArchive' $test1
+ $to | Should -Exist
+ "$to\MSITest\empty" | Should -Exist
+ (Get-ChildItem "$to\MSITest").Count | Should -Be 1
+ }
+
+ It 'extract normal MSI file with whitespace in path using msiexec' {
+ Mock get_config { $false }
+ $to = test_extract 'Expand-MsiArchive' $test2
+ $to | Should -Exist
+ "$to\MSITest\empty" | Should -Exist
+ (Get-ChildItem "$to\MSITest").Count | Should -Be 1
+ }
+
+ It 'extract normal MSI file using lessmsi' {
+ Mock get_config { $true }
+ $to = test_extract 'Expand-MsiArchive' $test1
+ $to | Should -Exist
+ }
+
+ It 'extract normal MSI file with whitespace in path using lessmsi' {
+ Mock get_config { $true }
+ $to = test_extract 'Expand-MsiArchive' $test2
+ $to | Should -Exist
+ }
+
+ It 'extract empty MSI file using lessmsi' {
+ Mock get_config { $true }
+ $to = test_extract 'Expand-MsiArchive' $test3
+ $to | Should -Exist
+ }
+
+ It 'works with "-Removal" switch ($removal param)' {
+ Mock get_config { $false }
+ $test1 | Should -Exist
+ test_extract 'Expand-MsiArchive' $test1 $true
+ $test1 | Should -Not -Exist
+ }
+ }
+
+ Context 'inno extraction' {
+
+ BeforeAll {
+ if ($env:CI) {
+ Mock Get-AppFilePath { $env:SCOOP_INNOUNP_PATH }
+ } elseif (!(installed innounp)) {
+ scoop install innounp
+ }
+ $test = "$working_dir\InnoTest.exe"
+ }
+
+ 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)' {
+ $test | Should -Exist
+ test_extract 'Expand-InnoArchive' $test $true
+ $test | Should -Not -Exist
+ }
+ }
+
+ Context 'zip extraction' {
+
+ BeforeAll {
+ $test = "$working_dir\ZipTest.zip"
+ }
+
+ 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)' {
+ $test | Should -Exist
+ test_extract 'Expand-ZipArchive' $test $true
+ $test | Should -Not -Exist
+ }
+ }
+}
diff --git a/test/Scoop-Depends.Tests.ps1 b/test/Scoop-Depends.Tests.ps1
new file mode 100644
index 0000000000..3e6713d050
--- /dev/null
+++ b/test/Scoop-Depends.Tests.ps1
@@ -0,0 +1,95 @@
+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' {
+ It 'Test 7zip requirement' {
+ Test-7zipRequirement -Uri 'test.xz' | Should -BeTrue
+ Test-7zipRequirement -Uri 'test.bin' | Should -BeFalse
+ Test-7zipRequirement -Uri @('test.xz', 'test.bin') | Should -BeTrue
+ }
+ It 'Test lessmsi requirement' {
+ Mock get_config { $true }
+ Test-LessmsiRequirement -Uri 'test.msi' | Should -BeTrue
+ Test-LessmsiRequirement -Uri 'test.bin' | Should -BeFalse
+ Test-LessmsiRequirement -Uri @('test.msi', 'test.bin') | Should -BeTrue
+ }
+ It 'Allow $Uri be $null' {
+ Test-7zipRequirement -Uri $null | Should -BeFalse
+ Test-LessmsiRequirement -Uri $null | Should -BeFalse
+ }
+ }
+
+ Context 'InstallationHelper function' {
+ BeforeAll {
+ $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 }
+ }
+ It 'Get helpers from URL' {
+ Mock get_config { $true }
+ Get-InstallationHelper -Manifest $manifest1 -Architecture '32bit' | Should -Be @('lessmsi')
+ }
+ It 'Get helpers from script' {
+ Mock get_config { $false }
+ Get-InstallationHelper -Manifest $manifest2 -Architecture '32bit' | Should -Be @('7zip')
+ }
+ It 'Helpers reflect config changes' {
+ 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 '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')
+ Get-InstallationHelper -Manifest $manifest2 -Architecture '32bit' | Should -BeNullOrEmpty
+ Mock Test-HelperInstalled { $false }-ParameterFilter { $Helper -eq '7zip' }
+ Mock Test-HelperInstalled { $true }-ParameterFilter { $Helper -eq 'Lessmsi' }
+ Get-InstallationHelper -Manifest $manifest1 -Architecture '32bit' | Should -BeNullOrEmpty
+ Get-InstallationHelper -Manifest $manifest2 -Architecture '32bit' | Should -Be @('7zip')
+ }
+ }
+
+ Context 'Dependencies resolution' {
+ BeforeAll {
+ Mock Test-HelperInstalled { $false }
+ Mock get_config { $true } -ParameterFilter { $name -eq 'USE_LESSMSI' }
+ Mock get_config { $false } -ParameterFilter { $name -eq 'USE_EXTERNAL_7ZIP' }
+ 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' }
+ }
+
+ It 'Resolve install dependencies' {
+ Mock Get-Manifest { 'test', @{ url = 'test.7z' }, $null, $null }
+ Get-Dependency -AppName 'test' -Architecture '32bit' | Should -Be @('lessmsi', '7zip', 'test')
+ Mock Get-Manifest { 'test', @{ innosetup = $true }, $null, $null }
+ Get-Dependency -AppName 'test' -Architecture '32bit' | Should -Be @('innounp', 'test')
+ }
+ It 'Resolve script dependencies' {
+ Mock Get-Manifest { 'test', @{ pre_install = 'Expand-7zipArchive ' }, $null, $null }
+ Get-Dependency -AppName 'test' -Architecture '32bit' | Should -Be @('lessmsi', '7zip', 'test')
+ }
+ It 'Resolve runtime dependencies' {
+ Mock Get-Manifest { 'depends', @{}, $null, $null } -ParameterFilter { $app -eq 'depends' }
+ Mock Get-Manifest { 'test', @{ depends = 'depends' }, $null, $null }
+ Get-Dependency -AppName 'test' -Architecture '32bit' | Should -Be @('depends', 'test')
+ }
+ It 'Keep bucket name of app' {
+ Mock Get-Manifest { 'depends', @{}, 'anotherbucket', $null } -ParameterFilter { $app -eq 'anotherbucket/depends' }
+ Mock Get-Manifest { 'test', @{ depends = 'anotherbucket/depends' }, 'bucket', $null }
+ Get-Dependency -AppName 'bucket/test' -Architecture '32bit' | Should -Be @('anotherbucket/depends', 'bucket/test')
+ }
+ }
+}
diff --git a/test/Scoop-Download.Tests.ps1 b/test/Scoop-Download.Tests.ps1
new file mode 100644
index 0000000000..8968c30014
--- /dev/null
+++ b/test/Scoop-Download.Tests.ps1
@@ -0,0 +1,49 @@
+BeforeAll {
+ . "$PSScriptRoot\Scoop-TestLib.ps1"
+ . "$PSScriptRoot\..\lib\core.ps1"
+ . "$PSScriptRoot\..\lib\download.ps1"
+}
+
+Describe 'Test-Aria2Enabled' -Tag 'Scoop' {
+ It 'should return true if aria2 is installed' {
+ Mock Test-HelperInstalled { $true }
+ Mock get_config { $true }
+ Test-Aria2Enabled | Should -BeTrue
+ }
+
+ It 'should return false if aria2 is not installed' {
+ Mock Test-HelperInstalled { $false }
+ Mock get_config { $false }
+ Test-Aria2Enabled | Should -BeFalse
+
+ Mock Test-HelperInstalled { $false }
+ Mock get_config { $true }
+ Test-Aria2Enabled | Should -BeFalse
+
+ Mock Test-HelperInstalled { $true }
+ Mock get_config { $false }
+ Test-Aria2Enabled | Should -BeFalse
+ }
+}
+
+Describe 'url_filename' -Tag 'Scoop' {
+ It 'should extract the real filename from an url' {
+ url_filename 'http://example.org/foo.txt' | Should -Be 'foo.txt'
+ url_filename 'http://example.org/foo.txt?var=123' | Should -Be 'foo.txt'
+ }
+
+ It 'can be tricked with a hash to override the real filename' {
+ url_filename 'http://example.org/foo-v2.zip#/foo.zip' | Should -Be 'foo.zip'
+ }
+}
+
+Describe 'url_remote_filename' -Tag 'Scoop' {
+ It 'should extract the real filename from an url' {
+ url_remote_filename 'http://example.org/foo.txt' | Should -Be 'foo.txt'
+ url_remote_filename 'http://example.org/foo.txt?var=123' | Should -Be 'foo.txt'
+ }
+
+ It 'can not be tricked with a hash to override the real filename' {
+ url_remote_filename 'http://example.org/foo-v2.zip#/foo.zip' | Should -Be 'foo-v2.zip'
+ }
+}
diff --git a/test/Scoop-GetOpts.Tests.ps1 b/test/Scoop-GetOpts.Tests.ps1
index 98525b21ef..c55781ecbf 100644
--- a/test/Scoop-GetOpts.Tests.ps1
+++ b/test/Scoop-GetOpts.Tests.ps1
@@ -1,71 +1,93 @@
-. "$psscriptroot\Scoop-TestLib.ps1"
-. "$psscriptroot\..\lib\getopt.ps1"
+BeforeAll {
+ . "$PSScriptRoot\Scoop-TestLib.ps1"
+ . "$PSScriptRoot\..\lib\getopt.ps1"
+}
-describe "getopt" {
- it 'handle short option with required argument missing' {
+Describe 'getopt' -Tag 'Scoop' {
+ It 'handle short option with required argument missing' {
$null, $null, $err = getopt '-x' 'x:' ''
- $err | should be 'Option -x requires an argument.'
+ $err | Should -Be 'Option -x requires an argument.'
$null, $null, $err = getopt '-xy' 'x:y' ''
- $err | should be 'Option -x requires an argument.'
+ $err | Should -Be 'Option -x requires an argument.'
}
- it 'handle long option with required argument missing' {
+ It 'handle long option with required argument missing' {
$null, $null, $err = getopt '--arb' '' 'arb='
- $err | should be 'Option --arb requires an argument.'
+ $err | Should -Be 'Option --arb requires an argument.'
+ }
+
+ It 'handle space in quote' {
+ $opt, $rem, $err = getopt '-x', 'space arg' 'x:' ''
+ $err | Should -BeNullOrEmpty
+ $opt.x | Should -Be 'space arg'
}
- it 'handle unrecognized short option' {
+ It 'handle unrecognized short option' {
$null, $null, $err = getopt '-az' 'a' ''
- $err | should be 'Option -z not recognized.'
+ $err | Should -Be 'Option -z not recognized.'
}
- it 'handle unrecognized long option' {
+ It 'handle unrecognized long option' {
$null, $null, $err = getopt '--non-exist' '' ''
- $err | should be 'Option --non-exist not recognized.'
+ $err | Should -Be 'Option --non-exist not recognized.'
- $null, $null, $err = getopt '--global','--another' 'abc:de:' 'global','one'
- $err | should be 'Option --another not recognized.'
+ $null, $null, $err = getopt '--global', '--another' 'abc:de:' 'global', 'one'
+ $err | Should -Be 'Option --another not recognized.'
}
- it 'remaining args returned' {
- $opt, $rem, $err = getopt '-g','rem' 'g' ''
- $err | should be $null
- $opt.g | should be $true
- $rem | should not be $null
- $rem.length | should be 1
- $rem[0] | should be 'rem'
+ It 'remaining args returned' {
+ $opt, $rem, $err = getopt '-g', 'rem' 'g' ''
+ $err | Should -BeNullOrEmpty
+ $opt.g | Should -BeTrue
+ $rem | Should -Not -BeNullOrEmpty
+ $rem.length | Should -Be 1
+ $rem[0] | Should -Be 'rem'
}
- it 'get a long flag and a short option with argument' {
- $a = "--global -a 32bit test" -split ' '
- $opt, $rem, $err = getopt $a 'ga:' 'global','arch='
+ It 'get a long flag and a short option with argument' {
+ $a = '--global -a 32bit test' -split ' '
+ $opt, $rem, $err = getopt $a 'ga:' 'global', 'arch='
- $err | should be $null
- $opt.global | should be $true
- $opt.a | should be '32bit'
+ $err | Should -BeNullOrEmpty
+ $opt.global | Should -BeTrue
+ $opt.a | Should -Be '32bit'
}
- it 'handles regex characters' {
- $a = "-?"
- { $opt, $rem, $err = getopt $a 'ga:' 'global' 'arch=' } | should not throw
- { $null, $null, $null = getopt $a '?:' 'help' | should not throw }
+ It 'handles regex characters' {
+ $a = '-?'
+ { $opt, $rem, $err = getopt $a 'ga:' 'global' 'arch=' } | Should -Not -Throw
+ { $null, $null, $null = getopt $a '?:' 'help' | Should -Not -Throw }
}
- it 'handles short option without required argument' {
+ It 'handles short option without required argument' {
$null, $null, $err = getopt '-x' 'x' ''
- $err | should be $null
+ $err | Should -BeNullOrEmpty
}
- it 'handles long option without required argument' {
+ It 'handles long option without required argument' {
$opt, $null, $err = getopt '--long-arg' '' 'long-arg'
- $err | should be $null
- $opt."long-arg" | should be $true
+ $err | Should -BeNullOrEmpty
+ $opt.'long-arg' | Should -BeTrue
}
- it 'handles long option with required argument' {
+ It 'handles long option with required argument' {
$opt, $null, $err = getopt '--long-arg', 'test' '' 'long-arg='
- $err | should be $null
- $opt."long-arg" | should be "test"
+ $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'
}
}
diff --git a/test/Scoop-Install.Tests.ps1 b/test/Scoop-Install.Tests.ps1
index 177b5c940b..3e564d1964 100644
--- a/test/Scoop-Install.Tests.ps1
+++ b/test/Scoop-Install.Tests.ps1
@@ -1,142 +1,102 @@
-. "$psscriptroot\..\lib\core.ps1"
-. "$psscriptroot\..\lib\manifest.ps1"
-. "$psscriptroot\..\lib\install.ps1"
-. "$psscriptroot\..\lib\unix.ps1"
-. "$psscriptroot\Scoop-TestLib.ps1"
-
-$isUnix = is_unix
-
-describe "ensure_architecture" {
- it "should keep correct architectures" {
- ensure_architecture "32bit" | Should be "32bit"
- ensure_architecture "64bit" | 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" {
- Mock abort
-
- ensure_architecture "PPC" | Should be $null
- Assert-MockCalled abort -Times 1
- }
-}
-
-describe "appname_from_url" {
- it "should extract the correct name" {
- appname_from_url "https://example.org/directory/foobar.json" | Should be "foobar"
- }
-}
-
-describe "url_filename" {
- it "should extract the real filename from an url" {
- url_filename "http://example.org/foo.txt" | Should be "foo.txt"
- url_filename "http://example.org/foo.txt?var=123" | Should be "foo.txt"
- }
-
- it "can be tricked with a hash to override the real filename" {
- url_filename "http://example.org/foo-v2.zip#/foo.zip" | Should be "foo.zip"
- }
+BeforeAll {
+ . "$PSScriptRoot\Scoop-TestLib.ps1"
+ . "$PSScriptRoot\..\lib\core.ps1"
+ . "$PSScriptRoot\..\lib\system.ps1"
+ . "$PSScriptRoot\..\lib\manifest.ps1"
+ . "$PSScriptRoot\..\lib\install.ps1"
}
-describe "url_remote_filename" {
- it "should extract the real filename from an url" {
- url_remote_filename "http://example.org/foo.txt" | Should be "foo.txt"
- url_remote_filename "http://example.org/foo.txt?var=123" | Should be "foo.txt"
- }
-
- it "can not be tricked with a hash to override the real filename" {
- url_remote_filename "http://example.org/foo-v2.zip#/foo.zip" | Should be "foo-v2.zip"
+Describe 'appname_from_url' -Tag 'Scoop' {
+ It 'should extract the correct name' {
+ appname_from_url 'https://example.org/directory/foobar.json' | Should -Be 'foobar'
}
}
-describe "is_in_dir" {
- it "should work correctly" -skip:$isUnix {
- is_in_dir "C:\test" "C:\foo" | Should be $false
- is_in_dir "C:\test" "C:\test\foo\baz.zip" | Should be $true
-
- is_in_dir "test" "$psscriptroot" | Should be $true
- is_in_dir "$psscriptroot\..\" "$psscriptroot" | Should be $false
+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
+ is_in_dir "$PSScriptRoot\..\" "$PSScriptRoot" | Should -BeFalse
}
}
-describe "env add and remove path" {
- # 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
}
- $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 {
- mock add_first_in_path {}
- mock remove_from_path {}
+ It 'should concat the correct path' {
+ Mock Add-Path {}
+ Mock Remove-Path {}
# adding
env_add_path $manifest $testdir $global
- Assert-MockCalled add_first_in_path -Times 1 -ParameterFilter {$dir -like "$testdir\foo"}
- Assert-MockCalled add_first_in_path -Times 1 -ParameterFilter {$dir -like "$testdir\bar"}
+ Should -Invoke -CommandName Add-Path -Times 1 -ParameterFilter { $Path -like "$testdir\foo" }
+ Should -Invoke -CommandName Add-Path -Times 1 -ParameterFilter { $Path -like "$testdir\bar" }
+ Should -Invoke -CommandName Add-Path -Times 1 -ParameterFilter { $Path -like $testdir }
+ Should -Invoke -CommandName Add-Path -Times 0 -ParameterFilter { $Path -like $PSScriptRoot }
env_rm_path $manifest $testdir $global
- Assert-MockCalled remove_from_path -Times 1 -ParameterFilter {$dir -like "$testdir\foo"}
- Assert-MockCalled remove_from_path -Times 1 -ParameterFilter {$dir -like "$testdir\bar"}
+ Should -Invoke -CommandName Remove-Path -Times 1 -ParameterFilter { $Path -like "$testdir\foo" }
+ Should -Invoke -CommandName Remove-Path -Times 1 -ParameterFilter { $Path -like "$testdir\bar" }
+ Should -Invoke -CommandName Remove-Path -Times 1 -ParameterFilter { $Path -like $testdir }
+ Should -Invoke -CommandName Remove-Path -Times 0 -ParameterFilter { $Path -like $PSScriptRoot }
}
}
-describe "shim_def" {
- it "should use strings correctly" {
- $target, $name, $shimArgs = shim_def "command.exe"
- $target | Should be "command.exe"
- $name | Should be "command"
- $shimArgs | Should be $null
+Describe 'shim_def' -Tag 'Scoop' {
+ It 'should use strings correctly' {
+ $target, $name, $shimArgs = shim_def 'command.exe'
+ $target | Should -Be 'command.exe'
+ $name | Should -Be 'command'
+ $shimArgs | Should -BeNullOrEmpty
}
- it "should expand the array correctly" {
- $target, $name, $shimArgs = shim_def @("foo.exe", "bar")
- $target | Should be "foo.exe"
- $name | Should be "bar"
- $shimArgs | Should be $null
+ It 'should expand the array correctly' {
+ $target, $name, $shimArgs = shim_def @('foo.exe', 'bar')
+ $target | Should -Be 'foo.exe'
+ $name | Should -Be 'bar'
+ $shimArgs | Should -BeNullOrEmpty
- $target, $name, $shimArgs = shim_def @("foo.exe", "bar", "--test")
- $target | Should be "foo.exe"
- $name | Should be "bar"
- $shimArgs | Should be "--test"
+ $target, $name, $shimArgs = shim_def @('foo.exe', 'bar', '--test')
+ $target | Should -Be 'foo.exe'
+ $name | Should -Be 'bar'
+ $shimArgs | Should -Be '--test'
}
}
-describe 'persist_def' {
- it 'parses string correctly' {
- $source, $target = persist_def "test"
- $source | Should be "test"
- $target | Should be "test"
+Describe 'persist_def' -Tag 'Scoop' {
+ It 'parses string correctly' {
+ $source, $target = persist_def 'test'
+ $source | Should -Be 'test'
+ $target | Should -Be 'test'
}
- it 'should strip directories of source for target' {
- $source, $target = persist_def "foo/bar"
- $source | Should be "foo/bar"
- $target | Should be "bar"
+ It 'should handle sub-folder' {
+ $source, $target = persist_def 'foo/bar'
+ $source | Should -Be 'foo/bar'
+ $target | Should -Be 'foo/bar'
}
- it 'should handle arrays' {
+ It 'should handle arrays' {
# both specified
- $source, $target = persist_def @("foo", "bar")
- $source | Should be "foo"
- $target | Should be "bar"
+ $source, $target = persist_def @('foo', 'bar')
+ $source | Should -Be 'foo'
+ $target | Should -Be 'bar'
# only first specified
- $source, $target = persist_def @("foo")
- $source | Should be "foo"
- $target | Should be "foo"
+ $source, $target = persist_def @('foo')
+ $source | Should -Be 'foo'
+ $target | Should -Be 'foo'
# null value specified
- $source, $target = persist_def @("foo", $null)
- $source | Should be "foo"
- $target | Should be "foo"
+ $source, $target = persist_def @('foo', $null)
+ $source | Should -Be 'foo'
+ $target | Should -Be 'foo'
}
}
diff --git a/test/Scoop-Manifest.Tests.ps1 b/test/Scoop-Manifest.Tests.ps1
index e4760d6777..232a946bbd 100644
--- a/test/Scoop-Manifest.Tests.ps1
+++ b/test/Scoop-Manifest.Tests.ps1
@@ -1,87 +1,86 @@
-. "$psscriptroot\Scoop-TestLib.ps1"
-. "$psscriptroot\..\lib\core.ps1"
-. "$psscriptroot\..\lib\manifest.ps1"
-
-describe "manifest-validation" {
- beforeall {
- $working_dir = setup_working "manifest"
- $schema = "$psscriptroot/../schema.json"
- Add-Type -Path "$psscriptroot\..\supporting\validator\Newtonsoft.Json.dll"
- Add-Type -Path "$psscriptroot\..\supporting\validator\Newtonsoft.Json.Schema.dll"
- Add-Type -Path "$psscriptroot\..\supporting\validator\Scoop.Validator.dll"
- }
-
- it "Scoop.Validator is available" {
- ([System.Management.Automation.PSTypeName]'Scoop.Validator').Type | should be 'Scoop.Validator'
- }
+BeforeAll {
+ . "$PSScriptRoot\..\lib\json.ps1"
+ . "$PSScriptRoot\..\lib\manifest.ps1"
+}
- context "parse_json function" {
- it "fails with invalid json" {
- { parse_json "$working_dir\broken_wget.json" } | should throw
+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 "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 be $false
- $validator.Errors.Count | should be 1
- $validator.Errors | select-object -First 1 | should match "broken_schema.*(line 6).*(position 4)"
+ Context 'Beautify JSON' {
+ BeforeDiscovery {
+ $manifests = (Get-ChildItem "$PSScriptRoot\fixtures\format\formatted" -File -Filter '*.json').Name
}
- it "fails with broken manifest" {
- $validator = new-object Scoop.Validator($schema, $true)
- $validator.Validate("$working_dir/broken_wget.json") | should be $false
- $validator.Errors.Count | should be 1
- $validator.Errors | select-object -First 1 | should match "broken_wget.*(line 5).*(position 4)"
+ BeforeAll {
+ $format = "$PSScriptRoot\fixtures\format"
}
- it "fails with invalid manifest" {
- $validator = new-object Scoop.Validator($schema, $true)
- $validator.Validate("$working_dir/invalid_wget.json") | should be $false
- $validator.Errors.Count | should be 16
- $validator.Errors | select-object -First 1 | should match "invalid_wget.*randomproperty.*properties\.$"
- $validator.Errors | select-object -Last 1 | should match "invalid_wget.*version\.$"
+ 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
}
}
+}
- context "manifest validates against the schema" {
- beforeall {
- $bucketdir = "$psscriptroot\..\bucket\"
- $manifest_files = gci $bucketdir *.json
- $validator = new-object Scoop.Validator($schema, $true)
- }
-
- $global:quota_exceeded = $false
-
- $manifest_files | % {
- it "$_" {
- $file = $_ # exception handling may overwrite $_
-
- if(!($global:quota_exceeded)) {
- try {
- $validator.Validate($file.fullname)
+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
+ }
+}
- if ($validator.Errors.Count -gt 0) {
- 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.*') {
- $global:quota_exceeded = $true
- write-host -f darkyellow 'Schema validation limit exceeded. Will skip further validations.'
- } else {
- throw
- }
- }
- }
+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"
+ }
- $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
- }
- }
+ 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\.'
}
}
diff --git a/test/Scoop-TestLib.ps1 b/test/Scoop-TestLib.ps1
index e72d72e9b6..8664ededff 100644
--- a/test/Scoop-TestLib.ps1
+++ b/test/Scoop-TestLib.ps1
@@ -1,85 +1,15 @@
-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($var -eq $null) { return "`$null" }
- if($var -is [string]) { return "'$var'" }
- return $var
-}
-
# copies fixtures to a working directory
function setup_working($name) {
- $fixtures = "$psscriptroot/fixtures/$name"
- if(!(test-path $fixtures)) {
- write-host "couldn't find fixtures for $name at $fixtures" -f red
+ $fixtures = "$PSScriptRoot\fixtures\$name"
+ if (!(Test-Path $fixtures)) {
+ Write-Host "couldn't find fixtures for $name at $fixtures" -f red
exit 1
}
# 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) {
+ if (Test-Path $working_dir) {
Remove-Item -Recurse -Force $working_dir
}
diff --git a/test/Scoop-Versions.Tests.ps1 b/test/Scoop-Versions.Tests.ps1
index 42a2972495..7043ee07cf 100644
--- a/test/Scoop-Versions.Tests.ps1
+++ b/test/Scoop-Versions.Tests.ps1
@@ -1,37 +1,112 @@
-. "$psscriptroot\Scoop-TestLib.ps1"
-. "$psscriptroot\..\lib\versions.ps1"
-
-describe "versions" {
- it 'compares versions with integer-string mismatch' {
- $a = '1.8.9'
- $b = '1.8.5-1'
- $res = compare_versions $a $b
+BeforeAll {
+ . "$PSScriptRoot\Scoop-TestLib.ps1"
+ . "$PSScriptRoot\..\lib\versions.ps1"
+}
- $res | should be 1
- }
+Describe 'versions comparison' -Tag 'Scoop' {
+ Context 'semver compliant versions' {
+ It 'handles major.minor.patch progressing' {
+ Compare-Version '0.1.0' '0.1.1' | Should -Be 1
+ Compare-Version '0.1.1' '0.2.0' | Should -Be 1
+ Compare-Version '0.2.0' '1.0.0' | Should -Be 1
+ }
- it 'handles plain string version comparison to int version' {
- $a = 'latest'
- $b = '20150405'
- $res = compare_versions $a $b
+ It 'handles pre-release versioning progression' {
+ Compare-Version '0.4.0' '0.5.0-alpha.1' | Should -Be 1
+ Compare-Version '0.5.0-alpha.1' '0.5.0-alpha.2' | Should -Be 1
+ Compare-Version '0.5.0-alpha.2' '0.5.0-alpha.10' | Should -Be 1
+ Compare-Version '0.5.0-alpha.10' '0.5.0-beta' | Should -Be 1
+ Compare-Version '0.5.0-beta' '0.5.0-alpha.10' | Should -Be -1
+ Compare-Version '0.5.0-beta' '0.5.0-beta.0' | Should -Be 1
+ }
- $res | should be 1
+ It 'handles the pre-release tags in an alphabetic order' {
+ Compare-Version '0.5.0-rc.1' '0.5.0-z' | Should -Be 1
+ Compare-Version '0.5.0-rc.1' '0.5.0-howdy' | Should -Be -1
+ Compare-Version '0.5.0-howdy' '0.5.0-rc.1' | Should -Be 1
+ }
}
- it 'handles dashed version components' {
- $a = '7.0.4-9'
- $b = '7.0.4-10'
+ Context 'semver semi-compliant versions' {
+ It 'handles Windows-styled major.minor.patch.build progression' {
+ Compare-Version '0.0.0.0' '0.0.0.1' | Should -Be 1
+ Compare-Version '0.0.0.1' '0.0.0.2' | Should -Be 1
+ Compare-Version '0.0.0.2' '0.0.1.0' | Should -Be 1
+ Compare-Version '0.0.1.0' '0.0.1.1' | Should -Be 1
+ Compare-Version '0.0.1.1' '0.0.1.2' | Should -Be 1
+ Compare-Version '0.0.1.2' '0.0.2.0' | Should -Be 1
+ Compare-Version '0.0.2.0' '0.1.0.0' | Should -Be 1
+ Compare-Version '0.1.0.0' '0.1.0.1' | Should -Be 1
+ Compare-Version '0.1.0.1' '0.1.0.2' | Should -Be 1
+ Compare-Version '0.1.0.2' '0.1.1.0' | Should -Be 1
+ Compare-Version '0.1.1.0' '0.1.1.1' | Should -Be 1
+ Compare-Version '0.1.1.1' '0.1.1.2' | Should -Be 1
+ Compare-Version '0.1.1.2' '0.2.0.0' | Should -Be 1
+ Compare-Version '0.2.0.0' '1.0.0.0' | Should -Be 1
+ }
- $res = compare_versions $a $b
+ It 'handles partial semver version differences' {
+ Compare-Version '1' '1.1' | Should -Be 1
+ Compare-Version '1' '1.0' | Should -Be 1
+ Compare-Version '1.1.0.0' '1.1' | Should -Be -1
+ Compare-Version '1.4' '1.3.0' | Should -Be -1
+ Compare-Version '1.4' '1.3.255.255' | Should -Be -1
+ Compare-Version '1.4' '1.4.4' | Should -Be 1
+ Compare-Version '1.1.1_8' '1.1.1' | Should -Be -1
+ Compare-Version '1.1.1_8' '1.1.1_9' | Should -Be 1
+ Compare-Version '1.1.1_10' '1.1.1_9' | Should -Be -1
+ Compare-Version '1.1.1b' '1.1.1a' | Should -Be -1
+ Compare-Version '1.1.1a' '1.1.1b' | Should -Be 1
+ Compare-Version '1.1a2' '1.1a3' | Should -Be 1
+ Compare-Version '1.1.1a10' '1.1.1b1' | Should -Be 1
+ }
- $res | should be -1
+ It 'handles dash-style versions' {
+ Compare-Version '1.8.9' '1.8.5-1' | Should -Be -1
+ Compare-Version '7.0.4-9' '7.0.4-10' | Should -Be 1
+ Compare-Version '7.0.4-9' '7.0.4-8' | Should -Be -1
+ Compare-Version '2019-01-01' '2019-01-02' | Should -Be 1
+ Compare-Version '2019-01-02' '2019-01-01' | Should -Be -1
+ Compare-Version '2018-01-01' '2019-01-01' | Should -Be 1
+ Compare-Version '2019-01-01' '2018-01-01' | Should -Be -1
+ }
+ It 'handles post-release tagging ("+")' {
+ Compare-Version '1' '1+hotfix.0' | Should -Be 1
+ Compare-Version '1.0.0' '1.0.0+hotfix.0' | Should -Be 1
+ Compare-Version '1.0.0+hotfix.0' '1.0.0+hotfix.1' | Should -Be 1
+ Compare-Version '1.0.0+hotfix.1' '1.0.1' | Should -Be 1
+ Compare-Version '1.0.0+1.1' '1.0.0+1' | Should -Be -1
+ }
}
- it 'handles comparsion against en empty string' {
- compare_versions '7.0.4-9' '' | should be 1
- }
+ Context 'other misc versions' {
+ It 'handles plain text string' {
+ Compare-Version 'latest' '20150405' | Should -Be -1
+ Compare-Version '0.5alpha' '0.5' | Should -Be 1
+ Compare-Version '0.5' '0.5Beta' | Should -Be -1
+ Compare-Version '0.4' '0.5Beta' | Should -Be 1
+ }
+
+ It 'handles empty string' {
+ Compare-Version '7.0.4-9' '' | Should -Be -1
+ }
+
+ 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 equal versions' {
- compare_versions '12.0' '12.0' | 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
+ }
}
}
diff --git a/test/bin/init.ps1 b/test/bin/init.ps1
new file mode 100644
index 0000000000..14e32d2a6b
--- /dev/null
+++ b/test/bin/init.ps1
@@ -0,0 +1,21 @@
+#Requires -Version 5.1
+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-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-Output 'PSScriptAnalyzer is already installed.'
+} else {
+ 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-Output 'BuildHelpers is already installed.'
+} else {
+ Write-Output 'Installing BuildHelpers ...'
+ Install-Module -Repository PSGallery -Scope CurrentUser -Force -Name BuildHelpers -SkipPublisherCheck
+}
diff --git a/test/bin/test.ps1 b/test/bin/test.ps1
new file mode 100644
index 0000000000..a25940ccb9
--- /dev/null
+++ b/test/bin/test.ps1
@@ -0,0 +1,103 @@
+#Requires -Version 5.1
+#Requires -Modules @{ ModuleName = 'BuildHelpers'; ModuleVersion = '2.0.1' }
+#Requires -Modules @{ ModuleName = 'Pester'; ModuleVersion = '5.2.0' }
+#Requires -Modules @{ ModuleName = 'PSScriptAnalyzer'; ModuleVersion = '1.17.1' }
+param(
+ [String] $TestPath = (Convert-Path "$PSScriptRoot\..")
+)
+
+$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
+
+ # Check if tests are called from the Core itself, if so, adding excludes
+ if ($TestPath -eq (Convert-Path "$PSScriptRoot\..")) {
+ if ($env:BHCommitMessage -match '!linter') {
+ Write-Warning "Skipping code linting per commit flag '!linter'"
+ $excludes += 'Linter'
+ }
+
+ $changedScripts = (Get-GitChangedFile -Include '*.ps1', '*.psd1', '*.psm1' -Commit $env:BHCommitHash)
+ if (!$changedScripts) {
+ Write-Warning "Skipping tests and code linting for PowerShell scripts because they didn't change"
+ $excludes += 'Linter'
+ $excludes += 'Scoop'
+ }
+
+ if (!($changedScripts -like '*decompress.ps1') -and !($changedScripts -like '*Decompress.Tests.ps1')) {
+ Write-Warning "Skipping tests and code linting for decompress.ps1 files because it didn't change"
+ $excludes += 'Decompress'
+ }
+
+ 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 | Out-Null
+ }
+
+ $env:SCOOP_LESSMSI_PATH = "$env:SCOOP_HELPERS_PATH\lessmsi\lessmsi.exe"
+ if (!(Test-Path $env:SCOOP_LESSMSI_PATH)) {
+ $source = 'https://github.com/activescott/lessmsi/releases/download/v1.10.0/lessmsi-v1.10.0.zip'
+ $destination = "$env:SCOOP_HELPERS_PATH\lessmsi.zip"
+ Invoke-WebRequest -Uri $source -OutFile $destination
+ & 7z.exe x "$env:SCOOP_HELPERS_PATH\lessmsi.zip" -o"$env:SCOOP_HELPERS_PATH\lessmsi" -y | Out-Null
+ }
+
+ $env:SCOOP_INNOUNP_PATH = "$env:SCOOP_HELPERS_PATH\innounp\innounp.exe"
+ if (!(Test-Path $env:SCOOP_INNOUNP_PATH)) {
+ $source = 'https://raw.githubusercontent.com/ScoopInstaller/Binary/master/innounp/innounp050.rar'
+ $destination = "$env:SCOOP_HELPERS_PATH\innounp.rar"
+ Invoke-WebRequest -Uri $source -OutFile $destination
+ & 7z.exe x "$env:SCOOP_HELPERS_PATH\innounp.rar" -o"$env:SCOOP_HELPERS_PATH\innounp" -y | Out-Null
+ }
+ }
+ }
+
+ # Display CI environment variables
+ $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' |
+ Format-Table -AutoSize -Property 'Name', 'Value' |
+ Out-String
+ Write-Host 'CI variables:'
+ Write-Host $details -ForegroundColor DarkGray
+}
+
+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
diff --git a/test/fixtures/decompress/TestCases.zip b/test/fixtures/decompress/TestCases.zip
new file mode 100644
index 0000000000..fb2092e56c
Binary files /dev/null and b/test/fixtures/decompress/TestCases.zip differ
diff --git a/test/fixtures/format/formatted/1-easy.json b/test/fixtures/format/formatted/1-easy.json
new file mode 100644
index 0000000000..b1422eb555
--- /dev/null
+++ b/test/fixtures/format/formatted/1-easy.json
@@ -0,0 +1,3 @@
+{
+ "bin": "single"
+}
diff --git a/test/fixtures/format/formatted/2-whitespaces-mess.json b/test/fixtures/format/formatted/2-whitespaces-mess.json
new file mode 100644
index 0000000000..e69fd91582
--- /dev/null
+++ b/test/fixtures/format/formatted/2-whitespaces-mess.json
@@ -0,0 +1,15 @@
+{
+ "version": "0.5.18",
+ "url": "https://whatever",
+ "hash": "whatever",
+ "architecture": {
+ "64bit": {
+ "installer": {
+ "script": [
+ "Do something",
+ "cosi"
+ ]
+ }
+ }
+ }
+}
diff --git a/test/fixtures/format/formatted/3-array-with-single-and-multi.json b/test/fixtures/format/formatted/3-array-with-single-and-multi.json
new file mode 100644
index 0000000000..540701a6c2
--- /dev/null
+++ b/test/fixtures/format/formatted/3-array-with-single-and-multi.json
@@ -0,0 +1,61 @@
+{
+ "homepage": "http://www.7-zip.org/",
+ "description": "A multi-format file archiver with high compression ratios",
+ "license": {
+ "identifier": "LGPL-2.0-only,BSD-3-Clause",
+ "url": "https://www.7-zip.org/license.txt"
+ },
+ "version": "18.05",
+ "architecture": {
+ "64bit": {
+ "url": "https://7-zip.org/a/7z1805-x64.msi",
+ "hash": "898c1ca0015183fe2ba7d55cacf0a1dea35e873bf3f8090f362a6288c6ef08d7"
+ },
+ "32bit": {
+ "url": "https://7-zip.org/a/7z1805.msi",
+ "hash": "c554238bee18a03d736525e06d9258c9ecf7f64ead7c6b0d1eb04db2c0de30d0"
+ }
+ },
+ "extract_dir": "Files/7-Zip",
+ "bin": [
+ "single",
+ [
+ "7z.exe",
+ "cosi"
+ ],
+ [
+ "7z.exe",
+ "cosi",
+ "param",
+ "icon"
+ ],
+ [
+ "7z.exe",
+ "empty",
+ "",
+ ""
+ ],
+ "singtwo"
+ ],
+ "checkver": "Download 7-Zip ([\\d.]+)",
+ "autoupdate": {
+ "architecture": {
+ "64bit": {
+ "url": "https://7-zip.org/a/7z$cleanVersion-x64.msi"
+ },
+ "32bit": {
+ "url": "https://7-zip.org/a/7z$cleanVersion.msi"
+ }
+ }
+ },
+ "shortcuts": [
+ [
+ "7zFM.exe",
+ "7-Zip"
+ ],
+ [
+ "name with spaces.exe",
+ "Shortcut with spaces in name"
+ ]
+ ]
+}
diff --git a/test/fixtures/format/formatted/4-script-block.json b/test/fixtures/format/formatted/4-script-block.json
new file mode 100644
index 0000000000..ace916f850
--- /dev/null
+++ b/test/fixtures/format/formatted/4-script-block.json
@@ -0,0 +1,38 @@
+{
+ "version": "1.0.6",
+ "description": "Rambox Pro. Free, Open Source and Cross Platform messaging and emailing app that combines common web applications into one.",
+ "homepage": "https://rambox.pro/",
+ "url": "https://github.com/ramboxapp/download/releases/download/v1.0.6/RamboxPro-1.0.6-win.exe#/cosi.7z",
+ "hash": "sha512:f4a1b5e12ae15c9a1339fef56b0522b6619d6c23b0ab806f128841c2ba7ce9d9c997fea81f5bc4a24988aed672a4415ff353542535dc7869b5e496f2f1e1efff",
+ "extract_dir": "\\$PLUGINSDIR",
+ "pre_install": "Get-ChildItem \"$dir\" -Exclude 'app-64.7z', 'app-32.7z' | Remove-Item -Force -Recurse",
+ "architecture": {
+ "64bit": {
+ "installer": {
+ "script": "Expand-7zipArchive \"$dir\\app-64.7z\" \"$dir\""
+ }
+ },
+ "32bit": {
+ "installer": {
+ "script": "Expand-7zipArchive \"$dir\\app-32.7z\" \"$dir\""
+ }
+ }
+ },
+ "post_install": "Remove-Item \"$dir\\app-64.7z\", \"$dir\\app-32.7z\"",
+ "shortcuts": [
+ [
+ "RamboxPro.exe",
+ "RamboxPro"
+ ]
+ ],
+ "checkver": {
+ "github": "https://github.com/ramboxapp/download/"
+ },
+ "autoupdate": {
+ "url": "https://github.com/ramboxapp/download/releases/download/v$version/RamboxPro-$version-win.exe#/cosi.7z",
+ "hash": {
+ "url": "https://github.com/ramboxapp/download/releases/download/v$version/latest.yml",
+ "find": "sha512:\\s+(.*)"
+ }
+ }
+}
diff --git a/test/fixtures/format/unformatted/1-easy.json b/test/fixtures/format/unformatted/1-easy.json
new file mode 100644
index 0000000000..644fc5f3d4
--- /dev/null
+++ b/test/fixtures/format/unformatted/1-easy.json
@@ -0,0 +1 @@
+{ "bin": ["single"]}
diff --git a/test/fixtures/format/unformatted/2-whitespaces-mess.json b/test/fixtures/format/unformatted/2-whitespaces-mess.json
new file mode 100644
index 0000000000..5d9daa5beb
--- /dev/null
+++ b/test/fixtures/format/unformatted/2-whitespaces-mess.json
@@ -0,0 +1,16 @@
+{
+ "version": "0.5.18",
+ "url": "https://whatever",
+
+ "hash": "whatever",
+ "architecture": {
+ "64bit": { "installer": {
+
+ "script": [
+ "Do something" , "cosi"
+ ]
+ }
+ }
+ }
+}
+
diff --git a/test/fixtures/format/unformatted/3-array-with-single-and-multi.json b/test/fixtures/format/unformatted/3-array-with-single-and-multi.json
new file mode 100644
index 0000000000..33c9a20583
--- /dev/null
+++ b/test/fixtures/format/unformatted/3-array-with-single-and-multi.json
@@ -0,0 +1,59 @@
+{
+ "homepage": "http://www.7-zip.org/",
+ "description": "A multi-format file archiver with high compression ratios",
+ "license": {
+ "identifier": "LGPL-2.0-only,BSD-3-Clause",
+ "url": "https://www.7-zip.org/license.txt"
+ },
+ "version": "18.05",
+ "architecture": {
+ "64bit": {
+ "url": "https://7-zip.org/a/7z1805-x64.msi",
+ "hash": [
+ "898c1ca0015183fe2ba7d55cacf0a1dea35e873bf3f8090f362a6288c6ef08d7"
+ ]
+ },
+ "32bit": {
+ "url": "https://7-zip.org/a/7z1805.msi",
+ "hash": "c554238bee18a03d736525e06d9258c9ecf7f64ead7c6b0d1eb04db2c0de30d0"
+ }
+ },
+ "extract_dir": "Files/7-Zip",
+ "bin": [
+ [
+ "single"
+ ],
+ [
+ "7z.exe",
+ "cosi"
+ ],
+ [
+ "7z.exe",
+ "cosi",
+ "param",
+ "icon"
+ ],
+ [
+ "7z.exe",
+ "empty",
+ "",
+ ""
+ ],
+ [
+ "singtwo"
+ ]
+ ],
+ "checkver": "Download 7-Zip ([\\d.]+)",
+ "autoupdate": {
+ "architecture": {
+ "64bit": {
+ "url": "https://7-zip.org/a/7z$cleanVersion-x64.msi"
+ }, "32bit": {
+ "url": "https://7-zip.org/a/7z$cleanVersion.msi"
+ }
+ }
+ },
+ "shortcuts": [
+ [ "7zFM.exe",
+ "7-Zip"
+], ["name with spaces.exe", "Shortcut with spaces in name"] ]}
diff --git a/test/fixtures/format/unformatted/4-script-block.json b/test/fixtures/format/unformatted/4-script-block.json
new file mode 100644
index 0000000000..f02f33b171
--- /dev/null
+++ b/test/fixtures/format/unformatted/4-script-block.json
@@ -0,0 +1,42 @@
+{
+ "version": "1.0.6",
+ "description": "Rambox Pro. Free, Open Source and Cross Platform messaging and emailing app that combines common web applications into one.",
+ "homepage": "https://rambox.pro/",
+ "url": "https://github.com/ramboxapp/download/releases/download/v1.0.6/RamboxPro-1.0.6-win.exe#/cosi.7z",
+ "hash": "sha512:f4a1b5e12ae15c9a1339fef56b0522b6619d6c23b0ab806f128841c2ba7ce9d9c997fea81f5bc4a24988aed672a4415ff353542535dc7869b5e496f2f1e1efff",
+ "extract_dir": "\\$PLUGINSDIR",
+ "pre_install": ["Get-ChildItem \"$dir\" -Exclude 'app-64.7z', 'app-32.7z' | Remove-Item -Force -Recurse"],
+ "architecture": {
+ "64bit": {
+ "installer": {
+ "script": [
+ "Expand-7zipArchive \"$dir\\app-64.7z\" \"$dir\""
+ ]
+ }
+ },
+ "32bit": {
+ "installer": {
+ "script": [
+ "Expand-7zipArchive \"$dir\\app-32.7z\" \"$dir\""
+ ]
+ }
+ }
+ },
+ "post_install": ["Remove-Item \"$dir\\app-64.7z\", \"$dir\\app-32.7z\""],
+ "shortcuts": [
+ [
+ "RamboxPro.exe",
+ "RamboxPro"
+ ]
+ ],
+ "checkver": {
+ "github": "https://github.com/ramboxapp/download/"
+ },
+ "autoupdate": {
+ "url": "https://github.com/ramboxapp/download/releases/download/v$version/RamboxPro-$version-win.exe#/cosi.7z",
+ "hash": {
+ "url": "https://github.com/ramboxapp/download/releases/download/v$version/latest.yml",
+ "find": "sha512:\\s+(.*)"
+ }
+ }
+}
diff --git a/test/fixtures/unzip_old/small.zip b/test/fixtures/unzip_old/small.zip
deleted file mode 100644
index 09e3f8bd9a..0000000000
Binary files a/test/fixtures/unzip_old/small.zip and /dev/null differ
diff --git a/test/fixtures/unzip_old/zerobyte.zip b/test/fixtures/unzip_old/zerobyte.zip
deleted file mode 100644
index e69de29bb2..0000000000