558 Commits

Author SHA1 Message Date
Hsiao-nan Cheung
851e100d15 fix(test): Fix 'cache_path' test in Linux
Signed-off-by: Hsiao-nan Cheung <niheaven@gmail.com>
2025-03-06 00:19:57 +08:00
Hsiao-nan Cheung
ac6f1baaf4 perf(shim): Update kiennq-shim to v3.1.2 (#6261) 2025-01-03 14:34:38 +08:00
Hsiao-nan Cheung
dc9d198014 docs(chglog): Update to 0.5.3 (#6258) 2024-12-30 13:55:32 +08:00
Chawye Hsu
84e00fdb77 fix(scoop-bucket): Add missing import for no_junction envs (#6181)
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
2024-10-11 14:20:43 +08:00
Ryan
7a309a1b00 fix(shim): properly check wslpath/cygpath command first (#6114)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2024-10-09 19:10:42 +08:00
HUMORCE
3577f91d82 fix(commands): Handling broken aliases (#6141) 2024-09-20 14:18:13 +08:00
kiennq
e0c682de7c fix(download): Fallback to default downloader when aria2 fails (#4292) 2024-08-26 16:10:30 +08:00
Hsiao-nan Cheung
79cf33d0b7 refactor(download): Move download-related functions to 'download.ps1' (#6095) 2024-08-11 17:23:59 +08:00
Olav Rønnestad Birkeland
7f99c499d7 fix (decompress): Expand-7zipArchive only delete temp dir / $extractDir if it is empty (#6092)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2024-08-09 11:03:51 +08:00
Hsiao-nan Cheung
859d1db51b chore(release): Bump to version 0.5.2 (#6080)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
Co-authored-by: Matt Cargile <74641867+mattcargile@users.noreply.github.com>
Co-authored-by: ccyykkcyk <91893497+ccyykkcyk@users.noreply.github.com>
2024-07-30 15:34:41 +08:00
Hsiao-nan Cheung
c7ec5c82b2 docs(chglog): Update CHANGELOG for v0.5.2 (#6081) 2024-07-25 20:29:02 +08:00
Hsiao-nan Cheung
46624b00c9 fix(core): Use 'Join-Path' to construct cache file path (#6079) 2024-07-25 13:54:26 +08:00
Hsiao-nan Cheung
49ee8ad6ec fix(scoop-hold): Use 'foreach' loop to allow 'continue' statement (#6078) 2024-07-25 13:00:36 +08:00
Hsiao-nan Cheung
5dc5dd22f8 fix(json): Fix JSON items counting function (#6073) 2024-07-23 19:55:40 +08:00
Hsiao-nan Cheung
5971f1dda8 builds(supporting): Update Json.Schema to 4.0.1 (#6072) 2024-07-23 19:13:00 +08:00
ccyykkcyk
0cb479abf0 fix(json): Don't serialize jsonpath return if only one result (#6066)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2024-07-22 19:02:06 +08:00
Matt Cargile
429ba7af5b fix(scoop-alias): Fix 'Option --verbose not recognized.' (#6062) 2024-07-17 22:12:29 +08:00
Hsiao-nan Cheung
be56faf290 chore(release): Bump to version 0.5.1 (#6057) 2024-07-17 10:38:53 +08:00
Hsiao-nan Cheung
69edc6dc54 chore(chglog): Update CHANGELOG for v0.5.1 (#6058) 2024-07-15 13:17:19 +08:00
L. Yeung
0138dc4266 fix(scoop-alias): Pass options correctly (#6003)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2024-07-15 13:06:22 +08:00
Bill ZHANG
1c271f5b90 fix(scoop-virustotal): Adjust json_path parameters to retrieve correct analysis stats (#6044) 2024-07-09 13:45:09 +08:00
qiuyk
a76884af19 fix(install): Fix parsing error when installing multiple apps w/ specific version (#6039)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2024-07-09 13:22:06 +08:00
Hsiao-nan Cheung
7cc4faea1d fix(bucket): Implement error handling for failed bucket addition (#6051) 2024-07-09 01:16:23 +08:00
Hsiao-nan Cheung
83f25a4673 fix(install): Expand env_set items (#6050) 2024-07-09 00:24:42 +08:00
Hsiao-nan Cheung
42af27d16c fix(sqlite): Fix compatibility with Windows PowerShell (#6045) 2024-07-08 13:43:22 +08:00
Hsiao-nan Cheung
716b6db3ae chore(release): Bump to version 0.5.0 (#6035) 2024-07-05 11:14:42 +08:00
Hsiao-nan Cheung
ade7aa4a15 (chore): Update changelog (#6036) 2024-06-30 18:19:19 +08:00
Hsiao-nan Cheung
7e0a2a28c6 Update chglog 2024-06-30 18:09:59 +08:00
Hsiao-nan Cheung
2d02483fb8 Merge branch 'master' into develop 2024-06-30 18:07:36 +08:00
Hsiao-nan Cheung
93359a43a1 fix(shim): Restore original path for JAR cmd (#6030) 2024-06-26 18:34:38 +08:00
L. Yeung
d8b3cc8a6c fix(checkver): Correct error messages (#6024) 2024-06-25 10:40:56 +08:00
Hsiao-nan Cheung
9239c26bbd feat(decompress): Use innounp-unicode as default Inno Setup Unpacker (#6028) 2024-06-24 21:20:29 +08:00
qiuyk
3a39ba048f fix(core): Limit the number of commands to get (#6013) 2024-06-14 00:18:14 +08:00
Hsiao-nan Cheung
a9ca75c0cd fix(core): Use correct path in 'bash' (#6006) 2024-06-11 11:03:35 +08:00
Matej Kafka
d20819e147 fix(core): Search for Git executable instead of any cmdlet (#5998) 2024-06-07 18:45:52 +08:00
L. Yeung
dec4232754 fix(decompress): Match extract_dir/extract_to and archives (#5983) 2024-05-26 15:36:06 +08:00
Chawye Hsu
fa1b42bf28 fix(checkver): Correct variable 'regex' to 'regexp' (#5993) 2024-05-26 14:30:47 +08:00
insertokername
700a2f4f5e feat(install): Added the ability to specify @ version when installing from url/file location (#5988) 2024-05-23 23:05:38 +08:00
Hsiao-nan Cheung
c9048ad978 fix(sqlite): Fix generic class error in PS5 (#5981) 2024-05-20 20:57:29 +08:00
Hsiao-nan Cheung
5c896e901f refactor(decompress): Use 7zip to extract Zstd archive (#5973) 2024-05-17 09:56:14 +08:00
Hsiao-nan Cheung
8ea37387ae fix(install): Add back arg $Name in Invoke-Installer() (#5971) 2024-05-15 19:25:35 +08:00
Hsiao-nan Cheung
2544745695 refactor(install): Replace 'run_(un)installer()' with 'Invoke-Installer()' (#5968) 2024-05-15 19:03:54 +08:00
Hsiao-nan Cheung
5ce70c4139 fix(sqlite): Update cache after removing bucket or manifests (#5967) 2024-05-15 17:07:37 +08:00
L. Yeung
2d50a02a32 fix(scoop-download|install|update): Use consistent options (#5956) 2024-05-14 22:43:53 +08:00
Hsiao-nan Cheung
f6f46f6cf4 fix(sqlite): Dispose all command to release database file handle (#5966) 2024-05-14 16:38:05 +08:00
Hsiao-nan Cheung
d337bb1fa6 chore(release): Bump to version 0.4.2 (#5964)
Co-authored-by: Xuesong <amorphobia@users.noreply.github.com>
Co-authored-by: Inseo Lee <capella87@outlook.com>
2024-05-14 13:44:20 +08:00
Hsiao-nan Cheung
cddcd98e33 doc(chglog): Update CHANGLOG 2024-05-13 19:02:43 +08:00
Hsiao-nan Cheung
86d3fef187 fix(core): Add 'PSObject.Copy()' to 'substitute()' (#5962) 2024-05-13 18:53:30 +08:00
Hsiao-nan Cheung
e324fa4c5f fix(core): Fix "Invoke-ExternalCommand" quoting rules (#5945) 2024-05-13 18:53:15 +08:00
Inseo Lee
d9c5c90285 fix(system): Fix argument passing to Split-PathLikeEnvVar() in deprecated strip_path() (#5937)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2024-05-13 18:53:15 +08:00
Xuesong
82640c456e fix(autoupdate): Copy PSCustomObject-type properties within autoupdate to prevent reference changes (#5934) 2024-05-13 18:53:15 +08:00
Hsiao-nan Cheung
4dd2cfdc5f fix(core): Add 'PSObject.Copy()' to 'substitute()' (#5962) 2024-05-13 13:46:59 +08:00
Hsiao-nan Cheung
a5bd2297c6 refactor(install): Separate archive extraction from downloader (#5951) 2024-05-12 18:47:16 +08:00
Hsiao-nan Cheung
b710ff6c0a fix(scoop-info): Fix download size estimating (#5958) 2024-05-11 18:22:31 +08:00
Hsiao-nan Cheung
1dd479f0be fix(database): Use 'Find-BucketDirectory()' to locate bucket dir (#5955) 2024-05-11 14:50:20 +08:00
Hsiao-nan Cheung
1752050614 fix(core): Fix "Invoke-ExternalCommand" quoting rules (#5945) 2024-05-11 14:49:49 +08:00
Hsiao-nan Cheung
edaae8d39f fix(database): Skip caching 'deprecated' dir (#5949) 2024-05-09 20:15:57 +08:00
Hsiao-nan Cheung
776135e0ab fix(database): Update cache when adding bucket (#5946) 2024-05-08 18:10:13 +08:00
Chawye Hsu
cc863353e2 fix(scoop-cache): Fix regression in 36026f18 (#5944)
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
2024-05-08 11:24:41 +08:00
Inseo Lee
5b86c302e5 fix(system): Fix argument passing to Split-PathLikeEnvVar() in deprecated strip_path() (#5937)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2024-05-06 10:04:40 +08:00
Xuesong
b8580aa931 fix(autoupdate): Copy PSCustomObject-type properties within autoupdate to prevent reference changes (#5934) 2024-05-01 23:02:13 +08:00
Chawye Hsu
23d55ced72 fix(scoop-search): Catch error of parsing invalid manifest (#5930) 2024-05-01 00:52:49 +08:00
Chawye Hsu
36026f1804 feat(core): New cache filename format (#5929)
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2024-04-29 18:36:19 +08:00
Chawye Hsu
3b34497eb4 fix(json): Serialize jsonpath return (#5921) 2024-04-26 18:12:34 +08:00
Hsiao-nan Cheung
bb88dfb2d4 Sync 'master' branch 2024-04-25 22:09:16 +08:00
Chawye Hsu
d285bb08d4 chore(release): Bump to version 0.4.1 (#5924)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2024-04-25 21:33:45 +08:00
Hsiao-nan Cheung
eac58400db fix(sqlite): Skip use_sqlite_cache config on ARM64 platform (#5918) 2024-04-25 21:32:41 +08:00
Hsiao-nan Cheung
2dd91d5ba3 feat(sqlite): Use SQLite for caching apps to speed up local search (#5851) 2024-04-19 14:02:50 +08:00
Hsiao-nan Cheung
105e4161fc chore(release): Bump to version 0.4.0 (#5424)
Co-authored-by: Richard Kuhnt <r15ch13+git@gmail.com>
Co-authored-by: HUMORCE <humorce@outlook.com>
Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
Co-authored-by: Ross Smith II <ross@smithii.com>
Co-authored-by: Ercolino <fabrizio.ciccarese@gmail.com>
Co-authored-by: Jeppe Frandsen <jeppe@algrens.dk>
Co-authored-by: Chawye Hsu <chawyehsu@hotmail.com>
Co-authored-by: 0x574859 <Hex574859@outlook.com>
Co-authored-by: Valinor <Valinor@users.noreply.github.com>
Co-authored-by: Stephen Albert-Moore <stephen@sherbet.space>
Co-authored-by: L. Yeung <lewis_yeung-ly@outlook.com>
Co-authored-by: Bill ZHANG <36790218+Lutra-Fs@users.noreply.github.com>
Co-authored-by: walpo <68171111+walpox@users.noreply.github.com>
Co-authored-by: Suhas <98212676+spider2048@users.noreply.github.com>
Co-authored-by: Gerardo Grignoli <gerardog@gmail.com>
Co-authored-by: Dustin <131928587+dooptydoo90x@users.noreply.github.com>
Co-authored-by: Hagai Gold <hagaigold@gmail.com>
Co-authored-by: David Watson <davidlwatsonjr@users.noreply.github.com>
Co-authored-by: András Svraka <svraka.andras@gmail.com>
Co-authored-by: Xuesong <amorphobia@users.noreply.github.com>
2024-04-19 00:07:58 +08:00
Hsiao-nan Cheung
78f6fecd60 docs(changelog): Rearrange and update CHANGELOG (#5904) 2024-04-18 20:05:13 +08:00
Hsiao-nan Cheung
5819b5a1ef feat(path): Isolate Scoop apps' PATH (#5840) 2024-04-18 19:14:53 +08:00
Hsiao-nan Cheung
fa06e921c2 refactor(shim): Remove CS shim codebase (#5903) 2024-04-18 19:09:08 +08:00
Hsiao-nan Cheung
98cf8ae4da fix(autoupdate): Fix bug that 'WebClient' doesn't auto-extract 'gzip' (#5901) 2024-04-17 22:29:20 +08:00
Hsiao-nan Cheung
7054c9d338 fix(decompress): Use wix.exe in WiX Toolset v4+ as primary extractor of Expand-DarkArchive() (#5871) 2024-04-12 16:09:11 +08:00
Hsiao-nan Cheung
6327146b97 fix(shim): Run JAR file from app's root directory (#5872) 2024-04-11 15:56:43 +08:00
Hsiao-nan Cheung
92b71c6057 refactor(core): Get rid of 'fullpath' (#3533) 2024-04-10 14:55:20 +08:00
HUMORCE
81e7dec78c fix(scoop-alias): Prevent overwrite existing file when adding alias (#5577)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2024-04-08 23:26:38 +08:00
Xuesong
b008fe5b11 fix(scoop-virustotal): escape character not available in PowerShell 5.1 (#5870) 2024-04-08 23:24:18 +08:00
HUMORCE
5a06eacd9c refactor(helper): Remove 7zip's fallback '7zip-zstd' (#5548) 2024-04-08 23:23:57 +08:00
András Svraka
0b135052ce fix(scoop-shim): Import system.ps1 (#5864) 2024-04-04 21:39:51 +08:00
David Watson
9ef03c24fb perf(scoop-update): Check for running process before wasting time on download (#5799) 2024-04-01 18:31:01 +08:00
Hsiao-nan Cheung
dfbeace066 fix(system): Remove EnvVar only if existed (#5858) 2024-04-01 18:02:32 +08:00
Hsiao-nan Cheung
6772e61b3d refactor(core): Rewrite and separate path-related functions to system.ps1 (#5836) 2024-03-27 17:32:39 +08:00
Hsiao-nan Cheung
77b66cc890 fix(core): Fix arguments parsing method of Invoke-ExternalCommand() (#5839) 2024-03-25 19:19:44 +08:00
Hsiao-nan Cheung
9770c86598 fix(shim): Update kiennq-shim to v3.1.1 (#5847) 2024-03-25 18:07:31 +08:00
Hsiao-nan Cheung
5153d7375b perf(shim): Update kiennq-shim to v3.1 (#5841) 2024-03-22 19:06:27 +08:00
Hsiao-nan Cheung
5354ab5d16 builds(supporting): Update Json to 13.0.3, Json.Schema to 3.0.15 (#5835) 2024-03-21 13:30:51 +08:00
Suhas
90766f9315 fix(shim): Allow GUI applications to attach to the shell's console when launched using the GUI shim (#5721) 2024-03-20 22:16:10 +08:00
Hsiao-nan Cheung
3186fef105 fix(update/uninstall): Remove items from PATH correctly (#5833) 2024-03-20 17:17:48 +08:00
Hsiao-nan Cheung
9d07c33e87 fix(decompress): Remove unused parent dir w/ 'extract_dir' (#5682) 2024-03-13 18:41:58 +08:00
Hsiao-nan Cheung
6f9ed1d464 fix(ci): Update 'psmodulecache' version to 'main' (#5828) 2024-03-13 13:22:58 +08:00
Hsiao-nan Cheung
54e0514833 fix(install): Fix bugs in #5715 (#5824) 2024-03-07 10:55:27 +08:00
Hsiao-nan Cheung
7e3dc73b83 refactor(core): Cleanup some old codes, e.g., msi section and config migration (#5715) 2024-03-06 21:04:46 +08:00
HUMORCE
48f793532c fix(manifest): Correct source of manifest (#5575) 2024-02-23 17:41:44 +08:00
Rashil Gandhi
5328bef269 fix(config): Warn users about misconfigured token (#5777)
* Warn users about misconfigured token

* Update CHANGELOG.md
2024-01-05 23:46:28 +05:30
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
HUMORCE
68760de1e8 fix(shortcuts): Output correctly formatted path (#5333) 2023-01-09 11:01:40 +08:00
Hsiao-nan Cheung
257304bbc7 fix(decompress): Exclude '*.nsis' that may cause error (#5294) 2022-12-18 23:22:41 +08:00
Hsiao-nan Cheung
52f9ce3a81 fix(autoupdate): Fix file hash extraction (#5295) 2022-12-18 23:15:03 +08:00
HUMORCE
6369ba60ba refactor(scoop-download): Output more detailed manifest information (#5277) 2022-12-10 23:38:30 +08:00
Hsiao-nan Cheung
af5ffcddab test(bucket): Skip manifest validation if no manifest changes (#5270) 2022-11-30 13:32:35 +08:00
Richard Kuhnt
360daa706a feat(chore): Improve git.exe execution and add parallel bucket updates (#5122) 2022-11-23 13:58:51 +08:00
Hsiao-nan Cheung
f93028001f chore(release): Bump to version 0.3.1 (#5247) 2022-11-15 10:50:18 +08:00
Hsiao-nan Cheung
c60df9cdad docs(changelog): Prepare for version 0.3.1 (#5248) 2022-11-12 23:41:12 +08:00
Hsiao-nan Cheung
ac71c6e1b7 feat(sysinternals): Add 'sysinternals' bucket to known (#5237) 2022-11-11 01:11:54 +08:00
Hsiao-nan Cheung
0f795733d8 refactor(unix): Remove unix.ps1 (#5235) 2022-11-11 01:10:52 +08:00
Hsiao-nan Cheung
29ed3cb050 builds(checkhashes): Use correct version number if UseCache (#5240) 2022-11-10 14:38:29 +08:00
Hsiao-nan Cheung
d7bfe52122 fix(scoop-config): Output [DateTime] as [String] (#5232) 2022-10-31 20:33:54 +08:00
Chawye Hsu
29e5898a45 feat(checkup): Add Windows Developer Mode check (#5233) 2022-10-31 11:24:40 +08:00
Hsiao-nan Cheung
ea6c73880a tests(bucket): Use BuildHelpers EnvVars (#5226) 2022-10-28 15:20:36 +08:00
Hsiao-nan Cheung
e4f9734b88 fix(shim): Exit if shim creating failed 'cause no git (#5225) 2022-10-28 13:17:53 +08:00
Hsiao-nan Cheung
1630e5f908 tests(pester): Update to Pester 5 (#5222) 2022-10-28 13:14:29 +08:00
Hsiao-nan Cheung
2474ab73e4 builds(schema): Add 'installer' and 'shortcuts' to 'autoupdate' (#5220) 2022-10-25 23:51:36 +08:00
Hsiao-nan Cheung
d65fee6d26 docs(scoop-cat): Fix help message (#5224) 2022-10-25 23:50:46 +08:00
Hsiao-nan Cheung
01fe9ccd63 fix(import): Fix scoop import command (#5210) 2022-10-24 04:06:31 +08:00
Hsiao-nan Cheung
1c6ab39e90 ci: Update modules version (#5209) 2022-10-20 09:33:56 +08:00
pynappo
c71376e12c feat(config): Allow scoop to check and update 'nightly' apps (#5166)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-10-18 23:46:13 +08:00
Amadeus
c9dc41e7c4 docs(config): Copyedit config description (#5197)
Copyedit config description
2022-10-18 01:31:05 +05:30
Hsiao-nan Cheung
5e6a9eeaa0 builds(pssa): Remove unused 'ExcludeRules' (#5201) 2022-10-17 22:41:32 +08:00
Hsiao-nan Cheung
b308769b14 (chore): Sync with 'master' 2022-10-15 23:24:39 +08:00
Hsiao-nan Cheung
1eea29b0d1 fix(decompress): Trim ending '/' (#5195) 2022-10-15 23:19:16 +08:00
Hsiao-nan Cheung
7dcb7c0030 fix(tests): Fix tests in Linux and macOS (#5179) 2022-10-15 23:12:52 +08:00
Hsiao-nan Cheung
9fda5428ae builds(checkver): Support XML default namespace (#5191) 2022-10-15 20:17:48 +08:00
Hsiao-nan Cheung
d0cbc36a58 fix(hash): Fix SF hash extraction (#5189) 2022-10-14 18:21:52 +08:00
yi_Xu
512ab44029 builds(auto-pr): Add CommitMessageFormat option (#5171) 2022-10-14 16:48:39 +08:00
Chawye Hsu
1f0f687a39 chore(installer): Drop the old installer (#5186)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-10-14 14:56:05 +08:00
Hsiao-nan Cheung
ec8161df6c fix(decompress): Use PS's default 'Expand-Archive()' (#5185) 2022-10-14 14:29:24 +08:00
Hsiao-nan Cheung
24301ac028 refactor(hash): Use 'Get-FileHash()' directly (#5177) 2022-10-13 19:15:32 +08:00
Hsiao-nan Cheung
8aee6f9980 chore(release): Bump to version 0.3.0
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
Co-authored-by: Richard Kuhnt <r15ch13+git@gmail.com>
Co-authored-by: Mathias Hermansson <mathias.hermansson@se.ibm.com>
Co-authored-by: yi_Xu <yi_Xu@yixuju.cn>
Co-authored-by: Chawye Hsu <chawyehsu@hotmail.com>
Co-authored-by: L. Yeung <lewis_yeung-ly@outlook.com>
Co-authored-by: AkariiinMKII <6019344+AkariiinMKII@users.noreply.github.com>
Co-authored-by: KOGA Mitsuhiro <shiena.jp+github@gmail.com>
Co-authored-by: Jules <jules+dev@simplelogin.com>
Co-authored-by: César Román <thecesrom@gmail.com>
2022-10-13 19:09:34 +08:00
Hsiao-nan Cheung
9baf293ab6 docs(changelog): Prepare for version 0.3.0 (#5167) 2022-10-07 00:26:31 +08:00
Hsiao-nan Cheung
7f47f662e2 feat(subdir): Allow subdir in 'bucket' (#5119) 2022-09-28 11:22:33 +08:00
Rashil Gandhi
7a599f062f feat(install): Add support for ARM64 architecture (#5154)
* Initial support for ARMv8

* Add fallback mechanism

* Update changelog

* Update useragent

* Some typo and format changes

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

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

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

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

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

* Update CHANGELOG.md

* Update CHANGELOG.md [skip ci]

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

* docs(CHANGELOG): Update changelog

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

* Update lib/install.ps1

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

* Update lib/install.ps1

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

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

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

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

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

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

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

* Update libexec/scoop-config.ps1

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

* Update libexec/scoop-hold.ps1

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

* Update libexec/scoop-unhold.ps1

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

* Update libexec/scoop-update.ps1

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

* perf(scoop-update): Update last_scoop_update

* docs(changelog): update changelog to add feature

* fix(changelog): fix changelog typo

* Update libexec/scoop-update.ps1

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

* Update libexec/scoop-config.ps1

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

* Update libexec/scoop-update.ps1

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

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

Consistent with scoop-export.

* fix(install): make config lastUpdate silent

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

* fix: update changelog

remove none used code.

* Update lib/core.ps1

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

* Update libexec/scoop-update.ps1

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

* Update libexec/scoop-update.ps1

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

* Update libexec/scoop-update.ps1

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

* Update libexec/scoop-update.ps1

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

* Update libexec/scoop-update.ps1

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

* Update libexec/scoop-update.ps1

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

* Update libexec/scoop-update.ps1

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

* Update libexec/scoop-update.ps1

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

* Update libexec/scoop-update.ps1

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

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

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

* Update lib/core.ps1

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

* docs(CHANGELOG): Update changelog

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

* changelog

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

* change flag name to `--local`

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

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

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

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

* update CHANGELOG

* Use foreach instead of ForEach-Object

* changelog

* update help

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

* Update lib/buckets.ps1

Make warning clearer

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

Co-authored-by: Rashil Gandhi <rashil2000@gmail.com>
Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
2022-07-07 10:49:53 +05:30
Hsiao-nan Cheung
c5702ddd19 docs(changelog): Prepare for v0.2.3 (#5036) 2022-07-05 18:11:10 +08:00
Rashil Gandhi
f992f049cc fix(chore): Fix help output of scoop-export (#5029) 2022-07-02 23:21:10 +08:00
Hsiao-nan Cheung
76c3bcd70c builds(json): Update Newton.Json to 13.0.1 (#5026) 2022-07-01 22:29:48 +08:00
Hsiao-nan Cheung
794f8a51aa builds(checkver): Exit routine earlier if error (#5025) 2022-07-01 22:22:49 +08:00
Rashil Gandhi
53f0e9a18c feat(checkver,auto-pr): Allow passing file path (#5019)
* feat(checkver,auto-pr): Allow passing file path

* changelog

* reuse $App parameter

* Update CHANGELOG.md
2022-07-01 12:12:52 +05:30
Issac Lin
1b5ee6f090 fix(decompress): Handle split RAR archives (#4994) 2022-06-24 22:15:54 +08:00
Rashil Gandhi
c4d1b9c22f feat(scoop-import): Import a Scoop installation from JSON (#5014)
* feat(scoop-export): Export Scoop installation in JSON

* optimize

* yesss done

* complete

* Update CHANGELOG.md

* Add suggestions from code review

* fix CI
2022-06-24 11:12:01 +05:30
Rashil Gandhi
9811a5f853 feat(chore): Add missing -a/--all param to all commands (#5004)
* feat(scoop-reset): Add -a/--all switch to reset all apps

* feat(scoop-cache): Add -a/--all switch to delete whole cache

* feat(scoop-virustotal): Add -e/--every switch to check every installed app

* Update CHANGELOG.md

* use 'all' instead of 'every'
2022-06-22 15:47:31 +05:30
Rashil Gandhi
6629331799 feat(scoop-status): Check bucket status, improve output (#5011)
* feat(scoop-status): Check bucket status, improve output

* Update CHANGELOG.md
2022-06-22 15:40:24 +05:30
tech189
4fec4d7089 feat(scoop-info): Show app installed/download size (#4886)
Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-06-21 23:22:01 +08:00
Rashil Gandhi
83d0fef02f fix(shortcuts): Fix missing parentheses (#5006)
* fix(shortcuts): Fix missing parentheses

* Update CHANGELOG.md
2022-06-21 18:31:20 +05:30
Francois Botha
0fd6657572 tests(typo): Fix typo ('formated' -> 'formatted') (#4217)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-06-21 14:46:35 +08:00
Rashil Gandhi
9723725402 fix(chore): Update help documentation (#5002)
* tweaks to help system

* update help text

* update changelog

* fix order of printing deps

* Apply suggestions from code review

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

* Update scoop-help.ps1

* Update scoop.ps1

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-06-21 12:08:05 +05:30
Rashil Gandhi
847756bd1e refactor(scoop-search): Output PSObject, use API token (#4997)
* refactor(scoop-search): Output PSObject, use API token

* warn about parsing error

* Update CHANGELOG.md

* Update scoop-search.ps1

* Apply suggestions from code review

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

* separate lines

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-06-21 11:48:58 +05:30
Ying Fan Chong
86e3efbaf0 fix(shortcuts): Fix network drive shortcut creation (#4410)
Co-authored-by: Rashil Gandhi <rashil2000@gmail.com>
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-06-21 14:12:08 +08:00
Hsiao-nan Cheung
93db5f47f1 chore(release): Bump to version 0.2.2 2022-06-21 13:48:57 +08:00
Hsiao-nan Cheung
5987e499b9 docs(changelog): Update CHANGELOG for v0.2.2 (#5000)
A celebratable 5000
2022-06-21 00:13:33 +08:00
Chawye Hsu
666d474ee1 feat(scoop-update): Support scoop update scoop (#4992) 2022-06-20 14:43:28 +08:00
L. Yeung
e7c0faa29a feat(scoop-hold,scoop-unhold): Support -g/--global flag (#4991)
* feat(scoop-hold,scoop-unhold): Support `-g`/`--global` flag

* Update CHANGELOG.md
2022-06-17 10:53:18 +05:30
ClassicDarkChocolate
9e6c758c1f feat(scoop-virustotal): Migrate to VirusTotal API v3 (#4983) 2022-06-15 23:39:45 +08:00
Hsiao-nan Cheung
0b38c91f1a fix(manifest): Fix bugs in 'Get-Manifest()' (#4986) 2022-06-14 14:25:53 +08:00
yi_Xu
6e25e440af feat(core): Add 'Get-Encoding()' function to fix missing webClient encoding (#4956)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-06-13 23:21:57 +08:00
Hsiao-nan Cheung
d63b7d6f01 chore(release): Bump to version 0.2.1 2022-06-10 23:22:07 +08:00
Hsiao-nan Cheung
ecb8f02d4e Merge branch 'master' into develop 2022-06-10 23:17:38 +08:00
Hsiao-nan Cheung
7e6be8f3f5 Revert "chore(release): Bump to version 0.2.1 (#4960)"
This reverts commit 574bea4975.
2022-06-10 23:13:38 +08:00
Hsiao-nan Cheung
574bea4975 chore(release): Bump to version 0.2.1 (#4960)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
Co-authored-by: Chawye Hsu <chawyehsu@hotmail.com>
Co-authored-by: Issac Lin <issaclin32@gmail.com>
Co-authored-by: Garcha Sprgchma <904364+sprgchma@users.noreply.github.com>
Co-authored-by: L. Yeung <lewis_yeung-ly@outlook.com>
Co-authored-by: Lewin Chan <quotidian-ennui@users.noreply.github.com>
Co-authored-by: Xuesong <amorphobia@users.noreply.github.com>
Co-authored-by: ISHIKAWA Takayuki <topstone@users.noreply.github.com>
Co-authored-by: Rosen Penev <rosenp@gmail.com>
Co-authored-by: rayinfinite <rayinfinite@hotmail.com>
Co-authored-by: beerpsi <92439990+beerpiss@users.noreply.github.com>
Co-authored-by: HUMORCE <humorce@outlook.com>
Co-authored-by: Daniel Villarreal <7376487+danx12@users.noreply.github.com>
2022-06-10 23:02:16 +08:00
Hsiao-nan Cheung
9e70dcad79 fix(get-manfest): Add back '$appPath' (#4981) 2022-06-10 22:31:43 +08:00
Daniel Villarreal
64364b40b4 fix(buckets): Make sure list_buckets return array (#4979) 2022-06-10 18:06:00 +08:00
Chawye Hsu
387835753d docs(changelog): Fix CHANGELOG (#4977) 2022-06-10 10:17:23 +08:00
HUMORCE
bfb5c8d04a fix(scoop-download): Use correct Args when calling Get-Manifest (#4970) 2022-06-10 09:37:39 +08:00
Hsiao-nan Cheung
3a1186ea1b docs(changelog): Update CHANGELOG (#4969) 2022-06-07 09:45:28 +08:00
Hsiao-nan Cheung
ccd067b2b1 refactor(manifest): Rename 'Find-Manifest()' to 'Get-Manifest()' (#4966) 2022-06-07 09:31:30 +08:00
beerpsi
78c1bc45b4 fix(scoop-uninstall): run pre_uninstall before testing running processes (#4962) 2022-06-03 12:17:55 +08:00
Chawye Hsu
dd0f51426b feat(core): Add pre_uninstall and post_uninstall hooks (#4957) 2022-06-02 00:34:57 +08:00
rayinfinite
d6c6ddcbb3 fix(update): Prevent uninstall when update (#4949)
Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-06-02 00:27:48 +08:00
Rosen Penev
2e52888b63 chore(core): Deprecate tls1 and tls1.1 (#4950) 2022-05-28 22:38:29 +08:00
Rashil Gandhi
0f6d012d26 fix(shim): Add 'Get-CommandPath()' to find git (#4913)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-05-27 10:18:41 +08:00
Issac Lin
896ea6cdbd chore: Update Nonportable bucket URL (#4955) 2022-05-26 22:39:45 +08:00
Hsiao-nan Cheung
d056d542db fix(core): Use Invoke-Command instead of Invoke-Expression (#4941) 2022-05-26 10:54:34 +08:00
ISHIKAWA Takayuki
ad04dc9e6f fix(core): Allow to use '_' and '.' in bucket name (#4952) 2022-05-25 20:07:21 +08:00
Xuesong
8140a2052c fix(scoop-search): Require files in 'bucket' dir for remote known buckets (#4944) 2022-05-24 18:49:28 +08:00
L. Yeung
ac2fb38722 fix(scoop): Pass CLI arguments as string objects (#4931)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-05-18 00:06:08 +08:00
Lewin Chan
47d7f76f7c fix(scoop-info): Fix error message when manifest is not found (#4935) 2022-05-17 23:31:41 +08:00
L. Yeung
bb5392b486 fix(shim): Remove character replacement in .cmd -> .ps1 shims (#4914) 2022-05-17 23:18:10 +08:00
Garcha Sprgchma
f49f976618 fix(config): Load config file before initialization (#4932) 2022-05-17 23:02:56 +08:00
Chawye Hsu
5d58703484 docs(readme): Update license badge [skip ci] (#4929) 2022-05-17 17:12:26 +08:00
Issac Lin
b130e606cf fix(depends): Avoid digits in archive file extension (#4915)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-05-16 22:32:26 +08:00
Chawye Hsu
c6fc2de306 fix(buckets): Don't write message OK before bucket is cloned (#4925) 2022-05-15 17:10:08 +08:00
Hsiao-nan Cheung
a2600b1203 fix(buckets): Don't check remote URL of non-git buckets (#4923) 2022-05-15 15:49:38 +08:00
Hsiao-nan Cheung
aaa726c09f chore(release): Bump to version 0.2.0
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
Co-authored-by: Rashil Gandhi <rashil2000@gmail.com>
Co-authored-by: Chawye Hsu <chawyehsu@hotmail.com>
Co-authored-by: Tyler887 <tylermageeshields@gmail.com>
Co-authored-by: e6c31d <90863725+e6c31d@users.noreply.github.com>
Co-authored-by: tech189 <dlloyd189@gmail.com>
Co-authored-by: Thad Smith <thadmsmith@gmail.com>
Co-authored-by: Alex Stelmachonak <100310178+astelmachonak-nydig@users.noreply.github.com>
Co-authored-by: Kinshuk Bairagi <kingster@users.noreply.github.com>
Co-authored-by: kiennq <kien.n.quang@gmail.com>
Co-authored-by: CrendKing <975235+CrendKing@users.noreply.github.com>
Co-authored-by: Krisztián Csordás <cskrisztianster@gmail.com>
Co-authored-by: L. Yeung <lewis_yeung-ly@outlook.com>
2022-05-12 20:04:30 +08:00
Hsiao-nan Cheung
b93d0b4157 docs(changelog): Bump to v0.2.0 (#4909) 2022-05-08 18:33:12 +08:00
Hsiao-nan Cheung
0b6de90c03 feat(relicense): Relicense to dual-license (Unlicense or MIT) (#4903)
Co-authored-by: Chawye Hsu <chawyehsu@hotmail.com>
Co-authored-by: Tyler887 <tylermageeshields@gmail.com>
2022-05-08 11:13:09 +08:00
Hsiao-nan Cheung
b96abcfda9 feat(scoop-cleanup): Add -a/--all switch to cleanup all apps (#4906) 2022-05-07 11:23:33 +08:00
Hsiao-nan Cheung
cb7cd99e7a docs(changelog): Rearrange CHANGELOG (#4897) 2022-05-04 10:44:01 +08:00
L. Yeung
22365c2169 fix(bucket): Return empty list correctly in Get-LocalBucket (#4885)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
Co-authored-by: Rashil Gandhi <rashil2000@gmail.com>
2022-04-27 17:37:18 +08:00
Hsiao-nan Cheung
e6d03715fa fix(libs): Add missing 'json.ps1' dependency (#4884) 2022-04-23 01:44:03 +08:00
Hsiao-nan Cheung
6296822f1f perf(scoop): Load libs only once (#4839) 2022-04-21 21:34:26 +08:00
Krisztián Csordás
7ee74a0638 fix(scoop-list): Fix format specifier for minutes in date format (#4880) 2022-04-19 17:48:59 +08:00
Hsiao-nan Cheung
f947b620d5 fix(test): Remove 'description' requirement (#4874) 2022-04-16 01:19:51 +08:00
CrendKing
47c0f46d58 feat(checkver): Add option to throw error as exception (#4867) 2022-04-14 21:38:56 +05:30
Hsiao-nan Cheung
f6679c2170 build(schema): Remove 'description' from required fields (#4853) 2022-04-03 00:35:13 +08:00
kiennq
22c7d58e33 fix(shim-kiennq): Update shimexe file name (#4850) 2022-04-01 23:45:18 +08:00
Rashil Gandhi
55b26da657 (chore): doc: Update PR checklist (#4851) 2022-04-01 00:32:37 +08:00
Alex Stelmachonak
f441968983 feat(config): Try SCOOP_GH_TOKEN value first before gh_token value from config (#4842) 2022-03-26 23:42:36 +08:00
Chawye Hsu
72fd0c5f83 docs(readme): Update installation instruction (#4825) 2022-03-23 13:59:16 +08:00
Kinshuk Bairagi
d29e336417 fix(install): Fix Junction creation during installation inside containers (#4837) 2022-03-23 13:43:44 +08:00
Hsiao-nan Cheung
32de4c5714 refactor(bucket): Move 'Find-Manifest' and 'list_buckets' to 'buckets' (#4814) 2022-03-23 10:47:52 +08:00
Rashil Gandhi
ced36b285d doc(scoop-shim): Fix typo (#4836)
* Update scoop-shim.ps1

* Update CHANGELOG.md
2022-03-22 19:56:21 +05:30
Alex Stelmachonak
ad3fc4f8fb feat(config): Rename checkver_token to gh_token and SCOOP_CHECKVER_TOKEN to SCOOP_GH_TOKEN (#4832)
* Properly filtering null input in dl function when private_hosts is not set in config

* Rename checkver_token to gh_token and SCOOP_CHECKVER_TOKEN to SCOOP_GH_TOKEN
2022-03-22 03:30:19 +05:30
Thad Smith
45db5fb325 feat(install): Allow downloading from private repositories (#4254)
* added ability to use private github repositories

To do this, define a gh_api_token in the sccop config, if the repository is private it will use the apis to get and use the asset id

* corrected inherited linting error

* updated url to pull filename

* inlined get_headers and get-members functions and updated changelog

* simplified host headers and switched to checkver_token from: astelmachonak-nydig

* added ability to use private github repositories

To do this, define a gh_api_token in the sccop config, if the repository is private it will use the apis to get and use the asset id

* updated url to pull filename

* inlined get_headers and get-members functions and updated changelog

* simplified host headers and switched to checkver_token from: astelmachonak-nydig

* Update lib/core.ps1

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

* Update lib/core.ps1

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

* Fix RegEx

* Some tweaks

* optimize

Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
Co-authored-by: Rashil Gandhi <rashil2000@gmail.com>
2022-03-22 02:25:53 +05:30
Rashil Gandhi
5e4e6e9e5d doc(readme): Fix badges for Gitter and CI Tests (#4830)
* Update README.md

* Update CHANGELOG.md
2022-03-21 14:49:22 +05:30
tech189
53cdf68e26 fix(scoop-download): Add failure check (#4822)
* scoop-download failure check, aria2 warn if uninstalled

* Revert core.ps1

* Update CHANGELOG.md
2022-03-18 20:36:46 +05:30
Chawye Hsu
4d36cbd90d fix(decompress): Fix tarball decompression (#4813)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-03-17 20:30:43 +08:00
e6c31d
635ae1715a fix(shim): Correctly quote $@ in sh->ps1 shims (#4809) 2022-03-14 08:58:30 +05:30
Hsiao-nan Cheung
5a795caca5 refactor(reset_aliases): Move core function of reset_aliases to scoop (#4794) 2022-03-11 18:10:04 +08:00
Chawye Hsu
5025661fa2 fix(shim): Manipulating shims with UTF8 encoding (#4791) 2022-03-10 15:55:15 +08:00
Rashil Gandhi
476b507bb6 fix(update): Skip logs starting with (chore) (#4800)
* fix(update): Skip logs starting with `(chore)`

* Update CHANGELOG.md
2022-03-10 13:14:46 +05:30
Hsiao-nan Cheung
a66a086fb0 fix(installed): If no $global, check both local and global installed (#4798) 2022-03-10 13:05:49 +08:00
Hsiao-nan Cheung
60d308f7d6 fix(scoop-prefix): Fix typo that breaks global installed apps (#4795) 2022-03-10 01:24:46 +08:00
Hsiao-nan Cheung
af26d86d02 refactor(relpath): Use $PSScriptRoot instead of relpath (#4793) 2022-03-10 00:30:40 +08:00
Hsiao-nan Cheung
7d5a47cc77 fix(install): Use 'Get-Command' to test scoop install status (#4785) 2022-03-08 21:00:58 +08:00
Hsiao-nan Cheung
04b30de9dd chore(release): Bump to version 0.1.0 2022-03-08 12:58:14 +08:00
Hsiao-nan Cheung
750ea54d49 fix(shim): Fix scoop which error (#4780) 2022-03-07 22:14:26 +08:00
zStruCat
43d5e99705 fix(scoop-search): Remove redundant 'bucket/' in search result (#4773)
* fix remote search

* add hint

* tweak

* docs(changelog): Update CHANGELOG

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-03-07 15:43:30 +05:30
HUMORCE
63b858c41f style: Use correct casing for $PSScriptRoot (#4775) 2022-03-04 22:55:45 +08:00
Chawye Hsu
59328fc83c fix(config): Ensure manipulating config with UTF8 encoding (#4644) 2022-03-04 20:28:13 +08:00
HUMORCE
6bb5e932fe docs(changelog): Rearrange CHANGELOG (#4774) 2022-03-04 10:48:25 +08:00
Hsiao-nan Cheung
3af0cdbc21 docs(changelog): Rearrange CHANGELOG (#4770) 2022-03-02 12:03:45 +08:00
Hsiao-nan Cheung
765d3aad7e build(ci): Use cache in GitHub Actions (#4671) 2022-03-02 11:48:54 +08:00
Hsiao-nan Cheung
b740e98c36 docs(changelog): Bump to v0.1.0 (#4764) 2022-03-02 10:28:41 +08:00
Rashil Gandhi
a8e36d35c7 feat(scoop-config): Show all settings (#4765)
* feat(scoop-config): Show all settings

* cl
2022-02-28 10:53:45 +05:30
Hsiao-nan Cheung
9024ee450c fix(shim): Fix shim when app path has white spaces (#4734) 2022-02-26 22:52:46 +08:00
Hsiao-nan Cheung
e4580dd705 feat(scoop-shim): Add scoop shim to manipulate shims (#4736) 2022-02-26 22:32:54 +08:00
Hsiao-nan Cheung
a67937f77d fix(cleanup): Hotfix for #4681 (#4763) 2022-02-26 22:22:33 +08:00
Rashil Gandhi
aa61f1994a feat(scoop-info): Revamp details and show more information (#4747)
* feat(scoop-info): Introduce `verbose` flag

* feat(scoop-info): Allow passing local manifest paths

* feat(scoop-info): Show bucket and shortcuts

* feat(scoop-info): Show dependencies and suggestions

* feat(scoop-info): Show 'Updated at' and 'Updated by'

* changelog

* optimize git call

* restore clicky-ness of homepage

* simplify joining

* use getopt

* Update libexec/scoop-info.ps1

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

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-02-25 13:06:46 +05:30
HUMORCE
0cb6152e1a fix(scoop-bucket): Fix date formatting issues with git bucket(s) (#4759) 2022-02-25 11:32:50 +08:00
Xavier Young
4047d6962c perf(install): Avoid checking all files for unlink persisted data (#4681) 2022-02-25 10:08:07 +08:00
Rashil Gandhi
40b2d951e8 fix(scoop-bucket): Check for git before running command (#4756)
* fix(scoop-bucket): Check for git before running command

* Apply suggestions from code review

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

* Update CHANGELOG.md

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-02-24 15:11:40 +05:30
Rashil Gandhi
b95ccbe14a refactor(scoop-config): Use underscores everywhere (#4745) 2022-02-21 10:01:20 +08:00
Rashil Gandhi
e1f569b01b feat(scoop-cat): Use bat to pretty-print JSON (#4742)
* feat(scoop-cat): Use `bat` to pretty-print JSON

* update changelog

* hide filename and line numbers

* Add `cat_style` config option

* use underscores

* Revert "use underscores"

This reverts commit 46524fc947.

* Apply suggestions from code review

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

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-02-17 22:57:18 +05:30
Rashil Gandhi
d1f828c942 fix(scoop-info): Use pipe to separate bins (#4744) 2022-02-17 19:21:52 +05:30
Rashil Gandhi
26517644df refactor(scoop-info): Use List View for output (#4741)
* refactor(scoop-info): Use List View for output

* review comments
2022-02-17 08:21:38 +05:30
Rashil Gandhi
f83fa145de feat(scoop-cache): Handle multiple apps, show more information (#4738)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-02-16 13:06:23 +08:00
Hsiao-nan Cheung
21c5c6e775 fix(scoop-alias): Fix alias initialization (#4737)
* fix(scoop-alias): Fix alias initialization

* fix(scoop-alias): Remove 'Format-Table'
2022-02-14 20:17:15 +05:30
Hsiao-nan Cheung
c41cb84404 feat(scoop-alter): Add scoop alter command to switch shim's target (#4727) 2022-02-13 20:42:55 +08:00
Hsiao-nan Cheung
f24159c8f1 fix(test-running-process): Fix wrong output (#4731) 2022-02-11 15:09:46 +08:00
CrendKing
14854c3548 feat(config): Allow Scoop to ignore running processes during reset/uninstall/update (#4713)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-02-11 13:55:42 +08:00
Hsiao-nan Cheung
3345a5ed10 docs(changelog): Link CHANGELOG headers to 'releases/tag' (#4730) 2022-02-11 01:14:12 +08:00
Hsiao-nan Cheung
53f56e350f docs(changelog): Rearrange CHANGELOG (#4729) 2022-02-11 00:39:09 +08:00
jantari
ef2bfeb3f2 fix(config): Fix set_config bugs (#3681)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-02-11 00:38:39 +08:00
Hsiao-nan Cheung
b2a27f420d fix(shim-test): Remove unused shim files (#4726) 2022-02-09 19:01:33 +08:00
Hsiao-nan Cheung
c01960f283 fix(scoop-update): Enforce $null array (#4725) 2022-02-09 18:27:37 +08:00
Hsiao-nan Cheung
285ffd0322 fix(no-junction): Fix error when 'NO_JUNCTIONS' is been set (#4722) 2022-02-09 11:08:56 +08:00
Rashil Gandhi
b69bdbd6d2 feat(scoop-list): Show last-updated time (#4723) 2022-02-09 11:08:24 +08:00
Hsiao-nan Cheung
ba970d5c42 fix(versions): Get current version from failed installation if possible (#4720) 2022-02-09 11:07:54 +08:00
Rashil Gandhi
e450843827 refactor(scoop-list): Allow list manipulation (#4718)
* refactor(scoop-list): Allow list manipulation

* update changelog
2022-02-08 17:26:23 +05:30
Rashil Gandhi
f559c813df refactor(shim): Use -file instead of -command in ps1 script shims (#4721)
* refactor(shim): Use `-file` instead of `-command` in ps1 script shims

* update changelog

* Update CHANGELOG.md

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2022-02-08 10:42:20 +05:30
Rashil Gandhi
7967905980 fix(scoop-bucket): Use git instead of git_cmd (#4707) 2022-02-02 20:05:17 +00:00
HUMORCE
0e4721a408 feat(scoop-bucket): List more detailed information for buckets (#4704)
* refactor(scoop-bucket): Show source/lastupdate for buckets

* use `StartsWith`

* CHANGELOG

* punctuation

* style

* upd

* Update libexec/scoop-bucket.ps1

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

* count num of manifests in the buckets

* update changelog

* remove write-host

* friendly_path

* datetime format

* order

* sty

* prop.

* trim

* obj

* update CHANGELOG

Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
2022-02-03 01:13:37 +05:30
snowman
e0a5313132 fix(autoupdate): rename $response to $res (#4706)
* fix(autoupdate): rename $response to $res

* docs(changelog): Update CHANGELOG.md
2022-02-02 08:22:28 +05:30
Rashil Gandhi
8c02776c6c refactor(git): Remove unused functions (#4703)
* refactor(git): Remove unused functions

* unused imports
2022-02-01 11:37:44 +00:00
HUMORCE
c6b10c8f89 refactor(diagnostic,scoop-checkup): Improvements for 'check_windows_defender' and 'scoop-checkup' (#4699)
* Downgrade defender checks from `warn` to `info`

* checkup update

- Skip `check_windows_defender` when have not admin privileges
- Separate defender issues($defenderIssues)
- Security Tips

* Skip check for `ExclusionPath` if defender realtime protect is disabled

* elif

* CHANGELOG
2022-02-01 13:24:48 +05:30
HUMORCE
5b0bdaf893 refactor(git): Use 'git -C' to specify the work directory instead of 'Push-Location'/'Pop-Location' (#4697)
* add `git_cmd`

-without any preset command/args

* remove unnecessary import

- `git.ps1`

* stop `Push-Location` and `Pop-Location` before/after git operations

* stop `Push-Location` and `Pop-Location` before/after git operations

* consistency of naming variable

* CHANGELOG

* punctuation mark

* remove functions that are no longer used

- `git_fetch`
- `git_pull`
- `get_checkout`
2022-02-01 13:16:45 +05:30
Rashil Gandhi
ba28a4f4f1 refactor(COMSPEC): Deprecate use of subshell cmd.exe (#4692) 2022-01-26 10:47:39 +08:00
Hsiao-nan Cheung
3f4c191faa refactor(rmdir): Use 'Remove-Item' instead of 'rmdir' (#4691) 2022-01-26 02:34:21 +08:00
Hsiao-nan Cheung
4a9efaa2d9 fix(current): Remove 'current' while it's not a junction (#4687) 2022-01-26 01:41:15 +08:00
Hsiao-nan Cheung
98ea7a5e82 refactor(mklink): Use 'New-Item' instead of 'mklink' (#4690) 2022-01-26 01:13:09 +08:00
Hsiao-nan Cheung
2644a5f7b1 test(decompress): Import 'versions.ps1' (#4689) 2022-01-25 23:58:43 +08:00
Hsiao-nan Cheung
158c0fd4d0 fix(install-status): Correctly handle failed installation of apps (#4676) 2022-01-25 21:58:03 +08:00
Hsiao-nan Cheung
e09127f7be fix(versions): Fix wrong version number when only one version dir (#4679) 2022-01-21 13:05:43 +08:00
Hsiao-nan Cheung
37f5024194 build(ci): Disable CI test on 'push' (#4677) 2022-01-20 23:32:03 +08:00
Hsiao-nan Cheung
5f407ca434 build(schema): Fix typo ('note' -> 'notes') (#4678) 2022-01-20 23:08:40 +08:00
Hsiao-nan Cheung
d023e6cf0d fix(depends): Keep bucket in 'Get-Dependency()' (#4673) 2022-01-19 22:06:12 +08:00
Hsiao-nan Cheung
81b7aaf8d7 fix(scoop-update): Remove 'Done.' output (#4672) 2022-01-18 15:45:43 +08:00
Hsiao-nan Cheung
4e64db7f93 fix(cleanup): Remove apps other than current version (#4665) 2022-01-18 14:25:55 +08:00
Hsiao-nan Cheung
6f8bf04ce5 fix(scoop-update): Skip updating non git buckets (#4670) 2022-01-18 01:28:28 +08:00
Rashil Gandhi
c9df8f4017 fix(ci): Run on each commit in a PR (#4664) 2022-01-18 01:09:01 +08:00
Chawye Hsu
d9f55a3a0a refactor(ci,tests): Support both AppVeyor and GitHub Actions (#4655) 2022-01-14 19:40:35 +08:00
Hsiao-nan Cheung
d7fb97f517 test(zstd): Fix 'zstd' extraction error in test (#4651) 2022-01-13 16:32:18 +08:00
Hsiao-nan Cheung
d71fe82f9d fix(installed): Fix 'core/installed' that mark failed app as 'installed' (#4650) 2022-01-12 20:46:44 +08:00
Hsiao-nan Cheung
5b87c99aa8 refactor(deps): Rewrite 'depends.ps1' (#4638) 2022-01-12 11:10:55 +08:00
Hsiao-nan Cheung
3ca1b1f2e3 fix(decompress): Fix Split-Path -LeafBase in PS5 (#4639) 2022-01-10 14:22:12 +08:00
ipcjs
30f57aee6a fix(shim): Fix sh shim error in WSL (#4637) 2022-01-09 22:58:52 +08:00
Hsiao-nan Cheung
bc35a563b5 build(vscode-settings): Remove formatOnSave trigger (#4635) 2022-01-08 23:12:33 +08:00
Michael Ziminsky (Z)
25b170895f fix(depends): Check if extractor is available (#4042) 2022-01-08 20:08:26 +08:00
Parker Mauney
92c89f86ed build(schema): Add explicit escape to opening bracket matcher in jp/jsonpath regex (#3719) 2022-01-08 20:07:29 +08:00
Rashil Gandhi
cabaf59f62 feat(install|virustotal): Allow skipping update check (#4634) 2022-01-08 16:05:56 +05:30
Rashil Gandhi
9142703bce feat(download): Allow downloading without installing (#4621)
* feat(download): Allow downloading without installing

* update changelog

* rename 'skip' -> 'no-hash-check'

* add --no-update-scoop flag
2022-01-08 15:59:19 +05:30
Hsiao-nan Cheung
00adc0d828 build(checkver): Fix output with '-Version' (#3774) 2022-01-08 16:09:29 +08:00
Bruce Axtens
399274e242 docs: Add sudo note in LongPaths suggestion (#4382)
* added sudo to Set-ItemProperty incl note about sudo

* Update diagnostic.ps1

Co-authored-by: Bruce M. Axtens <bugmagnet@outlook.com>
Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
2022-01-08 12:24:18 +05:30
Hsiao-nan Cheung
4f5ecd029e fix(config): Allow scoop config use Unicode characters (#4631) 2022-01-08 00:23:07 +08:00
Hsiao-nan Cheung
c864f68c0b test(manifest): Fix manifests validation (#4620) 2022-01-07 13:33:05 +08:00
caoli5288
3c5f5ff20a build(schema): Add '$schema' property (#4623) 2022-01-07 02:57:28 +08:00
Issac Lin
fba658c020 fix(autoupdate): Allow checksum file that contains whitespaces (#4619) 2022-01-05 15:01:05 +08:00
Hsiao-nan Cheung
00f7859b3f fix(shim): Fix PS1 shim error when in different drive in PS7 (#4614)
Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
2022-01-05 14:58:49 +08:00
Hsiao-nan Cheung
5d8aeb54bb test(test-bin): Only write output file in CI and fix trailing whitespaces (#4613) 2021-12-31 02:14:53 +08:00
Hsiao-nan Cheung
d5cb86078b fix(decompress): Fix nested Zstd archive extraction (#4608) 2021-12-31 01:04:47 +08:00
Hsiao-nan Cheung
271d41b949 style(test): Format scripts by VSCode's PowerShell extension (#4609) 2021-12-30 09:37:40 +08:00
Hsiao-nan Cheung
36ae35c606 docs(changelog): Add 'CHANGLOG.md' (#4600) 2021-12-29 21:38:16 +08:00
Hsiao-nan Cheung
0d1ad20869 Sync branch 'master' 2021-12-26 23:03:38 +08:00
Hsiao-nan Cheung
5602083868 fix(schema): Add 'license' definition (#4596)
* fix(schema): Add 'license' definition

Fix AppVeyor error

* Fix 'Manifest.Tests'
2021-12-26 23:01:44 +08:00
Rashil Gandhi
2a0187458d fix(depends): Prevent error on no URL (#4595) 2021-12-25 21:46:23 +05:30
Hsiao-nan Cheung
1dbab1fee8 Merge branch 'develop' into 'master' (#4594)
Related PRs:
- #4531 @filmor 
  - ac71fcc @niheaven 
- #4535 @rashil2000 
- #4522 @pratikpc 
- #4550 @niheaven 
- #4528 @niheaven 
- #4532 @MrNuggelz
- #4155 @MrNuggelz Co-authored-by: @rashil2000 
  - #4581 @niheaven 
  - fb496c4 @rashil2000 
- #4543 @rashil2000 Co-authored-by: @niheaven 
  - #4555 @rashil2000 
  - 3c90d1a @rashil2000 
  - 2ec00d5 @rashil2000 
- #4567 @rashil2000 
  - cbe29ed @rashil2000 
- #4570 @niheaven 
  - #4582 @niheaven 
- #4571 @niheaven 
- #3244 @nickbudi 
- #3821 @jfastnacht Co-authored-by: @rasa 
- #4578 @tukanos
- #4579 @rashil2000 

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
Co-authored-by: Jakub Čábera <cabera.jakub@gmail.com>
Co-authored-by: Ross Smith II <ross@smithii.com>
Co-authored-by: Benedikt Reinartz <filmor@gmail.com>
Co-authored-by: Joris <MrNuggelz@users.noreply.github.com>
Co-authored-by: Pratik Chowdhury <pratikc@live.co.uk>
Co-authored-by: Rashil Gandhi <rashil2000@gmail.com>
Co-authored-by: nickbudi <nickbudi@users.noreply.github.com>
Co-authored-by: Julian <github@fastnacht.consulting>
Co-authored-by: tukanos <patrik.svestka@gmail.com>
2021-12-25 23:09:49 +08:00
Rashil Gandhi
5e11c94a54 docs: Add link to Contributing Guide 2021-12-23 23:44:46 +05:30
Rashil Gandhi
fb496c482b fix: Show manifest name while reviewing
Useful when Scoop installs dependencies and shows their manifests first
2021-12-23 17:00:06 +05:30
Rashil Gandhi
dec2598052 chore: Remove JetBrains bucket 2021-12-23 01:17:10 +05:30
Rashil Gandhi
af2056a8fd (chore): Update PR template 2021-12-20 23:51:43 +05:30
Rashil Gandhi
f343bd9f5e chore(config): Document all configuration options (#4579)
* chore(config): Document all configuration options

* Update README.md

* Update scoop-config.ps1

* Update scoop-config.ps1

* Update scoop-config.ps1

* Add env vars
2021-12-20 13:49:30 +05:30
Hsiao-nan Cheung
cdba268b47 fix(install): Don't show manifest while updating (#4581) 2021-12-16 18:41:36 +08:00
Rashil Gandhi
cbe29eddb3 chore: Update repo links 2021-12-16 01:09:21 +05:30
Hsiao-nan Cheung
cd6d31dae8 fix(decompress): Fix 'Expand-7zipArchive()' for nested archive (#4582) 2021-12-15 11:38:02 +08:00
tukanos
6f60059035 fix(core): Escape '.' in 'parse_app()'. (#4578) 2021-12-15 02:19:49 +08:00
Hsiao-nan Cheung
f3cdfffcfe Merge branch 'master' into develop 2021-12-15 02:16:52 +08:00
Julian
b966ca8c63 Check Windows version for LongPaths (#3821)
* Added the check for the Windows version.

* Apply suggestions from code review

Co-Authored-By: Jakub Čábera <cabera.jakub@gmail.com>

* Additional lines added by GitHubs suggestion system removed. Function for the version check removed. If-condition adjusted to check for Major and Build version.

* TIL Windows 8.1 = major version 6, Windows 10 = major version 10.

* Update diagnostic.ps1

Co-authored-by: Jakub Čábera <cabera.jakub@gmail.com>
Co-authored-by: Ross Smith II <ross@smithii.com>
2021-12-12 12:36:39 +05:30
nickbudi
2f7ff1bab5 feat(install): Add portableapps.com to strip_filename skips (#3244) 2021-12-12 11:56:17 +05:30
Rashil Gandhi
6c6a2ca410 chore: Add issue/PR templates (#4572)
* chore: Add issue/PR templates

* chore: Readme tweaks
2021-12-10 12:03:14 +05:30
Hsiao-nan Cheung
02da753fa7 fix(core): Use '-Encoding ASCII' in 'Out-File' (#4571) 2021-12-10 00:52:44 +08:00
Hsiao-nan Cheung
b488cb9ab3 fix(core): Redirect 'StandardError' in Invoke-ExternalCommand (#4570) 2021-12-10 00:52:34 +08:00
Rashil Gandhi
48b035d7f9 Remove nightlies bucket 2021-12-09 17:55:55 +05:30
Rashil Gandhi
386d3be20e fix(auto-pr): Remove hardcoded 'master' branch (#4567) 2021-12-08 22:21:20 +05:30
Joris
992e99358a feat(install): Show manifest on installation (#4155)
* show manifest on installation

* Inline function

* Update install.ps1

Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
2021-12-08 14:37:28 +05:30
Hsiao-nan Cheung
c1d48e4853 Merge branch 'master' into develop 2021-12-06 14:49:52 +08:00
Rashil Gandhi
4d5fee36e1 fix: Specify function scope
Resolve https://github.com/ScoopInstaller/Scoop/issues/4444#issuecomment-986229596
2021-12-06 11:30:30 +05:30
Rashil Gandhi
2ec00d576c fix(shim): Specify command arg for bash - fix #3878 2021-12-04 02:05:15 +05:30
Rashil Gandhi
37a886947d fix(checkver): Use GitHub token from environment (#4557)
* Use GitHub token from environment

* consistent naming

* Update bin/checkver.ps1

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

Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2021-12-03 21:01:51 +05:30
Rashil Gandhi
6387b7d1cd Merge pull request #4555 from ScoopInstaller/ps1-shim-patch
feat(shim): ps1 shim hotfix
2021-12-02 23:43:50 +05:30
Rashil Gandhi
3c90d1a070 specify command arg 2021-12-02 21:10:23 +05:30
Rashil Gandhi
ef4349bee4 feat(shim): Rework shimming logic (#4543)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2021-12-02 21:23:36 +08:00
Rashil Gandhi
c31ccea971 Merge pull request #4532 from MrNuggelz/patch-2
Add scoop cat command
2021-12-02 00:20:26 +05:30
Hsiao-nan Cheung
d021438b20 Revert "feat(shim): Add another alternative shim written in rust (#4229)" (#4553)
This reverts commit 5ad8c76dd7.

Co-authored-by: Zoritle <66551926+zoritle@users.noreply.github.com>
2021-12-01 08:46:26 -08:00
Hsiao-nan Cheung
ab8be955b4 feat(schema): Enable autoupdate for 'license' (#4528) 2021-12-01 22:41:50 +08:00
Hsiao-nan Cheung
5a1cdcb93d fix(install): 'env_add_path' doesn't append '.' (#4550) 2021-12-01 16:18:22 +08:00
Pratik Chowdhury
4ec9eccdb4 feat(checkver): improve JSONPath extraction support (#4522) 2021-11-29 16:55:13 +08:00
Rashil Gandhi
07ecd01159 Merge pull request #4535 from ScoopInstaller/rashil2000-patch-1
Use newer function - fixes #4534
2021-11-24 20:15:35 +05:30
Ross Smith II
3bb7036ee1 docs: Fix links in readme 2021-11-23 23:09:48 -08:00
Rashil Gandhi
1d5e81d2dc Use newer function - fixes #4534 2021-11-24 10:46:43 +05:30
Joris
29477d992a Add scoop cat command 2021-11-23 20:02:48 +01:00
Hsiao-nan Cheung
ac71fccbec fix(scoop-update): Update apps with '--all' 2021-11-23 16:53:42 +08:00
Benedikt Reinartz
0f5097be4f fix(scoop-update): Fix scoop update -a requiring arguments (#4531) 2021-11-23 16:37:28 +08:00
Hsiao-nan Cheung
f34be82516 Merge branch 'master' into develop 2021-11-22 22:50:01 +08:00
Hsiao-nan Cheung
59088a9f00 Merge from ScoopInstaller/develop (#4527), 2021/11/22 2021-11-22 22:40:34 +08:00
Rashil Gandhi
cf3f57caa3 Merge pull request #4524 from kodybrown/patch-1
Update notes about the NirSoft bucket
2021-11-20 18:27:14 +05:30
Ross Smith II
3c344682fe Better link 2021-11-19 14:43:50 -08:00
Ross Smith II
90fa473262 Fix nirsoft link 2021-11-19 13:32:36 -08:00
Kody Brown
bbad8aef6c updated notes about the NirSoft bucket,
which now includes almost all of the 250+ available utilities.
2021-11-19 13:29:23 -07:00
Rashil Gandhi
2bc2e652e3 Merge pull request #4514 from ScoopInstaller/se35710-patch-1
readme: Update Java bucket text
2021-11-15 17:03:34 +05:30
Mathias Hermansson
abcb04878c Update Java bucket text
This better reflect the actual contents of the bucket, rather than just a list of JDKs that varies over time.
2021-11-15 10:19:25 +01:00
Hsiao-nan Cheung
e663027299 fix(test): Add more test cases for versions 2021-11-15 13:32:25 +08:00
Hsiao-nan Cheung
ae89213842 fix(versions): Fix situation that contains '_' 2021-11-15 13:22:04 +08:00
Rashil Gandhi
6c2b34d29b Merge pull request #3871 from filmor/patch-1
Add flags as an alternative to '*' to update all
2021-11-15 10:30:02 +05:30
Issac Lin
6161f0bf9f Merge pull request #4368 from d3vel0per/patch-1
Updated README to reflect addition of Microsoft OpenJDK
2021-11-15 12:39:59 +08:00
Retia
baa20aef55 fix(install): Fix aria2's resume download feature (#3292)
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2021-11-14 21:00:55 +08:00
Hsiao-nan Cheung
77d00d1771 refactor(versions): Refactor 'versions.ps1' (#3721)
Co-authored-by: Jakub Čábera <cabera.jakub@gmail.com>
Co-authored-by: David Duque <david.f.s.duque@tecnico.ulisboa.pt>
2021-11-14 00:44:58 +08:00
Hsiao-nan Cheung
ef3bf14547 feat(supporting): Update Json to 12.0.3, Json.Schema to 3.0.14 (#3352) 2021-11-13 21:42:00 +08:00
Zoritle
5ad8c76dd7 feat(shim): Add another alternative shim written in rust (#4229)
* Add alt-shim support via scoop config shim rshim

* update to new version
2021-11-11 00:05:18 +08:00
Hsiao-nan Cheung
47ebc6f176 fix(test): Use 32bit version of zstd 2021-11-10 16:42:57 +08:00
Pratik Chowdhury
84590f89f4 Merge pull request #4504 from ScoopInstaller/rasa-fix-schema
Fix schema to support + in version
2021-11-09 23:03:39 -08:00
Hsiao-nan Cheung
e35ff313a5 fix(decompress): Check .zst first
And also trim `\` in `-DestinationPath`
2021-11-10 11:11:45 +08:00
worldyun
af7a6f6d0e feat(decompress): Support Zstandard archive (#4372)
Co-authored-by: WorldYun <worldyun@qq.com>
Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com>
2021-11-10 09:40:11 +08:00
Ross Smith II
948daa0c63 Fix schema to support + in version
See 	3590444367/bucket/x265.json (L2)
2021-11-09 11:41:54 -08:00
Hsiao-nan Cheung
1490869e6f fix(autoupdate): Update array of arrays correctly (#4502) 2021-11-08 19:55:03 +08:00
Hsiao-nan Cheung
dcce404529 fix(scoop-install.ps1): Auto uninstall previous failed installation (#3281) 2021-11-08 19:46:52 +08:00
Henry Ruben Fischer
8bb7390a75 feat(message): Add config to disable aria2 warning message (#4422) 2021-11-08 19:41:26 +08:00
Chawye Hsu
2047f8a929 Merge branch 'master' into develop 2021-11-05 21:23:53 +08:00
Pratik Chowdhury
458ec9003f feat(scoop-prefix): remove unused imports and functions (#4494) 2021-11-05 13:26:02 +08:00
Hsiao-nan Cheung
bae0be9581 fix(core): use script:url instead of url (#4492) 2021-11-03 13:23:11 +08:00
Gal Szkolnik
1e90310838 Fix incompatible with Pansies url alias
Fixes https://github.com/ScoopInstaller/Scoop/issues/4185
A continuation of https://github.com/ScoopInstaller/Scoop/pull/4342
2021-11-02 09:38:47 -04:00
Hsiao-nan Cheung
30e7967a04 feat(autoupdate): add multiple URL/hash/extract_dir... support 2021-11-01 13:36:37 +08:00
Rashil Gandhi
6c340cb7e3 Merge pull request #4013 from sinloss/patch-1
Fix #4000, handle arch-specific env_add_path
2021-11-01 10:55:27 +05:30
Rashil Gandhi
35b2a42ede Change url() scope to avoid conflict with global aliases (#4342)
(e.g. Pansies)
2021-11-01 09:01:05 +05:30
Derrick Liu
818162fe82 Restrict url() scope to avoid conflict with global aliases 2021-10-30 15:44:07 -07:00
Rashil Gandhi
b174775b71 chore: capitalize to prevent redirect (#4483) 2021-10-28 14:51:07 -07:00
Ross Smith II
5226f26f18 chore: s/lukesamson/ScoopInstaller in install.ps1 2021-10-25 18:28:51 -07:00
Ross Smith II
4f5acd7210 chore: s/lukesampson/ScoopInstaller in readme 2021-10-25 18:27:14 -07:00
Ross Smith II
f1a46e1095 chore: Update extras bucket url in readme 2021-10-25 18:18:37 -07:00
Ross Smith II
3e9a4d4ea0 chore: move extras bucket to @ScoopInstaller 2021-10-25 18:17:11 -07:00
d3vel0per
2cf025a80b Updated README to reflect addition of Microsoft OpenJDK 2021-05-26 20:42:51 +05:30
FriendlyNeighborhoodShane
0920050464 reset: skip when app instance is running (#4359)
The issue is the same as for #2952, workaround until the proper
solution is implemented. The code is also directly copied from there.

Fixes #4310
2021-05-20 17:50:06 +02:00
Mehmet Ümit
3d67b7d37c Fixed trailing whitespace issue (#4307) 2021-03-30 19:40:48 -07:00
liuxy
63a26584cd Fix the eol error complained by the tests 2020-12-21 11:32:43 +08:00
lxy
dc7df618c1 Merge pull request #2 from lukesampson/master
Merge upstream commits
2020-12-21 11:28:04 +08:00
lxy
8ecdb7cc14 Merge pull request #1 from lukesampson/master
fix(tests): Force pester v4 (#4040)
2020-12-21 11:22:15 +08:00
Ross Smith II
227de6cfb8 Fix typo in Makefile's comments 2020-10-25 10:43:08 -07:00
linsui
ad061d2a6a fix get_shim_path (#4149)
Co-authored-by: linsui <linsui555@gmail.com>
2020-10-25 08:54:06 -07:00
Ross Smith II
0948824ec7 Fix typo 2020-10-23 11:11:35 -07:00
Ross Smith II
b0557b647b Merge branch 'master' into develop 2020-10-22 22:42:57 -07:00
Ross Smith II
7db0fe9382 Add alt-shim support (fixes #3634) (#3998)
* Add alt-shim support via scoop config shim 71|kiennq

* Add exes for alt-shim support

* Bump kiennq's shim.exe to v2.2

* s/true/$true/

* Upgrade kiennq's shim to version 2.2.1

* Tweak Makefile to be less chatty

* Fix Makefile to correctly report bump
2020-10-22 22:39:22 -07:00
Ross Smith II
643cfb0da8 Merge branch 'develop' into master 2020-10-22 13:24:31 -07:00
lxy
c8453767b4 Annihilate the trailing whitespace 2020-08-13 10:19:29 +08:00
lxy
5e81d49984 Re-trigger tests 2020-08-13 09:46:18 +08:00
Jakub Čábera
9b29bbb711 fix(core): Fosshub download (#4051)
https://github.com/Ash258/Scoop-Core/releases/tag/0.5.0.1
2020-07-01 10:57:59 +02:00
Jakub Čábera
22a59866c7 fix(install): Aria2 inline progress negative values (#4053) 2020-07-01 10:56:39 +02:00
Jakub Čábera
6df80c1aee fix(tests): Force pester v4 (#4040) 2020-07-01 10:23:44 +02:00
liuxy
6659c55959 scoop-info: Handle arch-specific envs 2020-06-09 09:38:54 +08:00
liuxy
91ea657923 Apply the suggestions from @Ash258 2020-06-09 09:38:22 +08:00
lxy
3188115369 Fix #4000, handle arch-specific env_add_path 2020-06-08 10:16:47 +08:00
Greg Hutchinson
22fd6986bf fix(git): Don't execute autostart programs when executing git commands (#3993) 2020-05-21 19:54:44 +02:00
Brian Jubelirer
078b29bc80 chore(update): Update outdated PowerShell 5 warning (#3986) 2020-05-17 12:44:31 +02:00
Jakub Čábera
33a357241d feat(aria2): Inline progress (#3987) 2020-05-17 12:41:24 +02:00
Richard Kuhnt
573e0933cf Merge branch 'master' into develop 2020-05-14 19:39:49 +02:00
Richard Kuhnt
96de9c14bb hotfix(download): Progress bar on small files
Closes #3923
2020-05-14 19:39:35 +02:00
Hsiao-nan Cheung
7995f99dc1 fix(install): [Array]::Reverse error (#3976) 2020-05-12 21:08:43 +02:00
Hsiao-nan Cheung
f91968cb16 fix(install): let pathes in 'env_add_path' be added ascendantly (#3788)
Co-Authored-By: Chawye Hsu <chawyehsu@hotmail.com>
2020-05-11 19:05:33 +02:00
Benedikt Reinartz
0d721abc2f Add flags as an alternative to '*' to update all
Bash will parse the '*' on the shell level which results in a strange
experience for everyone not familiar with it when trying to update
all packages. This adds -a and --all as alternatives.
2020-05-05 18:07:30 +02:00
NilsonPark
48f121e466 core(install): Readd "Don't send referer to portableapps.com" (#3961)
PortableApps still get hosted on download3.portableapps.com
Reverts #2401
2020-05-05 12:31:39 +02:00
Chawye Hsu
eada459be9 chore(scoop): Remove temporary code from the scoop executable (#3898) 2020-04-20 15:30:31 +02:00
Jakub Čábera
398ccea2ae feat(checkver): Present script property (#3900) 2020-04-20 15:29:10 +02:00
Hugo Locurcio
50df0c52c4 chore(hold): Replace "locked" terminology with "held" for consistency (#3917) 2020-04-20 15:27:55 +02:00
Samuel Lorétan
e6b355eae0 feat(install): Follow HTTP redirections when downloading a file (#3902)
Co-Authored-By: Jakub Čábera <cabera.jakub@gmail.com>
2020-04-20 15:26:27 +02:00
Hsiao-nan Cheung
5851eaf762 feat(autoupdate): add multi-urls aupport to 'autoupdate'
Also refactor
- 'update_manifest_with_new_version' -> 'Update-ManifestProperty'
- 'update_manifest_prop' -> 'PropertyHelper'
- 'autoupdate' -> 'Invoke-AutoUpdate'

Co-Authored-By: Jakub Čábera <cabera.jakub@gmail.com>

Signed-off-by: Hsiao-nan Cheung <niheaven@gmail.com>
2020-03-10 14:30:09 +08:00
Hsiao-nan Cheung
2a91ddb101 refactor(autoupdate): 'get_version_substitutions' -> 'Get-VersionSubstitution'
Signed-off-by: Hsiao-nan Cheung <niheaven@gmail.com>
2020-03-10 13:46:36 +08:00
Hsiao-nan Cheung
3279bbfb71 feat(core): add 'PSCustomObject' support to 'core/substitute'
Signed-off-by: Hsiao-nan Cheung <niheaven@gmail.com>
2020-03-10 13:46:36 +08:00
Hsiao-nan Cheung
efcd3bfa38 feat(schema): add arch-spec items in 'autoupdate'
Signed-off-by: Hsiao-nan Cheung <niheaven@gmail.com>
2020-03-10 13:46:36 +08:00
Ross Smith II
9c9cc807ba feat(autoupdate): initial multi-urls works by @rasa
Add multiple URLs support to 'autoupdate'

Co-Authored-By: Jakub Čábera <cabera.jakub@gmail.com>

Signed-off-by: Hsiao-nan Cheung <niheaven@gmail.com>
2020-03-10 13:46:36 +08:00
Hsiao-nan Cheung
4eba120897 fix(install): fix 'failed' function (#3867) 2020-03-01 12:49:20 +01:00
Hsiao-nan Cheung
fe01ed52d5 fix(install): fix wrong output of 'install/failed' (#3784) 2020-02-29 14:24:08 +01:00
Chawye Hsu
ad9f7c6ff1 feat(checkup): Add check_envs_requirements 2020-02-23 13:55:19 +01:00
Chawye Hsu
062e6d7973 feat(diagnostic): Add check_envs_requirements 2020-02-23 13:55:19 +01:00
Jakub Čábera
48bb96a3d8 feat: Add configuration option for default architecture (#3778)
- Closes #3770
- New available command: `scoop config 'default-architecture' '32bit|64bit'`
2019-12-16 11:29:25 +01:00
linsui
e0c5ac2396 fix(scoop-info): check bucket of installed app (#3740)
Co-Authored-By: Jakub Čábera <cabera.jakub@gmail.com>
2019-12-02 12:43:39 +01:00
Sergio Livi
7e32139322 fix(git): enforce pull without rebase (#3765)
Prevent issues if user has `pull.rebase` set `interactive` in global gitconfig
2019-12-02 12:36:58 +01:00
Ross Smith II
a9fa775d59 chore(buckets.json): Update scoop-nonportable URL (#3776) 2019-12-01 12:27:29 +01:00
Chawye Hsu
5afad4e3d1 feat(list): Display main bucket name (#3759) 2019-11-20 20:15:05 +01:00
Richard Kuhnt
8ac23f8fbc feat(autoupdate): Add $urlNoExt and $basenameNoExt substitutions (#3742)
Mentioned in https://github.com/lukesampson/scoop-extras/pull/2124/files#r282758151
2019-11-09 20:02:59 +01:00
linsui
6eb90c9c11 fix(update): support $persist_dir in uninstaller.script (#3692) 2019-10-23 20:37:32 +02:00
Xiang ZHU
eb3d42de8f fix(install): execution policy check (#3619)
fix #3590
2019-10-18 19:16:33 +02:00
Richard Kuhnt
e997017f1a fix(update): Fix scoop update changelog output 2019-10-18 16:22:34 +02:00
Richard Kuhnt
8ee45a57dc chore(git): Remove unnecessary git_proxy_cmd() calls for local commands 2019-10-18 16:22:34 +02:00
linsui
ce3464f2f4 fix(core): Use [Environment]::Is64BitOperatingSystem instead of [intptr]::size (#3690) 2019-10-18 16:14:10 +02:00
Richard Kuhnt
08af9ff6e7 Merge branch 'develop' of github.com:lukesampson/scoop 2019-10-18 14:03:43 +02:00
Richard Kuhnt
e44b848f24 Revert "Update 2019-10-18" (#3696)
This reverts commit d948720961.
2019-10-18 13:56:46 +02:00
Richard Kuhnt
d948720961 Update 2019-10-18 2019-10-18 13:47:57 +02:00
Richard Kuhnt
11c42d782f fix(install): Allow installing specific version if latest is installed
closes #3693
see #3694
2019-10-18 13:36:25 +02:00
Hsiao-nan Cheung
5643818e1b Revert 'Compare-Version' (#3333, #3578) (#3648) 2019-10-18 13:32:06 +02:00
linsui
19ed5e42a8 fix(autoupdate): Decode basename when extract hash (#3615)
Co-authored-by: Jakub Čábera <cabera.jakub@gmail.com>
2019-10-14 14:07:38 +02:00
Stephane
9a3579c523 feature(update): allow updating apps from local manifest or URL (#3685)
- Closes #3683 
- Closes #3607

Co-Authored-By: Jakub Čábera <cabera.jakub@gmail.com>
2019-10-14 12:39:40 +02:00
Chawye Hsu
15e11e62ae fix(checkurls): Trim renaming suffix in url (#3677) 2019-10-06 10:35:09 +02:00
Jakub Čábera
9c04608c48 fix(install): Use Join-Path instead of string gluing. (#3566) 2019-10-04 21:22:31 +02:00
linsui
9f693cbb7d fix(scoop-info): remove a whitespace (#3652) 2019-09-19 16:51:54 +02:00
linsui
6fc708cb25 fix(scoop-info): Fix output for single binaries with alias (#3651) 2019-09-19 12:36:20 +02:00
Jakub Čábera
a09926f5b9 fix(appveyor): use VS2019 image to fix PS6 issues (#3646)
Close #3643
2019-09-17 21:56:51 +02:00
gitolicious
8165b1d468 fix(bucket): only lookup directories in buckets folder (#3631)
IntelliJ is putting a project file in the buckets folder when setting up a project there. The bucket lookup then tries to open this as a folder as it lacks directory filter.
2019-09-06 16:00:23 +02:00
3e55a70971 docs(readme): Improve installation instructions (#3600) 2019-09-02 13:38:30 +02:00
Edgard Lorraine Messias
e37e4ca666 feat(install): Use 7zip when available for faster zip file extraction (#3460) 2019-09-01 13:58:55 +02:00
Jakub Čábera
0d251bafd1 fix(update,uninstall): Regression from Get-Process workaround (#3610)
https://github.com/lukesampson/scoop/pull/3608
2019-08-26 15:32:08 +02:00
Hsiao-nan Cheung
c7d72d21b9 feat(install): Add arch support to env_add_path and env_set (#3503) 2019-08-26 14:58:55 +02:00
Jakub Čábera
f555968c39 fix(uninstall,update): Do not uninstall when application is running (#3608) 2019-08-23 20:09:18 +02:00
Jakub Čábera
f52b339523 feat(tests): Do not force maintainers to have SCOOP_HELPERS (#3604) 2019-08-21 17:17:26 +02:00
Hsiao-nan Cheung
96fef5827d fix(install): Allow $version to be used in uninstaller scripts (#3592) 2019-08-16 17:13:40 +02:00
Richard Kuhnt
7879d272b2 Merge branch 'master' into develop 2019-08-02 17:21:07 +02:00
Richard Kuhnt
79f8538b57 fix(auto-pr): hard reset bucket after running 2019-08-02 17:20:43 +02:00
Richard Kuhnt
073d10dbc9 Merge branch 'master' into develop 2019-08-02 13:18:52 +02:00
Richard Kuhnt
7decfd4c10 fix(auto-pr): Fix git status detection
- Reverts: https://github.com/lukesampson/scoop/pull/3026

See https://git-scm.com/docs/git-status#_short_format
If the file was modified it shows ` M` and `M ` means it's staged.
 Files only containing whitespaces don't get staged by `git add` and we only care about actually staged files.

Since the order of the `git status`-output is not sorted anymore the `Select-Object -First 1` is useless and it now uses `Where-Object` to find the correct line.
2019-08-02 13:18:26 +02:00
Hsiao-nan Cheung
3ca08a5ae8 fix(versions): Hotfix for #3333 (#3578)
* fix(versions): Hotfix for #3333
2019-08-02 11:52:14 +02:00
linsui
9ad783d3a5 fix(autoupdate): remove any whitespace from hash (#3579)
Allow extracting hashes with containing spaces and newlines
(e.g. `ef 5d 41 08 32 9c 71 b4 b5 b6 0f be 2f bc 49 ac ef 86 69 49 42 e8 37 65 a4 86 30
 10 ea be 0d 79`)

FreeCad Example:
```json
"hash": {
    "url": "$url-SHA256.txt",
    "regex": "(?sm):\\s+([a-f\\d\\s]+)CertUtil"
}
```
2019-08-01 18:08:16 +02:00
Hsiao-nan Cheung
1508d2ab00 fix(versions): Refactor compare_versions -> Compare-Version (#3333)
fix #3329 
fix #2981 
fix #2720 
fix lukesampson/scoop-extras#2106
close #3469
2019-07-31 15:36:19 +02:00
issaclin32
544e6094cc fix(decompress): fix bugs on extract_dir (#3540) 2019-07-24 22:37:31 +02:00
Eric Bouchard
78d2ff75f4 fix(help): Rename help() to scoop_help() (#3564)
When a user has an alias named `help`, the `scoop help` command does not work anymore.
To prevent collision with a user alias the function is renamed from `help` to `scoop_help`
2019-07-18 18:33:22 +02:00
Hsiao-nan Cheung
f33799dee8 improvement(core): tweak Invoke-ExternalCommand parameters (#3547)
- Redirect standard error to log file.
- Fix `-RunAs` error.
  - `-RunAs` and `-Log` cannot be used together.
2019-07-16 18:30:15 +02:00
Niklas H
0550605de1 fix(comspec): Escape variables when calling COMSPEC commands (#3538)
COMSPEC commands fail when called with unescaped directory arguments which contain white spaces (typically a compound user name).

- Closes lukesampson/scoop-extras#1781
- Closes lukesampson/scoop-extras#2389
- Closes #2801

Signed-off-by: Niklas H. <Typhoon.CommanderCool@gmail.com>
2019-07-02 15:46:43 +02:00
Huiyi.FYJ
b71b5074b2 fix(editorconfig): add missing } to bat/cmd regex (#3529) 2019-06-24 14:35:15 +02:00
Richard Kuhnt
b9b48182b4 Merge remote-tracking branch 'origin/develop' into develop 2019-06-24 14:27:09 +02:00
Hsiao-nan Cheung
1caaed8f3d feat(compress): Allow 'Expand-InnoArchive -ExtractDir' to accept '{xxx}' (#3487) 2019-06-24 14:26:35 +02:00
Jakub Čábera
e12a7da593 fix(bin): Checkhashes downloading twice when architecture properties does hot have url property (#3479) 2019-06-24 14:26:35 +02:00
Hsiao-nan Cheung
c8047bd5ed fix(decompress): '$ExtractDir' error with '.zip' and subdir (#3472)
For some `extract_dir` in .zip that has sub-dir, the former one would remove parent dir and get error (flac, flac-1.3.2-win\win64), now use temp dir instead. And also fix .msi, in case of some installer that don't have `SourceDir`.

`Expand-DarkArchive` will be used in wix extraction, so it doesn't need `-ExtractDir`.

`Expand-7zipArchive` and `Expand-InnoArchive` works well.

Tested:

- calibre-normal (msi, PFiles\Calibre2)
- flac (zip, flac-1.3.2-win\win64)
- pkg-config (zip, multiple url and extract_dir)

BTW, `Expand-Archive` has `-PassThru` param in PowerShell 6+, and it will be more convinient to support `-ExtractDir` with it. I'll check function's source code and plan to rewrite `Expand-ZipArchive`.

Fix #3473, ref https://github.com/lukesampson/scoop/issues/3473#issuecomment-493446461
2019-06-24 14:26:35 +02:00
Hsiao-nan Cheung
a882c4f1eb fix(decompress): '$ExtractDir' removed original extract file by accident (#3470) 2019-06-24 14:26:35 +02:00
Hsiao-nan Cheung
2fafcb880a feature(decompress): Add 'ExtractDir' to 'Expand-...' functions (#3466)
* feature(decompress): Add 'ExtractDir' to 'Expand-...' functions

* Fix 'TrimEnd' and nested 7z
2019-06-24 14:26:35 +02:00
Hsiao-nan Cheung
61d1c1c41a refactor(core): Add more generic 'Invoke-ExternalCommand' instead of 'run' (#3432) 2019-06-24 14:26:35 +02:00
Mark Huo
2d22ac8233 fix(config): show correct output when removing a config value (#3462) 2019-06-24 14:26:27 +02:00
Jakub Čábera
1836edba88 fix(checkhashes): Do not call scoop directly (#3527)
* fix(checkhashes): Do not call scoop directly

https://github.com/Ash258/GithubActionsBucketForTesting/runs/153802813

* Also fix build
2019-06-22 12:42:05 -07:00
Ross Smith II
e8d0be663b Update readme with correct count of nirsoft apps 2019-06-19 16:05:00 -07:00
Ross Smith II
03bb07c823 Fix typo in readme 2019-06-19 13:20:12 -07:00
Ross Smith II
2849e0f960 Add known buckets to end of readme
Fixes #3515
2019-06-19 13:18:24 -07:00
Asif Mehedi
69a0843e9a Fix a small typo (#3512) 2019-06-17 23:16:17 -07:00
Hsiao-nan Cheung
81e3cf61b6 feat(compress): Allow 'Expand-InnoArchive -ExtractDir' to accept '{xxx}' (#3487) 2019-05-30 14:55:48 +02:00
Richard Kuhnt
51f40e11c9 Sync hotfixes to develop 2019-05-29 18:55:38 +02:00
Jorg Heymans
1ac8ac0c65 hotfix(proxy): rename parameters for Net.NetworkCredential (#3483)
close #3471
2019-05-29 18:48:12 +02:00
jonz94
5d0d39abae fix(readme): adjust URL of runat.json (#3484) 2019-05-29 18:38:34 +02:00
Jakub Čábera
1b84fe04fc fix(bin): Checkhashes downloading twice when architecture properties does hot have url property (#3479) 2019-05-26 11:51:06 +02:00
Hsiao-nan Cheung
a775d452ff fix(decompress): '$ExtractDir' error with '.zip' and subdir (#3472)
For some `extract_dir` in .zip that has sub-dir, the former one would remove parent dir and get error (flac, flac-1.3.2-win\win64), now use temp dir instead. And also fix .msi, in case of some installer that don't have `SourceDir`.

`Expand-DarkArchive` will be used in wix extraction, so it doesn't need `-ExtractDir`.

`Expand-7zipArchive` and `Expand-InnoArchive` works well.

Tested:

- calibre-normal (msi, PFiles\Calibre2)
- flac (zip, flac-1.3.2-win\win64)
- pkg-config (zip, multiple url and extract_dir)

BTW, `Expand-Archive` has `-PassThru` param in PowerShell 6+, and it will be more convinient to support `-ExtractDir` with it. I'll check function's source code and plan to rewrite `Expand-ZipArchive`.

Fix #3473, ref https://github.com/lukesampson/scoop/issues/3473#issuecomment-493446461
2019-05-17 18:19:51 +02:00
Hsiao-nan Cheung
f5fdc275ca fix(decompress): '$ExtractDir' removed original extract file by accident (#3470) 2019-05-17 05:53:57 +02:00
Hsiao-nan Cheung
e6b2e3d31e feature(decompress): Add 'ExtractDir' to 'Expand-...' functions (#3466)
* feature(decompress): Add 'ExtractDir' to 'Expand-...' functions

* Fix 'TrimEnd' and nested 7z
2019-05-16 17:59:42 +02:00
Richard Kuhnt
6141e46d6a fix(decompress): Change dark.exe parameter order
https://github.com/lukesampson/scoop-extras/pull/2143
https://github.com/ScoopInstaller/Main/pull/56
2019-05-15 19:53:54 +02:00
Hsiao-nan Cheung
b9deb57d03 refactor(core): Add more generic 'Invoke-ExternalCommand' instead of 'run' (#3432) 2019-05-15 19:18:28 +02:00
Mark Huo
ad6198eeb4 fix(config): show correct output when removing a config value (#3462) 2019-05-15 18:08:08 +02:00
Richard Kuhnt
731d878490 Merge branch 'release/2019-05-15' 2019-05-15 17:51:56 +02:00
Chawye Hsu
765706ce38 fix(autoupdate): Handle xml namespace in xpath mode (#3465) 2019-05-15 16:54:59 +02:00
Chawye Hsu
f6062855ba feat(manifest): xpath support in checkver and autoupdate (#3458) 2019-05-13 21:06:26 +02:00
Chawye Hsu
16bdee060b fix(update): support changing scoop tracking repository (#3459)
Allows tracking of custom scoop fork:
```
$ scoop config SCOOP_REPO "https://github.com/<user>/scoop-fork"
$ scoop config SCOOP_BRANCH "patch-17"
$ scoop update
```
2019-05-13 21:01:45 +02:00
Richard Kuhnt
81226ae2f9 Sync hotfix #3454 to develop 2019-05-12 14:06:03 +02:00
Richard Kuhnt
b1a09e6b82 Sync hotfix #3453 to develop 2019-05-12 13:01:43 +02:00
140 changed files with 9719 additions and 5327 deletions

View File

@@ -12,9 +12,14 @@ indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.{bat,cmd,[Bb][Aa][Tt],[Cc][Mm][Dd]]
[*.{[Bb][Aa][Tt],[Cc][Mm][Dd]}]
# DOS/Win *requires* BAT/CMD files to have CRLF newlines
end_of_line = crlf
[*.{yml, yaml}]
indent_size = 2
# Makefiles require tab indentation
[{{M,m,GNU}akefile{,.*},*.mak,*.mk}]
indent_style = tab
end_of_line = lf

47
.github/ISSUE_TEMPLATE/Bug_report.md vendored Normal file
View File

@@ -0,0 +1,47 @@
---
name: "Bug Report"
about: "I am facing some problems."
title: '[Bug] '
labels: "bug"
---
<!--
IMPORTANT:
If your problem is related to a specific package, open the issue in the relevant bucket,
not here.
By opening this issue you confirm that you have searched for similar issues/PRs here already.
Failing to do so will most likely result in closing of this issue without any explanation.
Incomplete form details below might also result in closing of the issue.
-->
## Bug Report
#### Current Behavior
<!-- A clear and concise description of the behavior. -->
#### Expected Behavior
<!-- A clear and concise description of what you expected to happen. -->
#### Additional context/output
<!-- Add any other context about the problem here. If applicable, paste terminal output here to help explain. -->
#### Possible Solution
<!--- Only if you have suggestions on a fix for the bug -->
### System details
**Windows version:** [e.g. 7, 8, 10, 11]
**OS architecture:** [e.g. 32bit, 64bit, arm64]
**PowerShell version:** [output of `"$($PSVersionTable.PSVersion)"`]
**Additional software:** [(optional) e.g. ConEmu, Git]
#### Scoop Configuration
<!-- Can be found in ~/.config/scoop/config.json -->
```json
//# Your configuration here
```

View File

@@ -0,0 +1,27 @@
---
name: "Feature Request"
about: "I have a suggestion (and may want to implement it)!"
title: '[Feature] '
labels: "enhancement"
---
<!--
IMPORTANT:
If your request is related to a specific package, open the issue in the relevant bucket,
not here.
By opening this issue you confirm that you have searched for similar issues/PRs here already.
Failing to do so will most likely result in closing of this issue without any explanation.
Incomplete form details below might also result in closing of the issue.
-->
## Feature Request
#### Is your feature request related to a problem? Please describe.
<!-- A clear and concise description of what the problem is. Ex. I have an issue when [...] -->
#### Describe the solution you'd like
<!-- A clear and concise description of what you want to happen. Add any considered drawbacks. -->
#### Describe alternatives you've considered
<!-- A clear and concise description of any alternative solutions or features you've considered. -->

2
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,2 @@
blank_issues_enabled: false

35
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,35 @@
<!-- Provide a general summary of your changes in the Title above -->
<!-- To help with semantic versioning the PR title should start with one of the conventional commit types. -->
<!-- The conventional commit types for Semantic PR are: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert -->
<!--
By opening this PR you confirm that you have searched for similar issues/PRs here already.
Failing to do so will most likely result in closing of this PR without any explanation.
It is also mandatory to open a relevant issue for discussion with the maintainers,
before creating any new PR.
Read the contributing guide first to save both your and our time.
-->
#### Description
<!-- Describe your changes in detail -->
#### Motivation and Context
<!-- Why is this change required? What problem does it solve? -->
<!-- If it fixes an open issue, please link to the issue here. -->
Closes #XXXX
<!-- or -->
Relates to #XXXX
#### How Has This Been Tested?
<!-- Please describe in detail how you tested your changes. -->
<!-- Include details of your testing environment, tests ran to see how -->
<!-- your change affects other areas of the code, etc. -->
#### Checklist:
<!-- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!-- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] I have read the [Contributing Guide](https://github.com/ScoopInstaller/.github/blob/main/.github/CONTRIBUTING.md).
- [ ] I have ensured that I am targeting the `develop` branch.
- [ ] I have updated the documentation accordingly.
- [ ] I have updated the tests accordingly.
- [ ] I have added an entry in the CHANGELOG.

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"

39
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
name: Scoop Core CI Tests
on:
pull_request:
workflow_dispatch:
jobs:
test_powershell:
name: WindowsPowerShell
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@main
with:
fetch-depth: 2
- name: Init Test Suite
uses: potatoqualitee/psmodulecache@main
with:
modules-to-cache: BuildHelpers
shell: powershell
- name: Test Scoop Core
shell: powershell
run: ./test/bin/test.ps1
test_pwsh:
name: PowerShell
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@main
with:
fetch-depth: 2
- name: Init Test Suite
uses: potatoqualitee/psmodulecache@main
with:
modules-to-cache: BuildHelpers
shell: pwsh
- name: Test Scoop Core
shell: pwsh
run: ./test/bin/test.ps1

2
.gitignore vendored
View File

@@ -1,3 +1,4 @@
*.log
.DS_Store
._.DS_Store
scoop.sublime-workspace
@@ -5,3 +6,4 @@ test/installer/tmp/*
test/tmp/*
*~
TestResults.xml
supporting/sqlite/*

View File

@@ -1,13 +1,12 @@
// Configure PSScriptAnalyzer settings
{
"[powershell]": {
// Disable formating until: https://github.com/PowerShell/vscode-powershell/issues/1019 is fixed
"editor.formatOnSave": false
},
"powershell.scriptAnalysis.settingsPath": "PSScriptAnalyzerSettings.psd1",
"powershell.codeFormatting.preset": "OTBS",
"powershell.codeFormatting.alignPropertyValuePairs": true,
"powershell.codeFormatting.ignoreOneLineBlock": true,
"powershell.codeFormatting.useConstantStrings": true,
"powershell.codeFormatting.useCorrectCasing": true,
"powershell.codeFormatting.whitespaceBetweenParameters": true,
"files.exclude": {
"**/.git": true,
"**/.svn": true,

916
CHANGELOG.md Normal file
View File

@@ -0,0 +1,916 @@
## [v0.5.3](https://github.com/ScoopInstaller/Scoop/compare/v0.5.2...v0.5.3) - 2024-12-31
### Bug Fixes
- **scoop-download|install|update:** Fallback to default downloader when aria2 fails ([#4292](https://github.com/ScoopInstaller/Scoop/issues/4292))
- **decompress**: `Expand-7zipArchive` only delete temp dir / `$extractDir` if it is empty ([#6092](https://github.com/ScoopInstaller/Scoop/issues/6092))
- **commands**: Handling broken aliases ([#6141](https://github.com/ScoopInstaller/Scoop/issues/6141))
- **shim:** Do not suppress `stderr`, properly check `wslpath`/`cygpath` command first ([#6114](https://github.com/ScoopInstaller/Scoop/issues/6114))
- **scoop-bucket:** Add missing import for `no_junction` envs ([#6181](https://github.com/ScoopInstaller/Scoop/issues/6181))
### Code Refactoring
- **download:** Move download-related functions to 'download.ps1' ([#6095](https://github.com/ScoopInstaller/Scoop/issues/6095))
### Performance Improvements
- **shim:** Update kiennq-shim to v3.1.2 ([#6261](https://github.com/ScoopInstaller/Scoop/issues/6261))
## [v0.5.2](https://github.com/ScoopInstaller/Scoop/compare/v0.5.1...v0.5.2) - 2024-07-26
### Bug Fixes
- **scoop-alias:** Fix 'Option --verbose not recognized.' ([#6062](https://github.com/ScoopInstaller/Scoop/issues/6062))
- **scoop-hold:** Use 'foreach' loop to allow 'continue' statement ([#6078](https://github.com/ScoopInstaller/Scoop/issues/6078))
- **core:** Use 'Join-Path' to construct cache file path ([#6079](https://github.com/ScoopInstaller/Scoop/issues/6079))
- **json:** Don't serialize jsonpath return if only one result ([#6066](https://github.com/ScoopInstaller/Scoop/issues/6066), [#6073](https://github.com/ScoopInstaller/Scoop/issues/6073))
### Builds
- **supporting:** Update Json.Schema to 4.0.1 ([#6072](https://github.com/ScoopInstaller/Scoop/issues/6072))
## [v0.5.1](https://github.com/ScoopInstaller/Scoop/compare/v0.5.0...v0.5.1) - 2024-07-16
### Bug Fixes
- **scoop-alias:** Pass options correctly ([#6003](https://github.com/ScoopInstaller/Scoop/issues/6003))
- **scoop-virustotal:** Adjust `json_path` parameters to retrieve correct analysis stats ([#6044](https://github.com/ScoopInstaller/Scoop/issues/6044))
- **bucket:** Implement error handling for failed bucket addition ([#6051](https://github.com/ScoopInstaller/Scoop/issues/6051))
- **database:** Fix compatibility with Windows PowerShell ([#6045](https://github.com/ScoopInstaller/Scoop/issues/6045))
- **install:** Expand `env_set` items before setting Environment Variables ([#6050](https://github.com/ScoopInstaller/Scoop/issues/6050))
- **install:** Fix parsing error when installing multiple apps w/ specific version ([#6039](https://github.com/ScoopInstaller/Scoop/issues/6039))
## [v0.5.0](https://github.com/ScoopInstaller/Scoop/compare/v0.4.2...v0.5.0) - 2024-07-01
### Features
- **scoop-search:** Use SQLite for caching apps to speed up local search ([#5851](https://github.com/ScoopInstaller/Scoop/issues/5851), [#5918](https://github.com/ScoopInstaller/Scoop/issues/5918), [#5946](https://github.com/ScoopInstaller/Scoop/issues/5946), [#5949](https://github.com/ScoopInstaller/Scoop/issues/5949), [#5955](https://github.com/ScoopInstaller/Scoop/issues/5955), [#5966](https://github.com/ScoopInstaller/Scoop/issues/5966), [#5967](https://github.com/ScoopInstaller/Scoop/issues/5967), [#5981](https://github.com/ScoopInstaller/Scoop/issues/5981))
- **core:** New cache filename format ([#5929](https://github.com/ScoopInstaller/Scoop/issues/5929), [#5944](https://github.com/ScoopInstaller/Scoop/issues/5944))
- **decompress:** Use innounp-unicode as default Inno Setup Unpacker ([#6028](https://github.com/ScoopInstaller/Scoop/issues/6028))
- **install:** Added the ability to install specific version of app from URL/file link ([#5988](https://github.com/ScoopInstaller/Scoop/issues/5988))
### Bug Fixes
- **scoop-download|install|update:** Use consistent options ([#5956](https://github.com/ScoopInstaller/Scoop/issues/5956))
- **scoop-info:** Fix download size estimating ([#5958](https://github.com/ScoopInstaller/Scoop/issues/5958))
- **scoop-search:** Catch error of parsing invalid manifest ([#5930](https://github.com/ScoopInstaller/Scoop/issues/5930))
- **checkver:** Correct variable 'regex' to 'regexp' ([#5993](https://github.com/ScoopInstaller/Scoop/issues/5993))
- **checkver:** Correct error messages ([#6024](https://github.com/ScoopInstaller/Scoop/issues/6024))
- **core:** Search for Git executable instead of any cmdlet ([#5998](https://github.com/ScoopInstaller/Scoop/issues/5998))
- **core:** Use correct path in 'bash' ([#6006](https://github.com/ScoopInstaller/Scoop/issues/6006))
- **core:** Limit the number of commands to get when search for git executable ([#6013](https://github.com/ScoopInstaller/Scoop/issues/6013))
- **decompress:** Match `extract_dir`/`extract_to` and archives ([#5983](https://github.com/ScoopInstaller/Scoop/issues/5983))
- **json:** Serialize jsonpath return ([#5921](https://github.com/ScoopInstaller/Scoop/issues/5921))
- **shim:** Restore original path for JAR cmd ([#6030](https://github.com/ScoopInstaller/Scoop/issues/6030))
### Code Refactoring
- **decompress:** Use 7zip to extract Zstd archive ([#5973](https://github.com/ScoopInstaller/Scoop/issues/5973))
- **install:** Separate archive extraction from downloader ([#5951](https://github.com/ScoopInstaller/Scoop/issues/5951))
- **install:** Replace 'run_(un)installer()' with 'Invoke-Installer()' ([#5968](https://github.com/ScoopInstaller/Scoop/issues/5968), [#5971](https://github.com/ScoopInstaller/Scoop/issues/5971))
## [v0.4.2](https://github.com/ScoopInstaller/Scoop/compare/v0.4.1...v0.4.2) - 2024-05-14
### Bug Fixes
- **autoupdate:** Copy `PSCustomObject`-type properties within `substitute()` to prevent reference changes ([#5934](https://github.com/ScoopInstaller/Scoop/issues/5934), [#5962](https://github.com/ScoopInstaller/Scoop/issues/5962))
- **core:** Fix `Invoke-ExternalCommand` quoting rules ([#5945](https://github.com/ScoopInstaller/Scoop/issues/5945))
- **system:** Fix argument passing to `Split-PathLikeEnvVar()` in deprecated `strip_path()` ([#5937](https://github.com/ScoopInstaller/Scoop/issues/5937))
## [v0.4.1](https://github.com/ScoopInstaller/Scoop/compare/v0.4.0...v0.4.1) - 2024-04-25
### Bug Fixes
- **core:** Fix `Invoke-ExternalCommand` regression ([#5923](https://github.com/ScoopInstaller/Scoop/issues/5923))
## [v0.4.0](https://github.com/ScoopInstaller/Scoop/compare/v0.3.1...v0.4.0) - 2024-04-18
### Features
- **scoop-update:** Add support for parallel syncing buckets in PowerShell 7 and improve output ([#5122](https://github.com/ScoopInstaller/Scoop/issues/5122))
- **bucket:** Switch nirsoft bucket to ScoopInstaller/Nirsoft ([#5328](https://github.com/ScoopInstaller/Scoop/issues/5328))
- **bucket:** Make official buckets higher priority ([#5398](https://github.com/ScoopInstaller/Scoop/issues/5398))
- **config:** Support portable config file ([#5369](https://github.com/ScoopInstaller/Scoop/issues/5369))
- **core:** Add `-Quiet` switch for `Invoke-ExternalCommand` ([#5346](https://github.com/ScoopInstaller/Scoop/issues/5346))
- **core:** Allow global install of PowerShell modules ([#5611](https://github.com/ScoopInstaller/Scoop/issues/5611))
- **path:** Isolate Scoop apps' PATH ([#5840](https://github.com/ScoopInstaller/Scoop/issues/5840))
### Bug Fixes
- **scoop-alias:** Prevent overwrite existing file when adding alias ([#5577](https://github.com/ScoopInstaller/Scoop/issues/5577))
- **scoop-checkup:** Skip defender check in Windows Sandbox ([#5519](https://github.com/ScoopInstaller/Scoop/issues/5519))
- **scoop-checkup:** Change the message level of helpers from ERROR to WARN ([#5614](https://github.com/ScoopInstaller/Scoop/issues/5614))
- **scoop-checkup:** Don't throw 7zip error when external 7zip is used ([#5703](https://github.com/ScoopInstaller/Scoop/issues/5703))
- **scoop-(un)hold:** Correct output the messages when manifest not found, (already|not) held ([#5519](https://github.com/ScoopInstaller/Scoop/issues/5519))
- **scoop-info:** Fix errors in file size collection when `--verbose` ([#5352](https://github.com/ScoopInstaller/Scoop/issues/5352))
- **scoop-reset:** Don't abort when multiple apps are passed and an app is running ([#5687](https://github.com/ScoopInstaller/Scoop/issues/5687))
- **scoop-update:** Change error message to a better instruction ([#5677](https://github.com/ScoopInstaller/Scoop/issues/5677))
- **scoop-virustotal:** Fix `scoop-virustotal` when `--all` has been passed without app ([#5593](https://github.com/ScoopInstaller/Scoop/issues/5593))
- **scoop-virustotal:** Fix the issue that escape character not available in PowerShell 5.1 ([#5870](https://github.com/ScoopInstaller/Scoop/issues/5870))
- **autoupdate:** Fix file hash extraction ([#5295](https://github.com/ScoopInstaller/Scoop/issues/5295))
- **autoupdate:** Fix bug that 'WebClient' doesn't auto-extract 'gzip' ([#5901](https://github.com/ScoopInstaller/Scoop/issues/5901))
- **buckets:** Avoid error messages for unexpected dir ([#5549](https://github.com/ScoopInstaller/Scoop/issues/5549))
- **config:** Warn users about misconfigured GitHub token ([#5777](https://github.com/ScoopInstaller/Scoop/issues/5777))
- **core:** Fix scripts' calling parameters ([#5365](https://github.com/ScoopInstaller/Scoop/issues/5365))
- **core:** Fix `is_in_dir` under Unix ([#5391](https://github.com/ScoopInstaller/Scoop/issues/5391))
- **core:** Rewrite config file when needed ([#5439](https://github.com/ScoopInstaller/Scoop/issues/5439))
- **core:** Prevents leaking HTTP(S)_PROXY env vars to current sessions after Invoke-Git in parallel execution ([#5436](https://github.com/ScoopInstaller/Scoop/issues/5436))
- **core:** Handle scoop aliases and broken(edited,copied) shim ([#5551](https://github.com/ScoopInstaller/Scoop/issues/5551))
- **core:** Avoid error messages when deleting non-existent environment variable ([#5547](https://github.com/ScoopInstaller/Scoop/issues/5547))
- **core:** Use relative path as fallback of `$scoopdir` ([#5544](https://github.com/ScoopInstaller/Scoop/issues/5544))
- **core:** Fix detection of Git ([#5545](https://github.com/ScoopInstaller/Scoop/issues/5545))
- **core:** Do not call `scoop` externally from inside the code ([#5695](https://github.com/ScoopInstaller/Scoop/issues/5695))
- **core:** Fix arguments parsing method of `Invoke-ExternalCommand()` ([#5839](https://github.com/ScoopInstaller/Scoop/issues/5839))
- **decompress:** Exclude '*.nsis' that may cause error ([#5294](https://github.com/ScoopInstaller/Scoop/issues/5294))
- **decompress:** Remove unused parent dir w/ 'extract_dir' ([#5682](https://github.com/ScoopInstaller/Scoop/issues/5682))
- **decompress:** Use `wix.exe` in WiX Toolset v4+ as primary extractor of `Expand-DarkArchive()` ([#5871](https://github.com/ScoopInstaller/Scoop/issues/5871))
- **env:** Avoid automatic expansion of `%%` in env ([#5395](https://github.com/ScoopInstaller/Scoop/issues/5395), [#5452](https://github.com/ScoopInstaller/Scoop/issues/5452), [#5631](https://github.com/ScoopInstaller/Scoop/issues/5631))
- **getopt:** Stop split arguments in `getopt()` and ensure array by explicit arguments type ([#5326](https://github.com/ScoopInstaller/Scoop/issues/5326))
- **install:** Fix download from private GitHub repositories ([#5361](https://github.com/ScoopInstaller/Scoop/issues/5361))
- **install:** Avoid error when unlinking non-existent junction/hardlink ([#5552](https://github.com/ScoopInstaller/Scoop/issues/5552))
- **manifest:** Correct source of manifest ([#5575](https://github.com/ScoopInstaller/Scoop/issues/5575))
- **shim:** Remove console window for GUI applications ([#5559](https://github.com/ScoopInstaller/Scoop/issues/5559))
- **shim:** Use bash executable directly ([#5433](https://github.com/ScoopInstaller/Scoop/issues/5433))
- **shim:** Check literal path in `Get-ShimPath` ([#5680](https://github.com/ScoopInstaller/Scoop/issues/5680))
- **shim:** Avoid unexpected output of `list` subcommand ([#5681](https://github.com/ScoopInstaller/Scoop/issues/5681))
- **shim:** Allow GUI applications to attach to the shell's console when launched using the GUI shim ([#5721](https://github.com/ScoopInstaller/Scoop/issues/5721))
- **shim:** Run JAR file from app's root directory ([#5872](https://github.com/ScoopInstaller/Scoop/issues/5872))
- **shortcuts:** Output correctly formatted path ([#5333](https://github.com/ScoopInstaller/Scoop/issues/5333))
- **update/uninstall:** Remove items from PATH correctly ([#5833](https://github.com/ScoopInstaller/Scoop/issues/5833))
### Performance Improvements
- **scoop-search:** Improve performance for local search ([#5644](https://github.com/ScoopInstaller/Scoop/issues/5644))
- **scoop-update:** Check for running process before wasting time on download ([#5799](https://github.com/ScoopInstaller/Scoop/issues/5799))
- **decompress:** Disable progress bar to improve `Expand-Archive` performance ([#5410](https://github.com/ScoopInstaller/Scoop/issues/5410))
- **shim:** Update kiennq-shim to v3.1.1 ([#5841](https://github.com/ScoopInstaller/Scoop/issues/5841), [#5847](https://github.com/ScoopInstaller/Scoop/issues/5847))
### Code Refactoring
- **scoop-download:** Output more detailed manifest information ([#5277](https://github.com/ScoopInstaller/Scoop/issues/5277))
- **core:** Cleanup some old codes, e.g., msi section and config migration ([#5715](https://github.com/ScoopInstaller/Scoop/issues/5715), [#5824](https://github.com/ScoopInstaller/Scoop/issues/5824))
- **core:** Rewrite and separate path-related functions to `system.ps1` ([#5836](https://github.com/ScoopInstaller/Scoop/issues/5836), [#5858](https://github.com/ScoopInstaller/Scoop/issues/5858), [#5864](https://github.com/ScoopInstaller/Scoop/issues/5864))
- **core:** Get rid of 'fullpath' ([#3533](https://github.com/ScoopInstaller/Scoop/issues/3533))
- **git:** Use Invoke-Git() with direct path to git.exe to prevent spawning shim subprocesses ([#5122](https://github.com/ScoopInstaller/Scoop/issues/5122), [#5375](https://github.com/ScoopInstaller/Scoop/issues/5375))
- **helper:** Remove 7zip's fallback '7zip-zstd' ([#5548](https://github.com/ScoopInstaller/Scoop/issues/5548))
- **shim:** Remove CS shim codebase ([#5903](https://github.com/ScoopInstaller/Scoop/issues/5903))
### Builds
- **checkver:** Read the private_host config variable ([#5381](https://github.com/ScoopInstaller/Scoop/issues/5381))
- **supporting:** Update Json to 13.0.3, Json.Schema to 3.0.15 ([#5835](https://github.com/ScoopInstaller/Scoop/issues/5835))
### Continuous Integration
- **dependabot:** Add dependabot.yml for GitHub Actions ([#5377](https://github.com/ScoopInstaller/Scoop/issues/5377))
- **module:** Update 'psmodulecache' version to 'main' ([#5828](https://github.com/ScoopInstaller/Scoop/issues/5828))
### Tests
- **bucket:** Skip manifest validation if no manifest changes ([#5270](https://github.com/ScoopInstaller/Scoop/issues/5270))
### Documentation
- **scoop-info:** Fix help message([#5445](https://github.com/ScoopInstaller/Scoop/issues/5445))
- **readme:** Improve documentation language ([#5638](https://github.com/ScoopInstaller/Scoop/issues/5638))
## [v0.3.1](https://github.com/ScoopInstaller/Scoop/compare/v0.3.0...v0.3.1) - 2022-11-15
### Features
- **config:** Allow Scoop to check if apps versioned as 'nightly' are outdated ([#5166](https://github.com/ScoopInstaller/Scoop/issues/5166))
- **checkup:** Add Windows Developer Mode check ([#5233](https://github.com/ScoopInstaller/Scoop/issues/5233))
- **bucket:** Add 'sysinternals' bucket to known ([#5237](https://github.com/ScoopInstaller/Scoop/issues/5237))
### Bug Fixes
- **decompress:** Use PS's default 'Expand-Archive()' ([#5185](https://github.com/ScoopInstaller/Scoop/issues/5185))
- **hash:** Fix SourceForge's hash extraction ([#5189](https://github.com/ScoopInstaller/Scoop/issues/5189))
- **decompress:** Trim ending '/' ([#5195](https://github.com/ScoopInstaller/Scoop/issues/5195))
- **shim:** Exit if shim creating failed 'cause no git ([#5225](https://github.com/ScoopInstaller/Scoop/issues/5225))
- **scoop-import:** Add correct architecture argument ([#5210](https://github.com/ScoopInstaller/Scoop/issues/5210))
- **scoop-config:** Output `[DateTime]` as `[String]` ([#5232](https://github.com/ScoopInstaller/Scoop/issues/5232))
- **shim:** fixed shim add bug related to Resolve-Path ([#5492](https://github.com/ScoopInstaller/Scoop/issues/5492))
### Code Refactoring
- **hash:** Use `Get-FileHash()` directly ([#5177](https://github.com/ScoopInstaller/Scoop/issues/5177))
- **installer:** Drop the old installer ([#5186](https://github.com/ScoopInstaller/Scoop/issues/5186))
- **unix:** Remove `unix.ps1` ([#5235](https://github.com/ScoopInstaller/Scoop/issues/5235))
### Builds
- **auto-pr:** Add `CommitMessageFormat` option ([#5171](https://github.com/ScoopInstaller/Scoop/issues/5171))
- **checkver:** Support XML default namespace ([#5191](https://github.com/ScoopInstaller/Scoop/issues/5191))
- **pssa:** Remove unused 'ExcludeRules' ([#5201](https://github.com/ScoopInstaller/Scoop/issues/5201))
- **schema:** Add 'installer' and 'shortcuts' to 'autoupdate' ([#5220](https://github.com/ScoopInstaller/Scoop/issues/5220))
- **checkhashes:** Use correct version number if `UseCache` ([#5240](https://github.com/ScoopInstaller/Scoop/issues/5240))
### Continuous Integration
- **module:** Update modules version ([#5209](https://github.com/ScoopInstaller/Scoop/issues/5209))
### Tests
- **unix:** Fix tests in Linux and macOS ([#5179](https://github.com/ScoopInstaller/Scoop/issues/5179))
- **pester:** Update to Pester 5 ([#5222](https://github.com/ScoopInstaller/Scoop/issues/5222))
- **bucket:** Use BuildHelpers' EnvVars ([#5226](https://github.com/ScoopInstaller/Scoop/issues/5226))
### Documentation
- **scoop-cat:** Fix help message([#5224](https://github.com/ScoopInstaller/Scoop/issues/5224))
## [v0.3.0](https://github.com/ScoopInstaller/Scoop/compare/v0.2.4...v0.3.0) - 2022-10-10
### Features
- **install:** Add support for ARM64 architecture ([#5154](https://github.com/ScoopInstaller/Scoop/issues/5154))
- **install:** Show the running process ([#5102](https://github.com/ScoopInstaller/Scoop/issues/5102))
- **getopt:** Support option terminator (`--`) ([#5121](https://github.com/ScoopInstaller/Scoop/issues/5121))
- **subdir:** Allow subdir in 'bucket' ([#5119](https://github.com/ScoopInstaller/Scoop/issues/5119))
- **scoop-config:** Allow 'hold_update_until' be set manually ([#5100](https://github.com/ScoopInstaller/Scoop/issues/5100))
- **scoop-(un)hold:** Support `scoop (un)hold scoop` ([#5089](https://github.com/ScoopInstaller/Scoop/issues/5089))
- **scoop-update:** Stash uncommitted changes before update ([#5091](https://github.com/ScoopInstaller/Scoop/issues/5091))
### Bug Fixes
- **config:** Change config option to snake_case in file and SCREAMING_CASE in code ([#5116](https://github.com/ScoopInstaller/Scoop/issues/5116))
- **jsonpath:** Prevent converting date string to DateTime in JSONPath ([#5130](https://github.com/ScoopInstaller/Scoop/issues/5130))
- **psmodule:** Remove folder recursively when unlinking previous module path ([#5127](https://github.com/ScoopInstaller/Scoop/issues/5127))
- **scoop-update:** Add `uninstall_psmodule` to update process ([#5136](https://github.com/ScoopInstaller/Scoop/issues/5136))
### Code Refactoring
- **download:** Rename `dl()` to `Invoke-Download()` ([#5143](https://github.com/ScoopInstaller/Scoop/issues/5143))
- **path:** Use 'Convert-Path()' instead of 'Resolve-Path()' ([#5109](https://github.com/ScoopInstaller/Scoop/issues/5109))
- **scoop-shim:** Use `getopt` to parse arguments ([#5125](https://github.com/ScoopInstaller/Scoop/issues/5125))
### Builds
- **checkver:** Implement SourceForge checkver functionality ([#5113](https://github.com/ScoopInstaller/Scoop/issues/5113), [#5163](https://github.com/ScoopInstaller/Scoop/issues/5163))
- **checkurls:** Allow checking URLs from private_hosts ([#5152](https://github.com/ScoopInstaller/Scoop/issues/5152))
- **schema:** Set manifest schema to be stricter ([#5093](https://github.com/ScoopInstaller/Scoop/issues/5093))
- **vscode:** Tweak VSCode setting ([#5149](https://github.com/ScoopInstaller/Scoop/issues/5149))
## [v0.2.4](https://github.com/ScoopInstaller/Scoop/compare/v0.2.3...v0.2.4) - 2022-08-08
### Features
- **core:** Create no window by default in `Invoke-ExternalCommand` ([#5066](https://github.com/ScoopInstaller/Scoop/issues/5066))
- **core:** Improve argument concatenation in `Invoke-ExternalCommand` ([#5065](https://github.com/ScoopInstaller/Scoop/issues/5065))
- **install:** Show bucket name while installing an app ([#5075](https://github.com/ScoopInstaller/Scoop/issues/5075))
- **scoop-status:** Add flag to disable remote checking ([#5073](https://github.com/ScoopInstaller/Scoop/issues/5073))
- **scoop-update:** Add support for `pre_uninstall` and `post_uninstall` ([#5085](https://github.com/ScoopInstaller/Scoop/issues/5085))
### Bug Fixes
- **core:** Avoid deadlock in `Invoke-ExternalCommand` ([#5064](https://github.com/ScoopInstaller/Scoop/issues/5064))
- **core:** Use 'System.Nullable<bool>' for param 'global' ([#5088](https://github.com/ScoopInstaller/Scoop/issues/5088))
- **install:** Move from cache when `--no-cache` is specified ([#5039](https://github.com/ScoopInstaller/Scoop/issues/5039))
- **scoop-status:** Correct formatting of `Info` output ([#5047](https://github.com/ScoopInstaller/Scoop/issues/5047))
### Builds
- **checkver:** Load page content before running 'script' ([#5080](https://github.com/ScoopInstaller/Scoop/issues/5080))
- **json:** Update Newtonsoft.Json.Schema to 3.0.15-beta2 ([#5053](https://github.com/ScoopInstaller/Scoop/issues/5053))
## [v0.2.3](https://github.com/ScoopInstaller/Scoop/compare/v0.2.2...v0.2.3) - 2022-07-07
### Features
- **chore:** Add missing -a/--all param to all commands ([#5004](https://github.com/ScoopInstaller/Scoop/issues/5004))
- **scoop-status:** Check bucket status, improve output ([#5011](https://github.com/ScoopInstaller/Scoop/issues/5011))
- **scoop-info:** Show app installed/download size ([#4886](https://github.com/ScoopInstaller/Scoop/issues/4886))
- **scoop-import:** Import a Scoop installation from JSON ([#5014](https://github.com/ScoopInstaller/Scoop/issues/5014), [#5034](https://github.com/ScoopInstaller/Scoop/issues/5034))
### Bug Fixes
- **chore:** Update help documentation ([#5002](https://github.com/ScoopInstaller/Scoop/issues/5002), [#5029](https://github.com/ScoopInstaller/Scoop/issues/5029))
- **decompress:** Handle split RAR archives ([#4994](https://github.com/ScoopInstaller/Scoop/issues/4994))
- **shortcuts:** Fix network drive shortcut creation ([#4410](https://github.com/ScoopInstaller/Scoop/issues/4410), [#5006](https://github.com/ScoopInstaller/Scoop/issues/5006))
### Code Refactoring
- **scoop-search:** Output PSObject, use API token ([#4997](https://github.com/ScoopInstaller/Scoop/issues/4997))
### Builds
- **checkver,auto-pr:** Allow passing file path ([#5019](https://github.com/ScoopInstaller/Scoop/issues/5019))
- **checkver:** Exit routine earlier if error ([#5025](https://github.com/ScoopInstaller/Scoop/issues/5025))
- **json:** Update Newton.Json to 13.0.1 ([#5026](https://github.com/ScoopInstaller/Scoop/issues/5026))
### Tests
- **typo:** Fix typo ('formated' -> 'formatted') ([#4217](https://github.com/ScoopInstaller/Scoop/issues/4217))
## [v0.2.2](https://github.com/ScoopInstaller/Scoop/compare/v0.2.1...v0.2.2) - 2022-06-21
### Features
- **core:** Add `Get-Encoding` function to fix missing webclient encoding ([#4956](https://github.com/ScoopInstaller/Scoop/issues/4956))
- **scoop-(un)hold:** Add `-g`/`--global` flag ([#4991](https://github.com/ScoopInstaller/Scoop/issues/4991))
- **scoop-update:** Support `scoop update scoop` ([#4992](https://github.com/ScoopInstaller/Scoop/issues/4992))
- **scoop-virustotal:** Migrate to VirusTotal API v3 ([#4983](https://github.com/ScoopInstaller/Scoop/issues/4983))
### Bug Fixes
- **manifest:** Fix bugs in 'Get-Manifest()' ([#4986](https://github.com/ScoopInstaller/Scoop/issues/4986))
## [v0.2.1](https://github.com/ScoopInstaller/Scoop/compare/v0.2.0...v0.2.1) - 2022-06-10
### Features
- **core:** Add pre_uninstall and post_uninstall hooks ([#4957](https://github.com/ScoopInstaller/Scoop/issues/4957), [#4962](https://github.com/ScoopInstaller/Scoop/issues/4962))
### Bug Fixes
- **bucket:** Make sure `list_buckets` return array ([#4979](https://github.com/ScoopInstaller/Scoop/issues/4979))
- **chore:** Deprecate tls1 and tls1.1 ([#4950](https://github.com/ScoopInstaller/Scoop/issues/4950))
- **chore:** Update Nonportable bucket URL ([#4955](https://github.com/ScoopInstaller/Scoop/issues/4955))
- **core:** Using `Invoke-Command` instead of `Invoke-Expression` ([#4941](https://github.com/ScoopInstaller/Scoop/issues/4941))
- **core:** Load config file before initialization ([#4932](https://github.com/ScoopInstaller/Scoop/issues/4932))
- **core:** Allow to use '_' and '.' in bucket name ([#4952](https://github.com/ScoopInstaller/Scoop/issues/4952))
- **depends:** Avoid digits in archive file extension (except for .7z and .001) ([#4915](https://github.com/ScoopInstaller/Scoop/issues/4915))
- **bucket:** Don't check remote URL of non-git buckets ([#4923](https://github.com/ScoopInstaller/Scoop/issues/4923))
- **bucket:** Don't write message OK before bucket is cloned ([#4925](https://github.com/ScoopInstaller/Scoop/issues/4925))
- **shim:** Add 'Get-CommandPath()' to find git ([#4913](https://github.com/ScoopInstaller/Scoop/issues/4913))
- **shim:** Remove character replacement in .cmd -> .ps1 shims ([#4914](https://github.com/ScoopInstaller/Scoop/issues/4914))
- **scoop:** Pass CLI arguments as string objects ([#4931](https://github.com/ScoopInstaller/Scoop/issues/4931))
- **scoop-info:** Fix error message when manifest is not found ([#4935](https://github.com/ScoopInstaller/Scoop/issues/4935))
- **scoop-search:** Require files in 'bucket' dir for remote known buckets ([#4944](https://github.com/ScoopInstaller/Scoop/issues/4944))
- **update:** Prevent uninstall when update ([#4949](https://github.com/ScoopInstaller/Scoop/issues/4949))
- **scoop-download:** Use correct Args when calling `Get-Manifest` ([#4970](https://github.com/ScoopInstaller/Scoop/issues/4970))
### Code Refactoring
- **manifest:** Rename 'Find-Manifest()' to 'Get-Manifest() ([#4966](https://github.com/ScoopInstaller/Scoop/issues/4966), [#4981](https://github.com/ScoopInstaller/Scoop/issues/4981))
### Documentation
- **readme:** Update license badge ([#4929](https://github.com/ScoopInstaller/Scoop/issues/4929))
## [v0.2.0](https://github.com/ScoopInstaller/Scoop/compare/v0.1.0...v0.2.0) - 2022-05-10
### Features
- **relicense:** Relicense to dual-license (Unlicense or MIT) ([#4903](https://github.com/ScoopInstaller/Scoop/issues/4903), [#4870](https://github.com/ScoopInstaller/Scoop/issues/4870))
- **install:** Allow downloading from private repositories ([#4254](https://github.com/ScoopInstaller/Scoop/issues/4254))
- **scoop-cleanup:** Add `-a/--all` switch to cleanup all apps ([#4906](https://github.com/ScoopInstaller/Scoop/issues/4906))
### Bug Fixes
- **bucket:** Return empty list correctly in `Get-LocalBucket` ([#4885](https://github.com/ScoopInstaller/Scoop/issues/4885))
- **install:** Fix issue with installation inside containers ([#4837](https://github.com/ScoopInstaller/Scoop/issues/4837))
- **installed:** If no `$global`, check both local and global installed ([#4798](https://github.com/ScoopInstaller/Scoop/issues/4798))
- **shim:** Manipulating shims with UTF8 encoding ([#4791](https://github.com/ScoopInstaller/Scoop/issues/4791), [#4813](https://github.com/ScoopInstaller/Scoop/issues/4813))
- **shim:** Correctly quote $@ in sh->ps1 shims ([#4809](https://github.com/ScoopInstaller/Scoop/issues/4809))
- **update:** Skip logs starting with `(chore)` ([#4800](https://github.com/ScoopInstaller/Scoop/issues/4800))
- **scoop-download:** Add failure check ([#4822](https://github.com/ScoopInstaller/Scoop/issues/4822))
- **scoop-list:** Fix date in 'Updated' column showing the months in the place of minutes ([#4880](https://github.com/ScoopInstaller/Scoop/issues/4880))
- **scoop-prefix:** Fix typo that breaks global installed apps ([#4795](https://github.com/ScoopInstaller/Scoop/issues/4795))
### Performance Improvements
- **scoop:** Load libs only once ([#4839](https://github.com/ScoopInstaller/Scoop/issues/4839), [#4884](https://github.com/ScoopInstaller/Scoop/issues/4884))
### Code Refactoring
- **bucket:** Move 'Find-Manifest' and 'list_buckets' to 'buckets' ([#4814](https://github.com/ScoopInstaller/Scoop/issues/4814))
- **relpath:** Use `$PSScriptRoot` instead of `relpath` ([#4793](https://github.com/ScoopInstaller/Scoop/issues/4793))
- **reset_aliases:** Move core function of `reset_aliases` to `scoop` ([#4794](https://github.com/ScoopInstaller/Scoop/issues/4794))
- **config:** Rename checkver_token to gh_token and SCOOP_CHECKVER_TOKEN to SCOOP_GH_TOKEN ([#4832](https://github.com/ScoopInstaller/Scoop/issues/4832), [#4842](https://github.com/ScoopInstaller/Scoop/issues/4842))
### Builds
- **checkver:** Add option to throw error as exception ([#4867](https://github.com/ScoopInstaller/Scoop/issues/4867))
- **schema:** Remove 'description' from required fields ([#4853](https://github.com/ScoopInstaller/Scoop/issues/4853), [#4874](https://github.com/ScoopInstaller/Scoop/issues/4874))
### Documentation
- **changelog:** Rearrange CHANGELOG ([#4897](https://github.com/ScoopInstaller/Scoop/issues/4897))
- **readme:** Update installation instruction ([#4825](https://github.com/ScoopInstaller/Scoop/issues/4825))
- **readme:** Fix badges for Gitter and CI Tests ([#4830](https://github.com/ScoopInstaller/Scoop/issues/4830))
- **scoop-shim:** Fix typo ([#4836](https://github.com/ScoopInstaller/Scoop/issues/4836))
## [v0.1.0](https://github.com/ScoopInstaller/Scoop/compare/2021-12-26...v0.1.0) - 2022-03-01
### Features
- **scoop-bucket:** List more detailed information for buckets ([#4704](https://github.com/ScoopInstaller/Scoop/issues/4704), [#4756](https://github.com/ScoopInstaller/Scoop/issues/4756), [#4759](https://github.com/ScoopInstaller/Scoop/issues/4759))
- **scoop-cache:** Handle multiple apps and show detailed information ([#4738](https://github.com/ScoopInstaller/Scoop/issues/4738))
- **scoop-cat:** Use `bat` to pretty-print JSON ([#4742](https://github.com/ScoopInstaller/Scoop/issues/4742))
- **scoop-config:** Allow Scoop to ignore running processes during reset/uninstall/update ([#4713](https://github.com/ScoopInstaller/Scoop/issues/4713), [#4731](https://github.com/ScoopInstaller/Scoop/issues/4731))
- **scoop-config:** Show all settings ([#4765](https://github.com/ScoopInstaller/Scoop/issues/4765))
- **scoop-download:** Add `scoop download` command ([#4621](https://github.com/ScoopInstaller/Scoop/issues/4621))
- **scoop-(install|virustotal):** Allow skipping update check ([#4634](https://github.com/ScoopInstaller/Scoop/issues/4634))
- **scoop-list:** Allow list manipulation ([#4718](https://github.com/ScoopInstaller/Scoop/issues/4718))
- **scoop-list:** Show last-updated time ([#4723](https://github.com/ScoopInstaller/Scoop/issues/4723))
- **scoop-info:** Revamp details and show more information ([#4747](https://github.com/ScoopInstaller/Scoop/issues/4747))
- **scoop-shim:** Add `scoop shim` to manipulate shims ([#4727](https://github.com/ScoopInstaller/Scoop/issues/4727), [#4736](https://github.com/ScoopInstaller/Scoop/issues/4736))
### Bug Fixes
- **autoupdate:** Allow checksum file that contains whitespaces ([#4619](https://github.com/ScoopInstaller/Scoop/issues/4619))
- **autoupdate:** Rename $response to $res ([#4706](https://github.com/ScoopInstaller/Scoop/issues/4706))
- **config:** Ensure manipulating config with UTF8 encoding ([#4644](https://github.com/ScoopInstaller/Scoop/issues/4644))
- **config:** Allow scoop config use Unicode characters ([#4631](https://github.com/ScoopInstaller/Scoop/issues/4631))
- **config:** Fix `set_config` bugs ([#3681](https://github.com/ScoopInstaller/Scoop/issues/3681))
- **current:** Remove 'current' while it's not a junction ([#4687](https://github.com/ScoopInstaller/Scoop/issues/4687))
- **depends:** Prevent error on no URL ([#4595](https://github.com/ScoopInstaller/Scoop/issues/4595))
- **depends:** Check if extractor is available ([#4042](https://github.com/ScoopInstaller/Scoop/issues/4042))
- **decompress:** Fix nested Zstd archive extraction ([#4608](https://github.com/ScoopInstaller/Scoop/issues/4608), [#4639](https://github.com/ScoopInstaller/Scoop/issues/4639))
- **installed:** Fix 'core/installed' that mark failed app as 'installed' ([#4650](https://github.com/ScoopInstaller/Scoop/issues/4650), [#4676](https://github.com/ScoopInstaller/Scoop/issues/4676), [#4689](https://github.com/ScoopInstaller/Scoop/issues/4689), [#4785](https://github.com/ScoopInstaller/Scoop/issues/4785))
- **no-junctions:** Fix error when `NO_JUNCTIONS` is been set ([#4722](https://github.com/ScoopInstaller/Scoop/issues/4722), [#4726](https://github.com/ScoopInstaller/Scoop/issues/4726))
- **shim:** Fix PS1 shim error when in different drive in PS7 ([#4614](https://github.com/ScoopInstaller/Scoop/issues/4614))
- **shim:** Fix `sh` shim error in WSL ([#4637](https://github.com/ScoopInstaller/Scoop/issues/4637))
- **shim:** Use `-file` instead of `-command` in ps1 script shims ([#4721](https://github.com/ScoopInstaller/Scoop/issues/4721))
- **shim:** Fix exe shim when app path has white spaces ([#4734](https://github.com/ScoopInstaller/Scoop/issues/4734), [#4780](https://github.com/ScoopInstaller/Scoop/issues/4780))
- **versions:** Fix wrong version number when only one version dir ([#4679](https://github.com/ScoopInstaller/Scoop/issues/4679))
- **versions:** Get current version from failed installation if possible ([#4720](https://github.com/ScoopInstaller/Scoop/issues/4720), [#4725](https://github.com/ScoopInstaller/Scoop/issues/4725))
- **scoop-alias:** Fix alias initialization ([#4737](https://github.com/ScoopInstaller/Scoop/issues/4737))
- **scoop-checkup:** Skip 'check_windows_defender' when have not admin privileges ([#4699](https://github.com/ScoopInstaller/Scoop/issues/4699))
- **scoop-cleanup:** Remove apps other than current version ([#4665](https://github.com/ScoopInstaller/Scoop/issues/4665))
- **scoop-search:** Remove redundant 'bucket/' in search result ([#4773](https://github.com/ScoopInstaller/Scoop/issues/4773))
- **scoop-update:** Skip updating non git buckets ([#4670](https://github.com/ScoopInstaller/Scoop/issues/4670), [#4672](https://github.com/ScoopInstaller/Scoop/issues/4672))
### Performance Improvements
- **uninstall:** Avoid checking all files for unlinking persisted data ([#4681](https://github.com/ScoopInstaller/Scoop/issues/4681), [#4763](https://github.com/ScoopInstaller/Scoop/issues/4763))
### Code Refactoring
- **depends:** Rewrite 'depends.ps1' ([#4638](https://github.com/ScoopInstaller/Scoop/issues/4638), [#4673](https://github.com/ScoopInstaller/Scoop/issues/4673))
- **mklink:** Use 'New-Item' instead of 'mklink' ([#4690](https://github.com/ScoopInstaller/Scoop/issues/4690))
- **rmdir:** Use 'Remove-Item' instead of 'rmdir' ([#4691](https://github.com/ScoopInstaller/Scoop/issues/4691))
- **COMSPEC:** Deprecate use of subshell cmd.exe ([#4692](https://github.com/ScoopInstaller/Scoop/issues/4692))
- **git:** Use 'git -C' to specify the work directory instead of 'Push-Location'/'Pop-Location' ([#4697](https://github.com/ScoopInstaller/Scoop/issues/4697))
- **scoop-info:** Use List View for output ([#4741](https://github.com/ScoopInstaller/Scoop/issues/4741))
- **scoop-config:** Use underscores everywhere ([#4745](https://github.com/ScoopInstaller/Scoop/issues/4745))
### Builds
- **checkver:** Fix output with '-Version' ([#3774](https://github.com/ScoopInstaller/Scoop/issues/3774))
- **schema:** Add '$schema' property ([#4623](https://github.com/ScoopInstaller/Scoop/issues/4623))
- **schema:** Add explicit escape to opening bracket matcher in jp/jsonpath regex ([#3719](https://github.com/ScoopInstaller/Scoop/issues/3719))
- **schema:** Fix typo ('note' -> 'notes') ([#4678](https://github.com/ScoopInstaller/Scoop/issues/4678))
- **tests:** Support both AppVeyor and GitHub Actions ([#4655](https://github.com/ScoopInstaller/Scoop/issues/4655))
- **tests:** Run GitHub Actions CI on each commit ([#4664](https://github.com/ScoopInstaller/Scoop/issues/4664))
- **tests:** Use cache in GitHub Actions ([#4671](https://github.com/ScoopInstaller/Scoop/issues/4671))
- **tests:** Disable CI test on 'push' ([#4677](https://github.com/ScoopInstaller/Scoop/issues/4677))
- **vscode-settings:** Remove 'formatOnSave' trigger ([#4635](https://github.com/ScoopInstaller/Scoop/issues/4635))
### Styles
- **test:** Format scripts by VSCode's PowerShell extension ([#4609](https://github.com/ScoopInstaller/Scoop/issues/4609))
- **style:** Use correct casing for `$PSScriptRoot` ([#4775](https://github.com/ScoopInstaller/Scoop/issues/4775))
### Tests
- **test-bin:** Only write output file in CI and fix trailing whitespaces ([#4613](https://github.com/ScoopInstaller/Scoop/issues/4613))
- **manifest:** Fix manifests validation ([#4620](https://github.com/ScoopInstaller/Scoop/issues/4620))
- **zstd:** Fix 'zstd' extraction error in test ([#4651](https://github.com/ScoopInstaller/Scoop/issues/4651))
### Documentation
- **changelog:** Add 'CHANGLOG.md' ([#4600](https://github.com/ScoopInstaller/Scoop/issues/4600))
- **changelog:** Rearrange CHANGELOG ([#4729](https://github.com/ScoopInstaller/Scoop/issues/4729))
- **changelog:** Link CHANGELOG headers to 'releases/tag' ([#4730](https://github.com/ScoopInstaller/Scoop/issues/4730))
## [2021-12-26](https://github.com/ScoopInstaller/Scoop/compare/2021-11-22...2021-12-26)
### Features
- **core:** Redirect 'StandardError' in `Invoke-ExternalCommand()` ([#4570](https://github.com/ScoopInstaller/Scoop/issues/4570), [#4582](https://github.com/ScoopInstaller/Scoop/issues/4582))
- **install:** Add portableapps.com to strip_filename skips ([#3244](https://github.com/ScoopInstaller/Scoop/issues/3244))
- **install:** Show manifest on installation ([#4155](https://github.com/ScoopInstaller/Scoop/issues/4155), [fb496c48](https://github.com/ScoopInstaller/Scoop/commit/fb496c482bec4063e01b328f943224ab703dbbd8), [#4581](https://github.com/ScoopInstaller/Scoop/issues/4581))
- **template:** Add issue/PR templates ([#4572](https://github.com/ScoopInstaller/Scoop/issues/4572))
- **scoop-cat:** Add `scoop cat` command ([#4532](https://github.com/ScoopInstaller/Scoop/issues/4532))
- **scoop-config:** Document all configuration options ([#4579](https://github.com/ScoopInstaller/Scoop/issues/4579))
### Bug Fixes
- **bucket:** Remove JetBrains bucket ([dec25980](https://github.com/ScoopInstaller/Scoop/commit/dec25980525a81c176b3fd5f238e964db00f3be3))
- **bucket:** Remove nightlies bucket ([48b035d7](https://github.com/ScoopInstaller/Scoop/commit/48b035d7f99baa2e81d87ead4ff03a9594e49c3d))
- **core:** Escape '.' in 'parse_app()'. ([#4578](https://github.com/ScoopInstaller/Scoop/issues/4578))
- **core:** Use '-Encoding ASCII' in 'Out-File' ([#4571](https://github.com/ScoopInstaller/Scoop/issues/4571))
- **depends:** Specify function scope ([4d5fee36](https://github.com/ScoopInstaller/Scoop/commit/4d5fee36e1ed13fc850fd22a5414186aec030c6e))
- **install:** Use `Select-CurrentVersion` ([#4535](https://github.com/ScoopInstaller/Scoop/issues/4535))
- **install:** 'env_add_path' doesn't append '.' ([#4550](https://github.com/ScoopInstaller/Scoop/issues/4550))
- **repo:** Update repo links ([cbe29edd](https://github.com/ScoopInstaller/Scoop/commit/cbe29eddb3475e34740300eb1c2c52715446e3be))
- **scoop-update:** Update apps with '--all' ([ac71fccb](https://github.com/ScoopInstaller/Scoop/commit/ac71fccbecb3d4158f249db9c1b9bb043cb8e966))
- **scoop-update:** Fix scoop update -a requiring arguments ([#4531](https://github.com/ScoopInstaller/Scoop/issues/4531))
### Code Refactoring
- **shim:** Rework shimming logic ([#4543](https://github.com/ScoopInstaller/Scoop/issues/4543), [#4555](https://github.com/ScoopInstaller/Scoop/issues/4555), [3c90d1a0](https://github.com/ScoopInstaller/Scoop/commit/3c90d1a0701b0b64730dbf9ebc8d31f9b9c238f1), [2ec00d57](https://github.com/ScoopInstaller/Scoop/commit/2ec00d576c7e594dc5c0f1eac4536c5310ce6f17))
### Builds
- **auto-pr:** Remove hardcoded 'master' branch ([#4567](https://github.com/ScoopInstaller/Scoop/issues/4567))
- **checkver:** Improve JSONPath extraction support ([#4522](https://github.com/ScoopInstaller/Scoop/issues/4522))
- **checkver:** Use GitHub token from environment ([#4557](https://github.com/ScoopInstaller/Scoop/issues/4557))
- **schema:** Enable autoupdate for 'license' ([#4528](https://github.com/ScoopInstaller/Scoop/issues/4528), [#4596](https://github.com/ScoopInstaller/Scoop/issues/4596))
### Documentation
- **readme:** Add link to Contributing Guide ([5e11c94a](https://github.com/ScoopInstaller/Scoop/commit/5e11c94a544ff2adbdbec5072c32a94d3e5acb9c))
- **readme:** Fix links ([3bb7036e](https://github.com/ScoopInstaller/Scoop/commit/3bb7036ee111bfe58e82ba3d0fd39189b058776a))
### Reverts
- **shim:** Revert [#4229](https://github.com/ScoopInstaller/Scoop/issues/4229) ([#4553](https://github.com/ScoopInstaller/Scoop/issues/4553))
## [2021-11-22](https://github.com/ScoopInstaller/Scoop/compare/2020-11-26...2021-11-22)
### Features
- **bucket:** Move extras bucket to [@ScoopInstaller](https://github.com/ScoopInstaller) ([3e9a4d4e](https://github.com/ScoopInstaller/Scoop/commit/3e9a4d4ea0e7e4d6489099c46a763f58db07e633))
- **decompress:** Support Zstandard archive ([#4372](https://github.com/ScoopInstaller/Scoop/issues/4372), [e35ff313](https://github.com/ScoopInstaller/Scoop/commit/e35ff313a5d35cab1049024938c3423a5f6bf060), [47ebc6f1](https://github.com/ScoopInstaller/Scoop/commit/47ebc6f176b0db0afeb51b4ee237a20b2d8649e9))
- **install:** Handle arch-specific env_add_path ([#4013](https://github.com/ScoopInstaller/Scoop/issues/4013))
- **install:** s/lukesamson/ScoopInstaller in install.ps1 ([5226f26f](https://github.com/ScoopInstaller/Scoop/commit/5226f26f18157ed78f1529144404ec682374452e))
- **message:** Add config to disable aria2 warning message ([#4422](https://github.com/ScoopInstaller/Scoop/issues/4422))
- **shim:** Add another alternative shim written in rust ([#4229](https://github.com/ScoopInstaller/Scoop/issues/4229))
- **scoop-prefix:** Remove unused imports and functions ([#4494](https://github.com/ScoopInstaller/Scoop/issues/4494))
- **scoop-install:** Auto uninstall previous failed installation ([#3281](https://github.com/ScoopInstaller/Scoop/issues/3281))
- **scoop-update:** Add flags `--all` as an alternative to '*' to update all ([#3871](https://github.com/ScoopInstaller/Scoop/issues/3871))
### Bug Fixes
- **core:** Change url() scope to avoid conflict with global aliases ([#4342](https://github.com/ScoopInstaller/Scoop/issues/4342), [#4492](https://github.com/ScoopInstaller/Scoop/issues/4492))
- **install:** Fix `aria2`'s resume download feature ([#3292](https://github.com/ScoopInstaller/Scoop/issues/3292))
- **shim:** Fixed trailing whitespace issue ([#4307](https://github.com/ScoopInstaller/Scoop/issues/4307))
- **scoop-reset:** Skip when app instance is running ([#4359](https://github.com/ScoopInstaller/Scoop/issues/4359))
### Code Refactoring
- **versions:** Refactor 'versions.ps1' ([#3721](https://github.com/ScoopInstaller/Scoop/issues/3721), [e6630272](https://github.com/ScoopInstaller/Scoop/commit/e663027299d03ca768a252fa4bcbc51d124d4cae), [ae892138](https://github.com/ScoopInstaller/Scoop/commit/ae892138423bb9bbf54c8f0bed8331b93199f6b8))
### Builds
- **autoupdate:** Add multiple URL/hash/extract_dir... support ([#3518](https://github.com/ScoopInstaller/Scoop/issues/3518), [#4502](https://github.com/ScoopInstaller/Scoop/issues/4502))
- **schema:** Fix Schema to support `+` in version ([#4504](https://github.com/ScoopInstaller/Scoop/issues/4504))
- **supporting:** Update Json to 12.0.3, Json.Schema to 3.0.14 ([#3352](https://github.com/ScoopInstaller/Scoop/issues/3352))
### Documentation
- **readme:** Capitalize to prevent redirect ([#4483](https://github.com/ScoopInstaller/Scoop/issues/4483))
- **readme:** s/lukesampson/ScoopInstaller in readme ([4f5acd72](https://github.com/ScoopInstaller/Scoop/commit/4f5acd72109a98a148d1bfa269c23a2d43644d23))
- **readme:** Update extras bucket url in readme ([f1a46e10](https://github.com/ScoopInstaller/Scoop/commit/f1a46e109596c55c7e83c77fc1fc9daedbe71636))
- **readme:** Update Java bucket text ([#4514](https://github.com/ScoopInstaller/Scoop/issues/4514))
- **readme:** Update notes about the NirSoft bucket ([#4524](https://github.com/ScoopInstaller/Scoop/issues/4524))
## [2020-11-26](https://github.com/ScoopInstaller/Scoop/compare/2020-10-22...2020-11-26)
### Bug Fixes
- **shim:** Fix Makefile typo ([0948824e](https://github.com/ScoopInstaller/Scoop/commit/0948824ec7269c979882d09342d9a269193cd674)) ([227de6cf](https://github.com/ScoopInstaller/Scoop/commit/227de6cfb8433a86ac0f0a279e691327ae04554c))
## [2020-10-22](https://github.com/ScoopInstaller/Scoop/compare/2019-10-23...2020-10-22)
### Features
- **aria2:** Inline progress ([#3987](https://github.com/ScoopInstaller/Scoop/issues/3987))
- **autoupdate:** Add $urlNoExt and $basenameNoExt substitutions ([#3742](https://github.com/ScoopInstaller/Scoop/issues/3742))
- **config:** Add configuration option for default architecture ([#3778](https://github.com/ScoopInstaller/Scoop/issues/3778))
- **install:** Follow HTTP redirections when downloading a file ([#3902](https://github.com/ScoopInstaller/Scoop/issues/3902))
- **install:** Let pathes in 'env_add_path' be added ascendantly ([#3788](https://github.com/ScoopInstaller/Scoop/issues/3788), [#3976](https://github.com/ScoopInstaller/Scoop/issues/3976))
- **list:** Display main bucket name ([#3759](https://github.com/ScoopInstaller/Scoop/issues/3759))
- **shim:** Add alt-shim support ([#3998](https://github.com/ScoopInstaller/Scoop/issues/3998))
- **scoop-checkup:** Add check_envs_requirements ([#3860](https://github.com/ScoopInstaller/Scoop/issues/3860))
### Bug Fixes
- **bucket:** Update scoop-nonportable URL ([#3776](https://github.com/ScoopInstaller/Scoop/issues/3776))
- **download:** Fosshub download ([#4051](https://github.com/ScoopInstaller/Scoop/issues/4051))
- **download:** Progress bar on small files ([96de9c14](https://github.com/ScoopInstaller/Scoop/commit/96de9c14bb483f9278e4b0a9e22b1923ee752901))
- **hold:** Replace "locked" terminology with "held" for consistency ([#3917](https://github.com/ScoopInstaller/Scoop/issues/3917))
- **git:** Don't execute autostart programs when executing git commands ([#3993](https://github.com/ScoopInstaller/Scoop/issues/3993))
- **git:** Enforce pull without rebase ([#3765](https://github.com/ScoopInstaller/Scoop/issues/3765))
- **install:** Aria2 inline progress negative values ([#4053](https://github.com/ScoopInstaller/Scoop/issues/4053))
- **install:** Fix wrong output of 'install/failed' ([#3784](https://github.com/ScoopInstaller/Scoop/issues/3784), [#3867](https://github.com/ScoopInstaller/Scoop/issues/3867))
- **install:** Re-add "Don't send referer to portableapps.com" ([#3961](https://github.com/ScoopInstaller/Scoop/issues/3961))
- **scoop:** Remove temporary code from the scoop executable ([#3898](https://github.com/ScoopInstaller/Scoop/issues/3898))
- **update:** Update outdated PowerShell 5 warning ([#3986](https://github.com/ScoopInstaller/Scoop/issues/3986))
- **scoop-info:** Check bucket of installed app ([#3740](https://github.com/ScoopInstaller/Scoop/issues/3740))
### Builds
- **checkver:** Present script property ([#3900](https://github.com/ScoopInstaller/Scoop/issues/3900))
### Tests
- **init:** Force pester v4 ([#4040](https://github.com/ScoopInstaller/Scoop/issues/4040))
## [2019-10-23](https://github.com/ScoopInstaller/Scoop/compare/2019-10-18...2019-10-23)
### Features
- **update:** Support $persist_dir in uninstaller.script ([#3692](https://github.com/ScoopInstaller/Scoop/issues/3692))
### Bug Fixes
- **core:** Use [Environment]::Is64BitOperatingSystem instead of [intptr]::size ([#3690](https://github.com/ScoopInstaller/Scoop/issues/3690))
- **git:** Remove unnecessary git_proxy_cmd() calls for local commands ([8ee45a57](https://github.com/ScoopInstaller/Scoop/commit/8ee45a57dc01a525dcf8776bf9bb45263992c81f))
- **install:** Check execution policy ([#3619](https://github.com/ScoopInstaller/Scoop/issues/3619))
- **update:** Fix scoop update changelog output ([e997017f](https://github.com/ScoopInstaller/Scoop/commit/e997017f1a03e2eefef2157acdfefe2e4fced896))
## [2019-10-18](https://github.com/ScoopInstaller/Scoop/compare/2019-06-24...2019-10-18)
### Features
- **core:** Tweak Invoke-ExternalCommand parameters ([#3547](https://github.com/ScoopInstaller/Scoop/issues/3547))
- **install:** Use 7zip when available for faster zip file extraction ([#3460](https://github.com/ScoopInstaller/Scoop/issues/3460))
- **install:** Add arch support to `env_add_path` and `env_set` ([#3503](https://github.com/ScoopInstaller/Scoop/issues/3503))
- **install:** Allow $version to be used in uninstaller scripts ([#3592](https://github.com/ScoopInstaller/Scoop/issues/3592))
- **install:** Allow installing specific version if latest is installed ([11c42d78](https://github.com/ScoopInstaller/Scoop/commit/11c42d782f8adb29fbe0d94daa5f121cdda935ab))
- **update:** Allow updating apps from local manifest or URL ([#3685](https://github.com/ScoopInstaller/Scoop/issues/3685))
### Bug Fixes
- **autoupdate:** Decode basename when extract hash ([#3615](https://github.com/ScoopInstaller/Scoop/issues/3615))
- **autoupdate:** Remove any whitespace from hash ([#3579](https://github.com/ScoopInstaller/Scoop/issues/3579))
- **bucket:** Only lookup directories in buckets folder ([#3631](https://github.com/ScoopInstaller/Scoop/issues/3631))
- **comspec:** Escape variables when calling COMSPEC commands ([#3538](https://github.com/ScoopInstaller/Scoop/issues/3538))
- **decompress:** Fix bugs on extract_dir ([#3540](https://github.com/ScoopInstaller/Scoop/issues/3540))
- **editorconfig:** Add missing } to bat/cmd regex ([#3529](https://github.com/ScoopInstaller/Scoop/issues/3529))
- **help:** Rename help() to scoop_help() ([#3564](https://github.com/ScoopInstaller/Scoop/issues/3564))
- **install:** Use Join-Path instead of string gluing. ([#3566](https://github.com/ScoopInstaller/Scoop/issues/3566))
- **scoop-info:** Fix output for single binaries with alias ([#3651](https://github.com/ScoopInstaller/Scoop/issues/3651))
- **scoop-info:** Remove a whitespace ([#3652](https://github.com/ScoopInstaller/Scoop/issues/3652))
### Builds
- **auto-pr:** Fix git status detection ([7decfd4c](https://github.com/ScoopInstaller/Scoop/commit/7decfd4c107b8d8a59d7eedfe8a56e1801120c2f))
- **auto-pr:** Hard reset bucket after running ([79f8538b](https://github.com/ScoopInstaller/Scoop/commit/79f8538b57b9021db71a279879b9032fefd1ae52))
- **checkurls:** Trim renaming suffix in url ([#3677](https://github.com/ScoopInstaller/Scoop/issues/3677))
### Continuous Integration
- **appveyor:** use VS2019 image to fix PS6 issues ([#3646](https://github.com/ScoopInstaller/Scoop/issues/3646))
- **tests:** Do not force maintainers to have SCOOP_HELPERS ([#3604](https://github.com/ScoopInstaller/Scoop/issues/3604))
### Documentation
- **readme:** Improve installation instructions ([#3600](https://github.com/ScoopInstaller/Scoop/issues/3600))
## [2019-06-24](https://github.com/ScoopInstaller/Scoop/compare/2019-05-15...2019-06-24)
### Features
- **decompress:** Add 'ExtractDir' to 'Expand-...' functions ([#3466](https://github.com/ScoopInstaller/Scoop/issues/3466), [#3470](https://github.com/ScoopInstaller/Scoop/issues/3470), [#3472](https://github.com/ScoopInstaller/Scoop/issues/3472))
- **decompress:** Allow 'Expand-InnoArchive -ExtractDir' to accept '{xxx}' ([#3487](https://github.com/ScoopInstaller/Scoop/issues/3487))
### Bug Fixes
- **config:** Show correct output when removing a config value ([#3462](https://github.com/ScoopInstaller/Scoop/issues/3462))
- **decompress:** Change dark.exe parameter order ([6141e46d](https://github.com/ScoopInstaller/Scoop/commit/6141e46d6ae74b3ccf65e02a1c3fc92e1b4d3e7a))
- **proxy:** Rename parameters for Net.NetworkCredential ([#3483](https://github.com/ScoopInstaller/Scoop/issues/3483))
### Code Refactoring
- **core:** `run()` -> 'Invoke-ExternalCommand()' ([#3432](https://github.com/ScoopInstaller/Scoop/issues/3432))
### Builds
- **checkhashes:** Checkhashes downloading twice when architecture properties does hot have url property ([#3479](https://github.com/ScoopInstaller/Scoop/issues/3479))
- **checkhashes:** Do not call scoop directly ([#3527](https://github.com/ScoopInstaller/Scoop/issues/3527))
### Documentation
- **readme:** Add known buckets to end of readme ([2849e0f9](https://github.com/ScoopInstaller/Scoop/commit/2849e0f96099004f761d7d8c715377e0d2c105f2))
- **readme:** Adjust URL of `runat.json` ([#3484](https://github.com/ScoopInstaller/Scoop/issues/3484))
- **readme:** Fix a small typo ([#3512](https://github.com/ScoopInstaller/Scoop/issues/3512))
- **readme:** Fix typo in readme ([03bb07c8](https://github.com/ScoopInstaller/Scoop/commit/03bb07c8231563fa3a2092b9b52d4dde372f2a8e))
- **readme:** Update readme with correct count of nirsoft apps ([e8d0be66](https://github.com/ScoopInstaller/Scoop/commit/e8d0be663b3bab25d9ee55c597b90bf922f4ec5d))
## [2019-05-15](https://github.com/ScoopInstaller/Scoop/compare/2019-05-12...2019-05-15)
### Features
- **manifest:** XPath support in checkver and autoupdate ([#3458](https://github.com/ScoopInstaller/Scoop/issues/3458))
- **update:** Support changing scoop tracking repository ([#3459](https://github.com/ScoopInstaller/Scoop/issues/3459))
### Bug Fixes
- **autoupdate:** Handle xml namespace in xpath mode ([#3465](https://github.com/ScoopInstaller/Scoop/issues/3465))
## [2019-05-12](https://github.com/ScoopInstaller/Scoop/releases/tag/2019-05-12)
### BREAKING CHANGE
- **core:** Finalize bucket extraction ([#3399](https://github.com/ScoopInstaller/Scoop/issues/3399))
- **core:** Bucket extraction and refactoring ([#3449](https://github.com/ScoopInstaller/Scoop/issues/3449))
### Features
- **autoupdate:** Add 'regex' alias for 'find' ([3453487e](https://github.com/ScoopInstaller/Scoop/commit/3453487ed65378cc9ba2efc658ed6bc1431ef463))
- **autoupdate:** Allow simple metalink and meta4 hash extraction ([ecf627c3](https://github.com/ScoopInstaller/Scoop/commit/ecf627c3b8493b3ccf7ddb882b0c946533774d76))
- **autoupdate:** Add version variables to autoupdate.hash.regex ([#2966](https://github.com/ScoopInstaller/Scoop/issues/2996))
- **autoupdate:** Autoupdate improvements ([#1371](https://github.com/ScoopInstaller/Scoop/issues/1371))
- **autoupdate:** Convert base64 encoded hash values ([04c9ddeb](https://github.com/ScoopInstaller/Scoop/commit/04c9ddeb6d3b99496c39543ad468d34f4f1adeff))
- **autoupdate:** Improve base64 hash detection ([310096e2](https://github.com/ScoopInstaller/Scoop/commit/310096e2386ff3bf9082d547b140a98b92b87a83))
- **core:** Add basic WSL support by appending .exe to powershell ([#2323](https://github.com/ScoopInstaller/Scoop/issues/2323))
- **core:** Add Expand-DarkArchive and some other dependency features ([#3450](https://github.com/ScoopInstaller/Scoop/issues/3450))
- **core:** Enable TLS 1.2 in core.ps1 ([#2074](https://github.com/ScoopInstaller/Scoop/issues/2074))
- **core:** Prepare extraction of main bucket ([#3060](https://github.com/ScoopInstaller/Scoop/issues/3060))
- **core:** Support loading basedirs from config ([#3121](https://github.com/ScoopInstaller/Scoop/issues/3121))
- **core:** Update requirement to version 5 or greater ([#3330](https://github.com/ScoopInstaller/Scoop/issues/3330))
- **core:** Use consistent User-Agent Header on all webrequests ([12962acf](https://github.com/ScoopInstaller/Scoop/commit/12962acfa853593e371d09186e51660aece331e5))
- **core:** Warn on shim overwrite ([#2033](https://github.com/ScoopInstaller/Scoop/issues/2033))
- **debug:** Add option to indent debug output ([bf54a978](https://github.com/ScoopInstaller/Scoop/commit/bf54a978a1bc2efcde52513a60ec5bcb7bb1a44e))
- **decompress:** Allow other args to be passthrough ([#3411](https://github.com/ScoopInstaller/Scoop/issues/3411))
- **download:** Add support for multi-connection downloads via aria2c ([#2312](https://github.com/ScoopInstaller/Scoop/issues/2312))
- **download:** Convert sourceforge urls to use downloads mirror ([#3340](https://github.com/ScoopInstaller/Scoop/issues/3340))
- **install:** Add .NET 4.5 check to scoop install script ([e52c24c9](https://github.com/ScoopInstaller/Scoop/commit/e52c24c94ec805a327440cc07aec699afc7cc308))
- **install:** Set file write permission to global persist dir ([#2524](https://github.com/ScoopInstaller/Scoop/issues/2524))
- **json:** Normalize multi-line strings to string arrays on format ([#2444](https://github.com/ScoopInstaller/Scoop/issues/2444))
- **persist:** Support persisting files without a file extension ([#2408](https://github.com/ScoopInstaller/Scoop/issues/2408))
- **shim:** Add '.com'-type shim ([#3366](https://github.com/ScoopInstaller/Scoop/issues/3366))
- **shim:** Enabled applications which require elevated privileges ([#2053](https://github.com/ScoopInstaller/Scoop/issues/2053))
- **shim:** Enabled shimming of external applications ([#2072](https://github.com/ScoopInstaller/Scoop/issues/2072))
- **shim:** Enabled wide characters forwarding in shims ([#2106](https://github.com/ScoopInstaller/Scoop/issues/2106))
- **shim:** Make shim support PowerShell 2.0 ([#2562](https://github.com/ScoopInstaller/Scoop/issues/2562))
- **shim:** Create sh shim ([#1951](https://github.com/ScoopInstaller/Scoop/issues/1951))
- **shortcuts:** Add subdirectories/arguments for shortcuts ([#1945](https://github.com/ScoopInstaller/Scoop/issues/1945))
- **shortcuts:** Allow $dir, $original_dir and $persist_dir substitutions for shortcuts ([f3ddf0c0](https://github.com/ScoopInstaller/Scoop/commit/f3ddf0c0f81ee2a11466edf5d9f6e38a0fc2b9d4))
- **shortcuts:** Get start menu folder location from environment rather than predefined user profile path ([c245a7fe](https://github.com/ScoopInstaller/Scoop/commit/c245a7fe96ffa0b0fba23bd47f31480ea93cc183))
- **uninstall:** Print purge step to console ([#3123](https://github.com/ScoopInstaller/Scoop/issues/3123))
- **uninstall:** Add support for soft/purge uninstalling of scoop itself ([#2781](https://github.com/ScoopInstaller/Scoop/issues/2781))
- **update:** Add hold/unhold command ([#3444](https://github.com/ScoopInstaller/Scoop/issues/3444))
- **scoop-checkup:** Add NTFS check to checkup command ([#1944](https://github.com/ScoopInstaller/Scoop/issues/1944))
- **scoop-checkup:** Check for LongPaths setting ([#3387](https://github.com/ScoopInstaller/Scoop/issues/3387))
- **scoop-info:** Add scoop-info command ([#2165](https://github.com/ScoopInstaller/Scoop/issues/2165))
- **scoop-info:** Support url manifest ([#2538](https://github.com/ScoopInstaller/Scoop/issues/2538))
- **scoop-prefix:** Add scoop prefix command ([#2117](https://github.com/ScoopInstaller/Scoop/issues/2117))
- **scoop-update:** Add notification for new main bucket ([#3392](https://github.com/ScoopInstaller/Scoop/issues/3392))
- **scoop-update:** Show changelog after updating scoop and buckets ([56c35f8f](https://github.com/ScoopInstaller/Scoop/commit/56c35f8f05ed387997ef1a80ec0362adec6e51a5))
- **scoop-which:** Also show other applications in PATH with 'scoop which' ([79bf99c3](https://github.com/ScoopInstaller/Scoop/commit/79bf99c3c110494d799e147263db7b6f2f921d4e))
### Bug Fixes
- **autoupdate:** Fix base64 hash extraction ([98afb999](https://github.com/ScoopInstaller/Scoop/commit/98afb99990561c4f98f1e1334f348e52b4bee4e7))
- **autoupdate:** Fix base64 hash extraction length ([#2852](https://github.com/ScoopInstaller/Scoop/issues/2852))
- **autoupdate:** Fix metalink hash extraction ([2ad54747](https://github.com/ScoopInstaller/Scoop/commit/2ad547477b1432e7a269c90b393d62d88dce9803))
- **autoupdate:** Fix single line hash extraction ([#3015](https://github.com/ScoopInstaller/Scoop/issues/3015))
- **autoupdate:** Improve auto-update hash extraction regex ([21bf0dea](https://github.com/ScoopInstaller/Scoop/commit/21bf0dea561db021aa59bcd9363792436ac7c162))
- **autoupdate:** Linter fix ([c9539b65](https://github.com/ScoopInstaller/Scoop/commit/c9539b6575e8842a8f895d82b4119c3aef01d7c2))
- **autoupdate:** Use normal variable instead of magic $matches variable name ([d74e0a85](https://github.com/ScoopInstaller/Scoop/commit/d74e0a85b4081745bd1ab107a45794f02299737d))
- **bucket:** Change wording of new_issue_msg() ([e82587df](https://github.com/ScoopInstaller/Scoop/commit/e82587dfc41618474e03347df333e847dfaffc70))
- **bucket:** Fix new_issue_msg ([#3375](https://github.com/ScoopInstaller/Scoop/issues/3375))
- **bucket:** Use $_.Name on gci result ([1eb2609d](https://github.com/ScoopInstaller/Scoop/commit/1eb2609db51587772a4b5d1b6f58114f52639568))
- **config:** Enable writing to hidden .scoop file ([#1982](https://github.com/ScoopInstaller/Scoop/issues/1982))
- **config:** Save and load true/false values as booleans in scoops config ([16aec1a4](https://github.com/ScoopInstaller/Scoop/commit/16aec1a40b45ba241ef2ac45ccf89de7206891be))
- **core:** Allowed underscores in package names ([#2930](https://github.com/ScoopInstaller/Scoop/issues/2930))
- **core:** Clean up some error messages ([#2032](https://github.com/ScoopInstaller/Scoop/issues/2032))
- **core:** Change sf regex not to break some manifests ([#2476](https://github.com/ScoopInstaller/Scoop/issues/2476))
- **core:** Check if 7zip installed via Scoop instead of using 7z.exe from PATH ([55ce0c0b](https://github.com/ScoopInstaller/Scoop/commit/55ce0c0b0c481ec3807655cb7aeac6dfcf9ef271))
- **core:** Filter null or empty string from Scoops directory settings ([5d5c7fa9](https://github.com/ScoopInstaller/Scoop/commit/5d5c7fa91c03f05b705d3420618ec96d8e870174))
- **core:** Fix "enable-encryptionscheme" for OSes before Windows 10 ([#2084](https://github.com/ScoopInstaller/Scoop/issues/2084))
- **core:** Fix bug with Start-Process -Wait, exclusive to PowerShell Core on Windows 7 ([#3415](https://github.com/ScoopInstaller/Scoop/issues/3415))
- **core:** Fix for relative paths ([ff9c0c3d](https://github.com/ScoopInstaller/Scoop/commit/ff9c0c3dafb3567ee958379b83205da84a925ecf))
- **core:** Fix robocopy not releasing a directory after moving it ([e2792f2e](https://github.com/ScoopInstaller/Scoop/commit/e2792f2e02adee5947ebb95022a62282fb61024f))
- **core:** Fix substitute() for arrays ([#2048](https://github.com/ScoopInstaller/Scoop/issues/2048))
- **core:** Format hashes to lowercase ([5d56f8ff](https://github.com/ScoopInstaller/Scoop/commit/5d56f8ff5760ddedaf44eaf9652000e833b0944e))
- **core:** Invoke powershell with -noprofile flag from bash shims ([#3165](https://github.com/ScoopInstaller/Scoop/issues/3165))
- **core:** Removed the bucket from the app name when checking directories ([#2435](https://github.com/ScoopInstaller/Scoop/issues/2435))
- **core:** Return true for checking if a directory is 'in' itself ([ac8a1567](https://github.com/ScoopInstaller/Scoop/commit/ac8a156796cb6d3d9cba24a2839271d924ab8fea))
- **core:** Store last update time as String ([e8af15cc](https://github.com/ScoopInstaller/Scoop/commit/e8af15cc0615b707aee79be95f9c00e3ae0bfd9b))
- **decompress:** Add .bz2 files to decompression ([#2085](https://github.com/ScoopInstaller/Scoop/issues/2085))
- **decompress:** Added retry when unzip fail because of AV ([#1822](https://github.com/ScoopInstaller/Scoop/issues/1822))
- **decompress:** Catch unzip failures from bad file names ([#2472](https://github.com/ScoopInstaller/Scoop/issues/2472))
- **decompress:** Compatible Expand-ZipArchive() with Pscx ([#3425](https://github.com/ScoopInstaller/Scoop/issues/3425))
- **decompress:** Correct deprecation function name ([#3406](https://github.com/ScoopInstaller/Scoop/issues/3406))
- **decompress:** Fix dark parameter order ([87a1e784](https://github.com/ScoopInstaller/Scoop/commit/87a1e784d7463fea36fa41fcb7cb5537cbcfdc52))
- **depends:** Don't force adding dark dependency ([#3453](https://github.com/ScoopInstaller/Scoop/issues/3453))
- **depends:** Don't include the requested app in the list of dependencies ([1bc6a479](https://github.com/ScoopInstaller/Scoop/commit/1bc6a479ee969e44e2b0d83ed6ff19efd86c6ae9))
- **depends:** Fix empty bucket name ([#2827](https://github.com/ScoopInstaller/Scoop/issues/2827))
- **depends:** Fix null reference error when no buckets are configured ([88040972](https://github.com/ScoopInstaller/Scoop/commit/88040972a30b459a3859c7c2f883e47e19da9f84))
- **depends:** Show message about missing bucket when installing dependencies ([7a6218c5](https://github.com/ScoopInstaller/Scoop/commit/7a6218c58677170fe32cf1c2bfcfe7488e4c3655))
- **download:** Don't send referer to portableapps.com ([0c2b3da3](https://github.com/ScoopInstaller/Scoop/commit/0c2b3da3ff639722ad3ddf587219bb3155e97c7f))
- **download:** Fix fosshub downloads with aria2c ([803525a8](https://github.com/ScoopInstaller/Scoop/commit/803525a8661ffaa39fc4ad6f0dc776cccad4c45e))
- **download:** Interrupt download causes partial cache file to be used for next install ([5be02865](https://github.com/ScoopInstaller/Scoop/commit/5be0286561398debfee2c0610e51f006ef2dc2fb))
- **download:** Overwrite any existing files when extracting ([58cca68f](https://github.com/ScoopInstaller/Scoop/commit/58cca68f7565bd5e8f63e08ad052c0029b98a23d))
- **download:** Show warning about SourceForge.net hash validation fails ([8504338b](https://github.com/ScoopInstaller/Scoop/commit/8504338bc5faab3235cef2e1c2f41abd7ae496eb))
- **getopt:** Don't try to parse int arguments ([23fe5a53](https://github.com/ScoopInstaller/Scoop/commit/23fe5a5319d4ede84c532df04f576c3854fd5826))
- **getopt:** Don't try to parse array arguments ([9b6e7b5e](https://github.com/ScoopInstaller/Scoop/commit/9b6e7b5e0f7f6ddecdb139f932ad7d582fe639a4))
- **getopt:** Return remaining args, use getopt for scoop install ([b7cfd6fd](https://github.com/ScoopInstaller/Scoop/commit/b7cfd6fdb0e18a623ceacfa6fc824241dabc6d01))
- **getopt:** Skip if arg is $null ([f2d9f0d7](https://github.com/ScoopInstaller/Scoop/commit/f2d9f0d79fdf4a63879c1b87a6c0f5317a40a1d9))
- **getopt:** Skip arg if it's decimal ([5f0c8cfb](https://github.com/ScoopInstaller/Scoop/commit/5f0c8cfb0a34078bb8118a21191cf046ddad18ac))
- **git:** Disable git pager when running git log ([cac99759](https://github.com/ScoopInstaller/Scoop/commit/cac9975924691fe6e608789218b06be56bb8c658))
- **git:** Fix update log output ([0daa25c6](https://github.com/ScoopInstaller/Scoop/commit/0daa25c6300cd2ab605d63b71037d741c9c904c6))
- **json:** Catch JsonReaderException ([fb58e92c](https://github.com/ScoopInstaller/Scoop/commit/fb58e92c13552199f19f5df112801fc41321eee2))
- **install:** Add filename to warning for files without hash in the manifest ([4c9beee8](https://github.com/ScoopInstaller/Scoop/commit/4c9beee8f2df891b2ec314e1efffb2ee9d5cca20))
- **install:** Add multi-line support to pre/post_install ([#1980](https://github.com/ScoopInstaller/Scoop/issues/1980))
- **install:** Added exclusion for sourceforge. [#METR-21516] ([#2109](https://github.com/ScoopInstaller/Scoop/issues/2109))
- **install:** Ignore url fragment for PowerShell Core 6.1.0 ([#2602](https://github.com/ScoopInstaller/Scoop/issues/2602))
- **install:** Fix fail when installing from non-default bucket ([#2247](https://github.com/ScoopInstaller/Scoop/issues/2247))
- **install:** Fix PowerShell core crash ([#2554](https://github.com/ScoopInstaller/Scoop/issues/2554))
- **install:** Option to skip hash validation and error message improvements ([#2260](https://github.com/ScoopInstaller/Scoop/issues/2260))
- **install:** Remove env_ensure_home ([#1967](https://github.com/ScoopInstaller/Scoop/issues/1967))
- **install:** Show first 8 bytes of file in the hash check error message ([e4cbb42e](https://github.com/ScoopInstaller/Scoop/commit/e4cbb42e64843e53b5b24de92f43062bca98c474))
- **persist:** Fix condition for persist_permission() ([eb7b7cbf](https://github.com/ScoopInstaller/Scoop/commit/eb7b7cbf4f30e4122762856723155f3c1e980d1b)) ([1a2598bc](https://github.com/ScoopInstaller/Scoop/commit/1a2598bc3082a2e3fffac1a6bea0b42032e388f0))
- **persist:** Fixed persisting bug when force update app with same version ([#2774](https://github.com/ScoopInstaller/Scoop/issues/2774))
- **persist:** Fix the target didn't be created ([#3008](https://github.com/ScoopInstaller/Scoop/issues/3008))
- **persist:** Prevent directory creation from being output ([#1999](https://github.com/ScoopInstaller/Scoop/issues/1999))
- **scoop:** Force to add new main bucket ([#3419](https://github.com/ScoopInstaller/Scoop/issues/3419))
- **shim:** Fix .ps1 shim parsing logic ([#2564](https://github.com/ScoopInstaller/Scoop/issues/2564))
- **shim:** Fixed ps1/jar->ps1 shims args handling ([#2120](https://github.com/ScoopInstaller/Scoop/issues/2120))
- **shortcuts:** Improve Shortcut creation ([83b82386](https://github.com/ScoopInstaller/Scoop/commit/83b823868f5ef5256d3dcfbecff278bb355fefc8))
- **uninstall:** Better error handling during uninstallation ([#2079](https://github.com/ScoopInstaller/Scoop/issues/2079))
- **uninstall:** Uninstall fails to remove architecture-specific shims ([8b1871b2](https://github.com/ScoopInstaller/Scoop/commit/8b1871b20df4dbf1b603d4066937ba213c03bb32))
- **update:** Rewording PowerShell update notice ([d006fb93](https://github.com/ScoopInstaller/Scoop/commit/d006fb9315b55a9d8e6a36218cf5dbdde51433ec))
- **versions:** Improvements for the reset command to deal with empty current alias dir correctly ([#2896](https://github.com/ScoopInstaller/Scoop/issues/2896))
- **scoop-alias:** Improve "scoop alias list" output ([#2163](https://github.com/ScoopInstaller/Scoop/issues/2163))
- **scoop-cache:** Display help on incorrect cache command ([#3431](https://github.com/ScoopInstaller/Scoop/issues/3431))
- **scoop-cache:** scoop cache command not using $SCOOP_CACHE ([#1990](https://github.com/ScoopInstaller/Scoop/issues/1990))
- **scoop-info:** Improve scoop-info license attributes output ([#2397](https://github.com/ScoopInstaller/Scoop/issues/2397))
- **scoop-install:** Prevent installing programs from JSON multiple times ([936cf9cb](https://github.com/ScoopInstaller/Scoop/commit/936cf9cbb0c4dd3a594fbaf5c696ce519e586d8c))
- **scoop-reset:** Persist data on reset ([#2773](https://github.com/ScoopInstaller/Scoop/issues/2773))
- **scoop-reset:** Re-create shortcuts ([6e5b7e57](https://github.com/ScoopInstaller/Scoop/commit/6e5b7e57bb0628f072872d9a5b8c8a0fa58389e1))
- **scoop-search:** Better handling for invalid query ([bf024705](https://github.com/ScoopInstaller/Scoop/commit/bf024705a8cc38592571aa3026dca2471f19ac5a))
- **scoop-uninstall:** Checked if uninstaller removed its directory ([#2078](https://github.com/ScoopInstaller/Scoop/issues/2078))
- **scoop-update:** Add config option "show_update_log" ([d68cb3ce](https://github.com/ScoopInstaller/Scoop/commit/d68cb3ce52acaa9983f278822febd506f54ebe02))
- **scoop-update:** First scoop update fails because scoop deletes itself too early ([376630fd](https://github.com/ScoopInstaller/Scoop/commit/376630fd80a3f9012fd6e673460b9e28e375e951))
- **scoop-update:** Fix branch switching ([#3372](https://github.com/ScoopInstaller/Scoop/issues/3372))
- **scoop-update:** Fix update with cookies ([#3261](https://github.com/ScoopInstaller/Scoop/issues/3261))
- **scoop-update:** Improve is_scoop_outdated() and add last_scoop_update() ([f3f559c4](https://github.com/ScoopInstaller/Scoop/commit/f3f559c460406689dab2375310fb1026e2be58bd))
- **scoop-update:** Resolve linting, fix appveyor tests error ([#2148](https://github.com/ScoopInstaller/Scoop/issues/2148))
### Code Refactoring
- **bucket:** Move function into lib from lib-exec ([#3062](https://github.com/ScoopInstaller/Scoop/issues/3062))
- **bucket:** Optimize buckets function ([#3341](https://github.com/ScoopInstaller/Scoop/issues/3341))
- **config:** Move configuration handling to core.ps1 ([#3242](https://github.com/ScoopInstaller/Scoop/issues/3242))
- **core:** aria2_path() -> file_path() ([0f464016](https://github.com/ScoopInstaller/Scoop/commit/0f4640168da8d68a52eb2b80af2f3ffa01c9b658))
- **core:** cmd_available() -> Test-CommandAvailable() ([#3314](https://github.com/ScoopInstaller/Scoop/issues/3314))
- **core:** ensure_all_installed() -> Confirm-InstallationStatus() ([#3293](https://github.com/ScoopInstaller/Scoop/issues/3293))
- **core:** Move default_aliases into the scoped function ([#3233](https://github.com/ScoopInstaller/Scoop/issues/3233))
- **core:** Refactor function names and fix installing 7zip locally if already globally available ([#3416](https://github.com/ScoopInstaller/Scoop/issues/3416))
- **core:** Simplified last_scoop_update() ([#2931](https://github.com/ScoopInstaller/Scoop/issues/2931))
- **core:** Tweak SecurityProtocol usage ([#3065](https://github.com/ScoopInstaller/Scoop/issues/3065))
- **decompress:** Refactored (w/ install.ps1, core.ps1) ([#3169](https://github.com/ScoopInstaller/Scoop/issues/3169))
- **decompress:** Refactor extraction handling functions ([#3204](https://github.com/ScoopInstaller/Scoop/issues/3204))
- **download:** Download functionality refactor ([#1329](https://github.com/ScoopInstaller/Scoop/issues/1329))
- **install:** Rename locate() to Find-Manifest() ([9eed3d89](https://github.com/ScoopInstaller/Scoop/commit/9eed3d8914c7a0fa294110eb0761776a01adf034))
### Builds
- **auto-pr:** Add -App parameter ([#3157](https://github.com/ScoopInstaller/Scoop/issues/3157))
- **auto-pr:** Add SkipUpdated parameter ([#3168](https://github.com/ScoopInstaller/Scoop/issues/3168))
- **checkhashes:** Add bin\checkhashes.ps1 ([#2766](https://github.com/ScoopInstaller/Scoop/issues/2766))
- **checkurls:** Add SkipValid Parameter ([#2845](https://github.com/ScoopInstaller/Scoop/issues/2845))
- **checkurls:** Import config.ps1 in checkurls.ps1 ([126e9c97](https://github.com/ScoopInstaller/Scoop/commit/126e9c97d2ef7db537a5137167089a97f343e98e))
- **checkver:** Add 'useragent' property ([8feb3867](https://github.com/ScoopInstaller/Scoop/commit/8feb3867a74ea0340585e3e695934d96cf483a05))
- **checkver:** Add 'jsonpath' alias for 'jp' ([76fdb6b7](https://github.com/ScoopInstaller/Scoop/commit/76fdb6b74c1772bf607d2dad5f6c50269369ff88))
- **checkver:** Add 're' alias 'regex' ([468649c8](https://github.com/ScoopInstaller/Scoop/commit/468649c88dea9c1ff9614f2cdf29a521d572664e))
- **checkver:** Allow using the current version in checkver URL ([607ac9ca](https://github.com/ScoopInstaller/Scoop/commit/607ac9ca7c185da61e2c746ea87d28c2abe62adc))
- **checkver:** Fix example parameters ([#3413](https://github.com/ScoopInstaller/Scoop/issues/3413))
- **checkver:** GitHub checkver case-insensitive version check ([2e2633e9](https://github.com/ScoopInstaller/Scoop/commit/2e2633e9640f6cab5c2f895b680345cd6ca))
- **checkver:** Remove old commented code ([72754036](https://github.com/ScoopInstaller/Scoop/commit/72754036a251fffd2f2eb0e242edfd9895543e3c))
- **checkver:** Resolve issue on Powershell >6.1.0 ([#2592](https://github.com/ScoopInstaller/Scoop/issues/2592))
- **checkver:** Support skipping up to date manifests ([#2624](https://github.com/ScoopInstaller/Scoop/issues/2624))
- **schema:** Add shortcutsArray definition to schema.json ([0c7e6002](https://github.com/ScoopInstaller/Scoop/commit/0c7e60024a06e122331b17a204a158e4c5800a3d))
- **schema:** extract_to property is on active duty (not deprecated) ([59e994c5](https://github.com/ScoopInstaller/Scoop/commit/59e994c5fdeb8dffe6037ca6767d56ad13bf04da))
- **schema:** Improve comments in schema.json ([b5ed0761](https://github.com/ScoopInstaller/Scoop/commit/b5ed0761aef4f3e864533dc0460d110115850ba7))
- **supporting:** Update validator.exe and shim.exe ([#2024](https://github.com/ScoopInstaller/Scoop/issues/2024), [#2034](https://github.com/ScoopInstaller/Scoop/issues/2034))
- **supporting:** Update Newtonsoft.Json to 11.0.2, Newtonsoft.Json.Schema to 3.0.10 ([#3043](https://github.com/ScoopInstaller/Scoop/issues/3043))
- **validator:** Improve error reporting, add support for multiple files ([#3134](https://github.com/ScoopInstaller/Scoop/issues/3134))
### Continuous Integration
- **appveyor:** Rebuild cache ([7311b41b](https://github.com/ScoopInstaller/Scoop/commit/7311b41b8d1e2e010175fb7d079662bbcba5bac8))
- **appveyor:** Run tests for PowerShell 5 and 6 ([#2603](https://github.com/ScoopInstaller/Scoop/issues/2603))
- **test:** Improve installation of lessmsi and innounp ([#3409](https://github.com/ScoopInstaller/Scoop/issues/3409))
### Styles
- **lint:** PSAvoidUsingCmdletAliases ([#2075](https://github.com/ScoopInstaller/Scoop/issues/2075))
### Tests
- **bucket:** Add importable tests for Buckets ([478f52c4](https://github.com/ScoopInstaller/Scoop/commit/478f52c421ca35ea35b5fd0b2df2631cf7d82487))
- **bucket:** Fix manifest tests for buckets ([589303fa](https://github.com/ScoopInstaller/Scoop/commit/589303facc5284f6f95c1305191e0558c0169691))
- **bucket:** Handle JSON.NET schema validation limit exceeded. ([139813a8](https://github.com/ScoopInstaller/Scoop/commit/139813a8f50ace85e2752d9b6c9f82fc64ff3e48))
- **file:** Move style constraints tests to separate test file ([7b7113fc](https://github.com/ScoopInstaller/Scoop/commit/7b7113fc3bf962aaeba625f58341c30a80f0fe6a))
- **linux:** Fix some tests on linux ([#2153](https://github.com/ScoopInstaller/Scoop/issues/2153))
- **manifest:** Expose bucketdir variable in manifest test script ([#2182](https://github.com/ScoopInstaller/Scoop/issues/2182))
- **test:** Add -TestPath param to test.ps1 ([f857dce9](https://github.com/ScoopInstaller/Scoop/commit/f857dce9f59a490f6dd07085c3abaa51e9577fda))
- **test:** Force install PSScriptAnalyzer and BuildHelpers ([7a1b5a18](https://github.com/ScoopInstaller/Scoop/commit/7a1b5a1840e30321951fa0f5333c34d10f57fa94))
- **test:** Require BuildHelpers version 2.0.0 ([ac3ee766](https://github.com/ScoopInstaller/Scoop/commit/ac3ee766722e99c1f15dc60a1f1dfb0a48428c55))
- **test:** Update BuildHelpers to version 2.0.1 ([dde4d0f9](https://github.com/ScoopInstaller/Scoop/commit/dde4d0f93f260191af5524c0ecab927f3e252361))
- **core:** Use Pester 4.0 syntax in core tests ([#2712](https://github.com/ScoopInstaller/Scoop/issues/2712))
- **install:** Use Pester 4.0 syntax to the install tests ([#2713](https://github.com/ScoopInstaller/Scoop/issues/2713))
- **test:** Use Pester 4.0 syntax to multiple files ([#2714](https://github.com/ScoopInstaller/Scoop/issues/2714))
### Documentation
- **readme:** Add discord chat badge ([#3241](https://github.com/ScoopInstaller/Scoop/issues/3241))
- **readme:** Add more details about scoops installation ([#2273](https://github.com/ScoopInstaller/Scoop/issues/2273))
- **readme:** Corrected enable powershell executionpolicy ([#2020](https://github.com/ScoopInstaller/Scoop/issues/2020))
- **readme:** Update Discord invite link ([5f269249](https://github.com/ScoopInstaller/Scoop/commit/5f269249609b43f5c4fa9aba4def999e7ee05fe1))
- **readme:** Update requirements note ([#2509](https://github.com/ScoopInstaller/Scoop/issues/2509))
- **readme:** Fix typo (you -> your), (it's -> its) ([#2698](https://github.com/ScoopInstaller/Scoop/issues/2698))
- **readme:** Remove trailing whitespaces ([d25186bf](https://github.com/ScoopInstaller/Scoop/commit/d25186bf1f833e30d8c5b530b7c260fe399b75ed))
- **readme:** Remove "tail" from example (is coreutils) ([#2158](https://github.com/ScoopInstaller/Scoop/issues/2158))
## *Commits before 2018 are trimmed*

49
LICENSE
View File

@@ -1,3 +1,27 @@
SPDX-License-Identifier: UNLICENSE or MIT
INFORMATION ABOUT THIS PROJECT'S LICENSE (SHORT)
============================================================================================
This project is licensed under the Unlicense or the MIT license,
at your option.
INFORMATION ABOUT THIS PROJECT'S LICENSE (LONG)
============================================================================================
This project ("Scoop") is free software, licensed under the Unlicense or the
MIT license, at your option. Scoop was previously licensed under only the Unlicense,
but was dual-licensed from version 0.2.0.
Scoop comes with ABSOLUTELY NO WARRANTY. Use it at your own risk. Scoop is provided
on an AS-IS BASIS and its contributors disclaim all warranties.
You may use, modify, distribute, sell, copy, compile, or merge Scoop by any means.
Copies of both licenses can be found below.
THE LICENSE OF SCOOP
============================================================================================
Unlicense
---------
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
@@ -22,3 +46,28 @@ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
MIT license
-----------
The MIT License (MIT)
Copyright (c) 2013-2017 Luke Sampson (https://github.com/lukesampson)
Copyright (c) 2013-present Scoop contributors (https://github.com/ScoopInstaller/Scoop/graphs/contributors)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,11 +1,8 @@
# The PowerShell Script Analyzer will generate a warning
# diagnostic record for this file due to a bug -
# https://github.com/PowerShell/PSScriptAnalyzer/issues/472
@{
# Only diagnostic records of the specified severity will be generated.
# Uncomment the following line if you only want Errors and Warnings but
# not Information diagnostic records.
Severity = @('Error','Warning')
Severity = @('Error')
# Analyze **only** the following rules. Use IncludeRules when you want
# to invoke only a small subset of the defualt rules.
@@ -26,12 +23,6 @@
# will be excluded.
ExcludeRules = @(
# Currently Scoop widely uses Write-Host to output colored text.
'PSAvoidUsingWriteHost',
# Temporarily allow uses of Invoke-Expression,
# this command is used by some core functions and hard to be removed.
'PSAvoidUsingInvokeExpression',
# PSUseDeclaredVarsMoreThanAssignments doesn't currently work due to:
# https://github.com/PowerShell/PSScriptAnalyzer/issues/636
'PSUseDeclaredVarsMoreThanAssignments'
'PSAvoidUsingWriteHost'
)
}

145
README.md
View File

@@ -1,25 +1,25 @@
<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/lukesampson/scoop#what-does-scoop-do">Features</a></b>
|
<b><a href="https://github.com/lukesampson/scoop#installation">Installation</a></b>
|
<b><a href="https://github.com/lukesampson/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" >
<a href="https://github.com/lukesampson/scoop">
<img src="https://img.shields.io/github/languages/code-size/lukesampson/scoop.svg" alt="Code Size" />
---
<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>
<a href="https://github.com/lukesampson/scoop">
<img src="https://img.shields.io/github/repo-size/lukesampson/scoop.svg" alt="Repository size" />
<a href="https://github.com/ScoopInstaller/Scoop">
<img src="https://img.shields.io/github/repo-size/ScoopInstaller/Scoop.svg" alt="Repository size" />
</a>
<a href="https://ci.appveyor.com/project/lukesampson/scoop">
<img src="https://ci.appveyor.com/api/projects/status/05foxatmrqo0l788?svg=true" alt="Build Status" />
<a href="https://github.com/ScoopInstaller/Scoop/actions/workflows/ci.yml">
<img src="https://github.com/ScoopInstaller/Scoop/actions/workflows/ci.yml/badge.svg" alt="Scoop Core CI Tests" />
</a>
<a href="https://discord.gg/s9yRQHt">
<img src="https://img.shields.io/badge/chat-on%20discord-7289DA.svg" alt="Discord Chat" />
@@ -27,8 +27,8 @@
<a href="https://gitter.im/lukesampson/scoop">
<img src="https://badges.gitter.im/lukesampson/scoop.png" alt="Gitter Chat" />
</a>
<a href="https://github.com/lukesampson/scoop/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/lukesampson/scoop.svg" alt="License" />
<a href="./LICENSE">
<img src="https://img.shields.io/badge/license-UNLICENSE%20or%20MIT-blue" alt="License" />
</a>
</p>
@@ -36,94 +36,113 @@ 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 tries to eliminate things like:
Scoop installs apps from the command line with a minimal amount of friction. It:
- Permission popup windows
- GUI wizard-style installers
- Path pollution from installing lots of programs
- Unexpected side-effects from installing and uninstalling programs
- The need to find and install dependencies
- The need to perform extra setup steps to get a working program
- 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.
## Requirements
- Windows 7 SP1+ / Windows Server 2008+
- [PowerShell 5](https://aka.ms/wmf5download) (or later, include [PowerShell Core](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-windows?view=powershell-6)) and [.NET Framework 4.5](https://www.microsoft.com/net/download) (or later)
- PowerShell must be enabled for your user account e.g. `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`
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 this command from your PowerShell to install scoop to its default location (`C:\Users\<user>\scoop`)
Run the following commands from a regular (non-admin) PowerShell terminal to install Scoop:
```powershell
iex (new-object net.webclient).downloadstring('https://get.scoop.sh')
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression
```
Once installed, run `scoop help` for instructions.
**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.
The default setup is configured so all user installed programs and Scoop itself live in `C:\Users\<user>\scoop`.
Globally installed programs (`--global`) live in `C:\ProgramData\scoop`.
These settings can be changed through environment variables.
It will install Scoop to its default location:
### Install Scoop to a Custom Directory
`C:\Users\<YOUR USERNAME>\scoop`
```powershell
$env:SCOOP='D:\Applications\Scoop'
[Environment]::SetEnvironmentVariable('SCOOP', $env:SCOOP, 'User')
iex (new-object net.webclient).downloadstring('https://get.scoop.sh')
```
### Configure Scoop to install global programs to a Custom Directory
```powershell
$env:SCOOP_GLOBAL='F:\GlobalScoopApps'
[Environment]::SetEnvironmentVariable('SCOOP_GLOBAL', $env:SCOOP_GLOBAL, 'Machine')
```
## [Documentation](https://github.com/lukesampson/scoop/wiki)
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
```
By default, `scoop` displays a warning when running `scoop install` or `scoop update` while `aria2` is enabled. This warning can be suppressed by running `scoop config aria2-warning-enabled false`.
You can tweak the following `aria2` settings with the `scoop config` command:
- aria2-enabled (default: true)
- aria2-warning-enabled (default: true)
- [aria2-retry-wait](https://aria2.github.io/manual/en/html/aria2c.html#cmdoption-retry-wait) (default: 2)
- [aria2-split](https://aria2.github.io/manual/en/html/aria2c.html#cmdoption-s) (default: 5)
- [aria2-max-connection-per-server](https://aria2.github.io/manual/en/html/aria2c.html#cmdoption-x) (default: 5)
- [aria2-min-split-size](https://aria2.github.io/manual/en/html/aria2c.html#cmdoption-k) (default: 5M)
- [aria2-options](https://aria2.github.io/manual/en/html/aria2c.html#options) (default: )
## 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 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/lukesampson/scoop/blob/master/bucket/runat.json) package for an example: it's really just a GitHub gist.
### Contribute to this project
If you would like to improve Scoop by adding features or fixing bugs, please read our [Contributing Guide](https://github.com/ScoopInstaller/.github/blob/main/.github/CONTRIBUTING.md).
### Support this project
If you find Scoop useful and would like to support 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:
- [main](https://github.com/ScoopInstaller/Main) - Default bucket which contains popular non-GUI apps.
- [extras](https://github.com/ScoopInstaller/Extras) - Apps that do not fit the main bucket's [criteria](https://github.com/ScoopInstaller/Scoop/wiki/Criteria-for-including-apps-in-the-main-bucket).
- [games](https://github.com/Calinou/scoop-games) - Open-source and freeware video games and game-related tools.
- [nerd-fonts](https://github.com/matthewjberger/scoop-nerd-fonts) - Nerd Fonts.
- [nirsoft](https://github.com/ScoopInstaller/Nirsoft) - A collection of over 250+ apps from [Nirsoft](https://nirsoft.net).
- [sysinternals](https://github.com/niheaven/scoop-sysinternals) - The Sysinternals suite from [Microsoft](https://learn.microsoft.com/sysinternals/).
- [java](https://github.com/ScoopInstaller/Java) - A collection of Java development kits (JDKs) and Java runtime engines (JREs), Java's virtual machine debugging tools and Java based runtime engines.
- [nonportable](https://github.com/ScoopInstaller/Nonportable) - Non-portable apps (may trigger UAC prompts).
- [php](https://github.com/ScoopInstaller/PHP) - Installers for most versions of PHP.
- [versions](https://github.com/ScoopInstaller/Versions) - Alternative versions of apps found in other buckets.
The `main` bucket is installed by default. You can make use of more buckets by typing:
```console
scoop bucket add <name>
```
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 on [ScoopSearch](https://scoop.sh/) or via [other search engines](https://rasa.github.io/scoop-directory/#other-search-engines).

View File

@@ -2,37 +2,34 @@ version: "{build}-{branch}"
branches:
except:
- gh-pages
build: off
deploy: off
clone_depth: 49
image:
- Visual Studio 2017
build: false
deploy: false
clone_depth: 2
image: Visual Studio 2022
environment:
scoop: C:\projects\scoop
scoop_home: C:\projects\scoop
scoop_helpers: C:\projects\helpers
lessmsi: '%scoop_helpers%\lessmsi\lessmsi.exe'
innounp: '%scoop_helpers%\innounp\innounp.exe'
matrix:
- PowerShell: 5
- PowerShell: 6
cache:
- '%USERPROFILE%\Documents\WindowsPowerShell\Modules -> appveyor.yml, test\bin\*.ps1'
- C:\projects\helpers -> appveyor.yml, test\bin\*.ps1
- PowerShell: 7
matrix:
fast_finish: true
for:
- matrix:
only:
- PowerShell: 5
cache:
- '%USERPROFILE%\Documents\WindowsPowerShell\Modules -> appveyor.yml, test\bin\*.ps1'
- C:\projects\helpers -> appveyor.yml, test\bin\*.ps1
install:
- ps: . "$env:SCOOP_HOME\test\bin\init.ps1"
- ps: .\test\bin\init.ps1
test_script:
- ps: . "$env:SCOOP_HOME\test\bin\test.ps1" -TestPath "$env:APPVEYOR_BUILD_FOLDER"
- ps: .\test\bin\test.ps1
- matrix:
only:
- PowerShell: 6
- PowerShell: 7
cache:
- '%USERPROFILE%\Documents\PowerShell\Modules -> appveyor.yml, test\bin\*.ps1'
- C:\projects\helpers -> appveyor.yml, test\bin\*.ps1
install:
- pwsh: . "$env:SCOOP_HOME\test\bin\init.ps1"
- pwsh: .\test\bin\init.ps1
test_script:
- pwsh: . "$env:SCOOP_HOME\test\bin\test.ps1" -TestPath "$env:APPVEYOR_BUILD_FOLDER"
- pwsh: .\test\bin\test.ps1

View File

@@ -2,25 +2,33 @@
.SYNOPSIS
Updates manifests and pushes them or creates pull-requests.
.DESCRIPTION
Updates manifests and pushes them directly to the master branch or creates pull-requests for upstream.
Updates manifests and pushes them directly to the origin branch or creates pull-requests for upstream.
.PARAMETER Upstream
Upstream repository with the target branch.
Must be in format '<user>/<repo>:<branch>'
.PARAMETER OriginBranch
Origin (local) branch name.
.PARAMETER App
Manifest name to search.
Placeholders are supported.
.PARAMETER CommitMessageFormat
The format of the commit message.
<app> will be replaced with the file name of manifest.
<version> will be replaced with the version of the latest manifest.
.PARAMETER Dir
The directory where to search for manifests.
.PARAMETER Push
Push updates directly to 'origin master'.
Push updates directly to 'origin branch'.
.PARAMETER Request
Create pull-requests on 'upstream master' for each update.
Create pull-requests on 'upstream branch' for each update.
.PARAMETER Help
Print help to console.
.PARAMETER SpecialSnowflakes
An array of manifests, which should be updated all the time. (-ForceUpdate parameter to checkver)
.PARAMETER SkipUpdated
Updated manifests will not be shown.
.PARAMETER ThrowError
Throw error as exception instead of just printing it.
.EXAMPLE
PS BUCKETROOT > .\bin\auto-pr.ps1 'someUsername/repository:branch' -Request
.EXAMPLE
@@ -37,8 +45,9 @@ param(
$true
})]
[String] $Upstream,
[String] $OriginBranch = 'master',
[String] $App = '*',
[Parameter(Mandatory = $true)]
[String] $CommitMessageFormat = '<app>: Update to version <version>',
[ValidateScript( {
if (!(Test-Path $_ -Type Container)) {
throw "$_ is not a directory!"
@@ -51,32 +60,38 @@ param(
[Switch] $Request,
[Switch] $Help,
[string[]] $SpecialSnowflakes,
[Switch] $SkipUpdated
[Switch] $SkipUpdated,
[Switch] $ThrowError
)
. "$PSScriptRoot\..\lib\manifest.ps1"
. "$PSScriptRoot\..\lib\json.ps1"
. "$PSScriptRoot\..\lib\unix.ps1"
$Dir = Resolve-Path $Dir
if ($App -ne '*' -and (Test-Path $App -PathType Leaf)) {
$Dir = Split-Path $App
} elseif ($Dir) {
$Dir = Convert-Path $Dir
} else {
throw "'-Dir' parameter required if '-App' is not a filepath!"
}
if ((!$Push -and !$Request) -or $Help) {
Write-Host @'
Usage: auto-pr.ps1 [OPTION]
Mandatory options:
-p, -push push updates directly to 'origin master'
-r, -request create pull-requests on 'upstream master' for each update
-p, -push push updates directly to 'origin branch'
-r, -request create pull-requests on 'upstream branch' for each update
Optional options:
-u, -upstream upstream repository with target branch
only used if -r is set (default: lukesampson/scoop:master)
-o, -originbranch origin (local) branch name
-h, -help
'@
exit 0
}
if (is_unix) {
if ($IsLinux -or $IsMacOS) {
if (!(which hub)) {
Write-Host "Please install hub ('brew install hub' or visit: https://hub.github.com/)" -ForegroundColor Yellow
exit 1
@@ -90,7 +105,7 @@ if (is_unix) {
function execute($cmd) {
Write-Host $cmd -ForegroundColor Green
$output = Invoke-Expression $cmd
$output = Invoke-Command ([scriptblock]::Create($cmd))
if ($LASTEXITCODE -gt 0) {
abort "^^^ Error! See above ^^^ (last command: $cmd)"
@@ -99,12 +114,12 @@ function execute($cmd) {
return $output
}
function pull_requests($json, [String] $app, [String] $upstream, [String] $manifest) {
function pull_requests($json, [String] $app, [String] $upstream, [String] $manifest, [String] $commitMessage) {
$version = $json.version
$homepage = $json.homepage
$branch = "manifest/$app-$version"
execute 'hub checkout master'
execute "hub checkout $OriginBranch"
Write-Host "hub rev-parse --verify $branch" -ForegroundColor Green
hub rev-parse --verify $branch
@@ -116,7 +131,7 @@ function pull_requests($json, [String] $app, [String] $upstream, [String] $manif
Write-Host "Creating update $app ($version) ..." -ForegroundColor DarkCyan
execute "hub checkout -b $branch"
execute "hub add $manifest"
execute "hub commit -m '${app}: Update to version $version'"
execute "hub commit -m '$commitMessage"
Write-Host "Pushing update $app ($version) ..." -ForegroundColor DarkCyan
execute "hub push origin $branch"
@@ -131,7 +146,7 @@ function pull_requests($json, [String] $app, [String] $upstream, [String] $manif
Write-Host "hub pull-request -m '<msg>' -b '$upstream' -h '$branch'" -ForegroundColor Green
$msg = @"
$app`: Update to version $version
$commitMessage
Hello lovely humans,
a new version of [$app]($homepage) is available.
@@ -141,27 +156,27 @@ a new version of [$app]($homepage) is available.
| New version | $version |
"@
hub pull-request -m "$msg" -b '$upstream' -h '$branch'
hub pull-request -m "$msg" -b "$upstream" -h "$branch"
if ($LASTEXITCODE -gt 0) {
execute 'hub reset'
abort "Pull Request failed! (hub pull-request -m '${app}: Update to version $version' -b '$upstream' -h '$branch')"
abort "Pull Request failed! (hub pull-request -m '$commitMessage' -b '$upstream' -h '$branch')"
}
}
Write-Host 'Updating ...' -ForegroundColor DarkCyan
if ($Push) {
execute 'hub pull origin master'
execute 'hub checkout master'
execute "hub pull origin $OriginBranch"
execute "hub checkout $OriginBranch"
} else {
execute 'hub pull upstream master'
execute 'hub push origin master'
execute "hub pull upstream $OriginBranch"
execute "hub push origin $OriginBranch"
}
. "$PSScriptRoot\checkver.ps1" -App $App -Dir $Dir -Update -SkipUpdated:$SkipUpdated
. "$PSScriptRoot\checkver.ps1" -App $App -Dir $Dir -Update -SkipUpdated:$SkipUpdated -ThrowError:$ThrowError
if ($SpecialSnowflakes) {
Write-Host "Forcing update on our special snowflakes: $($SpecialSnowflakes -join ',')" -ForegroundColor DarkCyan
$SpecialSnowflakes -split ',' | ForEach-Object {
. "$PSScriptRoot\checkver.ps1" $_ -Dir $Dir -ForceUpdate
. "$PSScriptRoot\checkver.ps1" $_ -Dir $Dir -ForceUpdate -ThrowError:$ThrowError
}
}
@@ -178,30 +193,30 @@ hub diff --name-only | ForEach-Object {
return
}
$version = $json.version
$CommitMessage = $CommitMessageFormat -replace '<app>',$app -replace '<version>',$version
if ($Push) {
Write-Host "Creating update $app ($version) ..." -ForegroundColor DarkCyan
execute "hub add $manifest"
# detect if file was staged, because it's not when only LF or CRLF have changed
$status = execute 'hub status --porcelain -uno'
$status = $status | Select-Object -First 1
if ($status -and $status -match "^\x20*M\x20+.*$app.json") {
execute "hub commit -m '${app}: Update to version $version'"
$status = $status | Where-Object { $_ -match "M\s{2}.*$app.json" }
if ($status -and $status.StartsWith('M ') -and $status.EndsWith("$app.json")) {
execute "hub commit -m '$commitMessage'"
} else {
Write-Host "Skipping $app because only LF/CRLF changes were detected ..." -ForegroundColor Yellow
}
} else {
pull_requests $json $app $Upstream $manifest
pull_requests $json $app $Upstream $manifest $CommitMessage
}
}
if ($Push) {
Write-Host 'Pushing updates ...' -ForegroundColor DarkCyan
execute 'hub push origin master'
execute "hub push origin $OriginBranch"
} else {
Write-Host 'Returning to master branch and removing unstaged files ...' -ForegroundColor DarkCyan
execute 'hub checkout -f master'
Write-Host "Returning to $OriginBranch branch and removing unstaged files ..." -ForegroundColor DarkCyan
execute "hub checkout -f $OriginBranch"
}
execute 'hub reset'
execute 'hub reset --hard'

View File

@@ -14,7 +14,7 @@
Manifests without mismatch will not be shown.
.PARAMETER UseCache
Downloaded files will not be deleted after script finish.
Should not be used, because check should be used for downloading actual version of file (as normal user, not finding in some document from vendors, which could be damaged / wrong (Example: Slack@3.3.1 lukesampson/scoop-extras#1192)), not some previously downloaded.
Should not be used, because check should be used for downloading actual version of file (as normal user, not finding in some document from vendors, which could be damaged / wrong (Example: Slack@3.3.1 ScoopInstaller/Extras#1192)), not some previously downloaded.
.EXAMPLE
PS BUCKETROOT> .\bin\checkhashes.ps1
Check all manifests for hash mismatch.
@@ -46,13 +46,12 @@ param(
. "$PSScriptRoot\..\lib\autoupdate.ps1"
. "$PSScriptRoot\..\lib\json.ps1"
. "$PSScriptRoot\..\lib\versions.ps1"
. "$PSScriptRoot\..\lib\install.ps1"
. "$PSScriptRoot\..\lib\unix.ps1"
. "$PSScriptRoot\..\lib\download.ps1"
$Dir = Resolve-Path $Dir
$Dir = Convert-Path $Dir
if ($ForceUpdate) { $Update = $true }
# Cleanup
if (!$UseCache) { scoop cache rm '*HASH_CHECK*' }
if (!$UseCache) { Remove-Item "$cachedir\*HASH_CHECK*" -Force }
function err ([String] $name, [String[]] $message) {
Write-Host "$name`: " -ForegroundColor Red -NoNewline
@@ -60,9 +59,10 @@ function err ([String] $name, [String[]] $message) {
}
$MANIFESTS = @()
foreach ($single in Get-ChildItem $Dir "$App.json") {
$name = (strip_ext $single.Name)
$manifest = parse_json "$Dir\$($single.Name)"
foreach ($single in Get-ChildItem $Dir -Filter "$App.json" -Recurse) {
$name = $single.BaseName
$file = $single.FullName
$manifest = parse_json $file
# Skip nighly manifests, since their hash validation is skipped
if ($manifest.version -eq 'nightly') { continue }
@@ -70,15 +70,17 @@ foreach ($single in Get-ChildItem $Dir "$App.json") {
$urls = @()
$hashes = @()
if ($manifest.architecture) {
# First handle 64bit
url $manifest '64bit' | ForEach-Object { $urls += $_ }
hash $manifest '64bit' | ForEach-Object { $hashes += $_ }
url $manifest '32bit' | ForEach-Object { $urls += $_ }
hash $manifest '32bit' | ForEach-Object { $hashes += $_ }
} elseif ($manifest.url) {
if ($manifest.url) {
$manifest.url | ForEach-Object { $urls += $_ }
$manifest.hash | ForEach-Object { $hashes += $_ }
} elseif ($manifest.architecture) {
# First handle 64bit
script:url $manifest '64bit' | ForEach-Object { $urls += $_ }
hash $manifest '64bit' | ForEach-Object { $hashes += $_ }
script:url $manifest '32bit' | ForEach-Object { $urls += $_ }
hash $manifest '32bit' | ForEach-Object { $hashes += $_ }
script:url $manifest 'arm64' | ForEach-Object { $urls += $_ }
hash $manifest 'arm64' | ForEach-Object { $hashes += $_ }
} else {
err $name 'Manifest does not contain URL property.'
continue
@@ -92,6 +94,7 @@ foreach ($single in Get-ChildItem $Dir "$App.json") {
$MANIFESTS += @{
app = $name
file = $file
manifest = $manifest
urls = $urls
hashes = $hashes
@@ -110,13 +113,16 @@ foreach ($current in $MANIFESTS) {
$current.urls | ForEach-Object {
$algorithm, $expected = get_hash $current.hashes[$count]
$version = 'HASH_CHECK'
$tmp = $expected_hash -split ':'
if ($UseCache) {
$version = $current.manifest.version
} else {
$version = 'HASH_CHECK'
}
dl_with_cache $current.app $version $_ $null $null -use_cache:$UseCache
Invoke-CachedDownload $current.app $version $_ $null $null -use_cache:$UseCache
$to_check = fullpath (cache_path $current.app $version $_)
$actual_hash = compute_hash $to_check $algorithm
$to_check = cache_path $current.app $version $_
$actual_hash = (Get-FileHash -Path $to_check -Algorithm $algorithm).Hash.ToLower()
# Append type of algorithm to both expected and actual if it's not sha256
if ($algorithm -ne 'sha256') {
@@ -140,13 +146,13 @@ foreach ($current in $MANIFESTS) {
Write-Host "$($current.app): " -NoNewline
Write-Host 'Mismatch found ' -ForegroundColor Red
$mismatched | ForEach-Object {
$file = fullpath (cache_path $current.app $version $current.urls[$_])
Write-Host "`tURL:`t`t$($current.urls[$_])"
$file = cache_path $current.app $version $current.urls[$_]
Write-Host "`tURL:`t`t$($current.urls[$_])"
if (Test-Path $file) {
Write-Host "`tFirst bytes:`t$((get_magic_bytes_pretty $file ' ').ToUpper())"
Write-Host "`tFirst bytes:`t$((get_magic_bytes_pretty $file ' ').ToUpper())"
}
Write-Host "`tExpected:`t$($current.hashes[$_])" -ForegroundColor Green
Write-Host "`tActual:`t`t$($actuals[$_])" -ForegroundColor Red
Write-Host "`tExpected:`t$($current.hashes[$_])" -ForegroundColor Green
Write-Host "`tActual:`t`t$($actuals[$_])" -ForegroundColor Red
}
}
@@ -158,23 +164,27 @@ foreach ($current in $MANIFESTS) {
# Defaults to zero, don't know, which architecture is available
$64bit_count = 0
$32bit_count = 0
$arm64_count = 0
# 64bit is get, donwloaded and added first
if ($platforms.Contains('64bit')) {
$64bit_count = $current.manifest.architecture.'64bit'.hash.Count
# 64bit is get, donwloaded and added first
$current.manifest.architecture.'64bit'.hash = $actuals[0..($64bit_count - 1)]
}
if ($platforms.Contains('32bit')) {
$32bit_count = $current.manifest.architecture.'32bit'.hash.Count
$max = $64bit_count + $32bit_count - 1 # Edge case if manifest contains 64bit and 32bit.
$current.manifest.architecture.'32bit'.hash = $actuals[($64bit_count)..$max]
$current.manifest.architecture.'32bit'.hash = $actuals[($64bit_count)..($64bit_count + $32bit_count - 1)]
}
if ($platforms.Contains('arm64')) {
$arm64_count = $current.manifest.architecture.'arm64'.hash.Count
$current.manifest.architecture.'arm64'.hash = $actuals[($64bit_count + $32bit_count)..($64bit_count + $32bit_count + $arm64_count - 1)]
}
}
Write-Host "Writing updated $($current.app) manifest" -ForegroundColor DarkGreen
$current.manifest = $current.manifest | ConvertToPrettyJson
$path = Resolve-Path "$Dir\$($current.app).json"
$path = Convert-Path $current.file
[System.IO.File]::WriteAllLines($path, $current.manifest)
}
}

View File

@@ -28,14 +28,14 @@ param(
. "$PSScriptRoot\..\lib\core.ps1"
. "$PSScriptRoot\..\lib\manifest.ps1"
. "$PSScriptRoot\..\lib\install.ps1"
. "$PSScriptRoot\..\lib\download.ps1"
$Dir = Resolve-Path $Dir
$Dir = Convert-Path $Dir
$Queue = @()
Get-ChildItem $Dir "$App.json" | ForEach-Object {
$manifest = parse_json "$Dir\$($_.Name)"
$Queue += , @($_.Name, $manifest)
Get-ChildItem $Dir -Filter "$App.json" -Recurse | ForEach-Object {
$manifest = parse_json $_.FullName
$Queue += , @($_.BaseName, $manifest)
}
Write-Host '[' -NoNewLine
@@ -50,6 +50,9 @@ Write-Host ']ailed'
Write-Host ' | | |'
function test_dl([String] $url, $cookies) {
# Trim renaming suffix, prevent getting 40x response
$url = ($url -split '#/')[0]
$wreq = [Net.WebRequest]::Create($url)
$wreq.Timeout = $Timeout * 1000
if ($wreq -is [Net.HttpWebRequest]) {
@@ -59,6 +62,13 @@ function test_dl([String] $url, $cookies) {
$wreq.Headers.Add('Cookie', (cookie_header $cookies))
}
}
get_config PRIVATE_HOSTS | Where-Object { $_ -ne $null -and $url -match $_.match } | ForEach-Object {
(ConvertFrom-StringData -StringData $_.Headers).GetEnumerator() | ForEach-Object {
$wreq.Headers[$_.Key] = $_.Value
}
}
$wres = $null
try {
$wres = $wreq.GetResponse()
@@ -86,8 +96,9 @@ foreach ($man in $Queue) {
if ($manifest.url) {
$manifest.url | ForEach-Object { $urls += $_ }
} else {
url $manifest '64bit' | ForEach-Object { $urls += $_ }
url $manifest '32bit' | ForEach-Object { $urls += $_ }
script:url $manifest '64bit' | ForEach-Object { $urls += $_ }
script:url $manifest '32bit' | ForEach-Object { $urls += $_ }
script:url $manifest 'arm64' | ForEach-Object { $urls += $_ }
}
$urls | ForEach-Object {
@@ -122,7 +133,7 @@ foreach ($man in $Queue) {
Write-Host $failed -NoNewLine -ForegroundColor Red
}
Write-Host '] ' -NoNewLine
Write-Host (strip_ext $name)
Write-Host $name
$errors | ForEach-Object {
Write-Host " > $_" -ForegroundColor DarkRed

View File

@@ -15,6 +15,10 @@
Useful for hash updates.
.PARAMETER SkipUpdated
Updated manifests will not be shown.
.PARAMETER Version
Update manifest to specific version.
.PARAMETER ThrowError
Throw error as exception instead of just printing it.
.EXAMPLE
PS BUCKETROOT > .\bin\checkver.ps1
Check all manifest inside default directory.
@@ -48,7 +52,6 @@
#>
param(
[String] $App = '*',
[Parameter(Mandatory = $true)]
[ValidateScript( {
if (!(Test-Path $_ -Type Container)) {
throw "$_ is not a directory!"
@@ -60,41 +63,55 @@ param(
[Switch] $Update,
[Switch] $ForceUpdate,
[Switch] $SkipUpdated,
[String] $Version = ''
[String] $Version = '',
[Switch] $ThrowError
)
. "$psscriptroot\..\lib\core.ps1"
. "$psscriptroot\..\lib\manifest.ps1"
. "$psscriptroot\..\lib\buckets.ps1"
. "$psscriptroot\..\lib\autoupdate.ps1"
. "$psscriptroot\..\lib\json.ps1"
. "$psscriptroot\..\lib\versions.ps1"
. "$psscriptroot\..\lib\install.ps1" # needed for hash generation
. "$psscriptroot\..\lib\unix.ps1"
. "$PSScriptRoot\..\lib\core.ps1"
. "$PSScriptRoot\..\lib\autoupdate.ps1"
. "$PSScriptRoot\..\lib\manifest.ps1"
. "$PSScriptRoot\..\lib\buckets.ps1"
. "$PSScriptRoot\..\lib\json.ps1"
. "$PSScriptRoot\..\lib\versions.ps1"
. "$PSScriptRoot\..\lib\download.ps1"
$Dir = Resolve-Path $Dir
$Search = $App
if ($App -ne '*' -and (Test-Path $App -PathType Leaf)) {
$Dir = Split-Path $App
$files = Get-ChildItem $Dir -Filter (Split-Path $App -Leaf)
} elseif ($Dir) {
$Dir = Convert-Path $Dir
$files = Get-ChildItem $Dir -Filter "$App.json" -Recurse
} else {
throw "'-Dir' parameter required if '-App' is not a filepath!"
}
$GitHubToken = Get-GitHubToken
# don't use $Version with $App = '*'
if ($App -eq '*' -and $Version -ne '') {
throw "Don't use '-Version' with '-App *'!"
}
# get apps to check
$Queue = @()
$json = ''
Get-ChildItem $Dir "$App.json" | ForEach-Object {
$json = parse_json "$Dir\$($_.Name)"
$files | ForEach-Object {
$file = $_.FullName
$json = parse_json $file
if ($json.checkver) {
$Queue += , @($_.Name, $json)
$Queue += , @($_.BaseName, $json, $file)
}
}
# clear any existing events
Get-Event | ForEach-Object {
Remove-Event $_.SourceIdentifier
}
Get-Event | Remove-Event
Get-EventSubscriber | Unregister-Event
# start all downloads
$Queue | ForEach-Object {
$name, $json = $_
$name, $json, $file = $_
$substitutions = get_version_substitutions $json.version
$substitutions = Get-VersionSubstitution $json.version # 'autoupdate.ps1'
$wc = New-Object Net.Webclient
if ($json.checkver.useragent) {
@@ -102,36 +119,81 @@ $Queue | ForEach-Object {
} else {
$wc.Headers.Add('User-Agent', (Get-UserAgent))
}
Register-ObjectEvent $wc downloadstringcompleted -ErrorAction Stop | Out-Null
Register-ObjectEvent $wc downloadDataCompleted -ErrorAction Stop | Out-Null
$githubRegex = '\/releases\/tag\/(?:v|V)?([\d.]+)'
$url = $json.homepage
# Not Specified
if ($json.checkver.url) {
$url = $json.checkver.url
}
$regex = ''
$jsonpath = ''
$replace = ''
if ($json.checkver -eq 'github') {
if (!$json.homepage.StartsWith('https://github.com/')) {
error "$name checkver expects the homepage to be a github repository"
}
$url = $json.homepage + '/releases/latest'
$regex = $githubRegex
}
if ($json.checkver.github) {
$url = $json.checkver.github + '/releases/latest'
$regex = $githubRegex
} else {
$url = $json.homepage
}
if ($json.checkver.re) {
$regex = $json.checkver.re
}
if ($json.checkver.regex) {
} elseif ($json.checkver.regex) {
$regex = $json.checkver.regex
} else {
$regex = ''
}
$jsonpath = ''
$xpath = ''
$replace = ''
$useGithubAPI = $false
# GitHub
if ($regex) {
$githubRegex = $regex
} else {
$githubRegex = '/releases/tag/(?:v|V)?([\d.]+)'
}
if ($json.checkver -eq 'github') {
if (!$json.homepage.StartsWith('https://github.com/')) {
error "$name checkver expects the homepage to be a github repository"
}
$url = $json.homepage.TrimEnd('/') + '/releases/latest'
$regex = $githubRegex
$useGithubAPI = $true
}
if ($json.checkver.github) {
$url = $json.checkver.github.TrimEnd('/') + '/releases/latest'
$regex = $githubRegex
if ($json.checkver.PSObject.Properties.Count -eq 1) { $useGithubAPI = $true }
}
# SourceForge
if ($regex) {
$sourceforgeRegex = $regex
} else {
$sourceforgeRegex = '(?!\.)([\d.]+)(?<=\d)'
}
if ($json.checkver -eq 'sourceforge') {
if ($json.homepage -match '//(sourceforge|sf)\.net/projects/(?<project>[^/]+)(/files/(?<path>[^/]+))?|//(?<project>[^.]+)\.(sourceforge\.(net|io)|sf\.net)') {
$project = $Matches['project']
$path = $Matches['path']
} else {
$project = strip_ext $name
}
$url = "https://sourceforge.net/projects/$project/rss"
if ($path) {
$url = $url + '?path=/' + $path.TrimStart('/')
}
$regex = "CDATA\[/$path/.*?$sourceforgeRegex.*?\]".Replace('//', '/')
}
if ($json.checkver.sourceforge) {
if ($json.checkver.sourceforge -is [System.String] -and $json.checkver.sourceforge -match '(?<project>[\w-]*)(/(?<path>.*))?') {
$project = $Matches['project']
$path = $Matches['path']
} else {
$project = $json.checkver.sourceforge.project
$path = $json.checkver.sourceforge.path
}
$url = "https://sourceforge.net/projects/$project/rss"
if ($path) {
$url = $url + '?path=/' + $path.TrimStart('/')
}
$regex = "CDATA\[/$path/.*?$sourceforgeRegex.*?\]".Replace('//', '/')
}
if ($json.checkver.jp) {
@@ -140,31 +202,49 @@ $Queue | ForEach-Object {
if ($json.checkver.jsonpath) {
$jsonpath = $json.checkver.jsonpath
}
if ($json.checkver.xpath) {
$xpath = $json.checkver.xpath
}
if ($json.checkver.replace -and $json.checkver.replace.GetType() -eq [System.String]) {
if ($json.checkver.replace -is [System.String]) { # If `checkver` is [System.String], it has a method called `Replace`
$replace = $json.checkver.replace
}
if (!$jsonpath -and !$regex) {
if (!$jsonpath -and !$regex -and !$xpath) {
$regex = $json.checkver
}
$reverse = $json.checkver.reverse -and $json.checkver.reverse -eq 'true'
if ($url -like '*api.github.com/*') { $useGithubAPI = $true }
if ($useGithubAPI -and ($null -ne $GitHubToken)) {
$url = $url -replace '//(www\.)?github.com/', '//api.github.com/repos/'
$wc.Headers.Add('Authorization', "token $GitHubToken")
}
$url = substitute $url $substitutions
$state = New-Object psobject @{
app = (strip_ext $name);
url = $url;
regex = $regex;
json = $json;
jsonpath = $jsonpath;
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))
$wc.DownloadStringAsync($url, $state)
$wc.DownloadDataAsync($url, $state)
}
function next($er) {
@@ -180,78 +260,129 @@ while ($in_progress -gt 0) {
$in_progress--
$state = $ev.SourceEventArgs.UserState
$result = $ev.SourceEventArgs.Result
$app = $state.app
$file = $state.file
$json = $state.json
$url = $state.url
$regexp = $state.regex
$jsonpath = $state.jsonpath
$xpath = $state.xpath
$script = $json.checkver.script
$reverse = $state.reverse
$replace = $state.replace
$expected_ver = $json.version
$ver = ''
$err = $ev.SourceEventArgs.Error
$page = $ev.SourceEventArgs.Result
if ($err) {
next "$($err.message)`r`nURL $url is not valid"
continue
}
if (!$regex -and $replace) {
next "'replace' requires 're' or 'regex'"
continue
}
if ($jsonpath) {
$ver = json_path $page $jsonpath
if (!$ver) {
$ver = json_path_legacy $page $jsonpath
}
if (!$ver) {
next "couldn't find '$jsonpath' in $url"
continue
}
}
if ($jsonpath -and $regexp) {
$page = $ver
$ver = ''
}
if ($regexp) {
$regex = New-Object System.Text.RegularExpressions.Regex($regexp)
if ($reverse) {
$match = $regex.Matches($page) | Select-Object -Last 1
} else {
$match = $regex.Matches($page) | Select-Object -First 1
}
if ($match -and $match.Success) {
$matchesHashtable = @{}
$regex.GetGroupNames() | ForEach-Object { $matchesHashtable.Add($_, $match.Groups[$_].Value) }
$ver = $matchesHashtable['1']
if ($replace) {
$ver = $regex.Replace($match.Value, $replace)
}
if (!$ver) {
$ver = $matchesHashtable['version']
}
} else {
next "couldn't match '$regexp' in $url"
continue
}
}
$ver = $Version
if (!$ver) {
next "couldn't find new version in $url"
continue
if (!$regexp -and $replace) {
next "'replace' requires 're' or 'regex'"
continue
}
$err = $ev.SourceEventArgs.Error
if ($err) {
next "$($err.message)`r`nURL $url is not valid"
continue
}
if ($url) {
$ms = New-Object System.IO.MemoryStream
$ms.Write($result, 0, $result.Length)
$ms.Seek(0, 0) | Out-Null
if ($result[0] -eq 0x1F -and $result[1] -eq 0x8B) {
$ms = New-Object System.IO.Compression.GZipStream($ms, [System.IO.Compression.CompressionMode]::Decompress)
}
$page = (New-Object System.IO.StreamReader($ms, (Get-Encoding $wc))).ReadToEnd()
}
$source = $url
if ($script) {
$page = Invoke-Command ([scriptblock]::Create($script -join "`r`n"))
$source = 'the output of script'
}
if ($jsonpath) {
# Return only a single value if regex is absent
$noregex = [String]::IsNullOrEmpty($regexp)
# If reverse is ON and regex is ON,
# Then reverse would have no effect because regex handles reverse
# on its own
# So in this case we have to disable reverse
$ver = json_path $page $jsonpath $null ($reverse -and $noregex) $noregex
if (!$ver) {
$ver = json_path_legacy $page $jsonpath
}
if (!$ver) {
next "couldn't find '$jsonpath' in $source"
continue
}
}
if ($xpath) {
$xml = [xml]$page
# Find all `significant namespace declarations` from the XML file
$nsList = $xml.SelectNodes("//namespace::*[not(. = ../../namespace::*)]")
# Then add them into the NamespaceManager
$nsmgr = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
$nsList | ForEach-Object {
if ($_.LocalName -eq 'xmlns') {
$nsmgr.AddNamespace('ns', $_.Value)
$xpath = $xpath -replace '/([^:/]+)((?=/)|(?=$))', '/ns:$1'
} else {
$nsmgr.AddNamespace($_.LocalName, $_.Value)
}
}
# Getting version from XML, using XPath
$ver = $xml.SelectSingleNode($xpath, $nsmgr).'#text'
if (!$ver) {
next "couldn't find '$($xpath -replace 'ns:', '')' in $source"
continue
}
}
if ($jsonpath -and $regexp) {
$page = $ver
$ver = ''
}
if ($xpath -and $regexp) {
$page = $ver
$ver = ''
}
if ($regexp) {
$re = New-Object System.Text.RegularExpressions.Regex($regexp)
if ($reverse) {
$match = $re.Matches($page) | Select-Object -Last 1
} else {
$match = $re.Matches($page) | Select-Object -First 1
}
if ($match -and $match.Success) {
$matchesHashtable = @{}
$re.GetGroupNames() | ForEach-Object { $matchesHashtable.Add($_, $match.Groups[$_].Value) }
$ver = $matchesHashtable['1']
if ($replace) {
$ver = $re.Replace($match.Value, $replace)
}
if (!$ver) {
$ver = $matchesHashtable['version']
}
} else {
next "couldn't match '$regexp' in $source"
continue
}
}
if (!$ver) {
next "couldn't find new version in $source"
continue
}
}
# Skip actual only if versions are same and there is no -f
if (($ver -eq $expected_ver) -and !$ForceUpdate -and $SkipUpdated) { continue }
Write-Host "$App`: " -NoNewline
Write-Host "$app`: " -NoNewline
# version hasn't changed (step over if forced update)
if ($ver -eq $expected_ver -and !$ForceUpdate) {
@@ -261,7 +392,7 @@ while ($in_progress -gt 0) {
Write-Host $ver -ForegroundColor DarkRed -NoNewline
Write-Host " (scoop version is $expected_ver)" -NoNewline
$update_available = (compare_versions $expected_ver $ver) -eq -1
$update_available = (Compare-Version -ReferenceVersion $ver -DifferenceVersion $expected_ver) -ne 0
if ($json.autoupdate -and $update_available) {
Write-Host ' autoupdate available' -ForegroundColor Cyan
@@ -277,12 +408,13 @@ while ($in_progress -gt 0) {
Write-Host 'Forcing autoupdate!' -ForegroundColor DarkMagenta
}
try {
if ($Version -ne "") {
$ver = $Version
}
autoupdate $App $Dir $json $ver $matchesHashtable
Invoke-AutoUpdate $app $file $json $ver $matchesHashtable # 'autoupdate.ps1'
} catch {
error $_.Exception.Message
if ($ThrowError) {
throw $_
} else {
error $_.Exception.Message
}
}
}
}

View File

@@ -23,13 +23,14 @@ param(
. "$PSScriptRoot\..\lib\core.ps1"
. "$PSScriptRoot\..\lib\manifest.ps1"
. "$PSScriptRoot\..\lib\description.ps1"
. "$PSScriptRoot\..\lib\download.ps1"
$Dir = Resolve-Path $Dir
$Dir = Convert-Path $Dir
$Queue = @()
Get-ChildItem $Dir "$App.json" | ForEach-Object {
$manifest = parse_json "$Dir\$($_.Name)"
$Queue += , @(($_.Name -replace '\.json$', ''), $manifest)
Get-ChildItem $Dir -Filter "$App.json" -Recurse | ForEach-Object {
$manifest = parse_json $_.FullName
$Queue += , @($_.BaseName, $manifest)
}
$Queue | ForEach-Object {
@@ -44,7 +45,8 @@ $Queue | ForEach-Object {
try {
$wc = New-Object Net.Webclient
$wc.Headers.Add('User-Agent', (Get-UserAgent))
$home_html = $wc.DownloadString($manifest.homepage)
$homepage = $wc.DownloadData($manifest.homepage)
$home_html = (Get-Encoding($wc)).GetString($homepage)
} catch {
Write-Host "`n$($_.Exception.Message)" -ForegroundColor Red
return

View File

@@ -31,15 +31,14 @@ param(
. "$PSScriptRoot\..\lib\manifest.ps1"
. "$PSScriptRoot\..\lib\json.ps1"
$Dir = Resolve-Path $Dir
Get-ChildItem $Dir "$App.json" | ForEach-Object {
if ($PSVersionTable.PSVersion.Major -gt 5) { $_ = $_.Name } # Fix for pwsh
$Dir = Convert-Path $Dir
Get-ChildItem $Dir -Filter "$App.json" -Recurse | ForEach-Object {
$file = $_.FullName
# beautify
$json = parse_json "$Dir\$_" | ConvertToPrettyJson
$json = parse_json $file | ConvertToPrettyJson
# convert to 4 spaces
$json = $json -replace "`t", ' '
[System.IO.File]::WriteAllLines("$Dir\$_", $json)
[System.IO.File]::WriteAllLines($file, $json)
}

View File

@@ -1,78 +1,2 @@
#Requires -Version 5
# remote install:
# iex (new-object net.webclient).downloadstring('https://get.scoop.sh')
$old_erroractionpreference = $erroractionpreference
$erroractionpreference = 'stop' # quit if anything goes wrong
if(($PSVersionTable.PSVersion.Major) -lt 5) {
Write-Output "PowerShell 5 or later is required to run Scoop."
Write-Output "Upgrade PowerShell: https://docs.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell"
break
}
# show notification to change execution policy:
if((Get-ExecutionPolicy) -gt 'RemoteSigned' -or (Get-ExecutionPolicy) -eq 'ByPass') {
Write-Output "PowerShell requires an execution policy of 'RemoteSigned' to run Scoop."
Write-Output "To make this change please run:"
Write-Output "'Set-ExecutionPolicy RemoteSigned -scope CurrentUser'"
break
}
if([System.Enum]::GetNames([System.Net.SecurityProtocolType]) -notcontains 'Tls12') {
Write-Output "Scoop requires at least .NET Framework 4.5"
Write-Output "Please download and install it first:"
Write-Output "https://www.microsoft.com/net/download"
break
}
# get core functions
$core_url = 'https://raw.githubusercontent.com/lukesampson/scoop/master/lib/core.ps1'
Write-Output 'Initializing...'
Invoke-Expression (new-object net.webclient).downloadstring($core_url)
# prep
if(installed 'scoop') {
write-host "Scoop is already installed. Run 'scoop update' to get the latest version." -f red
# don't abort if invoked with iex that would close the PS session
if($myinvocation.mycommand.commandtype -eq 'Script') { return } else { exit 1 }
}
$dir = ensure (versiondir 'scoop' 'current')
# download scoop zip
$zipurl = 'https://github.com/lukesampson/scoop/archive/master.zip'
$zipfile = "$dir\scoop.zip"
Write-Output 'Downloading scoop...'
dl $zipurl $zipfile
Write-Output 'Extracting...'
Add-Type -Assembly "System.IO.Compression.FileSystem"
[IO.Compression.ZipFile]::ExtractToDirectory($zipfile,"$dir\_tmp")
Copy-Item "$dir\_tmp\*master\*" $dir -Recurse -Force
Remove-Item "$dir\_tmp", $zipfile -Recurse -Force
Write-Output 'Creating shim...'
shim "$dir\bin\scoop.ps1" $false
# download main bucket
$dir = "$scoopdir\buckets\main"
$zipurl = 'https://github.com/ScoopInstaller/Main/archive/master.zip'
$zipfile = "$dir\main-bucket.zip"
Write-Output 'Downloading main bucket...'
New-Item $dir -Type Directory -Force | Out-Null
dl $zipurl $zipfile
Write-Output 'Extracting...'
[IO.Compression.ZipFile]::ExtractToDirectory($zipfile, "$dir\_tmp")
Copy-Item "$dir\_tmp\*-master\*" $dir -Recurse -Force
Remove-Item "$dir\_tmp", $zipfile -Recurse -Force
ensure_robocopy_in_path
ensure_scoop_in_path
scoop config lastupdate ([System.DateTime]::Now.ToString('o'))
success 'Scoop was installed successfully!'
Write-Output "Type 'scoop help' for instructions."
$erroractionpreference = $old_erroractionpreference # Reset $erroractionpreference to original value
Invoke-RestMethod https://get.scoop.sh | Invoke-Expression

View File

@@ -26,7 +26,7 @@ param(
. "$PSScriptRoot\..\lib\core.ps1"
. "$PSScriptRoot\..\lib\manifest.ps1"
$Dir = Resolve-Path $Dir
$Dir = Convert-Path $Dir
Write-Host '[' -NoNewLine
Write-Host 'C' -NoNewLine -ForegroundColor Green
@@ -36,8 +36,8 @@ Write-Host 'A' -NoNewLine -ForegroundColor Cyan
Write-Host ']utoupdate'
Write-Host ' | |'
Get-ChildItem $Dir "$App.json" | ForEach-Object {
$json = parse_json "$Dir\$($_.Name)"
Get-ChildItem $Dir -Filter "$App.json" -Recurse | ForEach-Object {
$json = parse_json $_.FullName
if ($SkipSupported -and $json.checkver -and $json.autoupdate) { return }
@@ -48,5 +48,5 @@ Get-ChildItem $Dir "$App.json" | ForEach-Object {
Write-Host '[' -NoNewLine
Write-Host $(if ($json.autoupdate) { 'A' } else { ' ' }) -NoNewLine -ForegroundColor Cyan
Write-Host '] ' -NoNewLine
Write-Host (strip_ext $_.Name)
Write-Host $_.BaseName
}

View File

@@ -1,7 +1,7 @@
# for development, update the installed scripts to match local source
. "$psscriptroot\..\lib\core.ps1"
. "$PSScriptRoot\..\lib\core.ps1"
$src = relpath ".."
$src = "$PSScriptRoot\.."
$dest = ensure (versiondir 'scoop' 'current')
# make sure not running from the installed directory
@@ -15,5 +15,4 @@ $output | Where-Object { $_ -ne "" }
Write-Output 'creating shim...'
shim "$dest\bin\scoop.ps1" $false
ensure_scoop_in_path
success 'scoop was refreshed!'

View File

@@ -1,41 +1,53 @@
#requires -v 3
param($cmd)
#Requires -Version 5
Set-StrictMode -Off
set-strictmode -off
. "$PSScriptRoot\..\lib\core.ps1"
. "$PSScriptRoot\..\lib\buckets.ps1"
. "$PSScriptRoot\..\lib\commands.ps1"
. "$PSScriptRoot\..\lib\help.ps1"
. "$psscriptroot\..\lib\core.ps1"
. "$psscriptroot\..\lib\git.ps1"
. "$psscriptroot\..\lib\buckets.ps1"
. (relpath '..\lib\commands')
$subCommand = $Args[0]
reset_aliases
# TODO: remove this in a few weeks
if ((Get-LocalBucket) -notcontains 'main') {
warn "The main bucket of Scoop has been separated to 'https://github.com/ScoopInstaller/Main'"
warn "You don't have the main bucket added, adding main bucket for you..."
add_bucket 'main'
exit
# for aliases where there's a local function, re-alias so the function takes precedence
$aliases = Get-Alias | Where-Object { $_.Options -notmatch 'ReadOnly|AllScope' } | ForEach-Object { $_.Name }
Get-ChildItem Function: | Where-Object -Property Name -In -Value $aliases | ForEach-Object {
Set-Alias -Name $_.Name -Value Local:$($_.Name) -Scope Script
}
$commands = commands
if ('--version' -contains $cmd -or (!$cmd -and '-v' -contains $args)) {
Push-Location $(versiondir 'scoop' 'current')
write-host "Current Scoop version:"
git_log --oneline HEAD -n 1
write-host ""
Pop-Location
Get-LocalBucket | ForEach-Object {
Push-Location (Find-BucketDirectory $_ -Root)
if(test-path '.git') {
write-host "'$_' bucket:"
git_log --oneline HEAD -n 1
write-host ""
switch ($subCommand) {
({ $subCommand -in @($null, '-h', '--help', '/?') }) {
exec 'help'
}
({ $subCommand -in @('-v', '--version') }) {
Write-Host 'Current Scoop version:'
if (Test-GitAvailable -and (Test-Path "$PSScriptRoot\..\.git") -and (get_config SCOOP_BRANCH 'master') -ne 'master') {
Invoke-Git -Path "$PSScriptRoot\.." -ArgumentList @('log', 'HEAD', '-1', '--oneline')
} else {
$version = Select-String -Pattern '^## \[(v[\d.]+)\].*?([\d-]+)$' -Path "$PSScriptRoot\..\CHANGELOG.md"
Write-Host $version.Matches.Groups[1].Value -ForegroundColor Cyan -NoNewline
Write-Host " - Released at $($version.Matches.Groups[2].Value)"
}
Pop-Location
Write-Host ''
Get-LocalBucket | ForEach-Object {
$bucketLoc = Find-BucketDirectory $_ -Root
if (Test-GitAvailable -and (Test-Path "$bucketLoc\.git")) {
Write-Host "'$_' bucket:"
Invoke-Git -Path $bucketLoc -ArgumentList @('log', 'HEAD', '-1', '--oneline')
Write-Host ''
}
}
}
({ $subCommand -in (commands) }) {
[string[]]$arguments = $Args | Select-Object -Skip 1
if ($null -ne $arguments -and $arguments[0] -in @('-h', '--help', '/?')) {
exec 'help' @($subCommand)
} else {
exec $subCommand $arguments
}
}
default {
warn "scoop: '$subCommand' isn't a scoop command. See 'scoop help'."
exit 1
}
}
elseif (@($null, '--help', '/?') -contains $cmd -or $args[0] -contains '-h') { exec 'help' $args }
elseif ($commands -contains $cmd) { exec $cmd $args }
else { "scoop: '$cmd' isn't a scoop command. See 'scoop help'."; exit 1 }

View File

@@ -1 +1 @@
invoke-pester "$psscriptroot\..\test"
. "$PSScriptRoot\..\test\bin\test.ps1"

View File

@@ -12,6 +12,7 @@ param(
)
. "$PSScriptRoot\..\lib\core.ps1"
. "$PSScriptRoot\..\lib\system.ps1"
. "$PSScriptRoot\..\lib\install.ps1"
. "$PSScriptRoot\..\lib\shortcuts.ps1"
. "$PSScriptRoot\..\lib\versions.ps1"
@@ -34,23 +35,23 @@ $errors = $false
# Uninstall given app
function do_uninstall($app, $global) {
$version = current_version $app $global
$version = Select-CurrentVersion -AppName $app -Global:$global
$dir = versiondir $app $version $global
$manifest = installed_manifest $app $version $global
$install = install_info $app $version $global
$architecture = $install.architecture
Write-Output "Uninstalling '$app'"
run_uninstaller $manifest $architecture $dir
rm_shims $manifest $global $architecture
Invoke-Installer -Path $dir -Manifest $manifest -ProcessorArchitecture $architecture -Uninstall
rm_shims $app $manifest $global $architecture
# If a junction was used during install, that will have been used
# as the reference directory. Othewise it will just be the version
# directory.
$refdir = unlink_current (appdir $app $global)
env_rm_path $manifest $refdir $global
env_rm $manifest $global
env_rm_path $manifest $refdir $global $architecture
env_rm $manifest $global $architecture
$appdir = appdir $app $global
try {
@@ -98,7 +99,9 @@ if ($purge) {
if ($global) { keep_onlypersist $globaldir }
}
remove_from_path (shimdir $false)
if ($global) { remove_from_path (shimdir $true) }
Remove-Path -Path (shimdir $global) -Global:$global
if (get_config USE_ISOLATED_PATH) {
Remove-Path -Path ('%' + $scoopPathEnvVar + '%') -Global:$global
}
success 'Scoop has been uninstalled.'

View File

@@ -1,13 +1,12 @@
{
"main": "https://github.com/ScoopInstaller/Main",
"extras": "https://github.com/lukesampson/scoop-extras",
"extras": "https://github.com/ScoopInstaller/Extras",
"versions": "https://github.com/ScoopInstaller/Versions",
"nightlies": "https://github.com/ScoopInstaller/Nightlies",
"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",
"nonportable": "https://github.com/oltolm/scoop-nonportable",
"nonportable": "https://github.com/ScoopInstaller/Nonportable",
"java": "https://github.com/ScoopInstaller/Java",
"games": "https://github.com/Calinou/scoop-games",
"jetbrains": "https://github.com/Ash258/Scoop-JetBrains"
"games": "https://github.com/Calinou/scoop-games"
}

View File

@@ -1,28 +1,34 @@
<#
TODO
- clean up
#>
. "$psscriptroot\..\lib\json.ps1"
# Must included with 'json.ps1'
. "$psscriptroot/core.ps1"
. "$psscriptroot/json.ps1"
function format_hash([String] $hash) {
$hash = $hash.toLower()
switch ($hash.Length) {
32 { $hash = "md5:$hash" } # md5
40 { $hash = "sha1:$hash" } # sha1
64 { $hash = $hash } # sha256
128 { $hash = "sha512:$hash" } # sha512
default { $hash = $null }
}
return $hash
}
function find_hash_in_rdf([String] $url, [String] $basename) {
$data = $null
$xml = $null
try {
# Download and parse RDF XML file
$wc = New-Object Net.Webclient
$wc.Headers.Add('Referer', (strip_filename $url))
$wc.Headers.Add('User-Agent', (Get-UserAgent))
[xml]$data = $wc.downloadstring($url)
} catch [system.net.webexception] {
write-host -f darkred $_
write-host -f darkred "URL $url is not valid"
$data = $wc.DownloadData($url)
[xml]$xml = (Get-Encoding($wc)).GetString($data)
} catch [System.Net.WebException] {
Write-Host $_ -ForegroundColor DarkRed
Write-Host "URL $url is not valid" -ForegroundColor DarkRed
return $null
}
# Find file content
$digest = $data.RDF.Content | Where-Object { [String]$_.about -eq $basename }
$digest = $xml.RDF.Content | Where-Object { [String]$_.about -eq $basename }
return format_hash $digest.sha256
}
@@ -31,40 +37,47 @@ function find_hash_in_textfile([String] $url, [Hashtable] $substitutions, [Strin
$hashfile = $null
$templates = @{
'$md5' = '([a-fA-F0-9]{32})';
'$sha1' = '([a-fA-F0-9]{40})';
'$sha256' = '([a-fA-F0-9]{64})';
'$sha512' = '([a-fA-F0-9]{128})';
'$checksum' = '([a-fA-F0-9]{32,128})';
'$base64' = '([a-zA-Z0-9+\/=]{24,88})';
'$md5' = '([a-fA-F0-9]{32})'
'$sha1' = '([a-fA-F0-9]{40})'
'$sha256' = '([a-fA-F0-9]{64})'
'$sha512' = '([a-fA-F0-9]{128})'
'$checksum' = '([a-fA-F0-9]{32,128})'
'$base64' = '([a-zA-Z0-9+\/=]{24,88})'
}
try {
$wc = New-Object Net.Webclient
$wc.Headers.Add('Referer', (strip_filename $url))
$wc.Headers.Add('User-Agent', (Get-UserAgent))
$hashfile = $wc.downloadstring($url)
$data = $wc.DownloadData($url)
$ms = New-Object System.IO.MemoryStream
$ms.Write($data, 0, $data.Length)
$ms.Seek(0, 0) | Out-Null
if ($data[0] -eq 0x1F -and $data[1] -eq 0x8B) {
$ms = New-Object System.IO.Compression.GZipStream($ms, [System.IO.Compression.CompressionMode]::Decompress)
}
$hashfile = (New-Object System.IO.StreamReader($ms, (Get-Encoding $wc))).ReadToEnd()
} catch [system.net.webexception] {
write-host -f darkred $_
write-host -f darkred "URL $url is not valid"
Write-Host $_ -ForegroundColor DarkRed
Write-Host "URL $url is not valid" -ForegroundColor DarkRed
return
}
if ($regex.Length -eq 0) {
$regex = '^([a-fA-F0-9]+)$'
$regex = '^\s*([a-fA-F0-9]+)\s*$'
}
$regex = substitute $regex $templates $false
$regex = substitute $regex $substitutions $true
debug $regex
if ($hashfile -match $regex) {
$hash = $matches[1] -replace ' ',''
debug $regex
$hash = $matches[1] -replace '\s', ''
}
# convert base64 encoded hash values
if ($hash -match '^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})$') {
$base64 = $matches[0]
if(!($hash -match '^[a-fA-F0-9]+$') -and $hash.length -notin @(32, 40, 64, 128)) {
if (!($hash -match '^[a-fA-F0-9]+$') -and $hash.Length -notin @(32, 40, 64, 128)) {
try {
$hash = ([System.Convert]::FromBase64String($base64) | ForEach-Object { $_.ToString('x2') }) -join ''
} catch {
@@ -75,13 +88,15 @@ function find_hash_in_textfile([String] $url, [Hashtable] $substitutions, [Strin
# find hash with filename in $hashfile
if ($hash.Length -eq 0) {
$filenameRegex = "([a-fA-F0-9]{32,128})[\x20\t]+.*`$basename(?:[\x20\t]+\d+)?"
$filenameRegex = "([a-fA-F0-9]{32,128})[\x20\t]+.*`$basename(?:\s|$)|`$basename[\x20\t]+.*?([a-fA-F0-9]{32,128})"
$filenameRegex = substitute $filenameRegex $substitutions $true
if ($hashfile -match $filenameRegex) {
debug $filenameRegex
$hash = $matches[1]
}
$metalinkRegex = "<hash[^>]+>([a-fA-F0-9]{64})"
$metalinkRegex = '<hash[^>]+>([a-fA-F0-9]{64})'
if ($hashfile -match $metalinkRegex) {
debug $metalinkRegex
$hash = $matches[1]
}
}
@@ -96,19 +111,68 @@ function find_hash_in_json([String] $url, [Hashtable] $substitutions, [String] $
$wc = New-Object Net.Webclient
$wc.Headers.Add('Referer', (strip_filename $url))
$wc.Headers.Add('User-Agent', (Get-UserAgent))
$json = $wc.downloadstring($url)
} catch [system.net.webexception] {
write-host -f darkred $_
write-host -f darkred "URL $url is not valid"
$data = $wc.DownloadData($url)
$ms = New-Object System.IO.MemoryStream
$ms.Write($data, 0, $data.Length)
$ms.Seek(0, 0) | Out-Null
if ($data[0] -eq 0x1F -and $data[1] -eq 0x8B) {
$ms = New-Object System.IO.Compression.GZipStream($ms, [System.IO.Compression.CompressionMode]::Decompress)
}
$json = (New-Object System.IO.StreamReader($ms, (Get-Encoding $wc))).ReadToEnd()
} catch [System.Net.WebException] {
Write-Host $_ -ForegroundColor DarkRed
Write-Host "URL $url is not valid" -ForegroundColor DarkRed
return
}
debug $jsonpath
$hash = json_path $json $jsonpath $substitutions
if(!$hash) {
if (!$hash) {
$hash = json_path_legacy $json $jsonpath $substitutions
}
return format_hash $hash
}
function find_hash_in_xml([String] $url, [Hashtable] $substitutions, [String] $xpath) {
$xml = $null
try {
$wc = New-Object Net.Webclient
$wc.Headers.Add('Referer', (strip_filename $url))
$wc.Headers.Add('User-Agent', (Get-UserAgent))
$data = $wc.DownloadData($url)
$ms = New-Object System.IO.MemoryStream
$ms.Write($data, 0, $data.Length)
$ms.Seek(0, 0) | Out-Null
if ($data[0] -eq 0x1F -and $data[1] -eq 0x8B) {
$ms = New-Object System.IO.Compression.GZipStream($ms, [System.IO.Compression.CompressionMode]::Decompress)
}
$xml = [xml]((New-Object System.IO.StreamReader($ms, (Get-Encoding $wc))).ReadToEnd())
} catch [system.net.webexception] {
Write-Host $_ -ForegroundColor DarkRed
Write-Host "URL $url is not valid" -ForegroundColor DarkRed
return
}
# Replace placeholders
if ($substitutions) {
$xpath = substitute $xpath $substitutions
}
# Find all `significant namespace declarations` from the XML file
$nsList = $xml.SelectNodes('//namespace::*[not(. = ../../namespace::*)]')
# Then add them into the NamespaceManager
$nsmgr = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
$nsList | ForEach-Object {
$nsmgr.AddNamespace($_.LocalName, $_.Value)
}
debug $xpath
debug $nsmgr
# Getting hash from XML, using XPath
$hash = $xml.SelectSingleNode($xpath, $nsmgr).'#text'
return format_hash $hash
}
function find_hash_in_headers([String] $url) {
$hash = $null
@@ -120,16 +184,16 @@ function find_hash_in_headers([String] $url) {
$req.Timeout = 2000
$req.Method = 'HEAD'
$res = $req.GetResponse()
if(([int]$response.StatusCode -ge 300) -and ([int]$response.StatusCode -lt 400)) {
if($res.Headers['Digest'] -match 'SHA-256=([^,]+)' -or $res.Headers['Digest'] -match 'SHA=([^,]+)' -or $res.Headers['Digest'] -match 'MD5=([^,]+)') {
if (([int]$res.StatusCode -ge 300) -and ([int]$res.StatusCode -lt 400)) {
if ($res.Headers['Digest'] -match 'SHA-256=([^,]+)' -or $res.Headers['Digest'] -match 'SHA=([^,]+)' -or $res.Headers['Digest'] -match 'MD5=([^,]+)') {
$hash = ([System.Convert]::FromBase64String($matches[1]) | ForEach-Object { $_.ToString('x2') }) -join ''
debug $hash
}
}
$res.Close()
} catch [system.net.webexception] {
write-host -f darkred $_
write-host -f darkred "URL $url is not valid"
} catch [System.Net.WebException] {
Write-Host $_ -ForegroundColor DarkRed
Write-Host "URL $url is not valid" -ForegroundColor DarkRed
return
}
@@ -140,21 +204,24 @@ function get_hash_for_app([String] $app, $config, [String] $version, [String] $u
$hash = $null
$hashmode = $config.mode
$basename = url_remote_filename($url)
$basename = [System.Web.HttpUtility]::UrlDecode((url_remote_filename($url)))
$substitutions = $substitutions.Clone()
$substitutions.Add('$url', (strip_fragment $url))
$substitutions.Add('$baseurl', (strip_filename (strip_fragment $url)).TrimEnd('/'))
$substitutions.Add('$basename', $basename)
$substitutions.Add('$urlNoExt', (strip_ext (strip_fragment $url)))
$substitutions.Add('$basenameNoExt', (strip_ext $basename))
debug $substitutions
$hashfile_url = substitute $config.url $substitutions
debug $hashfile_url
if ($hashfile_url) {
write-host -f DarkYellow 'Searching hash for ' -NoNewline
write-host -f Green $basename -NoNewline
write-host -f DarkYellow ' in ' -NoNewline
write-host -f Green $hashfile_url
Write-Host 'Searching hash for ' -ForegroundColor DarkYellow -NoNewline
Write-Host $basename -ForegroundColor Green -NoNewline
Write-Host ' in ' -ForegroundColor DarkYellow -NoNewline
Write-Host $hashfile_url -ForegroundColor Green
}
if ($hashmode.Length -eq 0 -and $config.url.Length -ne 0) {
@@ -178,11 +245,17 @@ function get_hash_for_app([String] $app, $config, [String] $version, [String] $u
$regex = $config.regex
}
if (!$hashfile_url -and $url -match "^(?:.*fosshub.com\/).*(?:\/|\?dwl=)(?<filename>.*)$") {
$xpath = ''
if ($config.xpath) {
$xpath = $config.xpath
$hashmode = 'xpath'
}
if (!$hashfile_url -and $url -match '^(?:.*fosshub.com\/).*(?:\/|\?dwl=)(?<filename>.*)$') {
$hashmode = 'fosshub'
}
if (!$hashfile_url -and $url -match "(?:downloads\.)?sourceforge.net\/projects?\/(?<project>[^\/]+)\/(?:files\/)?(?<file>.*)") {
if (!$hashfile_url -and $url -match '(?:downloads\.)?sourceforge.net\/projects?\/(?<project>[^\/]+)\/(?:files\/)?(?<file>.*)') {
$hashmode = 'sourceforge'
}
@@ -193,6 +266,9 @@ function get_hash_for_app([String] $app, $config, [String] $version, [String] $u
'json' {
$hash = find_hash_in_json $hashfile_url $substitutions $jsonpath
}
'xpath' {
$hash = find_hash_in_xml $hashfile_url $substitutions $xpath
}
'rdf' {
$hash = find_hash_in_rdf $hashfile_url $basename
}
@@ -203,190 +279,338 @@ function get_hash_for_app([String] $app, $config, [String] $version, [String] $u
}
}
'fosshub' {
$hash = find_hash_in_textfile $url $substitutions ($Matches.filename+'.*?"sha256":"([a-fA-F0-9]{64})"')
$hash = find_hash_in_textfile $url $substitutions ($matches.filename + '.*?"sha256":"([a-fA-F0-9]{64})"')
}
'sourceforge' {
# change the URL because downloads.sourceforge.net doesn't have checksums
$hashfile_url = (strip_filename (strip_fragment "https://sourceforge.net/projects/$($matches['project'])/files/$($matches['file'])")).TrimEnd('/')
$hash = find_hash_in_textfile $hashfile_url $substitutions '"$basename":.*?"sha1":\s"([a-fA-F0-9]{40})"'
$hash = find_hash_in_textfile $hashfile_url $substitutions '"$basename":.*?"sha1":\s*"([a-fA-F0-9]{40})"'
}
}
if ($hash) {
# got one!
write-host -f DarkYellow 'Found: ' -NoNewline
write-host -f Green $hash -NoNewline
write-host -f DarkYellow ' using ' -NoNewline
write-host -f Green "$((Get-Culture).TextInfo.ToTitleCase($hashmode)) Mode"
Write-Host 'Found: ' -ForegroundColor DarkYellow -NoNewline
Write-Host $hash -ForegroundColor Green -NoNewline
Write-Host ' using ' -ForegroundColor DarkYellow -NoNewline
Write-Host "$((Get-Culture).TextInfo.ToTitleCase($hashmode)) Mode" -ForegroundColor Green
return $hash
} elseif ($hashfile_url) {
write-host -f DarkYellow "Could not find hash in $hashfile_url"
Write-Host -f DarkYellow "Could not find hash in $hashfile_url"
}
write-host -f DarkYellow 'Downloading ' -NoNewline
write-host -f Green $basename -NoNewline
write-host -f DarkYellow ' to compute hashes!'
Write-Host 'Downloading ' -ForegroundColor DarkYellow -NoNewline
Write-Host $basename -ForegroundColor Green -NoNewline
Write-Host ' to compute hashes!' -ForegroundColor DarkYellow
try {
dl_with_cache $app $version $url $null $null $true
Invoke-CachedDownload $app $version $url $null $null $true
} catch [system.net.webexception] {
write-host -f darkred $_
write-host -f darkred "URL $url is not valid"
Write-Host $_ -ForegroundColor DarkRed
Write-Host "URL $url is not valid" -ForegroundColor DarkRed
return $null
}
$file = fullpath (cache_path $app $version $url)
$hash = compute_hash $file 'sha256'
write-host -f DarkYellow 'Computed hash: ' -NoNewline
write-host -f Green $hash
$file = cache_path $app $version $url
$hash = (Get-FileHash -Path $file -Algorithm SHA256).Hash.ToLower()
Write-Host 'Computed hash: ' -ForegroundColor DarkYellow -NoNewline
Write-Host $hash -ForegroundColor Green
return $hash
}
function update_manifest_with_new_version($json, [String] $version, [String] $url, [String] $hash, $architecture = $null) {
$json.version = $version
if ($null -eq $architecture) {
if ($json.url -is [System.Array]) {
$json.url[0] = $url
$json.hash[0] = $hash
} else {
$json.url = $url
$json.hash = $hash
}
} else {
# If there are multiple urls we replace the first one
if ($json.architecture.$architecture.url -is [System.Array]) {
$json.architecture.$architecture.url[0] = $url
$json.architecture.$architecture.hash[0] = $hash
} else {
$json.architecture.$architecture.url = $url
$json.architecture.$architecture.hash = $hash
}
function Update-ManifestProperty {
<#
.SYNOPSIS
Update propert(y|ies) in manifest
.DESCRIPTION
Update selected propert(y|ies) to given version in manifest.
.PARAMETER Manifest
Manifest to be updated
.PARAMETER Property
Selected propert(y|ies) to be updated
.PARAMETER AppName
Software name
.PARAMETER Version
Given software version
.PARAMETER Substitutions
Hashtable of internal substitutable variables
.OUTPUTS
System.Boolean
Flag that indicate if there are any changed properties
#>
[CmdletBinding(SupportsShouldProcess = $true)]
[OutputType([Boolean])]
param (
[Parameter(Mandatory = $true, Position = 1)]
[PSCustomObject]
$Manifest,
[Parameter(ValueFromPipeline = $true, Position = 2)]
[String[]]
$Property,
[String]
$AppName,
[String]
$Version,
[Alias('Matches')]
[HashTable]
$Substitutions
)
begin {
$hasManifestChanged = $false
}
}
function update_manifest_prop([String] $prop, $json, [Hashtable] $substitutions) {
# first try the global property
if ($json.$prop -and $json.autoupdate.$prop) {
$json.$prop = substitute $json.autoupdate.$prop $substitutions
}
# check if there are architecture specific variants
if ($json.architecture -and $json.autoupdate.architecture) {
$json.architecture | Get-Member -MemberType NoteProperty | ForEach-Object {
$architecture = $_.Name
if ($json.architecture.$architecture.$prop -and $json.autoupdate.architecture.$architecture.$prop) {
$json.architecture.$architecture.$prop = substitute (arch_specific $prop $json.autoupdate $architecture) $substitutions
process {
foreach ($currentProperty in $Property) {
if ($currentProperty -eq 'hash') {
# Update hash
if ($Manifest.hash) {
# Global
$newURL = substitute $Manifest.autoupdate.url $Substitutions
$newHash = HashHelper -AppName $AppName -Version $Version -HashExtraction $Manifest.autoupdate.hash -URL $newURL -Substitutions $Substitutions
$Manifest.hash, $hasPropertyChanged = PropertyHelper -Property $Manifest.hash -Value $newHash
$hasManifestChanged = $hasManifestChanged -or $hasPropertyChanged
} else {
# Arch-spec
$Manifest.architecture | Get-Member -MemberType NoteProperty | ForEach-Object {
$arch = $_.Name
$newURL = substitute (arch_specific 'url' $Manifest.autoupdate $arch) $Substitutions
$newHash = HashHelper -AppName $AppName -Version $Version -HashExtraction (arch_specific 'hash' $Manifest.autoupdate $arch) -URL $newURL -Substitutions $Substitutions
$Manifest.architecture.$arch.hash, $hasPropertyChanged = PropertyHelper -Property $Manifest.architecture.$arch.hash -Value $newHash
$hasManifestChanged = $hasManifestChanged -or $hasPropertyChanged
}
}
} elseif ($Manifest.$currentProperty -and $Manifest.autoupdate.$currentProperty) {
# Update other property (global)
$autoupdateProperty = $Manifest.autoupdate.$currentProperty
$newValue = substitute $autoupdateProperty $Substitutions
if (($autoupdateProperty.GetType().Name -eq 'Object[]') -and ($autoupdateProperty.Length -eq 1)) {
# Make sure it's an array
$newValue = , $newValue
}
$Manifest.$currentProperty, $hasPropertyChanged = PropertyHelper -Property $Manifest.$currentProperty -Value $newValue
$hasManifestChanged = $hasManifestChanged -or $hasPropertyChanged
} elseif ($Manifest.architecture) {
# Update other property (arch-spec)
$Manifest.architecture | Get-Member -MemberType NoteProperty | ForEach-Object {
$arch = $_.Name
if ($Manifest.architecture.$arch.$currentProperty -and ($Manifest.autoupdate.architecture.$arch.$currentProperty -or $Manifest.autoupdate.$currentProperty)) {
$autoupdateProperty = @(arch_specific $currentProperty $Manifest.autoupdate $arch)
$newValue = substitute $autoupdateProperty $Substitutions
if (($autoupdateProperty.GetType().Name -eq 'Object[]') -and ($autoupdateProperty.Length -eq 1)) {
# Make sure it's an array
$newValue = , $newValue
}
$Manifest.architecture.$arch.$currentProperty, $hasPropertyChanged = PropertyHelper -Property $Manifest.architecture.$arch.$currentProperty -Value $newValue
$hasManifestChanged = $hasManifestChanged -or $hasPropertyChanged
}
}
}
}
}
end {
if ($Version -ne '' -and $Manifest.version -ne $Version) {
$Manifest.version = $Version
$hasManifestChanged = $true
}
return $hasManifestChanged
}
}
function get_version_substitutions([String] $version, [Hashtable] $customMatches) {
$firstPart = $version.Split('-') | Select-Object -first 1
$lastPart = $version.Split('-') | Select-Object -last 1
function Get-VersionSubstitution {
param (
[String]
$Version,
[Hashtable]
$CustomMatches
)
$firstPart = $Version.Split('-') | Select-Object -First 1
$lastPart = $Version.Split('-') | Select-Object -Last 1
$versionVariables = @{
'$version' = $version;
'$underscoreVersion' = ($version -replace "\.", "_");
'$dashVersion' = ($version -replace "\.", "-");
'$cleanVersion' = ($version -replace "\.", "");
'$majorVersion' = $firstPart.Split('.') | Select-Object -first 1;
'$minorVersion' = $firstPart.Split('.') | Select-Object -skip 1 -first 1;
'$patchVersion' = $firstPart.Split('.') | Select-Object -skip 2 -first 1;
'$buildVersion' = $firstPart.Split('.') | Select-Object -skip 3 -first 1;
'$preReleaseVersion' = $lastPart;
'$version' = $Version
'$dotVersion' = ($Version -replace '[._-]', '.')
'$underscoreVersion' = ($Version -replace '[._-]', '_')
'$dashVersion' = ($Version -replace '[._-]', '-')
'$cleanVersion' = ($Version -replace '[._-]', '')
'$majorVersion' = $firstPart.Split('.') | Select-Object -First 1
'$minorVersion' = $firstPart.Split('.') | Select-Object -Skip 1 -First 1
'$patchVersion' = $firstPart.Split('.') | Select-Object -Skip 2 -First 1
'$buildVersion' = $firstPart.Split('.') | Select-Object -Skip 3 -First 1
'$preReleaseVersion' = $lastPart
}
if($version -match "(?<head>\d+\.\d+(?:\.\d+)?)(?<tail>.*)") {
$versionVariables.Set_Item('$matchHead', $matches['head'])
$versionVariables.Set_Item('$matchTail', $matches['tail'])
if ($Version -match '(?<head>\d+\.\d+(?:\.\d+)?)(?<tail>.*)') {
$versionVariables.Add('$matchHead', $Matches['head'])
$versionVariables.Add('$matchTail', $Matches['tail'])
}
if($customMatches) {
$customMatches.GetEnumerator() | ForEach-Object {
if($_.Name -ne "0") {
$versionVariables.Set_Item('$match' + (Get-Culture).TextInfo.ToTitleCase($_.Name), $_.Value)
if ($CustomMatches) {
$CustomMatches.GetEnumerator() | ForEach-Object {
if ($_.Name -ne '0') {
$versionVariables.Add('$match' + (Get-Culture).TextInfo.ToTitleCase($_.Name), $_.Value)
}
}
}
return $versionVariables
}
function autoupdate([String] $app, $dir, $json, [String] $version, [Hashtable] $matches) {
Write-Host -f DarkCyan "Autoupdating $app"
$has_changes = $false
$has_errors = $false
[Bool]$valid = $true
$substitutions = get_version_substitutions $version $matches
function Invoke-AutoUpdate {
param (
[String]
$AppName,
[String]
$Path,
[PSObject]
$Manifest,
[String]
$Version,
[Hashtable]
$CustomMatches
)
if ($json.url) {
# create new url
$url = substitute $json.autoupdate.url $substitutions
$valid = $true
if($valid) {
# create hash
$hash = get_hash_for_app $app $json.autoupdate.hash $version $url $substitutions
if ($null -eq $hash) {
$valid = $false
Write-Host -f DarkRed "Could not find hash!"
}
}
# write changes to the json object
if ($valid) {
$has_changes = $true
update_manifest_with_new_version $json $version $url $hash
} else {
$has_errors = $true
throw "Could not update $app"
}
} else {
$json.architecture | Get-Member -MemberType NoteProperty | ForEach-Object {
$valid = $true
$architecture = $_.Name
# create new url
$url = substitute (arch_specific "url" $json.autoupdate $architecture) $substitutions
$valid = $true
if($valid) {
# create hash
$hash = get_hash_for_app $app (arch_specific "hash" $json.autoupdate $architecture) $version $url $substitutions
if ($null -eq $hash) {
$valid = $false
Write-Host -f DarkRed "Could not find hash!"
}
}
# write changes to the json object
if ($valid) {
$has_changes = $true
update_manifest_with_new_version $json $version $url $hash $architecture
} else {
$has_errors = $true
throw "Could not update $app $architecture"
}
}
}
Write-Host "Autoupdating $AppName" -ForegroundColor DarkCyan
$substitutions = Get-VersionSubstitution $Version $CustomMatches
# update properties
update_manifest_prop "extract_dir" $json $substitutions
$updatedProperties = @(@($Manifest.autoupdate.PSObject.Properties.Name) -ne 'architecture')
if ($Manifest.autoupdate.architecture) {
$updatedProperties += $Manifest.autoupdate.architecture.PSObject.Properties | ForEach-Object { $_.Value.PSObject.Properties.Name }
}
if ($updatedProperties -contains 'url') {
$updatedProperties += 'hash'
}
$updatedProperties = $updatedProperties | Select-Object -Unique
debug [$updatedProperties]
$hasChanged = Update-ManifestProperty -Manifest $Manifest -Property $updatedProperties -AppName $AppName -Version $Version -Substitutions $substitutions
# update license
update_manifest_prop "license" $json $substitutions
if ($has_changes -and !$has_errors) {
if ($hasChanged) {
# write file
Write-Host -f DarkGreen "Writing updated $app manifest"
$path = join-path $dir "$app.json"
$file_content = $json | ConvertToPrettyJson
[System.IO.File]::WriteAllLines($path, $file_content)
Write-Host "Writing updated $AppName manifest" -ForegroundColor DarkGreen
# Accept unusual Unicode characters
# 'Set-Content -Encoding ASCII' don't works in PowerShell 5
# Wait for 'UTF8NoBOM' Encoding in PowerShell 7
# $Manifest | ConvertToPrettyJson | Set-Content -Path (Join-Path $Path "$AppName.json") -Encoding UTF8NoBOM
[System.IO.File]::WriteAllLines($Path, (ConvertToPrettyJson $Manifest))
# notes
if ($json.autoupdate.note) {
Write-Host ""
Write-Host -f DarkYellow $json.autoupdate.note
$note = "`nUpdating note:"
if ($Manifest.autoupdate.note) {
$note += "`nno-arch: $($Manifest.autoupdate.note)"
$hasNote = $true
}
if ($Manifest.autoupdate.architecture) {
'64bit', '32bit', 'arm64' | ForEach-Object {
if ($Manifest.autoupdate.architecture.$_.note) {
$note += "`n$_-arch: $($Manifest.autoupdate.architecture.$_.note)"
$hasNote = $true
}
}
}
if ($hasNote) {
Write-Host $note -ForegroundColor DarkYellow
}
} else {
Write-Host -f DarkGray "No updates for $app"
# This if-else branch may not be in use.
Write-Host "No updates for $AppName" -ForegroundColor DarkGray
}
}
## Helper Functions
function PropertyHelper {
<#
.SYNOPSIS
Helper of updating property
.DESCRIPTION
Update manifest property (String, Array or PSCustomObject).
.PARAMETER Property
Property to be updated
.PARAMETER Value
New property values
Update line by line
.OUTPUTS
System.Object[]
The first element is new property, the second element is change flag
#>
param (
[Object]$Property,
[Object]$Value
)
$hasChanged = $false
if (@($Property).Length -lt @($Value).Length) {
$Property = $Value
$hasChanged = $true
} else {
switch ($Property.GetType().Name) {
'String' {
$Value = $Value -as [String]
if ($null -ne $Value) {
$Property = $Value
$hasChanged = $true
}
}
'Object[]' {
$Value = @($Value)
for ($i = 0; $i -lt $Value.Length; $i++) {
$Property[$i], $hasItemChanged = PropertyHelper -Property $Property[$i] -Value $Value[$i]
$hasChanged = $hasChanged -or $hasItemChanged
}
}
'PSCustomObject' {
if ($Value -is [PSObject]) {
foreach ($name in $Property.PSObject.Properties.Name) {
if ($Value.$name) {
$Property.$name, $hasItemChanged = PropertyHelper -Property $Property.$name -Value $Value.$name
$hasChanged = $hasChanged -or $hasItemChanged
}
}
}
}
}
}
return $Property, $hasChanged
}
function HashHelper {
<#
.SYNOPSIS
Helper of getting file hash(es)
.DESCRIPTION
Extract or calculate file hash(es).
If hash extraction templates are less then URLs, the last template will be reused for the rest URLs.
.PARAMETER AppName
Software name
.PARAMETER Version
Given software version
.PARAMETER HashExtraction
Hash extraction template(s)
.PARAMETER URL
New download URL(s), used to calculate hash locally (fallback)
.PARAMETER Substitutions
Hashtable of internal substitutable variables
.OUTPUTS
System.String
Hash value (single URL)
System.String[]
Hash values (multi URLs)
#>
param (
[String]
$AppName,
[String]
$Version,
[PSObject[]]
$HashExtraction,
[String[]]
$URL,
[HashTable]
$Substitutions
)
$hash = @()
for ($i = 0; $i -lt $URL.Length; $i++) {
if ($null -eq $HashExtraction) {
$currentHashExtraction = $null
} else {
$currentHashExtraction = $HashExtraction[$i], $HashExtraction[-1] | Select-Object -First 1
}
$hash += get_hash_for_app $AppName $currentHashExtraction $Version $URL[$i] $Substitutions
if ($null -eq $hash[$i]) {
throw "Could not update $AppName, hash for $(url_remote_filename $URL[$i]) failed!"
}
}
return $hash
}

View File

@@ -1,5 +1,3 @@
. "$PSScriptRoot\core.ps1"
$bucketsdir = "$scoopdir\buckets"
function Find-BucketDirectory {
@@ -18,7 +16,9 @@ function Find-BucketDirectory {
)
# Handle info passing empty string as bucket ($install.bucket)
if(($null -eq $Name) -or ($Name -eq '')) { $Name = 'main' }
if (($null -eq $Name) -or ($Name -eq '')) {
$Name = 'main'
}
$bucket = "$bucketsdir\$Name"
if ((Test-Path "$bucket\bucket") -and !$Root) {
@@ -37,7 +37,7 @@ function bucketdir($name) {
function known_bucket_repos {
$json = "$PSScriptRoot\..\buckets.json"
return Get-Content $json -raw | convertfrom-json -ea stop
return Get-Content $json -Raw | ConvertFrom-Json -ErrorAction stop
}
function known_bucket_repo($name) {
@@ -46,11 +46,11 @@ function known_bucket_repo($name) {
}
function known_buckets {
known_bucket_repos | ForEach-Object { $_.psobject.properties | Select-Object -expand 'name' }
known_bucket_repos | ForEach-Object { $_.PSObject.Properties | Select-Object -Expand 'name' }
}
function apps_in_bucket($dir) {
return Get-ChildItem $dir | Where-Object { $_.Name.endswith('.json') } | ForEach-Object { $_.Name -replace '.json$', '' }
return (Get-ChildItem $dir -Filter '*.json' -Recurse).BaseName
}
function Get-LocalBucket {
@@ -58,8 +58,20 @@ function Get-LocalBucket {
.SYNOPSIS
List all local buckets.
#>
return (Get-ChildItem $bucketsdir).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
}
}
function buckets {
@@ -68,76 +80,126 @@ function buckets {
return Get-LocalBucket
}
function find_manifest($app, $bucket) {
if ($bucket) {
$manifest = manifest $app $bucket
if ($manifest) { return $manifest, $bucket }
return $null
}
function Convert-RepositoryUri {
[CmdletBinding()]
param (
[Parameter(Mandatory, Position = 0, ValueFromPipeline = $true)]
[AllowEmptyString()]
[String] $Uri
)
foreach($bucket in Get-LocalBucket) {
$manifest = manifest $app $bucket
if($manifest) { return $manifest, $bucket }
process {
# https://git-scm.com/docs/git-clone#_git_urls
# https://regex101.com/r/xGmwRr/1
if ($Uri -match '(?:@|/{1,3})(?:www\.|.*@)?(?<provider>[^/]+?)(?::\d+)?[:/](?<user>.+)/(?<repo>.+?)(?:\.git)?/?$') {
$Matches.provider, $Matches.user, $Matches.repo -join '/'
} else {
error "$Uri is not a valid Git URL!"
error "Please see https://git-scm.com/docs/git-clone#_git_urls for valid ones."
return $null
}
}
}
function list_buckets {
$buckets = @()
Get-LocalBucket | ForEach-Object {
$bucket = [Ordered]@{ Name = $_ }
$path = Find-BucketDirectory $_ -Root
if ((Test-Path (Join-Path $path '.git')) -and (Get-Command git -ErrorAction SilentlyContinue)) {
$bucket.Source = Invoke-Git -Path $path -ArgumentList @('config', 'remote.origin.url')
$bucket.Updated = Invoke-Git -Path $path -ArgumentList @('log', '--format=%aD', '-n', '1') | Get-Date
} else {
$bucket.Source = friendly_path $path
$bucket.Updated = (Get-Item "$path\bucket" -ErrorAction SilentlyContinue).LastWriteTime
}
$bucket.Manifests = Get-ChildItem "$path\bucket" -Force -Recurse -ErrorAction SilentlyContinue |
Measure-Object | Select-Object -ExpandProperty Count
$buckets += [PSCustomObject]$bucket
}
,$buckets
}
function add_bucket($name, $repo) {
if (!$name) { "<name> missing"; $usage_add; exit 1 }
if (!$repo) {
$repo = known_bucket_repo $name
if (!$repo) { "Unknown bucket '$name'. Try specifying <repo>."; $usage_add; exit 1 }
}
if (!(Test-CommandAvailable git)) {
abort "Git is required for buckets. Run 'scoop install git' and try again."
if (!(Test-GitAvailable)) {
error "Git is required for buckets. Run 'scoop install git' and try again."
return 1
}
$dir = Find-BucketDirectory $name -Root
if (test-path $dir) {
warn "The '$name' bucket already exists. Use 'scoop bucket rm $name' to remove it."
exit 0
if (Test-Path $dir) {
warn "The '$name' bucket already exists. To add this bucket again, first remove it by running 'scoop bucket rm $name'."
return 2
}
write-host 'Checking repo... ' -nonewline
$out = git_ls_remote $repo 2>&1
if ($lastexitcode -ne 0) {
abort "'$repo' doesn't look like a valid git repository`n`nError given:`n$out"
$uni_repo = Convert-RepositoryUri -Uri $repo
if ($null -eq $uni_repo) {
return 1
}
foreach ($bucket in Get-LocalBucket) {
if (Test-Path -Path "$bucketsdir\$bucket\.git") {
$remote = Invoke-Git -Path "$bucketsdir\$bucket" -ArgumentList @('config', '--get', 'remote.origin.url')
if ((Convert-RepositoryUri -Uri $remote) -eq $uni_repo) {
warn "Bucket $bucket already exists for $repo"
return 2
}
}
}
write-host 'ok'
ensure $bucketsdir > $null
Write-Host 'Checking repo... ' -NoNewline
$out = Invoke-Git -ArgumentList @('ls-remote', $repo) 2>&1
if ($LASTEXITCODE -ne 0) {
error "'$repo' doesn't look like a valid git repository`n`nError given:`n$out"
return 1
}
ensure $bucketsdir | Out-Null
$dir = ensure $dir
git_clone "$repo" "`"$dir`"" -q
$out = Invoke-Git -ArgumentList @('clone', $repo, $dir, '-q')
if ($LASTEXITCODE -ne 0) {
error "Failed to clone '$repo' to '$dir'.`n`nError given:`n$out`n`nPlease check the repository URL or network connection and try again."
Remove-Item $dir -Recurse -Force -ErrorAction SilentlyContinue
return 1
}
Write-Host 'OK'
if (get_config USE_SQLITE_CACHE) {
info 'Updating cache...'
Set-ScoopDB -Path (Get-ChildItem (Find-BucketDirectory $name) -Filter '*.json' -Recurse).FullName
}
success "The $name bucket was added successfully."
return 0
}
function rm_bucket($name) {
if (!$name) { "<name> missing"; $usage_rm; exit 1 }
$dir = Find-BucketDirectory $name -Root
if (!(test-path $dir)) {
abort "'$name' bucket not found."
if (!(Test-Path $dir)) {
error "'$name' bucket not found."
return 1
}
Remove-Item $dir -r -force -ea stop
Remove-Item $dir -Recurse -Force -ErrorAction Stop
if (get_config USE_SQLITE_CACHE) {
info 'Updating cache...'
Remove-ScoopDBItem -Bucket $name
}
success "The $name bucket was removed successfully."
return 0
}
function new_issue_msg($app, $bucket, $title, $body) {
$app, $manifest, $bucket, $url = Find-Manifest $app $bucket
$app, $manifest, $bucket, $url = Get-Manifest "$bucket/$app"
$url = known_bucket_repo $bucket
$bucket_path = "$bucketsdir\$bucket"
if (Test-path $bucket_path) {
Push-Location $bucket_path
$remote = git_config --get remote.origin.url
if (Test-Path $bucket_path) {
$remote = Invoke-Git -Path $bucket_path -ArgumentList @('config', '--get', 'remote.origin.url')
# Support ssh and http syntax
# git@PROVIDER:USER/REPO.git
# https://PROVIDER/USER/REPO.git
$remote -match '(@|:\/\/)(?<provider>.+)[:/](?<user>.*)\/(?<repo>.*)(\.git)?$' | Out-Null
$url = "https://$($Matches.Provider)/$($Matches.User)/$($Matches.Repo)"
Pop-Location
}
if(!$url) { return 'Please contact the bucket maintainer!' }
if (!$url) { return 'Please contact the bucket maintainer!' }
# Print only github repositories
if ($url -like '*github*') {
@@ -145,7 +207,7 @@ function new_issue_msg($app, $bucket, $title, $body) {
$body = [System.Web.HttpUtility]::UrlEncode($body)
$url = $url -replace '\.git$', ''
$url = "$url/issues/new?title=$title"
if($body) {
if ($body) {
$url += "&body=$body"
}
}

View File

@@ -1,7 +1,10 @@
# Description: Functions for managing commands and aliases.
## Functions for commands
function command_files {
(Get-ChildItem (relpath '..\libexec')) `
+ (Get-ChildItem "$scoopdir\shims") `
| Where-Object { $_.name -match 'scoop-.*?\.ps1$' }
(Get-ChildItem "$PSScriptRoot\..\libexec") + (Get-ChildItem "$scoopdir\shims") |
Where-Object 'scoop-.*?\.ps1$' -Property Name -Match
}
function commands {
@@ -13,18 +16,17 @@ function command_name($filename) {
}
function command_path($cmd) {
$cmd_path = relpath "..\libexec\scoop-$cmd.ps1"
$cmd_path = "$PSScriptRoot\..\libexec\scoop-$cmd.ps1"
# built in commands
if (!(Test-Path $cmd_path)) {
# get path from shim
$shim_path = "$scoopdir\shims\scoop-$cmd.ps1"
$line = ((Get-Content $shim_path) | Where-Object { $_.startswith('$path') })
if($line) {
Invoke-Expression -command "$line"
if ($line) {
Invoke-Command ([scriptblock]::Create($line)) -NoNewScope
$cmd_path = $path
}
else { $cmd_path = $shim_path }
} else { $cmd_path = $shim_path }
}
$cmd_path
@@ -35,3 +37,92 @@ function exec($cmd, $arguments) {
& $cmd_path @arguments
}
## Functions for aliases
function add_alias {
param(
[ValidateNotNullOrEmpty()]
[string]$name,
[ValidateNotNullOrEmpty()]
[string]$command,
[string]$description
)
$aliases = get_config ALIAS ([PSCustomObject]@{})
if ($aliases.$name) {
abort "Alias '$name' already exists."
}
$alias_script_name = "scoop-$name"
$shimdir = shimdir $false
if (Test-Path "$shimdir\$alias_script_name.ps1") {
abort "File '$alias_script_name.ps1' already exists in shims directory."
}
$script = @(
"# Summary: $description",
"$command"
) -join "`n"
try {
$script | Out-UTF8File "$shimdir\$alias_script_name.ps1"
} catch {
abort $_.Exception
}
# Add the new alias to the config.
$aliases | Add-Member -MemberType NoteProperty -Name $name -Value $alias_script_name
set_config ALIAS $aliases | Out-Null
}
function rm_alias {
param(
[ValidateNotNullOrEmpty()]
[string]$name
)
$aliases = get_config ALIAS ([PSCustomObject]@{})
if (!$aliases.$name) {
abort "Alias '$name' doesn't exist."
}
info "Removing alias '$name'..."
if (Test-Path "$(shimdir $false)\scoop-$name.ps1") {
Remove-Item "$(shimdir $false)\scoop-$name.ps1"
}
$aliases.PSObject.Properties.Remove($name)
set_config ALIAS $aliases | Out-Null
}
function list_aliases {
param(
[bool]$verbose
)
$aliases = get_config ALIAS ([PSCustomObject]@{})
$alias_info = $aliases.PSObject.Properties.Name | Where-Object { $_ } | ForEach-Object {
# Mark the alias as <BROKEN>, if the alias script file does NOT exist.
if (!(Test-Path "$(shimdir $false)\scoop-$_.ps1")) {
[PSCustomObject]@{
Name = $_
Command = '<BROKEN>'
}
return
}
$content = Get-Content (command_path $_)
[PSCustomObject]@{
Name = $_
Command = ($content | Select-Object -Skip 1).Trim()
Summary = (summary $content).Trim()
}
}
if (!$alias_info) {
info 'No alias found.'
return
}
$alias_info = $alias_info | Sort-Object Name
$properties = @('Name', 'Command')
if ($verbose) {
$properties += 'Summary'
}
$alias_info | Select-Object $properties
}

File diff suppressed because it is too large Load Diff

390
lib/database.ps1 Normal file
View File

@@ -0,0 +1,390 @@
# Description: Functions for interacting with the Scoop database cache
<#
.SYNOPSIS
Get SQLite .NET driver
.DESCRIPTION
Download and extract the SQLite .NET driver from NuGet.
.PARAMETER Version
System.String
The version of the SQLite .NET driver to download.
.INPUTS
None
.OUTPUTS
System.Boolean
True if the SQLite .NET driver was successfully downloaded and extracted, otherwise false.
#>
function Get-SQLite {
param (
[string]$Version = '1.0.118'
)
# Install SQLite
try {
Write-Host "Downloading SQLite $Version..." -ForegroundColor DarkYellow
$sqlitePkgPath = "$env:TEMP\sqlite.zip"
$sqliteTempPath = "$env:TEMP\sqlite"
$sqlitePath = "$PSScriptRoot\..\supporting\sqlite"
Invoke-WebRequest -Uri "https://api.nuget.org/v3-flatcontainer/stub.system.data.sqlite.core.netframework/$version/stub.system.data.sqlite.core.netframework.$version.nupkg" -OutFile $sqlitePkgPath
Write-Host "Extracting SQLite $Version..." -ForegroundColor DarkYellow -NoNewline
Expand-Archive -Path $sqlitePkgPath -DestinationPath $sqliteTempPath -Force
New-Item -Path $sqlitePath -ItemType Directory -Force | Out-Null
Move-Item -Path "$sqliteTempPath\build\net451\*", "$sqliteTempPath\lib\net451\System.Data.SQLite.dll" -Destination $sqlitePath -Force
Remove-Item -Path $sqlitePkgPath, $sqliteTempPath -Recurse -Force
Write-Host ' Done' -ForegroundColor DarkYellow
return $true
} catch {
return $false
}
}
<#
.SYNOPSIS
Open Scoop SQLite database.
.DESCRIPTION
Open Scoop SQLite database connection and create the necessary tables if not exists.
.INPUTS
None
.OUTPUTS
System.Data.SQLite.SQLiteConnection
The SQLite database connection if **PassThru** is used.
#>
function Open-ScoopDB {
# Load System.Data.SQLite
if (!('System.Data.SQLite.SQLiteConnection' -as [Type])) {
try {
if (!(Test-Path -Path "$PSScriptRoot\..\supporting\sqlite\System.Data.SQLite.dll")) {
Get-SQLite | Out-Null
}
Add-Type -Path "$PSScriptRoot\..\supporting\sqlite\System.Data.SQLite.dll"
} catch {
throw "Scoop's Database cache requires the ADO.NET driver:`n`thttp://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki"
}
}
$dbPath = Join-Path $scoopdir 'scoop.db'
$db = New-Object -TypeName System.Data.SQLite.SQLiteConnection
$db.ConnectionString = "Data Source=$dbPath"
$db.ParseViaFramework = $true # Allow UNC path
$db.Open()
$tableCommand = $db.CreateCommand()
$tableCommand.CommandText = "CREATE TABLE IF NOT EXISTS 'app' (
name TEXT NOT NULL COLLATE NOCASE,
description TEXT NOT NULL,
version TEXT NOT NULL,
bucket VARCHAR NOT NULL,
manifest JSON NOT NULL,
binary TEXT,
shortcut TEXT,
dependency TEXT,
suggest TEXT,
PRIMARY KEY (name, version, bucket)
)"
$tableCommand.CommandType = [System.Data.CommandType]::Text
$tableCommand.ExecuteNonQuery() | Out-Null
$tableCommand.Dispose()
return $db
}
<#
.SYNOPSIS
Set Scoop database item(s).
.DESCRIPTION
Insert or replace item(s) into the Scoop SQLite database.
.PARAMETER InputObject
System.Object[]
The database item(s) to insert or replace.
.INPUTS
System.Object[]
.OUTPUTS
None
#>
function Set-ScoopDBItem {
[CmdletBinding()]
param (
[Parameter(Mandatory, Position = 0, ValueFromPipeline)]
[psobject[]]
$InputObject
)
begin {
$db = Open-ScoopDB
$dbTrans = $db.BeginTransaction()
# TODO Support [hashtable]$InputObject
$colName = @($InputObject | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name)
$dbQuery = "INSERT OR REPLACE INTO app ($($colName -join ', ')) VALUES ($('@' + ($colName -join ', @')))"
$dbCommand = $db.CreateCommand()
$dbCommand.CommandText = $dbQuery
$dbCommand.CommandType = [System.Data.CommandType]::Text
}
process {
foreach ($item in $InputObject) {
$item.PSObject.Properties | ForEach-Object {
$dbCommand.Parameters.AddWithValue("@$($_.Name)", $_.Value) | Out-Null
}
$dbCommand.ExecuteNonQuery() | Out-Null
}
}
end {
try {
$dbTrans.Commit()
} catch {
$dbTrans.Rollback()
throw $_
} finally {
$dbCommand.Dispose()
$dbTrans.Dispose()
$db.Dispose()
}
}
}
<#
.SYNOPSIS
Set Scoop app database item(s).
.DESCRIPTION
Insert or replace Scoop app(s) into the database.
.PARAMETER Path
System.String
The path to the bucket.
.PARAMETER CommitHash
System.String
The commit hash to compare with the HEAD.
.INPUTS
None
.OUTPUTS
None
#>
function Set-ScoopDB {
[CmdletBinding()]
param (
[Parameter(Position = 0, ValueFromPipeline)]
[string[]]
$Path
)
begin {
$list = [System.Collections.Generic.List[psobject]]::new()
$arch = Get-DefaultArchitecture
}
process {
if ($Path.Count -eq 0) {
$bucketPath = Get-LocalBucket | ForEach-Object { Find-BucketDirectory $_ }
$Path = (Get-ChildItem $bucketPath -Filter '*.json' -Recurse).FullName
}
$Path | ForEach-Object {
$manifestRaw = [System.IO.File]::ReadAllText($_)
$manifest = ConvertFrom-Json $manifestRaw -ErrorAction SilentlyContinue
if ($null -ne $manifest.version) {
$list.Add([pscustomobject]@{
name = $($_ -replace '.*[\\/]([^\\/]+)\.json$', '$1')
description = if ($manifest.description) { $manifest.description } else { '' }
version = $manifest.version
bucket = $($_ -replace '.*buckets[\\/]([^\\/]+)(?:[\\/].*)', '$1')
manifest = $manifestRaw
binary = $(
$result = @()
@(arch_specific 'bin' $manifest $arch) | ForEach-Object {
if ($_ -is [System.Array]) {
$result += "$($_[1]).$($_[0].Split('.')[-1])"
} else {
$result += $_
}
}
$result -replace '.*?([^\\/]+)?(\.(exe|bat|cmd|ps1|jar|py))$', '$1' -join ' | '
)
shortcut = $(
$result = @()
@(arch_specific 'shortcuts' $manifest $arch) | ForEach-Object {
$result += $_[1]
}
$result -replace '.*?([^\\/]+$)', '$1' -join ' | '
)
dependency = $manifest.depends -join ' | '
suggest = $(
$suggest_output = @()
$manifest.suggest.PSObject.Properties | ForEach-Object {
$suggest_output += $_.Value -join ' | '
}
$suggest_output -join ' | '
)
})
}
}
}
end {
if ($list.Count -ne 0) {
Set-ScoopDBItem $list
}
}
}
<#
.SYNOPSIS
Select Scoop database item(s).
.DESCRIPTION
Select item(s) from the Scoop SQLite database.
The pattern is matched against the name, binaries, and shortcuts columns for apps.
.PARAMETER Pattern
System.String
The pattern to search for. If is an empty string, all items will be returned.
.PARAMETER From
System.String[]
The fields to search from.
.INPUTS
System.String
.OUTPUTS
System.Data.DataTable
The selected database item(s).
#>
function Select-ScoopDBItem {
[CmdletBinding()]
param (
[Parameter(Mandatory, Position = 0, ValueFromPipeline)]
[AllowEmptyString()]
[string]
$Pattern,
[Parameter(Mandatory, Position = 1)]
[ValidateNotNullOrEmpty()]
[string[]]
$From
)
begin {
$db = Open-ScoopDB
$dbAdapter = New-Object -TypeName System.Data.SQLite.SQLiteDataAdapter
$result = New-Object System.Data.DataTable
$dbQuery = "SELECT * FROM app WHERE $(($From -join ' LIKE @Pattern OR ') + ' LIKE @Pattern')"
$dbQuery = "SELECT * FROM ($($dbQuery + ' ORDER BY version DESC')) GROUP BY name, bucket"
$dbCommand = $db.CreateCommand()
$dbCommand.CommandText = $dbQuery
$dbCommand.CommandType = [System.Data.CommandType]::Text
$dbAdapter.SelectCommand = $dbCommand
}
process {
$dbCommand.Parameters.AddWithValue('@Pattern', $(if ($Pattern -eq '') { '%' } else { '%' + $Pattern + '%' })) | Out-Null
[void]$dbAdapter.Fill($result)
}
end {
$dbAdapter.Dispose()
$db.Dispose()
return $result
}
}
<#
.SYNOPSIS
Get Scoop database item.
.DESCRIPTION
Get item from the Scoop SQLite database.
.PARAMETER Name
System.String
The name of the item to get.
.PARAMETER Bucket
System.String
The bucket of the item to get.
.PARAMETER Version
System.String
The version of the item to get. If not provided, the latest version will be returned.
.INPUTS
System.String
.OUTPUTS
System.Data.DataTable
The selected database item.
#>
function Get-ScoopDBItem {
[CmdletBinding()]
param (
[Parameter(Mandatory, Position = 0, ValueFromPipeline)]
[string]
$Name,
[Parameter(Mandatory, Position = 1)]
[string]
$Bucket,
[Parameter(Position = 2)]
[string]
$Version
)
begin {
$db = Open-ScoopDB
$dbAdapter = New-Object -TypeName System.Data.SQLite.SQLiteDataAdapter
$result = New-Object System.Data.DataTable
$dbQuery = 'SELECT * FROM app WHERE name = @Name AND bucket = @Bucket'
if ($Version) {
$dbQuery += ' AND version = @Version'
} else {
$dbQuery += ' ORDER BY version DESC LIMIT 1'
}
$dbCommand = $db.CreateCommand()
$dbCommand.CommandText = $dbQuery
$dbCommand.CommandType = [System.Data.CommandType]::Text
$dbAdapter.SelectCommand = $dbCommand
}
process {
$dbCommand.Parameters.AddWithValue('@Name', $Name) | Out-Null
$dbCommand.Parameters.AddWithValue('@Bucket', $Bucket) | Out-Null
$dbCommand.Parameters.AddWithValue('@Version', $Version) | Out-Null
[void]$dbAdapter.Fill($result)
}
end {
$dbAdapter.Dispose()
$db.Dispose()
return $result
}
}
<#
.SYNOPSIS
Remove Scoop database item(s).
.DESCRIPTION
Remove item(s) from the Scoop SQLite database.
.PARAMETER Name
System.String
The name of the item to remove.
.PARAMETER Bucket
System.String
The bucket of the item to remove.
.INPUTS
System.String
.OUTPUTS
None
#>
function Remove-ScoopDBItem {
[CmdletBinding()]
param (
[Parameter(Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)]
[string]
$Name,
[Parameter(Mandatory, Position = 1, ValueFromPipelineByPropertyName)]
[string]
$Bucket
)
begin {
$db = Open-ScoopDB
$dbTrans = $db.BeginTransaction()
$dbQuery = 'DELETE FROM app WHERE bucket = @Bucket'
$dbCommand = $db.CreateCommand()
$dbCommand.CommandText = $dbQuery
$dbCommand.CommandType = [System.Data.CommandType]::Text
}
process {
$dbCommand.Parameters.AddWithValue('@Bucket', $Bucket) | Out-Null
if ($Name) {
$dbCommand.CommandText = $dbQuery + ' AND name = @Name'
$dbCommand.Parameters.AddWithValue('@Name', $Name) | Out-Null
}
$dbCommand.ExecuteNonQuery() | Out-Null
}
end {
try {
$dbTrans.Commit()
} catch {
$dbTrans.Rollback()
throw $_
} finally {
$dbCommand.Dispose()
$dbTrans.Dispose()
$db.Dispose()
}
}
}

View File

@@ -1,125 +1,224 @@
function Test-7zipRequirement {
[CmdletBinding(DefaultParameterSetName = "URL")]
[OutputType([Boolean])]
param(
[Parameter(Mandatory = $true, ParameterSetName = "URL")]
[String[]]
$URL,
[Parameter(Mandatory = $true, ParameterSetName = "File")]
[String]
$File
)
if ($URL) {
if ((get_config 7ZIPEXTRACT_USE_EXTERNAL)) {
return $false
} else {
return ($URL | Where-Object { Test-7zipRequirement -File $_ }).Count -gt 0
}
} else {
return $File -match '\.((gz)|(tar)|(tgz)|(lzma)|(bz)|(bz2)|(7z)|(rar)|(iso)|(xz)|(lzh)|(nupkg))$'
}
}
# Description: Functions for decompressing archives or installers
function Test-LessmsiRequirement {
[CmdletBinding()]
[OutputType([Boolean])]
param(
[Parameter(Mandatory = $true)]
[String[]]
$URL
function Invoke-Extraction {
param (
[string]
$Path,
[string[]]
$Name,
[psobject]
$Manifest,
[Alias('Arch', 'Architecture')]
[string]
$ProcessorArchitecture
)
if ((get_config MSIEXTRACT_USE_LESSMSI)) {
return ($URL | Where-Object { $_ -match '\.msi$' }).Count -gt 0
} else {
return $false
$uri = @(url $Manifest $ProcessorArchitecture)
# 'extract_dir' and 'extract_to' are paired
$extractDir = @(extract_dir $Manifest $ProcessorArchitecture)
$extractTo = @(extract_to $Manifest $ProcessorArchitecture)
$extracted = 0
for ($i = 0; $i -lt $Name.Length; $i++) {
# work out extraction method, if applicable
$extractFn = $null
switch -regex ($Name[$i]) {
'\.zip$' {
if ((Test-HelperInstalled -Helper 7zip) -or ((get_config 7ZIPEXTRACT_USE_EXTERNAL) -and (Test-CommandAvailable 7z))) {
$extractFn = 'Expand-7zipArchive'
} else {
$extractFn = 'Expand-ZipArchive'
}
continue
}
'\.msi$' {
$extractFn = 'Expand-MsiArchive'
continue
}
'\.exe$' {
if ($Manifest.innosetup) {
$extractFn = 'Expand-InnoArchive'
}
continue
}
{ Test-7zipRequirement -Uri $_ } {
$extractFn = 'Expand-7zipArchive'
continue
}
}
if ($extractFn) {
$fnArgs = @{
Path = Join-Path $Path $Name[$i]
DestinationPath = Join-Path $Path $extractTo[$extracted]
ExtractDir = $extractDir[$extracted]
}
Write-Host 'Extracting ' -NoNewline
Write-Host $(url_remote_filename $uri[$i]) -ForegroundColor Cyan -NoNewline
Write-Host ' ... ' -NoNewline
& $extractFn @fnArgs -Removal
Write-Host 'done.' -ForegroundColor Green
$extracted++
}
}
}
function Expand-7zipArchive {
[CmdletBinding()]
param(
param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[String]
$Path,
[Parameter(Position = 1)]
[String]
$DestinationPath = (Split-Path $Path),
[ValidateSet("All", "Skip", "Rename")]
[String]
$ExtractDir,
[Parameter(ValueFromRemainingArguments = $true)]
[String]
$Switches,
[ValidateSet('All', 'Skip', 'Rename')]
[String]
$Overwrite,
[Switch]
$Removal
)
if ((get_config USE_EXTERNAL_7ZIP)) {
try {
$7zPath = (Get-Command '7z' -CommandType Application -ErrorAction Stop | Select-Object -First 1).Source
} catch [System.Management.Automation.CommandNotFoundException] {
abort "`nCannot find external 7-Zip (7z.exe) while 'use_external_7zip' is 'true'!`nRun 'scoop config use_external_7zip false' or install 7-Zip manually and try again."
}
} else {
$7zPath = Get-HelperPath -Helper 7zip
}
$LogPath = "$(Split-Path $Path)\7zip.log"
$DestinationPath = $DestinationPath.TrimEnd('\')
$ArgList = @('x', $Path, "-o$DestinationPath", '-xr!*.nsis', '-y')
$IsTar = ((strip_ext $Path) -match '\.tar$') -or ($Path -match '\.t[abgpx]z2?$')
if (!$IsTar -and $ExtractDir) {
$ArgList += "-ir!$ExtractDir\*"
}
if ($Switches) {
$ArgList += (-split $Switches)
}
switch ($Overwrite) {
'All' { $ArgList += '-aoa' }
'Skip' { $ArgList += '-aos' }
'Rename' { $ArgList += '-aou' }
}
$Status = Invoke-ExternalCommand $7zPath $ArgList -LogPath $LogPath
if (!$Status) {
abort "Failed to extract files from $Path.`nLog file:`n $(friendly_path $LogPath)`n$(new_issue_msg $app $bucket 'decompress error')"
}
if ($IsTar) {
# Check for tar
$Status = Invoke-ExternalCommand $7zPath @('l', $Path) -LogPath $LogPath
if ($Status) {
# get inner tar file name
$TarFile = (Select-String -Path $LogPath -Pattern '[^ ]*tar$').Matches.Value
Expand-7zipArchive -Path "$DestinationPath\$TarFile" -DestinationPath $DestinationPath -ExtractDir $ExtractDir -Removal
} else {
abort "Failed to list files in $Path.`nNot a 7-Zip supported archive file."
}
}
if (!$IsTar -and $ExtractDir) {
movedir "$DestinationPath\$ExtractDir" $DestinationPath | Out-Null
# Remove temporary directory if it is empty
$ExtractDirTopPath = [string] "$DestinationPath\$($ExtractDir -replace '[\\/].*')"
if ((Get-ChildItem -Path $ExtractDirTopPath -Force -ErrorAction Ignore).Count -eq 0) {
Remove-Item -Path $ExtractDirTopPath -Recurse -Force -ErrorAction Ignore
}
}
if (Test-Path $LogPath) {
Remove-Item $LogPath -Force
}
if ($Removal) {
if (($Path -replace '.*\.([^\.]*)$', '$1') -eq '001') {
# Remove splitted 7-zip archive parts
Get-ChildItem "$($Path -replace '\.[^\.]*$', '').???" | Remove-Item -Force
} elseif (($Path -replace '.*\.part(\d+)\.rar$', '$1')[-1] -eq '1') {
# Remove splitted RAR archive parts
Get-ChildItem "$($Path -replace '\.part(\d+)\.rar$', '').part*.rar" | Remove-Item -Force
} else {
# Remove original archive file
Remove-Item $Path -Force
}
}
}
function Expand-ZstdArchive {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[String]
$Path,
[Parameter(Position = 1)]
[String]
$DestinationPath = (Split-Path $Path),
[String]
$ExtractDir,
[Parameter(ValueFromRemainingArguments = $true)]
[String]
$Switches,
[Switch]
$Removal
)
$LogLocation = "$(Split-Path $Path)\7zip.log"
switch ($Overwrite) {
"All" { $Switches += " -aoa" }
"Skip" { $Switches += " -aos" }
"Rename" { $Switches += " -aou" }
}
if ((get_config 7ZIPEXTRACT_USE_EXTERNAL)) {
try {
7z x "$Path" -o"$DestinationPath" (-split $Switches) -y | Out-File $LogLocation
} catch [System.Management.Automation.CommandNotFoundException] {
abort "Cannot find external 7-Zip (7z.exe) while '7ZIPEXTRACT_USE_EXTERNAL' is 'true'!`nRun 'scoop config 7ZIPEXTRACT_USE_EXTERNAL false' or install 7-Zip manually and try again."
}
} else {
& (Get-HelperPath -Helper 7zip) x "$Path" -o"$DestinationPath" (-split $Switches) -y | Out-File $LogLocation
}
if ($LASTEXITCODE -ne 0) {
abort "Failed to extract files from $Path.`nLog file:`n $(friendly_path $LogLocation)"
}
if (Test-Path $LogLocation) {
Remove-Item $LogLocation -Force
}
if ((strip_ext $Path) -match '\.tar$' -or $Path -match '\.tgz$') {
# Check for tar
$ArchivedFile = & (Get-HelperPath -Helper 7zip) l "$Path"
if ($LASTEXITCODE -eq 0) {
$TarFile = $ArchivedFile[-3] -replace '.{53}(.*)', '$1' # get inner tar file name
Expand-7zipArchive "$DestinationPath\$TarFile" $DestinationPath -Removal
} else {
abort "Failed to list files in $Path.`nNot a 7-Zip supported archive file."
}
}
if ($Removal) {
# Remove original archive file
Remove-Item $Path -Force
}
# TODO: Remove this function after 2024/12/31
Show-DeprecatedWarning $MyInvocation 'Expand-7zipArchive'
Expand-7zipArchive -Path $Path -DestinationPath $DestinationPath -ExtractDir $ExtractDir -Switches $Switches -Removal:$Removal
}
function Expand-MsiArchive {
[CmdletBinding()]
param(
param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[String]
$Path,
[Parameter(Position = 1)]
[String]
$DestinationPath = (Split-Path $Path),
[String]
$ExtractDir,
[Parameter(ValueFromRemainingArguments = $true)]
[String]
$Switches,
[Switch]
$Removal
)
$LogLocation = "$(Split-Path $Path)\msi.log"
if ((get_config MSIEXTRACT_USE_LESSMSI)) {
& (Get-HelperPath -Helper Lessmsi) x "$Path" "$DestinationPath\" | Out-File $LogLocation
if ($LASTEXITCODE -ne 0) {
abort "Failed to extract files from $Path.`nLog file:`n $(friendly_path $LogLocation)"
}
if (Test-Path "$DestinationPath\SourceDir") {
movedir "$DestinationPath\SourceDir" "$DestinationPath" | Out-Null
}
$DestinationPath = $DestinationPath.TrimEnd('\')
if ($ExtractDir) {
$OriDestinationPath = $DestinationPath
$DestinationPath = "$DestinationPath\_tmp"
}
if ((get_config USE_LESSMSI)) {
$MsiPath = Get-HelperPath -Helper Lessmsi
$ArgList = @('x', $Path, "$DestinationPath\")
} else {
$ok = run 'msiexec' @('/a', "`"$Path`"", '/qn', "TARGETDIR=`"$DestinationPath`"", "/lwe `"$LogLocation`"")
if (!$ok) {
abort "Failed to extract files from $Path.`nLog file:`n $(friendly_path $LogLocation)"
}
$MsiPath = 'msiexec.exe'
$ArgList = @('/a', $Path, '/qn', "TARGETDIR=$DestinationPath\SourceDir")
}
$LogPath = "$(Split-Path $Path)\msi.log"
if ($Switches) {
$ArgList += (-split $Switches)
}
$Status = Invoke-ExternalCommand $MsiPath $ArgList -LogPath $LogPath
if (!$Status) {
abort "Failed to extract files from $Path.`nLog file:`n $(friendly_path $LogPath)`n$(new_issue_msg $app $bucket 'decompress error')"
}
if ($ExtractDir -and (Test-Path "$DestinationPath\SourceDir")) {
movedir "$DestinationPath\SourceDir\$ExtractDir" $OriDestinationPath | Out-Null
Remove-Item $DestinationPath -Recurse -Force
} elseif ($ExtractDir) {
movedir "$DestinationPath\$ExtractDir" $OriDestinationPath | Out-Null
Remove-Item $DestinationPath -Recurse -Force
} elseif (Test-Path "$DestinationPath\SourceDir") {
movedir "$DestinationPath\SourceDir" $DestinationPath | Out-Null
}
if (($DestinationPath -ne (Split-Path $Path)) -and (Test-Path "$DestinationPath\$(fname $Path)")) {
Remove-Item "$DestinationPath\$(fname $Path)" -Force
}
if (Test-Path $LogLocation) {
Remove-Item $LogLocation -Force
if (Test-Path $LogPath) {
Remove-Item $LogPath -Force
}
if ($Removal) {
# Remove original archive file
@@ -129,7 +228,83 @@ function Expand-MsiArchive {
function Expand-InnoArchive {
[CmdletBinding()]
param(
param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[String]
$Path,
[Parameter(Position = 1)]
[String]
$DestinationPath = (Split-Path $Path),
[String]
$ExtractDir,
[Parameter(ValueFromRemainingArguments = $true)]
[String]
$Switches,
[Switch]
$Removal
)
$LogPath = "$(Split-Path $Path)\innounp.log"
$ArgList = @('-x', "-d$DestinationPath", $Path, '-y')
switch -Regex ($ExtractDir) {
'^[^{].*' { $ArgList += "-c{app}\$ExtractDir" }
'^{.*' { $ArgList += "-c$ExtractDir" }
Default { $ArgList += '-c{app}' }
}
if ($Switches) {
$ArgList += (-split $Switches)
}
$Status = Invoke-ExternalCommand (Get-HelperPath -Helper Innounp) $ArgList -LogPath $LogPath
if (!$Status) {
abort "Failed to extract files from $Path.`nLog file:`n $(friendly_path $LogPath)`n$(new_issue_msg $app $bucket 'decompress error')"
}
if (Test-Path $LogPath) {
Remove-Item $LogPath -Force
}
if ($Removal) {
# Remove original archive file
Remove-Item $Path -Force
}
}
function Expand-ZipArchive {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[String]
$Path,
[Parameter(Position = 1)]
[String]
$DestinationPath = (Split-Path $Path),
[String]
$ExtractDir,
[Switch]
$Removal
)
if ($ExtractDir) {
$OriDestinationPath = $DestinationPath
$DestinationPath = "$DestinationPath\_tmp"
}
# Disable progress bar to gain performance
$oldProgressPreference = $ProgressPreference
$global:ProgressPreference = 'SilentlyContinue'
# Compatible with Pscx v3 (https://github.com/Pscx/Pscx) ('Microsoft.PowerShell.Archive' is not needed for Pscx v4)
Microsoft.PowerShell.Archive\Expand-Archive -Path $Path -DestinationPath $DestinationPath -Force
$global:ProgressPreference = $oldProgressPreference
if ($ExtractDir) {
movedir "$DestinationPath\$ExtractDir" $OriDestinationPath | Out-Null
Remove-Item $DestinationPath -Recurse -Force
}
if ($Removal) {
# Remove original archive file
Remove-Item $Path -Force
}
}
function Expand-DarkArchive {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[String]
$Path,
@@ -142,108 +317,38 @@ function Expand-InnoArchive {
[Switch]
$Removal
)
$LogLocation = "$(Split-Path $Path)\innounp.log"
& (Get-HelperPath -Helper Innounp) -x -d"$DestinationPath" -c'{app}' "$Path" (-split $Switches) -y | Out-File $LogLocation
if ($LASTEXITCODE -ne 0) {
abort "Failed to extract files from $Path.`nLog file:`n $(friendly_path $LogLocation)"
}
if (Test-Path $LogLocation) {
Remove-Item $LogLocation -Force
}
if ($Removal) {
# Remove original archive file
Remove-Item $Path -Force
}
}
function Expand-ZipArchive {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[String]
$Path,
[Parameter(Position = 1)]
[String]
$DestinationPath = (Split-Path $Path),
[Switch]
$Removal
)
# All methods to unzip the file require .NET4.5+
if ($PSVersionTable.PSVersion.Major -lt 5) {
Add-Type -AssemblyName System.IO.Compression.FileSystem
try {
[System.IO.Compression.ZipFile]::ExtractToDirectory($Path, $DestinationPath)
} catch [System.IO.PathTooLongException] {
# try to fall back to 7zip if path is too long
if (Test-HelperInstalled -Helper 7zip) {
Expand-7zipArchive $Path $DestinationPath -Removal
return
} else {
abort "Unzip failed: Windows can't handle the long paths in this zip file.`nRun 'scoop install 7zip' and try again."
}
} catch [System.IO.IOException] {
if (Test-HelperInstalled -Helper 7zip) {
Expand-7zipArchive $Path $DestinationPath -Removal
return
} else {
abort "Unzip failed: Windows can't handle the file names in this zip file.`nRun 'scoop install 7zip' and try again."
}
} catch {
abort "Unzip failed: $_"
}
$LogPath = "$(Split-Path $Path)\dark.log"
$DarkPath = Get-HelperPath -Helper Dark
if ((Split-Path $DarkPath -Leaf) -eq 'wix.exe') {
$ArgList = @('burn', 'extract', $Path, '-out', $DestinationPath, '-outba', "$DestinationPath\UX")
} else {
# Use Expand-Archive to unzip in PowerShell 5+
# Compatible with Pscx (https://github.com/Pscx/Pscx)
Microsoft.PowerShell.Archive\Expand-Archive -Path $Path -DestinationPath $DestinationPath -Force
$ArgList = @('-nologo', '-x', $DestinationPath, $Path)
}
if ($Switches) {
$ArgList += (-split $Switches)
}
$Status = Invoke-ExternalCommand $DarkPath $ArgList -LogPath $LogPath
if (!$Status) {
abort "Failed to extract files from $Path.`nLog file:`n $(friendly_path $LogPath)`n$(new_issue_msg $app $bucket 'decompress error')"
}
if (Test-Path "$DestinationPath\WixAttachedContainer") {
Rename-Item "$DestinationPath\WixAttachedContainer" 'AttachedContainer' -ErrorAction Ignore
} else {
if (Test-Path "$DestinationPath\AttachedContainer\a0") {
$Xml = [xml](Get-Content -Raw "$DestinationPath\UX\manifest.xml" -Encoding utf8)
$Xml.BurnManifest.UX.Payload | ForEach-Object {
Rename-Item "$DestinationPath\UX\$($_.SourcePath)" $_.FilePath -ErrorAction Ignore
}
$Xml.BurnManifest.Payload | ForEach-Object {
Rename-Item "$DestinationPath\AttachedContainer\$($_.SourcePath)" $_.FilePath -ErrorAction Ignore
}
}
}
if (Test-Path $LogPath) {
Remove-Item $LogPath -Force
}
if ($Removal) {
# Remove original archive file
Remove-Item $Path -Force
}
}
function Expand-DarkArchive {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[String]
$Path,
[Parameter(Position = 1)]
[String]
$DestinationPath = (Split-Path $Path),
[Switch]
$Removal
)
$LogLocation = "$(Split-Path $Path)\dark.log"
& (Get-HelperPath -Helper Dark) -nologo -x "$Path" "$DestinationPath" | Out-File $LogLocation
if ($LASTEXITCODE -ne 0) {
abort "Failed to extract files from $Path.`nLog file:`n $(friendly_path $LogLocation)"
}
if (Test-Path $LogLocation) {
Remove-Item $LogLocation -Force
}
if ($Removal) {
# Remove original archive file
Remove-Item $Path -Force
}
}
function extract_7zip($path, $to, $removal) {
Show-DeprecatedWarning $MyInvocation 'Expand-7zipArchive'
Expand-7zipArchive -Path $path -DestinationPath $to -Removal:$removal @args
}
function extract_msi($path, $to, $removal) {
Show-DeprecatedWarning $MyInvocation 'Expand-MsiArchive'
Expand-MsiArchive -Path $path -DestinationPath $to -Removal:$removal
}
function unpack_inno($path, $to, $removal) {
Show-DeprecatedWarning $MyInvocation 'Expand-InnoArchive'
Expand-InnoArchive -Path $path -DestinationPath $to -Removal:$removal @args
}
function extract_zip($path, $to, $removal) {
Show-DeprecatedWarning $MyInvocation 'Expand-ZipArchive'
Expand-ZipArchive -Path $path -DestinationPath $to -Removal:$removal
}

View File

@@ -1,98 +1,158 @@
# resolve dependencies for the supplied apps, and sort into the correct order
function install_order($apps, $arch) {
$res = @()
foreach ($app in $apps) {
foreach ($dep in deps $app $arch) {
if ($res -notcontains $dep) { $res += $dep}
}
if ($res -notcontains $app) { $res += $app }
}
return $res
}
function Get-Dependency {
<#
.SYNOPSIS
Get app's dependencies (with apps attached at the end).
.PARAMETER AppName
App's name
.PARAMETER Architecture
App's architecture
.PARAMETER Resolved
List of resolved dependencies (internal use)
.PARAMETER Unresolved
List of unresolved dependencies (internal use)
.OUTPUTS
[Object[]]
List of app's dependencies
.NOTES
When pipeline input is used, the output will have duplicate items, and should be filtered by 'Select-Object -Unique'.
ALgorithm: http://www.electricmonk.nl/docs/dependency_resolving_algorithm/dependency_resolving_algorithm.html
#>
[CmdletBinding()]
[OutputType([Object[]])]
param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[PSObject]
$AppName,
[Parameter(Mandatory = $true, Position = 1)]
[String]
$Architecture,
[String[]]
$Resolved = @(),
[String[]]
$Unresolved = @()
)
process {
$AppName, $manifest, $bucket, $url = Get-Manifest $AppName
$Unresolved += $AppName
# http://www.electricmonk.nl/docs/dependency_resolving_algorithm/dependency_resolving_algorithm.html
function deps($app, $arch) {
$resolved = new-object collections.arraylist
dep_resolve $app $arch $resolved @()
if ($resolved.count -eq 1) { return @() } # no dependencies
return $resolved[0..($resolved.count - 2)]
}
function dep_resolve($app, $arch, $resolved, $unresolved) {
$app, $bucket, $null = parse_app $app
$unresolved += $app
$null, $manifest, $null, $null = Find-Manifest $app $bucket
if(!$manifest) {
if(((Get-LocalBucket) -notcontains $bucket) -and $bucket) {
warn "Bucket '$bucket' not installed. Add it with 'scoop bucket add $bucket' or 'scoop bucket add $bucket <repo>'."
}
abort "Couldn't find manifest for '$app'$(if(!$bucket) { '.' } else { " from '$bucket' bucket." })"
}
$deps = @(install_deps $manifest $arch) + @(runtime_deps $manifest) | Select-Object -Unique
foreach ($dep in $deps) {
if ($resolved -notcontains $dep) {
if ($unresolved -contains $dep) {
abort "Circular dependency detected: '$app' -> '$dep'."
if (!$manifest) {
if (((Get-LocalBucket) -notcontains $bucket) -and $bucket) {
warn "Bucket '$bucket' not added. Add it with $(if($bucket -in (known_buckets)) { "'scoop bucket add $bucket' or " })'scoop bucket add $bucket <repo>'."
}
dep_resolve $dep $arch $resolved $unresolved
abort "Couldn't find manifest for '$AppName'$(if($bucket) { " from '$bucket' bucket" } elseif($url) { " at '$url'" })."
}
$deps = @(Get-InstallationHelper $manifest $Architecture) + @($manifest.depends) | Select-Object -Unique
foreach ($dep in $deps) {
if ($Resolved -notcontains $dep) {
if ($Unresolved -contains $dep) {
abort "Circular dependency detected: '$AppName' -> '$dep'."
}
$Resolved, $Unresolved = Get-Dependency $dep $Architecture -Resolved $Resolved -Unresolved $Unresolved
}
}
$Unresolved = $Unresolved -ne $AppName
if ($bucket) {
$Resolved += "$bucket/$AppName"
} else {
if ($url) {
$Resolved += $url
} else {
$Resolved += $AppName
}
}
if ($Unresolved.Length -eq 0) {
return $Resolved
} else {
return $Resolved, $Unresolved
}
}
$resolved.add($app) | Out-Null
$unresolved = $unresolved -ne $app # remove from unresolved
}
function runtime_deps($manifest) {
if ($manifest.depends) { return $manifest.depends }
function Get-InstallationHelper {
<#
.SYNOPSIS
Get helpers that used in installation
.PARAMETER Manifest
App's manifest
.PARAMETER Architecture
Architecture of the app
.PARAMETER All
If true, return all helpers, otherwise return only helpers that are not already installed
.OUTPUTS
[Object[]]
List of helpers
#>
[CmdletBinding()]
[OutputType([Object[]])]
param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[PSObject]
$Manifest,
[Parameter(Mandatory = $true, Position = 1)]
[String]
$Architecture,
[Switch]
$All
)
begin {
$helper = @()
}
process {
$url = arch_specific 'url' $Manifest $Architecture
$pre_install = arch_specific 'pre_install' $Manifest $Architecture
$installer = arch_specific 'installer' $Manifest $Architecture
$post_install = arch_specific 'post_install' $Manifest $Architecture
$script = $pre_install + $installer.script + $post_install
if (((Test-7zipRequirement -Uri $url) -or ($script -like '*Expand-7zipArchive *')) -and !(get_config USE_EXTERNAL_7ZIP)) {
$helper += '7zip'
}
if (((Test-LessmsiRequirement -Uri $url) -or ($script -like '*Expand-MsiArchive *')) -and (get_config USE_LESSMSI)) {
$helper += 'lessmsi'
}
if ($Manifest.innosetup -or ($script -like '*Expand-InnoArchive *')) {
$helper += 'innounp'
}
if ($script -like '*Expand-DarkArchive *') {
$helper += 'dark'
}
if (!$All) {
'7zip', 'lessmsi', 'innounp', 'dark' | ForEach-Object {
if (Test-HelperInstalled -Helper $_) {
$helper = $helper -ne $_
}
}
}
}
end {
return $helper
}
}
function script_deps($script) {
$deps = @()
if($script -is [Array]) {
$script = $script -join "`n"
}
if([String]::IsNullOrEmpty($script)) {
return $deps
}
if($script -like '*Expand-7zipArchive *' -or $script -like '*extract_7zip *') {
$deps += '7zip'
}
if($script -like '*Expand-MsiArchive *' -or $script -like '*extract_msi *') {
$deps += 'lessmsi'
}
if($script -like '*Expand-InnoArchive *' -or $script -like '*unpack_inno *') {
$deps += 'innounp'
}
if($script -like '*Expand-DarkArchive *') {
$deps += 'dark'
}
return $deps
function Test-7zipRequirement {
[CmdletBinding()]
[OutputType([Boolean])]
param (
[Parameter(Mandatory = $true)]
[AllowNull()]
[String[]]
$Uri
)
return ($Uri | Where-Object {
$_ -match '\.(001|7z|bz(ip)?2?|gz|img|iso|lzma|lzh|nupkg|rar|tar|t[abgpx]z2?|t?zst|xz)(\.[^\d.]+)?$'
}).Count -gt 0
}
function install_deps($manifest, $arch) {
$deps = @()
if (!(Test-HelperInstalled -Helper 7zip) -and (Test-7zipRequirement -URL (url $manifest $arch))) {
$deps += '7zip'
}
if (!(Test-HelperInstalled -Helper Lessmsi) -and (Test-LessmsiRequirement -URL (url $manifest $arch))) {
$deps += 'lessmsi'
}
if (!(Test-HelperInstalled -Helper Innounp) -and $manifest.innosetup) {
$deps += 'innounp'
}
$pre_install = arch_specific 'pre_install' $manifest $arch
$installer = arch_specific 'installer' $manifest $arch
$post_install = arch_specific 'post_install' $manifest $arch
$deps += script_deps $pre_install
$deps += script_deps $installer.script
$deps += script_deps $post_install
return $deps | Select-Object -Unique
function Test-LessmsiRequirement {
[CmdletBinding()]
[OutputType([Boolean])]
param (
[Parameter(Mandatory = $true)]
[AllowNull()]
[String[]]
$Uri
)
return ($Uri | Where-Object { $_ -match '\.msi$' }).Count -gt 0
}

View File

@@ -18,7 +18,8 @@ function find_description($url, $html, $redir = $false) {
if($refresh -and !$redir) {
$wc = New-Object Net.Webclient
$wc.Headers.Add('User-Agent', (Get-UserAgent))
$html = $wc.downloadstring($refresh)
$data = $wc.DownloadData($refresh)
$html = (Get-Encoding($wc)).GetString($data)
return find_description $refresh $html $true
}

View File

@@ -3,22 +3,21 @@ Diagnostic tests.
Return $true if the test passed, otherwise $false.
Use 'warn' to highlight the issue, and follow up with the recommended actions to rectify.
#>
. "$PSScriptRoot\buckets.ps1"
function check_windows_defender($global) {
$defender = get-service -name WinDefend -errorAction SilentlyContinue
if($defender -and $defender.status) {
if($defender.status -eq [system.serviceprocess.servicecontrollerstatus]::running) {
if (Test-CommandAvailable Get-MpPreference) {
$defender = Get-Service -Name WinDefend -ErrorAction SilentlyContinue
if (Test-CommandAvailable Get-MpPreference) {
if ((Get-MpPreference).DisableRealtimeMonitoring) { return $true }
if ($defender -and $defender.Status) {
if ($defender.Status -eq [System.ServiceProcess.ServiceControllerStatus]::Running) {
$installPath = $scoopdir;
if($global) { $installPath = $globaldir; }
if ($global) { $installPath = $globaldir; }
$exclusionPath = (Get-MpPreference).exclusionPath
if(!($exclusionPath -contains $installPath)) {
warn "Windows Defender may slow down or disrupt installs with realtime scanning."
write-host " Consider running:"
write-host " sudo Add-MpPreference -ExclusionPath '$installPath'"
write-host " (Requires 'sudo' command. Run 'scoop install sudo' if you don't have it.)"
$exclusionPath = (Get-MpPreference).ExclusionPath
if (!($exclusionPath -contains $installPath)) {
info "Windows Defender may slow down or disrupt installs with realtime scanning."
Write-Host " Consider running:"
Write-Host " sudo Add-MpPreference -ExclusionPath '$installPath'"
Write-Host " (Requires 'sudo' command. Run 'scoop install sudo' if you don't have it.)"
return $false
}
}
@@ -28,7 +27,7 @@ function check_windows_defender($global) {
}
function check_main_bucket {
if ((Get-LocalBucket) -notcontains 'main'){
if ((Get-LocalBucket) -notcontains 'main') {
warn 'Main bucket is not added.'
Write-Host " run 'scoop bucket add main'"
@@ -39,12 +38,30 @@ function check_main_bucket {
}
function check_long_paths {
if ([System.Environment]::OSVersion.Version.Major -lt 10 -or [System.Environment]::OSVersion.Version.Build -lt 1607) {
warn 'This version of Windows does not support configuration of LongPaths.'
return $false
}
$key = Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -ErrorAction SilentlyContinue -Name 'LongPathsEnabled'
if (!$key -or ($key.LongPathsEnabled -eq 0)) {
warn 'LongPaths support is not enabled.'
Write-Host "You can enable it with running:"
Write-Host " Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' -Value 1"
Write-Host " You can enable it by running:"
Write-Host " sudo Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' -Value 1"
Write-Host " (Requires 'sudo' command. Run 'scoop install sudo' if you don't have it.)"
return $false
}
return $true
}
function Get-WindowsDeveloperModeStatus {
$DevModRegistryPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock"
if (!(Test-Path -Path $DevModRegistryPath) -or (Get-ItemProperty -Path `
$DevModRegistryPath -Name AllowDevelopmentWithoutDevLicense -ErrorAction `
SilentlyContinue).AllowDevelopmentWithoutDevLicense -ne 1) {
warn "Windows Developer Mode is not enabled. Operations relevant to symlinks may fail without proper rights."
Write-Host " You may read more about the symlinks support here:"
Write-Host " https://blogs.windows.com/windowsdeveloper/2016/12/02/symlinks-windows-10/"
return $false
}

769
lib/download.ps1 Normal file
View File

@@ -0,0 +1,769 @@
# Description: Functions for downloading files
## Meta downloader
function Invoke-ScoopDownload ($app, $version, $manifest, $bucket, $architecture, $dir, $use_cache = $true, $check_hash = $true) {
# we only want to show this warning once
if (!$use_cache) { warn 'Cache is being ignored.' }
# can be multiple urls: if there are, then installer should go first to make 'installer.args' section work
$urls = @(script:url $manifest $architecture)
# can be multiple cookies: they will be used for all HTTP requests.
$cookies = $manifest.cookie
# download first
if (Test-Aria2Enabled) {
Invoke-CachedAria2Download $app $version $manifest $architecture $dir $cookies $use_cache $check_hash
} else {
foreach ($url in $urls) {
$fname = url_filename $url
try {
Invoke-CachedDownload $app $version $url "$dir\$fname" $cookies $use_cache
} catch {
Write-Host -ForegroundColor DarkRed $_
abort "URL $url is not valid"
}
if ($check_hash) {
$manifest_hash = hash_for_url $manifest $url $architecture
$ok, $err = check_hash "$dir\$fname" $manifest_hash $(show_app $app $bucket)
if (!$ok) {
error $err
$cached = cache_path $app $version $url
if (Test-Path $cached) {
# rm cached file
Remove-Item -Force $cached
}
if ($url.Contains('sourceforge.net')) {
Write-Host -ForegroundColor Yellow 'SourceForge.net is known for causing hash validation fails. Please try again before opening a ticket.'
}
abort $(new_issue_msg $app $bucket 'hash check failed')
}
}
}
}
return $urls.ForEach({ url_filename $_ })
}
## [System.Net] downloader
function Invoke-CachedDownload ($app, $version, $url, $to, $cookies = $null, $use_cache = $true) {
$cached = cache_path $app $version $url
if (!(Test-Path $cached) -or !$use_cache) {
ensure $cachedir | Out-Null
Start-Download $url "$cached.download" $cookies
Move-Item "$cached.download" $cached -Force
} else { Write-Host "Loading $(url_remote_filename $url) from cache" }
if (!($null -eq $to)) {
if ($use_cache) {
Copy-Item $cached $to
} else {
Move-Item $cached $to -Force
}
}
}
function Start-Download ($url, $to, $cookies) {
$progress = [console]::isoutputredirected -eq $false -and
$host.name -ne 'Windows PowerShell ISE Host'
try {
$url = handle_special_urls $url
Invoke-Download $url $to $cookies $progress
} catch {
$e = $_.exception
if ($e.Response.StatusCode -eq 'Unauthorized') {
warn 'Token might be misconfigured.'
}
if ($e.innerexception) { $e = $e.innerexception }
throw $e
}
}
function Invoke-Download ($url, $to, $cookies, $progress) {
# download with filesize and progress indicator
$reqUrl = ($url -split '#')[0]
$wreq = [Net.WebRequest]::Create($reqUrl)
if ($wreq -is [Net.HttpWebRequest]) {
$wreq.UserAgent = Get-UserAgent
if (-not ($url -match 'sourceforge\.net' -or $url -match 'portableapps\.com')) {
$wreq.Referer = strip_filename $url
}
if ($url -match 'api\.github\.com/repos') {
$wreq.Accept = 'application/octet-stream'
$wreq.Headers['Authorization'] = "Bearer $(Get-GitHubToken)"
$wreq.Headers['X-GitHub-Api-Version'] = '2022-11-28'
}
if ($cookies) {
$wreq.Headers.Add('Cookie', (cookie_header $cookies))
}
get_config PRIVATE_HOSTS | Where-Object { $_ -ne $null -and $url -match $_.match } | ForEach-Object {
(ConvertFrom-StringData -StringData $_.Headers).GetEnumerator() | ForEach-Object {
$wreq.Headers[$_.Key] = $_.Value
}
}
}
try {
$wres = $wreq.GetResponse()
} catch [System.Net.WebException] {
$exc = $_.Exception
$handledCodes = @(
[System.Net.HttpStatusCode]::MovedPermanently, # HTTP 301
[System.Net.HttpStatusCode]::Found, # HTTP 302
[System.Net.HttpStatusCode]::SeeOther, # HTTP 303
[System.Net.HttpStatusCode]::TemporaryRedirect # HTTP 307
)
# Only handle redirection codes
$redirectRes = $exc.Response
if ($handledCodes -notcontains $redirectRes.StatusCode) {
throw $exc
}
# Get the new location of the file
if ((-not $redirectRes.Headers) -or ($redirectRes.Headers -notcontains 'Location')) {
throw $exc
}
$newUrl = $redirectRes.Headers['Location']
info "Following redirect to $newUrl..."
# Handle manual file rename
if ($url -like '*#/*') {
$null, $postfix = $url -split '#/'
$newUrl = "$newUrl`#/$postfix"
}
Invoke-Download $newUrl $to $cookies $progress
return
}
$total = $wres.ContentLength
if ($total -eq -1 -and $wreq -is [net.ftpwebrequest]) {
$total = ftp_file_size($url)
}
if ($progress -and ($total -gt 0)) {
[console]::CursorVisible = $false
function Trace-DownloadProgress ($read) {
Write-DownloadProgress $read $total $url
}
} else {
Write-Host "Downloading $url ($(filesize $total))..."
function Trace-DownloadProgress {
#no op
}
}
try {
$s = $wres.getresponsestream()
$fs = [io.file]::openwrite($to)
$buffer = New-Object byte[] 2048
$totalRead = 0
$sw = [diagnostics.stopwatch]::StartNew()
Trace-DownloadProgress $totalRead
while (($read = $s.read($buffer, 0, $buffer.length)) -gt 0) {
$fs.write($buffer, 0, $read)
$totalRead += $read
if ($sw.elapsedmilliseconds -gt 100) {
$sw.restart()
Trace-DownloadProgress $totalRead
}
}
$sw.stop()
Trace-DownloadProgress $totalRead
} finally {
if ($progress) {
[console]::CursorVisible = $true
Write-Host
}
if ($fs) {
$fs.close()
}
if ($s) {
$s.close()
}
$wres.close()
}
}
function Format-DownloadProgress ($url, $read, $total, $console) {
$filename = url_remote_filename $url
# calculate current percentage done
$p = [math]::Round($read / $total * 100, 0)
# pre-generate LHS and RHS of progress string
# so we know how much space we have
$left = "$filename ($(filesize $total))"
$right = [string]::Format('{0,3}%', $p)
# calculate remaining width for progress bar
$midwidth = $console.BufferSize.Width - ($left.Length + $right.Length + 8)
# calculate how many characters are completed
$completed = [math]::Abs([math]::Round(($p / 100) * $midwidth, 0) - 1)
# generate dashes to symbolise completed
if ($completed -gt 1) {
$dashes = [string]::Join('', ((1..$completed) | ForEach-Object { '=' }))
}
# this is why we calculate $completed - 1 above
$dashes += switch ($p) {
100 { '=' }
default { '>' }
}
# the remaining characters are filled with spaces
$spaces = switch ($dashes.Length) {
$midwidth { [string]::Empty }
default {
[string]::Join('', ((1..($midwidth - $dashes.Length)) | ForEach-Object { ' ' }))
}
}
"$left [$dashes$spaces] $right"
}
function Write-DownloadProgress ($read, $total, $url) {
$console = $Host.UI.RawUI
$left = $console.CursorPosition.X
$top = $console.CursorPosition.Y
$width = $console.BufferSize.Width
if ($read -eq 0) {
$maxOutputLength = $(Format-DownloadProgress $url 100 $total $console).Length
if (($left + $maxOutputLength) -gt $width) {
# not enough room to print progress on this line
# print on new line
Write-Host
$left = 0
$top = $top + 1
if ($top -gt $console.CursorPosition.Y) { $top = $console.CursorPosition.Y }
}
}
Write-Host $(Format-DownloadProgress $url $read $total $console) -NoNewline
[console]::SetCursorPosition($left, $top)
}
## Aria2 downloader
function Test-Aria2Enabled {
return (Test-HelperInstalled -Helper Aria2) -and (get_config 'aria2-enabled' $true)
}
function aria_exit_code($exitcode) {
$codes = @{
0 = 'All downloads were successful'
1 = 'An unknown error occurred'
2 = 'Timeout'
3 = 'Resource was not found'
4 = 'Aria2 saw the specified number of "resource not found" error. See --max-file-not-found option'
5 = 'Download aborted because download speed was too slow. See --lowest-speed-limit option'
6 = 'Network problem occurred.'
7 = 'There were unfinished downloads. This error is only reported if all finished downloads were successful and there were unfinished downloads in a queue when aria2 exited by pressing Ctrl-C by an user or sending TERM or INT signal'
8 = 'Remote server did not support resume when resume was required to complete download'
9 = 'There was not enough disk space available'
10 = 'Piece length was different from one in .aria2 control file. See --allow-piece-length-change option'
11 = 'Aria2 was downloading same file at that moment'
12 = 'Aria2 was downloading same info hash torrent at that moment'
13 = 'File already existed. See --allow-overwrite option'
14 = 'Renaming file failed. See --auto-file-renaming option'
15 = 'Aria2 could not open existing file'
16 = 'Aria2 could not create new file or truncate existing file'
17 = 'File I/O error occurred'
18 = 'Aria2 could not create directory'
19 = 'Name resolution failed'
20 = 'Aria2 could not parse Metalink document'
21 = 'FTP command failed'
22 = 'HTTP response header was bad or unexpected'
23 = 'Too many redirects occurred'
24 = 'HTTP authorization failed'
25 = 'Aria2 could not parse bencoded file (usually ".torrent" file)'
26 = '".torrent" file was corrupted or missing information that aria2 needed'
27 = 'Magnet URI was bad'
28 = 'Bad/unrecognized option was given or unexpected option argument was given'
29 = 'The remote server was unable to handle the request due to a temporary overloading or maintenance'
30 = 'Aria2 could not parse JSON-RPC request'
31 = 'Reserved. Not used'
32 = 'Checksum validation failed'
}
if ($null -eq $codes[$exitcode]) {
return 'An unknown error occurred'
}
return $codes[$exitcode]
}
function get_filename_from_metalink($file) {
$bytes = get_magic_bytes_pretty $file ''
# check if file starts with '<?xml'
if (!($bytes.StartsWith('3c3f786d6c'))) {
return $null
}
# Add System.Xml for reading metalink files
Add-Type -AssemblyName 'System.Xml'
$xr = [System.Xml.XmlReader]::Create($file)
$filename = $null
try {
$xr.ReadStartElement('metalink')
if ($xr.ReadToFollowing('file') -and $xr.MoveToFirstAttribute()) {
$filename = $xr.Value
}
} catch [System.Xml.XmlException] {
return $null
} finally {
$xr.Close()
}
return $filename
}
function Invoke-CachedAria2Download ($app, $version, $manifest, $architecture, $dir, $cookies = $null, $use_cache = $true, $check_hash = $true) {
$data = @{}
$urls = @(script:url $manifest $architecture)
# aria2 input file
$urlstxt = Join-Path $cachedir "$app.txt"
$urlstxt_content = ''
$download_finished = $true
# aria2 options
$options = @(
"--input-file='$urlstxt'"
"--user-agent='$(Get-UserAgent)'"
'--allow-overwrite=true'
'--auto-file-renaming=false'
"--retry-wait=$(get_config 'aria2-retry-wait' 2)"
"--split=$(get_config 'aria2-split' 5)"
"--max-connection-per-server=$(get_config 'aria2-max-connection-per-server' 5)"
"--min-split-size=$(get_config 'aria2-min-split-size' '5M')"
'--console-log-level=warn'
'--enable-color=false'
'--no-conf=true'
'--follow-metalink=true'
'--metalink-preferred-protocol=https'
'--min-tls-version=TLSv1.2'
"--stop-with-process=$PID"
'--continue'
'--summary-interval=0'
'--auto-save-interval=1'
)
if ($cookies) {
$options += "--header='Cookie: $(cookie_header $cookies)'"
}
$proxy = get_config PROXY
if ($proxy -ne 'none') {
if ([Net.Webrequest]::DefaultWebProxy.Address) {
$options += "--all-proxy='$([Net.Webrequest]::DefaultWebProxy.Address.Authority)'"
}
if ([Net.Webrequest]::DefaultWebProxy.Credentials.UserName) {
$options += "--all-proxy-user='$([Net.Webrequest]::DefaultWebProxy.Credentials.UserName)'"
}
if ([Net.Webrequest]::DefaultWebProxy.Credentials.Password) {
$options += "--all-proxy-passwd='$([Net.Webrequest]::DefaultWebProxy.Credentials.Password)'"
}
}
$more_options = get_config 'aria2-options'
if ($more_options) {
$options += $more_options
}
foreach ($url in $urls) {
$data.$url = @{
'target' = Join-Path $dir (url_filename $url)
'cachename' = fname (cache_path $app $version $url)
'source' = cache_path $app $version $url
}
if ((Test-Path $data.$url.source) -and -not((Test-Path "$($data.$url.source).aria2") -or (Test-Path $urlstxt)) -and $use_cache) {
Write-Host 'Loading ' -NoNewline
Write-Host $(url_remote_filename $url) -ForegroundColor Cyan -NoNewline
Write-Host ' from cache.'
} else {
$download_finished = $false
# create aria2 input file content
try {
$try_url = handle_special_urls $url
} catch {
if ($_.Exception.Response.StatusCode -eq 'Unauthorized') {
warn 'Token might be misconfigured.'
}
}
$urlstxt_content += "$try_url`n"
if (!$url.Contains('sourceforge.net')) {
$urlstxt_content += " referer=$(strip_filename $url)`n"
}
$urlstxt_content += " dir=$cachedir`n"
$urlstxt_content += " out=$($data.$url.cachename)`n"
}
}
if (-not($download_finished)) {
# write aria2 input file
if ($urlstxt_content -ne '') {
ensure $cachedir | Out-Null
# Write aria2 input-file with UTF8NoBOM encoding
$urlstxt_content | Out-UTF8File -FilePath $urlstxt
}
# build aria2 command
$aria2 = "& '$(Get-HelperPath -Helper Aria2)' $($options -join ' ')"
# handle aria2 console output
Write-Host 'Starting download with aria2 ...'
# Set console output encoding to UTF8 for non-ASCII characters printing
$oriConsoleEncoding = [Console]::OutputEncoding
[Console]::OutputEncoding = New-Object System.Text.UTF8Encoding
Invoke-Command ([scriptblock]::Create($aria2)) | ForEach-Object {
# Skip blank lines
if ([String]::IsNullOrWhiteSpace($_)) { return }
# Prevent potential overlaping of text when one line is shorter
$len = $Host.UI.RawUI.WindowSize.Width - $_.Length - 20
$blank = if ($len -gt 0) { ' ' * $len } else { '' }
$color = 'Gray'
if ($_.StartsWith('(OK):')) {
$noNewLine = $true
$color = 'Green'
} elseif ($_.StartsWith('[') -and $_.EndsWith(']')) {
$noNewLine = $true
$color = 'Cyan'
} elseif ($_.StartsWith('Download Results:')) {
$noNewLine = $false
}
Write-Host "`rDownload: $_$blank" -ForegroundColor $color -NoNewline:$noNewLine
}
Write-Host ''
if ($lastexitcode -gt 0) {
warn "Download failed! (Error $lastexitcode) $(aria_exit_code $lastexitcode)"
warn $urlstxt_content
warn $aria2
warn $(new_issue_msg $app $bucket "download via aria2 failed")
Write-Host "Fallback to default downloader ..."
try {
foreach ($url in $urls) {
Invoke-CachedDownload $app $version $url "$($data.$url.target)" $cookies $use_cache
}
} catch {
Write-Host $_ -ForegroundColor DarkRed
abort "URL $url is not valid"
}
}
# remove aria2 input file when done
if (Test-Path $urlstxt, "$($data.$url.source).aria2*") {
Remove-Item $urlstxt -Force -ErrorAction SilentlyContinue
Remove-Item "$($data.$url.source).aria2*" -Force -ErrorAction SilentlyContinue
}
# Revert console encoding
[Console]::OutputEncoding = $oriConsoleEncoding
}
foreach ($url in $urls) {
$metalink_filename = get_filename_from_metalink $data.$url.source
if ($metalink_filename) {
Remove-Item $data.$url.source -Force
Rename-Item -Force (Join-Path -Path $cachedir -ChildPath $metalink_filename) $data.$url.source
}
# run hash checks
if ($check_hash) {
$manifest_hash = hash_for_url $manifest $url $architecture
$ok, $err = check_hash $data.$url.source $manifest_hash $(show_app $app $bucket)
if (!$ok) {
error $err
if (Test-Path $data.$url.source) {
# rm cached file
Remove-Item $data.$url.source -Force -ErrorAction SilentlyContinue
Remove-Item "$($data.$url.source).aria2*" -Force -ErrorAction SilentlyContinue
}
if ($url.Contains('sourceforge.net')) {
Write-Host -f yellow 'SourceForge.net is known for causing hash validation fails. Please try again before opening a ticket.'
}
abort $(new_issue_msg $app $bucket 'hash check failed')
}
}
# copy or move file to target location
if (!(Test-Path $data.$url.source) ) {
abort $(new_issue_msg $app $bucket 'cached file not found')
}
if (!($dir -eq $cachedir)) {
if ($use_cache) {
Copy-Item $data.$url.source $data.$url.target
} else {
Move-Item $data.$url.source $data.$url.target -Force
}
}
}
}
## Helper functions
### Downloader parameters
function cookie_header($cookies) {
if (!$cookies) { return }
$vals = $cookies.psobject.properties | ForEach-Object {
"$($_.name)=$($_.value)"
}
[string]::join(';', $vals)
}
function Get-Encoding($wc) {
if ($null -ne $wc.ResponseHeaders -and $wc.ResponseHeaders['Content-Type'] -match 'charset=([^;]*)') {
return [System.Text.Encoding]::GetEncoding($Matches[1])
} else {
return [System.Text.Encoding]::GetEncoding('utf-8')
}
}
function Get-UserAgent() {
return "Scoop/1.0 (+http://scoop.sh/) PowerShell/$($PSVersionTable.PSVersion.Major).$($PSVersionTable.PSVersion.Minor) (Windows NT $([System.Environment]::OSVersion.Version.Major).$([System.Environment]::OSVersion.Version.Minor); $(if(${env:ProgramFiles(Arm)}){'ARM64; '}elseif($env:PROCESSOR_ARCHITECTURE -eq 'AMD64'){'Win64; x64; '})$(if($env:PROCESSOR_ARCHITEW6432 -in 'AMD64','ARM64'){'WOW64; '})$PSEdition)"
}
function setup_proxy() {
# note: '@' and ':' in password must be escaped, e.g. 'p@ssword' -> p\@ssword'
$proxy = get_config PROXY
if (!$proxy) {
return
}
try {
$credentials, $address = $proxy -split '(?<!\\)@'
if (!$address) {
$address, $credentials = $credentials, $null # no credentials supplied
}
if ($address -eq 'none') {
[net.webrequest]::defaultwebproxy = $null
} elseif ($address -ne 'default') {
[net.webrequest]::defaultwebproxy = New-Object net.webproxy "http://$address"
}
if ($credentials -eq 'currentuser') {
[net.webrequest]::defaultwebproxy.credentials = [net.credentialcache]::defaultcredentials
} elseif ($credentials) {
$username, $password = $credentials -split '(?<!\\):' | ForEach-Object { $_ -replace '\\([@:])', '$1' }
[net.webrequest]::defaultwebproxy.credentials = New-Object net.networkcredential($username, $password)
}
} catch {
warn "Failed to use proxy '$proxy': $($_.exception.message)"
}
}
function Get-GitHubToken {
return $env:SCOOP_GH_TOKEN, (get_config GH_TOKEN) | Where-Object -Property Length -Value 0 -GT | Select-Object -First 1
}
function github_ratelimit_reached {
$api_link = 'https://api.github.com/rate_limit'
$ret = (download_json $api_link).rate.remaining -eq 0
if ($ret) {
Write-Host "GitHub API rate limit reached.`r`nPlease try again later or configure your API token using 'scoop config gh_token <your token>'."
}
$ret
}
### URL handling
function handle_special_urls($url) {
# FossHub.com
if ($url -match '^(?:.*fosshub.com\/)(?<name>.*)(?:\/|\?dwl=)(?<filename>.*)$') {
$Body = @{
projectUri = $Matches.name
fileName = $Matches.filename
source = 'CF'
isLatestVersion = $true
}
if ((Invoke-RestMethod -Uri $url) -match '"p":"(?<pid>[a-f0-9]{24}).*?"r":"(?<rid>[a-f0-9]{24})') {
$Body.Add('projectId', $Matches.pid)
$Body.Add('releaseId', $Matches.rid)
}
$url = Invoke-RestMethod -Method Post -Uri 'https://api.fosshub.com/download/' -ContentType 'application/json' -Body (ConvertTo-Json $Body -Compress)
if ($null -eq $url.error) {
$url = $url.data.url
}
}
# Sourceforge.net
if ($url -match '(?:downloads\.)?sourceforge.net\/projects?\/(?<project>[^\/]+)\/(?:files\/)?(?<file>.*?)(?:$|\/download|\?)') {
# Reshapes the URL to avoid redirections
$url = "https://downloads.sourceforge.net/project/$($matches['project'])/$($matches['file'])"
}
# Github.com
if ($url -match 'github.com/(?<owner>[^/]+)/(?<repo>[^/]+)/releases/download/(?<tag>[^/]+)/(?<file>[^/#]+)(?<filename>.*)' -and ($token = Get-GitHubToken)) {
$headers = @{ 'Authorization' = "token $token" }
$privateUrl = "https://api.github.com/repos/$($Matches.owner)/$($Matches.repo)"
$assetUrl = "https://api.github.com/repos/$($Matches.owner)/$($Matches.repo)/releases/tags/$($Matches.tag)"
if ((Invoke-RestMethod -Uri $privateUrl -Headers $headers).Private) {
$url = ((Invoke-RestMethod -Uri $assetUrl -Headers $headers).Assets | Where-Object -Property Name -EQ -Value $Matches.file).Url, $Matches.filename -join ''
}
}
return $url
}
### Remote file information
function download_json($url) {
$githubtoken = Get-GitHubToken
$authheader = @{}
if ($githubtoken) {
$authheader = @{'Authorization' = "token $githubtoken" }
}
$ProgressPreference = 'SilentlyContinue'
$result = Invoke-WebRequest $url -UseBasicParsing -Headers $authheader | Select-Object -ExpandProperty content | ConvertFrom-Json
$ProgressPreference = 'Continue'
$result
}
function get_magic_bytes($file) {
if (!(Test-Path $file)) {
return ''
}
if ((Get-Command Get-Content).parameters.ContainsKey('AsByteStream')) {
# PowerShell Core (6.0+) '-Encoding byte' is replaced by '-AsByteStream'
return Get-Content $file -AsByteStream -TotalCount 8
} else {
return Get-Content $file -Encoding byte -TotalCount 8
}
}
function get_magic_bytes_pretty($file, $glue = ' ') {
if (!(Test-Path $file)) {
return ''
}
return (get_magic_bytes $file | ForEach-Object { $_.ToString('x2') }) -join $glue
}
Function Get-RemoteFileSize ($Uri) {
$response = Invoke-WebRequest -Uri $Uri -Method HEAD -UseBasicParsing
if (!$response.Headers.StatusCode) {
$response.Headers.'Content-Length' | ForEach-Object { [int]$_ }
}
}
function ftp_file_size($url) {
$request = [net.ftpwebrequest]::create($url)
$request.method = [net.webrequestmethods+ftp]::getfilesize
$request.getresponse().contentlength
}
function url_filename($url) {
(Split-Path $url -Leaf).split('?') | Select-Object -First 1
}
function url_remote_filename($url) {
# Unlike url_filename which can be tricked by appending a
# URL fragment (e.g. #/dl.7z, useful for coercing a local filename),
# this function extracts the original filename from the URL.
$uri = (New-Object URI $url)
$basename = Split-Path $uri.PathAndQuery -Leaf
If ($basename -match '.*[?=]+([\w._-]+)') {
$basename = $matches[1]
}
If (($basename -notlike '*.*') -or ($basename -match '^[v.\d]+$')) {
$basename = Split-Path $uri.AbsolutePath -Leaf
}
If (($basename -notlike '*.*') -and ($uri.Fragment -ne '')) {
$basename = $uri.Fragment.Trim('/', '#')
}
return $basename
}
### Hash-related functions
function hash_for_url($manifest, $url, $arch) {
$hashes = @(hash $manifest $arch) | Where-Object { $_ -ne $null }
if ($hashes.length -eq 0) { return $null }
$urls = @(script:url $manifest $arch)
$index = [array]::IndexOf($urls, $url)
if ($index -eq -1) { abort "Couldn't find hash in manifest for '$url'." }
@($hashes)[$index]
}
function check_hash($file, $hash, $app_name) {
# returns (ok, err)
if (!$hash) {
warn "Warning: No hash in manifest. SHA256 for '$(fname $file)' is:`n $((Get-FileHash -Path $file -Algorithm SHA256).Hash.ToLower())"
return $true, $null
}
Write-Host 'Checking hash of ' -NoNewline
Write-Host $(url_remote_filename $url) -ForegroundColor Cyan -NoNewline
Write-Host ' ... ' -NoNewline
$algorithm, $expected = get_hash $hash
if ($null -eq $algorithm) {
return $false, "Hash type '$algorithm' isn't supported."
}
$actual = (Get-FileHash -Path $file -Algorithm $algorithm).Hash.ToLower()
$expected = $expected.ToLower()
if ($actual -ne $expected) {
$msg = "Hash check failed!`n"
$msg += "App: $app_name`n"
$msg += "URL: $url`n"
if (Test-Path $file) {
$msg += "First bytes: $((get_magic_bytes_pretty $file ' ').ToUpper())`n"
}
if ($expected -or $actual) {
$msg += "Expected: $expected`n"
$msg += "Actual: $actual"
}
return $false, $msg
}
Write-Host 'ok.' -f Green
return $true, $null
}
function get_hash([String] $multihash) {
$type, $hash = $multihash -split ':'
if (!$hash) {
# no type specified, assume sha256
$type, $hash = 'sha256', $multihash
}
if (@('md5', 'sha1', 'sha256', 'sha512') -notcontains $type) {
return $null, "Hash type '$type' isn't supported."
}
return $type, $hash.ToLower()
}
# Setup proxy globally
setup_proxy

View File

@@ -8,7 +8,12 @@
# array of strings that are long-form options. options that take
# a parameter should end with '='
# returns @(opts hash, remaining_args array, error string)
function getopt($argv, $shortopts, $longopts) {
# NOTES:
# The first "--" in $argv, if any, will terminate all options; any
# following arguments are treated as non-option arguments, even if
# they begin with a hyphen. The "--" itself will not be included in
# the returned $opts. (POSIX-compatible)
function getopt([String[]]$argv, [String]$shortopts, [String[]]$longopts) {
$opts = @{}; $rem = @()
function err($msg) {
@@ -16,29 +21,31 @@ function getopt($argv, $shortopts, $longopts) {
}
function regex_escape($str) {
return [regex]::escape($str)
return [Regex]::Escape($str)
}
# ensure these are arrays
$argv = @($argv)
$longopts = @($longopts)
for($i = 0; $i -lt $argv.length; $i++) {
for ($i = 0; $i -lt $argv.Length; $i++) {
$arg = $argv[$i]
if($null -eq $arg) { continue }
if ($null -eq $arg) { continue }
# don't try to parse array arguments
if($arg -is [array]) { $rem += ,$arg; continue }
if($arg -is [int]) { $rem += $arg; continue }
if($arg -is [decimal]) { $rem += $arg; continue }
if ($arg -is [Array]) { $rem += , $arg; continue }
if ($arg -is [Int]) { $rem += $arg; continue }
if ($arg -is [Decimal]) { $rem += $arg; continue }
if($arg.startswith('--')) {
$name = $arg.substring(2)
if ($arg -eq '--') {
if ($i -lt $argv.Length - 1) {
$rem += $argv[($i + 1)..($argv.Length - 1)]
}
break
} elseif ($arg.StartsWith('--')) {
$name = $arg.Substring(2)
$longopt = $longopts | Where-Object { $_ -match "^$name=?$" }
if($longopt) {
if($longopt.endswith('=')) { # requires arg
if($i -eq $argv.length - 1) {
if ($longopt) {
if ($longopt.EndsWith('=')) {
# requires arg
if ($i -eq $argv.Length - 1) {
return err "Option --$name requires an argument."
}
$opts.$name = $argv[++$i]
@@ -48,14 +55,14 @@ function getopt($argv, $shortopts, $longopts) {
} else {
return err "Option --$name not recognized."
}
} elseif($arg.startswith('-') -and $arg -ne '-') {
for($j = 1; $j -lt $arg.length; $j++) {
$letter = $arg[$j].tostring()
} elseif ($arg.StartsWith('-') -and $arg -ne '-') {
for ($j = 1; $j -lt $arg.Length; $j++) {
$letter = $arg[$j].ToString()
if($shortopts -match "$(regex_escape $letter)`:?") {
$shortopt = $matches[0]
if($shortopt[1] -eq ':') {
if($j -ne $arg.length -1 -or $i -eq $argv.length - 1) {
if ($shortopts -match "$(regex_escape $letter)`:?") {
$shortopt = $Matches[0]
if ($shortopt[1] -eq ':') {
if ($j -ne $arg.Length - 1 -or $i -eq $argv.Length - 1) {
return err "Option -$letter requires an argument."
}
$opts.$letter = $argv[++$i]
@@ -70,6 +77,5 @@ function getopt($argv, $shortopts, $longopts) {
$rem += $arg
}
}
$opts, $rem
}

View File

@@ -1,52 +0,0 @@
function git_proxy_cmd {
$proxy = get_config 'proxy'
$cmd = "git $($args | ForEach-Object { "$_ " })"
if($proxy -and $proxy -ne 'none') {
$cmd = "SET HTTPS_PROXY=$proxy&&SET HTTP_PROXY=$proxy&&$cmd"
}
& "$env:COMSPEC" /c $cmd
}
function git_clone {
git_proxy_cmd clone $args
}
function git_ls_remote {
git_proxy_cmd ls-remote $args
}
function git_checkout {
git_proxy_cmd checkout $args
}
function git_branch {
git_proxy_cmd branch $args
}
function git_pull {
git_proxy_cmd pull $args
}
function git_fetch {
git_proxy_cmd fetch $args
}
function git_log {
git_proxy_cmd --no-pager log $args
}
function git_checkout {
git_proxy_cmd checkout $args
}
function git_branch {
git_proxy_cmd branch $args
}
function git_config {
git_proxy_cmd config $args
}
function git_reset {
git_proxy_cmd reset $args
}

View File

@@ -6,7 +6,7 @@ function summary($text) {
$text | Select-String '(?m)^# Summary: ([^\n]*)$' | ForEach-Object { $_.matches[0].groups[1].value }
}
function help($text) {
function scoop_help($text) {
$help_lines = $text | Select-String '(?ms)^# Help:(.(?!^[^#]))*' | ForEach-Object { $_.matches[0].value; }
$help_lines -replace '(?ms)^#\s?(Help: )?', ''
}

File diff suppressed because it is too large Load Diff

View File

@@ -92,32 +92,36 @@ function ConvertToPrettyJson {
}
}
function json_path([String] $json, [String] $jsonpath, [Hashtable] $substitutions) {
Add-Type -Path "$psscriptroot\..\supporting\validator\bin\Newtonsoft.Json.dll"
function json_path([String] $json, [String] $jsonpath, [Hashtable] $substitutions, [Boolean] $reverse, [Boolean] $single) {
Add-Type -Path "$PSScriptRoot\..\supporting\validator\bin\Newtonsoft.Json.dll"
if ($null -ne $substitutions) {
$jsonpath = substitute $jsonpath $substitutions ($jsonpath -like "*=~*")
}
try {
$obj = [Newtonsoft.Json.Linq.JObject]::Parse($json)
$settings = New-Object -Type Newtonsoft.Json.JsonSerializerSettings
$settings.DateParseHandling = [Newtonsoft.Json.DateParseHandling]::None
$obj = [Newtonsoft.Json.JsonConvert]::DeserializeObject($json, $settings)
} catch [Newtonsoft.Json.JsonReaderException] {
try {
$obj = [Newtonsoft.Json.Linq.JArray]::Parse($json)
} catch [Newtonsoft.Json.JsonReaderException] {
return $null
}
}
try {
try {
$result = $obj.SelectToken($jsonpath, $true)
} catch [Newtonsoft.Json.JsonException] {
return $null
}
return $result.ToString()
} catch [System.Management.Automation.MethodInvocationException] {
write-host -f DarkRed $_
return $null
}
try {
$result = $obj.SelectTokens($jsonpath, $true)
if ($reverse) {
# Return versions in reverse order
$result = [System.Linq.Enumerable]::Reverse($result)
}
if ([System.Linq.Enumerable]::Count($result) -eq 1 -or $single) {
# Extract First value
$result = [System.Linq.Enumerable]::First($result)
# Convert first value to string
$result = $result.ToString()
} else {
$result = [Newtonsoft.Json.JsonConvert]::SerializeObject($result)
}
return $result
} catch [Exception] {
Write-Host $_ -ForegroundColor DarkRed
}
return $null
}
@@ -160,7 +164,7 @@ function normalize_values([psobject] $json) {
# Recursively edit psobjects
# If the values is psobjects, its not normalized
# For example if manifest have architecture and it's architecture have array with single value it's not formatted.
# @see https://github.com/lukesampson/scoop/pull/2642#issue-220506263
# @see https://github.com/ScoopInstaller/Scoop/pull/2642#issue-220506263
if ($_.Value -is [System.Management.Automation.PSCustomObject]) {
$_.Value = normalize_values $_.Value
}

View File

@@ -1,13 +1,14 @@
. "$psscriptroot/core.ps1"
. "$psscriptroot/autoupdate.ps1"
function manifest_path($app, $bucket) {
fullpath "$(Find-BucketDirectory $bucket)\$(sanitary_path $app).json"
(Get-ChildItem (Find-BucketDirectory $bucket) -Filter "$(sanitary_path $app).json" -Recurse).FullName
}
function parse_json($path) {
if(!(test-path $path)) { return $null }
Get-Content $path -raw -Encoding UTF8 | convertfrom-json -ea stop
if ($null -eq $path -or !(Test-Path $path)) { return $null }
try {
Get-Content $path -Raw -Encoding UTF8 | ConvertFrom-Json -ErrorAction Stop
} catch {
warn "Error parsing JSON at '$path'."
}
}
function url_manifest($url) {
@@ -15,26 +16,68 @@ function url_manifest($url) {
try {
$wc = New-Object Net.Webclient
$wc.Headers.Add('User-Agent', (Get-UserAgent))
$str = $wc.downloadstring($url)
$data = $wc.DownloadData($url)
$str = (Get-Encoding($wc)).GetString($data)
} catch [system.management.automation.methodinvocationexception] {
warn "error: $($_.exception.innerexception.message)"
} catch {
throw
}
if(!$str) { return $null }
$str | convertfrom-json
if (!$str) { return $null }
try {
$str | ConvertFrom-Json -ErrorAction Stop
} catch {
warn "Error parsing JSON at '$url'."
}
}
function Get-Manifest($app) {
$bucket, $manifest, $url = $null
$app = $app.TrimStart('/')
# check if app is a URL or UNC path
if ($app -match '^(ht|f)tps?://|\\\\') {
$url = $app
$app = appname_from_url $url
$manifest = url_manifest $url
} else {
$app, $bucket, $version = parse_app $app
if ($bucket) {
$manifest = manifest $app $bucket
} else {
foreach ($tekcub in Get-LocalBucket) {
$manifest = manifest $app $tekcub
if ($manifest) {
$bucket = $tekcub
break
}
}
}
if (!$manifest) {
# couldn't find app in buckets: check if it's a local path
if (Test-Path $app) {
$url = Convert-Path $app
$app = appname_from_url $url
$manifest = url_manifest $url
} else {
if (($app -match '\\/') -or $app.EndsWith('.json')) { $url = $app }
$app = appname_from_url $app
}
}
}
return $app, $manifest, $bucket, $url
}
function manifest($app, $bucket, $url) {
if($url) { return url_manifest $url }
if ($url) { return url_manifest $url }
parse_json (manifest_path $app $bucket)
}
function save_installed_manifest($app, $bucket, $dir, $url) {
if($url) {
if ($url) {
$wc = New-Object Net.Webclient
$wc.Headers.Add('User-Agent', (Get-UserAgent))
$wc.downloadstring($url) > "$dir\manifest.json"
$data = $wc.DownloadData($url)
(Get-Encoding($wc)).GetString($data) | Out-UTF8File "$dir\manifest.json"
} else {
Copy-Item (manifest_path $app $bucket) "$dir\manifest.json"
}
@@ -48,52 +91,72 @@ function save_install_info($info, $dir) {
$nulls = $info.keys | Where-Object { $null -eq $info[$_] }
$nulls | ForEach-Object { $info.remove($_) } # strip null-valued
$file_content = $info | ConvertToPrettyJson
$file_content = $info | ConvertToPrettyJson # in 'json.ps1'
[System.IO.File]::WriteAllLines("$dir\install.json", $file_content)
}
function install_info($app, $version, $global) {
$path = "$(versiondir $app $version $global)\install.json"
if(!(test-path $path)) { return $null }
if (!(Test-Path $path)) { return $null }
parse_json $path
}
function default_architecture {
if([intptr]::size -eq 8) { return "64bit" }
"32bit"
}
function arch_specific($prop, $manifest, $architecture) {
if($manifest.architecture) {
if ($manifest.architecture) {
$val = $manifest.architecture.$architecture.$prop
if($val) { return $val } # else fallback to generic prop
if ($val) { return $val } # else fallback to generic prop
}
if($manifest.$prop) { return $manifest.$prop }
if ($manifest.$prop) { return $manifest.$prop }
}
function supports_architecture($manifest, $architecture) {
return -not [String]::IsNullOrEmpty((arch_specific 'url' $manifest $architecture))
function Get-SupportedArchitecture($manifest, $architecture) {
if ($architecture -eq 'arm64' -and ($manifest | ConvertToPrettyJson) -notmatch '[''"]arm64["'']') {
# Windows 10 enables existing unmodified x86 apps to run on Arm devices.
# Windows 11 adds the ability to run unmodified x64 Windows apps on Arm devices!
# Ref: https://learn.microsoft.com/en-us/windows/arm/overview
if ($WindowsBuild -ge 22000) {
# Windows 11
$architecture = '64bit'
} else {
# Windows 10
$architecture = '32bit'
}
}
if (![String]::IsNullOrEmpty((arch_specific 'url' $manifest $architecture))) {
return $architecture
}
}
function generate_user_manifest($app, $bucket, $version) {
$null, $manifest, $bucket, $null = Find-Manifest $app $bucket
# 'autoupdate.ps1' 'buckets.ps1' 'manifest.ps1'
$app, $manifest, $bucket, $null = Get-Manifest "$bucket/$app"
if ("$($manifest.version)" -eq "$version") {
return manifest_path $app $bucket
}
warn "Given version ($version) does not match manifest ($($manifest.version))"
warn "Attempting to generate manifest for '$app' ($version)"
ensure (usermanifestsdir) | Out-Null
$manifest_path = "$(usermanifestsdir)\$app.json"
if (get_config USE_SQLITE_CACHE) {
$cached_manifest = (Get-ScoopDBItem -Name $app -Bucket $bucket -Version $version).manifest
if ($cached_manifest) {
$cached_manifest | Out-UTF8File $manifest_path
return $manifest_path
}
}
if (!($manifest.autoupdate)) {
abort "'$app' does not have autoupdate capability`r`ncouldn't find manifest for '$app@$version'"
}
ensure $(usermanifestsdir) | out-null
try {
autoupdate $app "$(resolve-path $(usermanifestsdir))" $manifest $version $(@{})
return "$(resolve-path $(usermanifest $app))"
Invoke-AutoUpdate $app $manifest_path $manifest $version $(@{ })
return $manifest_path
} catch {
write-host -f darkred "Could not install $app@$version"
Write-Host -ForegroundColor DarkRed "Could not install $app@$version"
}
return $null
@@ -102,7 +165,6 @@ function generate_user_manifest($app, $bucket, $version) {
function url($manifest, $arch) { arch_specific 'url' $manifest $arch }
function installer($manifest, $arch) { arch_specific 'installer' $manifest $arch }
function uninstaller($manifest, $arch) { arch_specific 'uninstaller' $manifest $arch }
function msi($manifest, $arch) { arch_specific 'msi' $manifest $arch }
function hash($manifest, $arch) { arch_specific 'hash' $manifest $arch }
function extract_dir($manifest, $arch) { arch_specific 'extract_dir' $manifest $arch}
function extract_to($manifest, $arch) { arch_specific 'extract_to' $manifest $arch}
function extract_dir($manifest, $arch) { arch_specific 'extract_dir' $manifest $arch }
function extract_to($manifest, $arch) { arch_specific 'extract_to' $manifest $arch }

View File

@@ -1,59 +1,54 @@
$modulesdir = "$scoopdir\modules"
function install_psmodule($manifest, $dir, $global) {
$psmodule = $manifest.psmodule
if(!$psmodule) { return }
if (!$psmodule) { return }
if($global) {
abort "Installing PowerShell modules globally is not implemented!"
}
$targetdir = ensure (modulesdir $global)
$modulesdir = ensure $modulesdir
ensure_in_psmodulepath $modulesdir $global
ensure_in_psmodulepath $targetdir $global
$module_name = $psmodule.name
if(!$module_name) {
if (!$module_name) {
abort "Invalid manifest: The 'name' property is missing from 'psmodule'."
}
$linkfrom = "$modulesdir\$module_name"
write-host "Installing PowerShell module '$module_name'"
$linkfrom = "$targetdir\$module_name"
Write-Host "Installing PowerShell module '$module_name'"
write-host "Linking $(friendly_path $linkfrom) => $(friendly_path $dir)"
Write-Host "Linking $(friendly_path $linkfrom) => $(friendly_path $dir)"
if(test-path $linkfrom) {
if (Test-Path $linkfrom) {
warn "$(friendly_path $linkfrom) already exists. It will be replaced."
& "$env:COMSPEC" /c "rmdir $linkfrom"
Remove-Item -Path $linkfrom -Force -Recurse -ErrorAction SilentlyContinue
}
& "$env:COMSPEC" /c "mklink /j $linkfrom $dir" | out-null
New-DirectoryJunction $linkfrom $dir | Out-Null
}
function uninstall_psmodule($manifest, $dir, $global) {
$psmodule = $manifest.psmodule
if(!$psmodule) { return }
if (!$psmodule) { return }
$module_name = $psmodule.name
write-host "Uninstalling PowerShell module '$module_name'."
Write-Host "Uninstalling PowerShell module '$module_name'."
$linkfrom = "$modulesdir\$module_name"
if(test-path $linkfrom) {
write-host "Removing $(friendly_path $linkfrom)"
$linkfrom = resolve-path $linkfrom
& "$env:COMSPEC" /c "rmdir $linkfrom"
$targetdir = modulesdir $global
$linkfrom = "$targetdir\$module_name"
if (Test-Path $linkfrom) {
Write-Host "Removing $(friendly_path $linkfrom)"
$linkfrom = Convert-Path $linkfrom
Remove-Item -Path $linkfrom -Force -Recurse -ErrorAction SilentlyContinue
}
}
function ensure_in_psmodulepath($dir, $global) {
$path = env 'psmodulepath' $global
if(!$global -and $null -eq $path) {
$path = Get-EnvVar -Name 'PSModulePath' -Global:$global
if (!$global -and $null -eq $path) {
$path = "$env:USERPROFILE\Documents\WindowsPowerShell\Modules"
}
$dir = fullpath $dir
if($path -notmatch [regex]::escape($dir)) {
write-output "Adding $(friendly_path $dir) to $(if($global){'global'}else{'your'}) PowerShell module path."
if ($path -notmatch [Regex]::Escape($dir)) {
Write-Output "Adding $(friendly_path $dir) to $(if($global){'global'}else{'your'}) PowerShell module path."
env 'psmodulepath' $global "$dir;$path" # for future sessions...
$env:psmodulepath = "$dir;$env:psmodulepath" # for this session
Set-EnvVar -Name 'PSModulePath' -Value "$dir;$path" -Global:$global
}
}

View File

@@ -5,34 +5,35 @@ function create_startmenu_shortcuts($manifest, $dir, $global, $arch) {
$target = [System.IO.Path]::Combine($dir, $_.item(0))
$target = New-Object System.IO.FileInfo($target)
$name = $_.item(1)
$arguments = ""
$arguments = ''
$icon = $null
if($_.length -ge 3) {
if ($_.length -ge 3) {
$arguments = $_.item(2)
}
if($_.length -ge 4) {
if ($_.length -ge 4) {
$icon = [System.IO.Path]::Combine($dir, $_.item(3))
$icon = New-Object System.IO.FileInfo($icon)
}
$arguments = (substitute $arguments @{ '$dir' = $dir; '$original_dir' = $original_dir; '$persist_dir' = $persist_dir})
$arguments = (substitute $arguments @{ '$dir' = $dir; '$original_dir' = $original_dir; '$persist_dir' = $persist_dir })
startmenu_shortcut $target $name $arguments $icon $global
}
}
function shortcut_folder($global) {
$directory = [System.IO.Path]::Combine([Environment]::GetFolderPath('startmenu'), 'Programs', 'Scoop Apps')
if($global) {
$directory = [System.IO.Path]::Combine([Environment]::GetFolderPath('commonstartmenu'), 'Programs', 'Scoop Apps')
if ($global) {
$startmenu = 'CommonStartMenu'
} else {
$startmenu = 'StartMenu'
}
return $(ensure $directory)
return Convert-Path (ensure ([System.IO.Path]::Combine([Environment]::GetFolderPath($startmenu), 'Programs', 'Scoop Apps')))
}
function startmenu_shortcut([System.IO.FileInfo] $target, $shortcutName, $arguments, [System.IO.FileInfo]$icon, $global) {
if(!$target.Exists) {
if (!$target.Exists) {
Write-Host -f DarkRed "Creating shortcut for $shortcutName ($(fname $target)) failed: Couldn't find $target"
return
}
if($icon -and !$icon.Exists) {
if ($icon -and !$icon.Exists) {
Write-Host -f DarkRed "Creating shortcut for $shortcutName ($(fname $target)) failed: Couldn't find icon $icon"
return
}
@@ -50,11 +51,11 @@ function startmenu_shortcut([System.IO.FileInfo] $target, $shortcutName, $argume
if ($arguments) {
$wsShell.Arguments = $arguments
}
if($icon -and $icon.Exists) {
if ($icon -and $icon.Exists) {
$wsShell.IconLocation = $icon.FullName
}
$wsShell.Save()
write-host "Creating shortcut for $shortcutName ($(fname $target))"
Write-Host "Creating shortcut for $shortcutName ($(fname $target))"
}
# Removes the Startmenu shortcut if it exists
@@ -62,23 +63,10 @@ function rm_startmenu_shortcuts($manifest, $global, $arch) {
$shortcuts = @(arch_specific 'shortcuts' $manifest $arch)
$shortcuts | Where-Object { $_ -ne $null } | ForEach-Object {
$name = $_.item(1)
$shortcut = "$(shortcut_folder $global)\$name.lnk"
write-host "Removing shortcut $(friendly_path $shortcut)"
if(Test-Path -Path $shortcut) {
Remove-Item $shortcut
}
# Before issue 1514 Startmenu shortcut removal
#
# Shortcuts that should have been installed globally would
# have been installed locally up until 27 June 2017.
#
# TODO: Remove this 'if' block and comment after
# 27 June 2018.
if($global) {
$shortcut = "$(shortcut_folder $false)\$name.lnk"
if(Test-Path -Path $shortcut) {
Remove-Item $shortcut
}
$shortcut = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath("$(shortcut_folder $global)\$name.lnk")
Write-Host "Removing shortcut $(friendly_path $shortcut)"
if (Test-Path -Path $shortcut) {
Remove-Item $shortcut
}
}
}

176
lib/system.ps1 Normal file
View File

@@ -0,0 +1,176 @@
# System-related functions
## Environment Variables
function Publish-EnvVar {
if (-not ('Win32.NativeMethods' -as [Type])) {
Add-Type -Namespace Win32 -Name NativeMethods -MemberDefinition @'
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr SendMessageTimeout(
IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam,
uint fuFlags, uint uTimeout, out UIntPtr lpdwResult
);
'@
}
$HWND_BROADCAST = [IntPtr] 0xffff
$WM_SETTINGCHANGE = 0x1a
$result = [UIntPtr]::Zero
[Win32.NativeMethods]::SendMessageTimeout($HWND_BROADCAST,
$WM_SETTINGCHANGE,
[UIntPtr]::Zero,
'Environment',
2,
5000,
[ref] $result
) | Out-Null
}
function Get-EnvVar {
param(
[string]$Name,
[switch]$Global
)
$registerKey = if ($Global) {
Get-Item -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager'
} else {
Get-Item -Path 'HKCU:'
}
$envRegisterKey = $registerKey.OpenSubKey('Environment')
$registryValueOption = [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames
$envRegisterKey.GetValue($Name, $null, $registryValueOption)
}
function Set-EnvVar {
param(
[string]$Name,
[string]$Value,
[switch]$Global
)
$registerKey = if ($Global) {
Get-Item -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager'
} else {
Get-Item -Path 'HKCU:'
}
$envRegisterKey = $registerKey.OpenSubKey('Environment', $true)
if ($null -eq $Value -or $Value -eq '') {
if ($envRegisterKey.GetValue($Name)) {
$envRegisterKey.DeleteValue($Name)
}
} else {
$registryValueKind = if ($Value.Contains('%')) {
[Microsoft.Win32.RegistryValueKind]::ExpandString
} elseif ($envRegisterKey.GetValue($Name)) {
$envRegisterKey.GetValueKind($Name)
} else {
[Microsoft.Win32.RegistryValueKind]::String
}
$envRegisterKey.SetValue($Name, $Value, $registryValueKind)
}
Publish-EnvVar
}
function Split-PathLikeEnvVar {
param(
[string[]]$Pattern,
[string]$Path
)
if ($null -eq $Path -and $Path -eq '') {
return $null, $null
} else {
$splitPattern = $Pattern.Split(';', [System.StringSplitOptions]::RemoveEmptyEntries)
$splitPath = $Path.Split(';', [System.StringSplitOptions]::RemoveEmptyEntries)
$inPath = @()
foreach ($p in $splitPattern) {
$inPath += $splitPath.Where({ $_ -like $p })
$splitPath = $splitPath.Where({ $_ -notlike $p })
}
return ($inPath -join ';'), ($splitPath -join ';')
}
}
function Add-Path {
param(
[string[]]$Path,
[string]$TargetEnvVar = 'PATH',
[switch]$Global,
[switch]$Force,
[switch]$Quiet
)
# future sessions
$inPath, $strippedPath = Split-PathLikeEnvVar $Path (Get-EnvVar -Name $TargetEnvVar -Global:$Global)
if (!$inPath -or $Force) {
if (!$Quiet) {
$Path | ForEach-Object {
Write-Host "Adding $(friendly_path $_) to $(if ($Global) {'global'} else {'your'}) path."
}
}
Set-EnvVar -Name $TargetEnvVar -Value ((@($Path) + $strippedPath) -join ';') -Global:$Global
}
# current session
$inPath, $strippedPath = Split-PathLikeEnvVar $Path $env:PATH
if (!$inPath -or $Force) {
$env:PATH = (@($Path) + $strippedPath) -join ';'
}
}
function Remove-Path {
param(
[string[]]$Path,
[string]$TargetEnvVar = 'PATH',
[switch]$Global,
[switch]$Quiet,
[switch]$PassThru
)
# future sessions
$inPath, $strippedPath = Split-PathLikeEnvVar $Path (Get-EnvVar -Name $TargetEnvVar -Global:$Global)
if ($inPath) {
if (!$Quiet) {
$Path | ForEach-Object {
Write-Host "Removing $(friendly_path $_) from $(if ($Global) {'global'} else {'your'}) path."
}
}
Set-EnvVar -Name $TargetEnvVar -Value $strippedPath -Global:$Global
}
# current session
$inSessionPath, $strippedPath = Split-PathLikeEnvVar $Path $env:PATH
if ($inSessionPath) {
$env:PATH = $strippedPath
}
if ($PassThru) {
return $inPath
}
}
## Deprecated functions
function env($name, $global, $val) {
if ($PSBoundParameters.ContainsKey('val')) {
Show-DeprecatedWarning $MyInvocation 'Set-EnvVar'
Set-EnvVar -Name $name -Value $val -Global:$global
} else {
Show-DeprecatedWarning $MyInvocation 'Get-EnvVar'
Get-EnvVar -Name $name -Global:$global
}
}
function strip_path($orig_path, $dir) {
Show-DeprecatedWarning $MyInvocation 'Split-PathLikeEnvVar'
Split-PathLikeEnvVar -Pattern @($dir) -Path $orig_path
}
function add_first_in_path($dir, $global) {
Show-DeprecatedWarning $MyInvocation 'Add-Path'
Add-Path -Path $dir -Global:$global -Force
}
function remove_from_path($dir, $global) {
Show-DeprecatedWarning $MyInvocation 'Remove-Path'
Remove-Path -Path $dir -Global:$global
}

View File

@@ -1,45 +0,0 @@
# Note: This file is for overwriting global variables and functions to make
# them unix compatible. It has to be imported after everything else!
function is_unix() { $PSVersionTable.Platform -eq 'Unix' }
function is_mac() { $PSVersionTable.OS.ToLower().StartsWith('darwin') }
function is_linux() { $PSVersionTable.OS.ToLower().StartsWith('linux') }
if(!(is_unix)) {
return # get the hell outta here
}
# core.ps1
$scoopdir = $env:SCOOP, (get_config 'rootPath'), (Join-Path $env:HOME "scoop") | Select-Object -first 1
$globaldir = $env:SCOOP_GLOBAL, (get_config 'globalPath'), "/usr/local/scoop" | Select-Object -first 1
$cachedir = $env:SCOOP_CACHE, (get_config 'cachePath'), (Join-Path $scoopdir "cache") | Select-Object -first 1
# core.ps1
function ensure($dir) {
mkdir -p $dir > $null
return resolve-path $dir
}
# install.ps1
function compute_hash($file, $algname) {
if(is_mac) {
switch ($algname)
{
"md5" { $result = (md5 -q $file) }
"sha1" { $result = (shasum -ba 1 $file) }
"sha256" { $result = (shasum -ba 256 $file) }
"sha512" { $result = (shasum -ba 512 $file) }
default { $result = (shasum -ba 256 $file) }
}
} else {
switch ($algname)
{
"md5" { $result = (md5sum -b $file) }
"sha1" { $result = (sha1sum -b $file) }
"sha256" { $result = (sha256sum -b $file) }
"sha512" { $result = (sha512sum -b $file) }
default { $result = (sha256sum -b $file) }
}
}
return $result.split(' ') | Select-Object -first 1
}

View File

@@ -1,53 +1,296 @@
# versions
function latest_version($app, $bucket, $url) {
(manifest $app $bucket $url).version
}
function current_version($app, $global) {
@(versions $app $global)[-1]
}
function versions($app, $global) {
$appdir = appdir $app $global
if(!(test-path $appdir)) { return @() }
sort_versions (Get-ChildItem $appdir -dir -attr !reparsePoint | Where-Object { $null -ne $(Get-ChildItem $_.fullname) } | ForEach-Object { $_.name })
}
function version($ver) {
$ver -split '[\.-]' | ForEach-Object {
$num = $_ -as [int]
if($num) { $num } else { $_ }
function Get-LatestVersion {
<#
.SYNOPSIS
Get latest version of app from manifest
.PARAMETER AppName
App's name
.PARAMETER Bucket
Bucket which the app belongs to
.PARAMETER Uri
Remote app manifest's URI
#>
[OutputType([String])]
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[Alias('App')]
[String]
$AppName,
[Parameter(Position = 1)]
[String]
$Bucket,
[Parameter(Position = 2)]
[String]
$Uri
)
process {
return (manifest $AppName $Bucket $Uri).version
}
}
function compare_versions($a, $b) {
$ver_a = @(version $a)
$ver_b = @(version $b)
for($i=0;$i -lt $ver_a.length;$i++) {
if($i -gt $ver_b.length) { return 1; }
function Select-CurrentVersion { # 'manifest.ps1'
<#
.SYNOPSIS
Select current version of installed app, from 'current\manifest.json' or modified time of version directory
.PARAMETER AppName
App's name
.PARAMETER Global
Globally installed application
#>
[OutputType([String])]
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[Alias('App')]
[String]
$AppName,
[Parameter(Position = 1)]
[Switch]
$Global
)
process {
$currentPath = "$(appdir $AppName $Global)\current"
if (!(get_config NO_JUNCTION)) {
$currentVersion = (parse_json "$currentPath\manifest.json").version
if ($currentVersion -eq 'nightly') {
$currentVersion = (Get-Item $currentPath).Target | Split-Path -Leaf
}
}
if ($null -eq $currentVersion) {
$installedVersion = Get-InstalledVersion -AppName $AppName -Global:$Global
if ($installedVersion) {
$currentVersion = @($installedVersion)[-1]
} else {
$currentVersion = $null
}
}
return $currentVersion
}
}
# don't try to compare int to string
if($ver_b[$i] -is [string] -and $ver_a[$i] -isnot [string]) {
$ver_a[$i] = "$($ver_a[$i])"
function Get-InstalledVersion {
<#
.SYNOPSIS
Get all installed version of app, by checking version directories' 'install.json'
.PARAMETER AppName
App's name
.PARAMETER Global
Globally installed application
.NOTES
Versions are sorted from oldest to newest, i.e., latest installed version is the last one in the output array.
If no installed version found, empty array will be returned.
#>
[OutputType([Object[]])]
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[Alias('App')]
[String]
$AppName,
[Parameter(Position = 1)]
[Switch]
$Global
)
process {
$appPath = appdir $AppName $Global
if (Test-Path $appPath) {
$versions = @((Get-ChildItem "$appPath\*\install.json" | Sort-Object -Property LastWriteTimeUtc).Directory.Name)
return $versions | Where-Object { ($_ -ne 'current') -and ($_ -notlike '_*.old*') }
} else {
return @()
}
}
# Deprecated
# sort_versions (Get-ChildItem $appPath -dir -attr !reparsePoint | Where-Object { $null -ne $(Get-ChildItem $_.FullName) } | ForEach-Object { $_.Name })
}
function Compare-Version {
<#
.SYNOPSIS
Compare versions, mainly according to SemVer's rules
.PARAMETER ReferenceVersion
Specifies a version used as a reference for comparison
.PARAMETER DifferenceVersion
Specifies the version that are compared to the reference version
.PARAMETER Delimiter
Specifies the delimiter of versions
.OUTPUTS
System.Int32
'0' if DifferenceVersion is equal to ReferenceVersion,
'1' if DifferenceVersion is greater then ReferenceVersion,
'-1' if DifferenceVersion is less then ReferenceVersion
#>
[OutputType([Int32])]
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, Position = 0)]
[AllowEmptyString()]
[String]
$ReferenceVersion,
[Parameter(Mandatory = $true, Position = 1, ValueFromPipeline = $true)]
[AllowEmptyString()]
[String]
$DifferenceVersion,
[String]
$Delimiter = '-'
)
process {
# Use '+' sign as post-release, see https://github.com/ScoopInstaller/Scoop/pull/3721#issuecomment-553718093
$ReferenceVersion, $DifferenceVersion = @($ReferenceVersion, $DifferenceVersion) -replace '\+', '-'
# Return 0 if versions are equal
if ($DifferenceVersion -eq $ReferenceVersion) {
return 0
}
if($ver_a[$i] -gt $ver_b[$i]) { return 1; }
if($ver_a[$i] -lt $ver_b[$i]) { return -1; }
# Preprocess versions (split, convert and separate)
$splitReferenceVersion = @(SplitVersion -Version $ReferenceVersion -Delimiter $Delimiter)
$splitDifferenceVersion = @(SplitVersion -Version $DifferenceVersion -Delimiter $Delimiter)
# Nightly versions are always equal unless UPDATE_NIGHTLY is $true
if ($splitReferenceVersion[0] -eq 'nightly' -and $splitDifferenceVersion[0] -eq 'nightly') {
if (get_config UPDATE_NIGHTLY) {
# nightly versions will be compared by date if UPDATE_NIGHTLY is $true
if ($null -eq $splitReferenceVersion[1]) {
$splitReferenceVersion += Get-Date -Format 'yyyyMMdd'
}
if ($null -eq $splitDifferenceVersion[1]) {
$splitDifferenceVersion += Get-Date -Format 'yyyyMMdd'
}
return [Math]::Sign($splitDifferenceVersion[1] - $splitReferenceVersion[1])
} else {
return 0
}
}
for ($i = 0; $i -lt [Math]::Max($splitReferenceVersion.Length, $splitDifferenceVersion.Length); $i++) {
# '1.1-alpha' is less then '1.1'
if ($i -ge $splitReferenceVersion.Length) {
if ($splitDifferenceVersion[$i] -match 'alpha|beta|rc|pre') {
return -1
} else {
return 1
}
}
# '1.1' is greater then '1.1-beta'
if ($i -ge $splitDifferenceVersion.Length) {
if ($splitReferenceVersion[$i] -match 'alpha|beta|rc|pre') {
return 1
} else {
return -1
}
}
# If some parts of versions have '.', compare them with delimiter '.'
if (($splitReferenceVersion[$i] -match '\.') -or ($splitDifferenceVersion[$i] -match '\.')) {
$Result = Compare-Version -ReferenceVersion $splitReferenceVersion[$i] -DifferenceVersion $splitDifferenceVersion[$i] -Delimiter '.'
# If the parts are equal, continue to next part, otherwise return
if ($Result -ne 0) {
return $Result
} else {
continue
}
}
# If some parts of versions have '_', compare them with delimiter '_'
if (($splitReferenceVersion[$i] -match '_') -or ($splitDifferenceVersion[$i] -match '_')) {
$Result = Compare-Version -ReferenceVersion $splitReferenceVersion[$i] -DifferenceVersion $splitDifferenceVersion[$i] -Delimiter '_'
# If the parts are equal, continue to next part, otherwise return
if ($Result -ne 0) {
return $Result
} else {
continue
}
}
# Don't try to compare [Long] to [String]
if ($null -ne $splitReferenceVersion[$i] -and $null -ne $splitDifferenceVersion[$i]) {
if ($splitReferenceVersion[$i] -is [String] -and $splitDifferenceVersion[$i] -isnot [String]) {
$splitDifferenceVersion[$i] = "$($splitDifferenceVersion[$i])"
}
if ($splitDifferenceVersion[$i] -is [String] -and $splitReferenceVersion[$i] -isnot [String]) {
$splitReferenceVersion[$i] = "$($splitReferenceVersion[$i])"
}
}
# Compare [String] or [Long]
if ($splitDifferenceVersion[$i] -gt $splitReferenceVersion[$i]) {
return 1
}
if ($splitDifferenceVersion[$i] -lt $splitReferenceVersion[$i]) {
return -1
}
}
}
if($ver_b.length -gt $ver_a.length) { return -1 }
return 0
}
# Helper function
function SplitVersion {
<#
.SYNOPSIS
Split version by Delimiter, convert number string to number, and separate letters from numbers
.PARAMETER Version
Specifies a version
.PARAMETER Delimiter
Specifies the delimiter of version (Literal)
#>
[OutputType([Object[]])]
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[AllowEmptyString()]
[String]
$Version,
[String]
$Delimiter = '-'
)
process {
$Version = $Version -replace '[a-zA-Z]+', "$Delimiter$&$Delimiter"
return ($Version -split [Regex]::Escape($Delimiter) -ne '' | ForEach-Object { if ($_ -match '^\d+$') { [Long]$_ } else { $_ } })
}
}
# Deprecated
# Not used anymore in scoop core
function qsort($ary, $fn) {
if($null -eq $ary) { return @() }
if(!($ary -is [array])) { return @($ary) }
warn '"qsort" is deprecated. Please avoid using it anymore.'
if ($null -eq $ary) { return @() }
if (!($ary -is [array])) { return @($ary) }
$pivot = $ary[0]
$rem = $ary[1..($ary.length-1)]
$rem = $ary[1..($ary.length - 1)]
$lesser = qsort ($rem | Where-Object { (& $fn $_ $pivot) -lt 0 }) $fn
$lesser = qsort ($rem | Where-Object { (& $fn $pivot $_) -lt 0 }) $fn
$greater = qsort ($rem | Where-Object { (& $fn $_ $pivot) -ge 0 }) $fn
$greater = qsort ($rem | Where-Object { (& $fn $pivot $_) -ge 0 }) $fn
return @() + $lesser + @($pivot) + $greater
}
function sort_versions($versions) { qsort $versions compare_versions }
# Deprecated
# Not used anymore in scoop core
function sort_versions($versions) {
warn '"sort_versions" is deprecated. Please avoid using it anymore.'
qsort $versions Compare-Version
}
function compare_versions($a, $b) {
Show-DeprecatedWarning $MyInvocation 'Compare-Version'
# Please note the parameters' sequence
return Compare-Version -ReferenceVersion $b -DifferenceVersion $a
}
function latest_version($app, $bucket, $url) {
Show-DeprecatedWarning $MyInvocation 'Get-LatestVersion'
return Get-LatestVersion -AppName $app -Bucket $bucket -Uri $url
}
function current_version($app, $global) {
Show-DeprecatedWarning $MyInvocation 'Select-CurrentVersion'
return Select-CurrentVersion -AppName $app -Global:$global
}
function versions($app, $global) {
Show-DeprecatedWarning $MyInvocation 'Get-InstalledVersion'
return Get-InstalledVersion -AppName $app -Global:$global
}

View File

@@ -1,116 +1,68 @@
# Usage: scoop alias add|list|rm [<args>]
# Usage: scoop alias <subcommand> [options] [<args>]
# Summary: Manage scoop aliases
# Help: Add, remove or list Scoop aliases
# Help: Available subcommands: add, rm, list.
#
# Aliases are custom Scoop subcommands that can be created to make common tasks
# easier.
# Aliases are custom Scoop subcommands that can be created to make common tasks easier.
#
# To add an Alias:
# scoop alias add <name> <command> <description>
# To add an alias:
#
# e.g.:
# scoop alias add rm 'scoop uninstall $args[0]' 'Uninstalls an app'
# scoop alias add upgrade 'scoop update *' 'Updates all apps, just like brew or apt'
# scoop alias add <name> <command> [<description>]
#
# e.g.,
#
# scoop alias add rm 'scoop uninstall $args[0]' 'Uninstall an app'
# scoop alias add upgrade 'scoop update *' 'Update all apps, just like "brew" or "apt"'
#
# To remove an alias:
#
# scoop alias rm <name>
#
# To list all aliases:
#
# scoop alias list [-v|--verbose]
#
# Options:
# -v, --verbose Show alias description and table headers (works only for 'list')
# -v, --verbose Show alias description and table headers (works only for "list")
param(
[String]$opt,
[String]$name,
[String]$command,
[String]$description,
[Switch]$verbose = $false
)
param($SubCommand)
. "$psscriptroot\..\lib\core.ps1"
. "$psscriptroot\..\lib\help.ps1"
. "$psscriptroot\..\lib\install.ps1"
. "$PSScriptRoot\..\lib\getopt.ps1"
$script:config_alias = "alias"
function init_alias_config {
$aliases = get_config $script:config_alias
if(!$aliases) {
$aliases = @{}
}
return $aliases
}
function add_alias($name, $command) {
if(!$command) {
abort "Can't create an empty alias."
}
# get current aliases from config
$aliases = init_alias_config
if($aliases.$name) {
abort "Alias $name already exists."
}
$alias_file = "scoop-$name"
# generate script
$shimdir = shimdir $false
$script =
@"
# Summary: $description
$command
"@
$script | out-file "$shimdir\$alias_file.ps1" -encoding utf8
# add alias to config
$aliases | Add-Member -MemberType NoteProperty -Name $name -Value $alias_file
set_config $script:config_alias $aliases | Out-Null
}
function rm_alias($name) {
$aliases = init_alias_config
if(!$name) {
abort "Which alias should be removed?"
}
if($aliases.$name) {
"Removing alias $name..."
rm_shim $aliases.$name (shimdir $false)
$aliases.PSObject.Properties.Remove($name)
set_config $script:config_alias $aliases | Out-Null
$SubCommands = @('add', 'rm', 'list')
if ($SubCommand -notin $SubCommands) {
if (!$SubCommand) {
error '<subcommand> missing'
} else {
abort "Alias $name doesn't exist."
error "'$SubCommand' is not one of available subcommands: $($SubCommands -join ', ')"
}
my_usage
exit 1
}
function list_aliases {
$aliases = @()
$opt, $other, $err = getopt $Args 'v' 'verbose'
if ($err) { "scoop alias: $err"; exit 1 }
(init_alias_config).PSObject.Properties.GetEnumerator() | ForEach-Object {
$content = Get-Content (command_path $_.Name)
$command = ($content | Select-Object -Skip 1).Trim()
$summary = (summary $content).Trim()
$name, $command, $description = $other
$verbose = $opt.v -or $opt.verbose
$aliases += New-Object psobject -Property @{Name=$_.name; Summary=$summary; Command=$command}
switch ($SubCommand) {
'add' {
if (!$name -or !$command) {
error "<name> and <command> must be specified for subcommand 'add'"
exit 1
}
add_alias $name $command $description
}
if(!$aliases.count) {
warn "No aliases founds."
'rm' {
if (!$name) {
error "<name> must be specified for subcommand 'rm'"
exit 1
}
rm_alias $name
}
$aliases = $aliases.GetEnumerator() | Sort-Object Name
if($verbose) {
return $aliases | Select-Object Name, Command, Summary | Format-Table -autosize -wrap
} else {
return $aliases | Select-Object Name, Command | Format-Table -autosize -hidetablehead -wrap
'list' {
list_aliases $verbose
}
}
switch($opt) {
"add" { add_alias $name $command }
"rm" { rm_alias $name }
"list" { list_aliases }
default { my_usage; exit 1 }
}
exit 0

View File

@@ -10,7 +10,7 @@
# scoop bucket add <name> [<repo>]
#
# e.g.:
# scoop bucket add extras https://github.com/lukesampson/scoop-extras.git
# scoop bucket add extras https://github.com/ScoopInstaller/Extras.git
#
# Since the 'extras' bucket is known to Scoop, this can be shortened to:
# scoop bucket add extras
@@ -19,22 +19,62 @@
# scoop bucket known
param($cmd, $name, $repo)
. "$psscriptroot\..\lib\core.ps1"
. "$psscriptroot\..\lib\buckets.ps1"
. "$psscriptroot\..\lib\help.ps1"
. "$psscriptroot\..\lib\git.ps1"
reset_aliases
$usage_add = "usage: scoop bucket add <name> [<repo>]"
$usage_rm = "usage: scoop bucket rm <name>"
switch($cmd) {
'add' { add_bucket $name $repo }
'rm' { rm_bucket $name }
'list' { Get-LocalBucket }
'known' { known_buckets }
default { "scoop bucket: cmd '$cmd' not supported"; my_usage; exit 1 }
if (get_config NO_JUNCTION) {
. "$PSScriptRoot\..\lib\versions.ps1"
}
exit 0
if (get_config USE_SQLITE_CACHE) {
. "$PSScriptRoot\..\lib\manifest.ps1"
. "$PSScriptRoot\..\lib\database.ps1"
}
$usage_add = 'usage: scoop bucket add <name> [<repo>]'
$usage_rm = 'usage: scoop bucket rm <name>'
switch ($cmd) {
'add' {
if (!$name) {
'<name> missing'
$usage_add
exit 1
}
if (!$repo) {
$repo = known_bucket_repo $name
if (!$repo) {
"Unknown bucket '$name'. Try specifying <repo>."
$usage_add
exit 1
}
}
$status = add_bucket $name $repo
exit $status
}
'rm' {
if (!$name) {
'<name> missing'
$usage_rm
exit 1
}
$status = rm_bucket $name
exit $status
}
'list' {
$buckets = list_buckets
if (!$buckets.Length) {
warn "No bucket found. Please run 'scoop bucket add main' to add the default 'main' bucket."
exit 2
} else {
$buckets
exit 0
}
}
'known' {
known_buckets
exit 0
}
default {
"scoop bucket: cmd '$cmd' not supported"
my_usage
exit 1
}
}

View File

@@ -1,4 +1,4 @@
# Usage: scoop cache show|rm [app]
# Usage: scoop cache show|rm [app(s)]
# Summary: Show or clear the download cache
# Help: Scoop caches downloads so you don't need to download the same files
# when you uninstall and re-install the same version of an app.
@@ -10,48 +10,63 @@
#
# To clear everything in your cache, use:
# scoop cache rm *
param($cmd, $app)
# You can also use the `-a/--all` switch in place of `*` here
. "$psscriptroot\..\lib\help.ps1"
reset_aliases
param($cmd)
function cacheinfo($file) {
$app, $version, $url = $file.name -split '#'
$size = filesize $file.length
return new-object psobject -prop @{ app=$app; version=$version; url=$url; size=$size }
$app, $version, $url = $file.Name -split '#'
New-Object PSObject -Property @{ Name = $app; Version = $version; Length = $file.Length }
}
function show($app) {
$files = @(Get-ChildItem "$cachedir" | Where-Object { $_.name -match "^$app" })
$total_length = ($files | Measure-Object length -sum).sum -as [double]
function cacheshow($app) {
if (!$app -or $app -eq '*') {
$app = '.*?'
} else {
$app = '(' + ($app -join '|') + ')'
}
$files = @(Get-ChildItem $cachedir | Where-Object -Property Name -Value "^$app#" -Match)
$totalLength = ($files | Measure-Object -Property Length -Sum).Sum
$f_app = @{ expression={"$($_.app) ($($_.version))" }}
$f_url = @{ expression={$_.url};alignment='right'}
$f_size = @{ expression={$_.size}; alignment='right'}
$files | ForEach-Object { cacheinfo $_ } | Select-Object Name, Version, Length
Write-Host "Total: $($files.Length) $(pluralize $files.Length 'file' 'files'), $(filesize $totalLength)" -ForegroundColor Yellow
}
$files | ForEach-Object { cacheinfo $_ } | Format-Table $f_size, $f_app, $f_url -auto -hide
function cacheremove($app) {
if (!$app) {
'ERROR: <app(s)> missing'
my_usage
exit 1
} elseif ($app -eq '*' -or $app -eq '-a' -or $app -eq '--all') {
$files = @(Get-ChildItem $cachedir)
} else {
$app = '(' + ($app -join '|') + ')'
$files = @(Get-ChildItem $cachedir | Where-Object -Property Name -Value "^$app#" -Match)
}
$totalLength = ($files | Measure-Object -Property Length -Sum).Sum
"Total: $($files.length) $(pluralize $files.length 'file' 'files'), $(filesize $total_length)"
$files | ForEach-Object {
$curr = cacheinfo $_
Write-Host "Removing $($_.Name)..."
Remove-Item $_.FullName
if(Test-Path "$cachedir\$($curr.Name).txt") {
Remove-Item "$cachedir\$($curr.Name).txt"
}
}
Write-Host "Deleted: $($files.Length) $(pluralize $files.Length 'file' 'files'), $(filesize $totalLength)" -ForegroundColor Yellow
}
switch($cmd) {
'rm' {
if(!$app) { 'ERROR: <app> missing'; my_usage; exit 1 }
Remove-Item "$cachedir\$app#*"
if(test-path("$cachedir\$app.txt")) {
Remove-Item "$cachedir\$app.txt"
}
cacheremove $Args
}
'show' {
show $app
}
'' {
show
cacheshow $Args
}
default {
my_usage
cacheshow (@($cmd) + $Args)
}
}

27
libexec/scoop-cat.ps1 Normal file
View File

@@ -0,0 +1,27 @@
# Usage: scoop cat <app>
# Summary: Show content of specified manifest.
# Help: Show content of specified manifest.
# If configured, `bat` will be used to pretty-print the JSON.
# See `cat_style` in `scoop help config` for further information.
param($app)
. "$PSScriptRoot\..\lib\json.ps1" # 'ConvertToPrettyJson'
. "$PSScriptRoot\..\lib\manifest.ps1" # 'Get-Manifest'
if (!$app) { error '<app> missing'; my_usage; exit 1 }
$null, $manifest, $bucket, $url = Get-Manifest $app
if ($manifest) {
$style = get_config CAT_STYLE
if ($style) {
$manifest | ConvertToPrettyJson | bat --no-paging --style $style --language json
} else {
$manifest | ConvertToPrettyJson
}
} else {
abort "Couldn't find manifest for '$app'$(if($bucket) { " from '$bucket' bucket" } elseif($url) { " at '$url'" })."
}
exit $exitCode

View File

@@ -3,45 +3,54 @@
# Help: Performs a series of diagnostic tests to try to identify things that may
# cause problems with Scoop.
. "$psscriptroot\..\lib\core.ps1"
. "$psscriptroot\..\lib\diagnostic.ps1"
. "$PSScriptRoot\..\lib\diagnostic.ps1"
$issues = 0
$defenderIssues = 0
$adminPrivileges = ([System.Security.Principal.WindowsPrincipal] [System.Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
if ($adminPrivileges -and $env:USERNAME -ne 'WDAGUtilityAccount') {
$defenderIssues += !(check_windows_defender $false)
$defenderIssues += !(check_windows_defender $true)
}
$issues += !(check_windows_defender $false)
$issues += !(check_windows_defender $true)
$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'."
$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 require 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++
}
$globaldir = New-Object System.IO.DriveInfo($globaldir)
if($globaldir.DriveFormat -ne 'NTFS') {
error "Scoop requires an NTFS volume to work! Please point `$env:SCOOP_GLOBAL or 'globalPath' variable in '~/.config/scoop/config.json' to another Drive."
if ($globaldir.DriveFormat -ne 'NTFS') {
error "Scoop requires an NTFS volume to work! Please point `$env:SCOOP_GLOBAL or 'global_path' variable in '~/.config/scoop/config.json' to another Drive."
$issues++
}
$scoopdir = New-Object System.IO.DriveInfo($scoopdir)
if($scoopdir.DriveFormat -ne 'NTFS') {
error "Scoop requires an NTFS volume to work! Please point `$env:SCOOP or 'rootPath' variable in '~/.config/scoop/config.json' to another Drive."
if ($scoopdir.DriveFormat -ne 'NTFS') {
error "Scoop requires an NTFS volume to work! Please point `$env:SCOOP or 'root_path' variable in '~/.config/scoop/config.json' to another Drive."
$issues++
}
if($issues) {
if ($issues) {
warn "Found $issues potential $(pluralize $issues problem problems)."
} elseif ($defenderIssues) {
info "Found $defenderIssues performance $(pluralize $defenderIssues problem problems)."
warn "Security is more important than performance, in most cases."
} else {
success "No problems identified!"
}

View File

@@ -3,70 +3,78 @@
# Help: 'scoop cleanup' cleans Scoop apps by removing old versions.
# 'scoop cleanup <app>' cleans up the old versions of that app if said versions exist.
#
# You can use '*' in place of <app> to cleanup all apps.
# You can use '*' in place of <app> or `-a`/`--all` switch to cleanup all apps.
#
# Options:
# -a, --all Cleanup all apps (alternative to '*')
# -g, --global Cleanup a globally installed app
# -k, --cache Remove outdated download cache
. "$psscriptroot\..\lib\core.ps1"
. "$psscriptroot\..\lib\manifest.ps1"
. "$psscriptroot\..\lib\buckets.ps1"
. "$psscriptroot\..\lib\versions.ps1"
. "$psscriptroot\..\lib\getopt.ps1"
. "$psscriptroot\..\lib\help.ps1"
. "$psscriptroot\..\lib\install.ps1"
. "$PSScriptRoot\..\lib\getopt.ps1"
. "$PSScriptRoot\..\lib\manifest.ps1" # 'Select-CurrentVersion' (indirectly)
. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
. "$PSScriptRoot\..\lib\install.ps1" # persist related
reset_aliases
$opt, $apps, $err = getopt $args 'gk' 'global', 'cache'
$opt, $apps, $err = getopt $args 'agk' 'all', 'global', 'cache'
if ($err) { "scoop cleanup: $err"; exit 1 }
$global = $opt.g -or $opt.global
$cache = $opt.k -or $opt.cache
$all = $opt.a -or $opt.all
if (!$apps) { 'ERROR: <app> missing'; my_usage; exit 1 }
if (!$apps -and !$all) { 'ERROR: <app> missing'; my_usage; exit 1 }
if ($global -and !(is_admin)) {
'ERROR: you need admin rights to cleanup global apps'; exit 1
}
function cleanup($app, $global, $verbose, $cache) {
$current_version = current_version $app $global
$current_version = Select-CurrentVersion -AppName $app -Global:$global
if ($cache) {
Remove-Item "$cachedir\$app#*" -Exclude "$app#$current_version#*"
}
$versions = versions $app $global | Where-Object { $_ -ne $current_version -and $_ -ne 'current' }
$appDir = appdir $app $global
$versions = Get-ChildItem $appDir -Name
$versions = $versions | Where-Object { $current_version -ne $_ -and $_ -ne 'current' }
if (!$versions) {
if ($verbose) { success "$app is already clean" }
return
}
write-host -f yellow "Removing $app`:" -nonewline
Write-Host -f yellow "Removing $app`:" -NoNewline
$versions | ForEach-Object {
$version = $_
write-host " $version" -nonewline
Write-Host " $version" -NoNewline
$dir = versiondir $app $version $global
# unlink all potential old link before doing recursive Remove-Item
unlink_persist_data $dir
unlink_persist_data (installed_manifest $app $version $global) $dir
Remove-Item $dir -ErrorAction Stop -Recurse -Force
}
write-host ''
$leftVersions = Get-ChildItem $appDir
if ($leftVersions.Length -eq 1 -and $leftVersions.Name -eq 'current' -and $leftVersions.LinkType) {
attrib $leftVersions.FullName -R /L
Remove-Item $leftVersions.FullName -ErrorAction Stop -Force
$leftVersions = $null
}
if (!$leftVersions) {
Remove-Item $appDir -ErrorAction Stop -Force
}
Write-Host ''
}
if ($apps) {
$verbose = $true
if ($apps -eq '*') {
if ($apps -or $all) {
if ($apps -eq '*' -or $all) {
$verbose = $false
$apps = applist (installed_apps $false) $false
if ($global) {
$apps += applist (installed_apps $true) $true
}
} else {
$verbose = $true
$apps = Confirm-InstallationStatus $apps -Global:$global
}
# $apps is now a list of ($app, $global) tuples
$apps | ForEach-Object { cleanup @_ $verbose $cache}
$apps | ForEach-Object { cleanup @_ $verbose $cache }
if ($cache) {
Remove-Item "$cachedir\*.download" -ErrorAction Ignore

View File

@@ -1,6 +1,10 @@
# Usage: scoop config [rm] name [value]
# Summary: Get or set configuration values
# Help: The scoop configuration file is saved at ~/.scoop.
# Help: The scoop configuration file is saved at ~/.config/scoop/config.json.
#
# To get all configuration settings:
#
# scoop config
#
# To get a configuration setting:
#
@@ -17,36 +21,159 @@
# Settings
# --------
#
# use_external_7zip: $true|$false
# External 7zip (from path) will be used for archives extraction.
#
# use_lessmsi: $true|$false
# Prefer lessmsi utility over native msiexec.
#
# use_sqlite_cache: $true|$false
# Use SQLite database for caching. This is useful for speeding up 'scoop search' and 'scoop shim' commands.
#
# no_junction: $true|$false
# The 'current' version alias will not be used. Shims and shortcuts will point to specific version instead.
#
# scoop_repo: http://github.com/ScoopInstaller/Scoop
# Git repository containining scoop source code.
# This configuration is useful for custom forks.
#
# scoop_branch: master|develop
# Allow to use different branch than master.
# Could be used for testing specific functionalities before released into all users.
# If you want to receive updates earlier to test new functionalities use develop (see: 'https://github.com/ScoopInstaller/Scoop/issues/2939')
#
# proxy: [username:password@]host:port
# By default, Scoop will use the proxy settings from Internet Options, but with anonymous authentication.
#
# By default, Scoop will use the proxy settings from Internet Options, but with anonymous authentication.
# * To use the credentials for the current logged-in user, use 'currentuser' in place of username:password
# * To use the system proxy settings configured in Internet Options, use 'default' in place of host:port
# * An empty or unset value for proxy is equivalent to 'default' (with no username or password)
# * To bypass the system proxy and connect directly, use 'none' (with no username or password)
#
# * To use the credentials for the current logged-in user, use 'currentuser' in place of username:password
# * To use the system proxy settings configured in Internet Options, use 'default' in place of host:port
# * An empty or unset value for proxy is equivalent to 'default' (with no username or password)
# * To bypass the system proxy and connect directly, use 'none' (with no username or password)
# autostash_on_conflict: $true|$false
# When a conflict is detected during updating, Scoop will auto-stash the uncommitted changes.
# (Default is $false, which will abort the update)
#
# default_architecture: 64bit|32bit|arm64
# Allow to configure preferred architecture for application installation.
# If not specified, architecture is determined by system.
#
# debug: $true|$false
# Additional and detailed output will be shown.
#
# force_update: $true|$false
# Force apps updating to bucket's version.
#
# show_update_log: $true|$false
# Do not show changed commits on 'scoop update'
#
# show_manifest: $true|$false
# Displays the manifest of every app that's about to
# be installed, then asks user if they wish to proceed.
#
# shim: kiennq|scoopcs|71
# Choose scoop shim build.
#
# root_path: $Env:UserProfile\scoop
# Path to Scoop root directory.
#
# global_path: $Env:ProgramData\scoop
# Path to Scoop root directory for global apps.
#
# cache_path:
# For downloads, defaults to 'cache' folder under Scoop root directory.
#
# gh_token:
# GitHub API token used to make authenticated requests.
# This is essential for checkver and similar functions to run without
# incurring rate limits and download from private repositories.
#
# virustotal_api_key:
# API key used for uploading/scanning files using virustotal.
# See: 'https://support.virustotal.com/hc/en-us/articles/115002088769-Please-give-me-an-API-key'
#
# cat_style:
# When set to a non-empty string, Scoop will use 'bat' to display the manifest for
# the `scoop cat` command and while doing manifest review. This requires 'bat' to be
# installed (run `scoop install bat` to install it), otherwise errors will be thrown.
# The accepted values are the same as ones passed to the --style flag of 'bat'.
#
# ignore_running_processes: $true|$false
# When set to $false (default), Scoop would stop its procedure immediately if it detects
# any target app process is running. Procedure here refers to reset/uninstall/update.
# When set to $true, Scoop only displays a warning message and continues procedure.
#
# private_hosts:
# Array of private hosts that need additional authentication.
# For example, if you want to access a private GitHub repository,
# you need to add the host to this list with 'match' and 'headers' strings.
#
# hold_update_until:
# Disable/Hold Scoop self-updates, until the specified date.
# `scoop hold scoop` will set the value to one day later.
# Should be in the format 'YYYY-MM-DD', 'YYYY/MM/DD' or any other forms that accepted by '[System.DateTime]::Parse()'.
# Ref: https://docs.microsoft.com/dotnet/api/system.datetime.parse?view=netframework-4.5#StringToParse
#
# update_nightly: $true|$false
# Nightly version is formatted as 'nightly-yyyyMMdd' and will be updated after one day if this is set to $true.
# Otherwise, nightly version will not be updated unless `--force` is used.
#
# use_isolated_path: $true|$false|[string]
# When set to $true, Scoop will use `SCOOP_PATH` environment variable to store apps' `PATH`s.
# When set to arbitrary non-empty string, Scoop will use that string as the environment variable name instead.
# This is useful when you want to isolate Scoop from the system `PATH`.
#
# ARIA2 configuration
# -------------------
#
# aria2-enabled: $true|$false
# Aria2c will be used for downloading of artifacts.
#
# aria2-warning-enabled: $true|$false
# Disable Aria2c warning which is shown while downloading.
#
# aria2-retry-wait: 2
# Number of seconds to wait between retries.
# See: 'https://aria2.github.io/manual/en/html/aria2c.html#cmdoption-retry-wait'
#
# aria2-split: 5
# Number of connections used for downlaod.
# See: 'https://aria2.github.io/manual/en/html/aria2c.html#cmdoption-s'
#
# aria2-max-connection-per-server: 5
# The maximum number of connections to one server for each download.
# See: 'https://aria2.github.io/manual/en/html/aria2c.html#cmdoption-x'
#
# aria2-min-split-size: 5M
# Downloaded files will be splitted by this configured size and downloaded using multiple connections.
# See: 'https://aria2.github.io/manual/en/html/aria2c.html#cmdoption-k'
#
# aria2-options:
# Array of additional aria2 options.
# See: 'https://aria2.github.io/manual/en/html/aria2c.html#options'
param($name, $value)
. "$psscriptroot\..\lib\core.ps1"
. "$psscriptroot\..\lib\help.ps1"
reset_aliases
if(!$name) { my_usage; exit 1 }
if($name -like 'rm') {
if (!$name) {
$scoopConfig
} elseif ($name -like '--help') {
my_usage
} elseif ($name -like 'rm') {
set_config $value $null | Out-Null
Write-Output "'$name' has been removed"
} elseif($null -ne $value) {
Write-Host "'$value' has been removed"
} elseif ($null -ne $value) {
set_config $name $value | Out-Null
Write-Output "'$name' has been set to '$value'"
Write-Host "'$name' has been set to '$value'"
} else {
$value = get_config $name
if($null -eq $value) {
Write-Output "'$name' is not set"
Write-Host "'$name' is not set"
} else {
Write-Output $value
if ($value -is [System.DateTime]) {
$value.ToString('o')
} else {
$value
}
}
}

View File

@@ -11,29 +11,28 @@ function create_manifest($url) {
$url_parts = $null
try {
$url_parts = parse_url $url
}
catch {
} catch {
abort "Error: $url is not a valid URL"
}
$name = choose_item $url_parts "App name"
$name = choose_item $url_parts 'App name'
$name = if ($name.Length -gt 0) {
$name
}
else {
file_name ($url_parts | select-object -last 1)
} else {
file_name ($url_parts | Select-Object -Last 1)
}
$manifest.version = choose_item $url_parts "Version"
$manifest.version = choose_item $url_parts 'Version'
$manifest | convertto-json | out-file -filepath "$name.json" -encoding utf8
$manifest_path = join-path $pwd "$name.json"
write-host "Created '$manifest_path'."
$manifest | ConvertTo-Json | Out-File -FilePath "$name.json" -Encoding ASCII
$manifest_path = Join-Path $pwd "$name.json"
Write-Host "Created '$manifest_path'."
}
function new_manifest() {
@{ "homepage" = ""; "license" = ""; "version" = ""; "url" = "";
"hash" = ""; "extract_dir" = ""; "bin" = ""; "depends" = "" }
@{ 'homepage' = ''; 'license' = ''; 'version' = ''; 'url' = '';
'hash' = ''; 'extract_dir' = ''; 'bin' = ''; 'depends' = ''
}
}
function file_name($segment) {
@@ -41,28 +40,27 @@ function file_name($segment) {
}
function parse_url($url) {
$uri = new-object Uri $url
$uri.pathandquery.substring(1).split("/")
$uri = New-Object Uri $url
$uri.pathandquery.substring(1).split('/')
}
function choose_item($list, $query) {
for ($i = 0; $i -lt $list.count; $i++) {
$item = $list[$i]
write-host "$($i + 1)) $item"
Write-Host "$($i + 1)) $item"
}
$sel = read-host $query
$sel = Read-Host $query
if ($sel.trim() -match '^[0-9+]$') {
return $list[$sel-1]
return $list[$sel - 1]
}
$sel
}
if (!$url) {
scoop help create
}
else {
& "$PSScriptRoot\scoop-help.ps1" create
} else {
create_manifest $url
}

View File

@@ -1,31 +1,28 @@
# Usage: scoop depends <app>
# Summary: List dependencies for an app
# Summary: List dependencies for an app, in the order they'll be installed
. "$psscriptroot\..\lib\depends.ps1"
. "$psscriptroot\..\lib\install.ps1"
. "$psscriptroot\..\lib\manifest.ps1"
. "$psscriptroot\..\lib\buckets.ps1"
. "$psscriptroot\..\lib\getopt.ps1"
. "$psscriptroot\..\lib\decompress.ps1"
. "$psscriptroot\..\lib\help.ps1"
reset_aliases
. "$PSScriptRoot\..\lib\getopt.ps1"
. "$PSScriptRoot\..\lib\depends.ps1" # 'Get-Dependency'
. "$PSScriptRoot\..\lib\manifest.ps1" # 'Get-Manifest' (indirectly)
$opt, $apps, $err = getopt $args 'a:' 'arch='
$app = $apps[0]
if(!$app) { error '<app> missing'; my_usage; exit 1 }
$architecture = default_architecture
$architecture = Get-DefaultArchitecture
try {
$architecture = ensure_architecture ($opt.a + $opt.arch)
$architecture = Format-ArchitectureString ($opt.a + $opt.arch)
} catch {
abort "ERROR: $_"
}
$deps = @(deps $app $architecture)
if($deps) {
$deps[($deps.length - 1)..0]
$deps = @()
Get-Dependency $app $architecture | ForEach-Object {
$dep = [ordered]@{}
$dep.Source, $dep.Name = $_ -split '/'
$deps += [PSCustomObject]$dep
}
$deps
exit 0

142
libexec/scoop-download.ps1 Normal file
View File

@@ -0,0 +1,142 @@
# Usage: scoop download <app> [options]
# Summary: Download apps in the cache folder and verify hashes
# Help: e.g. The usual way to download an app, without installing it (uses your local 'buckets'):
# scoop download git
#
# To download a different version of the app
# (note that this will auto-generate the manifest using current version):
# scoop download gh@2.7.0
#
# To download an app from a manifest at a URL:
# scoop download https://raw.githubusercontent.com/ScoopInstaller/Main/master/bucket/runat.json
#
# To download an app from a manifest on your computer
# scoop download path\to\app.json
#
# Options:
# -f, --force Force download (overwrite cache)
# -s, --skip-hash-check Skip hash verification (use with caution!)
# -u, --no-update-scoop Don't update Scoop before downloading if it's outdated
# -a, --arch <32bit|64bit|arm64> Use the specified architecture, if the app supports it
. "$PSScriptRoot\..\lib\getopt.ps1"
. "$PSScriptRoot\..\lib\json.ps1" # 'autoupdate.ps1' (indirectly)
. "$PSScriptRoot\..\lib\autoupdate.ps1" # 'generate_user_manifest' (indirectly)
. "$PSScriptRoot\..\lib\manifest.ps1" # 'generate_user_manifest' 'Get-Manifest'
. "$PSScriptRoot\..\lib\download.ps1"
if (get_config USE_SQLITE_CACHE) {
. "$PSScriptRoot\..\lib\database.ps1"
}
$opt, $apps, $err = getopt $args 'fsua:' 'force', 'skip-hash-check', 'no-update-scoop', 'arch='
if ($err) { error "scoop download: $err"; exit 1 }
$check_hash = !($opt.s -or $opt.'skip-hash-check')
$use_cache = !($opt.f -or $opt.force)
$architecture = Get-DefaultArchitecture
try {
$architecture = Format-ArchitectureString ($opt.a + $opt.arch)
} catch {
abort "ERROR: $_"
}
if (!$apps) { error '<app> missing'; my_usage; exit 1 }
if (is_scoop_outdated) {
if ($opt.u -or $opt.'no-update-scoop') {
warn "Scoop is out of date."
} else {
& "$PSScriptRoot\scoop-update.ps1"
}
}
# we only want to show this warning once
if(!$use_cache) { warn "Cache is being ignored." }
foreach ($curr_app in $apps) {
# Prevent leaking variables from previous iteration
$bucket = $version = $app = $manifest = $url = $null
$app, $bucket, $version = parse_app $curr_app
$app, $manifest, $bucket, $url = Get-Manifest "$bucket/$app"
info "Downloading '$app'$(if ($version) { " ($version)" }) [$architecture]$(if ($bucket) { " from $bucket bucket" })"
# Generate manifest if there is different version in manifest
if (($null -ne $version) -and ($manifest.version -ne $version)) {
$generated = generate_user_manifest $app $bucket $version
if ($null -eq $generated) {
error 'Manifest cannot be generated with provided version'
continue
}
$manifest = parse_json($generated)
}
if(!$manifest) {
error "Couldn't find manifest for '$app'$(if($bucket) { " from '$bucket' bucket" } elseif($url) { " at '$url'" })."
continue
}
$version = $manifest.version
if(!$version) {
error "Manifest doesn't specify a version."
continue
}
if($version -match '[^\w\.\-\+_]') {
error "Manifest version has unsupported character '$($matches[0])'."
continue
}
$curr_check_hash = $check_hash
if ($version -eq 'nightly') {
$version = nightly_version
$curr_check_hash = $false
}
$architecture = Get-SupportedArchitecture $manifest $architecture
if ($null -eq $architecture) {
error "'$app' doesn't support current architecture!"
continue
}
if(Test-Aria2Enabled) {
Invoke-CachedAria2Download $app $version $manifest $architecture $cachedir $manifest.cookie $use_cache $curr_check_hash
} else {
foreach($url in script:url $manifest $architecture) {
try {
Invoke-CachedDownload $app $version $url $null $manifest.cookie $use_cache
} catch {
write-host -f darkred $_
error "URL $url is not valid"
$dl_failure = $true
continue
}
if($curr_check_hash) {
$manifest_hash = hash_for_url $manifest $url $architecture
$cached = cache_path $app $version $url
$ok, $err = check_hash $cached $manifest_hash (show_app $app $bucket)
if(!$ok) {
error $err
if(test-path $cached) {
# rm cached file
Remove-Item -force $cached
}
if ($url -like '*sourceforge.net*') {
warn 'SourceForge.net is known for causing hash validation fails. Please try again before opening a ticket.'
}
error (new_issue_msg $app $bucket "hash check failed")
continue
}
} else {
info "Skipping hash verification."
}
}
}
if (!$dl_failure) {
success "'$app' ($version) was downloaded successfully!"
}
}
exit 0

View File

@@ -1,60 +1,23 @@
# Usage: scoop export > filename
# Summary: Exports (an importable) list of installed apps
# Help: Lists all installed apps.
# Usage: scoop export > scoopfile.json
# Summary: Exports installed apps, buckets (and optionally configs) in JSON format
# Help: Options:
# -c, --config Export the Scoop configuration file too
. "$psscriptroot\..\lib\core.ps1"
. "$psscriptroot\..\lib\versions.ps1"
. "$psscriptroot\..\lib\manifest.ps1"
. "$psscriptroot\..\lib\buckets.ps1"
. "$PSScriptRoot\..\lib\json.ps1" # 'ConvertToPrettyJson'
reset_aliases
$def_arch = default_architecture
$export = @{}
$local = installed_apps $false | ForEach-Object { @{ name = $_; global = $false } }
$global = installed_apps $true | ForEach-Object { @{ name = $_; global = $true } }
$apps = @($local) + @($global)
$count = 0
# json
# echo "{["
if($apps) {
$apps | Sort-Object { $_.name } | Where-Object { !$query -or ($_.name -match $query) } | ForEach-Object {
$app = $_.name
$global = $_.global
$ver = current_version $app $global
$global_display = $null; if($global) { $global_display = ' *global*'}
$install_info = install_info $app $ver $global
$bucket = ''
if ($install_info.bucket) {
$bucket = ' [' + $install_info.bucket + ']'
} elseif ($install_info.url) {
$bucket = ' [' + $install_info.url + ']'
}
if ($install_info.architecture -and $def_arch -ne $install_info.architecture) {
$arch = ' {' + $install_info.architecture + '}'
} else {
$arch = ''
}
# json
# $val = "{ 'name': '$app', 'version': '$ver', 'global': $($global.toString().tolower()) }"
# if($count -gt 0) {
# " ," + $val
# } else {
# " " + $val
# }
# "$app (v:$ver) global:$($global.toString().tolower())"
"$app (v:$ver)$global_display$bucket$arch"
$count++
if ($args[0] -eq '-c' -or $args[0] -eq '--config') {
$export.config = $scoopConfig
# Remove machine-specific properties
foreach ($prop in 'last_update', 'root_path', 'global_path', 'cache_path', 'alias') {
$export.config.PSObject.Properties.Remove($prop)
}
}
# json
# echo "]}"
$export.buckets = list_buckets
$export.apps = @(& "$PSScriptRoot\scoop-list.ps1" 6>$null)
$export | ConvertToPrettyJSON
exit 0

View File

@@ -2,49 +2,43 @@
# Summary: Show help for a command
param($cmd)
. "$psscriptroot\..\lib\core.ps1"
. "$psscriptroot\..\lib\commands.ps1"
. "$psscriptroot\..\lib\help.ps1"
reset_aliases
function print_help($cmd) {
$file = Get-Content (command_path $cmd) -raw
$file = Get-Content (command_path $cmd) -Raw
$usage = usage $file
$summary = summary $file
$help = help $file
$help = scoop_help $file
if($usage) { "$usage`n" }
if($help) { $help }
if ($usage) { "$usage`n" }
if ($help) { $help }
}
function print_summaries {
$commands = @{}
$commands = @()
command_files | ForEach-Object {
$command = command_name $_
$summary = summary (Get-Content (command_path $command) -raw)
if(!($summary)) { $summary = '' }
$commands.add("$command ", $summary) # add padding
$command = [ordered]@{}
$command.Command = command_name $_
$command.Summary = summary (Get-Content (command_path $command.Command))
$commands += [PSCustomObject]$command
}
$commands.getenumerator() | Sort-Object name | Format-Table -hidetablehead -autosize -wrap
$commands
}
$commands = commands
if(!($cmd)) {
"Usage: scoop <command> [<args>]
Write-Host "Usage: scoop <command> [<args>]
Some useful commands are:"
Available commands are listed below.
Type 'scoop help <command>' to get more help for a specific command."
print_summaries
"Type 'scoop help <command>' to get help for a specific command."
} elseif($commands -contains $cmd) {
print_help $cmd
} else {
"scoop help: no such command '$cmd'"; exit 1
warn "scoop help: no such command '$cmd'"
exit 1
}
exit 0

View File

@@ -1,33 +1,71 @@
# Usage: scoop hold <apps>
# Summary: Hold an app to disable updates
# Help: To hold a user-scoped app:
# scoop hold <app>
#
# To hold a global app:
# scoop hold -g <app>
#
# Options:
# -g, --global Hold globally installed apps
. "$psscriptroot\..\lib\help.ps1"
. "$psscriptroot\..\lib\manifest.ps1"
. "$PSScriptRoot\..\lib\getopt.ps1"
. "$PSScriptRoot\..\lib\json.ps1" # 'save_install_info' (indirectly)
. "$PSScriptRoot\..\lib\manifest.ps1" # 'install_info' 'Select-CurrentVersion' (indirectly)
. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
reset_aliases
$apps = $args
$opt, $apps, $err = getopt $args 'g' 'global'
if ($err) { "scoop hold: $err"; exit 1 }
if(!$apps) {
$global = $opt.g -or $opt.global
if (!$apps) {
my_usage
exit 1
}
$apps | ForEach-Object {
$app = $_
$global = installed $app $true
if ($global -and !(is_admin)) {
error 'You need admin rights to hold a global app.'
exit 1
}
if (!(installed $app)) {
error "'$app' is not installed."
return
foreach ($app in $apps) {
if ($app -eq 'scoop') {
$hold_update_until = [System.DateTime]::Now.AddDays(1)
set_config HOLD_UPDATE_UNTIL $hold_update_until.ToString('o') | Out-Null
success "$app is now held and might not be updated until $($hold_update_until.ToLocalTime())."
continue
}
if (!(installed $app $global)) {
if ($global) {
error "'$app' is not installed globally."
} else {
error "'$app' is not installed."
}
continue
}
$dir = versiondir $app 'current' $global
$json = install_info $app 'current' $global
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))}
$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 locked and can not be updated anymore."
success "$app is now held and can not be updated anymore."
}
exit $exitcode

View File

@@ -2,24 +2,22 @@
# Summary: Opens the app homepage
param($app)
. "$psscriptroot\..\lib\core.ps1"
. "$psscriptroot\..\lib\help.ps1"
. "$psscriptroot\..\lib\manifest.ps1"
. "$psscriptroot\..\lib\buckets.ps1"
. "$PSScriptRoot\..\lib\manifest.ps1" # 'Get-Manifest'
reset_aliases
if($app) {
$manifest, $bucket = find_manifest $app
if($manifest) {
if([string]::isnullorempty($manifest.homepage)) {
if ($app) {
$null, $manifest, $bucket, $null = Get-Manifest $app
if ($manifest) {
if ($manifest.homepage) {
Start-Process $manifest.homepage
} else {
abort "Could not find homepage in manifest for '$app'."
}
Start-Process $manifest.homepage
}
else {
} else {
abort "Could not find manifest for '$app'."
}
} else { my_usage }
} else {
my_usage
exit 1
}
exit 0

65
libexec/scoop-import.ps1 Normal file
View File

@@ -0,0 +1,65 @@
# Usage: scoop import <path/url to scoopfile.json>
# Summary: Imports apps, buckets and configs from a Scoopfile in JSON format
# Help: To replicate a Scoop installation from a file stored on Desktop, run
# scoop import Desktop\scoopfile.json
param(
[Parameter(Mandatory)]
[String]
$scoopfile
)
. "$PSScriptRoot\..\lib\manifest.ps1"
$import = $null
$bucket_names = @()
$def_arch = Get-DefaultArchitecture
if (Test-Path $scoopfile) {
$import = parse_json $scoopfile
} elseif ($scoopfile -match '^(ht|f)tps?://|\\\\') {
$import = url_manifest $scoopfile
}
if (!$import) { abort 'Input file not a valid JSON.' }
foreach ($item in $import.config.PSObject.Properties) {
set_config $item.Name $item.Value | Out-Null
Write-Host "'$($item.Name)' has been set to '$($item.Value)'"
}
foreach ($item in $import.buckets) {
add_bucket $item.Name $item.Source | Out-Null
$bucket_names += $item.Name
}
foreach ($item in $import.apps) {
$instArgs = @()
$holdArgs = @()
$info = $item.Info -Split ', '
if ('Global install' -in $info) {
$instArgs += '--global'
$holdArgs += '--global'
}
if ('64bit' -in $info -and '64bit' -ne $def_arch) {
$instArgs += '--arch', '64bit'
} elseif ('32bit' -in $info -and '32bit' -ne $def_arch) {
$instArgs += '--arch', '32bit'
} elseif ('arm64' -in $info -and 'arm64' -ne $def_arch) {
$instArgs += '--arch', 'arm64'
}
$app = if ($item.Source -in $bucket_names) {
"$($item.Source)/$($item.Name)"
} elseif ($item.Source -eq '<auto-generated>') {
"$($item.Name)@$($item.Version)"
} else {
$item.Source
}
& "$PSScriptRoot\scoop-install.ps1" $app @instArgs
if ('Held package' -in $info) {
& "$PSScriptRoot\scoop-hold.ps1" $item.Name @holdArgs
}
}

View File

@@ -1,139 +1,246 @@
# Usage: scoop info <app>
# Usage: scoop info <app> [options]
# Summary: Display information about an app
param($app)
# Help: Options:
# -v, --verbose Show full paths and URLs
. "$psscriptroot\..\lib\buckets.ps1"
. "$psscriptroot\..\lib\core.ps1"
. "$psscriptroot\..\lib\depends.ps1"
. "$psscriptroot\..\lib\help.ps1"
. "$psscriptroot\..\lib\install.ps1"
. "$psscriptroot\..\lib\manifest.ps1"
. "$psscriptroot\..\lib\versions.ps1"
. "$PSScriptRoot\..\lib\getopt.ps1"
. "$PSScriptRoot\..\lib\manifest.ps1" # 'Get-Manifest'
. "$PSScriptRoot\..\lib\versions.ps1" # 'Get-InstalledVersion'
. "$PSScriptRoot\..\lib\download.ps1" # 'Get-RemoteFileSize'
reset_aliases
$opt, $app, $err = getopt $args 'v' 'verbose'
if ($err) { error "scoop info: $err"; exit 1 }
$verbose = $opt.v -or $opt.verbose
if(!$app) { my_usage; exit 1 }
if (!$app) { my_usage; exit 1 }
if ($app -match '^(ht|f)tps?://|\\\\') {
# check if $app is a URL or UNC path
$url = $app
$app = appname_from_url $url
$global = installed $app $true
$status = app_status $app $global
$manifest = url_manifest $url
$manifest_file = $url
} else {
# else $app is a normal app name
$global = installed $app $true
$app, $bucket, $null = parse_app $app
$status = app_status $app $global
$manifest, $bucket = find_manifest $app $bucket
}
$app, $manifest, $bucket, $url = Get-Manifest $app
if (!$manifest) {
abort "Could not find manifest for '$(show_app $app $bucket)'."
abort "Could not find manifest for '$(show_app $app)' in local buckets."
}
$global = installed $app $true
$status = app_status $app $global
$install = install_info $app $status.version $global
$status.installed = $bucket -and $install.bucket -eq $bucket
$version_output = $manifest.version
if (!$manifest_file) {
$manifest_file = manifest_path $app $bucket
$manifest_file = if ($bucket) {
manifest_path $app $bucket
} else {
$url
}
$dir = versiondir $app 'current' $global
$original_dir = versiondir $app $manifest.version $global
$persist_dir = persistdir $app $global
if ($verbose) {
$dir = currentdir $app $global
$original_dir = versiondir $app $manifest.version $global
$persist_dir = persistdir $app $global
} else {
$dir, $original_dir, $persist_dir = "<root>", "<root>", "<root>"
}
if($status.installed) {
if ($status.installed) {
$manifest_file = manifest_path $app $install.bucket
if ($install.url) {
$manifest_file = $install.url
}
if($status.version -eq $manifest.version) {
if ($status.version -eq $manifest.version) {
$version_output = $status.version
} else {
$version_output = "$($status.version) (Update to $($manifest.version) available)"
}
}
Write-Output "Name: $app"
$item = [ordered]@{ Name = $app }
if ($manifest.description) {
Write-Output "Description: $($manifest.description)"
$item.Description = $manifest.description
}
$item.Version = $version_output
if ($bucket) {
$item.Bucket = $bucket
}
if ($manifest.homepage) {
$item.Website = $manifest.homepage.TrimEnd('/')
}
Write-Output "Version: $version_output"
Write-Output "Website: $($manifest.homepage)"
# Show license
if ($manifest.license) {
$license = $manifest.license
if ($manifest.license.identifier -and $manifest.license.url) {
$license = "$($manifest.license.identifier) ($($manifest.license.url))"
$item.License = if ($manifest.license.identifier -and $manifest.license.url) {
if ($verbose) { "$($manifest.license.identifier) ($($manifest.license.url))" } else { $manifest.license.identifier }
} elseif ($manifest.license -match '^((ht)|f)tps?://') {
$license = "$($manifest.license)"
$manifest.license
} elseif ($manifest.license -match '[|,]') {
$licurl = $manifest.license.Split("|,") | ForEach-Object {"https://spdx.org/licenses/$_.html"}
$license = "$($manifest.license) ($($licurl -join ', '))"
if ($verbose) {
"$($manifest.license) ($(($manifest.license -Split "\||," | ForEach-Object { "https://spdx.org/licenses/$_.html" }) -join ', '))"
} else {
$manifest.license
}
} else {
$license = "$($manifest.license) (https://spdx.org/licenses/$($manifest.license).html)"
if ($verbose) { "$($manifest.license) (https://spdx.org/licenses/$($manifest.license).html)" } else { $manifest.license }
}
}
if ($manifest.depends) {
$item.Dependencies = $manifest.depends -join ' | '
}
if (Test-Path $manifest_file) {
if (Get-Command git -ErrorAction Ignore) {
$gitinfo = (Invoke-Git -Path (Split-Path $manifest_file) -ArgumentList @('log', '-1', '-s', '--format=%aD#%an', $manifest_file) 2> $null) -Split '#'
}
if ($gitinfo) {
$item.'Updated at' = $gitinfo[0] | Get-Date
$item.'Updated by' = $gitinfo[1]
} else {
$item.'Updated at' = (Get-Item $manifest_file).LastWriteTime
$item.'Updated by' = (Get-Acl $manifest_file).Owner.Split('\')[-1]
}
Write-Output "License: $license"
}
# Manifest file
Write-Output "Manifest:`n $manifest_file"
if ($verbose) { $item.Manifest = $manifest_file }
if($status.installed) {
if ($status.installed) {
# Show installed versions
Write-Output "Installed:"
$versions = versions $app $global
$versions | ForEach-Object {
$dir = versiondir $app $_ $global
if($global) { $dir += " *global*" }
Write-Output " $dir"
$installed_output = @()
Get-InstalledVersion -AppName $app -Global:$global | ForEach-Object {
$installed_output += if ($verbose) { versiondir $app $_ $global } else { "$_$(if ($global) { " *global*" })" }
}
$item.Installed = $installed_output -join "`n"
if ($verbose) {
# Show size of installation
$appsdir = appsdir $global
# Collect file list from each location
$appFiles = Get-ChildItem $appsdir -Filter $app
$currentFiles = Get-ChildItem $appFiles.FullName -Filter (Select-CurrentVersion $app $global)
$persistFiles = Get-ChildItem $persist_dir -ErrorAction Ignore # Will fail if app does not persist data
$cacheFiles = Get-ChildItem $cachedir -Filter "$app#*"
# Get the sum of each file list
$fileTotals = @()
foreach ($fileType in ($appFiles, $currentFiles, $persistFiles, $cacheFiles)) {
if ($null -ne $fileType) {
$fileSum = (Get-ChildItem $fileType.FullName -Recurse -File | Measure-Object -Property Length -Sum).Sum
$fileTotals += coalesce $fileSum 0
} else {
$fileTotals += 0
}
}
# Old versions = app total - current version size
$fileTotals += $fileTotals[0] - $fileTotals[1]
if ($fileTotals[2] + $fileTotals[3] + $fileTotals[4] -eq 0) {
# Simple app size output if no old versions, persisted data, cached downloads
$item.'Installed size' = filesize $fileTotals[1]
} else {
$fileSizes = [ordered] @{
'Current version: ' = $fileTotals[1]
'Old versions: ' = $fileTotals[4]
'Persisted data: ' = $fileTotals[2]
'Cached downloads: ' = $fileTotals[3]
'Total: ' = $fileTotals[0] + $fileTotals[2] + $fileTotals[3]
}
$fileSizeOutput = @()
# Don't output empty categories
$fileSizes.GetEnumerator() | ForEach-Object {
if ($_.Value -ne 0) {
$fileSizeOutput += $_.Key + (filesize $_.Value)
}
}
$item.'Installed size' = $fileSizeOutput -join "`n"
}
}
} else {
Write-Output "Installed: No"
if ($verbose) {
# Get download size if app not installed
$totalPackage = 0
foreach ($url in @(url $manifest (Get-DefaultArchitecture))) {
try {
if (Test-Path (cache_path $app $manifest.version $url)) {
$cached = " (latest version is cached)"
} else {
$cached = $null
}
$urlLength = Get-RemoteFileSize $url
$totalPackage += $urlLength
} catch [System.Management.Automation.RuntimeException] {
$totalPackage = 0
$packageError = "the server at $(([System.Uri]$url).Host) did not send a Content-Length header"
break
} catch {
$totalPackage = 0
$packageError = "the server at $(([System.Uri]$url).Host) is down"
break
}
}
if ($totalPackage -ne 0) {
$item.'Download size' = "$(filesize $totalPackage)$cached"
} else {
$item.'Download size' = "Unknown ($packageError)$cached"
}
}
}
$binaries = arch_specific 'bin' $manifest $install.architecture
if($binaries) {
$binary_output = "Binaries:`n "
$binaries = @(arch_specific 'bin' $manifest $install.architecture)
if ($binaries) {
$binary_output = @()
$binaries | ForEach-Object {
if($_ -is [System.Array]) {
$binary_output += " $($_[1]).exe"
if ($_ -is [System.Array]) {
$binary_output += "$($_[1]).$($_[0].Split('.')[-1])"
} else {
$binary_output += " $_"
$binary_output += $_
}
}
Write-Output $binary_output
$item.Binaries = $binary_output -join " | "
}
$shortcuts = @(arch_specific 'shortcuts' $manifest $install.architecture)
if ($shortcuts) {
$shortcut_output = @()
$shortcuts | ForEach-Object {
$shortcut_output += $_[1]
}
$item.Shortcuts = $shortcut_output -join " | "
}
$env_set = arch_specific 'env_set' $manifest $install.architecture
if ($env_set) {
$env_vars = @()
$env_set | Get-Member -member noteproperty | ForEach-Object {
$env_vars += "$($_.name) = $(substitute $env_set.$($_.name) @{ '$dir' = $dir })"
}
$item.Environment = $env_vars -join "`n"
}
$env_add_path = arch_specific 'env_add_path' $manifest $install.architecture
if ($env_add_path) {
$env_path = @()
$env_add_path | Where-Object { $_ } | ForEach-Object {
$env_path += if ($_ -eq '.') {
$dir
} else {
"$dir\$_"
}
}
$item.'Path Added' = $env_path -join "`n"
}
if($manifest.env_set -or $manifest.env_add_path) {
if($status.installed) {
Write-Output "Environment:"
} else {
Write-Output "Environment: (simulated)"
}
}
if($manifest.env_set) {
$manifest.env_set | Get-Member -member noteproperty | ForEach-Object {
$value = env $_.name $global
if(!$value) {
$value = format $manifest.env_set.$($_.name) @{ "dir" = $dir }
}
Write-Output " $($_.name)=$value"
}
}
if($manifest.env_add_path) {
$manifest.env_add_path | Where-Object { $_ } | ForEach-Object {
if($_ -eq '.') {
Write-Output " PATH=%PATH%;$dir"
} else {
Write-Output " PATH=%PATH%;$dir\$_"
}
if ($manifest.suggest) {
$suggest_output = @()
$manifest.suggest.PSObject.Properties | ForEach-Object {
$suggest_output += $_.Value -join ' | '
}
$item.Suggestions = $suggest_output -join ' | '
}
# Show notes
show_notes $manifest $dir $original_dir $persist_dir
if ($manifest.notes) {
# Show notes
$item.Notes = (substitute $manifest.notes @{ '$dir' = $dir; '$original_dir' = $original_dir; '$persist_dir' = $persist_dir }) -join "`n"
}
[PSCustomObject]$item
exit 0

View File

@@ -3,60 +3,56 @@
# Help: e.g. The usual way to install an app (uses your local 'buckets'):
# scoop install git
#
# To install a different version of the app
# (note that this will auto-generate the manifest using current version):
# scoop install gh@2.7.0
#
# To install an app from a manifest at a URL:
# scoop install https://raw.githubusercontent.com/ScoopInstaller/Main/master/bucket/runat.json
#
# To install a different version of the app from a URL:
# scoop install https://raw.githubusercontent.com/ScoopInstaller/Main/master/bucket/neovim.json@0.9.0
#
# To install an app from a manifest on your computer
# scoop install \path\to\app.json
#
# To install an app from a manifest on your computer
# scoop install \path\to\app.json@version
#
# Options:
# -g, --global Install the app globally
# -i, --independent Don't install dependencies automatically
# -k, --no-cache Don't use the download cache
# -s, --skip Skip hash validation (use with caution!)
# -a, --arch <32bit|64bit> Use the specified architecture, if the app supports it
# -g, --global Install the app globally
# -i, --independent Don't install dependencies automatically
# -k, --no-cache Don't use the download cache
# -s, --skip-hash-check Skip hash validation (use with caution!)
# -u, --no-update-scoop Don't update Scoop before installing if it's outdated
# -a, --arch <32bit|64bit|arm64> Use the specified architecture, if the app supports it
. "$psscriptroot\..\lib\core.ps1"
. "$psscriptroot\..\lib\manifest.ps1"
. "$psscriptroot\..\lib\buckets.ps1"
. "$psscriptroot\..\lib\decompress.ps1"
. "$psscriptroot\..\lib\install.ps1"
. "$psscriptroot\..\lib\shortcuts.ps1"
. "$psscriptroot\..\lib\psmodules.ps1"
. "$psscriptroot\..\lib\versions.ps1"
. "$psscriptroot\..\lib\help.ps1"
. "$psscriptroot\..\lib\getopt.ps1"
. "$psscriptroot\..\lib\depends.ps1"
reset_aliases
function is_installed($app, $global) {
if ($app.EndsWith('.json')) {
$app = [System.IO.Path]::GetFileNameWithoutExtension($app)
}
if (installed $app $global) {
function gf($g) { if ($g) { ' --global' } }
$version = @(versions $app $global)[-1]
if (!(install_info $app $version $global)) {
error "It looks like a previous installation of $app failed.`nRun 'scoop uninstall $app$(gf $global)' before retrying the install."
}
warn "'$app' ($version) is already installed.`nUse 'scoop update $app$(gf $global)' to install a new version."
return $true
}
return $false
. "$PSScriptRoot\..\lib\getopt.ps1"
. "$PSScriptRoot\..\lib\json.ps1" # 'autoupdate.ps1' 'manifest.ps1' (indirectly)
. "$PSScriptRoot\..\lib\autoupdate.ps1" # 'generate_user_manifest' (indirectly)
. "$PSScriptRoot\..\lib\manifest.ps1" # 'generate_user_manifest' 'Get-Manifest' 'Select-CurrentVersion' (indirectly)
. "$PSScriptRoot\..\lib\system.ps1"
. "$PSScriptRoot\..\lib\install.ps1"
. "$PSScriptRoot\..\lib\download.ps1"
. "$PSScriptRoot\..\lib\decompress.ps1"
. "$PSScriptRoot\..\lib\shortcuts.ps1"
. "$PSScriptRoot\..\lib\psmodules.ps1"
. "$PSScriptRoot\..\lib\versions.ps1"
. "$PSScriptRoot\..\lib\depends.ps1"
if (get_config USE_SQLITE_CACHE) {
. "$PSScriptRoot\..\lib\database.ps1"
}
$opt, $apps, $err = getopt $args 'gfiksa:' 'global', 'force', 'independent', 'no-cache', 'skip', 'arch='
$opt, $apps, $err = getopt $args 'giksua:' 'global', 'independent', 'no-cache', 'skip-hash-check', 'no-update-scoop', 'arch='
if ($err) { "scoop install: $err"; exit 1 }
$global = $opt.g -or $opt.global
$check_hash = !($opt.s -or $opt.skip)
$check_hash = !($opt.s -or $opt.'skip-hash-check')
$independent = $opt.i -or $opt.independent
$use_cache = !($opt.k -or $opt.'no-cache')
$architecture = default_architecture
$architecture = Get-DefaultArchitecture
try {
$architecture = ensure_architecture ($opt.a + $opt.arch)
$architecture = Format-ArchitectureString ($opt.a + $opt.arch)
} catch {
abort "ERROR: $_"
}
@@ -68,13 +64,24 @@ if ($global -and !(is_admin)) {
}
if (is_scoop_outdated) {
scoop update
if ($opt.u -or $opt.'no-update-scoop') {
warn "Scoop is out of date."
} else {
& "$PSScriptRoot\scoop-update.ps1"
}
}
ensure_none_failed $apps
if ($apps.length -eq 1) {
$app, $null, $null = parse_app $apps
if (is_installed $app $global) {
return
$app, $null, $version = parse_app $apps
if ($app.EndsWith('.json')) {
$app = [System.IO.Path]::GetFileNameWithoutExtension($app)
}
$curVersion = Select-CurrentVersion -AppName $app -Global:$global
if ($null -eq $version -and $curVersion) {
warn "'$app' ($curVersion) is already installed.`nUse 'scoop update $app$(if ($global) { ' --global' })' to install a new version."
exit 0
}
}
@@ -85,7 +92,7 @@ $specific_versions = $apps | Where-Object {
}
# compare object does not like nulls
if ($specific_versions.length -gt 0) {
if ($specific_versions.Count -gt 0) {
$difference = Compare-Object -ReferenceObject $apps -DifferenceObject $specific_versions -PassThru
} else {
$difference = $apps
@@ -94,34 +101,36 @@ if ($specific_versions.length -gt 0) {
$specific_versions_paths = $specific_versions | ForEach-Object {
$app, $bucket, $version = parse_app $_
if (installed_manifest $app $version) {
abort "'$app' ($version) is already installed.`nUse 'scoop update $app$global_flag' to install a new version."
warn "'$app' ($version) is already installed.`nUse 'scoop update $app$(if ($global) { ' --global' })' to install a new version."
continue
}
generate_user_manifest $app $bucket $version
}
$apps = @(($specific_versions_paths + $difference) | Where-Object { $_ } | Sort-Object -Unique)
$apps = @((@($specific_versions_paths) + $difference) | Where-Object { $_ } | Select-Object -Unique)
# remember which were explictly requested so that we can
# differentiate after dependencies are added
$explicit_apps = $apps
if (!$independent) {
$apps = install_order $apps $architecture # adds dependencies
$apps = $apps | Get-Dependency -Architecture $architecture | Select-Object -Unique # adds dependencies
}
ensure_none_failed $apps $global
ensure_none_failed $apps
$apps, $skip = prune_installed $apps $global
$skip | Where-Object { $explicit_apps -contains $_ } | ForEach-Object {
$app, $null, $null = parse_app $_
$version = @(versions $app $global)[-1]
$version = Select-CurrentVersion -AppName $app -Global:$global
warn "'$app' ($version) is already installed. Skipping."
}
$suggested = @{ };
if (Test-Aria2Enabled) {
if ((Test-Aria2Enabled) -and (get_config 'aria2-warning-enabled' $true)) {
warn "Scoop uses 'aria2c' for multi-connection downloads."
warn "Should it cause issues, run 'scoop config aria2-enabled false' to disable it."
warn "To disable this warning, run 'scoop config aria2-warning-enabled false'."
}
$apps | ForEach-Object { install_app $_ $architecture $global $suggested $use_cache $check_hash }

View File

@@ -3,49 +3,60 @@
# Help: Lists all installed apps, or the apps matching the supplied query.
param($query)
. "$psscriptroot\..\lib\core.ps1"
. "$psscriptroot\..\lib\versions.ps1"
. "$psscriptroot\..\lib\manifest.ps1"
. "$psscriptroot\..\lib\buckets.ps1"
. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
. "$PSScriptRoot\..\lib\manifest.ps1" # 'parse_json' 'Select-CurrentVersion' (indirectly)
reset_aliases
$def_arch = default_architecture
$def_arch = Get-DefaultArchitecture
if (-not (Get-FormatData ScoopApps)) {
Update-FormatData "$PSScriptRoot\..\supporting\formats\ScoopTypes.Format.ps1xml"
}
$local = installed_apps $false | ForEach-Object { @{ name = $_ } }
$global = installed_apps $true | ForEach-Object { @{ name = $_; global = $true } }
$apps = @($local) + @($global)
if($apps) {
write-host "Installed apps$(if($query) { `" matching '$query'`"}): `n"
$apps | Sort-Object { $_.name } | Where-Object { !$query -or ($_.name -match $query) } | ForEach-Object {
$app = $_.name
$global = $_.global
$ver = current_version $app $global
$install_info = install_info $app $ver $global
write-host " $app " -NoNewline
write-host -f DarkCyan $ver -NoNewline
if($global) { write-host -f DarkGreen ' *global*' -NoNewline }
if (!$install_info) { Write-Host ' *failed*' -ForegroundColor DarkRed -NoNewline }
if ($install_info.hold) { Write-Host ' *hold*' -ForegroundColor DarkMagenta -NoNewline }
if ($install_info.bucket -and ($install_info.bucket -ne 'main')) {
write-host -f Yellow " [$($install_info.bucket)]" -NoNewline
} elseif ($install_info.url) {
write-host -f Yellow " [$($install_info.url)]" -NoNewline
}
if ($install_info.architecture -and $def_arch -ne $install_info.architecture) {
write-host -f DarkRed " {$($install_info.architecture)}" -NoNewline
}
write-host ''
}
write-host ''
exit 0
} else {
write-host "There aren't any apps installed."
if (-not $apps) {
Write-Host "There aren't any apps installed."
exit 1
}
$list = @()
Write-Host "Installed apps$(if($query) { `" matching '$query'`"}):"
$apps | Where-Object { !$query -or ($_.name -match $query) } | ForEach-Object {
$app = $_.name
$global = $_.global
$item = @{}
$ver = Select-CurrentVersion -AppName $app -Global:$global
$item.Name = $app
$item.Version = $ver
$install_info_path = "$(versiondir $app $ver $global)\install.json"
$updated = (Get-Item (appdir $app $global)).LastWriteTime
$install_info = $null
if (Test-Path $install_info_path) {
$install_info = parse_json $install_info_path
$updated = (Get-Item $install_info_path).LastWriteTime
}
$item.Source = if ($install_info.bucket) {
$install_info.bucket
} elseif ($install_info.url) {
if ($install_info.url -eq (usermanifest $app)) { '<auto-generated>' }
else { $install_info.url }
}
$item.Updated = $updated
$info = @()
if ($global) { $info += 'Global install' }
if (failed $app $global) { $info += 'Install failed' }
if ($install_info.hold) { $info += 'Held package' }
if ($install_info.architecture -and $def_arch -ne $install_info.architecture) {
$info += $install_info.architecture
}
$item.Info = $info -join ', '
$list += [PSCustomObject]$item
}
$list | Add-Member -TypeName 'ScoopApps' -PassThru
exit 0

View File

@@ -2,21 +2,19 @@
# Summary: Returns the path to the specified app
param($app)
. "$psscriptroot\..\lib\core.ps1"
. "$psscriptroot\..\lib\help.ps1"
. "$psscriptroot\..\lib\manifest.ps1"
. "$psscriptroot\..\lib\buckets.ps1"
. "$PSScriptRoot\..\lib\versions.ps1" # 'currentdir' (indirectly)
reset_aliases
if(!$app) { my_usage; exit 1 }
$app_path = versiondir $app 'current' $false
if(!(Test-Path $app_path)) {
$app_path = versiondir $app 'current' $true
if (!$app) {
my_usage
exit 1
}
if(Test-Path $app_path) {
$app_path = currentdir $app $false
if (!(Test-Path $app_path)) {
$app_path = currentdir $app $true
}
if (Test-Path $app_path) {
Write-Output $app_path
} else {
abort "Could not find app path for '$app'."

View File

@@ -3,22 +3,23 @@
# Help: Used to resolve conflicts in favor of a particular app. For example,
# if you've installed 'python' and 'python27', you can use 'scoop reset' to switch between
# using one or the other.
#
# You can use '*' in place of <app> or `-a`/`--all` switch to reset all apps.
. "$psscriptroot\..\lib\core.ps1"
. "$psscriptroot\..\lib\manifest.ps1"
. "$psscriptroot\..\lib\help.ps1"
. "$psscriptroot\..\lib\getopt.ps1"
. "$psscriptroot\..\lib\install.ps1"
. "$psscriptroot\..\lib\versions.ps1"
. "$psscriptroot\..\lib\shortcuts.ps1"
. "$PSScriptRoot\..\lib\getopt.ps1"
. "$PSScriptRoot\..\lib\manifest.ps1" # 'Select-CurrentVersion' (indirectly)
. "$PSScriptRoot\..\lib\system.ps1" # 'env_add_path' (indirectly)
. "$PSScriptRoot\..\lib\install.ps1"
. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
. "$PSScriptRoot\..\lib\shortcuts.ps1"
reset_aliases
$opt, $apps, $err = getopt $args
$opt, $apps, $err = getopt $args 'a' 'all'
if($err) { "scoop reset: $err"; exit 1 }
$all = $opt.a -or $opt.all
if(!$apps) { error '<app> missing'; my_usage; exit 1 }
if(!$apps -and !$all) { error '<app> missing'; my_usage; exit 1 }
if($apps -eq '*') {
if($apps -eq '*' -or $all) {
$local = installed_apps $false | ForEach-Object { ,@($_, $false) }
$global = installed_apps $true | ForEach-Object { ,@($_, $true) }
$apps = @($local) + @($global)
@@ -45,7 +46,7 @@ $apps | ForEach-Object {
}
if ($null -eq $version) {
$version = current_version $app $global
$version = Select-CurrentVersion -AppName $app -Global:$global
}
$manifest = installed_manifest $app $version $global
@@ -63,20 +64,29 @@ $apps | ForEach-Object {
write-host "Resetting $app ($version)."
$dir = resolve-path (versiondir $app $version $global)
$dir = Convert-Path (versiondir $app $version $global)
$original_dir = $dir
$persist_dir = persistdir $app $global
#region Workaround for #2952
if (test_running_process $app $global) {
return
}
#endregion Workaround for #2952
$install = install_info $app $version $global
$architecture = $install.architecture
$dir = link_current $dir
create_shims $manifest $dir $global $architecture
create_startmenu_shortcuts $manifest $dir $global $architecture
env_add_path $manifest $dir
env_set $manifest $dir $global
# unset all potential old env before re-adding
env_rm_path $manifest $dir $global $architecture
env_rm $manifest $global $architecture
env_add_path $manifest $dir $global $architecture
env_set $manifest $global $architecture
# unlink all potential old link before re-persisting
unlink_persist_data $original_dir
unlink_persist_data $manifest $original_dir
persist_data $manifest $original_dir $persist_dir
persist_permission $manifest $global
}

View File

@@ -3,73 +3,129 @@
# Help: Searches for apps that are available to install.
#
# If used with [query], shows app names that match the query.
# - With 'use_sqlite_cache' enabled, [query] is partially matched against app names, binaries, and shortcuts.
# - Without 'use_sqlite_cache', [query] can be a regular expression to match against app names and binaries.
# Without [query], shows all the available apps.
param($query)
. "$psscriptroot\..\lib\core.ps1"
. "$psscriptroot\..\lib\buckets.ps1"
. "$psscriptroot\..\lib\manifest.ps1"
. "$psscriptroot\..\lib\versions.ps1"
reset_aliases
. "$PSScriptRoot\..\lib\manifest.ps1" # 'manifest'
. "$PSScriptRoot\..\lib\versions.ps1" # 'Get-LatestVersion'
. "$PSScriptRoot\..\lib\download.ps1"
$list = [System.Collections.Generic.List[PSCustomObject]]::new()
function bin_match($manifest, $query) {
if(!$manifest.bin) { return $false }
foreach($bin in $manifest.bin) {
if (!$manifest.bin) { return $false }
$bins = foreach ($bin in $manifest.bin) {
$exe, $alias, $args = $bin
$fname = split-path $exe -leaf -ea stop
$fname = Split-Path $exe -Leaf -ErrorAction Stop
if((strip_ext $fname) -match $query) { return $fname }
if($alias -match $query) { return $alias }
if ((strip_ext $fname) -match $query) { $fname }
elseif ($alias -match $query) { $alias }
}
$false
if ($bins) { return $bins }
else { return $false }
}
function search_bucket($bucket, $query) {
$apps = apps_in_bucket (Find-BucketDirectory $bucket) | ForEach-Object {
@{ name = $_ }
}
if($query) {
try {
$query = new-object regex $query, 'IgnoreCase'
} catch {
abort "Invalid regular expression: $($_.exception.innerexception.message)"
}
$apps = $apps | Where-Object {
if($_.name -match $query) { return $true }
$bin = bin_match (manifest $_.name $bucket) $query
if($bin) {
$_.bin = $bin; return $true;
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]
}
}
}
}
$apps | ForEach-Object { $_.version = (latest_version $_.name $bucket); $_ }
if ($bins) { return $bins }
else { return $false }
}
function download_json($url) {
$progressPreference = 'silentlycontinue'
$result = invoke-webrequest $url -UseBasicParsing | Select-Object -exp content | convertfrom-json
$progressPreference = 'continue'
$result
function search_bucket($bucket, $query) {
$apps = Get-ChildItem (Find-BucketDirectory $bucket) -Filter '*.json' -Recurse
$apps | ForEach-Object {
$filepath = $_.FullName
$json = try {
[System.Text.Json.JsonDocument]::Parse([System.IO.File]::ReadAllText($filepath))
} catch {
debug "Failed to parse manifest file: $filepath (error: $_)"
return
}
$name = $_.BaseName
if ($name -match $query) {
$list.Add([PSCustomObject]@{
Name = $name
Version = $json.RootElement.GetProperty('version')
Source = $bucket
Binaries = ''
})
} else {
$bin = bin_match_json $json $query
if ($bin) {
$list.Add([PSCustomObject]@{
Name = $name
Version = $json.RootElement.GetProperty('version')
Source = $bucket
Binaries = $bin -join ' | '
})
}
}
}
}
function github_ratelimit_reached {
$api_link = "https://api.github.com/rate_limit"
(download_json $api_link).rate.remaining -eq 0
# fallback function for PowerShell 5
function search_bucket_legacy($bucket, $query) {
$apps = Get-ChildItem (Find-BucketDirectory $bucket) -Filter '*.json' -Recurse
$apps | ForEach-Object {
$manifest = [System.IO.File]::ReadAllText($_.FullName) | ConvertFrom-Json -ErrorAction Continue
$name = $_.BaseName
if ($name -match $query) {
$list.Add([PSCustomObject]@{
Name = $name
Version = $manifest.Version
Source = $bucket
Binaries = ''
})
} else {
$bin = bin_match $manifest $query
if ($bin) {
$list.Add([PSCustomObject]@{
Name = $name
Version = $manifest.Version
Source = $bucket
Binaries = $bin -join ' | '
})
}
}
}
}
function search_remote($bucket, $query) {
$repo = known_bucket_repo $bucket
$uri = [system.uri]($repo)
if ($uri.absolutepath -match '/([a-zA-Z0-9]*)/([a-zA-Z0-9-]*)(.git|/)?') {
$user = $matches[1]
$repo_name = $matches[2]
$uri = [System.Uri](known_bucket_repo $bucket)
if ($uri.AbsolutePath -match '/([a-zA-Z0-9]*)/([a-zA-Z0-9-]*)(?:.git|/)?') {
$user = $Matches[1]
$repo_name = $Matches[2]
$api_link = "https://api.github.com/repos/$user/$repo_name/git/trees/HEAD?recursive=1"
$result = download_json $api_link | Select-Object -exp tree | Where-Object {
$_.path -match "(^(.*$query.*).json$)"
} | ForEach-Object { $matches[2] }
$result = download_json $api_link | Select-Object -ExpandProperty tree |
Where-Object -Value "^bucket/(.*$query.*)\.json$" -Property Path -Match |
ForEach-Object { $Matches[1] }
}
$result
@@ -77,44 +133,71 @@ function search_remote($bucket, $query) {
function search_remotes($query) {
$buckets = known_bucket_repos
$names = $buckets | get-member -m noteproperty | Select-Object -exp name
$names = $buckets | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty name
$results = $names | Where-Object { !(test-path $(Find-BucketDirectory $_)) } | ForEach-Object {
@{"bucket" = $_; "results" = (search_remote $_ $query)}
$results = $names | Where-Object { !(Test-Path $(Find-BucketDirectory $_)) } | ForEach-Object {
@{ 'bucket' = $_; 'results' = (search_remote $_ $query) }
} | Where-Object { $_.results }
if ($results.count -gt 0) {
"Results from other known buckets..."
"(add them using 'scoop bucket add <name>')"
""
Write-Host "Results from other known buckets...
(add them using 'scoop bucket add <bucket name>')"
}
$remote_list = @()
$results | ForEach-Object {
"'$($_.bucket)' bucket:"
$_.results | ForEach-Object { " $_" }
""
}
}
Get-LocalBucket | ForEach-Object {
$res = search_bucket $_ $query
$local_results = $local_results -or $res
if($res) {
$name = "$_"
Write-Host "'$name' bucket:"
$res | ForEach-Object {
$item = " $($_.name) ($($_.version))"
if($_.bin) { $item += " --> includes '$($_.bin)'" }
$item
$bucket = $_.bucket
$_.results | ForEach-Object {
$item = [ordered]@{}
$item.Name = $_
$item.Source = $bucket
$remote_list += [PSCustomObject]$item
}
}
$remote_list
}
if (get_config USE_SQLITE_CACHE) {
. "$PSScriptRoot\..\lib\database.ps1"
Select-ScoopDBItem $query -From @('name', 'binary', 'shortcut') |
Select-Object -Property name, version, bucket, binary |
ForEach-Object {
$list.Add([PSCustomObject]@{
Name = $_.name
Version = $_.version
Source = $_.bucket
Binaries = $_.binary
})
}
} else {
try {
$query = New-Object Regex $query, 'IgnoreCase'
} catch {
abort "Invalid regular expression: $($_.Exception.InnerException.Message)"
}
$jsonTextAvailable = [System.AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { [System.IO.Path]::GetFileNameWithoutExtension($_.Location) -eq 'System.Text.Json' }
Get-LocalBucket | ForEach-Object {
if ($jsonTextAvailable) {
search_bucket $_ $query
} else {
search_bucket_legacy $_ $query
}
""
}
}
if (!$local_results -and !(github_ratelimit_reached)) {
if ($list.Count -gt 0) {
Write-Host 'Results from local buckets...'
$list
}
if ($list.Count -eq 0 -and !(github_ratelimit_reached)) {
$remote_results = search_remotes $query
if(!$remote_results) { [console]::error.writeline("No matches found."); exit 1 }
if (!$remote_results) {
warn 'No matches found.'
exit 1
}
$remote_results
}

240
libexec/scoop-shim.ps1 Normal file
View File

@@ -0,0 +1,240 @@
# Usage: scoop shim <subcommand> [<shim_name>...] [options] [other_args]
# Summary: Manipulate Scoop shims
# Help: Available subcommands: add, rm, list, info, alter.
#
# To add a custom shim, use the 'add' subcommand:
#
# scoop shim add <shim_name> <command_path> [<args>...]
#
# To remove shims, use the 'rm' subcommand: (CAUTION: this could remove shims added by an app manifest)
#
# scoop shim rm <shim_name> [<shim_name>...]
#
# To list all shims or matching shims, use the 'list' subcommand:
#
# scoop shim list [<regex_pattern>...]
#
# To show a shim's information, use the 'info' subcommand:
#
# scoop shim info <shim_name>
#
# To alternate a shim's target source, use the 'alter' subcommand:
#
# scoop shim alter <shim_name>
#
# Options:
# -g, --global Manipulate global shim(s)
#
# HINT: The FIRST double-hyphen '--', if any, will be treated as the POSIX-style command option terminator
# and will NOT be included in arguments, so if you want to pass arguments like '-g' or '--global' to
# the shim, put them after a '--'. Note that in PowerShell, you must use a QUOTED '--', e.g.,
#
# scoop shim add myapp 'D:\path\myapp.exe' '--' myapp_args --global
param($SubCommand)
. "$PSScriptRoot\..\lib\getopt.ps1"
. "$PSScriptRoot\..\lib\install.ps1" # for rm_shim
. "$PSScriptRoot\..\lib\system.ps1" # 'Add-Path' (indirectly)
if ($SubCommand -notin @('add', 'rm', 'list', 'info', 'alter')) {
if (!$SubCommand) {
error '<subcommand> missing'
} else {
error "'$SubCommand' is not one of available subcommands: add, rm, list, info, alter"
}
my_usage
exit 1
}
$opt, $other, $err = getopt $Args 'g' 'global'
if ($err) { "scoop shim: $err"; exit 1 }
$global = $opt.g -or $opt.global
if ($SubCommand -ne 'list' -and $other.Length -eq 0) {
error "<shim_name> must be specified for subcommand '$SubCommand'"
my_usage
exit 1
}
if (-not (Get-FormatData ScoopShims)) {
Update-FormatData "$PSScriptRoot\..\supporting\formats\ScoopTypes.Format.ps1xml"
}
$localShimDir = shimdir $false
$globalShimDir = shimdir $true
function Get-ShimInfo($ShimPath) {
$info = [Ordered]@{}
$info.Name = strip_ext (fname $ShimPath)
$info.Path = $ShimPath -replace 'shim$', 'exe'
$info.Source = (get_app_name_from_shim $ShimPath) -replace '^$', 'External'
$info.Type = if ($ShimPath.EndsWith('.ps1')) { 'ExternalScript' } else { 'Application' }
$altShims = Get-Item -Path "$ShimPath.*" -Exclude '*.shim', '*.cmd', '*.ps1'
if ($altShims) {
$info.Alternatives = (@($info.Source) + ($altShims | ForEach-Object { $_.Extension.Remove(0, 1) } | Select-Object -Unique)) -join ' '
}
$info.IsGlobal = $ShimPath.StartsWith("$globalShimDir")
$info.IsHidden = !((Get-Command -Name $info.Name).Path -eq $info.Path)
[PSCustomObject]$info
}
function Get-ShimPath($ShimName, $Global) {
'.shim', '.ps1' | ForEach-Object {
$shimPath = Join-Path (shimdir $Global) "$ShimName$_"
if (Test-Path -LiteralPath $shimPath) {
return $shimPath
}
}
}
switch ($SubCommand) {
'add' {
if ($other.Length -lt 2 -or $other[1] -eq '') {
error "<command_path> must be specified for subcommand 'add'"
my_usage
exit 1
}
$shimName = $other[0]
$commandPath = $other[1]
if ($other.Length -gt 2) {
$commandArgs = $other[2..($other.Length - 1)]
}
if ($commandPath -notmatch '[\\/]') {
$shortPath = $commandPath
$commandPath = Get-ShimTarget (Get-ShimPath $shortPath $global)
if (!$commandPath) {
$exCommand = Get-Command $shortPath -ErrorAction SilentlyContinue
if ($exCommand -and $exCommand.CommandType -eq 'Application') {
$commandPath = $exCommand.Path
} # TODO - add support for more command types: Alias, Cmdlet, ExternalScript, Filter, Function, Script, and Workflow
}
}
if ($commandPath -and (Test-Path $commandPath)) {
Write-Host "Adding $(if ($global) { 'global' } else { 'local' }) shim " -NoNewline
Write-Host $shimName -ForegroundColor Cyan -NoNewline
Write-Host '...'
shim $commandPath $global $shimName $commandArgs
} else {
Write-Host "ERROR: Command path does not exist: " -ForegroundColor Red -NoNewline
Write-Host $($other[1]) -ForegroundColor Cyan
exit 3
}
}
'rm' {
$failed = @()
$other | ForEach-Object {
if (Get-ShimPath $_ $global) {
rm_shim $_ (shimdir $global)
} else {
$failed += $_
}
}
if ($failed) {
$failed | ForEach-Object {
Write-Host "ERROR: $(if ($global) { 'Global' } else {'Local' }) shim not found: " -ForegroundColor Red -NoNewline
Write-Host $_ -ForegroundColor Cyan
}
exit 3
}
}
'list' {
$other = @($other) -ne '*'
# Validate all given patterns before matching.
$other | ForEach-Object {
try {
$pattern = $_
[void][Regex]::New($pattern)
} catch {
Write-Host "ERROR: Invalid pattern: " -ForegroundColor Red -NoNewline
Write-Host $pattern -ForegroundColor Magenta
exit 1
}
}
$pattern = $other -join '|'
$shims = @()
if (!$global) {
$shims += Get-ChildItem -Path $localShimDir -Recurse -Include '*.shim', '*.ps1' |
Where-Object { !$pattern -or ($_.BaseName -match $pattern) } |
Select-Object -ExpandProperty FullName
}
if (Test-Path $globalShimDir) {
$shims += Get-ChildItem -Path $globalShimDir -Recurse -Include '*.shim', '*.ps1' |
Where-Object { !$pattern -or ($_.BaseName -match $pattern) } |
Select-Object -ExpandProperty FullName
}
$shims.ForEach({ Get-ShimInfo $_ }) | Add-Member -TypeName 'ScoopShims' -PassThru
}
'info' {
$shimName = $other[0]
$shimPath = Get-ShimPath $shimName $global
if ($shimPath) {
Get-ShimInfo $shimPath
} else {
Write-Host "ERROR: $(if ($global) { 'Global' } else { 'Local' }) shim not found: " -ForegroundColor Red -NoNewline
Write-Host $shimName -ForegroundColor Cyan
if (Get-ShimPath $shimName (!$global)) {
Write-Host "But a $(if ($global) { 'local' } else {'global' }) shim exists, " -NoNewline
Write-Host "run 'scoop shim info $shimName$(if (!$global) { ' --global' })' to show its info"
exit 2
}
exit 3
}
}
'alter' {
$shimName = $other[0]
$shimPath = Get-ShimPath $shimName $global
if ($shimPath) {
$shimInfo = Get-ShimInfo $shimPath
if ($null -eq $shimInfo.Alternatives) {
Write-Host 'ERROR: No alternatives of ' -ForegroundColor Red -NoNewline
Write-Host $shimName -ForegroundColor Cyan -NoNewline
Write-Host ' found.' -ForegroundColor Red
exit 2
}
$shimInfo.Alternatives = $shimInfo.Alternatives.Split(' ')
[System.Management.Automation.Host.ChoiceDescription[]]$altApps = 1..$shimInfo.Alternatives.Length | ForEach-Object {
New-Object System.Management.Automation.Host.ChoiceDescription "&$($_)`b$($shimInfo.Alternatives[$_ - 1])", "Sets '$shimName' shim from $($shimInfo.Alternatives[$_ - 1])."
}
$selected = $Host.UI.PromptForChoice("Alternatives of '$shimName' command", "Please choose one that provides '$shimName' as default:", $altApps, 0)
if ($selected -eq 0) {
Write-Host 'INFO: ' -ForegroundColor Blue -NoNewline
Write-Host $shimName -ForegroundColor Cyan -NoNewline
Write-Host ' is already from ' -NoNewline
Write-Host $shimInfo.Source -ForegroundColor DarkYellow -NoNewline
Write-Host ', nothing changed.'
} else {
$newApp = $shimInfo.Alternatives[$selected]
Write-Host 'Use ' -NoNewline
Write-Host $shimName -ForegroundColor Cyan -NoNewline
Write-Host ' from ' -NoNewline
Write-Host $newApp -ForegroundColor DarkYellow -NoNewline
Write-Host ' as default...' -NoNewline
$pathNoExt = strip_ext $shimPath
'', '.shim', '.cmd', '.ps1' | ForEach-Object {
$oldShimPath = "$pathNoExt$_"
$newShimPath = "$oldShimPath.$newApp"
if (Test-Path -Path $oldShimPath -PathType Leaf) {
Rename-Item -Path $oldShimPath -NewName "$oldShimPath.$($shimInfo.Source)" -Force
if (Test-Path -Path $newShimPath -PathType Leaf) {
Rename-Item -Path $newShimPath -NewName $oldShimPath -Force
}
}
}
Write-Host 'done.'
}
} else {
Write-Host "ERROR: $(if ($global) { 'Global' } else { 'Local' }) shim not found: " -ForegroundColor Red -NoNewline
Write-Host $shimName -ForegroundColor Cyan
if (Get-ShimPath $shimName (!$global)) {
Write-Host "But a $(if ($global) { 'local' } else {'global' }) shim exists, " -NoNewline
Write-Host "run 'scoop shim alter $shimName$(if (!$global) { ' --global' })' to alternate its source"
exit 2
}
exit 3
}
}
}
exit 0

View File

@@ -1,107 +1,83 @@
# Usage: scoop status
# Summary: Show status and check for new app versions
# Help: Options:
# -l, --local Checks the status for only the locally installed apps,
# and disables remote fetching/checking for Scoop and buckets
. "$psscriptroot\..\lib\core.ps1"
. "$psscriptroot\..\lib\manifest.ps1"
. "$psscriptroot\..\lib\buckets.ps1"
. "$psscriptroot\..\lib\versions.ps1"
. "$psscriptroot\..\lib\depends.ps1"
. "$psscriptroot\..\lib\git.ps1"
reset_aliases
. "$PSScriptRoot\..\lib\manifest.ps1" # 'manifest' 'parse_json' "install_info"
. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
# check if scoop needs updating
$currentdir = fullpath $(versiondir 'scoop' 'current')
$currentdir = versiondir 'scoop' 'current'
$needs_update = $false
if(test-path "$currentdir\.git") {
Push-Location $currentdir
git_fetch -q origin
$commits = $(git log "HEAD..origin/$(scoop config SCOOP_BRANCH)" --oneline)
if($commits) { $needs_update = $true }
Pop-Location
}
else {
$needs_update = $true
$bucket_needs_update = $false
$script:network_failure = $false
$no_remotes = $args[0] -eq '-l' -or $args[0] -eq '--local'
if (!(Get-Command git -ErrorAction SilentlyContinue)) { $no_remotes = $true }
$list = @()
if (!(Get-FormatData ScoopStatus)) {
Update-FormatData "$PSScriptRoot\..\supporting\formats\ScoopTypes.Format.ps1xml"
}
if($needs_update) {
warn "Scoop is out of date. Run 'scoop update' to get the latest changes."
function Test-UpdateStatus($repopath) {
if (Test-Path "$repopath\.git") {
Invoke-Git -Path $repopath -ArgumentList @('fetch', '-q', 'origin')
$script:network_failure = 128 -eq $LASTEXITCODE
$branch = Invoke-Git -Path $repopath -ArgumentList @('branch', '--show-current')
$commits = Invoke-Git -Path $repopath -ArgumentList @('log', "HEAD..origin/$branch", '--oneline')
if ($commits) { return $true }
else { return $false }
} else {
return $true
}
}
else { success "Scoop is up to date."}
$failed = @()
$outdated = @()
$removed = @()
$missing_deps = @()
$onhold = @()
if (!$no_remotes) {
$needs_update = Test-UpdateStatus $currentdir
foreach ($bucket in Get-LocalBucket) {
if (Test-UpdateStatus (Find-BucketDirectory $bucket -Root)) {
$bucket_needs_update = $true
break
}
}
}
if ($needs_update) {
warn "Scoop out of date. Run 'scoop update' to get the latest changes."
} elseif ($bucket_needs_update) {
warn "Scoop bucket(s) out of date. Run 'scoop update' to get the latest changes."
} elseif (!$script:network_failure -and !$no_remotes) {
success 'Scoop is up to date.'
}
$true, $false | ForEach-Object { # local and global apps
$global = $_
$dir = appsdir $global
if(!(test-path $dir)) { return }
if (!(Test-Path $dir)) { return }
Get-ChildItem $dir | Where-Object name -ne 'scoop' | ForEach-Object {
Get-ChildItem $dir | Where-Object name -NE 'scoop' | ForEach-Object {
$app = $_.name
$status = app_status $app $global
if($status.failed) {
$failed += @{ $app = $status.version }
}
if($status.removed) {
$removed += @{ $app = $status.version }
}
if($status.outdated) {
$outdated += @{ $app = @($status.version, $status.latest_version) }
if($status.hold) {
$onhold += @{ $app = @($status.version, $status.latest_version) }
}
}
if($status.missing_deps) {
$missing_deps += ,(@($app) + @($status.missing_deps))
}
if (!$status.outdated -and !$status.failed -and !$status.removed -and !$status.missing_deps) { return }
$item = [ordered]@{}
$item.Name = $app
$item.'Installed Version' = $status.version
$item.'Latest Version' = if ($status.outdated) { $status.latest_version } else { "" }
$item.'Missing Dependencies' = $status.missing_deps -Split ' ' -Join ' | '
$info = @()
if ($status.failed) { $info += 'Install failed' }
if ($status.hold) { $info += 'Held package' }
if ($status.removed) { $info += 'Manifest removed' }
$item.Info = $info -join ', '
$list += [PSCustomObject]$item
}
}
if($outdated) {
write-host -f DarkCyan 'Updates are available for:'
$outdated.keys | ForEach-Object {
$versions = $outdated.$_
" $_`: $($versions[0]) -> $($versions[1])"
}
if ($list.Length -eq 0 -and !$needs_update -and !$bucket_needs_update -and !$script:network_failure) {
success 'Everything is ok!'
}
if($onhold) {
write-host -f DarkCyan 'These apps are outdated and on hold:'
$onhold.keys | ForEach-Object {
$versions = $onhold.$_
" $_`: $($versions[0]) -> $($versions[1])"
}
}
if($removed) {
write-host -f DarkCyan 'These app manifests have been removed:'
$removed.keys | ForEach-Object {
" $_"
}
}
if($failed) {
write-host -f DarkCyan 'These apps failed to install:'
$failed.keys | ForEach-Object {
" $_"
}
}
if($missing_deps) {
write-host -f DarkCyan 'Missing runtime dependencies:'
$missing_deps | ForEach-Object {
$app, $deps = $_
" '$app' requires '$([string]::join("', '", $deps))'"
}
}
if(!$old -and !$removed -and !$failed -and !$missing_deps -and !$needs_update) {
success "Everything is ok!"
}
$list | Add-Member -TypeName ScoopStatus -PassThru
exit 0

View File

@@ -1,33 +1,71 @@
# Usage: scoop unhold <app>
# Summary: Unhold an app to enable updates
# Help: To unhold a user-scoped app:
# scoop unhold <app>
#
# To unhold a global app:
# scoop unhold -g <app>
#
# Options:
# -g, --global Unhold globally installed apps
. "$psscriptroot\..\lib\help.ps1"
. "$psscriptroot\..\lib\manifest.ps1"
. "$PSScriptRoot\..\lib\getopt.ps1"
. "$PSScriptRoot\..\lib\json.ps1" # 'save_install_info' (indirectly)
. "$PSScriptRoot\..\lib\manifest.ps1" # 'install_info' 'Select-CurrentVersion' (indirectly)
. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
reset_aliases
$apps = $args
$opt, $apps, $err = getopt $args 'g' 'global'
if ($err) { "scoop unhold: $err"; exit 1 }
if(!$apps) {
$global = $opt.g -or $opt.global
if (!$apps) {
my_usage
exit 1
}
if ($global -and !(is_admin)) {
error 'You need admin rights to unhold a global app.'
exit 1
}
$apps | ForEach-Object {
$app = $_
$global = installed $app $true
if (!(installed $app)) {
error "'$app' is not installed."
if ($app -eq 'scoop') {
set_config HOLD_UPDATE_UNTIL $null | Out-Null
success "$app is no longer held and can be updated again."
return
}
if (!(installed $app $global)) {
if ($global) {
error "'$app' is not installed globally."
} else {
error "'$app' is not installed."
}
return
}
$dir = versiondir $app 'current' $global
$json = install_info $app 'current' $global
if (get_config NO_JUNCTION){
$version = Select-CurrentVersion -App $app -Global:$global
} else {
$version = 'current'
}
$dir = versiondir $app $version $global
$json = install_info $app $version $global
if (!$json) {
error "Failed to unhold '$app'"
continue
}
$install = @{}
$json | Get-Member -MemberType Properties | ForEach-Object { $install.Add($_.Name, $json.($_.Name))}
$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 now unlocked and can be updated again."
success "$app is no longer held and can be updated again."
}
exit $exitcode

View File

@@ -6,16 +6,13 @@
# -g, --global Uninstall a globally installed app
# -p, --purge Remove all persistent data
. "$PSScriptRoot\..\lib\core.ps1"
. "$PSScriptRoot\..\lib\manifest.ps1"
. "$PSScriptRoot\..\lib\help.ps1"
. "$PSScriptRoot\..\lib\getopt.ps1"
. "$PSScriptRoot\..\lib\manifest.ps1" # 'Get-Manifest' 'Select-CurrentVersion' (indirectly)
. "$PSScriptRoot\..\lib\system.ps1"
. "$PSScriptRoot\..\lib\install.ps1"
. "$PSScriptRoot\..\lib\shortcuts.ps1"
. "$PSScriptRoot\..\lib\psmodules.ps1"
. "$PSScriptRoot\..\lib\versions.ps1"
. "$PSScriptRoot\..\lib\getopt.ps1"
reset_aliases
. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
# options
$opt, $apps, $err = getopt $args 'gp' 'global', 'purge'
@@ -50,65 +47,79 @@ if (!$apps) { exit 0 }
:app_loop foreach ($_ in $apps) {
($app, $global) = $_
$version = current_version $app $global
Write-Host "Uninstalling '$app' ($version)."
$version = Select-CurrentVersion -AppName $app -Global:$global
$appDir = appdir $app $global
if ($version) {
Write-Host "Uninstalling '$app' ($version)."
$dir = versiondir $app $version $global
$persist_dir = persistdir $app $global
$dir = versiondir $app $version $global
$persist_dir = persistdir $app $global
try {
Test-Path $dir -ErrorAction Stop | Out-Null
} catch [UnauthorizedAccessException] {
error "Access denied: $dir. You might need to restart."
continue
}
$manifest = installed_manifest $app $version $global
$install = install_info $app $version $global
$architecture = $install.architecture
$manifest = installed_manifest $app $version $global
$install = install_info $app $version $global
$architecture = $install.architecture
Invoke-HookScript -HookType 'pre_uninstall' -Manifest $manifest -Arch $architecture
run_uninstaller $manifest $architecture $dir
rm_shims $manifest $global $architecture
rm_startmenu_shortcuts $manifest $global $architecture
# If a junction was used during install, that will have been used
# as the reference directory. Otherwise it will just be the version
# directory.
$refdir = unlink_current $dir
uninstall_psmodule $manifest $refdir $global
env_rm_path $manifest $refdir $global
env_rm $manifest $global
try {
# unlink all potential old link before doing recursive Remove-Item
unlink_persist_data $dir
Remove-Item $dir -Recurse -Force -ErrorAction Stop
} catch {
if (Test-Path $dir) {
error "Couldn't remove '$(friendly_path $dir)'; it may be in use."
#region Workaround for #2952
if (test_running_process $app $global) {
continue
}
}
#endregion Workaround for #2952
try {
Test-Path $dir -ErrorAction Stop | Out-Null
} catch [UnauthorizedAccessException] {
error "Access denied: $dir. You might need to restart."
continue
}
Invoke-Installer -Path $dir -Manifest $manifest -ProcessorArchitecture $architecture -Uninstall
rm_shims $app $manifest $global $architecture
rm_startmenu_shortcuts $manifest $global $architecture
# If a junction was used during install, that will have been used
# as the reference directory. Otherwise it will just be the version
# directory.
$refdir = unlink_current $dir
uninstall_psmodule $manifest $refdir $global
env_rm_path $manifest $refdir $global $architecture
env_rm $manifest $global $architecture
# remove older versions
$old = @(versions $app $global)
foreach ($oldver in $old) {
Write-Host "Removing older version ($oldver)."
$dir = versiondir $app $oldver $global
try {
# unlink all potential old link before doing recursive Remove-Item
unlink_persist_data $dir
unlink_persist_data $manifest $dir
Remove-Item $dir -Recurse -Force -ErrorAction Stop
} catch {
if (Test-Path $dir) {
error "Couldn't remove '$(friendly_path $dir)'; it may be in use."
continue
}
}
Invoke-HookScript -HookType 'post_uninstall' -Manifest $manifest -Arch $architecture
}
# remove older versions
$oldVersions = @(Get-ChildItem $appDir -Name -Exclude 'current')
foreach ($version in $oldVersions) {
Write-Host "Removing older version ($version)."
$dir = versiondir $app $version $global
try {
# unlink all potential old link before doing recursive Remove-Item
unlink_persist_data $manifest $dir
Remove-Item $dir -Recurse -Force -ErrorAction Stop
} catch {
error "Couldn't remove '$(friendly_path $dir)'; it may be in use."
continue app_loop
}
}
if (@(versions $app $global).length -eq 0) {
$appdir = appdir $app $global
if (Test-Path ($currentDir = Join-Path $appDir 'current')) {
attrib $currentDir -R /L
Remove-Item $currentDir -ErrorAction Stop -Force
}
if (!(Get-ChildItem $appDir)) {
try {
# if last install failed, the directory seems to be locked and this
# will throw an error about the directory not existing

View File

@@ -6,170 +6,276 @@
# You can use '*' in place of <app> to update all apps.
#
# Options:
# -f, --force Force update even when there isn't a newer version
# -g, --global Update a globally installed app
# -i, --independent Don't install dependencies automatically
# -k, --no-cache Don't use the download cache
# -s, --skip Skip hash validation (use with caution!)
# -q, --quiet Hide extraneous messages
# -f, --force Force update even when there isn't a newer version
# -g, --global Update a globally installed app
# -i, --independent Don't install dependencies automatically
# -k, --no-cache Don't use the download cache
# -s, --skip-hash-check Skip hash validation (use with caution!)
# -q, --quiet Hide extraneous messages
# -a, --all Update all apps (alternative to '*')
. "$psscriptroot\..\lib\core.ps1"
. "$psscriptroot\..\lib\shortcuts.ps1"
. "$psscriptroot\..\lib\psmodules.ps1"
. "$psscriptroot\..\lib\decompress.ps1"
. "$psscriptroot\..\lib\manifest.ps1"
. "$psscriptroot\..\lib\buckets.ps1"
. "$psscriptroot\..\lib\versions.ps1"
. "$psscriptroot\..\lib\getopt.ps1"
. "$psscriptroot\..\lib\depends.ps1"
. "$psscriptroot\..\lib\git.ps1"
. "$psscriptroot\..\lib\install.ps1"
. "$PSScriptRoot\..\lib\getopt.ps1"
. "$PSScriptRoot\..\lib\json.ps1" # 'save_install_info' in 'manifest.ps1' (indirectly)
. "$PSScriptRoot\..\lib\system.ps1"
. "$PSScriptRoot\..\lib\shortcuts.ps1"
. "$PSScriptRoot\..\lib\psmodules.ps1"
. "$PSScriptRoot\..\lib\decompress.ps1"
. "$PSScriptRoot\..\lib\manifest.ps1"
. "$PSScriptRoot\..\lib\versions.ps1"
. "$PSScriptRoot\..\lib\depends.ps1"
. "$PSScriptRoot\..\lib\install.ps1"
. "$PSScriptRoot\..\lib\download.ps1"
if (get_config USE_SQLITE_CACHE) {
. "$PSScriptRoot\..\lib\database.ps1"
}
reset_aliases
$opt, $apps, $err = getopt $args 'gfiksq:' 'global', 'force', 'independent', 'no-cache', 'skip', 'quiet'
$opt, $apps, $err = getopt $args 'gfiksqa' 'global', 'force', 'independent', 'no-cache', 'skip-hash-check', 'quiet', 'all'
if ($err) { "scoop update: $err"; exit 1 }
$global = $opt.g -or $opt.global
$force = $opt.f -or $opt.force
$check_hash = !($opt.s -or $opt.skip)
$check_hash = !($opt.s -or $opt.'skip-hash-check')
$use_cache = !($opt.k -or $opt.'no-cache')
$quiet = $opt.q -or $opt.quiet
$independent = $opt.i -or $opt.independent
$all = $opt.a -or $opt.all
# load config
$repo = $(get_config SCOOP_REPO)
if (!$repo) {
$repo = "https://github.com/lukesampson/scoop"
set_config SCOOP_REPO "$repo" | Out-Null
$configRepo = get_config SCOOP_REPO
if (!$configRepo) {
$configRepo = 'https://github.com/ScoopInstaller/Scoop'
set_config SCOOP_REPO $configRepo | Out-Null
}
# Find current update channel from config
$branch = $(get_config SCOOP_BRANCH)
if (!$branch) {
$branch = "master"
set_config SCOOP_BRANCH "$branch" | Out-Null
$configBranch = get_config SCOOP_BRANCH
if (!$configBranch) {
$configBranch = 'master'
set_config SCOOP_BRANCH $configBranch | Out-Null
}
if(($PSVersionTable.PSVersion.Major) -lt 5) {
if (($PSVersionTable.PSVersion.Major) -lt 5) {
# check powershell version
# should be deleted after Oct 1, 2019
If ((Get-Date).ToUniversalTime() -ge "2019-10-01") {
Write-Output "PowerShell 5 or later is required to run Scoop."
Write-Output "Upgrade PowerShell: https://docs.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell"
break
} else {
Write-Output "Scoop is going to stop supporting old version of PowerShell."
Write-Output "Please upgrade to PowerShell 5 or later version before Oct 1, 2019 UTC."
Write-Output "Guideline: https://docs.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell"
}
Write-Output 'PowerShell 5 or later is required to run Scoop.'
Write-Output 'Upgrade PowerShell: https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-windows'
break
}
$show_update_log = get_config SHOW_UPDATE_LOG $true
function Sync-Scoop {
[CmdletBinding()]
Param (
[Switch]$Log
)
# Test if Scoop Core is hold
if (Test-ScoopCoreOnHold) {
return
}
function update_scoop() {
# check for git
if(!(Test-CommandAvailable git)) { abort "Scoop uses Git to update itself. Run 'scoop install git' and try again." }
if (!(Test-GitAvailable)) { abort "Scoop uses Git to update itself. Run 'scoop install git' and try again." }
write-host "Updating Scoop..."
$last_update = $(last_scoop_update)
if ($null -eq $last_update) {$last_update = [System.DateTime]::Now}
$last_update = $last_update.ToString('s')
$show_update_log = get_config 'show_update_log' $true
$currentdir = fullpath $(versiondir 'scoop' 'current')
if (!(test-path "$currentdir\.git")) {
$newdir = fullpath $(versiondir 'scoop' 'new')
Write-Host 'Updating Scoop...'
$currentdir = versiondir 'scoop' 'current'
if (!(Test-Path "$currentdir\.git")) {
$newdir = "$currentdir\..\new"
$olddir = "$currentdir\..\old"
# get git scoop
git_clone -q $repo --branch $branch --single-branch "`"$newdir`""
Invoke-Git -ArgumentList @('clone', '-q', $configRepo, '--branch', $configBranch, '--single-branch', $newdir)
# check if scoop was successful downloaded
if (!(test-path "$newdir")) {
abort 'Scoop update failed.'
if (!(Test-Path "$newdir\bin\scoop.ps1")) {
Remove-Item $newdir -Force -Recurse
abort "Scoop download failed. If this appears several times, try removing SCOOP_REPO by 'scoop config rm SCOOP_REPO'"
} else {
# replace non-git scoop with the git version
try {
Rename-Item $currentdir 'old' -ErrorAction Stop
Rename-Item $newdir 'current' -ErrorAction Stop
} catch {
Write-Warning $_
abort "Scoop update failed. Folder in use. Please rename folders $currentdir to ``old`` and $newdir to ``current``."
}
}
} else {
if (Test-Path "$currentdir\..\old") {
Remove-Item "$currentdir\..\old" -Recurse -Force -ErrorAction SilentlyContinue
}
# replace non-git scoop with the git version
Remove-Item -r -force $currentdir -ea stop
Move-Item $newdir $currentdir
} else {
Push-Location $currentdir
$previousCommit = Invoke-Git -Path $currentdir -ArgumentList @('rev-parse', 'HEAD')
$currentRepo = Invoke-Git -Path $currentdir -ArgumentList @('config', 'remote.origin.url')
$currentBranch = Invoke-Git -Path $currentdir -ArgumentList @('branch')
# Change branch if user configured other branch
if (!((git_branch) -match "\*\s+$branch")) {
# reset git fetch refs (GH-3368)
git_config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
# fetch remote branches
git_fetch --force origin -q
$isRepoChanged = !($currentRepo -match $configRepo)
$isBranchChanged = !($currentBranch -match "\*\s+$configBranch")
# Stash uncommitted changes
if (Invoke-Git -Path $currentdir -ArgumentList @('diff', 'HEAD', '--name-only')) {
if (get_config AUTOSTASH_ON_CONFLICT) {
warn 'Uncommitted changes detected. Stashing...'
Invoke-Git -Path $currentdir -ArgumentList @('stash', 'push', '-m', "WIP at $([System.DateTime]::Now.ToString('o'))", '-u', '-q')
} else {
warn 'Uncommitted changes detected. Update aborted.'
return
}
}
# Change remote url if the repo is changed
if ($isRepoChanged) {
Invoke-Git -Path $currentdir -ArgumentList @('config', 'remote.origin.url', $configRepo)
}
# Fetch and reset local repo if the repo or the branch is changed
if ($isRepoChanged -or $isBranchChanged) {
# Reset git fetch refs, so that it can fetch all branches (GH-3368)
Invoke-Git -Path $currentdir -ArgumentList @('config', 'remote.origin.fetch', '+refs/heads/*:refs/remotes/origin/*')
# fetch remote branch
Invoke-Git -Path $currentdir -ArgumentList @('fetch', '--force', 'origin', "refs/heads/$configBranch`:refs/remotes/origin/$configBranch", '-q')
# checkout and track the branch
git_checkout -B $branch -t origin/$branch -q
Invoke-Git -Path $currentdir -ArgumentList @('checkout', '-B', $configBranch, '-t', "origin/$configBranch", '-q')
# reset branch HEAD
git_reset --hard origin/$branch -q
Invoke-Git -Path $currentdir -ArgumentList @('reset', '--hard', "origin/$configBranch", '-q')
} else {
git_pull -q
Invoke-Git -Path $currentdir -ArgumentList @('pull', '-q')
}
$res = $lastexitcode
if ($show_update_log) {
git_log --no-decorate --date=local --since="`"$last_update`"" --format="`"tformat: * %C(yellow)%h%Creset %<|(72,trunc)%s %C(cyan)%cr%Creset`"" HEAD
if ($Log) {
Invoke-GitLog -Path $currentdir -CommitHash $previousCommit
}
Pop-Location
if ($res -ne 0) {
abort 'Update failed.'
}
}
if ((Get-LocalBucket) -notcontains 'main') {
info "The main bucket of Scoop has been separated to 'https://github.com/ScoopInstaller/Main'"
info "Adding main bucket..."
add_bucket 'main'
}
ensure_scoop_in_path
shim "$currentdir\bin\scoop.ps1" $false
}
Get-LocalBucket | ForEach-Object {
write-host "Updating '$_' bucket..."
function Sync-Bucket {
Param (
[Switch]$Log
)
Write-Host 'Updating Buckets...'
$loc = Find-BucketDirectory $_ -Root
# Make sure main bucket, which was downloaded as zip, will be properly "converted" into git
if (($_ -eq 'main') -and !(Test-Path "$loc\.git")) {
rm_bucket 'main'
add_bucket 'main'
if (!(Test-Path (Join-Path (Find-BucketDirectory 'main' -Root) '.git'))) {
info "Converting 'main' bucket to git repo..."
$status = rm_bucket 'main'
if ($status -ne 0) {
abort "Failed to remove local 'main' bucket."
}
Push-Location $loc
git_pull -q
if ($show_update_log) {
git_log --no-decorate --date=local --since="`"$last_update`"" --format="`"tformat: * %C(yellow)%h%Creset %<|(72,trunc)%s %C(cyan)%cr%Creset`"" HEAD
$status = add_bucket 'main' (known_bucket_repo 'main')
if ($status -ne 0) {
abort "Failed to add remote 'main' bucket."
}
Pop-Location
}
set_config lastupdate ([System.DateTime]::Now.ToString('o')) | Out-Null
success 'Scoop was updated successfully!'
$buckets = Get-LocalBucket | ForEach-Object {
$path = Find-BucketDirectory $_ -Root
return @{
name = $_
valid = Test-Path (Join-Path $path '.git')
path = $path
}
}
$buckets | Where-Object { !$_.valid } | ForEach-Object { Write-Host "'$($_.name)' is not a git repository. Skipped." }
$updatedFiles = [System.Collections.ArrayList]::Synchronized([System.Collections.ArrayList]::new())
$removedFiles = [System.Collections.ArrayList]::Synchronized([System.Collections.ArrayList]::new())
if ($PSVersionTable.PSVersion.Major -ge 7) {
# Parallel parameter is available since PowerShell 7
$buckets | Where-Object { $_.valid } | ForEach-Object -ThrottleLimit 5 -Parallel {
. "$using:PSScriptRoot\..\lib\core.ps1"
. "$using:PSScriptRoot\..\lib\buckets.ps1"
$name = $_.name
$bucketLoc = $_.path
$innerBucketLoc = Find-BucketDirectory $name
$previousCommit = Invoke-Git -Path $bucketLoc -ArgumentList @('rev-parse', 'HEAD')
Invoke-Git -Path $bucketLoc -ArgumentList @('pull', '-q')
if ($using:Log) {
Invoke-GitLog -Path $bucketLoc -Name $name -CommitHash $previousCommit
}
if (get_config USE_SQLITE_CACHE) {
Invoke-Git -Path $bucketLoc -ArgumentList @('diff', '--name-status', $previousCommit) | ForEach-Object {
$status, $file = $_ -split '\s+', 2
$filePath = Join-Path $bucketLoc $file
if ($filePath -match "^$([regex]::Escape($innerBucketLoc)).*\.json$") {
switch ($status) {
{ $_ -in 'A', 'M', 'R' } {
[void]($using:updatedFiles).Add($filePath)
}
'D' {
[void]($using:removedFiles).Add([pscustomobject]@{
Name = ([System.IO.FileInfo]$file).BaseName
Bucket = $name
})
}
}
}
}
}
}
} else {
$buckets | Where-Object { $_.valid } | ForEach-Object {
$name = $_.name
$bucketLoc = $_.path
$innerBucketLoc = Find-BucketDirectory $name
$previousCommit = Invoke-Git -Path $bucketLoc -ArgumentList @('rev-parse', 'HEAD')
Invoke-Git -Path $bucketLoc -ArgumentList @('pull', '-q')
if ($Log) {
Invoke-GitLog -Path $bucketLoc -Name $name -CommitHash $previousCommit
}
if (get_config USE_SQLITE_CACHE) {
Invoke-Git -Path $bucketLoc -ArgumentList @('diff', '--name-status', $previousCommit) | ForEach-Object {
$status, $file = $_ -split '\s+', 2
$filePath = Join-Path $bucketLoc $file
if ($filePath -match "^$([regex]::Escape($innerBucketLoc)).*\.json$") {
switch ($status) {
{ $_ -in 'A', 'M', 'R' } {
[void]($updatedFiles).Add($filePath)
}
'D' {
[void]($removedFiles).Add([pscustomobject]@{
Name = ([System.IO.FileInfo]$file).BaseName
Bucket = $name
})
}
}
}
}
}
}
}
if ((get_config USE_SQLITE_CACHE) -and ($updatedFiles.Count -gt 0 -or $removedFiles.Count -gt 0)) {
info 'Updating cache...'
Set-ScoopDB -Path $updatedFiles
$removedFiles | Remove-ScoopDBItem
}
}
function update($app, $global, $quiet = $false, $independent, $suggested, $use_cache = $true, $check_hash = $true) {
$old_version = current_version $app $global
$old_version = Select-CurrentVersion -AppName $app -Global:$global
$old_manifest = installed_manifest $app $old_version $global
$install = install_info $app $old_version $global
# re-use architecture, bucket and url from first install
$architecture = ensure_architecture $install.architecture
$architecture = Format-ArchitectureString $install.architecture
$bucket = $install.bucket
if ($null -eq $bucket) {
$bucket = 'main'
}
$url = $install.url
if (!$independent) {
# check dependencies
$deps = @(deps $app $architecture) | Where-Object { !(installed $_) }
$deps | ForEach-Object { install_app $_ $architecture $global $suggested $use_cache $check_hash }
}
$version = latest_version $app $bucket $url
$manifest = manifest $app $bucket $url
$version = $manifest.version
$is_nightly = $version -eq 'nightly'
if ($is_nightly) {
$version = nightly_version $(get-date) $quiet
$version = nightly_version $quiet
$check_hash = $false
}
@@ -185,37 +291,42 @@ function update($app, $global, $quiet = $false, $independent, $suggested, $use_c
return
}
$manifest = manifest $app $bucket $url
Write-Host "Updating '$app' ($old_version -> $version)"
write-host "Updating '$app' ($old_version -> $version)"
#region Workaround for #2952
if (test_running_process $app $global) {
Write-Host 'Running process detected, skip updating.'
return
}
#endregion Workaround for #2952
# region Workaround
# Workaround for https://github.com/lukesampson/scoop/issues/2220 until install is refactored
# Workaround for https://github.com/ScoopInstaller/Scoop/issues/2220 until install is refactored
# Remove and replace whole region after proper fix
Write-Host "Downloading new version"
Write-Host 'Downloading new version'
if (Test-Aria2Enabled) {
dl_with_cache_aria2 $app $version $manifest $architecture $cachedir $manifest.cookie $true $check_hash
Invoke-CachedAria2Download $app $version $manifest $architecture $cachedir $manifest.cookie $true $check_hash
} else {
$urls = url $manifest $architecture
$urls = script:url $manifest $architecture
foreach ($url in $urls) {
dl_with_cache $app $version $url $null $manifest.cookie $true
Invoke-CachedDownload $app $version $url $null $manifest.cookie $true
if ($check_hash) {
$manifest_hash = hash_for_url $manifest $url $architecture
$source = fullpath (cache_path $app $version $url)
$source = cache_path $app $version $url
$ok, $err = check_hash $source $manifest_hash $(show_app $app $bucket)
if (!$ok) {
error $err
if (test-path $source) {
if (Test-Path $source) {
# rm cached file
Remove-Item -force $source
Remove-Item -Force $source
}
if ($url.Contains('sourceforge.net')) {
Write-Host -f yellow 'SourceForge.net is known for causing hash validation fails. Please try again before opening a ticket.'
}
abort $(new_issue_msg $app $bucket "hash check failed")
abort $(new_issue_msg $app $bucket 'hash check failed')
}
}
}
@@ -225,17 +336,21 @@ function update($app, $global, $quiet = $false, $independent, $suggested, $use_c
# endregion Workaround
$dir = versiondir $app $old_version $global
$persist_dir = persistdir $app $global
write-host "Uninstalling '$app' ($old_version)"
run_uninstaller $old_manifest $architecture $dir
rm_shims $old_manifest $global $architecture
env_rm_path $old_manifest $dir $global
env_rm $old_manifest $global
Invoke-HookScript -HookType 'pre_uninstall' -Manifest $old_manifest -Arch $architecture
Write-Host "Uninstalling '$app' ($old_version)"
Invoke-Installer -Path $dir -Manifest $old_manifest -ProcessorArchitecture $architecture -Uninstall
rm_shims $app $old_manifest $global $architecture
# If a junction was used during install, that will have been used
# as the reference directory. Otherwise it will just be the version
# directory.
$refdir = unlink_current $dir
uninstall_psmodule $old_manifest $refdir $global
env_rm_path $old_manifest $refdir $global $architecture
env_rm $old_manifest $global $architecture
if ($force -and ($old_version -eq $version)) {
if (!(Test-Path "$dir/../_$version.old")) {
@@ -249,70 +364,103 @@ function update($app, $global, $quiet = $false, $independent, $suggested, $use_c
}
}
Invoke-HookScript -HookType 'post_uninstall' -Manifest $old_manifest -Arch $architecture
if ($bucket) {
# add bucket name it was installed from
$app = "$bucket/$app"
}
install_app $app $architecture $global $suggested $use_cache $check_hash
if ($install.url) {
# use the url of the install json if the application was installed through url
$app = $install.url
}
if ($independent) {
install_app $app $architecture $global $suggested $use_cache $check_hash
} else {
# Also add missing dependencies
$apps = @(Get-Dependency $app $architecture) -ne $app
ensure_none_failed $apps
$apps.Where({ !(installed $_) }) + $app | ForEach-Object { install_app $_ $architecture $global $suggested $use_cache $check_hash }
}
}
if (!$apps) {
if (-not ($apps -or $all)) {
if ($global) {
"scoop update: --global is invalid when <app> is not specified."; exit 1
error 'scoop update: --global is invalid when <app> is not specified.'
exit 1
}
if (!$use_cache) {
"scoop update: --no-cache is invalid when <app> is not specified."; exit 1
error 'scoop update: --no-cache is invalid when <app> is not specified.'
exit 1
}
update_scoop
Sync-Scoop -Log:$show_update_log
Sync-Bucket -Log:$show_update_log
set_config LAST_UPDATE ([System.DateTime]::Now.ToString('o')) | Out-Null
success 'Scoop was updated successfully!'
} else {
if ($global -and !(is_admin)) {
'ERROR: You need admin rights to update global apps.'; exit 1
}
if (is_scoop_outdated) {
update_scoop
}
$outdated = @()
$updateScoop = $null -ne ($apps | Where-Object { $_ -eq 'scoop' }) -or (is_scoop_outdated)
$apps = $apps | Where-Object { $_ -ne 'scoop' }
$apps_param = $apps
if ($apps_param -eq '*') {
if ($updateScoop) {
Sync-Scoop -Log:$show_update_log
Sync-Bucket -Log:$show_update_log
set_config LAST_UPDATE ([System.DateTime]::Now.ToString('o')) | Out-Null
success 'Scoop was updated successfully!'
}
if ($apps_param -eq '*' -or $all) {
$apps = applist (installed_apps $false) $false
if ($global) {
$apps += applist (installed_apps $true) $true
}
} else {
$apps = Confirm-InstallationStatus $apps_param -Global:$global
if ($apps_param) {
$apps = Confirm-InstallationStatus $apps_param -Global:$global
}
}
if ($apps) {
$apps | ForEach-Object {
($app, $global) = $_
$status = app_status $app $global
if ($force -or $status.outdated) {
if(!$status.hold) {
if ($status.installed -and ($force -or $status.outdated)) {
if (!$status.hold) {
$outdated += applist $app $global
write-host -f yellow ("$app`: $($status.version) -> $($status.latest_version){0}" -f ('',' (global)')[$global])
Write-Host -f yellow ("$app`: $($status.version) -> $($status.latest_version){0}" -f ('', ' (global)')[$global])
} else {
warn "'$app' is locked to version $($status.version)"
warn "'$app' is held to version $($status.version)"
}
} elseif ($apps_param -ne '*' -and !$all) {
if ($status.installed) {
ensure_none_failed $app
Write-Host "$app`: $($status.version) (latest version)" -ForegroundColor Green
} else {
info 'Please reinstall it or fix the manifest.'
}
} elseif ($apps_param -ne '*') {
write-host -f green "$app`: $($status.version) (latest version)"
}
}
if ($outdated -and (Test-Aria2Enabled)) {
if ($outdated -and ((Test-Aria2Enabled) -and (get_config 'aria2-warning-enabled' $true))) {
warn "Scoop uses 'aria2c' for multi-connection downloads."
warn "Should it cause issues, run 'scoop config aria2-enabled false' to disable it."
warn "To disable this warning, run 'scoop config aria2-warning-enabled false'."
}
if ($outdated.Length -gt 1) {
write-host -f DarkCyan "Updating $($outdated.Length) outdated apps:"
Write-Host -f DarkCyan "Updating $($outdated.Length) outdated apps:"
} elseif ($outdated.Length -eq 0) {
write-host -f Green "Latest versions for all apps are installed! For more information try 'scoop status'"
Write-Host -f Green "Latest versions for all apps are installed! For more information try 'scoop status'"
} else {
write-host -f DarkCyan "Updating one outdated app:"
Write-Host -f DarkCyan 'Updating one outdated app:'
}
}
$suggested = @{};
$suggested = @{}
# $outdated is a list of ($app, $global) tuples
$outdated | ForEach-Object { update @_ $quiet $independent $suggested $use_cache $check_hash }
}

View File

@@ -1,77 +1,75 @@
# Usage: scoop virustotal [* | app1 app2 ...] [options]
# Summary: Look for app's hash on virustotal.com
# Help: Look for app's hash (MD5, SHA1 or SHA256) on virustotal.com
# Summary: Look for app's hash or url on virustotal.com
# Help: Look for app's hash or url on virustotal.com
#
# Use a single '*' for app to check all installed apps.
# Use a single '*' or the '-a/--all' switch to check all installed apps.
#
# The download's hash is also a key to access VirusTotal's scan results.
# This allows to check the safety of the files without even downloading
# them in many cases. If the hash is unknown to VirusTotal, the
# download link is printed to submit it to VirusTotal.
#
# If you have signed up to VirusTotal's community, you have an API key
# that this script can use to submit unknown packages for inspection
# if you use the `--scan' flag. Tell scoop about your API key with:
# To use this command, you have to sign up to VirusTotal's community,
# and get an API key. Then, tell scoop about your API key with:
#
# scoop config virustotal_api_key <your API key: 64 lower case hex digits>
#
# Exit codes:
# 0 -> success
# 1 -> problem parsing arguments
# 2 -> at least one package was marked unsafe by VirusTotal
# 4 -> at least one exception was raised while looking for info
# 8 -> at least one package couldn't be queried because its hash type
# isn't supported by VirusTotal, the manifest couldn't be found
# or didn't contain a hash
# 0 -> success
# 1 -> problem parsing arguments
# 2 -> at least one package was marked unsafe by VirusTotal
# 4 -> at least one exception was raised while looking for info
# 8 -> at least one package couldn't be queried because the manifest couldn't be found
# 16 -> VirusTotal API key is not configured
# Note: the exit codes (2, 4 & 8) may be combined, e.g. 6 -> exit codes
# 2 & 4 combined
#
# Options:
# -a, --arch <32bit|64bit> Use the specified architecture, if the app supports it
# -s, --scan For packages where VirusTotal has no information, send download URL
# for analysis (and future retrieval). This requires you to configure
# your virustotal_api_key.
# -n, --no-depends By default, all dependencies are checked, too. This flag allows
# to avoid it.
# -a, --all Check for all installed apps
# -s, --scan For packages where VirusTotal has no information, send download URL
# for analysis (and future retrieval). This requires you to configure
# your virustotal_api_key.
# -n, --no-depends By default, all dependencies are checked too. This flag avoids it.
# -u, --no-update-scoop Don't update Scoop before checking if it's outdated
# -p, --passthru Return reports as objects
. "$psscriptroot\..\lib\core.ps1"
. "$psscriptroot\..\lib\help.ps1"
. "$psscriptroot\..\lib\getopt.ps1"
. "$psscriptroot\..\lib\manifest.ps1"
. "$psscriptroot\..\lib\buckets.ps1"
. "$psscriptroot\..\lib\json.ps1"
. "$psscriptroot\..\lib\decompress.ps1"
. "$psscriptroot\..\lib\install.ps1"
. "$psscriptroot\..\lib\depends.ps1"
. "$PSScriptRoot\..\lib\getopt.ps1"
. "$PSScriptRoot\..\lib\manifest.ps1" # 'Get-Manifest'
. "$PSScriptRoot\..\lib\json.ps1" # 'json_path'
. "$PSScriptRoot\..\lib\download.ps1" # 'hash_for_url'
. "$PSScriptRoot\..\lib\depends.ps1" # 'Get-Dependency'
reset_aliases
$opt, $apps, $err = getopt $args 'asnup' @('all', 'scan', 'no-depends', 'no-update-scoop', 'passthru')
if ($err) { "scoop virustotal: $err"; exit 1 }
$all = $apps -eq '*' -or $opt.a -or $opt.all
if (!$apps -and !$all) { my_usage; exit 1 }
$architecture = Get-DefaultArchitecture
$opt, $apps, $err = getopt $args 'a:sn' @('arch=', 'scan', 'no-depends')
if($err) { "scoop virustotal: $err"; exit 1 }
if(!$apps) { my_usage; exit 1 }
$architecture = ensure_architecture ($opt.a + $opt.arch)
if(is_scoop_outdated) { scoop update }
$apps_param = $apps
if($apps_param -eq '*') {
$apps = installed_apps $false
$apps += installed_apps $true
if (is_scoop_outdated) {
if ($opt.u -or $opt.'no-update-scoop') {
warn 'Scoop is out of date.'
} else {
& "$PSScriptRoot\scoop-update.ps1"
}
}
if (!$opt.n -and !$opt."no-depends") {
$apps = install_order $apps $architecture
if ($all) {
$apps = (installed_apps $false) + (installed_apps $true)
}
if (!$opt.n -and !$opt.'no-depends') {
$apps = $apps | Get-Dependency -Architecture $architecture | Select-Object -Unique
}
$_ERR_UNSAFE = 2
$_ERR_EXCEPTION = 4
$_ERR_NO_INFO = 8
$_ERR_NO_API_KEY = 16
$exit_code = 0
# Global flag to warn only once about missing API key:
$warned_no_api_key = $False
# Global API key:
$api_key = get_config VIRUSTOTAL_API_KEY
if (!$api_key) {
abort ("VirusTotal API key is not configured`n" +
" You could get one from https://www.virustotal.com/gui/my-apikey and set with`n" +
" scoop config virustotal_api_key <API key>") $_ERR_NO_API_KEY
}
# Global flag to explain only once about sleep between requests
$explained_rate_limit_sleeping = $False
@@ -80,66 +78,127 @@ $explained_rate_limit_sleeping = $False
# script execution progresses
$requests = 0
Function Get-VirusTotalResult($hash, $app) {
$hash = $hash.ToLower()
$url = "https://www.virustotal.com/ui/files/$hash"
$wc = New-Object Net.Webclient
$wc.Headers.Add('User-Agent', (Get-UserAgent))
$result = $wc.downloadstring($url)
$stats = json_path $result '$.data.attributes.last_analysis_stats'
$malicious = json_path $stats '$.malicious'
$suspicious = json_path $stats '$.suspicious'
$undetected = json_path $stats '$.undetected'
$unsafe = [int]$malicious + [int]$suspicious
$see_url = "see https://www.virustotal.com/#/file/$hash/detection"
switch ($unsafe) {
0 { if ($undetected -eq 0) { $fg = "Yellow" } else { $fg = "DarkGreen" } }
1 { $fg = "DarkYellow" }
2 { $fg = "Yellow" }
default { $fg = "Red" }
}
write-host -f $fg "$app`: $unsafe/$undetected, $see_url"
if($unsafe -gt 0) {
return $_ERR_UNSAFE
}
return 0
Function ConvertTo-VirusTotalUrlId ($url) {
$url_id = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($url))
$url_id = $url_id -replace '\+', '-'
$url_id = $url_id -replace '/', '_'
$url_id = $url_id -replace '=', ''
$url_id
}
Function Search-VirusTotal ($hash, $app) {
if ($hash -match '(?<algo>[^:]+):(?<hash>.*)') {
$hash = $matches['hash']
if ($matches['algo'] -match '(md5|sha1|sha256)') {
return Get-VirusTotalResult $hash $app
} else {
warn "$app`: Unsupported hash $($matches['algo']). VirusTotal needs md5, sha1 or sha256."
return $_ERR_NO_INFO
Function Get-VirusTotalResultByHash ($hash, $url, $app) {
$hash = $hash.ToLower()
$api_url = "https://www.virustotal.com/api/v3/files/$hash"
$headers = @{}
$headers.Add('Accept', 'application/json')
$headers.Add('x-apikey', $api_key)
$response = Invoke-WebRequest -Uri $api_url -Method GET -Headers $headers -UseBasicParsing
$result = $response.Content
$stats = json_path $result '$.data.attributes.last_analysis_stats'
[int]$malicious = json_path $stats '$.malicious'
[int]$suspicious = json_path $stats '$.suspicious'
[int]$timeout = json_path $stats '$.timeout'
[int]$undetected = json_path $stats '$.undetected'
[int]$unsafe = $malicious + $suspicious
[int]$total = $unsafe + $undetected
[int]$fileSize = json_path $result '$.data.attributes.size'
$report_hash = json_path $result '$.data.attributes.sha256'
$report_url = "https://www.virustotal.com/gui/file/$report_hash"
if ($total -eq 0) {
info "$app`: Analysis in progress."
[PSCustomObject] @{
'App.Name' = $app
'App.Url' = $url
'App.Hash' = $hash
'App.HashType' = $null
'App.Size' = filesize $fileSize
'FileReport.Url' = $report_url
'FileReport.Hash' = $report_hash
'UrlReport.Url' = $null
}
} else {
$vendorResults = (ConvertFrom-Json((json_path $result '$.data.attributes.last_analysis_results'))).PSObject.Properties.Value
switch ($unsafe) {
0 {
success "$app`: $unsafe/$total, see $report_url"
}
1 {
warn "$app`: $unsafe/$total, see $report_url"
}
2 {
warn "$app`: $unsafe/$total, see $report_url"
}
Default {
warn "$([char]0x1b)[31m$app`: $unsafe/$total, see $report_url$([char]0x1b)[0m"
}
}
$maliciousResults = $vendorResults |
Where-Object -Property category -EQ 'malicious' |
Select-Object -ExpandProperty engine_name
$suspiciousResults = $vendorResults |
Where-Object -Property category -EQ 'suspicious' |
Select-Object -ExpandProperty engine_name
[PSCustomObject] @{
'App.Name' = $app
'App.Url' = $url
'App.Hash' = $hash
'App.HashType' = $null
'App.Size' = filesize $fileSize
'FileReport.Url' = $report_url
'FileReport.Hash' = $report_hash
'FileReport.Malicious' = if ($maliciousResults) { $maliciousResults } else { 0 }
'FileReport.Suspicious' = if ($suspiciousResults) { $suspiciousResults } else { 0 }
'FileReport.Timeout' = $timeout
'FileReport.Undetected' = $undetected
'UrlReport.Url' = $null
}
}
return Get-VirusTotalResult $hash $app
if ($unsafe -gt 0) {
$Script:exit_code = $exit_code -bor $_ERR_UNSAFE
}
}
Function Submit-RedirectedUrl {
# Follow up to one level of HTTP redirection
#
# Copied from http://www.powershellmagazine.com/2013/01/29/pstip-retrieve-a-redirected-url/
# Adapted according to Roy's response (January 23, 2014 at 11:59 am)
# Adapted to always return an URL
Param (
[Parameter(Mandatory=$true)]
[String]$URL
)
$request = [System.Net.WebRequest]::Create($url)
$request.AllowAutoRedirect=$false
$response=$request.GetResponse()
if (([int]$response.StatusCode -ge 300) -and ([int]$response.StatusCode -lt 400)) {
$redir = $response.GetResponseHeader("Location")
Function Get-VirusTotalResultByUrl ($url, $app) {
$id = ConvertTo-VirusTotalUrlId $url
$api_url = "https://www.virustotal.com/api/v3/urls/$id"
$headers = @{}
$headers.Add('Accept', 'application/json')
$headers.Add('x-apikey', $api_key)
$response = Invoke-WebRequest -Uri $api_url -Method GET -Headers $headers -UseBasicParsing
$result = $response.Content
$id = json_path $result '$.data.id'
$hash = json_path $result '$.data.attributes.last_http_response_content_sha256' 6>$null
$last_analysis_date = json_path $result '$.data.attributes.last_analysis_date' 6>$null
$url_report_url = "https://www.virustotal.com/gui/url/$id"
info "$app`: Url report found."
if (!$hash) {
if (!$last_analysis_date) {
info "$app`: Analysis in progress."
} else {
info "$app`: Related file report not found."
warn "$app`: Manual file upload is required (instead of url submission)."
}
[PSCustomObject] @{
'App.Name' = $app
'App.Url' = $url
'App.Hash' = $null
'App.HashType' = $null
'FileReport.Url' = $null
'UrlReport.Url' = $url_report_url
'UrlReport.Hash' = $null
}
} else {
info "$app`: Related file report found."
[PSCustomObject] @{
'App.Name' = $app
'App.Url' = $url
'App.Hash' = $null
'App.HashType' = $null
'FileReport.Url' = $null
'UrlReport.Url' = $url_report_url
'UrlReport.Hash' = $hash
}
}
else {
$redir = $URL
}
$response.Close()
return $redir
}
# Submit-ToVirusTotal
@@ -152,33 +211,39 @@ Function Submit-RedirectedUrl {
# submitting the file after a delay if the rate limit is
# exceeded, without risking an infinite loop (as stack
# overflow) if the submission keeps failing.
Function Submit-ToVirusTotal ($url, $app, $do_scan, $retrying=$False) {
$api_key = get_config("virustotal_api_key")
if ($do_scan -and !$api_key -and !$warned_no_api_key) {
$warned_no_api_key = $true
info "Submitting unknown apps needs a VirusTotal API key. " +
"Set it up with`n`tscoop config virustotal_api_key <API key>"
}
if (!$do_scan -or !$api_key) {
warn "$app`: not found`: manually submit $url"
Function Submit-ToVirusTotal ($url, $app, $do_scan, $retrying = $False) {
if (!$do_scan) {
warn "$app`: not found`: you can manually submit $url"
return
}
try {
# Follow redirections (for e.g. sourceforge URLs) because
# VirusTotal analyzes only "direct" download links
$url = $url.Split("#").GetValue(0)
$new_redir = $url
do {
$orig_redir = $new_redir
$new_redir = Submit-RedirectedUrl $orig_redir
} while ($orig_redir -ne $new_redir)
$requests += 1
$result = Invoke-WebRequest -Uri "https://www.virustotal.com/vtapi/v2/url/scan" -Body @{apikey=$api_key;url=$new_redir} -Method Post -UseBasicParsing
$submitted = $result.StatusCode -eq 200
if ($submitted) {
warn "$app`: not found`: submitted $url"
$encoded_url = [System.Web.HttpUtility]::UrlEncode($url)
$api_url = 'https://www.virustotal.com/api/v3/urls'
$content_type = 'application/x-www-form-urlencoded'
$headers = @{}
$headers.Add('Accept', 'application/json')
$headers.Add('x-apikey', $api_key)
$headers.Add('Content-Type', $content_type)
$body = "url=$encoded_url"
$result = Invoke-WebRequest -Uri $api_url -Method POST -Headers $headers -ContentType $content_type -Body $body -UseBasicParsing
if ($result.StatusCode -eq 200) {
$id = ((json_path $result '$.data.id') -split '-')[1]
$url_report_url = "https://www.virustotal.com/gui/url/$id"
$fileSize = Get-RemoteFileSize $url
if ($fileSize -gt 80000000) {
info "$app`: Remote file size: $(filesize $fileSize). Large files might require manual file upload instead of url submission."
}
info "$app`: Analysis in progress."
[PSCustomObject] @{
'App.Name' = $app
'App.Url' = $url
'App.Size' = filesize $fileSize
'FileReport.Url' = $null
'UrlReport.Url' = $url_report_url
}
return
}
@@ -189,10 +254,10 @@ Function Submit-ToVirusTotal ($url, $app, $do_scan, $retrying=$False) {
info "Sleeping 60+ seconds between requests due to VirusTotal's 4/min limit"
}
Start-Sleep -s (60 + $requests)
Submit-ToVirusTotal $new_redir $app $do_scan $True
Submit-ToVirusTotal $url $app $do_scan $True
} else {
warn "$app`: VirusTotal submission of $url failed`:`n" +
"`tAPI returned $($result.StatusCode) after retrying"
"`tAPI returned $($result.StatusCode) after retrying"
}
} catch [Exception] {
warn "$app`: VirusTotal submission failed`: $($_.Exception.Message)"
@@ -200,39 +265,120 @@ Function Submit-ToVirusTotal ($url, $app, $do_scan, $retrying=$False) {
}
}
$apps | ForEach-Object {
$reports = $apps | ForEach-Object {
$app = $_
# write-host $app
$manifest, $bucket = find_manifest $app
if(!$manifest) {
$null, $manifest, $bucket, $null = Get-Manifest $app
if (!$manifest) {
$exit_code = $exit_code -bor $_ERR_NO_INFO
warn "$app`: manifest not found"
return
}
$urls = url $manifest $architecture
[int]$index = 0
$urls = script:url $manifest $architecture
$urls | ForEach-Object {
$url = $_
$index++
if ($urls.GetType().IsArray) {
info "$app`: url $index"
}
$hash = hash_for_url $manifest $url $architecture
try {
if($hash) {
$exit_code = $exit_code -bor (Search-VirusTotal $hash $app)
} else {
warn "$app`: Can't find hash for $url"
$isHashUnsupported = $false
if ($hash -match '(?<algo>[^:]+):(?<hash>.*)') {
$algo = $matches.algo
$hash = $matches.hash
if ($matches.algo -inotin 'md5', 'sha1', 'sha256') {
$hash = $null
$isHashUnsupported = $true
warn "$app`: Unsupported hash $($matches.algo). Will search by url instead."
}
} elseif ($hash) {
$algo = 'sha256'
}
if ($hash) {
$file_report = Get-VirusTotalResultByHash $hash $url $app
$file_report.'App.HashType' = $algo
$file_report
return
} elseif (!$isHashUnsupported) {
warn "$app`: Hash not found. Will search by url instead."
}
} catch [Exception] {
$exit_code = $exit_code -bor $_ERR_EXCEPTION
if ($_.Exception.Message -like "*(404)*") {
Submit-ToVirusTotal $url $app ($opt.scan -or $opt.s)
if ($_.Exception.Response.StatusCode -eq 404) {
$file_report_not_found = $true
warn "$app`: File report not found. Will search by url instead."
} else {
if ($_.Exception.Message -match "\(204|429\)") {
abort "$app`: VirusTotal request failed`: $($_.Exception.Message)", $exit_code
if ($_.Exception.Response.StatusCode -in 204, 429) {
abort "$app`: VirusTotal request failed`: $($_.Exception.Message)" $exit_code
}
warn "$app`: VirusTotal request failed`: $($_.Exception.Message)"
return
}
}
try {
$url_report = Get-VirusTotalResultByUrl $url $app
$url_report.'App.Hash' = $hash
$url_report.'App.HashType' = $algo
if ($url_report.'UrlReport.Hash' -and ($file_report_not_found -eq $true) -and $hash) {
if ($algo -eq 'sha256') {
if ($url_report.'UrlReport.Hash' -eq $hash) {
warn "$app`: Manual file upload is required (instead of url submission) for $url"
} else {
error "$app`: Hash not matched for $url"
}
} else {
error "$app`: Hash not matched or manual file upload is required (instead of url submission) for $url"
}
$url_report
return
}
if (!$url_report.'UrlReport.Hash') {
$url_report
return
}
} catch [Exception] {
$exit_code = $exit_code -bor $_ERR_EXCEPTION
if ($_.Exception.Response.StatusCode -eq 404) {
warn "$app`: Url report not found. Will submit $url"
Submit-ToVirusTotal $url $app ($opt.scan -or $opt.s)
return
} else {
if ($_.Exception.Response.StatusCode -in 204, 429) {
abort "$app`: VirusTotal request failed`: $($_.Exception.Message)" $exit_code
}
warn "$app`: VirusTotal request failed`: $($_.Exception.Message)"
return
}
}
try {
$file_report = Get-VirusTotalResultByHash $url_report.'UrlReport.Hash' $url $app
$file_report.'App.Hash' = $hash
$file_report.'App.HashType' = $algo
$file_report.'UrlReport.Url' = $url_report.'UrlReport.Url'
$file_report
warn "$app`: Unable to check hash match for $url"
} catch [Exception] {
$exit_code = $exit_code -bor $_ERR_EXCEPTION
if ($_.Exception.Response.StatusCode -eq 404) {
warn "$app`: File report not found for unknown reason. Manual file upload is required (instead of url submission)."
$url_report
} else {
if ($_.Exception.Response.StatusCode -in 204, 429) {
abort "$app`: VirusTotal request failed`: $($_.Exception.Message)" $exit_code
}
warn "$app`: VirusTotal request failed`: $($_.Exception.Message)"
return
}
}
}
}
if ($opt.p -or $opt.'passthru') {
$reports
}
exit $exit_code

View File

@@ -2,42 +2,19 @@
# Summary: Locate a shim/executable (similar to 'which' on Linux)
# Help: Locate the path to a shim/executable that was installed with Scoop (similar to 'which' on Linux)
param($command)
. "$psscriptroot\..\lib\core.ps1"
. "$psscriptroot\..\lib\help.ps1"
reset_aliases
if(!$command) { 'ERROR: <command> missing'; my_usage; exit 1 }
try {
$gcm = Get-Command "$command" -ea stop
} catch {
abort "'$command' not found" 3
if (!$command) {
error '<command> missing'
my_usage
exit 1
}
$path = "$($gcm.path)"
$usershims = "$(resolve-path $(shimdir $false))"
$globalshims = fullpath (shimdir $true) # don't resolve: may not exist
$path = Get-CommandPath $command
if($path.endswith(".ps1") -and ($path -like "$usershims*" -or $path -like "$globalshims*")) {
$shimtext = Get-Content $path
$exepath = ($shimtext | Where-Object { $_.startswith('$path') }).split(' ') | Select-Object -Last 1 | Invoke-Expression
if(![system.io.path]::ispathrooted($exepath)) {
# Expand relative path
$exepath = resolve-path (join-path (split-path $path) $exepath)
}
friendly_path $exepath
} elseif($gcm.commandtype -eq 'Application') {
$gcm.Source
} elseif($gcm.commandtype -eq 'Alias') {
scoop which $gcm.resolvedcommandname
} else {
[console]::error.writeline("Not a scoop shim.")
$path
if ($null -eq $path) {
warn "'$command' not found, not a scoop shim, or a broken shim."
exit 2
} else {
friendly_path $path
exit 0
}
exit 0

View File

@@ -7,6 +7,10 @@
"pattern": "^([a-fA-F0-9]{64}|(sha1|sha256|sha512|md5):([a-fA-F0-9]{32}|[a-fA-F0-9]{40}|[a-fA-F0-9]{64}|[a-fA-F0-9]{128}))$",
"type": "string"
},
"jsonPathPattern": {
"pattern": "^\\$[.\\[].*$",
"type": "string"
},
"hash": {
"anyOf": [
{
@@ -35,12 +39,13 @@
"type": "string"
},
"jp": {
"pattern": "^\\$[.[].*$",
"type": "string",
"$ref": "#/definitions/jsonPathPattern",
"description": "Same as 'jsonpath'"
},
"jsonpath": {
"pattern": "^\\$[.[].*$",
"$ref": "#/definitions/jsonPathPattern"
},
"xpath": {
"type": "string"
},
"mode": {
@@ -48,6 +53,7 @@
"download",
"extract",
"json",
"xpath",
"rdf",
"metalink",
"fosshub",
@@ -82,6 +88,21 @@
},
"type": "object"
},
"hashExtractionOrArrayOfHashExtractions": {
"anyOf": [
{
"$ref": "#/definitions/hashExtraction"
},
{
"items": {
"$ref": "#/definitions/hashExtraction"
},
"minItems": 1,
"type": "array",
"uniqueItems": false
}
]
},
"architecture": {
"additionalProperties": false,
"properties": {
@@ -91,6 +112,12 @@
"checkver": {
"$ref": "#/definitions/checkver"
},
"env_add_path": {
"$ref": "#/definitions/stringOrArrayOfStrings"
},
"env_set": {
"type": "object"
},
"extract_dir": {
"$ref": "#/definitions/stringOrArrayOfStrings"
},
@@ -100,16 +127,18 @@
"installer": {
"$ref": "#/definitions/installer"
},
"msi": {
"$ref": "#/definitions/stringOrArrayOfStrings",
"description": "Deprecated"
},
"post_install": {
"$ref": "#/definitions/stringOrArrayOfStrings"
},
"post_uninstall": {
"$ref": "#/definitions/stringOrArrayOfStrings"
},
"pre_install": {
"$ref": "#/definitions/stringOrArrayOfStrings"
},
"pre_uninstall": {
"$ref": "#/definitions/stringOrArrayOfStrings"
},
"shortcuts": {
"$ref": "#/definitions/shortcutsArray"
},
@@ -145,62 +174,110 @@
"minItems": 1,
"type": "array"
},
"autoupdate": {
"autoupdateArch": {
"type": "object",
"additionalProperties": false,
"properties": {
"architecture": {
"additionalProperties": false,
"properties": {
"32bit": {
"additionalProperties": false,
"properties": {
"extract_dir": {
"type": "string"
},
"url": {
"format": "uri",
"type": "string"
},
"hash": {
"$ref": "#/definitions/hashExtraction"
}
},
"type": "object"
},
"64bit": {
"additionalProperties": false,
"properties": {
"extract_dir": {
"type": "string"
},
"url": {
"format": "uri",
"type": "string"
},
"hash": {
"$ref": "#/definitions/hashExtraction"
}
},
"type": "object"
}
},
"bin": {
"$ref": "#/definitions/stringOrArrayOfStringsOrAnArrayOfArrayOfStrings"
},
"env_add_path": {
"$ref": "#/definitions/stringOrArrayOfStrings"
},
"env_set": {
"type": "object"
},
"extract_dir": {
"type": "string"
},
"hash": {
"$ref": "#/definitions/hashExtraction"
},
"note": {
"$ref": "#/definitions/stringOrArrayOfStrings"
},
"hash": {
"$ref": "#/definitions/hashExtractionOrArrayOfHashExtractions"
},
"installer": {
"type": "object",
"additionalProperties": false,
"properties": {
"file": {
"type": "string"
}
}
},
"shortcuts": {
"$ref": "#/definitions/shortcutsArray"
},
"url": {
"format": "uri",
"type": "string"
"$ref": "#/definitions/autoupdateUriOrArrayOfAutoupdateUris"
}
},
"type": "object"
}
},
"autoupdate": {
"type": "object",
"additionalProperties": false,
"properties": {
"architecture": {
"type": "object",
"additionalProperties": false,
"properties": {
"32bit": {
"$ref": "#/definitions/autoupdateArch"
},
"64bit": {
"$ref": "#/definitions/autoupdateArch"
},
"arm64": {
"$ref": "#/definitions/autoupdateArch"
}
}
},
"bin": {
"$ref": "#/definitions/stringOrArrayOfStringsOrAnArrayOfArrayOfStrings"
},
"env_add_path": {
"$ref": "#/definitions/stringOrArrayOfStrings"
},
"env_set": {
"type": "object"
},
"extract_dir": {
"$ref": "#/definitions/stringOrArrayOfStrings"
},
"hash": {
"$ref": "#/definitions/hashExtractionOrArrayOfHashExtractions"
},
"installer": {
"type": "object",
"additionalProperties": false,
"properties": {
"file": {
"type": "string"
}
}
},
"license": {
"$ref": "#/definitions/license"
},
"notes": {
"$ref": "#/definitions/stringOrArrayOfStrings"
},
"persist": {
"$ref": "#/definitions/stringOrArrayOfStringsOrAnArrayOfArrayOfStrings"
},
"psmodule": {
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
"type": "string"
}
}
},
"shortcuts": {
"$ref": "#/definitions/shortcutsArray"
},
"url": {
"$ref": "#/definitions/autoupdateUriOrArrayOfAutoupdateUris"
}
}
},
"checkver": {
"anyOf": [
@@ -229,12 +306,13 @@
"type": "string"
},
"jp": {
"pattern": "^\\$[.[].*$",
"type": "string",
"$ref": "#/definitions/jsonPathPattern",
"description": "Same as 'jsonpath'"
},
"jsonpath": {
"pattern": "^\\$[.[].*$",
"$ref": "#/definitions/jsonPathPattern"
},
"xpath": {
"type": "string"
},
"reverse": {
@@ -247,6 +325,29 @@
},
"useragent": {
"type": "string"
},
"script": {
"$ref": "#/definitions/stringOrArrayOfStrings",
"description": "Custom PowerShell script to retrieve application version using more complex approach."
},
"sourceforge": {
"anyOf": [
{
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"project": {
"type": "string"
},
"path": {
"type": "string"
}
},
"type": "object"
}
]
}
},
"type": "object"
@@ -352,6 +453,23 @@
}
]
},
"autoupdateUriOrArrayOfAutoupdateUris": {
"anyOf": [
{
"format": "uri",
"type": "string"
},
{
"items": {
"format": "uri",
"type": "string"
},
"minItems": 1,
"type": "array",
"uniqueItems": true
}
]
},
"licenseIdentifiers": {
"type": "string",
"description": "License identifier based on SPDX License List https://spdx.org/licenses/",
@@ -377,9 +495,36 @@
"Shareware",
"Unlicense"
]
},
"license": {
"anyOf": [
{
"$ref": "#/definitions/licenseIdentifiers"
},
{
"additionalProperties": false,
"properties": {
"url": {
"format": "uri",
"type": "string"
},
"identifier": {
"$ref": "#/definitions/licenseIdentifiers"
}
},
"required": [
"identifier"
],
"type": "object"
}
]
}
},
"properties": {
"$schema": {
"type": "string",
"format": "uri"
},
"_comment": {
"description": "Deprecated. Use ## instead.",
"$ref": "#/definitions/stringOrArrayOfStrings"
@@ -396,6 +541,9 @@
},
"64bit": {
"$ref": "#/definitions/architecture"
},
"arm64": {
"$ref": "#/definitions/architecture"
}
},
"type": "object"
@@ -442,38 +590,14 @@
"type": "string"
},
"innosetup": {
"description": "True if the installer InnoSetup based. Found in https://github.com/lukesampson/scoop/search?l=JSON&q=innosetup",
"description": "True if the installer InnoSetup based. Found in https://github.com/ScoopInstaller/Main/search?l=JSON&q=innosetup",
"type": "boolean"
},
"installer": {
"$ref": "#/definitions/installer"
},
"license": {
"anyOf": [
{
"$ref": "#/definitions/licenseIdentifiers"
},
{
"additionalProperties": false,
"properties": {
"url": {
"format": "uri",
"type": "string"
},
"identifier": {
"$ref": "#/definitions/licenseIdentifiers"
}
},
"required": [
"identifier"
],
"type": "object"
}
]
},
"msi": {
"$ref": "#/definitions/stringOrArrayOfStrings",
"description": "Deprecated"
"$ref": "#/definitions/license"
},
"notes": {
"$ref": "#/definitions/stringOrArrayOfStrings"
@@ -481,9 +605,15 @@
"post_install": {
"$ref": "#/definitions/stringOrArrayOfStrings"
},
"post_uninstall": {
"$ref": "#/definitions/stringOrArrayOfStrings"
},
"pre_install": {
"$ref": "#/definitions/stringOrArrayOfStrings"
},
"pre_uninstall": {
"$ref": "#/definitions/stringOrArrayOfStrings"
},
"psmodule": {
"additionalProperties": false,
"properties": {
@@ -512,12 +642,42 @@
"$ref": "#/definitions/uriOrArrayOfUris"
},
"version": {
"pattern": "^[\\w\\.\\-_]+$",
"pattern": "^[\\w\\.\\-+_]+$",
"type": "string"
}
},
"if": {
"properties": {
"architecture": {
"properties": {
"64bit": {
"properties": {
"url": false
}
},
"32bit": {
"properties": {
"url": false
}
},
"arm64": {
"properties": {
"url": false
}
}
}
}
}
},
"then": {
"required": [
"url"
]
},
"required": [
"version"
"version",
"homepage",
"license"
],
"title": "scoop app manifest schema",
"type": "object"

View File

@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="utf-8"?>
<Configuration>
<ViewDefinitions>
<View>
<Name>ScoopAppsType</Name>
<ViewSelectedBy>
<TypeName>ScoopApps</TypeName>
</ViewSelectedBy>
<TableControl>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>Name</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Version</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Source</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Updated</PropertyName>
<FormatString>yyyy-MM-dd HH:mm:ss</FormatString>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Info</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
<View>
<Name>ScoopShimsType</Name>
<ViewSelectedBy>
<TypeName>ScoopShims</TypeName>
</ViewSelectedBy>
<TableControl>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>Name</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Source</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Alternatives</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>IsGlobal</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>IsHidden</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
<View>
<Name>ScoopStatusType</Name>
<ViewSelectedBy>
<TypeName>ScoopStatus</TypeName>
</ViewSelectedBy>
<TableControl>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>Name</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Installed Version</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Latest Version</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Missing Dependencies</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Info</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
</ViewDefinitions>
</Configuration>

View File

@@ -1 +0,0 @@
packages/

View File

@@ -1 +0,0 @@
cb440b8a08a2095a59666a859b35aa5a1524b140b909ecc760f38f3baccf80e6 *shim.exe

View File

@@ -1 +0,0 @@
710aeef5381f96ea0360a27ce6b792f67e018abb91d6dc67fc5c18c15baf611f36268a3f9e70a339b1a1b0e5dbfdaee10d74288352e609764d5b81303409a332 *shim.exe

Binary file not shown.

View File

@@ -1,21 +0,0 @@
Param([Switch]$Fast)
Push-Location $psscriptroot
. "$psscriptroot\..\..\lib\install.ps1"
if(!$Fast) {
Write-Host "Install dependencies ..."
Invoke-Expression "$psscriptroot\install.ps1"
}
$output = "$psscriptroot\bin"
Write-Output 'Compiling shim.cs ...'
& "$psscriptroot\packages\Microsoft.Net.Compilers\tools\csc.exe" /deterministic /platform:anycpu /nologo /optimize /target:exe /out:"$output\shim.exe" shim.cs
Write-Output 'Computing checksums ...'
Remove-Item "$psscriptroot\bin\checksum.sha256" -ErrorAction Ignore
Remove-Item "$psscriptroot\bin\checksum.sha512" -ErrorAction Ignore
Get-ChildItem "$psscriptroot\bin\*" -Include *.exe,*.dll | ForEach-Object {
"$(compute_hash $_ 'sha256') *$($_.Name)" | Out-File "$psscriptroot\bin\checksum.sha256" -Append -Encoding oem
"$(compute_hash $_ 'sha512') *$($_.Name)" | Out-File "$psscriptroot\bin\checksum.sha512" -Append -Encoding oem
}
Pop-Location

View File

@@ -1,8 +0,0 @@
# https://github.com/edymtt/nugetstandalone
$destinationFolder = "$psscriptroot\packages"
if ((Test-Path -path $destinationFolder)) {
Remove-Item -Path $destinationFolder -Recurse | Out-Null
}
New-Item $destinationFolder -Type Directory | Out-Null
nuget install packages.config -o $destinationFolder -ExcludeVersion

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Net.Compilers" version="2.10.0" targetFramework="net45" developmentDependency="true" />
</packages>

View File

@@ -1,168 +0,0 @@
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace Scoop {
class Program {
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
static extern bool CreateProcess(string lpApplicationName,
string lpCommandLine, IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes, bool bInheritHandles,
uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory,
[In] ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
const int ERROR_ELEVATION_REQUIRED = 740;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct STARTUPINFO {
public Int32 cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwYSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
internal struct PROCESS_INFORMATION {
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[DllImport("kernel32.dll", SetLastError=true)]
static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);
const UInt32 INFINITE = 0xFFFFFFFF;
[DllImport("kernel32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetExitCodeProcess(IntPtr hProcess, out uint lpExitCode);
static int Main(string[] args) {
var exe = Assembly.GetExecutingAssembly().Location;
var dir = Path.GetDirectoryName(exe);
var name = Path.GetFileNameWithoutExtension(exe);
var configPath = Path.Combine(dir, name + ".shim");
if(!File.Exists(configPath)) {
Console.Error.WriteLine("Couldn't find " + Path.GetFileName(configPath) + " in " + dir);
return 1;
}
var config = Config(configPath);
var path = Get(config, "path");
var add_args = Get(config, "args");
var si = new STARTUPINFO();
var pi = new PROCESS_INFORMATION();
// create command line
var cmd_args = add_args ?? "";
var pass_args = GetArgs(Environment.CommandLine);
if(!string.IsNullOrEmpty(pass_args)) {
if(!string.IsNullOrEmpty(cmd_args)) cmd_args += " ";
cmd_args += pass_args;
}
if(!string.IsNullOrEmpty(cmd_args)) cmd_args = " " + cmd_args;
var cmd = "\"" + path + "\"" + cmd_args;
if(!CreateProcess(null, cmd, IntPtr.Zero, IntPtr.Zero,
bInheritHandles: true,
dwCreationFlags: 0,
lpEnvironment: IntPtr.Zero, // inherit parent
lpCurrentDirectory: null, // inherit parent
lpStartupInfo: ref si,
lpProcessInformation: out pi)) {
var error = Marshal.GetLastWin32Error();
if(error == ERROR_ELEVATION_REQUIRED) {
// Unfortunately, ShellExecute() does not allow us to run program without
// CREATE_NEW_CONSOLE, so we can not replace CreateProcess() completely.
// The good news is we are okay with CREATE_NEW_CONSOLE when we run program with elevation.
Process process = new Process();
process.StartInfo = new ProcessStartInfo(path, cmd_args);
process.StartInfo.UseShellExecute = true;
try {
process.Start();
}
catch(Win32Exception exception) {
return exception.ErrorCode;
}
process.WaitForExit();
return process.ExitCode;
}
return error;
}
WaitForSingleObject(pi.hProcess, INFINITE);
uint exit_code = 0;
GetExitCodeProcess(pi.hProcess, out exit_code);
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return (int)exit_code;
}
// now uses GetArgs instead
static string Serialize(string[] args) {
return string.Join(" ", args.Select(a => a.Contains(' ') ? '"' + a + '"' : a));
}
// strips the program name from the command line, returns just the arguments
static string GetArgs(string cmdLine) {
if(cmdLine.StartsWith("\"")) {
var endQuote = cmdLine.IndexOf("\" ", 1);
if(endQuote < 0) return "";
return cmdLine.Substring(endQuote + 1);
}
var space = cmdLine.IndexOf(' ');
if(space < 0 || space == cmdLine.Length - 1) return "";
return cmdLine.Substring(space + 1);
}
static string Get(Dictionary<string, string> dic, string key) {
string value = null;
dic.TryGetValue(key, out value);
return value;
}
static Dictionary<string, string> Config(string path) {
var config = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
foreach(var line in File.ReadAllLines(path)) {
var m = Regex.Match(line, @"([^=]+)=(.*)");
if(m.Success) {
config[m.Groups[1].Value.Trim()] = m.Groups[2].Value.Trim();
}
}
return config;
}
}
}

View File

@@ -1,36 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="packages\Microsoft.Net.Compilers.2.10.0\build\Microsoft.Net.Compilers.props" Condition="Exists('packages\Microsoft.Net.Compilers.2.10.0\build\Microsoft.Net.Compilers.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{381F9D2E-2355-4F84-9206-06BB9175F97B}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>Scoop.Shim</RootNamespace>
<AssemblyName>Scoop.Shim</AssemblyName>
<TargetFrameworkVersion>v4.5.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="shim.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('packages\Microsoft.Net.Compilers.2.10.0\build\Microsoft.Net.Compilers.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.Net.Compilers.2.10.0\build\Microsoft.Net.Compilers.props'))" />
</Target>
</Project>

View File

@@ -1,10 +0,0 @@
# https://github.com/edymtt/nugetstandalone
$destinationFolder = "$psscriptroot\packages"
if (!(Test-Path -path $destinationFolder)) {
Write-Host -f Red "Run .\install.ps1 first!"
exit 1
}
nuget update packages.config -r $destinationFolder
Remove-Item $destinationFolder -Force -Recurse | Out-Null
nuget install packages.config -o $destinationFolder -ExcludeVersion

View File

@@ -0,0 +1 @@
70d4690b8ac3b3f715f537cdea6e07a39fda4bc0347bf6b958e4f3ff2f0e04d4 shim.exe

View File

@@ -0,0 +1 @@
ecde07b32192846c4885cf4d2208eedc170765ea115ae49b81509fed0ce474e21064100bb2f3d815ee79f1c12463d32ef013d4182647eae71855cd18e4196176 shim.exe

Binary file not shown.

View File

@@ -0,0 +1 @@
140e3801d8adeda639a21b14e62b93a4c7d26b7a758421f43c82be59753be49b *shim.exe

View File

@@ -0,0 +1 @@
59d9da9f9714003b915bcafbe1b41f53b121dde206ecc23984f62273e957766eece8d64ffc53011c328d3a2ad627aa0f4f7c39bbec8e7b64d0d2ee7b7e771423 *shim.exe

Binary file not shown.

View File

@@ -0,0 +1 @@
v3.1.2

View File

@@ -0,0 +1 @@
0116068768fc992fc536738396b33db3dafe6b0cf0e6f54f6d1aa8b0331f3cec *shim.exe

View File

@@ -0,0 +1 @@
d734c528e9f20581ed3c7aa71a458f7dff7e2780fa0c319ccb9c813cd8dbf656bd7e550b81d2aa3ee8775bff9a4e507bc0b25f075697405adca0f47d37835848 *shim.exe

Binary file not shown.

View File

@@ -0,0 +1 @@
1.1.0

Some files were not shown because too many files have changed in this diff Show More