diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0b78b04..0fd79ee 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ on: jobs: test_powershell: - name: WindowsPowerShell + name: Test (WindowsPowerShell) runs-on: windows-latest steps: - name: Checkout @@ -25,13 +25,14 @@ jobs: - name: Test Scoop Install command shell: powershell run: | + $VerbosePreference = "Continue" ./install.ps1 -RunAsAdmin echo "$Env:USERPROFILE\scoop\shims" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - name: Test scoop command availability shell: powershell run: scoop help test_pwsh_cloning: - name: PowerShell (with cloning) + name: Test (PowerShell, with cloning) runs-on: windows-latest steps: - name: Checkout @@ -49,13 +50,14 @@ jobs: - name: Test Scoop Install command shell: pwsh run: | + $VerbosePreference = "Continue" ./install.ps1 -RunAsAdmin echo "~\scoop\shims" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - name: Test scoop command availability shell: pwsh run: scoop help - test_pwsh_download: - name: PowerShell (with downloading) + install_pwsh_download: + name: Installation (using download due to failing git clone) runs-on: windows-latest steps: - name: Checkout @@ -66,8 +68,26 @@ jobs: shell: pwsh run: | git config --global protocol.https.allow never + $VerbosePreference = "Continue" ./install.ps1 -RunAsAdmin echo "~\scoop\shims" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - name: Test scoop command availability shell: pwsh run: scoop help + install_pwsh_args: + name: Installation (using download of given source) + runs-on: windows-latest + steps: + - name: Checkout + uses: actions/checkout@main + with: + fetch-depth: 2 + - name: Test Scoop Install command + shell: pwsh + run: | + $VerbosePreference = "Continue" + ./install.ps1 -ScoopAppRepoZip "https://github.com/ScoopInstaller/Scoop/archive/master.zip" -RunAsAdmin + echo "~\scoop\shims" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + - name: Test scoop command availability + shell: pwsh + run: scoop help diff --git a/install.ps1 b/install.ps1 index b213c59..e58a7ad 100644 --- a/install.ps1 +++ b/install.ps1 @@ -40,6 +40,20 @@ .PARAMETER ScoopCacheDir Specifies cache directory. If not specified, caches will be downloaded to '$ScoopDir\cache'. +.PARAMETER ScoopAppRepoZip + Specifies the source of Scoop app as zip file. + If not specified, the default app repository zip will be used. +.PARAMETER ScoopAppRepoGit + Specifies the source of Scoop app as git repository. + If not specified, the default app git repository will be used. +.PARAMETER ScoopMainBucketRepoZip + Specifies the source of Scoop main bucket as zip file. + If not specified, but a Scoop app source is specified, no main bucket will be installed. + Otherwise, the default main bucket repository zip will be used. +.PARAMETER ScoopMainBucketRepoGit + Specifies the source of Scoop main bucket as git repository. + If not specified, but a Scoop app source is specified, no main bucket will be installed. + Otherwise, the default main bucket git repository will be used. .PARAMETER NoProxy Bypass system proxy during the installation. .PARAMETER Proxy @@ -59,6 +73,10 @@ param( [String] $ScoopDir, [String] $ScoopGlobalDir, [String] $ScoopCacheDir, + [String] $ScoopAppRepoZip, + [String] $ScoopAppRepoGit, + [String] $ScoopMainBucketRepoZip, + [String] $ScoopMainBucketRepoGit, [Switch] $NoProxy, [Uri] $Proxy, [System.Management.Automation.PSCredential] $ProxyCredential, @@ -568,6 +586,35 @@ function Test-CommandAvailable { return [Boolean](Get-Command $Command -ErrorAction SilentlyContinue) } +function Get-Scoop-Source { + param ( + [Parameter(Mandatory = $False, Position = 0)] + [String] $ScoopAppRepoZip = "", + [Parameter(Mandatory = $False, Position = 1)] + [String] $ScoopAppRepoGit = "", + [Parameter(Mandatory = $False, Position = 2)] + [String] $ScoopMainBucketRepoZip = "", + [Parameter(Mandatory = $False, Position = 3)] + [String] $ScoopMainBucketRepoGit = "" + ) + $ScoopSource = @{} + if ($ScoopAppRepoZip -or $Env:SCOOP_APP_REPO_ZIP -or + $ScoopAppRepoGit -or $Env:SCOOP_APP_REPO_GIT) { + # In case of any app repo source is provided, we expect all repo source parameters are provided. + # Otherwise we skip the main bucket source. + $ScoopSource.AppRepoZip = $ScoopAppRepoZip, $Env:SCOOP_APP_REPO_ZIP | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -First 1 + $ScoopSource.AppRepoGit = $ScoopAppRepoGit, $Env:SCOOP_APP_REPO_GIT | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -First 1 + $ScoopSource.MainBucketRepoZip = $ScoopMainBucketRepoZip, $Env:SCOOP_MAIN_BUCKET_REPO_ZIP | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -First 1 + $ScoopSource.MainBucketRepoGit = $ScoopMainBucketRepoGit, $Env:SCOOP_MAIN_BUCKET_REPO_GIT | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -First 1 + } else { + $ScoopSource.AppRepoZip = "https://github.com/ScoopInstaller/Scoop/archive/master.zip" + $ScoopSource.AppRepoGit = "https://github.com/ScoopInstaller/Scoop.git" + $ScoopSource.MainBucketRepoZip = $ScoopMainBucketRepoZip, $Env:SCOOP_MAIN_BUCKET_REPO_ZIP, "https://github.com/ScoopInstaller/Main/archive/master.zip" | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -First 1 + $ScoopSource.MainBucketRepoGit = $ScoopMainBucketRepoGit, $Env:SCOOP_MAIN_BUCKET_REPO_GIT, "https://github.com/ScoopInstaller/Main.git" | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -First 1 + } + return $ScoopSource +} + function Install-Scoop { Write-InstallInfo 'Initializing...' # Validate install parameters @@ -578,11 +625,18 @@ function Install-Scoop { Optimize-SecurityProtocol # Download scoop from GitHub - Write-InstallInfo 'Downloading...' + Write-InstallInfo 'Installing ...' $downloader = Get-Downloader - [bool]$downloadZipsRequired = $True + [bool]$downloadAppZipRequired = $True + [bool]$downloadMainBucketZipRequired = $True - if (Test-CommandAvailable('git')) { + # Create buckets dir as it might not be created in case no + # initial bucket is provided + if (!(Test-Path $SCOOP_BUCKETS_DIR)) { + New-Item -Type Directory $SCOOP_BUCKETS_DIR | Out-Null + } + + if (($ScoopSources.AppRepoGit -or $ScoopSources.MainBucketRepoGit) -and (Test-CommandAvailable('git'))) { $old_https = $env:HTTPS_PROXY $old_http = $env:HTTP_PROXY try { @@ -591,17 +645,22 @@ function Install-Scoop { $Env:HTTP_PROXY = $downloader.Proxy.Address $Env:HTTPS_PROXY = $downloader.Proxy.Address } - Write-Verbose "Cloning $SCOOP_PACKAGE_GIT_REPO to $SCOOP_APP_DIR" - git clone -q $SCOOP_PACKAGE_GIT_REPO $SCOOP_APP_DIR - if (-Not $?) { - throw 'Cloning failed. Falling back to downloading zip files.' + if ($ScoopSources.AppRepoGit) { + Write-Verbose ("Cloning {0} to $SCOOP_APP_DIR" -f $ScoopSources.AppRepoGit) + git clone -q $ScoopSources.AppRepoGit $SCOOP_APP_DIR + if (-Not $?) { + throw 'Cloning failed. Falling back to downloading zip files.' + } + $downloadAppZipRequired = $False } - Write-Verbose "Cloning $SCOOP_MAIN_BUCKET_GIT_REPO to $SCOOP_MAIN_BUCKET_DIR" - git clone -q $SCOOP_MAIN_BUCKET_GIT_REPO $SCOOP_MAIN_BUCKET_DIR - if (-Not $?) { - throw 'Cloning failed. Falling back to downloading zip files.' + if ($ScoopSources.MainBucketRepoGit) { + Write-Verbose ("Cloning {0} to $SCOOP_MAIN_BUCKET_DIR" -f $ScoopSources.MainBucketRepoGit) + git clone -q $ScoopSources.MainBucketRepoGit $SCOOP_MAIN_BUCKET_DIR + if (-Not $?) { + throw 'Cloning failed. Falling back to downloading zip files.' + } + $downloadMainBucketZipRequired = $False } - $downloadZipsRequired = $False } catch { Write-Warning "$($_.Exception.Message)" $Global:LastExitCode = 0 @@ -611,41 +670,42 @@ function Install-Scoop { } } - if ($downloadZipsRequired) { - # 1. download scoop + if ($ScoopSources.AppRepoZip -and $downloadAppZipRequired) { + # 1. download scoop app $scoopZipfile = "$SCOOP_APP_DIR\scoop.zip" if (!(Test-Path $SCOOP_APP_DIR)) { New-Item -Type Directory $SCOOP_APP_DIR | Out-Null } - Write-Verbose "Downloading $SCOOP_PACKAGE_REPO to $scoopZipfile" - $downloader.downloadFile($SCOOP_PACKAGE_REPO, $scoopZipfile) + Write-Verbose ("Downloading {0} to $scoopZipfile" -f $ScoopSources.AppRepoZip) + $downloader.downloadFile($ScoopSources.AppRepoZip, $scoopZipfile) + # extract + $scoopUnzipTempDir = "$SCOOP_APP_DIR\_tmp" + Write-Verbose "Extracting $scoopZipfile to $scoopUnzipTempDir" + Expand-ZipArchive $scoopZipfile $scoopUnzipTempDir + Copy-Item "$scoopUnzipTempDir\scoop-*\*" $SCOOP_APP_DIR -Recurse -Force + # cleanup + Remove-Item $scoopUnzipTempDir -Recurse -Force + Remove-Item $scoopZipfile + } + + if ($ScoopSources.MainBucketRepoZip -and $downloadMainBucketZipRequired) { # 2. download scoop main bucket $scoopMainZipfile = "$SCOOP_MAIN_BUCKET_DIR\scoop-main.zip" if (!(Test-Path $SCOOP_MAIN_BUCKET_DIR)) { New-Item -Type Directory $SCOOP_MAIN_BUCKET_DIR | Out-Null } - Write-Verbose "Downloading $SCOOP_MAIN_BUCKET_REPO to $scoopMainZipfile" - $downloader.downloadFile($SCOOP_MAIN_BUCKET_REPO, $scoopMainZipfile) - - # Extract files from downloaded zip - Write-InstallInfo 'Extracting...' - # 1. extract scoop - $scoopUnzipTempDir = "$SCOOP_APP_DIR\_tmp" - Write-Verbose "Extracting $scoopZipfile to $scoopUnzipTempDir" - Expand-ZipArchive $scoopZipfile $scoopUnzipTempDir - Copy-Item "$scoopUnzipTempDir\scoop-*\*" $SCOOP_APP_DIR -Recurse -Force - # 2. extract scoop main bucket + Write-Verbose ("Downloading {0} to $scoopMainZipfile" -f $ScoopSources.MainBucketRepoZip) + $downloader.downloadFile($ScoopSources.MainBucketRepoZip, $scoopMainZipfile) + # extract $scoopMainUnzipTempDir = "$SCOOP_MAIN_BUCKET_DIR\_tmp" Write-Verbose "Extracting $scoopMainZipfile to $scoopMainUnzipTempDir" Expand-ZipArchive $scoopMainZipfile $scoopMainUnzipTempDir Copy-Item "$scoopMainUnzipTempDir\Main-*\*" $SCOOP_MAIN_BUCKET_DIR -Recurse -Force - - # Cleanup - Remove-Item $scoopUnzipTempDir -Recurse -Force - Remove-Item $scoopZipfile + # cleanup Remove-Item $scoopMainUnzipTempDir -Recurse -Force Remove-Item $scoopMainZipfile } + # Create the scoop shim Import-ScoopShim # Finially ensure scoop shims is in the PATH @@ -689,20 +749,17 @@ $SCOOP_GLOBAL_DIR = $ScoopGlobalDir, $env:SCOOP_GLOBAL, "$env:ProgramData\scoop" $SCOOP_CACHE_DIR = $ScoopCacheDir, $env:SCOOP_CACHE, "$SCOOP_DIR\cache" | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -First 1 # Scoop shims directory $SCOOP_SHIMS_DIR = "$SCOOP_DIR\shims" +# Scoop buckets directory +$SCOOP_BUCKETS_DIR = "$SCOOP_DIR\buckets" # Scoop itself directory $SCOOP_APP_DIR = "$SCOOP_DIR\apps\scoop\current" # Scoop main bucket directory -$SCOOP_MAIN_BUCKET_DIR = "$SCOOP_DIR\buckets\main" +$SCOOP_MAIN_BUCKET_DIR = "$SCOOP_BUCKETS_DIR\main" # Scoop config file location $SCOOP_CONFIG_HOME = $env:XDG_CONFIG_HOME, "$env:USERPROFILE\.config" | Select-Object -First 1 $SCOOP_CONFIG_FILE = "$SCOOP_CONFIG_HOME\scoop\config.json" -# TODO: Use a specific version of Scoop and the main bucket -$SCOOP_PACKAGE_REPO = 'https://github.com/ScoopInstaller/Scoop/archive/master.zip' -$SCOOP_MAIN_BUCKET_REPO = 'https://github.com/ScoopInstaller/Main/archive/master.zip' - -$SCOOP_PACKAGE_GIT_REPO = 'https://github.com/ScoopInstaller/Scoop.git' -$SCOOP_MAIN_BUCKET_GIT_REPO = 'https://github.com/ScoopInstaller/Main.git' +$ScoopSources = Get-Scoop-Source -ScoopAppRepoZip $ScoopAppRepoZip -ScoopAppRepoGit $ScoopAppRepoGit -ScoopMainBucketRepoZip $ScoopMainBucketRepoZip -ScoopMainBucketRepoGit $ScoopMainBucketRepoGit # Quit if anything goes wrong $oldErrorActionPreference = $ErrorActionPreference diff --git a/test/install.Tests.ps1 b/test/install.Tests.ps1 index 806aa0d..f340325 100644 --- a/test/install.Tests.ps1 +++ b/test/install.Tests.ps1 @@ -40,3 +40,74 @@ Describe 'Test-CommandAvailable' -Tag 'CommandLine' { } } } + +Describe 'Get-Scoop-Source' -Tag 'Scoop' { + Context 'No source parameters provided' { + It 'Returns default source URLs' { + $expectedSource = @{ + AppRepoZip = "https://github.com/ScoopInstaller/Scoop/archive/master.zip" + AppRepoGit = "https://github.com/ScoopInstaller/Scoop.git" + MainBucketRepoZip = "https://github.com/ScoopInstaller/Main/archive/master.zip" + MainBucketRepoGit = "https://github.com/ScoopInstaller/Main.git" + } + $actualSource = Get-Scoop-Source + $actualSourceJson = $actualSource | ConvertTo-Json + $expectedSourceJson = $expectedSource | ConvertTo-Json + $actualSourceJson | Should -Be $expectedSourceJson + } + } + + Context 'Selected source parameters provided' { + It 'Provide all source parameters as arguments' { + $providedSource = @{ + AppRepoZip = "https://example.com/apprepo.zip" + AppRepoGit = "https://example.com/apprepo.git" + MainBucketRepoZip = "https://example.com/mainbucket.zip" + MainBucketRepoGit = "https://example.com/mainbucket.git" + } + $actualSource = Get-Scoop-Source -ScoopAppRepoZip $providedSource.AppRepoZip ` + -ScoopAppRepoGit $providedSource.AppRepoGit ` + -ScoopMainBucketRepoZip $providedSource.MainBucketRepoZip ` + -ScoopMainBucketRepoGit $providedSource.MainBucketRepoGit + $actualSourceJson = $actualSource | ConvertTo-Json + $expectedSourceJson = $providedSource | ConvertTo-Json + $actualSourceJson | Should -Be $expectedSourceJson + } + + It 'Provide app repo zip url as argument' { + $actualSource = Get-Scoop-Source -ScoopAppRepoZip "https://example.com/apprepo.zip" + $actualSourceJson = $actualSource | ConvertTo-Json + $expectedSourceJson = @{ + AppRepoZip = "https://example.com/apprepo.zip" + AppRepoGit = $null + MainBucketRepoZip = $null + MainBucketRepoGit = $null + } | ConvertTo-Json + $actualSourceJson | Should -Be $expectedSourceJson + } + + It 'Provide app repo git url as argument' { + $actualSource = Get-Scoop-Source -ScoopAppRepoGit "https://example.com/apprepo.git" + $actualSourceJson = $actualSource | ConvertTo-Json + $expectedSourceJson = @{ + AppRepoZip = $null + AppRepoGit = "https://example.com/apprepo.git" + MainBucketRepoZip = $null + MainBucketRepoGit = $null + } | ConvertTo-Json + $actualSourceJson | Should -Be $expectedSourceJson + } + + It 'Provide main bucket repo zip url as argument' { + $actualSource = Get-Scoop-Source -ScoopMainBucketRepoZip "https://example.com/mainbucket.zip" + $actualSourceJson = $actualSource | ConvertTo-Json + $expectedSourceJson = @{ + AppRepoZip = "https://github.com/ScoopInstaller/Scoop/archive/master.zip" + AppRepoGit = "https://github.com/ScoopInstaller/Scoop.git" + MainBucketRepoZip = "https://example.com/mainbucket.zip" + MainBucketRepoGit = "https://github.com/ScoopInstaller/Main.git" + } | ConvertTo-Json + $actualSourceJson | Should -Be $expectedSourceJson + } + } +}