Skip to content

Commit

Permalink
feat: Adopt Resolve-ManifestObject for installation (#237)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ash258 committed Dec 8, 2021
1 parent f2486a3 commit b001941
Show file tree
Hide file tree
Showing 12 changed files with 383 additions and 156 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

## [0.6.5](https://github.com/Ash258/Scoop-Core/milestone/5)

🎉🎉 YAML typed manifest and archived manifest installation support 🎉🎉

- Adopt new resolve function for parameter passing
- **scoop-install**
- **scoop-depends**
- Refactor dependencies handling
- `scoop-depends`: Add `s`, `--skip-installed` parameter
- By default all dependencies are shown (including installed)
Expand Down
55 changes: 55 additions & 0 deletions lib/Applications.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -250,3 +250,58 @@ function Confirm-InstallationStatus {

return , $installed
}

function Test-ResolvedObjectIsInstalled {
[CmdletBinding()]
[OutputType([System.Boolean])]
param($ResolvedObject, [Switch] $Global)

process {
$app = $ResolvedObject.ApplicationName
$gf = if ($Global) { ' --global' } else { '' }

if (installed $app $Global) {
$installedVersion = Select-CurrentVersion -AppName $app -Global:$Global
$info = install_info $app $installedVersion $Global

if ($info.hold -and ($info.hold -eq $true)) {
Write-UserMessage -Message @(
"'$app' is being held."
"Use 'scoop unhold$gf $app' to unhold the application first and then try again."
) -Warning

return $true
}

# Test if explicitly provided version is installed
if ($ResolvedObject.RequestedVersion) {
$all = @(Get-InstalledVersion -AppName $app -Global:$Global)

$verdict = $all -contains $ResolvedObject.RequestedVersion
if ($verdict) {
Write-UserMessage -Message "'$app' ($($ResolvedObject.RequestedVersion)) is already installed." -Warning
}

return $verdict
}

if (!$info) {
Write-UserMessage -Err -Message @(
"It looks like a previous installation of '$app' failed."
"Run 'scoop uninstall$gf $app' before retrying the install."
)

return $true
}

Write-UserMessage -Message @(
"'$app' ($installedVersion) is already installed.",
"Use 'scoop update$gc $app' to install a new version."
) -Warning

return $true
}

return $false
}
}
4 changes: 2 additions & 2 deletions lib/Dependencies.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ function Resolve-MultipleApplicationDependency {
foreach ($dep in $deps.Deps) {
# TODOOOO: Better handle the different versions
if ($toInstall.ApplicationName -notcontains $dep.ApplicationName) {
$dep | Add-Member -MemberType 'NoteProperty' -Name 'Dependency' -Value $s.ApplicationName
$dep.Dependency = $s.ApplicationName
if ($IncludeInstalledDeps -or !(installed $dep.ApplicationName)) {
$toInstall += $dep
}
Expand All @@ -270,7 +270,7 @@ function Resolve-MultipleApplicationDependency {

# TODOOOO: Better handle the different versions
if ($toInstall.ApplicationName -notcontains $s.ApplicationName) {
$s | Add-Member -MemberType 'NoteProperty' -Name 'Dependency' -Value $false
$s.Dependency = $false

if ($IncludeInstalledApps -or !(installed $s.ApplicationName)) {
$toInstall += $s
Expand Down
160 changes: 160 additions & 0 deletions lib/Installation.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
@(
@('core', 'Test-ScoopDebugEnabled'),
@('Versions', 'Clear-InstalledVersion'),
@('manifest', 'Resolve-ManifestInformation')
) | ForEach-Object {
if (!(Get-Command $_[1] -ErrorAction 'Ignore')) {
Write-Verbose "Import of lib '$($_[0])' initiated from '$PSCommandPath'"
. (Join-Path $PSScriptRoot "$($_[0]).ps1")
}
}

function Install-ScoopApplication {
[CmdletBinding()]
param($ResolvedObject, [String] $Architecture, [Switch] $Global, $Suggested, [Switch] $UseCache, [Switch] $CheckHash)

process {
$appName = $ResolvedObject.ApplicationName
$manifest = $ResolvedObject.ManifestObject
$version = $ResolvedObject.ManifestObject.version

if ($version -match '[^\w\.\-\+_]') {
throw [ScoopException] "Invalid manifest|-Manifest version has unsupported character '$($matches[0])'." # TerminatingError thrown
}

if ($version -eq 'nightly') {
$version = nightly_version
$CheckHash = $false
}

if (!(supports_architecture $manifest $Architecture)) {
throw [ScoopException] "'$appName' does not support $Architecture architecture" # TerminatingError thrown
}

Deny-ArmInstallation -Manifest $manifest -Architecture $architecture

$buc = if ($ResolvedObject.Bucket) { " [$($ResolvedObject.Bucket)]" } else { '' }
$dep = if ($ResolvedObject.Dependency -ne $false) { " {Dependency for $($ResolvedObject.Dependency)}" } else { '' }

Write-UserMessage -Message "Installing '$appName' ($version) [$Architecture]$buc$dep" -Success

# Show license
$license = $manifest.license
if ($license -and ($license -ne 'Unknown')) {
$id = if ($license.identifier) { $license.identifier } else { $license }
# Remove [|,]...
if ($id -like '*...') { $id = $id -replace '[|,]\.{3}' }
$id = $id -split ','
$id = $id -split '\|'

if ($license.url) {
$s = if ($id.Count -eq 1) { $id } else { $id -join ', ' }
$toShow = $s + ' (' + $license.url + ')'
} else {
$line = if ($id.Count -gt 1) { "`r`n " } else { '' }
$id | ForEach-Object {
$toShow += "$line$_ (https://spdx.org/licenses/$_.html)"
}
}

Write-UserMessage -Message "By installing you accept following $(pluralize $id.Count 'license' 'licenses'): $toShow" -Warn
}

# Variables
$dir = versiondir $appName $version $Global | Confirm-DirectoryExistence
$current_dir = current_dir $dir # Save some lines in manifests
$original_dir = $dir # Keep reference to real (not linked) directory
$persist_dir = persistdir $appName $Global

# Suggest installing arm64
if ((Test-IsArmArchitecture) -and ($Architecture -ne 'arm64') -and ($manifest.'architecture'.'arm64')) {
Write-UserMessage -Message 'Manifest explicitly supports arm64. Consider to install using arm64 version to achieve best compatibility/performance.' -Success
}

# Download and extraction
Invoke-ManifestScript -Manifest $manifest -ScriptName 'pre_download' -Architecture $Architecture
# TODOOOOOOOOOO: Extract to better function
$fname = dl_urls $appName $version $manifest $ResolvedObject.Bucket $Architecture $dir $UseCache $CheckHash

# Installers
Invoke-ManifestScript -Manifest $manifest -ScriptName 'pre_install' -Architecture $Architecture
run_installer $fname $manifest $Architecture $dir $Global
ensure_install_dir_not_in_path $dir $Global
$dir = link_current $dir
create_shims $manifest $dir $Global $Architecture
create_startmenu_shortcuts $manifest $dir $Global $Architecture
install_psmodule $manifest $dir $Global
if ($Global) { ensure_scoop_in_path $Global } # Can assume local scoop is in path
env_add_path $manifest $dir $Global $Architecture
env_set $manifest $dir $Global $Architecture

# Persist data
persist_data $manifest $original_dir $persist_dir
#TODOOOO: Eliminate
persist_permission $manifest $Global

Invoke-ManifestScript -Manifest $manifest -ScriptName 'post_install' -Architecture $Architecture

# Save helper files for uninstall and other commands
Set-ScoopManifestHelperFile -ResolvedObject $ResolvedObject -Directory $dir
Set-ScoopInfoHelperFile -ResolvedObject $ResolvedObject -Architecture $Architecture -Directory $dir

if ($manifest.suggest) { $Suggested[$appName] = $manifest.suggest }

Write-UserMessage -Message "'$appName' ($version) was installed successfully!" -Success

# Additional info to user
show_notes $manifest $dir $original_dir $persist_dir

if ($manifest.changelog) {
$changelog = $manifest.changelog
if (!$changelog.StartsWith('http')) { $changelog = friendly_path (Join-Path $dir $changelog) }

Write-UserMessage -Message "New changes in this release: '$changelog'" -Success
}
}
}

function Set-ScoopManifestHelperFile {
[CmdletBinding()]
param($ResolvedObject, $Directory)

process {
$p = $ResolvedObject.LocalPath
$name = 'scoop-manifest'

if ($p -and (Test-Path -LiteralPath $p -PathType 'Leaf')) {
$name = "$name$($p.Extension)"
$t = Join-Path $Directory $name
Copy-Item -LiteralPath $ResolvedObject.LocalPath -Destination $t
} else {
Write-UserMessage -Message 'Cannot copy local manifest. Creating from object' -Info

ConvertTo-Manifest -File (Join-Path $Directory "$name.yml") -Manifest $ResolvedObject.ManifestObject
}
}
}

function Set-ScoopInfoHelperFile {
[CmdletBinding()]
param($ResolvedObject, $Architecture, $Directory)

process {
$dep = if ($ResolvedObject.Dependency -ne $false) { $ResolvedObject.Dependency } else { $null }
$url = if ($ResolvedObject.Url) { $ResolvedObject.Url } else { $ResolvedObject.LocalPath }

if ($ResolvedObject.Bucket) { $url = $null }

$info = @{
'architecture' = $Architecture
'bucket' = $ResolvedObject.Bucket
'url' = if ($url) { "$url" } else { $null } # Force string in case of FileInfo
'dependency_for' = $dep
}

$nulls = $info.Keys | Where-Object { $null -eq $info[$_] }
$nulls | ForEach-Object { $info.Remove($_) } # strip null-valued

$info | ConvertToPrettyJson | Out-UTF8File -Path (Join-Path $Directory 'scoop-install.json')
}
}
71 changes: 47 additions & 24 deletions lib/Update.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
@('commands', 'Invoke-ScoopCommand'),
@('Git', 'Invoke-GitCmd'),
@('install', 'install_app'),
@('Dependencies', 'Resolve-DependsProperty'),
@('Installation', 'Install-ScoopApp'),
@('manifest', 'Resolve-ManifestInformation')
) | ForEach-Object {
if (!([bool] (Get-Command $_[1] -ErrorAction 'Ignore'))) {
Expand Down Expand Up @@ -275,29 +277,55 @@ function Update-App {
$install = install_info $App $oldVersion $Global

# Old variables
$check_hash = !$SkipHashCheck
$use_cache = !$SkipCache
$old_version = $oldVersion
$old_manifest = $oldManifest
$checkHash = !$SkipHashCheck
$useCache = !$SkipCache
$oldVersion = $oldVersion
$oldManifest = $oldManifest
$toInstall = @{
'Failed' = @()
'Resolved' = @()
}

# Re-use architecture, bucket and url from first install
$architecture = ensure_architecture $install.architecture
$url = $install.url
$bucket = $install.bucket
if ($null -eq $bucket) { $bucket = 'main' }

$a = if ($url) { $url } else { "$bucket/$App" }

# Check dependencies
if (!$Independent) {
$man = if ($url) { $url } else { $app }
# TODO: Adopt the new dependencies refactor
$deps = @(deps $man $architecture) | Where-Object { !(installed $_) }
$deps | ForEach-Object { install_app $_ $architecture $Global $Suggested $SkipCache (!$SkipHashCheck) }
if ($Independent) {
$ar = $null
try {
$ar = Resolve-ManifestInformation -ApplicationQuery $a
} catch {
throw [ScoopException] $_.Exception.Message # TerminatingError thrown
}
$toInstall.Resolved += $ar
} else {
$toInstall = Resolve-MultipleApplicationDependency -Applications @($a) -Architecture $architecture -IncludeInstalledApps
}

if ($toInstall.Failed.Count -gt 0) {
throw [ScoopException] 'Cannot resolve all dependencies' # TerminatingError thrown
}

$_deps = @($toInstall.Resolved | Where-Object -Property 'Dependency' -NE -Value $false)
$applicationToUpdate = @($toInstall.Resolved | Where-Object -Property 'Dependency' -EQ -Value $false) | Select-Object -First 1

# Install dependencies
foreach ($d in $_deps) {
Install-ScoopApplication -ResolvedObject $d -Architecture $architecture -Global:$Global -Suggested:$Suggested `
-UseCache:$useCache -CheckHash:$checkHash
}

$version = Get-LatestVersion -AppName $App -Bucket $bucket -Uri $url
$manifest = $applicationToUpdate.ManifestObject
$version = $manifest.version

if ($version -eq 'nightly') {
$version = nightly_version (Get-Date) $Quiet
$SkipHashCheck = $true
$checkHash = $false
}

# TODO: Could this ever happen?
Expand All @@ -311,16 +339,14 @@ function Update-App {
throw [ScoopException] "No manifest available for '$App'" # TerminatingError thrown
}

$manifest = manifest $App $bucket $url

# Do not update if the new manifest does not support the installed architecture
if (!(supports_architecture $manifest $architecture)) {
throw [ScoopException] "Manifest no longer supports specific architecture '$architecture'" # TerminatingError thrown
}

Deny-ArmInstallation -Manifest $manifest -Architecture $architecture

Write-UserMessage -Message "Updating '$App' ($oldVersion -> $version) [$architecture]"
Write-UserMessage -Message "Updating '$App' ($oldVersion -> $version) [$architecture]" -Success

#region Workaround of #2220
# Remove and replace whole region after proper implementation
Expand All @@ -329,14 +355,14 @@ function Update-App {
Invoke-ManifestScript -Manifest $manifest -ScriptName 'pre_download' -Architecture $architecture

if (Test-Aria2Enabled) {
dl_with_cache_aria2 $App $version $manifest $architecture $SCOOP_CACHE_DIRECTORY $manifest.cookie $true (!$SkipHashCHeck)
dl_with_cache_aria2 $App $version $manifest $architecture $SCOOP_CACHE_DIRECTORY $manifest.cookie $true $checkHash
} else {
$urls = url $manifest $architecture

foreach ($url in $urls) {
dl_with_cache $App $version $url $null $manifest.cookie $true

if (!$SkipHashCheck) {
if ($checkHash) {
$manifest_hash = hash_for_url $manifest $url $architecture
$source = cache_path $App $version $url
$ok, $err = check_hash $source $manifest_hash (show_app $App $bucket)
Expand All @@ -354,7 +380,7 @@ function Update-App {
}

# There is no need to check hash again while installing
$SkipHashCheck = $true
$checkHash = $false
#endregion Workaround of #2220

$result = Uninstall-ScoopApplication -App $App -Global:$Global
Expand All @@ -365,18 +391,15 @@ function Update-App {
$dir = versiondir $App $oldVersion $Global

$old = Join-Path $dir "..\_$version.old"
if (Test-Path $old -PathType 'Container') {
if (Test-Path -LiteralPath $old -PathType 'Container') {
$i = 1
while (Test-Path "$old($i)") { ++$i }
while (Test-Path -LiteralPath "$old($i)" -PathType 'Container') { ++$i }
Move-Item $dir "$old($i)"
} else {
Move-Item $dir $old
}
}

# TODO: Adopt Resolve-ManifestInformation???
$toUpdate = if ($install.url) { $install.url } else { "$bucket/$App" }

# Error catching should be handled on upper scope
install_app $toUpdate $architecture $Global $Suggested (!$SkipCache) (!$SkipHashCheck)
Install-ScoopApplication -ResolvedObject $applicationToUpdate -Architecture $architecture -Global:$Global -Suggested:$Suggested `
-UseCache:$useCache -CheckHash:$checkHash
}
Loading

0 comments on commit b001941

Please sign in to comment.