mirror of
https://github.com/ScoopInstaller/Scoop.git
synced 2025-11-28 04:13:30 +00:00
Compare commits
44 Commits
rasa/sandb
...
feat-iec
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea37a9ef63 | ||
|
|
fb3169629f | ||
|
|
7e81e49152 | ||
|
|
7b35e19d4c | ||
|
|
6cdcc75ad8 | ||
|
|
14b38b4092 | ||
|
|
2847e0a37c | ||
|
|
3a3f41c556 | ||
|
|
15f9bbec97 | ||
|
|
ab34b7fb61 | ||
|
|
863af42d4e | ||
|
|
b3c05e71fa | ||
|
|
acc271d115 | ||
|
|
6d79d62cc8 | ||
|
|
00c92b04d6 | ||
|
|
becc7a7b76 | ||
|
|
6898773a8d | ||
|
|
353137f0a9 | ||
|
|
43579714cc | ||
|
|
aa09601503 | ||
|
|
6a35a22b0b | ||
|
|
0b4919ca32 | ||
|
|
efdd6dd7ca | ||
|
|
3dfb4bfd97 | ||
|
|
1d140585a4 | ||
|
|
52059ca1ac | ||
|
|
cddc52e03b | ||
|
|
682a1e2c07 | ||
|
|
2accaae5d1 | ||
|
|
a20bb4f1a6 | ||
|
|
ad0f6178d0 | ||
|
|
41620bb169 | ||
|
|
559c6f9e64 | ||
|
|
7826d6fe2d | ||
|
|
8acfeeefcf | ||
|
|
c00dd42cae | ||
|
|
3f11454a3c | ||
|
|
0a39de86e2 | ||
|
|
c44e214743 | ||
|
|
7c6aeb240e | ||
|
|
32ca856f63 | ||
|
|
1d0bd434ab | ||
|
|
54e3613fca | ||
|
|
e2558ace75 |
8
.github/dependabot.yml
vendored
Normal file
8
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
# ~/.github/dependabot.yml
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/" # == /.github/workflows/
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
52
CHANGELOG.md
52
CHANGELOG.md
@@ -3,22 +3,71 @@
|
|||||||
### Features
|
### Features
|
||||||
|
|
||||||
- **scoop-update:** Add support for parallel syncing buckets in PowerShell 7 and improve output ([#5122](https://github.com/ScoopInstaller/Scoop/issues/5122))
|
- **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))
|
||||||
|
- **config:** Support portable config file ([#5369](https://github.com/ScoopInstaller/Scoop/issues/5369))
|
||||||
|
- **bucket:** Make official buckets higher priority ([#5398](https://github.com/ScoopInstaller/Scoop/issues/5398))
|
||||||
|
- **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))
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **shim:** Remove console window for GUI applications ([#5559](https://github.com/ScoopInstaller/Scoop/issues/5559))
|
||||||
- **decompress:** Exclude '*.nsis' that may cause error ([#5294](https://github.com/ScoopInstaller/Scoop/issues/5294))
|
- **decompress:** Exclude '*.nsis' that may cause error ([#5294](https://github.com/ScoopInstaller/Scoop/issues/5294))
|
||||||
- **autoupdate:** Fix file hash extraction ([#5295](https://github.com/ScoopInstaller/Scoop/issues/5295))
|
- **autoupdate:** Fix file hash extraction ([#5295](https://github.com/ScoopInstaller/Scoop/issues/5295))
|
||||||
|
- **getopt:** Stop split arguments in `getopt()` and ensure array by explicit arguments type ([#5326](https://github.com/ScoopInstaller/Scoop/issues/5326))
|
||||||
- **shortcuts:** Output correctly formatted path ([#5333](https://github.com/ScoopInstaller/Scoop/issues/5333))
|
- **shortcuts:** Output correctly formatted path ([#5333](https://github.com/ScoopInstaller/Scoop/issues/5333))
|
||||||
|
- **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/pull/5436))
|
||||||
|
- **core:** Handle scoop aliases and broken(edited,copied) shim ([#5551](https://github.com/ScoopInstaller/Scoop/issues/5551))
|
||||||
|
- **env:** Avoid automatic expansion of `%%` in env ([#5395](https://github.com/ScoopInstaller/Scoop/issues/5395), [#5452](https://github.com/ScoopInstaller/Scoop/pull/5452), [#5631](https://github.com/ScoopInstaller/Scoop/pull/5631))
|
||||||
|
- **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))
|
||||||
|
- **scoop-info:** Fix errors in file size collection when `--verbose` ([#5352](https://github.com/ScoopInstaller/Scoop/pull/5352))
|
||||||
|
- **shim:** Use bash executable directly ([#5433](https://github.com/ScoopInstaller/Scoop/issues/5433))
|
||||||
|
- **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))
|
||||||
|
- **scoop-checkup:** Skip defender check in Windows Sandbox ([#5519](https://github.com/ScoopInstaller/Scoop/issues/5519))
|
||||||
|
- **buckets:** Avoid error messages for unexpected dir ([#5549](https://github.com/ScoopInstaller/Scoop/issues/5549))
|
||||||
|
- **scoop-virustotal:** Fix `scoop-virustotal` when `--all` has been passed without app ([#5593](https://github.com/ScoopInstaller/Scoop/pull/5593))
|
||||||
|
- **scoop-checkup:** Change the message level of helpers from ERROR to WARN ([#5549](https://github.com/ScoopInstaller/Scoop/issues/5614))
|
||||||
|
- **scoop-(un)hold:** Correct output the messages when manifest not found, (already|not) held ([#5519](https://github.com/ScoopInstaller/Scoop/issues/5519))
|
||||||
|
- **scoop-update:** Change error message to a better instruction ([#5677](https://github.com/ScoopInstaller/Scoop/issues/5677))
|
||||||
|
- **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))
|
||||||
|
- **scoop-reset:** Don't abort when multiple apps are passed and an app is running ([#5687](https://github.com/ScoopInstaller/Scoop/issues/5687))
|
||||||
|
- **core:** Do not call `scoop` externally from inside the code ([#5695](https://github.com/ScoopInstaller/Scoop/issues/5695))
|
||||||
|
- **scoop-checkup:** Don't throw 7zip error when external 7zip is used ([#5703](https://github.com/ScoopInstaller/Scoop/issues/5703))
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
- **decompress:** Disable progress bar to improve `Expand-Archive` performance ([#5410](https://github.com/ScoopInstaller/Scoop/issues/5410))
|
||||||
|
- **scoop-search:** Improve performance for local search ([#5324](https://github.com/ScoopInstaller/Scoop/issues/5324))
|
||||||
|
|
||||||
### Code Refactoring
|
### Code Refactoring
|
||||||
|
|
||||||
- **git:** Use Invoke-Git() with direct path to git.exe to prevent spawning shim subprocesses ([#5122](https://github.com/ScoopInstaller/Scoop/issues/5122))
|
- **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))
|
||||||
- **scoop-download:** Output more detailed manifest information ([#5277](https://github.com/ScoopInstaller/Scoop/issues/5277))
|
- **scoop-download:** Output more detailed manifest information ([#5277](https://github.com/ScoopInstaller/Scoop/issues/5277))
|
||||||
|
|
||||||
|
### Builds
|
||||||
|
|
||||||
|
- **checkver:** Read the private_host config variable ([#5381](https://github.com/ScoopInstaller/Scoop/issues/5381))
|
||||||
|
|
||||||
|
### Continuous Integration
|
||||||
|
|
||||||
|
- **dependabot:** Add dependabot.yml for GitHub Actions ([#5377](https://github.com/ScoopInstaller/Scoop/pull/5377))
|
||||||
|
|
||||||
### Tests
|
### Tests
|
||||||
|
|
||||||
- **bucket:** Skip manifest validation if no manifest changes ([#5270](https://github.com/ScoopInstaller/Scoop/issues/5270))
|
- **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
|
## [v0.3.1](https://github.com/ScoopInstaller/Scoop/compare/v0.3.0...v0.3.1) - 2022-11-15
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
@@ -35,6 +84,7 @@
|
|||||||
- **shim:** Exit if shim creating failed 'cause no git ([#5225](https://github.com/ScoopInstaller/Scoop/issues/5225))
|
- **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-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))
|
- **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
|
### Code Refactoring
|
||||||
|
|
||||||
|
|||||||
103
README.md
103
README.md
@@ -1,17 +1,17 @@
|
|||||||
<p align="center">
|
<h1 align="center">Scoop</h1>
|
||||||
|
|
||||||
<!--<img src="scoop.png" alt="Long live Scoop!"/>-->
|
<!--<img src="scoop.png" alt="Long live Scoop!"/>-->
|
||||||
<h1 align="center">Scoop</h1>
|
|
||||||
</p>
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<b><a href="https://github.com/ScoopInstaller/Scoop#what-does-scoop-do">Features</a></b>
|
<a href="https://github.com/ScoopInstaller/Scoop#what-does-scoop-do">Features</a>
|
||||||
|
|
|
|
||||||
<b><a href="https://github.com/ScoopInstaller/Scoop#installation">Installation</a></b>
|
<a href="https://github.com/ScoopInstaller/Scoop#installation">Installation</a>
|
||||||
|
|
|
|
||||||
<b><a href="https://github.com/ScoopInstaller/Scoop/wiki">Documentation</a></b>
|
<a href="https://github.com/ScoopInstaller/Scoop/wiki">Documentation</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
- - -
|
---
|
||||||
<p align="center" >
|
|
||||||
|
<p align="center">
|
||||||
<a href="https://github.com/ScoopInstaller/Scoop">
|
<a href="https://github.com/ScoopInstaller/Scoop">
|
||||||
<img src="https://img.shields.io/github/languages/code-size/ScoopInstaller/Scoop.svg" alt="Code Size" />
|
<img src="https://img.shields.io/github/languages/code-size/ScoopInstaller/Scoop.svg" alt="Code Size" />
|
||||||
</a>
|
</a>
|
||||||
@@ -36,43 +36,48 @@ Scoop is a command-line installer for Windows.
|
|||||||
|
|
||||||
## What does Scoop do?
|
## What does Scoop do?
|
||||||
|
|
||||||
Scoop installs programs from the command line with a minimal amount of friction. It:
|
Scoop installs apps from the command line with a minimal amount of friction. It:
|
||||||
|
|
||||||
- Eliminates permission popup windows
|
- Eliminates [User Account Control](https://learn.microsoft.com/windows/security/application-security/application-control/user-account-control/) (UAC) prompt notifications.
|
||||||
- Hides GUI wizard-style installers
|
- Hides the graphical user interface (GUI) of wizard-style installers.
|
||||||
- Prevents PATH pollution from installing lots of programs
|
- 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 programs
|
- Avoids unexpected side effects from installing and uninstalling apps.
|
||||||
- Finds and installs dependencies automatically
|
- Resolves and installs dependencies automatically.
|
||||||
- Performs all the extra setup steps itself to get a working program
|
- Performs all the necessary steps to get an app to a working state.
|
||||||
|
|
||||||
Scoop is very scriptable, so you can run repeatable setups to get your environment just the way you like, e.g.:
|
Scoop is quite script-friendly. Your environment can become the way you like by using repeatable setups. For example:
|
||||||
|
|
||||||
```powershell
|
```console
|
||||||
scoop install sudo
|
scoop install sudo
|
||||||
sudo scoop install 7zip git openssh --global
|
sudo scoop install 7zip git openssh --global
|
||||||
scoop install aria2 curl grep sed less touch
|
scoop install aria2 curl grep sed less touch
|
||||||
scoop install python ruby go perl
|
scoop install python ruby go perl
|
||||||
```
|
```
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Run the following command from a **non-admin** PowerShell to install scoop to its default location `C:\Users\<YOUR USERNAME>\scoop`.
|
Run the following commands from a regular (non-admin) PowerShell terminal to install Scoop:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
iwr -useb get.scoop.sh | iex
|
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
|
||||||
|
Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression
|
||||||
```
|
```
|
||||||
|
|
||||||
Advanced installation instruction and full documentation of the installer are available in [ScoopInstaller/Install](https://github.com/ScoopInstaller/Install). Please create new issues there if you have questions about the installation.
|
**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.
|
||||||
|
|
||||||
## [Documentation](https://github.com/ScoopInstaller/Scoop/wiki)
|
It will install Scoop to its default location:
|
||||||
|
|
||||||
|
`C:\Users\<YOUR USERNAME>\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`
|
## 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.
|
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.
|
||||||
|
|
||||||
```powershell
|
```console
|
||||||
scoop install aria2
|
scoop install aria2
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -90,54 +95,54 @@ You can tweak the following `aria2` settings with the `scoop config` command:
|
|||||||
|
|
||||||
## Inspiration
|
## Inspiration
|
||||||
|
|
||||||
- [Homebrew](http://mxcl.github.io/homebrew/)
|
- [Homebrew](https://brew.sh/)
|
||||||
- [sub](https://github.com/37signals/sub#readme)
|
- [Sub](https://signalvnoise.com/posts/3264-automating-with-convention-introducing-sub)
|
||||||
|
|
||||||
## What sort of apps can Scoop install?
|
## What sort of apps can Scoop install?
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
Since installers are common, Scoop supports them too (and their uninstallers).
|
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.
|
||||||
|
|
||||||
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/ScoopInstaller/Main/blob/master/bucket/runat.json) package for an example: it's really just a GitHub gist.
|
|
||||||
|
|
||||||
### Contribute to this project
|
### Contribute to this project
|
||||||
|
|
||||||
If you'd 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).
|
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
|
### Support this project
|
||||||
|
|
||||||
If you find Scoop useful and would like to support ongoing development and maintenance, here's how:
|
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 donation)
|
- [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=DM2SUH9EUXSKJ) (one-time donations)
|
||||||
|
|
||||||
## Known application buckets
|
## Known application buckets
|
||||||
|
|
||||||
The following buckets are known to scoop:
|
The following buckets are known to Scoop:
|
||||||
|
|
||||||
- [main](https://github.com/ScoopInstaller/Main) - Default bucket for the most common (mostly CLI) apps
|
- [main](https://github.com/ScoopInstaller/Main) - Default bucket which contains popular non-GUI apps.
|
||||||
- [extras](https://github.com/ScoopInstaller/Extras) - Apps that don't fit the main bucket's [criteria](https://github.com/ScoopInstaller/Scoop/wiki/Criteria-for-including-apps-in-the-main-bucket)
|
- [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/freeware games and game-related tools
|
- [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
|
- [nerd-fonts](https://github.com/matthewjberger/scoop-nerd-fonts) - Nerd Fonts.
|
||||||
- [nirsoft](https://github.com/kodybrown/scoop-nirsoft) - Almost all of the [250+](https://rasa.github.io/scoop-directory/by-apps#kodybrown_scoop-nirsoft) apps from [Nirsoft](https://nirsoft.net)
|
- [nirsoft](https://github.com/ScoopInstaller/Nirsoft) - A collection of over 250+ apps from [Nirsoft](https://nirsoft.net).
|
||||||
- [sysinternals](https://github.com/niheaven/scoop-sysinternals) - Sysinternals Suite and all individual application from [Microsoft](https://learn.microsoft.com/sysinternals/)
|
- [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), Java runtime engines (JREs), Java's virtual machine debugging tools and Java based runtime engines.
|
- [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 require UAC)
|
- [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
|
- [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
|
- [versions](https://github.com/ScoopInstaller/Versions) - Alternative versions of apps found in other buckets.
|
||||||
|
|
||||||
The main bucket is installed by default. To add any of the other buckets, type:
|
The `main` bucket is installed by default. You can make use of more buckets by typing:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
scoop bucket add bucketname
|
scoop bucket add <name>
|
||||||
```
|
```
|
||||||
|
|
||||||
For example, to add the extras bucket, type:
|
For example, to add the `extras` bucket, type:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
scoop bucket add extras
|
scoop bucket add extras
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You would be able to install apps from the `extras` bucket now.
|
||||||
|
|
||||||
## Other application buckets
|
## Other application buckets
|
||||||
|
|
||||||
Many other application buckets hosted on Github can be found in the [Scoop Directory](https://rasa.github.io/scoop-directory/) or via [other search engines](https://rasa.github.io/scoop-directory/#other-search-engines).
|
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).
|
||||||
|
|||||||
@@ -226,15 +226,21 @@ $Queue | ForEach-Object {
|
|||||||
$url = substitute $url $substitutions
|
$url = substitute $url $substitutions
|
||||||
|
|
||||||
$state = New-Object psobject @{
|
$state = New-Object psobject @{
|
||||||
app = $name;
|
app = $name
|
||||||
file = $file;
|
file = $file
|
||||||
url = $url;
|
url = $url
|
||||||
regex = $regex;
|
regex = $regex
|
||||||
json = $json;
|
json = $json
|
||||||
jsonpath = $jsonpath;
|
jsonpath = $jsonpath
|
||||||
xpath = $xpath;
|
xpath = $xpath
|
||||||
reverse = $reverse;
|
reverse = $reverse
|
||||||
replace = $replace;
|
replace = $replace
|
||||||
|
}
|
||||||
|
|
||||||
|
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.Headers.Add('Referer', (strip_filename $url))
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"main": "https://github.com/ScoopInstaller/Main",
|
"main": "https://github.com/ScoopInstaller/Main",
|
||||||
"extras": "https://github.com/ScoopInstaller/Extras",
|
"extras": "https://github.com/ScoopInstaller/Extras",
|
||||||
"versions": "https://github.com/ScoopInstaller/Versions",
|
"versions": "https://github.com/ScoopInstaller/Versions",
|
||||||
"nirsoft": "https://github.com/kodybrown/scoop-nirsoft",
|
"nirsoft": "https://github.com/ScoopInstaller/Nirsoft",
|
||||||
"sysinternals": "https://github.com/niheaven/scoop-sysinternals",
|
"sysinternals": "https://github.com/niheaven/scoop-sysinternals",
|
||||||
"php": "https://github.com/ScoopInstaller/PHP",
|
"php": "https://github.com/ScoopInstaller/PHP",
|
||||||
"nerd-fonts": "https://github.com/matthewjberger/scoop-nerd-fonts",
|
"nerd-fonts": "https://github.com/matthewjberger/scoop-nerd-fonts",
|
||||||
|
|||||||
@@ -58,10 +58,18 @@ function Get-LocalBucket {
|
|||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
List all local buckets.
|
List all local buckets.
|
||||||
#>
|
#>
|
||||||
$bucketNames = (Get-ChildItem -Path $bucketsdir -Directory).Name
|
$bucketNames = [System.Collections.Generic.List[String]](Get-ChildItem -Path $bucketsdir -Directory).Name
|
||||||
if ($null -eq $bucketNames) {
|
if ($null -eq $bucketNames) {
|
||||||
return @() # Return a zero-length list instead of $null.
|
return @() # Return a zero-length list instead of $null.
|
||||||
} else {
|
} 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
|
return $bucketNames
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,10 +108,10 @@ function list_buckets {
|
|||||||
$path = Find-BucketDirectory $_ -Root
|
$path = Find-BucketDirectory $_ -Root
|
||||||
if ((Test-Path (Join-Path $path '.git')) -and (Get-Command git -ErrorAction SilentlyContinue)) {
|
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.Source = Invoke-Git -Path $path -ArgumentList @('config', 'remote.origin.url')
|
||||||
$bucket.Updated = Invoke-Git -Path $path -ArgumentList @('log', "--format='%aD'", '-n', '1')
|
$bucket.Updated = Invoke-Git -Path $path -ArgumentList @('log', '--format=%aD', '-n', '1') | Get-Date
|
||||||
} else {
|
} else {
|
||||||
$bucket.Source = friendly_path $path
|
$bucket.Source = friendly_path $path
|
||||||
$bucket.Updated = (Get-Item "$path\bucket").LastWriteTime
|
$bucket.Updated = (Get-Item "$path\bucket" -ErrorAction SilentlyContinue).LastWriteTime
|
||||||
}
|
}
|
||||||
$bucket.Manifests = Get-ChildItem "$path\bucket" -Force -Recurse -ErrorAction SilentlyContinue |
|
$bucket.Manifests = Get-ChildItem "$path\bucket" -Force -Recurse -ErrorAction SilentlyContinue |
|
||||||
Measure-Object | Select-Object -ExpandProperty Count
|
Measure-Object | Select-Object -ExpandProperty Count
|
||||||
|
|||||||
378
lib/core.ps1
378
lib/core.ps1
@@ -1,3 +1,51 @@
|
|||||||
|
function Get-PESubsystem($filePath) {
|
||||||
|
try {
|
||||||
|
$fileStream = [System.IO.FileStream]::new($filePath, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read)
|
||||||
|
$binaryReader = [System.IO.BinaryReader]::new($fileStream)
|
||||||
|
|
||||||
|
$fileStream.Seek(0x3C, [System.IO.SeekOrigin]::Begin) | Out-Null
|
||||||
|
$peOffset = $binaryReader.ReadInt32()
|
||||||
|
|
||||||
|
$fileStream.Seek($peOffset, [System.IO.SeekOrigin]::Begin) | Out-Null
|
||||||
|
$fileHeaderOffset = $fileStream.Position
|
||||||
|
|
||||||
|
$fileStream.Seek(18, [System.IO.SeekOrigin]::Current) | Out-Null
|
||||||
|
$fileStream.Seek($fileHeaderOffset + 0x5C, [System.IO.SeekOrigin]::Begin) | Out-Null
|
||||||
|
|
||||||
|
return $binaryReader.ReadInt16()
|
||||||
|
} catch {
|
||||||
|
return -1
|
||||||
|
} finally {
|
||||||
|
$binaryReader.Close()
|
||||||
|
$fileStream.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Set-PESubsystem($filePath, $targetSubsystem) {
|
||||||
|
try {
|
||||||
|
$fileStream = [System.IO.FileStream]::new($filePath, [System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite)
|
||||||
|
$binaryReader = [System.IO.BinaryReader]::new($fileStream)
|
||||||
|
$binaryWriter = [System.IO.BinaryWriter]::new($fileStream)
|
||||||
|
|
||||||
|
$fileStream.Seek(0x3C, [System.IO.SeekOrigin]::Begin) | Out-Null
|
||||||
|
$peOffset = $binaryReader.ReadInt32()
|
||||||
|
|
||||||
|
$fileStream.Seek($peOffset, [System.IO.SeekOrigin]::Begin) | Out-Null
|
||||||
|
$fileHeaderOffset = $fileStream.Position
|
||||||
|
|
||||||
|
$fileStream.Seek(18, [System.IO.SeekOrigin]::Current) | Out-Null
|
||||||
|
$fileStream.Seek($fileHeaderOffset + 0x5C, [System.IO.SeekOrigin]::Begin) | Out-Null
|
||||||
|
|
||||||
|
$binaryWriter.Write([System.Int16] $targetSubsystem)
|
||||||
|
} catch {
|
||||||
|
return $false
|
||||||
|
} finally {
|
||||||
|
$binaryReader.Close()
|
||||||
|
$fileStream.Close()
|
||||||
|
}
|
||||||
|
return $true
|
||||||
|
}
|
||||||
|
|
||||||
function Optimize-SecurityProtocol {
|
function Optimize-SecurityProtocol {
|
||||||
# .NET Framework 4.7+ has a default security protocol called 'SystemDefault',
|
# .NET Framework 4.7+ has a default security protocol called 'SystemDefault',
|
||||||
# which allows the operating system to choose the best protocol to use.
|
# which allows the operating system to choose the best protocol to use.
|
||||||
@@ -145,41 +193,31 @@ function Invoke-Git {
|
|||||||
|
|
||||||
$proxy = get_config PROXY
|
$proxy = get_config PROXY
|
||||||
$git = Get-HelperPath -Helper Git
|
$git = Get-HelperPath -Helper Git
|
||||||
$arguments = $ArgumentList -join ' '
|
|
||||||
$cmd = "`"$git`" $arguments"
|
|
||||||
|
|
||||||
if ($WorkingDirectory) {
|
if ($WorkingDirectory) {
|
||||||
$cmd = "`"$git`" -C `"$WorkingDirectory`" $arguments"
|
$ArgumentList = @('-C', $WorkingDirectory) + $ArgumentList
|
||||||
}
|
}
|
||||||
$sb = [scriptblock]::Create("& $cmd")
|
|
||||||
|
|
||||||
if([String]::IsNullOrEmpty($proxy) -or $proxy -eq 'none') {
|
if([String]::IsNullOrEmpty($proxy) -or $proxy -eq 'none') {
|
||||||
return Invoke-Command $sb
|
return & $git @ArgumentList
|
||||||
}
|
}
|
||||||
|
|
||||||
if($arguments -Match '\b(clone|checkout|pull|fetch|ls-remote)\b') {
|
if($ArgumentList -Match '\b(clone|checkout|pull|fetch|ls-remote)\b') {
|
||||||
$old_https = $env:HTTPS_PROXY
|
$j = Start-Job -ScriptBlock {
|
||||||
$old_http = $env:HTTP_PROXY
|
|
||||||
try {
|
|
||||||
# convert proxy setting for git
|
# convert proxy setting for git
|
||||||
if ($proxy.StartsWith('currentuser@')) {
|
$proxy = $using:proxy
|
||||||
|
if ($proxy -and $proxy.StartsWith('currentuser@')) {
|
||||||
$proxy = $proxy.Replace('currentuser@', ':@')
|
$proxy = $proxy.Replace('currentuser@', ':@')
|
||||||
}
|
}
|
||||||
$env:HTTPS_PROXY = $proxy
|
$env:HTTPS_PROXY = $proxy
|
||||||
$env:HTTP_PROXY = $proxy
|
$env:HTTP_PROXY = $proxy
|
||||||
return Invoke-Command $sb
|
& $using:git @using:ArgumentList
|
||||||
}
|
|
||||||
catch {
|
|
||||||
error $_
|
|
||||||
return
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
$env:HTTPS_PROXY = $old_https
|
|
||||||
$env:HTTP_PROXY = $old_http
|
|
||||||
}
|
}
|
||||||
|
$o = $j | Receive-Job -Wait -AutoRemoveJob
|
||||||
|
return $o
|
||||||
}
|
}
|
||||||
|
|
||||||
return Invoke-Command $sb
|
return & $git @ArgumentList
|
||||||
}
|
}
|
||||||
|
|
||||||
function Invoke-GitLog {
|
function Invoke-GitLog {
|
||||||
@@ -198,7 +236,7 @@ function Invoke-GitLog {
|
|||||||
}
|
}
|
||||||
$Name = "%Cgreen$($Name.PadRight(12, ' ').Substring(0, 12))%Creset "
|
$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")
|
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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,6 +312,7 @@ function filesize($length) {
|
|||||||
function basedir($global) { if($global) { return $globaldir } $scoopdir }
|
function basedir($global) { if($global) { return $globaldir } $scoopdir }
|
||||||
function appsdir($global) { "$(basedir $global)\apps" }
|
function appsdir($global) { "$(basedir $global)\apps" }
|
||||||
function shimdir($global) { "$(basedir $global)\shims" }
|
function shimdir($global) { "$(basedir $global)\shims" }
|
||||||
|
function modulesdir($global) { "$(basedir $global)\modules" }
|
||||||
function appdir($app, $global) { "$(appsdir $global)\$app" }
|
function appdir($app, $global) { "$(appsdir $global)\$app" }
|
||||||
function versiondir($app, $version, $global) { "$(appdir $app $global)\$version" }
|
function versiondir($app, $version, $global) { "$(appdir $app $global)\$version" }
|
||||||
|
|
||||||
@@ -359,7 +398,7 @@ Function Test-CommandAvailable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Function Test-GitAvailable {
|
Function Test-GitAvailable {
|
||||||
Return [Boolean](Test-Path (Get-HelperPath -Helper Git) -ErrorAction Ignore)
|
return [Boolean](Get-HelperPath -Helper Git)
|
||||||
}
|
}
|
||||||
|
|
||||||
function Get-HelperPath {
|
function Get-HelperPath {
|
||||||
@@ -377,8 +416,8 @@ function Get-HelperPath {
|
|||||||
process {
|
process {
|
||||||
switch ($Helper) {
|
switch ($Helper) {
|
||||||
'Git' {
|
'Git' {
|
||||||
$internalgit = "$(versiondir 'git' 'current')\mingw64\bin\git.exe"
|
$internalgit = (Get-AppFilePath 'git' 'mingw64\bin\git.exe'), (Get-AppFilePath 'git' 'mingw32\bin\git.exe') | Where-Object { $_ -ne $null }
|
||||||
if (Test-Path $internalgit) {
|
if ($internalgit) {
|
||||||
$HelperPath = $internalgit
|
$HelperPath = $internalgit
|
||||||
} else {
|
} else {
|
||||||
$HelperPath = (Get-Command git -ErrorAction Ignore).Source
|
$HelperPath = (Get-Command git -ErrorAction Ignore).Source
|
||||||
@@ -426,7 +465,10 @@ function Get-CommandPath {
|
|||||||
} catch {
|
} catch {
|
||||||
return $null
|
return $null
|
||||||
}
|
}
|
||||||
$commandPath = if ($comm.Path -like "$userShims*" -or $comm.Path -like "$globalShims*") {
|
$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')
|
Get-ShimTarget ($comm.Path -replace '\.exe$', '.shim')
|
||||||
} elseif ($comm.CommandType -eq 'Application') {
|
} elseif ($comm.CommandType -eq 'Application') {
|
||||||
$comm.Source
|
$comm.Source
|
||||||
@@ -550,125 +592,233 @@ function is_local($path) {
|
|||||||
# operations
|
# operations
|
||||||
|
|
||||||
function run($exe, $arg, $msg, $continue_exit_codes) {
|
function run($exe, $arg, $msg, $continue_exit_codes) {
|
||||||
Show-DeprecatedWarning $MyInvocation 'Invoke-ExternalCommand'
|
Show-DeprecatedWarning $MyInvocation 'Start-ExternalProcess'
|
||||||
Invoke-ExternalCommand -FilePath $exe -ArgumentList $arg -Activity $msg -ContinueExitCodes $continue_exit_codes
|
Start-ExternalProcess -FilePath $exe -ArgumentList $arg -Prompt $msg -ContinueExitCodes $continue_exit_codes
|
||||||
}
|
}
|
||||||
|
|
||||||
function Invoke-ExternalCommand {
|
function Invoke-ExternalCommand {
|
||||||
[CmdletBinding(DefaultParameterSetName = "Default")]
|
[CmdletBinding(DefaultParameterSetName = 'Default')]
|
||||||
[OutputType([Boolean])]
|
[OutputType([Boolean])]
|
||||||
param (
|
param (
|
||||||
[Parameter(Mandatory = $true,
|
[Parameter(Mandatory = $true, Position = 0)]
|
||||||
Position = 0)]
|
[Alias('Path')]
|
||||||
[Alias("Path")]
|
|
||||||
[ValidateNotNullOrEmpty()]
|
[ValidateNotNullOrEmpty()]
|
||||||
[String]
|
[String]
|
||||||
$FilePath,
|
$FilePath,
|
||||||
[Parameter(Position = 1)]
|
[Parameter(Position = 1)]
|
||||||
[Alias("Args")]
|
[Alias('Args')]
|
||||||
[String[]]
|
[String[]]
|
||||||
$ArgumentList,
|
$ArgumentList,
|
||||||
[Parameter(ParameterSetName = "UseShellExecute")]
|
[Parameter(ParameterSetName = 'UseShellExecute')]
|
||||||
[Switch]
|
[Switch]
|
||||||
$RunAs,
|
$RunAs,
|
||||||
[Alias("Msg")]
|
[Parameter(ParameterSetName = 'UseShellExecute')]
|
||||||
|
[Switch]
|
||||||
|
$Quiet,
|
||||||
|
[Alias('Msg')]
|
||||||
[String]
|
[String]
|
||||||
$Activity,
|
$Activity,
|
||||||
[Alias("cec")]
|
[Alias('cec')]
|
||||||
[Hashtable]
|
[Hashtable]
|
||||||
$ContinueExitCodes,
|
$ContinueExitCodes,
|
||||||
[Parameter(ParameterSetName = "Default")]
|
[Parameter(ParameterSetName = 'Default')]
|
||||||
[Alias("Log")]
|
[Alias('Log')]
|
||||||
[String]
|
[String]
|
||||||
$LogPath
|
$LogPath
|
||||||
)
|
)
|
||||||
if ($Activity) {
|
Show-DeprecatedWarning $MyInvocation 'Start-ExternalProcess'
|
||||||
Write-Host "$Activity " -NoNewline
|
if ($RunAs) {
|
||||||
|
Start-ExternalProcess -FilePath $FilePath -ArgumentList $ArgumentList -Prompt $Activity -ContinueExitCodes $ContinueExitCodes -RunAs -Quiet:$Quiet
|
||||||
|
} else {
|
||||||
|
Start-ExternalProcess -FilePath $FilePath -ArgumentList $ArgumentList -Prompt $Activity -ContinueExitCodes $ContinueExitCodes -LogName $LogPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Start-ExternalProcess {
|
||||||
|
[CmdletBinding(DefaultParameterSetName = 'Default')]
|
||||||
|
[OutputType([Boolean])]
|
||||||
|
param (
|
||||||
|
[Parameter(Mandatory = $true, Position = 0)]
|
||||||
|
[Alias('PSPath', 'Path')]
|
||||||
|
[ValidateNotNullOrEmpty()]
|
||||||
|
[String]
|
||||||
|
$FilePath,
|
||||||
|
[Parameter(Position = 1)]
|
||||||
|
[Alias('Args')]
|
||||||
|
[String[]]
|
||||||
|
$ArgumentList,
|
||||||
|
[Parameter(ParameterSetName = 'Default')]
|
||||||
|
[String]
|
||||||
|
$WorkingDirectory,
|
||||||
|
[Parameter(ParameterSetName = 'UseShellExecute')]
|
||||||
|
[Switch]
|
||||||
|
$RunAs,
|
||||||
|
[Parameter(ParameterSetName = 'UseShellExecute')]
|
||||||
|
[Switch]
|
||||||
|
$Quiet,
|
||||||
|
[Alias('Msg')]
|
||||||
|
[String]
|
||||||
|
$Prompt,
|
||||||
|
[Alias('cec')]
|
||||||
|
[Hashtable]
|
||||||
|
$ContinueExitCodes,
|
||||||
|
[Parameter(ParameterSetName = 'Default')]
|
||||||
|
[Alias('EnvVar')]
|
||||||
|
[Hashtable]
|
||||||
|
$EnvironmentVariables,
|
||||||
|
[Parameter(ParameterSetName = 'Default')]
|
||||||
|
[Alias('LogPath')]
|
||||||
|
[String]
|
||||||
|
$LogName
|
||||||
|
)
|
||||||
|
if ($Prompt) {
|
||||||
|
Write-Host "$Prompt " -NoNewline
|
||||||
}
|
}
|
||||||
$Process = New-Object System.Diagnostics.Process
|
$Process = New-Object System.Diagnostics.Process
|
||||||
$Process.StartInfo.FileName = $FilePath
|
$Process.StartInfo.FileName = $FilePath
|
||||||
$Process.StartInfo.UseShellExecute = $false
|
$Process.StartInfo.UseShellExecute = $false
|
||||||
if ($LogPath) {
|
if ($LogName) {
|
||||||
if ($FilePath -match '^msiexec(.exe)?$') {
|
if ($FilePath -match '^msiexec(.exe)?$') {
|
||||||
$ArgumentList += "/lwe `"$LogPath`""
|
$ArgumentList += "/lwe `"$LogName`""
|
||||||
} else {
|
} else {
|
||||||
$redirectToLogFile = $true
|
$redirectToLogFile = $true
|
||||||
$Process.StartInfo.RedirectStandardOutput = $true
|
|
||||||
$Process.StartInfo.RedirectStandardError = $true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($RunAs) {
|
if ($RunAs) {
|
||||||
$Process.StartInfo.UseShellExecute = $true
|
$Process.StartInfo.UseShellExecute = $true
|
||||||
$Process.StartInfo.Verb = 'RunAs'
|
$Process.StartInfo.Verb = 'RunAs'
|
||||||
} else {
|
} else {
|
||||||
$Process.StartInfo.CreateNoWindow = $true
|
$Process.StartInfo.RedirectStandardOutput = $true
|
||||||
}
|
$Process.StartInfo.RedirectStandardError = $true
|
||||||
if ($FilePath -match '^((cmd|cscript|wscript|msiexec)(\.exe)?|.*\.(bat|cmd|js|vbs|wsf))$') {
|
if ($WorkingDirectory) {
|
||||||
$Process.StartInfo.Arguments = $ArgumentList -join ' '
|
$Process.StartInfo.WorkingDirectory = ensure $WorkingDirectory
|
||||||
} elseif ($Process.StartInfo.ArgumentList.Add) {
|
}
|
||||||
# ArgumentList is supported in PowerShell 6.1 and later (built on .NET Core 2.1+)
|
}
|
||||||
# ref-1: https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.processstartinfo.argumentlist?view=net-6.0
|
if ($Quiet) {
|
||||||
# ref-2: https://docs.microsoft.com/en-us/powershell/scripting/whats-new/differences-from-windows-powershell?view=powershell-7.2#net-framework-vs-net-core
|
$Process.StartInfo.UseShellExecute = $true
|
||||||
$ArgumentList | ForEach-Object { $Process.StartInfo.ArgumentList.Add($_) }
|
$Process.StartInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
|
||||||
} else {
|
}
|
||||||
# escape arguments manually in lower versions, refer to https://docs.microsoft.com/en-us/previous-versions/17w5ykft(v=vs.85)
|
if ($EnvironmentVariables) {
|
||||||
$escapedArgs = $ArgumentList | ForEach-Object {
|
$EnvironmentVariables.GetEnumerator() | ForEach-Object { $Process.StartInfo.EnvironmentVariables.Add($_.Key, $_.Value) }
|
||||||
# escape N consecutive backslash(es), which are followed by a double quote, to 2N consecutive ones
|
}
|
||||||
$s = $_ -replace '(\\+)"', '$1$1"'
|
if ($ArgumentList) {
|
||||||
# escape N consecutive backslash(es), which are at the end of the string, to 2N consecutive ones
|
if ($FilePath -match '^((cmd|cscript|wscript|msiexec)(\.exe)?|.*\.(bat|cmd|js|vbs|wsf))$') {
|
||||||
$s = $s -replace '(\\+)$', '$1$1'
|
$Process.StartInfo.Arguments = $ArgumentList -join ' '
|
||||||
# escape double quotes
|
} elseif ($Process.StartInfo.ArgumentList.Add) {
|
||||||
$s = $s -replace '"', '\"'
|
# ArgumentList is supported in PowerShell 6.1 and later (built on .NET Core 2.1+)
|
||||||
# quote the argument
|
# ref-1: https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.processstartinfo.argumentlist?view=net-6.0
|
||||||
"`"$s`""
|
# ref-2: https://docs.microsoft.com/en-us/powershell/scripting/whats-new/differences-from-windows-powershell?view=powershell-7.2#net-framework-vs-net-core
|
||||||
|
$ArgumentList | ForEach-Object { $Process.StartInfo.ArgumentList.Add($_) }
|
||||||
|
} else {
|
||||||
|
# escape arguments manually in lower versions, refer to https://docs.microsoft.com/en-us/previous-versions/17w5ykft(v=vs.85)
|
||||||
|
$escapedArgs = $ArgumentList | ForEach-Object {
|
||||||
|
# escape N consecutive backslash(es), which are followed by a double quote, to 2N consecutive ones
|
||||||
|
$s = $_ -replace '(\\+)"', '$1$1"'
|
||||||
|
# escape N consecutive backslash(es), which are at the end of the string, to 2N consecutive ones
|
||||||
|
$s = $s -replace '(\\+)$', '$1$1'
|
||||||
|
# escape double quotes
|
||||||
|
$s = $s -replace '"', '\"'
|
||||||
|
# quote the argument
|
||||||
|
"`"$s`""
|
||||||
|
}
|
||||||
|
$Process.StartInfo.Arguments = $escapedArgs -join ' '
|
||||||
}
|
}
|
||||||
$Process.StartInfo.Arguments = $escapedArgs -join ' '
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
[void]$Process.Start()
|
[void]$Process.Start()
|
||||||
} catch {
|
} catch {
|
||||||
if ($Activity) {
|
if ($Prompt) {
|
||||||
Write-Host "error." -ForegroundColor DarkRed
|
Write-Host 'error.' -ForegroundColor DarkRed
|
||||||
}
|
}
|
||||||
error $_.Exception.Message
|
error $_.Exception.Message
|
||||||
return $false
|
return $false
|
||||||
}
|
}
|
||||||
if ($redirectToLogFile) {
|
# we do this to remove a deadlock potential
|
||||||
# we do this to remove a deadlock potential
|
# ref: https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.process.standardoutput?view=netframework-4.5#remarks
|
||||||
# ref: https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.process.standardoutput?view=netframework-4.5#remarks
|
$stdoutTask = $Process.StandardOutput.ReadToEndAsync()
|
||||||
$stdoutTask = $Process.StandardOutput.ReadToEndAsync()
|
$stderrTask = $Process.StandardError.ReadToEndAsync()
|
||||||
$stderrTask = $Process.StandardError.ReadToEndAsync()
|
|
||||||
}
|
|
||||||
$Process.WaitForExit()
|
$Process.WaitForExit()
|
||||||
if ($redirectToLogFile) {
|
if ($redirectToLogFile) {
|
||||||
Out-UTF8File -FilePath $LogPath -Append -InputObject $stdoutTask.Result
|
Out-UTF8File -FilePath $LogName -Append -InputObject $stdoutTask.Result.Trim()
|
||||||
Out-UTF8File -FilePath $LogPath -Append -InputObject $stderrTask.Result
|
Out-UTF8File -FilePath $LogName -Append -InputObject $stderrTask.Result.Trim()
|
||||||
|
} else {
|
||||||
|
if ($stdoutTask.Result) {
|
||||||
|
$stdoutTask.Result.Trim() | Out-Default
|
||||||
|
}
|
||||||
|
if ($stderrTask.Result) {
|
||||||
|
$stderrTask.Result.Trim() | Out-Default
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ($Process.ExitCode -ne 0) {
|
if ($Process.ExitCode -ne 0) {
|
||||||
if ($ContinueExitCodes -and ($ContinueExitCodes.ContainsKey($Process.ExitCode))) {
|
if ($ContinueExitCodes -and ($ContinueExitCodes.ContainsKey($Process.ExitCode))) {
|
||||||
if ($Activity) {
|
if ($Prompt) {
|
||||||
Write-Host "done." -ForegroundColor DarkYellow
|
Write-Host 'done.' -ForegroundColor DarkYellow
|
||||||
}
|
}
|
||||||
warn $ContinueExitCodes[$Process.ExitCode]
|
warn $ContinueExitCodes[$Process.ExitCode]
|
||||||
return $true
|
return $true
|
||||||
} else {
|
} else {
|
||||||
if ($Activity) {
|
if ($Prompt) {
|
||||||
Write-Host "error." -ForegroundColor DarkRed
|
Write-Host 'error.' -ForegroundColor DarkRed
|
||||||
}
|
}
|
||||||
error "Exit code was $($Process.ExitCode)!"
|
error "Exit code was $($Process.ExitCode)!"
|
||||||
return $false
|
return $false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($Activity) {
|
if ($Prompt) {
|
||||||
Write-Host "done." -ForegroundColor Green
|
Write-Host 'done.' -ForegroundColor Green
|
||||||
}
|
}
|
||||||
return $true
|
return $true
|
||||||
}
|
}
|
||||||
|
|
||||||
function env($name,$global,$val='__get') {
|
function Publish-Env {
|
||||||
$target = 'User'; if($global) {$target = 'Machine'}
|
if (-not ("Win32.NativeMethods" -as [Type])) {
|
||||||
if($val -eq '__get') { [environment]::getEnvironmentVariable($name,$target) }
|
Add-Type -Namespace Win32 -Name NativeMethods -MemberDefinition @"
|
||||||
else { [environment]::setEnvironmentVariable($name,$val,$target) }
|
[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 env($name, $global, $val = '__get') {
|
||||||
|
$RegisterKey = if ($global) {
|
||||||
|
Get-Item -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager'
|
||||||
|
} else {
|
||||||
|
Get-Item -Path 'HKCU:'
|
||||||
|
}
|
||||||
|
$EnvRegisterKey = $RegisterKey.OpenSubKey('Environment', $val -ne '__get')
|
||||||
|
|
||||||
|
if ($val -eq '__get') {
|
||||||
|
$RegistryValueOption = [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames
|
||||||
|
$EnvRegisterKey.GetValue($name, $null, $RegistryValueOption)
|
||||||
|
} elseif ($val -eq $null) {
|
||||||
|
try { $EnvRegisterKey.DeleteValue($name) } catch { }
|
||||||
|
Publish-Env
|
||||||
|
} else {
|
||||||
|
$RegistryValueKind = if ($val.Contains('%')) {
|
||||||
|
[Microsoft.Win32.RegistryValueKind]::ExpandString
|
||||||
|
} elseif ($EnvRegisterKey.GetValue($name)) {
|
||||||
|
$EnvRegisterKey.GetValueKind($name)
|
||||||
|
} else {
|
||||||
|
[Microsoft.Win32.RegistryValueKind]::String
|
||||||
|
}
|
||||||
|
$EnvRegisterKey.SetValue($name, $val, $RegistryValueKind)
|
||||||
|
Publish-Env
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isFileLocked([string]$path) {
|
function isFileLocked([string]$path) {
|
||||||
@@ -752,7 +902,7 @@ function Get-ShimTarget($ShimPath) {
|
|||||||
if (!$shimTarget) {
|
if (!$shimTarget) {
|
||||||
$shimTarget = ((Select-String -Path $ShimPath -Pattern '[''"]([^@&]*?)[''"]' -AllMatches).Matches.Groups | Select-Object -Last 1).Value
|
$shimTarget = ((Select-String -Path $ShimPath -Pattern '[''"]([^@&]*?)[''"]' -AllMatches).Matches.Groups | Select-Object -Last 1).Value
|
||||||
}
|
}
|
||||||
$shimTarget | Convert-Path
|
$shimTarget | Convert-Path -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -784,10 +934,10 @@ function shim($path, $global, $name, $arg) {
|
|||||||
$shim = "$abs_shimdir\$($name.tolower())"
|
$shim = "$abs_shimdir\$($name.tolower())"
|
||||||
|
|
||||||
# convert to relative path
|
# convert to relative path
|
||||||
Push-Location $abs_shimdir
|
|
||||||
$relative_path = Resolve-Path -Relative $path
|
|
||||||
Pop-Location
|
|
||||||
$resolved_path = Convert-Path $path
|
$resolved_path = Convert-Path $path
|
||||||
|
Push-Location $abs_shimdir
|
||||||
|
$relative_path = Resolve-Path -Relative $resolved_path
|
||||||
|
Pop-Location
|
||||||
|
|
||||||
if ($path -match '\.(exe|com)$') {
|
if ($path -match '\.(exe|com)$') {
|
||||||
# for programs with no awareness of any shell
|
# for programs with no awareness of any shell
|
||||||
@@ -797,6 +947,12 @@ function shim($path, $global, $name, $arg) {
|
|||||||
if ($arg) {
|
if ($arg) {
|
||||||
Write-Output "args = $arg" | Out-UTF8File "$shim.shim" -Append
|
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 .bat, .cmd so they can be used by programs with no awareness of PSH
|
||||||
warn_on_overwrite "$shim.cmd" $path
|
warn_on_overwrite "$shim.cmd" $path
|
||||||
@@ -882,19 +1038,9 @@ function shim($path, $global, $name, $arg) {
|
|||||||
) -join "`n" | Out-UTF8File $shim -NoNewLine
|
) -join "`n" | Out-UTF8File $shim -NoNewLine
|
||||||
} else {
|
} else {
|
||||||
warn_on_overwrite "$shim.cmd" $path
|
warn_on_overwrite "$shim.cmd" $path
|
||||||
# find path to Git's bash so that batch scripts can run bash scripts
|
|
||||||
if (!(Get-CommandPath git)) {
|
|
||||||
error "Can't shim '$shim': 'git' is needed but not installed."
|
|
||||||
error "Please install git ('scoop install git') and try again."
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
$gitdir = (Get-Item (Get-CommandPath git) -ErrorAction:Stop).Directory.Parent
|
|
||||||
if ($gitdir.FullName -imatch 'mingw') {
|
|
||||||
$gitdir = $gitdir.Parent
|
|
||||||
}
|
|
||||||
@(
|
@(
|
||||||
"@rem $resolved_path",
|
"@rem $resolved_path",
|
||||||
"@`"$(Join-Path (Join-Path $gitdir.FullName 'bin') 'bash.exe')`" `"$resolved_path`" $arg %*"
|
"@bash `"$resolved_path`" $arg %*"
|
||||||
) -join "`r`n" | Out-UTF8File "$shim.cmd"
|
) -join "`r`n" | Out-UTF8File "$shim.cmd"
|
||||||
|
|
||||||
warn_on_overwrite $shim $path
|
warn_on_overwrite $shim $path
|
||||||
@@ -1300,10 +1446,33 @@ Optimize-SecurityProtocol
|
|||||||
# Load Scoop config
|
# Load Scoop config
|
||||||
$configHome = $env:XDG_CONFIG_HOME, "$env:USERPROFILE\.config" | Select-Object -First 1
|
$configHome = $env:XDG_CONFIG_HOME, "$env:USERPROFILE\.config" | Select-Object -First 1
|
||||||
$configFile = "$configHome\scoop\config.json"
|
$configFile = "$configHome\scoop\config.json"
|
||||||
|
# Check if it's the expected install path for scoop: <root>/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\<root>\config.json <- a reversed path
|
||||||
|
# Imagine `<root>/apps/scoop/current/` in a reversed format,
|
||||||
|
# and the directory tree:
|
||||||
|
#
|
||||||
|
# ```
|
||||||
|
# <root>:
|
||||||
|
# ├─apps
|
||||||
|
# ├─buckets
|
||||||
|
# ├─cache
|
||||||
|
# ├─persist
|
||||||
|
# ├─shims
|
||||||
|
# ├─config.json
|
||||||
|
# ```
|
||||||
|
$configPortablePath = fullpath "$coreRoot\..\..\..\config.json"
|
||||||
|
if (Test-Path $configPortablePath) {
|
||||||
|
$configFile = $configPortablePath
|
||||||
|
}
|
||||||
|
}
|
||||||
$scoopConfig = load_cfg $configFile
|
$scoopConfig = load_cfg $configFile
|
||||||
|
|
||||||
# NOTE Scoop config file migration. Remove this after 2023/6/30
|
# NOTE Scoop config file migration. Remove this after 2023/6/30
|
||||||
if ($scoopConfig) {
|
if ($scoopConfig -and $scoopConfig.PSObject.Properties.Name -contains 'lastUpdate') {
|
||||||
$newConfigNames = @{
|
$newConfigNames = @{
|
||||||
'lastUpdate' = 'last_update'
|
'lastUpdate' = 'last_update'
|
||||||
'SCOOP_REPO' = 'scoop_repo'
|
'SCOOP_REPO' = 'scoop_repo'
|
||||||
@@ -1321,19 +1490,14 @@ if ($scoopConfig) {
|
|||||||
$value = $scoopConfig.$($_.Key)
|
$value = $scoopConfig.$($_.Key)
|
||||||
$scoopConfig.PSObject.Properties.Remove($_.Key)
|
$scoopConfig.PSObject.Properties.Remove($_.Key)
|
||||||
$scoopConfig | Add-Member -MemberType NoteProperty -Name $_.Value -Value $value
|
$scoopConfig | Add-Member -MemberType NoteProperty -Name $_.Value -Value $value
|
||||||
if ($_.Key -eq 'lastUpdate') {
|
|
||||||
$scoopConfigChg = $true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($scoopConfigChg) { # Only save config file if there was a change
|
ConvertTo-Json $scoopConfig | Out-UTF8File -FilePath $configFile
|
||||||
ConvertTo-Json $scoopConfig | Out-UTF8File -FilePath $configFile
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
# END NOTE
|
# END NOTE
|
||||||
|
|
||||||
# Scoop root directory
|
# Scoop root directory
|
||||||
$scoopdir = $env:SCOOP, (get_config ROOT_PATH), "$([System.Environment]::GetFolderPath('UserProfile'))\scoop" | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -First 1
|
$scoopdir = $env:SCOOP, (get_config ROOT_PATH), (Resolve-Path "$PSScriptRoot\..\..\..\.."), "$([System.Environment]::GetFolderPath('UserProfile'))\scoop" | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -First 1
|
||||||
|
|
||||||
# Scoop global apps directory
|
# Scoop global apps directory
|
||||||
$globaldir = $env:SCOOP_GLOBAL, (get_config GLOBAL_PATH), "$([System.Environment]::GetFolderPath('CommonApplicationData'))\scoop" | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -First 1
|
$globaldir = $env:SCOOP_GLOBAL, (get_config GLOBAL_PATH), "$([System.Environment]::GetFolderPath('CommonApplicationData'))\scoop" | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -First 1
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ function Expand-7zipArchive {
|
|||||||
} else {
|
} else {
|
||||||
$7zPath = Get-HelperPath -Helper 7zip
|
$7zPath = Get-HelperPath -Helper 7zip
|
||||||
}
|
}
|
||||||
$LogPath = "$(Split-Path $Path)\7zip.log"
|
$LogName = "$(Split-Path $Path)\7zip.log"
|
||||||
$DestinationPath = $DestinationPath.TrimEnd('\')
|
$DestinationPath = $DestinationPath.TrimEnd('\')
|
||||||
$ArgList = @('x', $Path, "-o$DestinationPath", '-xr!*.nsis', '-y')
|
$ArgList = @('x', $Path, "-o$DestinationPath", '-xr!*.nsis', '-y')
|
||||||
$IsTar = ((strip_ext $Path) -match '\.tar$') -or ($Path -match '\.t[abgpx]z2?$')
|
$IsTar = ((strip_ext $Path) -match '\.tar$') -or ($Path -match '\.t[abgpx]z2?$')
|
||||||
@@ -42,22 +42,22 @@ function Expand-7zipArchive {
|
|||||||
'Skip' { $ArgList += '-aos' }
|
'Skip' { $ArgList += '-aos' }
|
||||||
'Rename' { $ArgList += '-aou' }
|
'Rename' { $ArgList += '-aou' }
|
||||||
}
|
}
|
||||||
$Status = Invoke-ExternalCommand $7zPath $ArgList -LogPath $LogPath
|
$Status = Start-ExternalProcess $7zPath $ArgList -LogName $LogName
|
||||||
if (!$Status) {
|
if (!$Status) {
|
||||||
abort "Failed to extract files from $Path.`nLog file:`n $(friendly_path $LogPath)`n$(new_issue_msg $app $bucket 'decompress error')"
|
abort "Failed to extract files from $Path.`nLog file:`n $(friendly_path $LogName)`n$(new_issue_msg $app $bucket 'decompress error')"
|
||||||
}
|
}
|
||||||
if (!$IsTar -and $ExtractDir) {
|
if (!$IsTar -and $ExtractDir) {
|
||||||
movedir "$DestinationPath\$ExtractDir" $DestinationPath | Out-Null
|
movedir "$DestinationPath\$ExtractDir" $DestinationPath | Out-Null
|
||||||
}
|
}
|
||||||
if (Test-Path $LogPath) {
|
if (Test-Path $LogName) {
|
||||||
Remove-Item $LogPath -Force
|
Remove-Item $LogName -Force
|
||||||
}
|
}
|
||||||
if ($IsTar) {
|
if ($IsTar) {
|
||||||
# Check for tar
|
# Check for tar
|
||||||
$Status = Invoke-ExternalCommand $7zPath @('l', $Path) -LogPath $LogPath
|
$Status = Start-ExternalProcess $7zPath @('l', $Path) -LogName $LogName
|
||||||
if ($Status) {
|
if ($Status) {
|
||||||
# get inner tar file name
|
# get inner tar file name
|
||||||
$TarFile = (Select-String -Path $LogPath -Pattern '[^ ]*tar$').Matches.Value
|
$TarFile = (Select-String -Path $LogName -Pattern '[^ ]*tar$').Matches.Value
|
||||||
Expand-7zipArchive -Path "$DestinationPath\$TarFile" -DestinationPath $DestinationPath -ExtractDir $ExtractDir -Removal
|
Expand-7zipArchive -Path "$DestinationPath\$TarFile" -DestinationPath $DestinationPath -ExtractDir $ExtractDir -Removal
|
||||||
} else {
|
} else {
|
||||||
abort "Failed to list files in $Path.`nNot a 7-Zip supported archive file."
|
abort "Failed to list files in $Path.`nNot a 7-Zip supported archive file."
|
||||||
@@ -95,7 +95,7 @@ function Expand-ZstdArchive {
|
|||||||
$Removal
|
$Removal
|
||||||
)
|
)
|
||||||
$ZstdPath = Get-HelperPath -Helper Zstd
|
$ZstdPath = Get-HelperPath -Helper Zstd
|
||||||
$LogPath = Join-Path (Split-Path $Path) 'zstd.log'
|
$LogName = Join-Path (Split-Path $Path) 'zstd.log'
|
||||||
$DestinationPath = $DestinationPath.TrimEnd('\')
|
$DestinationPath = $DestinationPath.TrimEnd('\')
|
||||||
ensure $DestinationPath | Out-Null
|
ensure $DestinationPath | Out-Null
|
||||||
$ArgList = @('-d', $Path, '--output-dir-flat', $DestinationPath, '-f', '-v')
|
$ArgList = @('-d', $Path, '--output-dir-flat', $DestinationPath, '-f', '-v')
|
||||||
@@ -107,16 +107,16 @@ function Expand-ZstdArchive {
|
|||||||
# Remove original archive file
|
# Remove original archive file
|
||||||
$ArgList += '--rm'
|
$ArgList += '--rm'
|
||||||
}
|
}
|
||||||
$Status = Invoke-ExternalCommand $ZstdPath $ArgList -LogPath $LogPath
|
$Status = Start-ExternalProcess $ZstdPath $ArgList -LogName $LogName
|
||||||
if (!$Status) {
|
if (!$Status) {
|
||||||
abort "Failed to extract files from $Path.`nLog file:`n $(friendly_path $LogPath)`n$(new_issue_msg $app $bucket 'decompress error')"
|
abort "Failed to extract files from $Path.`nLog file:`n $(friendly_path $LogName)`n$(new_issue_msg $app $bucket 'decompress error')"
|
||||||
}
|
}
|
||||||
$IsTar = (strip_ext $Path) -match '\.tar$'
|
$IsTar = (strip_ext $Path) -match '\.tar$'
|
||||||
if (!$IsTar -and $ExtractDir) {
|
if (!$IsTar -and $ExtractDir) {
|
||||||
movedir (Join-Path $DestinationPath $ExtractDir) $DestinationPath | Out-Null
|
movedir (Join-Path $DestinationPath $ExtractDir) $DestinationPath | Out-Null
|
||||||
}
|
}
|
||||||
if (Test-Path $LogPath) {
|
if (Test-Path $LogName) {
|
||||||
Remove-Item $LogPath -Force
|
Remove-Item $LogName -Force
|
||||||
}
|
}
|
||||||
if ($IsTar) {
|
if ($IsTar) {
|
||||||
# Check for tar
|
# Check for tar
|
||||||
@@ -154,13 +154,13 @@ function Expand-MsiArchive {
|
|||||||
$MsiPath = 'msiexec.exe'
|
$MsiPath = 'msiexec.exe'
|
||||||
$ArgList = @('/a', "`"$Path`"", '/qn', "TARGETDIR=`"$DestinationPath\SourceDir`"")
|
$ArgList = @('/a', "`"$Path`"", '/qn', "TARGETDIR=`"$DestinationPath\SourceDir`"")
|
||||||
}
|
}
|
||||||
$LogPath = "$(Split-Path $Path)\msi.log"
|
$LogName = "$(Split-Path $Path)\msi.log"
|
||||||
if ($Switches) {
|
if ($Switches) {
|
||||||
$ArgList += (-split $Switches)
|
$ArgList += (-split $Switches)
|
||||||
}
|
}
|
||||||
$Status = Invoke-ExternalCommand $MsiPath $ArgList -LogPath $LogPath
|
$Status = Start-ExternalProcess $MsiPath $ArgList -LogName $LogName
|
||||||
if (!$Status) {
|
if (!$Status) {
|
||||||
abort "Failed to extract files from $Path.`nLog file:`n $(friendly_path $LogPath)`n$(new_issue_msg $app $bucket 'decompress error')"
|
abort "Failed to extract files from $Path.`nLog file:`n $(friendly_path $LogName)`n$(new_issue_msg $app $bucket 'decompress error')"
|
||||||
}
|
}
|
||||||
if ($ExtractDir -and (Test-Path "$DestinationPath\SourceDir")) {
|
if ($ExtractDir -and (Test-Path "$DestinationPath\SourceDir")) {
|
||||||
movedir "$DestinationPath\SourceDir\$ExtractDir" $OriDestinationPath | Out-Null
|
movedir "$DestinationPath\SourceDir\$ExtractDir" $OriDestinationPath | Out-Null
|
||||||
@@ -174,8 +174,8 @@ function Expand-MsiArchive {
|
|||||||
if (($DestinationPath -ne (Split-Path $Path)) -and (Test-Path "$DestinationPath\$(fname $Path)")) {
|
if (($DestinationPath -ne (Split-Path $Path)) -and (Test-Path "$DestinationPath\$(fname $Path)")) {
|
||||||
Remove-Item "$DestinationPath\$(fname $Path)" -Force
|
Remove-Item "$DestinationPath\$(fname $Path)" -Force
|
||||||
}
|
}
|
||||||
if (Test-Path $LogPath) {
|
if (Test-Path $LogName) {
|
||||||
Remove-Item $LogPath -Force
|
Remove-Item $LogName -Force
|
||||||
}
|
}
|
||||||
if ($Removal) {
|
if ($Removal) {
|
||||||
# Remove original archive file
|
# Remove original archive file
|
||||||
@@ -200,7 +200,7 @@ function Expand-InnoArchive {
|
|||||||
[Switch]
|
[Switch]
|
||||||
$Removal
|
$Removal
|
||||||
)
|
)
|
||||||
$LogPath = "$(Split-Path $Path)\innounp.log"
|
$LogName = "$(Split-Path $Path)\innounp.log"
|
||||||
$ArgList = @('-x', "-d$DestinationPath", $Path, '-y')
|
$ArgList = @('-x', "-d$DestinationPath", $Path, '-y')
|
||||||
switch -Regex ($ExtractDir) {
|
switch -Regex ($ExtractDir) {
|
||||||
'^[^{].*' { $ArgList += "-c{app}\$ExtractDir" }
|
'^[^{].*' { $ArgList += "-c{app}\$ExtractDir" }
|
||||||
@@ -210,12 +210,12 @@ function Expand-InnoArchive {
|
|||||||
if ($Switches) {
|
if ($Switches) {
|
||||||
$ArgList += (-split $Switches)
|
$ArgList += (-split $Switches)
|
||||||
}
|
}
|
||||||
$Status = Invoke-ExternalCommand (Get-HelperPath -Helper Innounp) $ArgList -LogPath $LogPath
|
$Status = Start-ExternalProcess (Get-HelperPath -Helper Innounp) $ArgList -LogName $LogName
|
||||||
if (!$Status) {
|
if (!$Status) {
|
||||||
abort "Failed to extract files from $Path.`nLog file:`n $(friendly_path $LogPath)`n$(new_issue_msg $app $bucket 'decompress error')"
|
abort "Failed to extract files from $Path.`nLog file:`n $(friendly_path $LogName)`n$(new_issue_msg $app $bucket 'decompress error')"
|
||||||
}
|
}
|
||||||
if (Test-Path $LogPath) {
|
if (Test-Path $LogName) {
|
||||||
Remove-Item $LogPath -Force
|
Remove-Item $LogName -Force
|
||||||
}
|
}
|
||||||
if ($Removal) {
|
if ($Removal) {
|
||||||
# Remove original archive file
|
# Remove original archive file
|
||||||
@@ -241,8 +241,14 @@ function Expand-ZipArchive {
|
|||||||
$OriDestinationPath = $DestinationPath
|
$OriDestinationPath = $DestinationPath
|
||||||
$DestinationPath = "$DestinationPath\_tmp"
|
$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)
|
# 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
|
Microsoft.PowerShell.Archive\Expand-Archive -Path $Path -DestinationPath $DestinationPath -Force
|
||||||
|
|
||||||
|
$global:ProgressPreference = $oldProgressPreference
|
||||||
if ($ExtractDir) {
|
if ($ExtractDir) {
|
||||||
movedir "$DestinationPath\$ExtractDir" $OriDestinationPath | Out-Null
|
movedir "$DestinationPath\$ExtractDir" $OriDestinationPath | Out-Null
|
||||||
Remove-Item $DestinationPath -Recurse -Force
|
Remove-Item $DestinationPath -Recurse -Force
|
||||||
@@ -268,17 +274,17 @@ function Expand-DarkArchive {
|
|||||||
[Switch]
|
[Switch]
|
||||||
$Removal
|
$Removal
|
||||||
)
|
)
|
||||||
$LogPath = "$(Split-Path $Path)\dark.log"
|
$LogName = "$(Split-Path $Path)\dark.log"
|
||||||
$ArgList = @('-nologo', '-x', $DestinationPath, $Path)
|
$ArgList = @('-nologo', '-x', $DestinationPath, $Path)
|
||||||
if ($Switches) {
|
if ($Switches) {
|
||||||
$ArgList += (-split $Switches)
|
$ArgList += (-split $Switches)
|
||||||
}
|
}
|
||||||
$Status = Invoke-ExternalCommand (Get-HelperPath -Helper Dark) $ArgList -LogPath $LogPath
|
$Status = Start-ExternalProcess (Get-HelperPath -Helper Dark) $ArgList -LogName $LogName
|
||||||
if (!$Status) {
|
if (!$Status) {
|
||||||
abort "Failed to extract files from $Path.`nLog file:`n $(friendly_path $LogPath)`n$(new_issue_msg $app $bucket 'decompress error')"
|
abort "Failed to extract files from $Path.`nLog file:`n $(friendly_path $LogName)`n$(new_issue_msg $app $bucket 'decompress error')"
|
||||||
}
|
}
|
||||||
if (Test-Path $LogPath) {
|
if (Test-Path $LogName) {
|
||||||
Remove-Item $LogPath -Force
|
Remove-Item $LogName -Force
|
||||||
}
|
}
|
||||||
if ($Removal) {
|
if ($Removal) {
|
||||||
# Remove original archive file
|
# Remove original archive file
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
# following arguments are treated as non-option arguments, even if
|
# following arguments are treated as non-option arguments, even if
|
||||||
# they begin with a hyphen. The "--" itself will not be included in
|
# they begin with a hyphen. The "--" itself will not be included in
|
||||||
# the returned $opts. (POSIX-compatible)
|
# the returned $opts. (POSIX-compatible)
|
||||||
function getopt($argv, $shortopts, $longopts) {
|
function getopt([String[]]$argv, [String]$shortopts, [String[]]$longopts) {
|
||||||
$opts = @{}; $rem = @()
|
$opts = @{}; $rem = @()
|
||||||
|
|
||||||
function err($msg) {
|
function err($msg) {
|
||||||
@@ -24,10 +24,6 @@ function getopt($argv, $shortopts, $longopts) {
|
|||||||
return [Regex]::Escape($str)
|
return [Regex]::Escape($str)
|
||||||
}
|
}
|
||||||
|
|
||||||
# ensure these are arrays
|
|
||||||
$argv = @($argv -split ' ')
|
|
||||||
$longopts = @($longopts)
|
|
||||||
|
|
||||||
for ($i = 0; $i -lt $argv.Length; $i++) {
|
for ($i = 0; $i -lt $argv.Length; $i++) {
|
||||||
$arg = $argv[$i]
|
$arg = $argv[$i]
|
||||||
if ($null -eq $arg) { continue }
|
if ($null -eq $arg) { continue }
|
||||||
@@ -81,6 +77,5 @@ function getopt($argv, $shortopts, $longopts) {
|
|||||||
$rem += $arg
|
$rem += $arg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$opts, $rem
|
$opts, $rem
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -365,7 +365,8 @@ function Invoke-Download ($url, $to, $cookies, $progress) {
|
|||||||
}
|
}
|
||||||
if ($url -match 'api\.github\.com/repos') {
|
if ($url -match 'api\.github\.com/repos') {
|
||||||
$wreq.Accept = 'application/octet-stream'
|
$wreq.Accept = 'application/octet-stream'
|
||||||
$wreq.Headers['Authorization'] = "token $(Get-GitHubToken)"
|
$wreq.Headers['Authorization'] = "Bearer $(Get-GitHubToken)"
|
||||||
|
$wreq.Headers['X-GitHub-Api-Version'] = "2022-11-28"
|
||||||
}
|
}
|
||||||
if ($cookies) {
|
if ($cookies) {
|
||||||
$wreq.Headers.Add('Cookie', (cookie_header $cookies))
|
$wreq.Headers.Add('Cookie', (cookie_header $cookies))
|
||||||
@@ -632,7 +633,7 @@ function cookie_header($cookies) {
|
|||||||
function is_in_dir($dir, $check) {
|
function is_in_dir($dir, $check) {
|
||||||
$check = "$(fullpath $check)"
|
$check = "$(fullpath $check)"
|
||||||
$dir = "$(fullpath $dir)"
|
$dir = "$(fullpath $dir)"
|
||||||
$check -match "^$([regex]::escape("$dir"))(\\|`$)"
|
$check -match "^$([regex]::Escape("$dir"))([/\\]|`$)"
|
||||||
}
|
}
|
||||||
|
|
||||||
function ftp_file_size($url) {
|
function ftp_file_size($url) {
|
||||||
@@ -733,7 +734,7 @@ function install_msi($fname, $dir, $msi) {
|
|||||||
|
|
||||||
$continue_exit_codes = @{ 3010 = "a restart is required to complete installation" }
|
$continue_exit_codes = @{ 3010 = "a restart is required to complete installation" }
|
||||||
|
|
||||||
$installed = Invoke-ExternalCommand 'msiexec' $arg -Activity "Running installer..." -ContinueExitCodes $continue_exit_codes
|
$installed = Start-ExternalProcess 'msiexec' $arg -Prompt 'Running installer...' -ContinueExitCodes $continue_exit_codes
|
||||||
if(!$installed) {
|
if(!$installed) {
|
||||||
abort "Installation aborted. You might need to run 'scoop uninstall $app' before trying again."
|
abort "Installation aborted. You might need to run 'scoop uninstall $app' before trying again."
|
||||||
}
|
}
|
||||||
@@ -765,7 +766,7 @@ function install_prog($fname, $dir, $installer, $global) {
|
|||||||
if($prog.endswith('.ps1')) {
|
if($prog.endswith('.ps1')) {
|
||||||
& $prog @arg
|
& $prog @arg
|
||||||
} else {
|
} else {
|
||||||
$installed = Invoke-ExternalCommand $prog $arg -Activity "Running installer..."
|
$installed = Start-ExternalProcess $prog $arg -Prompt 'Running installer...'
|
||||||
if(!$installed) {
|
if(!$installed) {
|
||||||
abort "Installation aborted. You might need to run 'scoop uninstall $app' before trying again."
|
abort "Installation aborted. You might need to run 'scoop uninstall $app' before trying again."
|
||||||
}
|
}
|
||||||
@@ -818,7 +819,7 @@ function run_uninstaller($manifest, $architecture, $dir) {
|
|||||||
if($exe.endswith('.ps1')) {
|
if($exe.endswith('.ps1')) {
|
||||||
& $exe @arg
|
& $exe @arg
|
||||||
} else {
|
} else {
|
||||||
$uninstalled = Invoke-ExternalCommand $exe $arg -Activity "Running uninstaller..." -ContinueExitCodes $continue_exit_codes
|
$uninstalled = Start-ExternalProcess $exe $arg -Prompt 'Running uninstaller...' -ContinueExitCodes $continue_exit_codes
|
||||||
if(!$uninstalled) { abort "Uninstallation aborted." }
|
if(!$uninstalled) { abort "Uninstallation aborted." }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1066,13 +1067,18 @@ function ensure_none_failed($apps) {
|
|||||||
foreach ($app in $apps) {
|
foreach ($app in $apps) {
|
||||||
$app = ($app -split '/|\\')[-1] -replace '\.json$', ''
|
$app = ($app -split '/|\\')[-1] -replace '\.json$', ''
|
||||||
foreach ($global in $true, $false) {
|
foreach ($global in $true, $false) {
|
||||||
|
if ($global) {
|
||||||
|
$instArgs = @('--global')
|
||||||
|
} else {
|
||||||
|
$instArgs = @()
|
||||||
|
}
|
||||||
if (failed $app $global) {
|
if (failed $app $global) {
|
||||||
if (installed $app $global) {
|
if (installed $app $global) {
|
||||||
info "Repair previous failed installation of $app."
|
info "Repair previous failed installation of $app."
|
||||||
& "$PSScriptRoot\..\libexec\scoop-reset.ps1" $app$(if ($global) { ' --global' })
|
& "$PSScriptRoot\..\libexec\scoop-reset.ps1" $app @instArgs
|
||||||
} else {
|
} else {
|
||||||
warn "Purging previous failed installation of $app."
|
warn "Purging previous failed installation of $app."
|
||||||
& "$PSScriptRoot\..\libexec\scoop-uninstall.ps1" $app$(if ($global) { ' --global' })
|
& "$PSScriptRoot\..\libexec\scoop-uninstall.ps1" $app @instArgs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1179,7 +1185,7 @@ function unlink_persist_data($manifest, $dir) {
|
|||||||
if ($persist) {
|
if ($persist) {
|
||||||
@($persist) | ForEach-Object {
|
@($persist) | ForEach-Object {
|
||||||
$source, $null = persist_def $_
|
$source, $null = persist_def $_
|
||||||
$source = Get-Item "$dir\$source"
|
$source = Get-Item "$dir\$source" -ErrorAction SilentlyContinue
|
||||||
if ($source.LinkType) {
|
if ($source.LinkType) {
|
||||||
$source_path = $source.FullName
|
$source_path = $source.FullName
|
||||||
# directory (junction)
|
# directory (junction)
|
||||||
|
|||||||
@@ -1,22 +1,17 @@
|
|||||||
$modulesdir = "$scoopdir\modules"
|
|
||||||
|
|
||||||
function install_psmodule($manifest, $dir, $global) {
|
function install_psmodule($manifest, $dir, $global) {
|
||||||
$psmodule = $manifest.psmodule
|
$psmodule = $manifest.psmodule
|
||||||
if (!$psmodule) { return }
|
if (!$psmodule) { return }
|
||||||
|
|
||||||
if ($global) {
|
$targetdir = ensure (modulesdir $global)
|
||||||
abort 'Installing PowerShell modules globally is not implemented!'
|
|
||||||
}
|
|
||||||
|
|
||||||
$modulesdir = ensure $modulesdir
|
ensure_in_psmodulepath $targetdir $global
|
||||||
ensure_in_psmodulepath $modulesdir $global
|
|
||||||
|
|
||||||
$module_name = $psmodule.name
|
$module_name = $psmodule.name
|
||||||
if (!$module_name) {
|
if (!$module_name) {
|
||||||
abort "Invalid manifest: The 'name' property is missing from 'psmodule'."
|
abort "Invalid manifest: The 'name' property is missing from 'psmodule'."
|
||||||
}
|
}
|
||||||
|
|
||||||
$linkfrom = "$modulesdir\$module_name"
|
$linkfrom = "$targetdir\$module_name"
|
||||||
Write-Host "Installing PowerShell module '$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)"
|
||||||
@@ -36,7 +31,9 @@ function uninstall_psmodule($manifest, $dir, $global) {
|
|||||||
$module_name = $psmodule.name
|
$module_name = $psmodule.name
|
||||||
Write-Host "Uninstalling PowerShell module '$module_name'."
|
Write-Host "Uninstalling PowerShell module '$module_name'."
|
||||||
|
|
||||||
$linkfrom = "$modulesdir\$module_name"
|
$targetdir = modulesdir $global
|
||||||
|
|
||||||
|
$linkfrom = "$targetdir\$module_name"
|
||||||
if (Test-Path $linkfrom) {
|
if (Test-Path $linkfrom) {
|
||||||
Write-Host "Removing $(friendly_path $linkfrom)"
|
Write-Host "Removing $(friendly_path $linkfrom)"
|
||||||
$linkfrom = Convert-Path $linkfrom
|
$linkfrom = Convert-Path $linkfrom
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ $defenderIssues = 0
|
|||||||
|
|
||||||
$adminPrivileges = ([System.Security.Principal.WindowsPrincipal] [System.Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
|
$adminPrivileges = ([System.Security.Principal.WindowsPrincipal] [System.Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||||
|
|
||||||
if ($adminPrivileges) {
|
if ($adminPrivileges -and $env:USERNAME -ne 'WDAGUtilityAccount') {
|
||||||
$defenderIssues += !(check_windows_defender $false)
|
$defenderIssues += !(check_windows_defender $false)
|
||||||
$defenderIssues += !(check_windows_defender $true)
|
$defenderIssues += !(check_windows_defender $true)
|
||||||
}
|
}
|
||||||
@@ -19,18 +19,18 @@ $issues += !(check_main_bucket)
|
|||||||
$issues += !(check_long_paths)
|
$issues += !(check_long_paths)
|
||||||
$issues += !(Get-WindowsDeveloperModeStatus)
|
$issues += !(Get-WindowsDeveloperModeStatus)
|
||||||
|
|
||||||
if (!(Test-HelperInstalled -Helper 7zip)) {
|
if (!(Test-HelperInstalled -Helper 7zip) -and !(get_config USE_EXTERNAL_7ZIP)) {
|
||||||
error "'7-Zip' is not installed! It's required for unpacking most programs. Please Run 'scoop install 7zip' or 'scoop install 7zip-zstd'."
|
warn "'7-Zip' is not installed! It's required for unpacking most programs. Please Run 'scoop install 7zip' or 'scoop install 7zip-zstd'."
|
||||||
$issues++
|
$issues++
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(Test-HelperInstalled -Helper Innounp)) {
|
if (!(Test-HelperInstalled -Helper Innounp)) {
|
||||||
error "'Inno Setup Unpacker' is not installed! It's required for unpacking InnoSetup files. Please run 'scoop install innounp'."
|
warn "'Inno Setup Unpacker' is not installed! It's required for unpacking InnoSetup files. Please run 'scoop install innounp'."
|
||||||
$issues++
|
$issues++
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(Test-HelperInstalled -Helper Dark)) {
|
if (!(Test-HelperInstalled -Helper Dark)) {
|
||||||
error "'dark' is not installed! It's required for unpacking installers created with the WiX Toolset. Please run 'scoop install dark' or 'scoop install wixtoolset'."
|
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++
|
$issues++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ function choose_item($list, $query) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!$url) {
|
if (!$url) {
|
||||||
scoop help create
|
& "$PSScriptRoot\scoop-help.ps1" create
|
||||||
} else {
|
} else {
|
||||||
create_manifest $url
|
create_manifest $url
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ if (is_scoop_outdated) {
|
|||||||
if ($opt.u -or $opt.'no-update-scoop') {
|
if ($opt.u -or $opt.'no-update-scoop') {
|
||||||
warn "Scoop is out of date."
|
warn "Scoop is out of date."
|
||||||
} else {
|
} else {
|
||||||
scoop update
|
& "$PSScriptRoot\scoop-update.ps1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,15 +47,23 @@ $apps | ForEach-Object {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_config NO_JUNCTION){
|
if (get_config NO_JUNCTION) {
|
||||||
$version = Select-CurrentVersion -App $app -Global:$global
|
$version = Select-CurrentVersion -App $app -Global:$global
|
||||||
} else {
|
} else {
|
||||||
$version = 'current'
|
$version = 'current'
|
||||||
}
|
}
|
||||||
$dir = versiondir $app $version $global
|
$dir = versiondir $app $version $global
|
||||||
$json = install_info $app $version $global
|
$json = install_info $app $version $global
|
||||||
|
if (!$json) {
|
||||||
|
error "Failed to hold '$app'."
|
||||||
|
continue
|
||||||
|
}
|
||||||
$install = @{}
|
$install = @{}
|
||||||
$json | Get-Member -MemberType Properties | ForEach-Object { $install.Add($_.Name, $json.($_.Name)) }
|
$json | Get-Member -MemberType Properties | ForEach-Object { $install.Add($_.Name, $json.($_.Name)) }
|
||||||
|
if ($install.hold) {
|
||||||
|
info "'$app' is already held."
|
||||||
|
continue
|
||||||
|
}
|
||||||
$install.hold = $true
|
$install.hold = $true
|
||||||
save_install_info $install $dir
|
save_install_info $install $dir
|
||||||
success "$app is now held and can not be updated anymore."
|
success "$app is now held and can not be updated anymore."
|
||||||
|
|||||||
@@ -34,20 +34,19 @@ foreach ($item in $import.buckets) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($item in $import.apps) {
|
foreach ($item in $import.apps) {
|
||||||
|
$instArgs = @()
|
||||||
|
$holdArgs = @()
|
||||||
$info = $item.Info -Split ', '
|
$info = $item.Info -Split ', '
|
||||||
$global = if ('Global install' -in $info) {
|
if ('Global install' -in $info) {
|
||||||
' --global'
|
$instArgs += '--global'
|
||||||
} else {
|
$holdArgs += '--global'
|
||||||
''
|
|
||||||
}
|
}
|
||||||
$arch = if ('64bit' -in $info -and '64bit' -ne $def_arch) {
|
if ('64bit' -in $info -and '64bit' -ne $def_arch) {
|
||||||
' --arch 64bit'
|
$instArgs += '--arch', '64bit'
|
||||||
} elseif ('32bit' -in $info -and '32bit' -ne $def_arch) {
|
} elseif ('32bit' -in $info -and '32bit' -ne $def_arch) {
|
||||||
' --arch 32bit'
|
$instArgs += '--arch', '32bit'
|
||||||
} elseif ('arm64' -in $info -and 'arm64' -ne $def_arch) {
|
} elseif ('arm64' -in $info -and 'arm64' -ne $def_arch) {
|
||||||
' --arch arm64'
|
$instArgs += '--arch', 'arm64'
|
||||||
} else {
|
|
||||||
''
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$app = if ($item.Source -in $bucket_names) {
|
$app = if ($item.Source -in $bucket_names) {
|
||||||
@@ -58,9 +57,9 @@ foreach ($item in $import.apps) {
|
|||||||
$item.Source
|
$item.Source
|
||||||
}
|
}
|
||||||
|
|
||||||
& "$PSScriptRoot\scoop-install.ps1" $app$global$arch
|
& "$PSScriptRoot\scoop-install.ps1" $app @instArgs
|
||||||
|
|
||||||
if ('Held package' -in $info) {
|
if ('Held package' -in $info) {
|
||||||
& "$PSScriptRoot\scoop-hold.ps1" $($item.Name)$global
|
& "$PSScriptRoot\scoop-hold.ps1" $item.Name @holdArgs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Usage: scoop info <app> [--verbose]
|
# Usage: scoop info <app> [options]
|
||||||
# Summary: Display information about an app
|
# Summary: Display information about an app
|
||||||
# Options:
|
# Help: Options:
|
||||||
# -v, --verbose Show full paths and URLs
|
# -v, --verbose Show full paths and URLs
|
||||||
|
|
||||||
. "$PSScriptRoot\..\lib\getopt.ps1"
|
. "$PSScriptRoot\..\lib\getopt.ps1"
|
||||||
. "$PSScriptRoot\..\lib\manifest.ps1" # 'Get-Manifest'
|
. "$PSScriptRoot\..\lib\manifest.ps1" # 'Get-Manifest'
|
||||||
@@ -84,7 +84,7 @@ if ($manifest.depends) {
|
|||||||
|
|
||||||
if (Test-Path $manifest_file) {
|
if (Test-Path $manifest_file) {
|
||||||
if (Get-Command git -ErrorAction Ignore) {
|
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 '#'
|
$gitinfo = (Invoke-Git -Path (Split-Path $manifest_file) -ArgumentList @('log', '-1', '-s', '--format=%aD#%an', $manifest_file) 2> $null) -Split '#'
|
||||||
}
|
}
|
||||||
if ($gitinfo) {
|
if ($gitinfo) {
|
||||||
$item.'Updated at' = $gitinfo[0] | Get-Date
|
$item.'Updated at' = $gitinfo[0] | Get-Date
|
||||||
@@ -112,7 +112,7 @@ if ($status.installed) {
|
|||||||
|
|
||||||
# Collect file list from each location
|
# Collect file list from each location
|
||||||
$appFiles = Get-ChildItem $appsdir -Filter $app
|
$appFiles = Get-ChildItem $appsdir -Filter $app
|
||||||
$currentFiles = Get-ChildItem $appFiles -Filter (Select-CurrentVersion $app $global)
|
$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
|
$persistFiles = Get-ChildItem $persist_dir -ErrorAction Ignore # Will fail if app does not persist data
|
||||||
$cacheFiles = Get-ChildItem $cachedir -Filter "$app#*"
|
$cacheFiles = Get-ChildItem $cachedir -Filter "$app#*"
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ if ($status.installed) {
|
|||||||
$fileTotals = @()
|
$fileTotals = @()
|
||||||
foreach ($fileType in ($appFiles, $currentFiles, $persistFiles, $cacheFiles)) {
|
foreach ($fileType in ($appFiles, $currentFiles, $persistFiles, $cacheFiles)) {
|
||||||
if ($null -ne $fileType) {
|
if ($null -ne $fileType) {
|
||||||
$fileSum = (Get-ChildItem $fileType -Recurse | Measure-Object -Property Length -Sum).Sum
|
$fileSum = (Get-ChildItem $fileType.FullName -Recurse -File | Measure-Object -Property Length -Sum).Sum
|
||||||
$fileTotals += coalesce $fileSum 0
|
$fileTotals += coalesce $fileSum 0
|
||||||
} else {
|
} else {
|
||||||
$fileTotals += 0
|
$fileTotals += 0
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ if (is_scoop_outdated) {
|
|||||||
if ($opt.u -or $opt.'no-update-scoop') {
|
if ($opt.u -or $opt.'no-update-scoop') {
|
||||||
warn "Scoop is out of date."
|
warn "Scoop is out of date."
|
||||||
} else {
|
} else {
|
||||||
scoop update
|
& "$PSScriptRoot\scoop-update.ps1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ $apps | ForEach-Object {
|
|||||||
|
|
||||||
#region Workaround for #2952
|
#region Workaround for #2952
|
||||||
if (test_running_process $app $global) {
|
if (test_running_process $app $global) {
|
||||||
continue
|
return
|
||||||
}
|
}
|
||||||
#endregion Workaround for #2952
|
#endregion Workaround for #2952
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ param($query)
|
|||||||
. "$PSScriptRoot\..\lib\manifest.ps1" # 'manifest'
|
. "$PSScriptRoot\..\lib\manifest.ps1" # 'manifest'
|
||||||
. "$PSScriptRoot\..\lib\versions.ps1" # 'Get-LatestVersion'
|
. "$PSScriptRoot\..\lib\versions.ps1" # 'Get-LatestVersion'
|
||||||
|
|
||||||
$list = @()
|
$list = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$query = New-Object Regex $query, 'IgnoreCase'
|
$query = New-Object Regex $query, 'IgnoreCase'
|
||||||
@@ -32,24 +32,90 @@ function bin_match($manifest, $query) {
|
|||||||
if ((strip_ext $fname) -match $query) { $fname }
|
if ((strip_ext $fname) -match $query) { $fname }
|
||||||
elseif ($alias -match $query) { $alias }
|
elseif ($alias -match $query) { $alias }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($bins) { return $bins }
|
||||||
|
else { return $false }
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ($bins) { return $bins }
|
if ($bins) { return $bins }
|
||||||
else { return $false }
|
else { return $false }
|
||||||
}
|
}
|
||||||
|
|
||||||
function search_bucket($bucket, $query) {
|
function search_bucket($bucket, $query) {
|
||||||
$apps = apps_in_bucket (Find-BucketDirectory $bucket) | ForEach-Object { @{ name = $_ } }
|
$apps = Get-ChildItem (Find-BucketDirectory $bucket) -Filter '*.json' -Recurse
|
||||||
|
|
||||||
if ($query) {
|
$apps | ForEach-Object {
|
||||||
$apps = $apps | Where-Object {
|
$json = [System.Text.Json.JsonDocument]::Parse([System.IO.File]::ReadAllText($_.FullName))
|
||||||
if ($_.name -match $query) { return $true }
|
$name = $_.BaseName
|
||||||
$bin = bin_match (manifest $_.name $bucket) $query
|
|
||||||
|
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) {
|
if ($bin) {
|
||||||
$_.bin = $bin
|
$list.Add([PSCustomObject]@{
|
||||||
return $true
|
Name = $name
|
||||||
|
Version = $json.RootElement.GetProperty("version")
|
||||||
|
Source = $bucket
|
||||||
|
Binaries = $bin -join ' | '
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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 ' | '
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$apps | ForEach-Object { $_.version = (Get-LatestVersion -AppName $_.name -Bucket $bucket); $_ }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function download_json($url) {
|
function download_json($url) {
|
||||||
@@ -96,43 +162,35 @@ function search_remotes($query) {
|
|||||||
(add them using 'scoop bucket add <bucket name>')"
|
(add them using 'scoop bucket add <bucket name>')"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$remote_list = @()
|
||||||
$results | ForEach-Object {
|
$results | ForEach-Object {
|
||||||
$name = $_.bucket
|
$bucket = $_.bucket
|
||||||
$_.results | ForEach-Object {
|
$_.results | ForEach-Object {
|
||||||
$item = [ordered]@{}
|
$item = [ordered]@{}
|
||||||
$item.Name = $_
|
$item.Name = $_
|
||||||
$item.Source = $name
|
$item.Source = $bucket
|
||||||
$list += [PSCustomObject]$item
|
$remote_list += [PSCustomObject]$item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$remote_list
|
||||||
$list
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$jsonTextAvailable = [System.AppDomain]::CurrentDomain.GetAssemblies() | Where-object { [System.IO.Path]::GetFileNameWithoutExtension($_.Location) -eq "System.Text.Json" }
|
||||||
|
|
||||||
Get-LocalBucket | ForEach-Object {
|
Get-LocalBucket | ForEach-Object {
|
||||||
$res = search_bucket $_ $query
|
if ($jsonTextAvailable) {
|
||||||
$local_results = $local_results -or $res
|
search_bucket $_ $query
|
||||||
if ($res) {
|
} else {
|
||||||
$name = "$_"
|
search_bucket_legacy $_ $query
|
||||||
|
|
||||||
$res | ForEach-Object {
|
|
||||||
$item = [ordered]@{}
|
|
||||||
$item.Name = $_.name
|
|
||||||
$item.Version = $_.version
|
|
||||||
$item.Source = $name
|
|
||||||
$item.Binaries = ""
|
|
||||||
if ($_.bin) { $item.Binaries = $_.bin -join ' | ' }
|
|
||||||
$list += [PSCustomObject]$item
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($list.Length -gt 0) {
|
if ($list.Count -gt 0) {
|
||||||
Write-Host "Results from local buckets..."
|
Write-Host "Results from local buckets..."
|
||||||
$list
|
$list
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$local_results -and !(github_ratelimit_reached)) {
|
if ($list.Count -eq 0 -and !(github_ratelimit_reached)) {
|
||||||
$remote_results = search_remotes $query
|
$remote_results = search_remotes $query
|
||||||
if (!$remote_results) {
|
if (!$remote_results) {
|
||||||
warn "No matches found."
|
warn "No matches found."
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
#
|
#
|
||||||
# To list all shims or matching shims, use the 'list' subcommand:
|
# To list all shims or matching shims, use the 'list' subcommand:
|
||||||
#
|
#
|
||||||
# scoop shim list [<shim_name>/<pattern>...]
|
# scoop shim list [<regex_pattern>...]
|
||||||
#
|
#
|
||||||
# To show a shim's information, use the 'info' subcommand:
|
# To show a shim's information, use the 'info' subcommand:
|
||||||
#
|
#
|
||||||
@@ -82,7 +82,7 @@ function Get-ShimInfo($ShimPath) {
|
|||||||
function Get-ShimPath($ShimName, $Global) {
|
function Get-ShimPath($ShimName, $Global) {
|
||||||
'.shim', '.ps1' | ForEach-Object {
|
'.shim', '.ps1' | ForEach-Object {
|
||||||
$shimPath = Join-Path (shimdir $Global) "$ShimName$_"
|
$shimPath = Join-Path (shimdir $Global) "$ShimName$_"
|
||||||
if (Test-Path $shimPath) {
|
if (Test-Path -LiteralPath $shimPath) {
|
||||||
return $shimPath
|
return $shimPath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -144,7 +144,7 @@ switch ($SubCommand) {
|
|||||||
$other | ForEach-Object {
|
$other | ForEach-Object {
|
||||||
try {
|
try {
|
||||||
$pattern = $_
|
$pattern = $_
|
||||||
[Regex]::New($pattern)
|
[void][Regex]::New($pattern)
|
||||||
} catch {
|
} catch {
|
||||||
Write-Host "ERROR: Invalid pattern: " -ForegroundColor Red -NoNewline
|
Write-Host "ERROR: Invalid pattern: " -ForegroundColor Red -NoNewline
|
||||||
Write-Host $pattern -ForegroundColor Magenta
|
Write-Host $pattern -ForegroundColor Magenta
|
||||||
|
|||||||
@@ -53,8 +53,16 @@ $apps | ForEach-Object {
|
|||||||
}
|
}
|
||||||
$dir = versiondir $app $version $global
|
$dir = versiondir $app $version $global
|
||||||
$json = install_info $app $version $global
|
$json = install_info $app $version $global
|
||||||
|
if (!$json) {
|
||||||
|
error "Failed to unhold '$app'"
|
||||||
|
continue
|
||||||
|
}
|
||||||
$install = @{}
|
$install = @{}
|
||||||
$json | Get-Member -MemberType Properties | ForEach-Object { $install.Add($_.Name, $json.($_.Name)) }
|
$json | Get-Member -MemberType Properties | ForEach-Object { $install.Add($_.Name, $json.($_.Name)) }
|
||||||
|
if (!$install.hold) {
|
||||||
|
info "'$app' is not held."
|
||||||
|
continue
|
||||||
|
}
|
||||||
$install.hold = $null
|
$install.hold = $null
|
||||||
save_install_info $install $dir
|
save_install_info $install $dir
|
||||||
success "$app is no longer held and can be updated again."
|
success "$app is no longer held and can be updated again."
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ function Sync-Scoop {
|
|||||||
Rename-Item $newdir 'current' -ErrorAction Stop
|
Rename-Item $newdir 'current' -ErrorAction Stop
|
||||||
} catch {
|
} catch {
|
||||||
Write-Warning $_
|
Write-Warning $_
|
||||||
abort "Scoop update failed. Folder in use. Paste $newdir into $currentdir."
|
abort "Scoop update failed. Folder in use. Please rename folders $currentdir to ``old`` and $newdir to ``current``."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -36,14 +36,14 @@
|
|||||||
|
|
||||||
$opt, $apps, $err = getopt $args 'asnup' @('all', 'scan', 'no-depends', 'no-update-scoop', 'passthru')
|
$opt, $apps, $err = getopt $args 'asnup' @('all', 'scan', 'no-depends', 'no-update-scoop', 'passthru')
|
||||||
if ($err) { "scoop virustotal: $err"; exit 1 }
|
if ($err) { "scoop virustotal: $err"; exit 1 }
|
||||||
if (!$apps) { my_usage; exit 1 }
|
if (!$apps -and -$all) { my_usage; exit 1 }
|
||||||
$architecture = Format-ArchitectureString
|
$architecture = Format-ArchitectureString
|
||||||
|
|
||||||
if (is_scoop_outdated) {
|
if (is_scoop_outdated) {
|
||||||
if ($opt.u -or $opt.'no-update-scoop') {
|
if ($opt.u -or $opt.'no-update-scoop') {
|
||||||
warn 'Scoop is out of date.'
|
warn 'Scoop is out of date.'
|
||||||
} else {
|
} else {
|
||||||
scoop update
|
& "$PSScriptRoot\scoop-update.ps1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
param($command)
|
param($command)
|
||||||
|
|
||||||
if (!$command) {
|
if (!$command) {
|
||||||
'ERROR: <command> missing'
|
error '<command> missing'
|
||||||
my_usage
|
my_usage
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
@@ -12,7 +12,7 @@ if (!$command) {
|
|||||||
$path = Get-CommandPath $command
|
$path = Get-CommandPath $command
|
||||||
|
|
||||||
if ($null -eq $path) {
|
if ($null -eq $path) {
|
||||||
Write-Host "'$command' not found / not a scoop shim."
|
warn "'$command' not found, not a scoop shim, or a broken shim."
|
||||||
exit 2
|
exit 2
|
||||||
} else {
|
} else {
|
||||||
friendly_path $path
|
friendly_path $path
|
||||||
|
|||||||
@@ -17,6 +17,12 @@ Describe 'getopt' -Tag 'Scoop' {
|
|||||||
$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' ''
|
$null, $null, $err = getopt '-az' 'a' ''
|
||||||
$err | Should -Be 'Option -z not recognized.'
|
$err | Should -Be 'Option -z not recognized.'
|
||||||
|
|||||||
Reference in New Issue
Block a user