Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(install): Add support for ARM64 architecture #5154

Merged
merged 8 commits into from
Sep 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/ISSUE_TEMPLATE/Bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ labels: "bug"

### System details

**Windows version:** [e.g. 7, 8, 10]
**Windows version:** [e.g. 7, 8, 10, 11]

**OS architecture:** [e.g. 32bit, 64bit]
**OS architecture:** [e.g. 32bit, 64bit, arm64]

**PowerShell version:** [output of `"$($PSVersionTable.PSVersion)"`]

Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

### Features

- **install:** Add support for ARM64 architecture ([#5154](https://github.com/ScoopInstaller/Scoop/issues/5154))
- **getopt:** Support option terminator (`--`) ([#5121](https://github.com/ScoopInstaller/Scoop/issues/5121))
- **scoop-(un)hold:** Support `scoop (un)hold scoop` ([#5089](https://github.com/ScoopInstaller/Scoop/issues/5089))
- **scoop-config:** Allow 'hold_update_until' be set manually ([#5100](https://github.com/ScoopInstaller/Scoop/issues/5100))
Expand Down
12 changes: 9 additions & 3 deletions bin/checkhashes.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ foreach ($single in Get-ChildItem $Dir "$App.json") {
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
Expand Down Expand Up @@ -158,16 +160,20 @@ 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)]
}
}

Expand Down
1 change: 1 addition & 0 deletions bin/checkurls.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ foreach ($man in $Queue) {
} else {
script:url $manifest '64bit' | ForEach-Object { $urls += $_ }
script:url $manifest '32bit' | ForEach-Object { $urls += $_ }
script:url $manifest 'arm64' | ForEach-Object { $urls += $_ }
}

$urls | ForEach-Object {
Expand Down
2 changes: 1 addition & 1 deletion lib/autoupdate.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ function Invoke-AutoUpdate {
$hasNote = $true
}
if ($Manifest.autoupdate.architecture) {
'64bit', '32bit' | ForEach-Object {
'64bit', '32bit', 'arm64' | ForEach-Object {
if ($Manifest.autoupdate.architecture.$_.note) {
$note += "`n$_-arch: $($Manifest.autoupdate.architecture.$_.note)"
$hasNote = $true
Expand Down
44 changes: 35 additions & 9 deletions lib/core.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function Get-Encoding($wc) {
}

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:PROCESSOR_ARCHITECTURE -eq 'AMD64'){'Win64; x64; '})$(if($env:PROCESSOR_ARCHITEW6432 -eq 'AMD64'){'WOW64; '})$PSEdition)"
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 Show-DeprecatedWarning {
Expand Down Expand Up @@ -857,15 +857,38 @@ function ensure_in_path($dir, $global) {
}
}

function ensure_architecture($architecture_opt) {
if(!$architecture_opt) {
return default_architecture
function Get-DefaultArchitecture {
$arch = get_config DEFAULT_ARCHITECTURE
$system = if (${env:ProgramFiles(Arm)}) {
rashil2000 marked this conversation as resolved.
Show resolved Hide resolved
'arm64'
} elseif ([System.Environment]::Is64BitOperatingSystem) {
'64bit'
} else {
'32bit'
}
if ($null -eq $arch) {
$arch = $system
} else {
try {
$arch = Format-ArchitectureString $arch
} catch {
warn 'Invalid default architecture configured. Determining default system architecture'
$arch = $system
}
}
$architecture_opt = $architecture_opt.ToString().ToLower()
switch($architecture_opt) {
{ @('64bit', '64', 'x64', 'amd64', 'x86_64', 'x86-64') -contains $_ } { return '64bit' }
{ @('32bit', '32', 'x86', 'i386', '386', 'i686') -contains $_ } { return '32bit' }
default { throw [System.ArgumentException] "Invalid architecture: '$architecture_opt'"}
return $arch
}

function Format-ArchitectureString($Architecture) {
if (!$Architecture) {
return Get-DefaultArchitecture
}
$Architecture = $Architecture.ToString().ToLower()
switch ($Architecture) {
{ @('64bit', '64', 'x64', 'amd64', 'x86_64', 'x86-64') -contains $_ } { return '64bit' }
{ @('32bit', '32', 'x86', 'i386', '386', 'i686') -contains $_ } { return '32bit' }
{ @('arm64', 'arm', 'aarch64') -contains $_ } { return 'arm64' }
default { throw [System.ArgumentException] "Invalid architecture: '$Architecture'" }
}
}

Expand Down Expand Up @@ -1240,5 +1263,8 @@ $globaldir = $env:SCOOP_GLOBAL, (get_config GLOBAL_PATH), "$env:ProgramData\scoo
# Use at your own risk.
$cachedir = $env:SCOOP_CACHE, (get_config CACHE_PATH), "$scoopdir\cache" | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -First 1

# OS information
$WindowsBuild = [System.Environment]::OSVersion.Version.Build
niheaven marked this conversation as resolved.
Show resolved Hide resolved

# Setup proxy globally
setup_proxy
7 changes: 4 additions & 3 deletions lib/install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ function install_app($app, $architecture, $global, $suggested, $use_cache = $tru
$check_hash = $false
}

if(!(supports_architecture $manifest $architecture)) {
write-host -f DarkRed "'$app' doesn't support $architecture architecture!"
$architecture = Get-SupportedArchitecture $manifest $architecture
if ($null -eq $architecture) {
error "'$app' doesn't support current architecture!"
return
}

Expand Down Expand Up @@ -1046,7 +1047,7 @@ function Invoke-HookScript {
[ValidateNotNullOrEmpty()]
[PSCustomObject] $Manifest,
[Parameter(Mandatory = $true)]
[ValidateSet('32bit', '64bit')]
[ValidateSet('32bit', '64bit', 'arm64')]
[String] $Arch
)

Expand Down
35 changes: 16 additions & 19 deletions lib/manifest.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -102,23 +102,6 @@ function install_info($app, $version, $global) {
parse_json $path
}

function default_architecture {
$arch = get_config DEFAULT_ARCHITECTURE
$system = if ([Environment]::Is64BitOperatingSystem) { '64bit' } else { '32bit' }
if ($null -eq $arch) {
$arch = $system
} else {
try {
$arch = ensure_architecture $arch
} catch {
warn 'Invalid default architecture configured. Determining default system architecture'
$arch = $system
}
}

return $arch
}

function arch_specific($prop, $manifest, $architecture) {
if ($manifest.architecture) {
$val = $manifest.architecture.$architecture.$prop
Expand All @@ -128,8 +111,22 @@ function arch_specific($prop, $manifest, $architecture) {
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) {
Expand Down
2 changes: 1 addition & 1 deletion libexec/scoop-config.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
# 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
# default_architecture: 64bit|32bit|arm64
# Allow to configure preferred architecture for application installation.
# If not specified, architecture is determined be system.
#
Expand Down
6 changes: 3 additions & 3 deletions libexec/scoop-depends.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@

. "$PSScriptRoot\..\lib\getopt.ps1"
. "$PSScriptRoot\..\lib\depends.ps1" # 'Get-Dependency'
. "$PSScriptRoot\..\lib\manifest.ps1" # 'default_architecture'
. "$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: $_"
}
Expand Down
19 changes: 10 additions & 9 deletions libexec/scoop-download.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,25 @@
# scoop download path\to\app.json
#
# Options:
# -f, --force Force download (overwrite cache)
# -h, --no-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> Use the specified architecture, if the app supports it
# -f, --force Force download (overwrite cache)
# -h, --no-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" # 'default_architecture' 'generate_user_manifest' 'Get-Manifest'
. "$PSScriptRoot\..\lib\manifest.ps1" # 'generate_user_manifest' 'Get-Manifest'
. "$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 }

$check_hash = !($opt.h -or $opt.'no-hash-check')
$use_cache = !($opt.f -or $opt.force)
$architecture = default_architecture
$architecture = Get-DefaultArchitecture
try {
$architecture = ensure_architecture ($opt.a + $opt.arch)
$architecture = Format-ArchitectureString ($opt.a + $opt.arch)
} catch {
abort "ERROR: $_"
}
Expand Down Expand Up @@ -89,8 +89,9 @@ foreach ($curr_app in $apps) {
$curr_check_hash = $false
}

if(!(supports_architecture $manifest $architecture)) {
error "'$app' doesn't support $architecture architecture!"
$architecture = Get-SupportedArchitecture $manifest $architecture
if ($null -eq $architecture) {
error "'$app' doesn't support current architecture!"
continue
}

Expand Down
8 changes: 4 additions & 4 deletions libexec/scoop-import.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ param(

$import = $null
$bucket_names = @()
$def_arch = default_architecture
$def_arch = Get-DefaultArchitecture

if (Test-Path $scoopfile) {
$import = parse_json $scoopfile
Expand All @@ -40,12 +40,12 @@ foreach ($item in $import.apps) {
} else {
''
}
$arch = if ('64bit' -in $info -and '32bit' -eq $def_arch) {
$arch = if ('64bit' -in $info) {
' --arch 64bit'
} elseif ('32bit' -in $info -and '64bit' -eq $def_arch) {
} elseif ('32bit' -in $info) {
' --arch 32bit'
} else {
''
' --arch arm64'
}

$app = if ($item.Source -in $bucket_names) {
Expand Down
2 changes: 1 addition & 1 deletion libexec/scoop-info.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ if ($status.installed) {
if ($verbose) {
# Get download size if app not installed
$totalPackage = 0
foreach ($url in @(url $manifest (default_architecture))) {
foreach ($url in @(url $manifest (Get-DefaultArchitecture))) {
try {
if (Test-Path (fullpath (cache_path $app $manifest.version $url))) {
$cached = " (latest version is cached)"
Expand Down
18 changes: 9 additions & 9 deletions libexec/scoop-install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@
# scoop install \path\to\app.json
#
# Options:
# -g, --global Install the app globally
# -i, --independent Don't install dependencies automatically
# -k, --no-cache Don't use the download cache
# -u, --no-update-scoop Don't update Scoop before installing if it's outdated
# -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
# -u, --no-update-scoop Don't update Scoop before installing if it's outdated
# -s, --skip Skip hash validation (use with caution!)
# -a, --arch <32bit|64bit|arm64> Use the specified architecture, if the app supports it

. "$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' 'Get-Manifest' 'Select-CurrentVersion' (indirectly)
. "$PSScriptRoot\..\lib\manifest.ps1" # 'generate_user_manifest' 'Get-Manifest' 'Select-CurrentVersion' (indirectly)
. "$PSScriptRoot\..\lib\install.ps1"
. "$PSScriptRoot\..\lib\decompress.ps1"
. "$PSScriptRoot\..\lib\shortcuts.ps1"
Expand All @@ -39,9 +39,9 @@ $global = $opt.g -or $opt.global
$check_hash = !($opt.s -or $opt.skip)
$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: $_"
}
Expand Down
2 changes: 1 addition & 1 deletion libexec/scoop-list.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ param($query)
. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
. "$PSScriptRoot\..\lib\manifest.ps1" # 'parse_json' 'Select-CurrentVersion' (indirectly)

$def_arch = default_architecture
$def_arch = Get-DefaultArchitecture
if (-not (Get-FormatData ScoopApps)) {
Update-FormatData "$PSScriptRoot\..\supporting\formats\ScoopTypes.Format.ps1xml"
}
Expand Down
2 changes: 1 addition & 1 deletion libexec/scoop-update.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ function update($app, $global, $quiet = $false, $independent, $suggested, $use_c
$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'
Expand Down
2 changes: 1 addition & 1 deletion libexec/scoop-virustotal.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
$opt, $apps, $err = getopt $args 'asnup' @('all', 'scan', 'no-depends', 'no-update-scoop', 'passthru')
if ($err) { "scoop virustotal: $err"; exit 1 }
if (!$apps) { my_usage; exit 1 }
$architecture = ensure_architecture
$architecture = Format-ArchitectureString

if (is_scoop_outdated) {
if ($opt.u -or $opt.'no-update-scoop') {
Expand Down
Loading