diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 2e42f0d94d..0a7a20bf89 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -29,5 +29,7 @@ Relates to #XXXX - [ ] I have read the [Contributing Guide](https://github.com/ScoopInstaller/.github/blob/main/.github/CONTRIBUTING.md). +- [ ] I have ensured that I am targeting the `develop` branch. - [ ] I have updated the documentation accordingly. - [ ] I have updated the tests accordingly. +- [ ] I have added an entry in the CHANGELOG. diff --git a/CHANGELOG.md b/CHANGELOG.md index 62c4f9b4d0..435d35db80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,46 @@ +## [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 diff --git a/LICENSE b/LICENSE index 68a49daad8..68b7fd92d6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,27 @@ +SPDX-License-Identifier: UNLICENSE or MIT + +INFORMATION ABOUT THIS PROJECT'S LICENSE (SHORT) +============================================================================================ +This project is licensed under the Unlicense or the MIT license, +at your option. + +INFORMATION ABOUT THIS PROJECT'S LICENSE (LONG) +============================================================================================ +This project ("Scoop") is free software, licensed under the Unlicense or the +MIT license, at your option. Scoop was previously licensed under only the Unlicense, +but was dual-licensed from version 0.2.0. + +Scoop comes with ABSOLUTELY NO WARRANTY. Use it at your own risk. Scoop is provided +on an AS-IS BASIS and its contributors disclaim all warranties. + +You may use, modify, distribute, sell, copy, compile, or merge Scoop by any means. + +Copies of both licenses can be found below. + +THE LICENSE OF SCOOP +============================================================================================ +Unlicense +--------- This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or @@ -22,3 +46,28 @@ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to + +MIT license +----------- +The MIT License (MIT) + +Copyright (c) 2013-2017 Luke Sampson (https://github.com/lukesampson) +Copyright (c) 2013-present Scoop contributors (https://github.com/ScoopInstaller/Scoop/graphs/contributors) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 109396074b..706e5a7bf3 100644 --- a/README.md +++ b/README.md @@ -18,14 +18,14 @@ Repository size - - Build Status + + Scoop Core CI Tests Discord Chat - - Gitter Chat + + Gitter Chat License @@ -56,60 +56,15 @@ 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` - ## Installation -Run the following command from your PowerShell to install scoop to its default location (`C:\Users\\scoop`) +Run the following command from a **non-admin** PowerShell to install scoop to its default location `C:\Users\\scoop`. ```powershell -Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh') - -# or shorter iwr -useb get.scoop.sh | iex ``` -Once installed, run `scoop help` for instructions. - -The default setup is configured so all user installed programs and Scoop itself live in `C:\Users\\scoop`. -Globally installed programs (`--global`) live in `C:\ProgramData\scoop`. -These settings can be changed through environment variables. - -### Install Scoop to a Custom Directory by changing `SCOOP` - -```powershell -$env:SCOOP='D:\Applications\Scoop' -[Environment]::SetEnvironmentVariable('SCOOP', $env:SCOOP, 'User') -# run the installer -``` - -### Configure Scoop to install global programs to a Custom Directory by changing `SCOOP_GLOBAL` - -```powershell -$env:SCOOP_GLOBAL='F:\GlobalScoopApps' -[Environment]::SetEnvironmentVariable('SCOOP_GLOBAL', $env:SCOOP_GLOBAL, 'Machine') -# run the installer -``` - -### Configure Scoop to store downloads to a Custom Directory by changing `SCOOP_CACHE` - -```powershell -$env:SCOOP_CACHE='F:\ScoopCache' -[Environment]::SetEnvironmentVariable('SCOOP_CACHE', $env:SCOOP_CACHE, 'Machine') -# run the installer -``` - -### Configure Scoop to use a GitHub API token during searching and checkver by setting `SCOOP_CHECKVER_TOKEN` - -```powershell -$env:SCOOP_CHECKVER_TOKEN='' -[Environment]::SetEnvironmentVariable('SCOOP_CHECKVER_TOKEN', $env:SCOOP_CHECKVER_TOKEN, 'Machine') -# search for an app -``` +Advanced installation instruction and full documentation of the installer are available in [ScoopInstaller/Install](https://github.com/ScoopInstaller/Install). Please create new issues there if you have questions about the installation. ## [Documentation](https://github.com/ScoopInstaller/Scoop/wiki) diff --git a/bin/auto-pr.ps1 b/bin/auto-pr.ps1 index a78a4153fc..aa70d37258 100644 --- a/bin/auto-pr.ps1 +++ b/bin/auto-pr.ps1 @@ -23,6 +23,8 @@ 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 @@ -54,7 +56,8 @@ param( [Switch] $Request, [Switch] $Help, [string[]] $SpecialSnowflakes, - [Switch] $SkipUpdated + [Switch] $SkipUpdated, + [Switch] $ThrowError ) . "$PSScriptRoot\..\lib\manifest.ps1" @@ -160,11 +163,11 @@ if ($Push) { 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 } } diff --git a/bin/checkver.ps1 b/bin/checkver.ps1 index 3d6d43dee8..2850c7cc73 100644 --- a/bin/checkver.ps1 +++ b/bin/checkver.ps1 @@ -17,6 +17,8 @@ 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. @@ -62,13 +64,14 @@ param( [Switch] $Update, [Switch] $ForceUpdate, [Switch] $SkipUpdated, - [String] $Version = '' + [String] $Version = '', + [Switch] $ThrowError ) . "$PSScriptRoot\..\lib\core.ps1" +. "$PSScriptRoot\..\lib\autoupdate.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 @@ -76,7 +79,7 @@ param( $Dir = Resolve-Path $Dir $Search = $App -$GitHubToken = $env:SCOOP_CHECKVER_TOKEN, (get_config 'checkver-token') | Where-Object -Property Length -Value 0 -GT | Select-Object -First 1 +$GitHubToken = Get-GitHubToken # don't use $Version with $App = '*' if ($App -eq '*' -and $Version -ne '') { @@ -102,7 +105,7 @@ Get-Event | ForEach-Object { $Queue | ForEach-Object { $name, $json = $_ - $substitutions = Get-VersionSubstitution $json.version + $substitutions = Get-VersionSubstitution $json.version # 'autoupdate.ps1' $wc = New-Object Net.Webclient if ($json.checkver.useragent) { @@ -334,9 +337,13 @@ while ($in_progress -gt 0) { Write-Host 'Forcing autoupdate!' -ForegroundColor DarkMagenta } try { - Invoke-AutoUpdate $App $Dir $json $ver $matchesHashtable + Invoke-AutoUpdate $App $Dir $json $ver $matchesHashtable # 'autoupdate.ps1' } catch { - error $_.Exception.Message + if ($ThrowError) { + throw $_ + } else { + error $_.Exception.Message + } } } } diff --git a/bin/refresh.ps1 b/bin/refresh.ps1 index a3492e35f7..27a7beb95b 100644 --- a/bin/refresh.ps1 +++ b/bin/refresh.ps1 @@ -1,7 +1,7 @@ # for development, update the installed scripts to match local source . "$PSScriptRoot\..\lib\core.ps1" -$src = relpath ".." +$src = "$PSScriptRoot\.." $dest = ensure (versiondir 'scoop' 'current') # make sure not running from the installed directory diff --git a/bin/scoop.ps1 b/bin/scoop.ps1 index 5fe0a8f316..b4b8e1c77f 100644 --- a/bin/scoop.ps1 +++ b/bin/scoop.ps1 @@ -1,29 +1,56 @@ #Requires -Version 5 -param($cmd) +param($SubCommand) -Set-StrictMode -off +Set-StrictMode -Off . "$PSScriptRoot\..\lib\core.ps1" . "$PSScriptRoot\..\lib\buckets.ps1" . "$PSScriptRoot\..\lib\commands.ps1" +. "$PSScriptRoot\..\lib\help.ps1" -reset_aliases +# for aliases where there's a local function, re-alias so the function takes precedence +$aliases = Get-Alias | Where-Object { $_.Options -notmatch 'ReadOnly|AllScope' } | ForEach-Object { $_.Name } +Get-ChildItem Function: | Where-Object -Property Name -In -Value $aliases | ForEach-Object { + Set-Alias -Name $_.Name -Value Local:$($_.Name) -Scope Script +} -$commands = commands -if ('--version' -contains $cmd -or (!$cmd -and '-v' -contains $args)) { - Write-Host "Current Scoop version:" - Invoke-Expression "git -C '$(versiondir 'scoop' 'current')' --no-pager log --oneline HEAD -n 1" - Write-Host "" +switch ($SubCommand) { + ({ $SubCommand -in @($null, '--help', '/?') }) { + if (!$SubCommand -and $Args -eq '-v') { + $SubCommand = '--version' + } else { + exec 'help' + } + } + ({ $SubCommand -eq '--version' }) { + Write-Host 'Current Scoop version:' + if ((Test-CommandAvailable git) -and (Test-Path "$PSScriptRoot\..\.git") -and (get_config SCOOP_BRANCH 'master') -ne 'master') { + Invoke-Expression "git -C '$PSScriptRoot\..' --no-pager log --oneline HEAD -n 1" + } else { + $version = Select-String -Pattern '^## \[(v[\d.]+)\].*?([\d-]+)$' -Path "$PSScriptRoot\..\CHANGELOG.md" + Write-Host $version.Matches.Groups[1].Value -ForegroundColor Cyan -NoNewline + Write-Host " - Released at $($version.Matches.Groups[2].Value)" + } + Write-Host '' - Get-LocalBucket | ForEach-Object { - $bucketLoc = Find-BucketDirectory $_ -Root - if(Test-Path (Join-Path $bucketLoc '.git')) { - Write-Host "'$_' bucket:" - Invoke-Expression "git -C '$bucketLoc' --no-pager log --oneline HEAD -n 1" - Write-Host "" + Get-LocalBucket | ForEach-Object { + $bucketLoc = Find-BucketDirectory $_ -Root + if ((Test-Path (Join-Path $bucketLoc '.git')) -and (Test-CommandAvailable git)) { + Write-Host "'$_' bucket:" + Invoke-Expression "git -C '$bucketLoc' --no-pager log --oneline HEAD -n 1" + Write-Host '' + } } } + ({ $SubCommand -in (commands) }) { + if ($Args -in @('-h', '--help', '/?')) { + exec 'help' @($SubCommand) + } else { + exec $SubCommand $Args + } + } + default { + "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 } diff --git a/lib/autoupdate.ps1 b/lib/autoupdate.ps1 index 6a71870738..f6c991aa5b 100644 --- a/lib/autoupdate.ps1 +++ b/lib/autoupdate.ps1 @@ -1,10 +1,4 @@ -<# -TODO - - clean up -#> -. "$PSScriptRoot\core.ps1" -. "$PSScriptRoot\json.ps1" - +# Must included with 'json.ps1' function find_hash_in_rdf([String] $url, [String] $basename) { $data = $null try { diff --git a/lib/buckets.ps1 b/lib/buckets.ps1 index 07704d3bbc..9561f65baf 100644 --- a/lib/buckets.ps1 +++ b/lib/buckets.ps1 @@ -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 | Where-Object { $_.Name.EndsWith('.json') } | ForEach-Object { $_.Name -replace '.json$', '' } } function Get-LocalBucket { @@ -58,8 +58,12 @@ function Get-LocalBucket { .SYNOPSIS List all local buckets. #> - - return (Get-ChildItem -Directory $bucketsdir).Name + $bucketNames = (Get-ChildItem -Path $bucketsdir -Directory).Name + if ($null -eq $bucketNames) { + return @() # Return a zero-length list instead of $null. + } else { + return $bucketNames + } } function buckets { @@ -68,57 +72,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 Find-Manifest($app, $bucket) { + $manifest, $url = $null, $null + + # 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 { + if ($bucket) { + $manifest = manifest $app $bucket + } else { + foreach ($bucket in Get-LocalBucket) { + $manifest = manifest $app $bucket + if ($manifest) { break } + } + } + + if (!$manifest) { + # couldn't find app in buckets: check if it's a local path + $path = $app + if (!$path.endswith('.json')) { $path += '.json' } + if (Test-Path $path) { + $url = "$(Resolve-Path $path)" + $app = appname_from_url $url + $manifest, $bucket = url_manifest $url + } + } } - foreach($bucket in Get-LocalBucket) { - $manifest = manifest $app $bucket - if($manifest) { return $manifest, $bucket } + return $app, $manifest, $bucket, $url +} + +function Convert-RepositoryUri { + [CmdletBinding()] + param ( + [Parameter(Mandatory, Position = 0, ValueFromPipeline = $true)] + [String] $Uri + ) + + process { + # https://git-scm.com/docs/git-clone#_git_urls + # https://regex101.com/r/xGmwRr/1 + if ($Uri -match '(?:@|/{1,3})(?:www\.|.*@)?(?[^/]+?)(?::\d+)?[:/](?.+)/(?.+?)(?:\.git)?/?$') { + $Matches.provider, $Matches.user, $Matches.repo -join '/' + } else { + error "$Uri is not a valid Git URL!" + error "Please see https://git-scm.com/docs/git-clone#_git_urls for valid ones." + return $null + } } } -function add_bucket($name, $repo) { - if (!$name) { " missing"; $usage_add; exit 1 } - if (!$repo) { - $repo = known_bucket_repo $name - if (!$repo) { "Unknown bucket '$name'. Try specifying ."; $usage_add; exit 1 } +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 = git -C $path config remote.origin.url + $bucket.Updated = git -C $path log --format='%aD' -n 1 | Get-Date + } else { + $bucket.Source = friendly_path $path + $bucket.Updated = (Get-Item "$path\bucket").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 (!(Test-CommandAvailable git)) { - abort "Git is required for buckets. Run 'scoop install git' and try again." + error "Git is required for buckets. Run 'scoop install git' and try again." + return 1 } $dir = Find-BucketDirectory $name -Root - if (test-path $dir) { + if (Test-Path $dir) { warn "The '$name' bucket already exists. Use 'scoop bucket rm $name' to remove it." - exit 0 + return 2 + } + + $uni_repo = Convert-RepositoryUri -Uri $repo + if ($null -eq $uni_repo) { + return 1 + } + foreach ($bucket in Get-LocalBucket) { + $remote = git -C "$bucketsdir\$bucket" config --get remote.origin.url + if ((Convert-RepositoryUri -Uri $remote) -eq $uni_repo) { + warn "Bucket $bucket already exists for $repo" + return 2 + } } - write-host 'Checking repo... ' -nonewline + Write-Host 'Checking repo... ' -NoNewline $out = git_cmd ls-remote $repo 2>&1 - if ($lastexitcode -ne 0) { - abort "'$repo' doesn't look like a valid git repository`n`nError given:`n$out" + if ($LASTEXITCODE -ne 0) { + error "'$repo' doesn't look like a valid git repository`n`nError given:`n$out" + return 1 } - write-host 'ok' + Write-Host 'OK' - ensure $bucketsdir > $null + ensure $bucketsdir | Out-Null $dir = ensure $dir git_cmd clone "$repo" "`"$dir`"" -q success "The $name bucket was added successfully." + return 0 } function rm_bucket($name) { - if (!$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 + return 0 } function new_issue_msg($app, $bucket, $title, $body) { @@ -126,7 +199,7 @@ function new_issue_msg($app, $bucket, $title, $body) { $url = known_bucket_repo $bucket $bucket_path = "$bucketsdir\$bucket" - if (Test-path $bucket_path) { + if (Test-Path $bucket_path) { $remote = Invoke-Expression "git -C '$bucket_path' config --get remote.origin.url" # Support ssh and http syntax # git@PROVIDER:USER/REPO.git @@ -135,7 +208,7 @@ function new_issue_msg($app, $bucket, $title, $body) { $url = "https://$($Matches.Provider)/$($Matches.User)/$($Matches.Repo)" } - if(!$url) { return 'Please contact the bucket maintainer!' } + if (!$url) { return 'Please contact the bucket maintainer!' } # Print only github repositories if ($url -like '*github*') { @@ -143,7 +216,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" } } diff --git a/lib/commands.ps1 b/lib/commands.ps1 index 8ae0c16526..02b55ab908 100644 --- a/lib/commands.ps1 +++ b/lib/commands.ps1 @@ -1,7 +1,6 @@ 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,7 +12,7 @@ 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)) { diff --git a/lib/core.ps1 b/lib/core.ps1 index 83e7a28aad..4f45ef5978 100644 --- a/lib/core.ps1 +++ b/lib/core.ps1 @@ -187,6 +187,9 @@ function filesize($length) { } elseif($length -gt $kb) { "{0:n1} KB" -f ($length / $kb) } else { + if ($null -eq $length) { + $length = 0 + } "$($length) B" } } @@ -215,6 +218,9 @@ function cache_path($app, $version, $url) { "$cachedir\$app#$version#$($url -rep # apps function sanitary_path($path) { return [regex]::replace($path, "[/\\?:*<>|]", "") } function installed($app, $global) { + if (-not $PSBoundParameters.ContainsKey('global')) { + return (installed $app $false) -or (installed $app $true) + } # Dependencies of the format "bucket/dependency" install in a directory of form # "dependency". So we need to extract the bucket from the name and only give the app # name to is_directory @@ -401,11 +407,16 @@ function url_remote_filename($url) { return $basename } -function ensure($dir) { if(!(test-path $dir)) { mkdir $dir > $null }; resolve-path $dir } -function fullpath($path) { # should be ~ rooted - $executionContext.sessionState.path.getUnresolvedProviderPathFromPSPath($path) +function ensure($dir) { + if (!(Test-Path -Path $dir)) { + New-Item -Path $dir -ItemType Directory | Out-Null + } + Convert-Path -Path $dir +} +function fullpath($path) { + # should be ~ rooted + $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($path) } -function relpath($path) { "$($myinvocation.psscriptroot)\$path" } # relative to calling script function friendly_path($path) { $h = (Get-PsProvider 'FileSystem').home; if(!$h.endswith('\')) { $h += '\' } if($h -eq '\') { return $path } @@ -479,8 +490,8 @@ function Invoke-ExternalCommand { return $false } if ($LogPath -and ($FilePath -notmatch '(^|\W)msiexec($|\W)')) { - Out-File -FilePath $LogPath -Encoding Default -Append -InputObject $Process.StandardOutput.ReadToEnd() - Out-File -FilePath $LogPath -Encoding Default -Append -InputObject $Process.StandardError.ReadToEnd() + Out-UTF8File -FilePath $LogPath -Append -InputObject $Process.StandardOutput.ReadToEnd() + Out-UTF8File -FilePath $LogPath -Append -InputObject $Process.StandardError.ReadToEnd() } $Process.WaitForExit() if ($Process.ExitCode -ne 0) { @@ -625,9 +636,9 @@ function shim($path, $global, $name, $arg) { # for programs with no awareness of any shell warn_on_overwrite "$shim.shim" $path Copy-Item (get_shim_path) "$shim.exe" -Force - Write-Output "path = `"$resolved_path`"" | Out-File "$shim.shim" -Encoding ASCII + Write-Output "path = `"$resolved_path`"" | Out-UTF8File "$shim.shim" if ($arg) { - Write-Output "args = $arg" | Out-File "$shim.shim" -Encoding ASCII -Append + Write-Output "args = $arg" | Out-UTF8File "$shim.shim" -Append } } elseif ($path -match '\.(bat|cmd)$') { # shim .bat, .cmd so they can be used by programs with no awareness of PSH @@ -635,14 +646,14 @@ function shim($path, $global, $name, $arg) { @( "@rem $resolved_path", "@`"$resolved_path`" $arg %*" - ) -join "`r`n" | Out-File "$shim.cmd" -Encoding ASCII + ) -join "`r`n" | Out-UTF8File "$shim.cmd" warn_on_overwrite $shim $path @( "#!/bin/sh", "# $resolved_path", "MSYS2_ARG_CONV_EXCL=/C cmd.exe /C `"$resolved_path`" $arg `"$@`"" - ) -join "`n" | Out-File $shim -Encoding ASCII -NoNewline + ) -join "`n" | Out-UTF8File $shim -NoNewLine } elseif ($path -match '\.ps1$') { # if $path points to another drive resolve-path prepends .\ which could break shims warn_on_overwrite "$shim.ps1" $path @@ -661,7 +672,7 @@ function shim($path, $global, $name, $arg) { "exit `$LASTEXITCODE" ) } - $ps1text -join "`r`n" | Out-File "$shim.ps1" -Encoding ASCII + $ps1text -join "`r`n" | Out-UTF8File "$shim.ps1" # make ps1 accessible from cmd.exe warn_on_overwrite "$shim.cmd" $path @@ -682,44 +693,44 @@ function shim($path, $global, $name, $arg) { ") else (", " powershell -noprofile -ex unrestricted -file `"$resolved_path`" $arg %args%", ")" - ) -join "`r`n" | Out-File "$shim.cmd" -Encoding ASCII + ) -join "`r`n" | Out-UTF8File "$shim.cmd" warn_on_overwrite $shim $path @( "#!/bin/sh", "# $resolved_path", "if command -v pwsh.exe > /dev/null 2>&1; then", - " pwsh.exe -noprofile -ex unrestricted -file `"$resolved_path`" $arg $@", + " pwsh.exe -noprofile -ex unrestricted -file `"$resolved_path`" $arg `"$@`"", "else", - " powershell.exe -noprofile -ex unrestricted -file `"$resolved_path`" $arg $@", + " powershell.exe -noprofile -ex unrestricted -file `"$resolved_path`" $arg `"$@`"", "fi" - ) -join "`n" | Out-File $shim -Encoding ASCII -NoNewline + ) -join "`n" | Out-UTF8File $shim -NoNewLine } elseif ($path -match '\.jar$') { warn_on_overwrite "$shim.cmd" $path @( "@rem $resolved_path", "@java -jar `"$resolved_path`" $arg %*" - ) -join "`r`n" | Out-File "$shim.cmd" -Encoding ASCII + ) -join "`r`n" | Out-UTF8File "$shim.cmd" warn_on_overwrite $shim $path @( "#!/bin/sh", "# $resolved_path", "java.exe -jar `"$resolved_path`" $arg `"$@`"" - ) -join "`n" | Out-File $shim -Encoding ASCII -NoNewline + ) -join "`n" | Out-UTF8File $shim -NoNewLine } elseif ($path -match '\.py$') { warn_on_overwrite "$shim.cmd" $path @( "@rem $resolved_path", "@python `"$resolved_path`" $arg %*" - ) -join "`r`n" | Out-File "$shim.cmd" -Encoding ASCII + ) -join "`r`n" | Out-UTF8File "$shim.cmd" warn_on_overwrite $shim $path @( "#!/bin/sh", "# $resolved_path", "python.exe `"$resolved_path`" $arg `"$@`"" - ) -join "`n" | Out-File $shim -Encoding ASCII -NoNewline + ) -join "`n" | Out-UTF8File $shim -NoNewLine } else { warn_on_overwrite "$shim.cmd" $path # find path to Git's bash so that batch scripts can run bash scripts @@ -730,14 +741,14 @@ function shim($path, $global, $name, $arg) { @( "@rem $resolved_path", "@`"$(Join-Path (Join-Path $gitdir.FullName 'bin') 'bash.exe')`" `"$resolved_path`" $arg %*" - ) -join "`r`n" | Out-File "$shim.cmd" -Encoding ASCII + ) -join "`r`n" | Out-UTF8File "$shim.cmd" warn_on_overwrite $shim $path @( "#!/bin/sh", "# $resolved_path", "`"$resolved_path`" $arg `"$@`"" - ) -join "`n" | Out-File $shim -Encoding ASCII -NoNewline + ) -join "`n" | Out-UTF8File $shim -NoNewLine } } @@ -885,55 +896,6 @@ function pluralize($count, $singular, $plural) { if($count -eq 1) { $singular } else { $plural } } -function reset_alias($name, $value) { - if($existing = get-alias $name -ea ignore | Where-Object { $_.options -match 'readonly' }) { - if($existing.definition -ne $value) { - write-host "Alias $name is read-only; can't reset it." -f darkyellow - } - return # already set - } - if($value -is [scriptblock]) { - if(!(test-path -path "function:script:$name")) { - new-item -path function: -name "script:$name" -value $value | out-null - } - return - } - - set-alias $name $value -scope script -option allscope -} - -function reset_aliases() { - # for aliases where there's a local function, re-alias so the function takes precedence - $aliases = get-alias | Where-Object { $_.options -notmatch 'readonly|allscope' } | ForEach-Object { $_.name } - get-childitem function: | ForEach-Object { - $fn = $_.name - if($aliases -contains $fn) { - set-alias $fn local:$fn -scope script - } - } - - # for dealing with user aliases - $default_aliases = @{ - 'cp' = 'copy-item' - 'echo' = 'write-output' - 'gc' = 'get-content' - 'gci' = 'get-childitem' - 'gcm' = 'get-command' - 'gm' = 'get-member' - 'iex' = 'invoke-expression' - 'ls' = 'get-childitem' - 'mkdir' = { new-item -type directory @args } - 'mv' = 'move-item' - 'rm' = 'remove-item' - 'sc' = 'set-content' - 'select' = 'select-object' - 'sls' = 'select-string' - } - - # set default aliases - $default_aliases.keys | ForEach-Object { reset_alias $_ $default_aliases[$_] } -} - # convert list of apps to list of ($app, $global) tuples function applist($apps, $global) { if(!$apps) { return @() } @@ -959,7 +921,7 @@ function show_app($app, $bucket, $version) { function last_scoop_update() { # PowerShell 6 returns an DateTime Object - $last_update = (scoop config lastupdate) + $last_update = (get_config lastupdate) if ($null -ne $last_update -and $last_update.GetType() -eq [System.String]) { try { @@ -975,7 +937,7 @@ function is_scoop_outdated() { $last_update = $(last_scoop_update) $now = [System.DateTime]::Now if($null -eq $last_update) { - scoop config lastupdate $now.ToString('o') + set_config lastupdate $now.ToString('o') # enforce an update for the first time return $true } @@ -1046,6 +1008,10 @@ function get_hash([String] $multihash) { return $type, $hash.ToLower() } +function Get-GitHubToken { + return $env:SCOOP_GH_TOKEN, (get_config 'gh_token') | Where-Object -Property Length -Value 0 -GT | Select-Object -First 1 +} + function handle_special_urls($url) { # FossHub.com @@ -1071,6 +1037,18 @@ function handle_special_urls($url) # Reshapes the URL to avoid redirections $url = "https://downloads.sourceforge.net/project/$($matches['project'])/$($matches['file'])" } + + # Github.com + if ($url -match 'github.com/(?[^/]+)/(?[^/]+)/releases/download/(?[^/]+)/(?[^/#]+)(?.*)' -and ($token = Get-GitHubToken)) { + $headers = @{ "Authorization" = "token $token" } + $privateUrl = "https://api.github.com/repos/$($Matches.owner)/$($Matches.repo)" + $assetUrl = "https://api.github.com/repos/$($Matches.owner)/$($Matches.repo)/releases/tags/$($Matches.tag)" + + if ((Invoke-RestMethod -Uri $privateUrl -Headers $headers).Private) { + $url = ((Invoke-RestMethod -Uri $assetUrl -Headers $headers).Assets | Where-Object -Property Name -EQ -Value $Matches.file).Url, $Matches.filename -join '' + } + } + return $url } @@ -1101,14 +1079,25 @@ function Out-UTF8File { [Parameter(Mandatory = $True, Position = 0)] [Alias("Path")] [String] $FilePath, + [Switch] $Append, + [Switch] $NoNewLine, [Parameter(ValueFromPipeline = $True)] [PSObject] $InputObject ) process { - # Ref: https://stackoverflow.com/questions/5596982 - # Performance Note: `WriteAllLines` throttles memory usage while - # `WriteAllText` needs to keep the complete string in memory. - [System.IO.File]::WriteAllLines($FilePath, $InputObject) + if ($Append) { + [System.IO.File]::AppendAllText($FilePath, $InputObject) + } else { + if (!$NoNewLine) { + # Ref: https://stackoverflow.com/questions/5596982 + # Performance Note: `WriteAllLines` throttles memory usage while + # `WriteAllText` needs to keep the complete string in memory. + [System.IO.File]::WriteAllLines($FilePath, $InputObject) + } else { + # However `WriteAllText` does not add ending newline. + [System.IO.File]::WriteAllText($FilePath, $InputObject) + } + } } } diff --git a/lib/decompress.ps1 b/lib/decompress.ps1 index 436f9610d7..8851e8671f 100644 --- a/lib/decompress.ps1 +++ b/lib/decompress.ps1 @@ -55,7 +55,8 @@ function Expand-7zipArchive { # Check for tar $Status = Invoke-ExternalCommand $7zPath @('l', "`"$Path`"") -LogPath $LogPath if ($Status) { - $TarFile = (Get-Content -Path $LogPath)[-5] -replace '.{53}(.*)', '$1' # get inner tar file name + # 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." diff --git a/lib/diagnostic.ps1 b/lib/diagnostic.ps1 index 807e1e73e5..5caf8e7c7e 100644 --- a/lib/diagnostic.ps1 +++ b/lib/diagnostic.ps1 @@ -3,8 +3,6 @@ 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 (Test-CommandAvailable Get-MpPreference) { @@ -55,4 +53,3 @@ function check_long_paths { return $true } - diff --git a/lib/install.ps1 b/lib/install.ps1 index 1a84bc2d38..5859af4e13 100644 --- a/lib/install.ps1 +++ b/lib/install.ps1 @@ -1,6 +1,3 @@ -. "$PSScriptRoot\autoupdate.ps1" -. "$PSScriptRoot\buckets.ps1" - function nightly_version($date, $quiet = $false) { $date_str = $date.tostring("yyyyMMdd") if (!$quiet) { @@ -83,38 +80,6 @@ function install_app($app, $architecture, $global, $suggested, $use_cache = $tru show_notes $manifest $dir $original_dir $persist_dir } -function locate($app, $bucket) { - Show-DeprecatedWarning $MyInvocation 'Find-Manifest' - return Find-Manifest $app $bucket -} - -function Find-Manifest($app, $bucket) { - $manifest, $url = $null, $null - - # check if app is a URL or UNC path - if($app -match '^(ht|f)tps?://|\\\\') { - $url = $app - $app = appname_from_url $url - $manifest = url_manifest $url - } else { - # check buckets - $manifest, $bucket = find_manifest $app $bucket - - if(!$manifest) { - # couldn't find app in buckets: check if it's a local path - $path = $app - if(!$path.endswith('.json')) { $path += '.json' } - if(test-path $path) { - $url = "$(resolve-path $path)" - $app = appname_from_url $url - $manifest, $bucket = url_manifest $url - } - } - } - - return $app, $manifest, $bucket, $url -} - function dl_with_cache($app, $version, $url, $to, $cookies = $null, $use_cache = $true) { $cached = fullpath (cache_path $app $version $url) @@ -387,15 +352,25 @@ function dl_with_cache_aria2($app, $version, $manifest, $architecture, $dir, $co # download with filesize and progress indicator function dl($url, $to, $cookies, $progress) { - $reqUrl = ($url -split "#")[0] - $wreq = [net.webrequest]::create($reqUrl) - if($wreq -is [net.httpwebrequest]) { - $wreq.useragent = Get-UserAgent - if (-not ($url -imatch "sourceforge\.net" -or $url -imatch "portableapps\.com")) { - $wreq.referer = strip_filename $url + $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'] = "token $(Get-GitHubToken)" + } + if ($cookies) { + $wreq.Headers.Add('Cookie', (cookie_header $cookies)) } - 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 + } } } @@ -946,7 +921,7 @@ function link_current($versiondir) { Remove-Item $currentdir -Recurse -Force -ErrorAction Stop } - New-Item -Path $currentdir -ItemType Junction -Value $versiondir | Out-Null + New-DirectoryJunction $currentdir $versiondir | Out-Null attrib $currentdir +R /L return $currentdir } @@ -1197,7 +1172,7 @@ function persist_data($manifest, $original_dir, $persist_dir) { # create link if (is_directory $target) { # target is a directory, create junction - New-Item -Path $source -ItemType Junction -Value $target | Out-Null + New-DirectoryJunction $source $target | Out-Null attrib $source +R /L } else { # target is a file, create hard link @@ -1260,3 +1235,14 @@ function test_running_process($app, $global) { return $false } } + +# wrapper function to create junction links +# Required to handle docker/for-win#12240 +function New-DirectoryJunction($source, $target) { + # test if this script is being executed inside a docker container + if (Get-Service -Name cexecsvc -ErrorAction SilentlyContinue) { + cmd.exe /d /c "mklink /j `"$source`" `"$target`"" + } else { + New-Item -Path $source -ItemType Junction -Value $target + } +} diff --git a/lib/manifest.ps1 b/lib/manifest.ps1 index fee32ff991..efc8701b56 100644 --- a/lib/manifest.ps1 +++ b/lib/manifest.ps1 @@ -1,6 +1,3 @@ -. "$PSScriptRoot\core.ps1" -. "$PSScriptRoot\autoupdate.ps1" - function manifest_path($app, $bucket) { fullpath "$(Find-BucketDirectory $bucket)\$(sanitary_path $app).json" } @@ -48,7 +45,7 @@ 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) } @@ -88,7 +85,7 @@ function supports_architecture($manifest, $architecture) { return -not [String]::IsNullOrEmpty((arch_specific 'url' $manifest $architecture)) } -function generate_user_manifest($app, $bucket, $version) { +function generate_user_manifest($app, $bucket, $version) { # 'autoupdate.ps1' 'buckets.ps1' 'manifest.ps1' $null, $manifest, $bucket, $null = Find-Manifest $app $bucket if ("$($manifest.version)" -eq "$version") { return manifest_path $app $bucket diff --git a/lib/psmodules.ps1 b/lib/psmodules.ps1 index fc32e99425..dcaf38818f 100644 --- a/lib/psmodules.ps1 +++ b/lib/psmodules.ps1 @@ -26,7 +26,7 @@ function install_psmodule($manifest, $dir, $global) { Remove-Item -Path $linkfrom -Force -ErrorAction SilentlyContinue } - New-Item -Path $linkfrom -ItemType Junction -Value $dir | Out-Null + New-DirectoryJunction $linkfrom $dir | Out-Null } function uninstall_psmodule($manifest, $dir, $global) { diff --git a/lib/versions.ps1 b/lib/versions.ps1 index 16c903b88a..5cf21a66f4 100644 --- a/lib/versions.ps1 +++ b/lib/versions.ps1 @@ -1,4 +1,3 @@ -# versions function Get-LatestVersion { <# .SYNOPSIS @@ -29,7 +28,7 @@ function Get-LatestVersion { } } -function Select-CurrentVersion { +function Select-CurrentVersion { # 'manifest.ps1' <# .SYNOPSIS Select current version of installed app, from 'current\manifest.json' or modified time of version directory diff --git a/libexec/scoop-alias.ps1 b/libexec/scoop-alias.ps1 index c639790cf3..e226548d50 100644 --- a/libexec/scoop-alias.ps1 +++ b/libexec/scoop-alias.ps1 @@ -23,9 +23,7 @@ param( [Switch]$verbose = $false ) -. "$PSScriptRoot\..\lib\core.ps1" -. "$PSScriptRoot\..\lib\help.ps1" -. "$PSScriptRoot\..\lib\install.ps1" +. "$PSScriptRoot\..\lib\install.ps1" # shim related $script:config_alias = 'alias' @@ -58,7 +56,7 @@ function add_alias($name, $command) { # Summary: $description $command "@ - $script | Out-File "$shimdir\$alias_file.ps1" -Encoding ASCII + $script | Out-UTF8File "$shimdir\$alias_file.ps1" # add alias to config $aliases | Add-Member -MemberType NoteProperty -Name $name -Value $alias_file @@ -96,7 +94,7 @@ function list_aliases { } if (!$aliases.count) { - warn 'No aliases founds.' + info "No alias found." } $aliases = $aliases.GetEnumerator() | Sort-Object Name if ($verbose) { diff --git a/libexec/scoop-bucket.ps1 b/libexec/scoop-bucket.ps1 index effb55a3a9..6a2e90e6cb 100644 --- a/libexec/scoop-bucket.ps1 +++ b/libexec/scoop-bucket.ps1 @@ -19,48 +19,53 @@ # scoop bucket known param($cmd, $name, $repo) -. "$PSScriptRoot\..\lib\core.ps1" -. "$PSScriptRoot\..\lib\buckets.ps1" -. "$PSScriptRoot\..\lib\help.ps1" +$usage_add = 'usage: scoop bucket add []' +$usage_rm = 'usage: scoop bucket rm ' -reset_aliases - -$usage_add = "usage: scoop bucket add []" -$usage_rm = "usage: scoop bucket rm " - -function list_buckets { - $buckets = @() - - foreach ($bucket in Get-LocalBucket) { - $source = Find-BucketDirectory $bucket -Root - $manifests = ( - Get-ChildItem "$source\bucket" -Force -Recurse -ErrorAction SilentlyContinue | - Measure-Object | Select-Object -ExpandProperty Count - ) - $updated = 'N/A' - if ((Test-Path (Join-Path $source '.git')) -and (Get-Command git -ErrorAction SilentlyContinue)) { - $updated = git -C $source log --format='%aD' -n 1 | Get-Date - $source = git -C $source config remote.origin.url - } else { - $updated = (Get-Item "$source\bucket").LastWriteTime - $source = friendly_path $source +switch ($cmd) { + 'add' { + if (!$name) { + ' missing' + $usage_add + exit 1 } - $buckets += New-Object PSObject -Property @{ - Name = $bucket - Source = $source - Updated = $updated - Manifests = $manifests + if (!$repo) { + $repo = known_bucket_repo $name + if (!$repo) { + "Unknown bucket '$name'. Try specifying ." + $usage_add + exit 1 + } } + $status = add_bucket $name $repo + exit $status + } + 'rm' { + if (!$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 } - return $buckets | Select-Object Name, Source, Updated, Manifests -} - -switch ($cmd) { - 'add' { add_bucket $name $repo } - 'rm' { rm_bucket $name } - 'list' { list_buckets } - 'known' { known_buckets } - default { "scoop bucket: cmd '$cmd' not supported"; my_usage; exit 1 } } - -exit 0 diff --git a/libexec/scoop-cache.ps1 b/libexec/scoop-cache.ps1 index b4eccc7720..96cd23763c 100644 --- a/libexec/scoop-cache.ps1 +++ b/libexec/scoop-cache.ps1 @@ -12,8 +12,6 @@ # scoop cache rm * param($cmd) -. "$PSScriptRoot\..\lib\help.ps1" - function cacheinfo($file) { $app, $version, $url = $file.Name -split '#' New-Object PSObject -Property @{ Name = $app; Version = $version; Length = $file.Length; URL = $url } diff --git a/libexec/scoop-cat.ps1 b/libexec/scoop-cat.ps1 index 43bf7e95dd..be217ad79b 100644 --- a/libexec/scoop-cat.ps1 +++ b/libexec/scoop-cat.ps1 @@ -3,11 +3,8 @@ param($app) -. "$PSScriptRoot\..\lib\manifest.ps1" -. "$PSScriptRoot\..\lib\install.ps1" -. "$PSScriptRoot\..\lib\help.ps1" - -reset_aliases +. "$PSScriptRoot\..\lib\json.ps1" # 'ConvertToPrettyJson' +. "$PSScriptRoot\..\lib\manifest.ps1" # 'Find-Manifest' (indirectly) if (!$app) { error ' missing'; my_usage; exit 1 } diff --git a/libexec/scoop-checkup.ps1 b/libexec/scoop-checkup.ps1 index 41d0282977..1b3c329940 100644 --- a/libexec/scoop-checkup.ps1 +++ b/libexec/scoop-checkup.ps1 @@ -3,7 +3,6 @@ # 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" $issues = 0 diff --git a/libexec/scoop-cleanup.ps1 b/libexec/scoop-cleanup.ps1 index 3c8c108592..6ce40a211f 100644 --- a/libexec/scoop-cleanup.ps1 +++ b/libexec/scoop-cleanup.ps1 @@ -3,28 +3,25 @@ # Help: 'scoop cleanup' cleans Scoop apps by removing old versions. # 'scoop cleanup ' cleans up the old versions of that app if said versions exist. # -# You can use '*' in place of to cleanup all apps. +# You can use '*' in place of or `-a`/`--all` switch to cleanup all apps. # # Options: +# -a, --all Cleanup all apps (alternative to '*') # -g, --global Cleanup a globally installed app # -k, --cache Remove outdated download cache -. "$PSScriptRoot\..\lib\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\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: missing'; my_usage; exit 1 } +if (!$apps -and !$all) { 'ERROR: missing'; my_usage; exit 1 } if ($global -and !(is_admin)) { 'ERROR: you need admin rights to cleanup global apps'; exit 1 @@ -64,8 +61,8 @@ function cleanup($app, $global, $verbose, $cache) { Write-Host '' } -if ($apps) { - if ($apps -eq '*') { +if ($apps -or $all) { + if ($apps -eq '*' -or $all) { $verbose = $false $apps = applist (installed_apps $false) $false if ($global) { diff --git a/libexec/scoop-config.ps1 b/libexec/scoop-config.ps1 index 556bf5748f..9ac0de17ea 100644 --- a/libexec/scoop-config.ps1 +++ b/libexec/scoop-config.ps1 @@ -76,10 +76,10 @@ # cachePath: # For downloads, defaults to 'cache' folder under Scoop root directory. # -# checkver_token: +# gh_token: # GitHub API token used to make authenticated requests. -# This is essential for checkver and similar functions -# to run without incurring rate limits. +# 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. @@ -96,6 +96,11 @@ # 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. +# # ARIA2 configuration # ------------------- # @@ -127,11 +132,6 @@ param($name, $value) -. "$PSScriptRoot\..\lib\core.ps1" -. "$PSScriptRoot\..\lib\help.ps1" - -reset_aliases - if (!$name) { $scoopConfig } elseif ($name -like '--help') { diff --git a/libexec/scoop-depends.ps1 b/libexec/scoop-depends.ps1 index 4883dc78da..e6b501b468 100644 --- a/libexec/scoop-depends.ps1 +++ b/libexec/scoop-depends.ps1 @@ -1,15 +1,9 @@ # Usage: scoop depends # Summary: List dependencies for an app -. "$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\depends.ps1" # 'Get-Dependency' +. "$PSScriptRoot\..\lib\manifest.ps1" # 'default_architecture' $opt, $apps, $err = getopt $args 'a:' 'arch=' $app = $apps[0] diff --git a/libexec/scoop-download.ps1 b/libexec/scoop-download.ps1 index e13a2520ed..faab60bb6b 100644 --- a/libexec/scoop-download.ps1 +++ b/libexec/scoop-download.ps1 @@ -15,12 +15,11 @@ # -u, --no-update-scoop Don't update Scoop before downloading if it's outdated # -a, --arch <32bit|64bit> Use the specified architecture, if the app supports it -. "$PSScriptRoot\..\lib\manifest.ps1" -. "$PSScriptRoot\..\lib\install.ps1" -. "$PSScriptRoot\..\lib\help.ps1" . "$PSScriptRoot\..\lib\getopt.ps1" - -reset_aliases +. "$PSScriptRoot\..\lib\json.ps1" # 'autoupdate.ps1' (indirectly) +. "$PSScriptRoot\..\lib\autoupdate.ps1" # 'generate_user_manifest' (indirectly) +. "$PSScriptRoot\..\lib\manifest.ps1" # 'default_architecture' 'generate_user_manifest' 'Find-Manifest' (indirectly) +. "$PSScriptRoot\..\lib\install.ps1" $opt, $apps, $err = getopt $args 'fhua:' 'force', 'no-hash-check', 'no-update-scoop', 'arch=' if ($err) { error "scoop download: $err"; exit 1 } @@ -100,6 +99,7 @@ foreach ($curr_app in $apps) { } catch { write-host -f darkred $_ error "URL $url is not valid" + $dl_failure = $true continue } @@ -126,7 +126,9 @@ foreach ($curr_app in $apps) { } } - success "'$app' ($version) was downloaded successfully!" + if (!$dl_failure) { + success "'$app' ($version) was downloaded successfully!" + } } exit 0 diff --git a/libexec/scoop-export.ps1 b/libexec/scoop-export.ps1 index 1c03635f9b..78410dab73 100644 --- a/libexec/scoop-export.ps1 +++ b/libexec/scoop-export.ps1 @@ -2,12 +2,9 @@ # Summary: Exports (an importable) list of installed apps # Help: Lists all installed apps. -. "$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" # 'default_architecture' 'Select-CurrentVersion' (indirectly) -reset_aliases $def_arch = default_architecture $local = installed_apps $false | ForEach-Object { @{ name = $_; global = $false } } diff --git a/libexec/scoop-help.ps1 b/libexec/scoop-help.ps1 index 45b0cb9f7a..819800ece0 100644 --- a/libexec/scoop-help.ps1 +++ b/libexec/scoop-help.ps1 @@ -2,12 +2,6 @@ # 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 @@ -47,4 +41,3 @@ Some useful commands are:" } exit 0 - diff --git a/libexec/scoop-hold.ps1 b/libexec/scoop-hold.ps1 index ed171f4def..3eb3c2e70e 100644 --- a/libexec/scoop-hold.ps1 +++ b/libexec/scoop-hold.ps1 @@ -1,11 +1,10 @@ # Usage: scoop hold # Summary: Hold an app to disable updates -. "$PSScriptRoot\..\lib\help.ps1" -. "$PSScriptRoot\..\lib\manifest.ps1" -. "$PSScriptRoot\..\lib\versions.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 if(!$apps) { diff --git a/libexec/scoop-home.ps1 b/libexec/scoop-home.ps1 index aae57f69f4..916b09af25 100644 --- a/libexec/scoop-home.ps1 +++ b/libexec/scoop-home.ps1 @@ -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" # 'Find-Manifest' (indirectly) -reset_aliases - -if($app) { - $manifest, $bucket = find_manifest $app - if($manifest) { - if([string]::isnullorempty($manifest.homepage)) { +if ($app) { + $null, $manifest, $bucket, $null = Find-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 diff --git a/libexec/scoop-info.ps1 b/libexec/scoop-info.ps1 index 630606af8b..e192409626 100644 --- a/libexec/scoop-info.ps1 +++ b/libexec/scoop-info.ps1 @@ -3,13 +3,9 @@ # Options: # -v, --verbose Show full paths and URLs -. "$PSScriptRoot\..\lib\help.ps1" -. "$PSScriptRoot\..\lib\install.ps1" -. "$PSScriptRoot\..\lib\manifest.ps1" -. "$PSScriptRoot\..\lib\versions.ps1" . "$PSScriptRoot\..\lib\getopt.ps1" - -reset_aliases +. "$PSScriptRoot\..\lib\manifest.ps1" # 'Find-Manifest' (indirectly) +. "$PSScriptRoot\..\lib\versions.ps1" # 'Get-InstalledVersion' $opt, $app, $err = getopt $args 'v' 'verbose' if ($err) { error "scoop info: $err"; exit 1 } diff --git a/libexec/scoop-install.ps1 b/libexec/scoop-install.ps1 index d28938b6ea..9c11ddfce0 100644 --- a/libexec/scoop-install.ps1 +++ b/libexec/scoop-install.ps1 @@ -17,20 +17,17 @@ # -s, --skip Skip hash validation (use with caution!) # -a, --arch <32bit|64bit> 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\getopt.ps1" +. "$PSScriptRoot\..\lib\json.ps1" # 'autoupdate.ps1' 'manifest.ps1' (indirectly) +. "$PSScriptRoot\..\lib\autoupdate.ps1" # 'generate_user_manifest' (indirectly) +. "$PSScriptRoot\..\lib\manifest.ps1" # 'default_architecture' 'generate_user_manifest' 'Select-CurrentVersion' (indirectly) . "$PSScriptRoot\..\lib\install.ps1" +. "$PSScriptRoot\..\lib\decompress.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 - $opt, $apps, $err = getopt $args 'gikusa:' 'global', 'independent', 'no-cache', 'no-update-scoop', 'skip', 'arch=' if ($err) { "scoop install: $err"; exit 1 } diff --git a/libexec/scoop-list.ps1 b/libexec/scoop-list.ps1 index 1e265b0497..0d681d36d3 100644 --- a/libexec/scoop-list.ps1 +++ b/libexec/scoop-list.ps1 @@ -3,12 +3,9 @@ # 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 if (-not (Get-FormatData ScoopApps)) { Update-FormatData "$PSScriptRoot\..\supporting\formats\ScoopTypes.Format.ps1xml" diff --git a/libexec/scoop-prefix.ps1 b/libexec/scoop-prefix.ps1 index f54af5e86c..c16cda574a 100644 --- a/libexec/scoop-prefix.ps1 +++ b/libexec/scoop-prefix.ps1 @@ -2,18 +2,16 @@ # Summary: Returns the path to the specified app param($app) +. "$PSScriptRoot\..\lib\versions.ps1" # 'currentdir' (indirectly) + if (!$app) { - . "$PSScriptRoot\..\lib\help.ps1" my_usage exit 1 } -. "$PSScriptRoot\..\lib\core.ps1" -. "$PSScriptRoot\..\lib\versions.ps1" - $app_path = currentdir $app $false if (!(Test-Path $app_path)) { - $app_path = currentdir $app$true + $app_path = currentdir $app $true } if (Test-Path $app_path) { diff --git a/libexec/scoop-reset.ps1 b/libexec/scoop-reset.ps1 index ceb98d8bf7..05cefe47cc 100644 --- a/libexec/scoop-reset.ps1 +++ b/libexec/scoop-reset.ps1 @@ -4,15 +4,12 @@ # if you've installed 'python' and 'python27', you can use 'scoop reset' to switch between # using one or the other. -. "$PSScriptRoot\..\lib\core.ps1" -. "$PSScriptRoot\..\lib\manifest.ps1" -. "$PSScriptRoot\..\lib\help.ps1" . "$PSScriptRoot\..\lib\getopt.ps1" +. "$PSScriptRoot\..\lib\manifest.ps1" # 'Select-CurrentVersion' (indirectly) . "$PSScriptRoot\..\lib\install.ps1" -. "$PSScriptRoot\..\lib\versions.ps1" +. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion' . "$PSScriptRoot\..\lib\shortcuts.ps1" -reset_aliases $opt, $apps, $err = getopt $args if($err) { "scoop reset: $err"; exit 1 } diff --git a/libexec/scoop-search.ps1 b/libexec/scoop-search.ps1 index 4ddc29c682..c077df2543 100644 --- a/libexec/scoop-search.ps1 +++ b/libexec/scoop-search.ps1 @@ -5,12 +5,9 @@ # If used with [query], shows app names that match the query. # 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' function bin_match($manifest, $query) { if(!$manifest.bin) { return $false } diff --git a/libexec/scoop-shim.ps1 b/libexec/scoop-shim.ps1 index d6b0e414f7..20f6d0c684 100644 --- a/libexec/scoop-shim.ps1 +++ b/libexec/scoop-shim.ps1 @@ -2,7 +2,7 @@ # Summary: Manipulate Scoop shims # Help: Manipulate Scoop shims: add, rm, list, info, alter, etc. # -# To add a costom shim, use the 'add' subcommand: +# To add a custom shim, use the 'add' subcommand: # # scoop shim add [...] # @@ -29,7 +29,6 @@ param($SubCommand, $ShimName, [Switch]$global) -. "$PSScriptRoot\..\lib\help.ps1" . "$PSScriptRoot\..\lib\install.ps1" # for rm_shim if ($SubCommand -notin @('add', 'rm', 'list', 'info', 'alter')) { diff --git a/libexec/scoop-status.ps1 b/libexec/scoop-status.ps1 index 2aa60d458b..878656693c 100644 --- a/libexec/scoop-status.ps1 +++ b/libexec/scoop-status.ps1 @@ -1,31 +1,24 @@ # Usage: scoop status # Summary: Show status and check for new app versions -. "$PSScriptRoot\..\lib\core.ps1" -. "$PSScriptRoot\..\lib\manifest.ps1" -. "$PSScriptRoot\..\lib\buckets.ps1" -. "$PSScriptRoot\..\lib\versions.ps1" -. "$PSScriptRoot\..\lib\depends.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') $needs_update = $false -if(Test-Path "$currentdir\.git") { +if (Test-Path "$currentdir\.git") { git_cmd -C "`"$currentdir`"" fetch -q origin - $commits = $(git -C $currentdir log "HEAD..origin/$(scoop config SCOOP_BRANCH)" --oneline) - if($commits) { $needs_update = $true } -} -else { + $commits = $(git -C $currentdir log "HEAD..origin/$(get_config SCOOP_BRANCH)" --oneline) + if ($commits) { $needs_update = $true } +} else { $needs_update = $true } -if($needs_update) { +if ($needs_update) { warn "Scoop is out of date. Run 'scoop update' to get the latest changes." -} -else { success "Scoop is up to date."} +} else { success 'Scoop is up to date.' } $failed = @() $outdated = @() @@ -36,30 +29,30 @@ $onhold = @() $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) { + if ($status.failed) { $failed += @{ $app = $status.version } } - if($status.removed) { + if ($status.removed) { $removed += @{ $app = $status.version } } - if($status.outdated) { + if ($status.outdated) { $outdated += @{ $app = @($status.version, $status.latest_version) } - if($status.hold) { + if ($status.hold) { $onhold += @{ $app = @($status.version, $status.latest_version) } } } - if($status.missing_deps) { - $missing_deps += ,(@($app) + @($status.missing_deps)) + if ($status.missing_deps) { + $missing_deps += , (@($app) + @($status.missing_deps)) } } } -if($outdated) { +if ($outdated) { Write-Host -f DarkCyan 'Updates are available for:' $outdated.keys | ForEach-Object { $versions = $outdated.$_ @@ -67,7 +60,7 @@ if($outdated) { } } -if($onhold) { +if ($onhold) { Write-Host -f DarkCyan 'These apps are outdated and on hold:' $onhold.keys | ForEach-Object { $versions = $onhold.$_ @@ -75,21 +68,21 @@ if($onhold) { } } -if($removed) { +if ($removed) { Write-Host -f DarkCyan 'These app manifests have been removed:' $removed.keys | ForEach-Object { " $_" } } -if($failed) { +if ($failed) { Write-Host -f DarkCyan 'These apps failed to install:' $failed.keys | ForEach-Object { " $_" } } -if($missing_deps) { +if ($missing_deps) { Write-Host -f DarkCyan 'Missing runtime dependencies:' $missing_deps | ForEach-Object { $app, $deps = $_ @@ -97,8 +90,8 @@ if($missing_deps) { } } -if(!$old -and !$removed -and !$failed -and !$missing_deps -and !$needs_update) { - success "Everything is ok!" +if (!$old -and !$removed -and !$failed -and !$missing_deps -and !$needs_update) { + success 'Everything is ok!' } exit 0 diff --git a/libexec/scoop-unhold.ps1 b/libexec/scoop-unhold.ps1 index 9a16d75289..c749cadfee 100644 --- a/libexec/scoop-unhold.ps1 +++ b/libexec/scoop-unhold.ps1 @@ -1,11 +1,10 @@ # Usage: scoop unhold # Summary: Unhold an app to enable updates -. "$PSScriptRoot\..\lib\help.ps1" -. "$PSScriptRoot\..\lib\manifest.ps1" -. "$PSScriptRoot\..\lib\versions.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 if(!$apps) { diff --git a/libexec/scoop-uninstall.ps1 b/libexec/scoop-uninstall.ps1 index 94351b7762..ba4ca466b9 100644 --- a/libexec/scoop-uninstall.ps1 +++ b/libexec/scoop-uninstall.ps1 @@ -6,16 +6,12 @@ # -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" # 'Select-CurrentVersion' (indirectly) . "$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' diff --git a/libexec/scoop-update.ps1 b/libexec/scoop-update.ps1 index f971017720..a1901cc09a 100644 --- a/libexec/scoop-update.ps1 +++ b/libexec/scoop-update.ps1 @@ -14,19 +14,16 @@ # -q, --quiet Hide extraneous messages # -a, --all Update all apps (alternative to '*') -. "$PSScriptRoot\..\lib\core.ps1" +. "$PSScriptRoot\..\lib\getopt.ps1" +. "$PSScriptRoot\..\lib\json.ps1" # 'save_install_info' in 'manifest.ps1' (indirectly) . "$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\install.ps1" -reset_aliases - $opt, $apps, $err = getopt $args 'gfiksqa' 'global', 'force', 'independent', 'no-cache', 'skip', 'quiet', 'all' if ($err) { "scoop update: $err"; exit 1 } $global = $opt.g -or $opt.global @@ -111,7 +108,7 @@ function update_scoop() { $res = $lastexitcode if ($show_update_log) { - Invoke-Expression "git -C '$currentdir' --no-pager log --no-decorate --grep='^chore' --invert-grep --format='tformat: * %C(yellow)%h%Creset %<|(72,trunc)%s %C(cyan)%cr%Creset' '$previousCommit..HEAD'" + Invoke-Expression "git -C '$currentdir' --no-pager log --no-decorate --grep='^(chore)' --invert-grep --format='tformat: * %C(yellow)%h%Creset %<|(72,trunc)%s %C(cyan)%cr%Creset' '$previousCommit..HEAD'" } if ($res -ne 0) { @@ -148,7 +145,7 @@ function update_scoop() { $previousCommit = (Invoke-Expression "git -C '$bucketLoc' rev-parse HEAD") git_cmd -C "`"$bucketLoc`"" pull -q if ($show_update_log) { - Invoke-Expression "git -C '$bucketLoc' --no-pager log --no-decorate --grep='^chore' --invert-grep --format='tformat: * %C(yellow)%h%Creset %<|(72,trunc)%s %C(cyan)%cr%Creset' '$previousCommit..HEAD'" + Invoke-Expression "git -C '$bucketLoc' --no-pager log --no-decorate --grep='^(chore)' --invert-grep --format='tformat: * %C(yellow)%h%Creset %<|(72,trunc)%s %C(cyan)%cr%Creset' '$previousCommit..HEAD'" } } diff --git a/libexec/scoop-virustotal.ps1 b/libexec/scoop-virustotal.ps1 index 87c4593e05..e3e847bad9 100644 --- a/libexec/scoop-virustotal.ps1 +++ b/libexec/scoop-virustotal.ps1 @@ -34,26 +34,20 @@ # -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 -. "$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" - -reset_aliases +. "$PSScriptRoot\..\lib\manifest.ps1" # 'Find-Manifest' (indirectly) +. "$PSScriptRoot\..\lib\json.ps1" # 'json_path' +. "$PSScriptRoot\..\lib\install.ps1" # 'hash_for_url' +. "$PSScriptRoot\..\lib\depends.ps1" # 'Get-Dependency' $opt, $apps, $err = getopt $args 'a:snu' @('arch=', 'scan', 'no-depends', 'no-update-scoop') -if($err) { "scoop virustotal: $err"; exit 1 } -if(!$apps) { my_usage; exit 1 } +if ($err) { "scoop virustotal: $err"; exit 1 } +if (!$apps) { my_usage; exit 1 } $architecture = ensure_architecture ($opt.a + $opt.arch) if (is_scoop_outdated) { if ($opt.u -or $opt.'no-update-scoop') { - warn "Scoop is out of date." + warn 'Scoop is out of date.' } else { scoop update } @@ -61,7 +55,7 @@ if (is_scoop_outdated) { $apps_param = $apps -if($apps_param -eq '*') { +if ($apps_param -eq '*') { $apps = installed_apps $false $apps += installed_apps $true } @@ -99,13 +93,13 @@ Function Get-VirusTotalResult($hash, $app) { $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" } + 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) { + Write-Host -f $fg "$app`: $unsafe/$undetected, $see_url" + if ($unsafe -gt 0) { return $_ERR_UNSAFE } return 0 @@ -132,16 +126,15 @@ Function Submit-RedirectedUrl { # Adapted according to Roy's response (January 23, 2014 at 11:59 am) # Adapted to always return an URL Param ( - [Parameter(Mandatory=$true)] + [Parameter(Mandatory = $true)] [String]$URL ) $request = [System.Net.WebRequest]::Create($url) - $request.AllowAutoRedirect=$false - $response=$request.GetResponse() + $request.AllowAutoRedirect = $false + $response = $request.GetResponse() if (([int]$response.StatusCode -ge 300) -and ([int]$response.StatusCode -lt 400)) { - $redir = $response.GetResponseHeader("Location") - } - else { + $redir = $response.GetResponseHeader('Location') + } else { $redir = $URL } $response.Close() @@ -158,8 +151,8 @@ 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") +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. " + @@ -209,7 +202,7 @@ Function Submit-ToVirusTotal ($url, $app, $do_scan, $retrying=$False) { $apps | ForEach-Object { $app = $_ # write-host $app - $manifest, $bucket = find_manifest $app + $null, $manifest, $bucket, $null = Find-Manifest $app if(!$manifest) { $exit_code = $exit_code -bor $_ERR_NO_INFO warn "$app`: manifest not found" diff --git a/libexec/scoop-which.ps1 b/libexec/scoop-which.ps1 index 5966d35edc..c79d59fc6d 100644 --- a/libexec/scoop-which.ps1 +++ b/libexec/scoop-which.ps1 @@ -2,10 +2,6 @@ # Summary: Locate a shim/executable (similar to 'which' on Linux) # Help: Locate the path to a shim/executable that was installed with Scoop (similar to 'which' on Linux) param($command) -. "$PSScriptRoot\..\lib\core.ps1" -. "$PSScriptRoot\..\lib\help.ps1" - -reset_aliases if (!$command) { 'ERROR: missing' diff --git a/schema.json b/schema.json index 5f03ada7aa..f1b934dd04 100644 --- a/schema.json +++ b/schema.json @@ -604,7 +604,6 @@ }, "required": [ "version", - "description", "homepage", "license" ], diff --git a/supporting/formats/ScoopTypes.Format.ps1xml b/supporting/formats/ScoopTypes.Format.ps1xml index dc049b438a..b2dff49d84 100644 --- a/supporting/formats/ScoopTypes.Format.ps1xml +++ b/supporting/formats/ScoopTypes.Format.ps1xml @@ -21,7 +21,7 @@ Updated - yyyy-MM-dd HH:MM:ss + yyyy-MM-dd HH:mm:ss Info diff --git a/supporting/shims/kiennq/Makefile b/supporting/shims/kiennq/Makefile index da872b9462..1610fc723c 100644 --- a/supporting/shims/kiennq/Makefile +++ b/supporting/shims/kiennq/Makefile @@ -1,6 +1,6 @@ VER?=2.2.1 -ZIP=shimexe-$(VER).zip +ZIP=shimexe.zip URL?=https://github.com/kiennq/scoop-better-shimexe/releases/download/$(VER)/$(ZIP) LATEST_URL?=https://github.com/kiennq/scoop-better-shimexe/releases/latest NEWVER=$(shell cat version.txt) diff --git a/test/Import-Bucket-Tests.ps1 b/test/Import-Bucket-Tests.ps1 index 63fc49fbdb..bdc249f800 100644 --- a/test/Import-Bucket-Tests.ps1 +++ b/test/Import-Bucket-Tests.ps1 @@ -64,7 +64,7 @@ Describe 'Manifest Validator' -Tag 'Validator' { $validator.Validate("$working_dir\invalid_wget.json") | Should -BeFalse $validator.Errors.Count | Should -Be 16 $validator.Errors | Select-Object -First 1 | Should -Match "Property 'randomproperty' has not been defined and the schema does not allow additional properties\." - $validator.Errors | Select-Object -Last 1 | Should -Match 'Required properties are missing from object: version, description\.' + $validator.Errors | Select-Object -Last 1 | Should -Match 'Required properties are missing from object: version\.' } } } @@ -125,4 +125,3 @@ Describe 'manifest validates against the schema' -Tag 'Manifests' { } } } - diff --git a/test/Scoop-Alias.Tests.ps1 b/test/Scoop-Alias.Tests.ps1 index 9d3f4078b6..7c6c0d842e 100644 --- a/test/Scoop-Alias.Tests.ps1 +++ b/test/Scoop-Alias.Tests.ps1 @@ -1,14 +1,15 @@ +. "$PSScriptRoot\Scoop-TestLib.ps1" +. "$PSScriptRoot\..\lib\core.ps1" +. "$PSScriptRoot\..\lib\help.ps1" . "$PSScriptRoot\..\libexec\scoop-alias.ps1" | Out-Null -reset_aliases - Describe 'add_alias' -Tag 'Scoop' { - Mock shimdir { 'TestDrive:\shim' } + Mock shimdir { "$env:TEMP\shims" } Mock set_config { } Mock get_config { @{} } $shimdir = shimdir - mkdir $shimdir + ensure $shimdir Context "alias doesn't exist" { It 'creates a new alias' { @@ -23,7 +24,7 @@ Describe 'add_alias' -Tag 'Scoop' { Context 'alias exists' { It 'does not change existing alias' { $alias_file = "$shimdir\scoop-rm.ps1" - New-Item $alias_file -type file + New-Item $alias_file -Type File -Force $alias_file | Should -Exist add_alias 'rm' 'test' @@ -33,12 +34,12 @@ Describe 'add_alias' -Tag 'Scoop' { } Describe 'rm_alias' -Tag 'Scoop' { - Mock shimdir { 'TestDrive:\shim' } + Mock shimdir { "$env:TEMP\shims" } Mock set_config { } Mock get_config { @{} } $shimdir = shimdir - mkdir $shimdir + ensure $shimdir Context 'alias exists' { It 'removes an existing alias' { diff --git a/test/Scoop-Config.Tests.ps1 b/test/Scoop-Config.Tests.ps1 index e992a2bde7..604a25b2f0 100644 --- a/test/Scoop-Config.Tests.ps1 +++ b/test/Scoop-Config.Tests.ps1 @@ -1,3 +1,4 @@ +. "$PSScriptRoot\Scoop-TestLib.ps1" . "$PSScriptRoot\..\lib\core.ps1" Describe 'config' -Tag 'Scoop' { diff --git a/test/Scoop-Core.Tests.ps1 b/test/Scoop-Core.Tests.ps1 index e4fd6a6f06..75d6b7d7df 100644 --- a/test/Scoop-Core.Tests.ps1 +++ b/test/Scoop-Core.Tests.ps1 @@ -1,7 +1,7 @@ +. "$PSScriptRoot\Scoop-TestLib.ps1" . "$PSScriptRoot\..\lib\core.ps1" . "$PSScriptRoot\..\lib\install.ps1" . "$PSScriptRoot\..\lib\unix.ps1" -. "$PSScriptRoot\Scoop-TestLib.ps1" $repo_dir = (Get-Item $MyInvocation.MyCommand.Path).directory.parent.FullName $isUnix = is_unix @@ -234,12 +234,12 @@ Describe 'get_app_name_from_shim' -Tag 'Scoop' { } It 'returns app name if file exists and is a shim to an app' -Skip:$isUnix { - mkdir -p "$working_dir/mockapp/current/" + ensure "$working_dir/mockapp/current/" Write-Output '' | Out-File "$working_dir/mockapp/current/mockapp1.ps1" shim "$working_dir/mockapp/current/mockapp1.ps1" $false 'shim-test1' $shim_path1 = (Get-Command 'shim-test1.ps1').Path get_app_name_from_shim "$shim_path1" | Should -Be 'mockapp' - mkdir -p "$working_dir/mockapp/1.0.0/" + ensure "$working_dir/mockapp/1.0.0/" Write-Output '' | Out-File "$working_dir/mockapp/1.0.0/mockapp2.ps1" shim "$working_dir/mockapp/1.0.0/mockapp2.ps1" $false 'shim-test2' $shim_path2 = (Get-Command 'shim-test2.ps1').Path @@ -267,10 +267,6 @@ Describe 'ensure_robocopy_in_path' -Tag 'Scoop' { $shimdir = shimdir $false Mock versiondir { $repo_dir } - BeforeAll { - reset_aliases - } - Context 'robocopy is not in path' { It 'shims robocopy when not on path' -Skip:$isUnix { Mock Test-CommandAvailable { $false } diff --git a/test/Scoop-Decompress.Tests.ps1 b/test/Scoop-Decompress.Tests.ps1 index 5accad1cab..4cf6744936 100644 --- a/test/Scoop-Decompress.Tests.ps1 +++ b/test/Scoop-Decompress.Tests.ps1 @@ -1,9 +1,10 @@ . "$PSScriptRoot\Scoop-TestLib.ps1" +. "$PSScriptRoot\..\lib\core.ps1" . "$PSScriptRoot\..\lib\decompress.ps1" -. "$PSScriptRoot\..\lib\unix.ps1" . "$PSScriptRoot\..\lib\install.ps1" . "$PSScriptRoot\..\lib\manifest.ps1" . "$PSScriptRoot\..\lib\versions.ps1" +. "$PSScriptRoot\..\lib\unix.ps1" $isUnix = is_unix diff --git a/test/Scoop-Depends.Tests.ps1 b/test/Scoop-Depends.Tests.ps1 index 0c0b82e75c..ba54550554 100644 --- a/test/Scoop-Depends.Tests.ps1 +++ b/test/Scoop-Depends.Tests.ps1 @@ -1,5 +1,7 @@ . "$PSScriptRoot\Scoop-TestLib.ps1" +. "$PSScriptRoot\..\lib\core.ps1" . "$PSScriptRoot\..\lib\depends.ps1" +. "$PSScriptRoot\..\lib\buckets.ps1" . "$PSScriptRoot\..\lib\install.ps1" . "$PSScriptRoot\..\lib\manifest.ps1" diff --git a/test/Scoop-Install.Tests.ps1 b/test/Scoop-Install.Tests.ps1 index a2678165eb..8750feb506 100644 --- a/test/Scoop-Install.Tests.ps1 +++ b/test/Scoop-Install.Tests.ps1 @@ -1,8 +1,8 @@ +. "$PSScriptRoot\Scoop-TestLib.ps1" . "$PSScriptRoot\..\lib\core.ps1" . "$PSScriptRoot\..\lib\manifest.ps1" . "$PSScriptRoot\..\lib\install.ps1" . "$PSScriptRoot\..\lib\unix.ps1" -. "$PSScriptRoot\Scoop-TestLib.ps1" $isUnix = is_unix