44 Commits

Author SHA1 Message Date
Hsiao-nan Cheung
ea37a9ef63 refactor(iec): Rename to 'Start-ExternalProcess'
- refactor(iec): Rename some parameters
- feat(iec): Support EnvVars in 'Invoke-ExternalCommand()'
- fix(iec): Redirect output when 'CreateNoWindow'
- fix(iec): Allow empty 'ArgumentList'
- feat(iec): Support 'WorkingDirectory'
2023-11-08 00:33:24 +08:00
Rashil Gandhi
fb3169629f fix(scoop-checkup): Don't throw 7zip error when external 7zip is used (#5703)
* fix(scoop-checkup): Don't throw 7zip error when external 7zip is used

* Update CHANGELOG.md
2023-10-26 14:13:25 +05:30
Bill ZHANG
7e81e49152 fix(scoop-reset): Don't abort when multiple apps are passed and an app is running (#5687)
* fix(scoop-reset): change #2952 fix to be the same with scoop-install

* update changelog

* Update CHANGELOG.md

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

---------

Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
2023-10-26 12:58:10 +05:30
Hagai Gold
7b35e19d4c fix(perf): Do not call scoop externally from inside the code (#5695)
* fix: do not call `scoop` externally from inside the code

* update CHANGELOG.md

* update CHANGELOG.md
2023-10-19 13:19:31 +05:30
Sp1d3R
6cdcc75ad8 fix(shim): Fix a minor issue with Get-Subsystem (#5684)
* Fix PE read error and refractor

* refactor Change-Subsystem -> Set-Subsystem and additional `catch` block

* refactor Change-Subsystem -> Set-Subsystem and additional `catch` block

* add a return value to `Set-PESubsystem`

* fix trailing whitespace
2023-10-14 16:04:46 +05:30
L. Yeung
14b38b4092 fix(scoop-shim): Check literal path in Get-ShimPath (#5680)
Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
2023-10-10 16:50:53 +05:30
L. Yeung
2847e0a37c fix(scoop-shim): Avoid unexpected output of list subcommand (#5681)
* fix(shim): Avoid unexpected output of `list` subcommand

* Update libexec/scoop-shim.ps1

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

---------

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2023-10-10 16:47:46 +05:30
Dustin
3a3f41c556 fix(shim): Fix shim adding bug related to Resolve-Path(#5493)
* fixed shim add bug related to #5492

* Updated CHANGLOG.md per contributor guidelines
2023-10-08 19:04:36 +05:30
Rashil Gandhi
15f9bbec97 fix(update): Change error message to a better instruction (#5677)
* fix(update): Change error message to a better instruction

* Update CHANGELOG.md
2023-10-06 14:51:45 +05:30
Gerardo Grignoli
ab34b7fb61 feat(core): Allow global install of PowerShell modules (#5611)
* Allow global install of PowerShell modules to $env:ProgramFiles\WindowsPowerShell\Modules

* tabs vs spaces

* Updated CHANGELOG.md

* Changed global install of PowerShell modules to $globaldir\Modules
2023-10-05 16:40:03 +05:30
HUMORCE
863af42d4e fix(core): Fix detection of Git (#5545)
* fix(core): Fix `Test-GitAvailable`

* fix(core): Fallback git(32bit) to `Get-HelperPath`

* check value of `$internalgit` also

* changlog

* path already tested when invoke `Get-AppFilePAth`
2023-10-05 12:21:29 +05:30
Richard Kuhnt
b3c05e71fa perf(scoop-search): Improve performance for local search (#5644)
* perf(search): improve local search performance

* Update libexec/scoop-search.ps1

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

* Update libexec/scoop-search.ps1

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

* Update libexec/scoop-search.ps1

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

* Update libexec/scoop-search.ps1

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

* Update libexec/scoop-search.ps1

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

* Update libexec/scoop-search.ps1

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

* Added [JsonDocument]::Parse for testing

* Fix array length check

* Used wrong function

* Add fallback function for PowerShell 5

* Check for System.Text.Json in Assemblies instead

* Show help output

* Revert "Show help output"

This reverts commit d3d6b01d08.

* Update CHANGELOG.md

---------

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
2023-10-03 19:35:45 +05:30
HUMORCE
acc271d115 fix(scoop-(un)hold): Correct output the messages when manifest not found, (already|not) held (#5554)
* fix(scoop-(un)hold): Abort when manifest not found

* abort when already held or not held

* use continue

* CHANGELOG

* Update CHANGELOG.md

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

---------

Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
2023-10-03 19:27:01 +05:30
HUMORCE
6d79d62cc8 fix(core): Handle scoop aliases and broken (edited,copied) shim (#5551)
* fix(core): Avoid error messages when shim broked, Allow get path for scoop aliases

* update `scoop-which`

* Add CHANGELOG entry

* Update CHANGELOG.md

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

---------

Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
2023-10-03 18:59:10 +05:30
HUMORCE
00c92b04d6 fix(install): Avoid error when unlinking non-existent junction/hardlink (#5552)
* fix(install): Avoid error when unlinking non-existent junction / hardlink

* CHANGELOG

* Update CHANGELOG.md

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

---------

Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
2023-10-03 18:58:02 +05:30
HUMORCE
becc7a7b76 fix(core): Avoid error messages when deleting non-existent environment variable (#5547)
* fix(core): Check if the envrionment variable exists before delete

* CHANGELOG

* Use `try, catch`, value of env variable may is null/empty

* UPDATE CHANGELOG

* Brackets

---------

Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
2023-10-03 16:29:44 +05:30
HUMORCE
6898773a8d fix(core): Use relative path as fallback of $scoopdir (#5544)
* fix(core): Use relative path as fallback of `$scoopdir`(Scoop root directory)

* typo

* changelog

* re

---------

Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
2023-10-03 16:23:00 +05:30
Sp1d3R
353137f0a9 fix(shim): Remove console window for GUI apps (#5559)
* Change shim subsystem to prevent console window for GUI apps.

* Removed redundant log

* Update core.ps1

* Fixes file access rights and the log message

* update changelog

* Update CHANGELOG.md (PR Number)

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

---------

Co-authored-by: Quasar <suhas.nandibhatla@gmail.com>
Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
2023-10-03 00:09:48 +05:30
Rashil Gandhi
43579714cc fix(env): Publish environment change when deleting variable (#5631)
* fix(env): Publish environment change when deleting variable

* Update CHANGELOG.md
2023-10-02 20:59:50 +05:30
walpo
aa09601503 docs(readme): Improve documentation language (#5638)
* readme.md: refactor HTML blocks

* readme.md: enhance style and fix typos and more

* readme.md: improve composition

* Update README.md

It seems GitHub does not work well with the 'style' attribute, so the deprecated attribute 'align' cannot be replaced.

* readme.md: update writing

* Update README.md

* Update README.md

* Update CHANGELOG.md

---------

Co-authored-by: walpo <3212100-walpo@users.noreply.gitlab.com>
Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
2023-10-02 14:36:06 +05:30
HUMORCE
6a35a22b0b fix(scoop-checkup): Change the message level of helpers from ERROR to WARN (#5614)
* fix(scoop-checkup): Downgrade the message level of helpers from ERROR to WARN

* update CHANGELOG

---------

Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
2023-09-11 13:50:07 +05:30
Bill ZHANG
0b4919ca32 fix(scoop-virustotal): Continue execution when no app but -a flag is provided (#5593)
* fix(scoop-virustotal): continue exec when no app but -a provided

* update CHANGELOG.md

* CHANGELOG: fix typo

---------

Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
2023-09-11 00:28:53 +05:30
Bill ZHANG
efdd6dd7ca docs(CHANGELOG): Add missing brackets for the links (#5596)
add missing brackets for the links
2023-08-11 18:46:58 +05:30
HUMORCE
3dfb4bfd97 fix(buckets): Avoid error messages for unexpected dir (#5549) 2023-06-30 00:18:19 +08:00
HUMORCE
1d140585a4 fix(scoop-checkup): Skip defender check in Windows Sandbox (#5519) 2023-05-30 13:46:05 +08:00
0x574859
52059ca1ac fix(env): Apply env immediately by SendMessageTimeout (#5452) 2023-04-07 13:05:46 +08:00
HUMORCE
cddc52e03b docs(scoop-info): Fix help message (#5445) 2023-03-27 14:37:10 +08:00
Richard Kuhnt
682a1e2c07 fix(git): set HTTP(S)_PROXY only in process scope to prevent race condition (#5436) 2023-03-20 23:52:41 +08:00
Hsiao-nan Cheung
2accaae5d1 fix(core): Rewrite config file when needed (#5439) 2023-03-20 22:44:55 +08:00
Rashil Gandhi
a20bb4f1a6 fix(shim): Use bash executable directly (#5433)
* fix(shim): Use bash executable directly

* Update CHANGELOG.md
2023-03-16 20:09:18 +05:30
Ross Smith II
ad0f6178d0 feat(bucket): Switch nirsoft bucket to ScoopInstaller/Nirsoft (#5328) 2023-03-11 21:42:14 +08:00
L. Yeung
41620bb169 feat(core): Add -Silent switch for Invoke-ExternalCommand (#5346) 2023-03-11 21:39:45 +08:00
Hsiao-nan Cheung
559c6f9e64 feat(bucket): Make official buckets higher priority (#5398) 2023-03-10 17:24:41 +08:00
Richard Kuhnt
7826d6fe2d perf(decompress): disable progress bar to improve Expand-Archive performance (#5410)
See: https://github.com/ScoopInstaller/Install/pull/42

---------

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2023-02-27 20:11:40 +01:00
Stephen Albert-Moore
8acfeeefcf fix(scoop-info) --verbose file size collection (#5352) 2023-02-26 20:19:54 +01:00
Valinor
c00dd42cae fix(getopt): Stop split arguments in getopt() and ensure array by explicit arguments type (#5326)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2023-02-26 14:32:16 +08:00
Hsiao-nan Cheung
3f11454a3c fix(core): Fix scripts' calling parameters (#5365) 2023-02-26 14:31:38 +08:00
0x574859
0a39de86e2 fix(env): Avoid automatic expansion of %% in env (#5395)
Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
2023-02-25 20:38:09 +08:00
Chawye Hsu
c44e214743 feat(config): Support portable config file (#5369) 2023-02-25 20:22:56 +08:00
Jeppe Frandsen
7c6aeb240e fix(install): Fix downloading release assets from private GitHub repositories (#5361)
Fix download from private GitHub repos
2023-02-25 14:00:37 +05:30
Hsiao-nan Cheung
32ca856f63 fix(core): Fix is_in_dir under Unix (#5391) 2023-02-19 23:56:53 +08:00
Ercolino
1d0bd434ab builds(checkver): Read the private_host config variable (#5381) 2023-02-19 17:19:01 +08:00
Ross Smith II
54e3613fca ci(dependabot): Add dependabot.yml for GitHub Actions (#5377) 2023-02-18 22:50:08 +08:00
Rashil Gandhi
e2558ace75 fix(chore): Handle spaces in git command arguments (#5375)
* fix(chore): Handle spaces in git command arguments

* changelog

* Use splatting
2023-02-07 04:55:54 +05:30
26 changed files with 610 additions and 286 deletions

8
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,8 @@
---
# ~/.github/dependabot.yml
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/" # == /.github/workflows/
schedule:
interval: "daily"

View File

@@ -3,22 +3,71 @@
### Features
- **scoop-update:** Add support for parallel syncing buckets in PowerShell 7 and improve output ([#5122](https://github.com/ScoopInstaller/Scoop/issues/5122))
- **bucket:** Switch nirsoft bucket to ScoopInstaller/Nirsoft ([#5328](https://github.com/ScoopInstaller/Scoop/issues/5328))
- **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
- **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))
- **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))
- **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
- **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))
### 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
- **bucket:** Skip manifest validation if no manifest changes ([#5270](https://github.com/ScoopInstaller/Scoop/issues/5270))
### Documentation
- **scoop-info:** Fix help message([#5445](https://github.com/ScoopInstaller/Scoop/issues/5445))
- **readme:** Improve documentation language ([#5638](https://github.com/ScoopInstaller/Scoop/issues/5638))
## [v0.3.1](https://github.com/ScoopInstaller/Scoop/compare/v0.3.0...v0.3.1) - 2022-11-15
### Features
@@ -35,6 +84,7 @@
- **shim:** Exit if shim creating failed 'cause no git ([#5225](https://github.com/ScoopInstaller/Scoop/issues/5225))
- **scoop-import:** Add correct architecture argument ([#5210](https://github.com/ScoopInstaller/Scoop/issues/5210))
- **scoop-config:** Output `[DateTime]` as `[String]` ([#5232](https://github.com/ScoopInstaller/Scoop/issues/5232))
- **shim:** fixed shim add bug related to Resolve-Path ([#5492](https://github.com/ScoopInstaller/Scoop/issues/5492))
### Code Refactoring

103
README.md
View File

@@ -1,17 +1,17 @@
<p align="center">
<h1 align="center">Scoop</h1>
<!--<img src="scoop.png" alt="Long live Scoop!"/>-->
<h1 align="center">Scoop</h1>
</p>
<p align="center">
<b><a href="https://github.com/ScoopInstaller/Scoop#what-does-scoop-do">Features</a></b>
|
<b><a href="https://github.com/ScoopInstaller/Scoop#installation">Installation</a></b>
|
<b><a href="https://github.com/ScoopInstaller/Scoop/wiki">Documentation</a></b>
<a href="https://github.com/ScoopInstaller/Scoop#what-does-scoop-do">Features</a>
|
<a href="https://github.com/ScoopInstaller/Scoop#installation">Installation</a>
|
<a href="https://github.com/ScoopInstaller/Scoop/wiki">Documentation</a>
</p>
- - -
<p align="center" >
---
<p align="center">
<a href="https://github.com/ScoopInstaller/Scoop">
<img src="https://img.shields.io/github/languages/code-size/ScoopInstaller/Scoop.svg" alt="Code Size" />
</a>
@@ -36,43 +36,48 @@ Scoop is a command-line installer for Windows.
## 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
- Hides GUI wizard-style installers
- Prevents PATH pollution from installing lots of programs
- Avoids unexpected side-effects from installing and uninstalling programs
- Finds and installs dependencies automatically
- Performs all the extra setup steps itself to get a working program
- Eliminates [User Account Control](https://learn.microsoft.com/windows/security/application-security/application-control/user-account-control/) (UAC) prompt notifications.
- Hides the graphical user interface (GUI) of wizard-style installers.
- Prevents polluting the `PATH` environment variable. Normally, this variable gets cluttered as different apps are installed on the device.
- Avoids unexpected side effects from installing and uninstalling apps.
- Resolves and installs dependencies automatically.
- Performs all the necessary steps to get an app to a working state.
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
sudo scoop install 7zip git openssh --global
scoop install aria2 curl grep sed less touch
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
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
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`
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
```
@@ -90,54 +95,54 @@ You can tweak the following `aria2` settings with the `scoop config` command:
## Inspiration
- [Homebrew](http://mxcl.github.io/homebrew/)
- [sub](https://github.com/37signals/sub#readme)
- [Homebrew](https://brew.sh/)
- [Sub](https://signalvnoise.com/posts/3264-automating-with-convention-introducing-sub)
## 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 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.
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.
### 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
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
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
- [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)
- [games](https://github.com/Calinou/scoop-games) - Open source/freeware games and game-related tools
- [nerd-fonts](https://github.com/matthewjberger/scoop-nerd-fonts) - Nerd Fonts
- [nirsoft](https://github.com/kodybrown/scoop-nirsoft) - Almost all of the [250+](https://rasa.github.io/scoop-directory/by-apps#kodybrown_scoop-nirsoft) apps from [Nirsoft](https://nirsoft.net)
- [sysinternals](https://github.com/niheaven/scoop-sysinternals) - Sysinternals Suite and all individual application from [Microsoft](https://learn.microsoft.com/sysinternals/)
- [java](https://github.com/ScoopInstaller/Java) - A collection of Java development kits (JDKs), Java runtime engines (JREs), Java's virtual machine debugging tools and Java based runtime engines.
- [nonportable](https://github.com/ScoopInstaller/Nonportable) - Non-portable apps (may require UAC)
- [php](https://github.com/ScoopInstaller/PHP) - Installers for most versions of PHP
- [versions](https://github.com/ScoopInstaller/Versions) - Alternative versions of apps found in other buckets
- [main](https://github.com/ScoopInstaller/Main) - Default bucket which contains popular non-GUI apps.
- [extras](https://github.com/ScoopInstaller/Extras) - Apps that do not fit the main bucket's [criteria](https://github.com/ScoopInstaller/Scoop/wiki/Criteria-for-including-apps-in-the-main-bucket).
- [games](https://github.com/Calinou/scoop-games) - Open-source and freeware video games and game-related tools.
- [nerd-fonts](https://github.com/matthewjberger/scoop-nerd-fonts) - Nerd Fonts.
- [nirsoft](https://github.com/ScoopInstaller/Nirsoft) - A collection of over 250+ apps from [Nirsoft](https://nirsoft.net).
- [sysinternals](https://github.com/niheaven/scoop-sysinternals) - The Sysinternals suite from [Microsoft](https://learn.microsoft.com/sysinternals/).
- [java](https://github.com/ScoopInstaller/Java) - A collection of Java development kits (JDKs) and Java runtime engines (JREs), Java's virtual machine debugging tools and Java based runtime engines.
- [nonportable](https://github.com/ScoopInstaller/Nonportable) - Non-portable apps (may trigger UAC prompts).
- [php](https://github.com/ScoopInstaller/PHP) - Installers for most versions of PHP.
- [versions](https://github.com/ScoopInstaller/Versions) - Alternative versions of apps found in other buckets.
The main bucket is installed by default. 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
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
scoop bucket add extras
```
You would be able to install apps from the `extras` bucket now.
## 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).

View File

@@ -226,15 +226,21 @@ $Queue | ForEach-Object {
$url = substitute $url $substitutions
$state = New-Object psobject @{
app = $name;
file = $file;
url = $url;
regex = $regex;
json = $json;
jsonpath = $jsonpath;
xpath = $xpath;
reverse = $reverse;
replace = $replace;
app = $name
file = $file
url = $url
regex = $regex
json = $json
jsonpath = $jsonpath
xpath = $xpath
reverse = $reverse
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))

View File

@@ -2,7 +2,7 @@
"main": "https://github.com/ScoopInstaller/Main",
"extras": "https://github.com/ScoopInstaller/Extras",
"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",
"php": "https://github.com/ScoopInstaller/PHP",
"nerd-fonts": "https://github.com/matthewjberger/scoop-nerd-fonts",

View File

@@ -58,10 +58,18 @@ function Get-LocalBucket {
.SYNOPSIS
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) {
return @() # Return a zero-length list instead of $null.
} else {
$knownBuckets = known_buckets
for ($i = $knownBuckets.Count - 1; $i -ge 0 ; $i--) {
$name = $knownBuckets[$i]
if ($bucketNames.Contains($name)) {
[void]$bucketNames.Remove($name)
$bucketNames.Insert(0, $name)
}
}
return $bucketNames
}
}
@@ -100,10 +108,10 @@ function list_buckets {
$path = Find-BucketDirectory $_ -Root
if ((Test-Path (Join-Path $path '.git')) -and (Get-Command git -ErrorAction SilentlyContinue)) {
$bucket.Source = Invoke-Git -Path $path -ArgumentList @('config', 'remote.origin.url')
$bucket.Updated = Invoke-Git -Path $path -ArgumentList @('log', "--format='%aD'", '-n', '1')
$bucket.Updated = Invoke-Git -Path $path -ArgumentList @('log', '--format=%aD', '-n', '1') | Get-Date
} else {
$bucket.Source = friendly_path $path
$bucket.Updated = (Get-Item "$path\bucket").LastWriteTime
$bucket.Updated = (Get-Item "$path\bucket" -ErrorAction SilentlyContinue).LastWriteTime
}
$bucket.Manifests = Get-ChildItem "$path\bucket" -Force -Recurse -ErrorAction SilentlyContinue |
Measure-Object | Select-Object -ExpandProperty Count

View File

@@ -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 {
# .NET Framework 4.7+ has a default security protocol called 'SystemDefault',
# which allows the operating system to choose the best protocol to use.
@@ -145,41 +193,31 @@ function Invoke-Git {
$proxy = get_config PROXY
$git = Get-HelperPath -Helper Git
$arguments = $ArgumentList -join ' '
$cmd = "`"$git`" $arguments"
if ($WorkingDirectory) {
$cmd = "`"$git`" -C `"$WorkingDirectory`" $arguments"
$ArgumentList = @('-C', $WorkingDirectory) + $ArgumentList
}
$sb = [scriptblock]::Create("& $cmd")
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') {
$old_https = $env:HTTPS_PROXY
$old_http = $env:HTTP_PROXY
try {
if($ArgumentList -Match '\b(clone|checkout|pull|fetch|ls-remote)\b') {
$j = Start-Job -ScriptBlock {
# convert proxy setting for git
if ($proxy.StartsWith('currentuser@')) {
$proxy = $using:proxy
if ($proxy -and $proxy.StartsWith('currentuser@')) {
$proxy = $proxy.Replace('currentuser@', ':@')
}
$env:HTTPS_PROXY = $proxy
$env:HTTP_PROXY = $proxy
return Invoke-Command $sb
}
catch {
error $_
return
}
finally {
$env:HTTPS_PROXY = $old_https
$env:HTTP_PROXY = $old_http
& $using:git @using:ArgumentList
}
$o = $j | Receive-Job -Wait -AutoRemoveJob
return $o
}
return Invoke-Command $sb
return & $git @ArgumentList
}
function Invoke-GitLog {
@@ -198,7 +236,7 @@ function Invoke-GitLog {
}
$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 appsdir($global) { "$(basedir $global)\apps" }
function shimdir($global) { "$(basedir $global)\shims" }
function modulesdir($global) { "$(basedir $global)\modules" }
function appdir($app, $global) { "$(appsdir $global)\$app" }
function versiondir($app, $version, $global) { "$(appdir $app $global)\$version" }
@@ -359,7 +398,7 @@ Function Test-CommandAvailable {
}
Function Test-GitAvailable {
Return [Boolean](Test-Path (Get-HelperPath -Helper Git) -ErrorAction Ignore)
return [Boolean](Get-HelperPath -Helper Git)
}
function Get-HelperPath {
@@ -377,8 +416,8 @@ function Get-HelperPath {
process {
switch ($Helper) {
'Git' {
$internalgit = "$(versiondir 'git' 'current')\mingw64\bin\git.exe"
if (Test-Path $internalgit) {
$internalgit = (Get-AppFilePath 'git' 'mingw64\bin\git.exe'), (Get-AppFilePath 'git' 'mingw32\bin\git.exe') | Where-Object { $_ -ne $null }
if ($internalgit) {
$HelperPath = $internalgit
} else {
$HelperPath = (Get-Command git -ErrorAction Ignore).Source
@@ -426,7 +465,10 @@ function Get-CommandPath {
} catch {
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')
} elseif ($comm.CommandType -eq 'Application') {
$comm.Source
@@ -550,125 +592,233 @@ function is_local($path) {
# operations
function run($exe, $arg, $msg, $continue_exit_codes) {
Show-DeprecatedWarning $MyInvocation 'Invoke-ExternalCommand'
Invoke-ExternalCommand -FilePath $exe -ArgumentList $arg -Activity $msg -ContinueExitCodes $continue_exit_codes
Show-DeprecatedWarning $MyInvocation 'Start-ExternalProcess'
Start-ExternalProcess -FilePath $exe -ArgumentList $arg -Prompt $msg -ContinueExitCodes $continue_exit_codes
}
function Invoke-ExternalCommand {
[CmdletBinding(DefaultParameterSetName = "Default")]
[CmdletBinding(DefaultParameterSetName = 'Default')]
[OutputType([Boolean])]
param (
[Parameter(Mandatory = $true,
Position = 0)]
[Alias("Path")]
[Parameter(Mandatory = $true, Position = 0)]
[Alias('Path')]
[ValidateNotNullOrEmpty()]
[String]
$FilePath,
[Parameter(Position = 1)]
[Alias("Args")]
[Alias('Args')]
[String[]]
$ArgumentList,
[Parameter(ParameterSetName = "UseShellExecute")]
[Parameter(ParameterSetName = 'UseShellExecute')]
[Switch]
$RunAs,
[Alias("Msg")]
[Parameter(ParameterSetName = 'UseShellExecute')]
[Switch]
$Quiet,
[Alias('Msg')]
[String]
$Activity,
[Alias("cec")]
[Alias('cec')]
[Hashtable]
$ContinueExitCodes,
[Parameter(ParameterSetName = "Default")]
[Alias("Log")]
[Parameter(ParameterSetName = 'Default')]
[Alias('Log')]
[String]
$LogPath
)
if ($Activity) {
Write-Host "$Activity " -NoNewline
Show-DeprecatedWarning $MyInvocation 'Start-ExternalProcess'
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.StartInfo.FileName = $FilePath
$Process.StartInfo.UseShellExecute = $false
if ($LogPath) {
if ($LogName) {
if ($FilePath -match '^msiexec(.exe)?$') {
$ArgumentList += "/lwe `"$LogPath`""
$ArgumentList += "/lwe `"$LogName`""
} else {
$redirectToLogFile = $true
$Process.StartInfo.RedirectStandardOutput = $true
$Process.StartInfo.RedirectStandardError = $true
}
}
if ($RunAs) {
$Process.StartInfo.UseShellExecute = $true
$Process.StartInfo.Verb = 'RunAs'
} else {
$Process.StartInfo.CreateNoWindow = $true
}
if ($FilePath -match '^((cmd|cscript|wscript|msiexec)(\.exe)?|.*\.(bat|cmd|js|vbs|wsf))$') {
$Process.StartInfo.Arguments = $ArgumentList -join ' '
} elseif ($Process.StartInfo.ArgumentList.Add) {
# ArgumentList is supported in PowerShell 6.1 and later (built on .NET Core 2.1+)
# ref-1: https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.processstartinfo.argumentlist?view=net-6.0
# ref-2: https://docs.microsoft.com/en-us/powershell/scripting/whats-new/differences-from-windows-powershell?view=powershell-7.2#net-framework-vs-net-core
$ArgumentList | ForEach-Object { $Process.StartInfo.ArgumentList.Add($_) }
} else {
# escape arguments manually in lower versions, refer to https://docs.microsoft.com/en-us/previous-versions/17w5ykft(v=vs.85)
$escapedArgs = $ArgumentList | ForEach-Object {
# escape N consecutive backslash(es), which are followed by a double quote, to 2N consecutive ones
$s = $_ -replace '(\\+)"', '$1$1"'
# escape N consecutive backslash(es), which are at the end of the string, to 2N consecutive ones
$s = $s -replace '(\\+)$', '$1$1'
# escape double quotes
$s = $s -replace '"', '\"'
# quote the argument
"`"$s`""
$Process.StartInfo.RedirectStandardOutput = $true
$Process.StartInfo.RedirectStandardError = $true
if ($WorkingDirectory) {
$Process.StartInfo.WorkingDirectory = ensure $WorkingDirectory
}
}
if ($Quiet) {
$Process.StartInfo.UseShellExecute = $true
$Process.StartInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
}
if ($EnvironmentVariables) {
$EnvironmentVariables.GetEnumerator() | ForEach-Object { $Process.StartInfo.EnvironmentVariables.Add($_.Key, $_.Value) }
}
if ($ArgumentList) {
if ($FilePath -match '^((cmd|cscript|wscript|msiexec)(\.exe)?|.*\.(bat|cmd|js|vbs|wsf))$') {
$Process.StartInfo.Arguments = $ArgumentList -join ' '
} elseif ($Process.StartInfo.ArgumentList.Add) {
# ArgumentList is supported in PowerShell 6.1 and later (built on .NET Core 2.1+)
# ref-1: https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.processstartinfo.argumentlist?view=net-6.0
# ref-2: https://docs.microsoft.com/en-us/powershell/scripting/whats-new/differences-from-windows-powershell?view=powershell-7.2#net-framework-vs-net-core
$ArgumentList | ForEach-Object { $Process.StartInfo.ArgumentList.Add($_) }
} else {
# escape arguments manually in lower versions, refer to https://docs.microsoft.com/en-us/previous-versions/17w5ykft(v=vs.85)
$escapedArgs = $ArgumentList | ForEach-Object {
# escape N consecutive backslash(es), which are followed by a double quote, to 2N consecutive ones
$s = $_ -replace '(\\+)"', '$1$1"'
# escape N consecutive backslash(es), which are at the end of the string, to 2N consecutive ones
$s = $s -replace '(\\+)$', '$1$1'
# escape double quotes
$s = $s -replace '"', '\"'
# quote the argument
"`"$s`""
}
$Process.StartInfo.Arguments = $escapedArgs -join ' '
}
$Process.StartInfo.Arguments = $escapedArgs -join ' '
}
try {
[void]$Process.Start()
} catch {
if ($Activity) {
Write-Host "error." -ForegroundColor DarkRed
if ($Prompt) {
Write-Host 'error.' -ForegroundColor DarkRed
}
error $_.Exception.Message
return $false
}
if ($redirectToLogFile) {
# we do this to remove a deadlock potential
# ref: https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.process.standardoutput?view=netframework-4.5#remarks
$stdoutTask = $Process.StandardOutput.ReadToEndAsync()
$stderrTask = $Process.StandardError.ReadToEndAsync()
}
# we do this to remove a deadlock potential
# ref: https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.process.standardoutput?view=netframework-4.5#remarks
$stdoutTask = $Process.StandardOutput.ReadToEndAsync()
$stderrTask = $Process.StandardError.ReadToEndAsync()
$Process.WaitForExit()
if ($redirectToLogFile) {
Out-UTF8File -FilePath $LogPath -Append -InputObject $stdoutTask.Result
Out-UTF8File -FilePath $LogPath -Append -InputObject $stderrTask.Result
Out-UTF8File -FilePath $LogName -Append -InputObject $stdoutTask.Result.Trim()
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 ($ContinueExitCodes -and ($ContinueExitCodes.ContainsKey($Process.ExitCode))) {
if ($Activity) {
Write-Host "done." -ForegroundColor DarkYellow
if ($Prompt) {
Write-Host 'done.' -ForegroundColor DarkYellow
}
warn $ContinueExitCodes[$Process.ExitCode]
return $true
} else {
if ($Activity) {
Write-Host "error." -ForegroundColor DarkRed
if ($Prompt) {
Write-Host 'error.' -ForegroundColor DarkRed
}
error "Exit code was $($Process.ExitCode)!"
return $false
}
}
if ($Activity) {
Write-Host "done." -ForegroundColor Green
if ($Prompt) {
Write-Host 'done.' -ForegroundColor Green
}
return $true
}
function env($name,$global,$val='__get') {
$target = 'User'; if($global) {$target = 'Machine'}
if($val -eq '__get') { [environment]::getEnvironmentVariable($name,$target) }
else { [environment]::setEnvironmentVariable($name,$val,$target) }
function Publish-Env {
if (-not ("Win32.NativeMethods" -as [Type])) {
Add-Type -Namespace Win32 -Name NativeMethods -MemberDefinition @"
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr SendMessageTimeout(
IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam,
uint fuFlags, uint uTimeout, out UIntPtr lpdwResult);
"@
}
$HWND_BROADCAST = [IntPtr] 0xffff;
$WM_SETTINGCHANGE = 0x1a;
$result = [UIntPtr]::Zero
[Win32.Nativemethods]::SendMessageTimeout($HWND_BROADCAST,
$WM_SETTINGCHANGE,
[UIntPtr]::Zero,
"Environment",
2,
5000,
[ref] $result
) | Out-Null
}
function 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) {
@@ -752,7 +902,7 @@ function Get-ShimTarget($ShimPath) {
if (!$shimTarget) {
$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())"
# convert to relative path
Push-Location $abs_shimdir
$relative_path = Resolve-Path -Relative $path
Pop-Location
$resolved_path = Convert-Path $path
Push-Location $abs_shimdir
$relative_path = Resolve-Path -Relative $resolved_path
Pop-Location
if ($path -match '\.(exe|com)$') {
# for programs with no awareness of any shell
@@ -797,6 +947,12 @@ function shim($path, $global, $name, $arg) {
if ($arg) {
Write-Output "args = $arg" | Out-UTF8File "$shim.shim" -Append
}
$target_subsystem = Get-PESubsystem $resolved_path
if ($target_subsystem -eq 2) { # we only want to make shims GUI
Write-Output "Making $shim.exe a GUI binary."
Set-PESubsystem "$shim.exe" $target_subsystem | Out-Null
}
} elseif ($path -match '\.(bat|cmd)$') {
# shim .bat, .cmd so they can be used by programs with no awareness of PSH
warn_on_overwrite "$shim.cmd" $path
@@ -882,19 +1038,9 @@ function shim($path, $global, $name, $arg) {
) -join "`n" | Out-UTF8File $shim -NoNewLine
} else {
warn_on_overwrite "$shim.cmd" $path
# find path to Git's bash so that batch scripts can run bash scripts
if (!(Get-CommandPath git)) {
error "Can't shim '$shim': 'git' is needed but not installed."
error "Please install git ('scoop install git') and try again."
exit 1
}
$gitdir = (Get-Item (Get-CommandPath git) -ErrorAction:Stop).Directory.Parent
if ($gitdir.FullName -imatch 'mingw') {
$gitdir = $gitdir.Parent
}
@(
"@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"
warn_on_overwrite $shim $path
@@ -1300,10 +1446,33 @@ Optimize-SecurityProtocol
# Load Scoop config
$configHome = $env:XDG_CONFIG_HOME, "$env:USERPROFILE\.config" | Select-Object -First 1
$configFile = "$configHome\scoop\config.json"
# Check if it's the expected install path for scoop: <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
# NOTE Scoop config file migration. Remove this after 2023/6/30
if ($scoopConfig) {
if ($scoopConfig -and $scoopConfig.PSObject.Properties.Name -contains 'lastUpdate') {
$newConfigNames = @{
'lastUpdate' = 'last_update'
'SCOOP_REPO' = 'scoop_repo'
@@ -1321,19 +1490,14 @@ if ($scoopConfig) {
$value = $scoopConfig.$($_.Key)
$scoopConfig.PSObject.Properties.Remove($_.Key)
$scoopConfig | Add-Member -MemberType NoteProperty -Name $_.Value -Value $value
if ($_.Key -eq 'lastUpdate') {
$scoopConfigChg = $true
}
}
}
if ($scoopConfigChg) { # Only save config file if there was a change
ConvertTo-Json $scoopConfig | Out-UTF8File -FilePath $configFile
}
ConvertTo-Json $scoopConfig | Out-UTF8File -FilePath $configFile
}
# END NOTE
# 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
$globaldir = $env:SCOOP_GLOBAL, (get_config GLOBAL_PATH), "$([System.Environment]::GetFolderPath('CommonApplicationData'))\scoop" | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -First 1

View File

@@ -27,7 +27,7 @@ function Expand-7zipArchive {
} else {
$7zPath = Get-HelperPath -Helper 7zip
}
$LogPath = "$(Split-Path $Path)\7zip.log"
$LogName = "$(Split-Path $Path)\7zip.log"
$DestinationPath = $DestinationPath.TrimEnd('\')
$ArgList = @('x', $Path, "-o$DestinationPath", '-xr!*.nsis', '-y')
$IsTar = ((strip_ext $Path) -match '\.tar$') -or ($Path -match '\.t[abgpx]z2?$')
@@ -42,22 +42,22 @@ function Expand-7zipArchive {
'Skip' { $ArgList += '-aos' }
'Rename' { $ArgList += '-aou' }
}
$Status = Invoke-ExternalCommand $7zPath $ArgList -LogPath $LogPath
$Status = Start-ExternalProcess $7zPath $ArgList -LogName $LogName
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) {
movedir "$DestinationPath\$ExtractDir" $DestinationPath | Out-Null
}
if (Test-Path $LogPath) {
Remove-Item $LogPath -Force
if (Test-Path $LogName) {
Remove-Item $LogName -Force
}
if ($IsTar) {
# Check for tar
$Status = Invoke-ExternalCommand $7zPath @('l', $Path) -LogPath $LogPath
$Status = Start-ExternalProcess $7zPath @('l', $Path) -LogName $LogName
if ($Status) {
# 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
} else {
abort "Failed to list files in $Path.`nNot a 7-Zip supported archive file."
@@ -95,7 +95,7 @@ function Expand-ZstdArchive {
$Removal
)
$ZstdPath = Get-HelperPath -Helper Zstd
$LogPath = Join-Path (Split-Path $Path) 'zstd.log'
$LogName = Join-Path (Split-Path $Path) 'zstd.log'
$DestinationPath = $DestinationPath.TrimEnd('\')
ensure $DestinationPath | Out-Null
$ArgList = @('-d', $Path, '--output-dir-flat', $DestinationPath, '-f', '-v')
@@ -107,16 +107,16 @@ function Expand-ZstdArchive {
# Remove original archive file
$ArgList += '--rm'
}
$Status = Invoke-ExternalCommand $ZstdPath $ArgList -LogPath $LogPath
$Status = Start-ExternalProcess $ZstdPath $ArgList -LogName $LogName
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$'
if (!$IsTar -and $ExtractDir) {
movedir (Join-Path $DestinationPath $ExtractDir) $DestinationPath | Out-Null
}
if (Test-Path $LogPath) {
Remove-Item $LogPath -Force
if (Test-Path $LogName) {
Remove-Item $LogName -Force
}
if ($IsTar) {
# Check for tar
@@ -154,13 +154,13 @@ function Expand-MsiArchive {
$MsiPath = 'msiexec.exe'
$ArgList = @('/a', "`"$Path`"", '/qn', "TARGETDIR=`"$DestinationPath\SourceDir`"")
}
$LogPath = "$(Split-Path $Path)\msi.log"
$LogName = "$(Split-Path $Path)\msi.log"
if ($Switches) {
$ArgList += (-split $Switches)
}
$Status = Invoke-ExternalCommand $MsiPath $ArgList -LogPath $LogPath
$Status = Start-ExternalProcess $MsiPath $ArgList -LogName $LogName
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")) {
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)")) {
Remove-Item "$DestinationPath\$(fname $Path)" -Force
}
if (Test-Path $LogPath) {
Remove-Item $LogPath -Force
if (Test-Path $LogName) {
Remove-Item $LogName -Force
}
if ($Removal) {
# Remove original archive file
@@ -200,7 +200,7 @@ function Expand-InnoArchive {
[Switch]
$Removal
)
$LogPath = "$(Split-Path $Path)\innounp.log"
$LogName = "$(Split-Path $Path)\innounp.log"
$ArgList = @('-x', "-d$DestinationPath", $Path, '-y')
switch -Regex ($ExtractDir) {
'^[^{].*' { $ArgList += "-c{app}\$ExtractDir" }
@@ -210,12 +210,12 @@ function Expand-InnoArchive {
if ($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) {
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) {
Remove-Item $LogPath -Force
if (Test-Path $LogName) {
Remove-Item $LogName -Force
}
if ($Removal) {
# Remove original archive file
@@ -241,8 +241,14 @@ function Expand-ZipArchive {
$OriDestinationPath = $DestinationPath
$DestinationPath = "$DestinationPath\_tmp"
}
# Disable progress bar to gain performance
$oldProgressPreference = $ProgressPreference
$global:ProgressPreference = 'SilentlyContinue'
# Compatible with Pscx v3 (https://github.com/Pscx/Pscx) ('Microsoft.PowerShell.Archive' is not needed for Pscx v4)
Microsoft.PowerShell.Archive\Expand-Archive -Path $Path -DestinationPath $DestinationPath -Force
$global:ProgressPreference = $oldProgressPreference
if ($ExtractDir) {
movedir "$DestinationPath\$ExtractDir" $OriDestinationPath | Out-Null
Remove-Item $DestinationPath -Recurse -Force
@@ -268,17 +274,17 @@ function Expand-DarkArchive {
[Switch]
$Removal
)
$LogPath = "$(Split-Path $Path)\dark.log"
$LogName = "$(Split-Path $Path)\dark.log"
$ArgList = @('-nologo', '-x', $DestinationPath, $Path)
if ($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) {
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) {
Remove-Item $LogPath -Force
if (Test-Path $LogName) {
Remove-Item $LogName -Force
}
if ($Removal) {
# Remove original archive file

View File

@@ -13,7 +13,7 @@
# following arguments are treated as non-option arguments, even if
# they begin with a hyphen. The "--" itself will not be included in
# the returned $opts. (POSIX-compatible)
function getopt($argv, $shortopts, $longopts) {
function getopt([String[]]$argv, [String]$shortopts, [String[]]$longopts) {
$opts = @{}; $rem = @()
function err($msg) {
@@ -24,10 +24,6 @@ function getopt($argv, $shortopts, $longopts) {
return [Regex]::Escape($str)
}
# ensure these are arrays
$argv = @($argv -split ' ')
$longopts = @($longopts)
for ($i = 0; $i -lt $argv.Length; $i++) {
$arg = $argv[$i]
if ($null -eq $arg) { continue }
@@ -81,6 +77,5 @@ function getopt($argv, $shortopts, $longopts) {
$rem += $arg
}
}
$opts, $rem
}

View File

@@ -365,7 +365,8 @@ function Invoke-Download ($url, $to, $cookies, $progress) {
}
if ($url -match 'api\.github\.com/repos') {
$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) {
$wreq.Headers.Add('Cookie', (cookie_header $cookies))
@@ -632,7 +633,7 @@ function cookie_header($cookies) {
function is_in_dir($dir, $check) {
$check = "$(fullpath $check)"
$dir = "$(fullpath $dir)"
$check -match "^$([regex]::escape("$dir"))(\\|`$)"
$check -match "^$([regex]::Escape("$dir"))([/\\]|`$)"
}
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" }
$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) {
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')) {
& $prog @arg
} else {
$installed = Invoke-ExternalCommand $prog $arg -Activity "Running installer..."
$installed = Start-ExternalProcess $prog $arg -Prompt 'Running installer...'
if(!$installed) {
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')) {
& $exe @arg
} 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." }
}
}
@@ -1066,13 +1067,18 @@ function ensure_none_failed($apps) {
foreach ($app in $apps) {
$app = ($app -split '/|\\')[-1] -replace '\.json$', ''
foreach ($global in $true, $false) {
if ($global) {
$instArgs = @('--global')
} else {
$instArgs = @()
}
if (failed $app $global) {
if (installed $app $global) {
info "Repair previous failed installation of $app."
& "$PSScriptRoot\..\libexec\scoop-reset.ps1" $app$(if ($global) { ' --global' })
& "$PSScriptRoot\..\libexec\scoop-reset.ps1" $app @instArgs
} else {
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) {
@($persist) | ForEach-Object {
$source, $null = persist_def $_
$source = Get-Item "$dir\$source"
$source = Get-Item "$dir\$source" -ErrorAction SilentlyContinue
if ($source.LinkType) {
$source_path = $source.FullName
# directory (junction)

View File

@@ -1,22 +1,17 @@
$modulesdir = "$scoopdir\modules"
function install_psmodule($manifest, $dir, $global) {
$psmodule = $manifest.psmodule
if (!$psmodule) { return }
if ($global) {
abort 'Installing PowerShell modules globally is not implemented!'
}
$targetdir = ensure (modulesdir $global)
$modulesdir = ensure $modulesdir
ensure_in_psmodulepath $modulesdir $global
ensure_in_psmodulepath $targetdir $global
$module_name = $psmodule.name
if (!$module_name) {
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 "Linking $(friendly_path $linkfrom) => $(friendly_path $dir)"
@@ -36,7 +31,9 @@ function uninstall_psmodule($manifest, $dir, $global) {
$module_name = $psmodule.name
Write-Host "Uninstalling PowerShell module '$module_name'."
$linkfrom = "$modulesdir\$module_name"
$targetdir = modulesdir $global
$linkfrom = "$targetdir\$module_name"
if (Test-Path $linkfrom) {
Write-Host "Removing $(friendly_path $linkfrom)"
$linkfrom = Convert-Path $linkfrom

View File

@@ -10,7 +10,7 @@ $defenderIssues = 0
$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 $true)
}
@@ -19,18 +19,18 @@ $issues += !(check_main_bucket)
$issues += !(check_long_paths)
$issues += !(Get-WindowsDeveloperModeStatus)
if (!(Test-HelperInstalled -Helper 7zip)) {
error "'7-Zip' is not installed! It's required for unpacking most programs. Please Run 'scoop install 7zip' or 'scoop install 7zip-zstd'."
if (!(Test-HelperInstalled -Helper 7zip) -and !(get_config USE_EXTERNAL_7ZIP)) {
warn "'7-Zip' is not installed! It's required for unpacking most programs. Please Run 'scoop install 7zip' or 'scoop install 7zip-zstd'."
$issues++
}
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++
}
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++
}

View File

@@ -59,7 +59,7 @@ function choose_item($list, $query) {
}
if (!$url) {
scoop help create
& "$PSScriptRoot\scoop-help.ps1" create
} else {
create_manifest $url
}

View File

@@ -43,7 +43,7 @@ if (is_scoop_outdated) {
if ($opt.u -or $opt.'no-update-scoop') {
warn "Scoop is out of date."
} else {
scoop update
& "$PSScriptRoot\scoop-update.ps1"
}
}

View File

@@ -47,15 +47,23 @@ $apps | ForEach-Object {
return
}
if (get_config NO_JUNCTION){
if (get_config NO_JUNCTION) {
$version = Select-CurrentVersion -App $app -Global:$global
} else {
$version = 'current'
}
$dir = versiondir $app $version $global
$json = install_info $app $version $global
if (!$json) {
error "Failed to hold '$app'."
continue
}
$install = @{}
$json | Get-Member -MemberType Properties | ForEach-Object { $install.Add($_.Name, $json.($_.Name)) }
if ($install.hold) {
info "'$app' is already held."
continue
}
$install.hold = $true
save_install_info $install $dir
success "$app is now held and can not be updated anymore."

View File

@@ -34,20 +34,19 @@ foreach ($item in $import.buckets) {
}
foreach ($item in $import.apps) {
$instArgs = @()
$holdArgs = @()
$info = $item.Info -Split ', '
$global = if ('Global install' -in $info) {
' --global'
} else {
''
if ('Global install' -in $info) {
$instArgs += '--global'
$holdArgs += '--global'
}
$arch = if ('64bit' -in $info -and '64bit' -ne $def_arch) {
' --arch 64bit'
if ('64bit' -in $info -and '64bit' -ne $def_arch) {
$instArgs += '--arch', '64bit'
} elseif ('32bit' -in $info -and '32bit' -ne $def_arch) {
' --arch 32bit'
$instArgs += '--arch', '32bit'
} elseif ('arm64' -in $info -and 'arm64' -ne $def_arch) {
' --arch arm64'
} else {
''
$instArgs += '--arch', 'arm64'
}
$app = if ($item.Source -in $bucket_names) {
@@ -58,9 +57,9 @@ foreach ($item in $import.apps) {
$item.Source
}
& "$PSScriptRoot\scoop-install.ps1" $app$global$arch
& "$PSScriptRoot\scoop-install.ps1" $app @instArgs
if ('Held package' -in $info) {
& "$PSScriptRoot\scoop-hold.ps1" $($item.Name)$global
& "$PSScriptRoot\scoop-hold.ps1" $item.Name @holdArgs
}
}

View File

@@ -1,7 +1,7 @@
# Usage: scoop info <app> [--verbose]
# Usage: scoop info <app> [options]
# Summary: Display information about an app
# Options:
# -v, --verbose Show full paths and URLs
# Help: Options:
# -v, --verbose Show full paths and URLs
. "$PSScriptRoot\..\lib\getopt.ps1"
. "$PSScriptRoot\..\lib\manifest.ps1" # 'Get-Manifest'
@@ -84,7 +84,7 @@ if ($manifest.depends) {
if (Test-Path $manifest_file) {
if (Get-Command git -ErrorAction Ignore) {
$gitinfo = (Invoke-Git -Path (Split-Path $manifest_file) -ArgumentList @('log', '-1', '-s', "--format='%aD#%an'", $manifest_file) 2> $null) -Split '#'
$gitinfo = (Invoke-Git -Path (Split-Path $manifest_file) -ArgumentList @('log', '-1', '-s', '--format=%aD#%an', $manifest_file) 2> $null) -Split '#'
}
if ($gitinfo) {
$item.'Updated at' = $gitinfo[0] | Get-Date
@@ -112,7 +112,7 @@ if ($status.installed) {
# Collect file list from each location
$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
$cacheFiles = Get-ChildItem $cachedir -Filter "$app#*"
@@ -120,7 +120,7 @@ if ($status.installed) {
$fileTotals = @()
foreach ($fileType in ($appFiles, $currentFiles, $persistFiles, $cacheFiles)) {
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
} else {
$fileTotals += 0

View File

@@ -56,7 +56,7 @@ if (is_scoop_outdated) {
if ($opt.u -or $opt.'no-update-scoop') {
warn "Scoop is out of date."
} else {
scoop update
& "$PSScriptRoot\scoop-update.ps1"
}
}

View File

@@ -69,7 +69,7 @@ $apps | ForEach-Object {
#region Workaround for #2952
if (test_running_process $app $global) {
continue
return
}
#endregion Workaround for #2952

View File

@@ -9,7 +9,7 @@ param($query)
. "$PSScriptRoot\..\lib\manifest.ps1" # 'manifest'
. "$PSScriptRoot\..\lib\versions.ps1" # 'Get-LatestVersion'
$list = @()
$list = [System.Collections.Generic.List[PSCustomObject]]::new()
try {
$query = New-Object Regex $query, 'IgnoreCase'
@@ -32,24 +32,90 @@ function bin_match($manifest, $query) {
if ((strip_ext $fname) -match $query) { $fname }
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 }
else { return $false }
}
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 = $apps | Where-Object {
if ($_.name -match $query) { return $true }
$bin = bin_match (manifest $_.name $bucket) $query
$apps | ForEach-Object {
$json = [System.Text.Json.JsonDocument]::Parse([System.IO.File]::ReadAllText($_.FullName))
$name = $_.BaseName
if ($name -match $query) {
$list.Add([PSCustomObject]@{
Name = $name
Version = $json.RootElement.GetProperty("version")
Source = $bucket
Binaries = ""
})
} else {
$bin = bin_match_json $json $query
if ($bin) {
$_.bin = $bin
return $true
$list.Add([PSCustomObject]@{
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) {
@@ -96,43 +162,35 @@ function search_remotes($query) {
(add them using 'scoop bucket add <bucket name>')"
}
$remote_list = @()
$results | ForEach-Object {
$name = $_.bucket
$bucket = $_.bucket
$_.results | ForEach-Object {
$item = [ordered]@{}
$item.Name = $_
$item.Source = $name
$list += [PSCustomObject]$item
$item.Source = $bucket
$remote_list += [PSCustomObject]$item
}
}
$list
$remote_list
}
$jsonTextAvailable = [System.AppDomain]::CurrentDomain.GetAssemblies() | Where-object { [System.IO.Path]::GetFileNameWithoutExtension($_.Location) -eq "System.Text.Json" }
Get-LocalBucket | ForEach-Object {
$res = search_bucket $_ $query
$local_results = $local_results -or $res
if ($res) {
$name = "$_"
$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 ($jsonTextAvailable) {
search_bucket $_ $query
} else {
search_bucket_legacy $_ $query
}
}
if ($list.Length -gt 0) {
if ($list.Count -gt 0) {
Write-Host "Results from local buckets..."
$list
}
if (!$local_results -and !(github_ratelimit_reached)) {
if ($list.Count -eq 0 -and !(github_ratelimit_reached)) {
$remote_results = search_remotes $query
if (!$remote_results) {
warn "No matches found."

View File

@@ -12,7 +12,7 @@
#
# 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:
#
@@ -82,7 +82,7 @@ function Get-ShimInfo($ShimPath) {
function Get-ShimPath($ShimName, $Global) {
'.shim', '.ps1' | ForEach-Object {
$shimPath = Join-Path (shimdir $Global) "$ShimName$_"
if (Test-Path $shimPath) {
if (Test-Path -LiteralPath $shimPath) {
return $shimPath
}
}
@@ -144,7 +144,7 @@ switch ($SubCommand) {
$other | ForEach-Object {
try {
$pattern = $_
[Regex]::New($pattern)
[void][Regex]::New($pattern)
} catch {
Write-Host "ERROR: Invalid pattern: " -ForegroundColor Red -NoNewline
Write-Host $pattern -ForegroundColor Magenta

View File

@@ -53,8 +53,16 @@ $apps | ForEach-Object {
}
$dir = versiondir $app $version $global
$json = install_info $app $version $global
if (!$json) {
error "Failed to unhold '$app'"
continue
}
$install = @{}
$json | Get-Member -MemberType Properties | ForEach-Object { $install.Add($_.Name, $json.($_.Name)) }
if (!$install.hold) {
info "'$app' is not held."
continue
}
$install.hold = $null
save_install_info $install $dir
success "$app is no longer held and can be updated again."

View File

@@ -89,7 +89,7 @@ function Sync-Scoop {
Rename-Item $newdir 'current' -ErrorAction Stop
} catch {
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 {

View File

@@ -36,14 +36,14 @@
$opt, $apps, $err = getopt $args 'asnup' @('all', 'scan', 'no-depends', 'no-update-scoop', 'passthru')
if ($err) { "scoop virustotal: $err"; exit 1 }
if (!$apps) { my_usage; exit 1 }
if (!$apps -and -$all) { my_usage; exit 1 }
$architecture = Format-ArchitectureString
if (is_scoop_outdated) {
if ($opt.u -or $opt.'no-update-scoop') {
warn 'Scoop is out of date.'
} else {
scoop update
& "$PSScriptRoot\scoop-update.ps1"
}
}

View File

@@ -4,7 +4,7 @@
param($command)
if (!$command) {
'ERROR: <command> missing'
error '<command> missing'
my_usage
exit 1
}
@@ -12,7 +12,7 @@ if (!$command) {
$path = Get-CommandPath $command
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
} else {
friendly_path $path

View File

@@ -17,6 +17,12 @@ Describe 'getopt' -Tag 'Scoop' {
$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' {
$null, $null, $err = getopt '-az' 'a' ''
$err | Should -Be 'Option -z not recognized.'