Skip to content

Commit

Permalink
Option to skip hash validation and error message improvements (#2260)
Browse files Browse the repository at this point in the history
* Add show_app() function for displaying `app/bucket@version`

* Add option to skip hash check on install/update

Allows users to install an app when the manifest provides an outdated hash

* Show filename instead of robocopy output when moving fails

* Add new_issue_msg() for nicer error messages (with link bucket repo)

- returns a message with a link to the buckets GitHub repository
- clicking on the link opens a new issues with a predefined title

* Use new_issue_msg() for errors while moving files

- this removes the unreadable robocopy error dumps

* Use new_issue_msg() error handling for check_hash()

* Show robocopy exit code
  • Loading branch information
r15ch13 authored Jun 14, 2018
1 parent 16609b7 commit f8f9b75
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 35 deletions.
22 changes: 22 additions & 0 deletions lib/buckets.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,25 @@ function find_manifest($app, $bucket) {
if($manifest) { return $manifest, $bucket }
}
}

function new_issue_msg($app, $bucket, $title, $body) {
$app, $manifest, $bucket, $url = locate $app $bucket
$url = known_bucket_repo $bucket
if($manifest -and $null -eq $url -and $null -eq $bucket) {
$url = 'https://github.com/lukesampson/scoop'
}
if(!$url) {
return "Please contact the bucket maintainer!"
}

$title = [System.Web.HttpUtility]::UrlEncode("$app@$($manifest.version): $title")
$body = [System.Web.HttpUtility]::UrlEncode($body)
$url = $url -replace '^(.*).git$','$1'
$url = "$url/issues/new?title=$title"
if($body) {
$url += "&body=$body"
}

$msg = "`nPlease create a new issue by using the following link and paste your console output:"
return "$msg`n$url"
}
12 changes: 11 additions & 1 deletion lib/core.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ function movedir($from, $to) {

$out = robocopy "$from" "$to" /e /move
if($lastexitcode -ge 8) {
throw "Error moving directory: `n$out"
throw "Could not find '$(fname $from)'! (error $lastexitcode)"
}
}

Expand Down Expand Up @@ -501,6 +501,16 @@ function parse_app([string] $app) {
return $app, $null, $null
}

function show_app($app, $bucket, $version) {
if($bucket) {
$app = "$bucket/$app"
}
if($version) {
$app = "$app@$version"
}
return $app
}

function last_scoop_update() {
$last_update = (scoop config lastupdate)
if(!$last_update) {
Expand Down
47 changes: 33 additions & 14 deletions lib/install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ function nightly_version($date, $quiet = $false) {
"nightly-$date_str"
}

function install_app($app, $architecture, $global, $suggested, $use_cache = $true) {
function install_app($app, $architecture, $global, $suggested, $use_cache = $true, $check_hash = $true) {
$app, $bucket, $null = parse_app $app
$app, $manifest, $bucket, $url = locate $app $bucket
$check_hash = $true

if(!$manifest) {
abort "Couldn't find manifest for '$app'$(if($url) { " at the URL $url" })."
Expand Down Expand Up @@ -41,7 +40,7 @@ function install_app($app, $architecture, $global, $suggested, $use_cache = $tru
$original_dir = $dir # keep reference to real (not linked) directory
$persist_dir = persistdir $app $global

$fname = dl_urls $app $version $manifest $architecture $dir $use_cache $check_hash
$fname = dl_urls $app $version $manifest $bucket $architecture $dir $use_cache $check_hash
unpack_inno $fname $manifest $dir
pre_install $manifest $architecture
run_installer $fname $manifest $architecture $dir $global
Expand Down Expand Up @@ -272,7 +271,7 @@ function dl_progress($read, $total, $url) {
[console]::SetCursorPosition($left, $top)
}

function dl_urls($app, $version, $manifest, $architecture, $dir, $use_cache = $true, $check_hash = $true) {
function dl_urls($app, $version, $manifest, $bucket, $architecture, $dir, $use_cache = $true, $check_hash = $true) {
# we only want to show this warning once
if(!$use_cache) { warn "Cache is being ignored." }

Expand Down Expand Up @@ -312,12 +311,16 @@ function dl_urls($app, $version, $manifest, $architecture, $dir, $use_cache = $t
$fname = $data.$url.fname

if($check_hash) {
$ok, $err = check_hash "$dir\$fname" $url $manifest $architecture
$manifest_hash = hash_for_url $manifest $url $arch
$ok, $err = check_hash "$dir\$fname" $manifest_hash $(show_app $app $bucket)
if(!$ok) {
# rm cached
error $err
$cached = cache_path $app $version $url
if(test-path $cached) { Remove-Item -force $cached }
abort $err
if(test-path $cached) {
# rm cached file
Remove-Item -force $cached
}
abort $(new_issue_msg $app $bucket "hash check failed")
}
}

Expand Down Expand Up @@ -360,7 +363,13 @@ function dl_urls($app, $version, $manifest, $architecture, $dir, $use_cache = $t
}
# fails if zip contains long paths (e.g. atom.json)
#cp "$dir\_tmp\$extract_dir\*" "$dir\$extract_to" -r -force -ea stop
movedir "$dir\_tmp\$extract_dir" "$dir\$extract_to"
try {
movedir "$dir\_tmp\$extract_dir" "$dir\$extract_to"
}
catch {
error $_
abort $(new_issue_msg $app $bucket "extract_dir error")
}

if(test-path "$dir\_tmp") { # might have been moved by movedir
try {
Expand Down Expand Up @@ -430,11 +439,10 @@ function hash_for_url($manifest, $url, $arch) {
}

# returns (ok, err)
function check_hash($file, $url, $manifest, $arch) {
$hash = hash_for_url $manifest $url $arch
function check_hash($file, $hash, $app_name) {
if(!$hash) {
warn "Warning: No hash in manifest. SHA256 is:`n $(compute_hash (fullpath $file) 'sha256')"
return $true
return $true, $null
}

write-host "Checking hash of $(url_remote_filename $url)... " -nonewline
Expand All @@ -450,11 +458,21 @@ function check_hash($file, $url, $manifest, $arch) {

$actual = compute_hash (fullpath $file) $type

$expected = $expected.ToLower()
$actual = $actual.ToLower()

if($actual -ne $expected) {
return $false, "Hash check failed for '$url'.`nExpected:`n $($expected)`nActual:`n $($actual)"
$msg = "Hash check failed!`n"
$msg += "App: $app_name`n"
$msg += "URL: $url`n"
if($expected -or $actual) {
$msg += "Expected: $expected`n"
$msg += "Actual: $actual"
}
return $false, $msg
}
write-host "ok."
return $true
return $true, $null
}

function compute_hash($file, $algname) {
Expand All @@ -473,6 +491,7 @@ function compute_hash($file, $algname) {
if($fs) { $fs.dispose() }
if($alg) { $alg.dispose() }
}
return ''
}

function cmd_available($cmd) {
Expand Down
6 changes: 1 addition & 5 deletions libexec/scoop-info.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,7 @@ $status = app_status $app $global
$manifest, $bucket = find_manifest $app $bucket

if (!$manifest) {
if ($bucket) {
abort "Could not find manifest for '$bucket/$app'."
} else {
abort "Could not find manifest for '$app'."
}
abort "Could not find manifest for '$(show_app $app $bucket)'."
}

$install = install_info $app $status.version $global
Expand Down
10 changes: 6 additions & 4 deletions libexec/scoop-install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
# When installing from your computer, you can leave the .json extension off if you like.
#
# Options:
# -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
# -g, --global Install the app globally
# -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"
Expand Down Expand Up @@ -46,10 +47,11 @@ function is_installed($app, $global) {
return $false
}

$opt, $apps, $err = getopt $args 'gika:' 'global', 'independent', 'no-cache', 'arch='
$opt, $apps, $err = getopt $args 'gfiksa:' 'global', 'force', 'independent', 'no-cache', 'skip', 'arch='
if($err) { "scoop install: $err"; exit 1 }

$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
Expand Down Expand Up @@ -117,7 +119,7 @@ $skip | Where-Object { $explicit_apps -contains $_} | ForEach-Object {
}

$suggested = @{};
$apps | ForEach-Object { install_app $_ $architecture $global $suggested $use_cache }
$apps | ForEach-Object { install_app $_ $architecture $global $suggested $use_cache $check_hash }

show_suggestions $suggested

Expand Down
24 changes: 13 additions & 11 deletions libexec/scoop-update.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
# You can use '*' in place of <app> to update all apps.
#
# Options:
# --global, -g Update a globally installed app
# --force, -f Force update even when there isn't a newer version
# --no-cache, -k Don't use the download cache
# --independent, -i Don't install dependencies automatically
# --quiet, -q Hide extraneous messages
# -f, --force Force update even when there isn't a newer version
# -g, --global Update a globally installed app
# -i, --independent Don't install dependencies automatically
# -k, --no-cache Don't use the download cache
# -s, --skip Skip hash validation (use with caution!)
# -q, --quiet Hide extraneous messages

. "$psscriptroot\..\lib\core.ps1"
. "$psscriptroot\..\lib\shortcuts.ps1"
. "$psscriptroot\..\lib\psmodules.ps1"
Expand All @@ -26,10 +28,11 @@

reset_aliases

$opt, $apps, $err = getopt $args 'gfkqi' 'global','force', 'no-cache', 'quiet', 'independent'
$opt, $apps, $err = getopt $args 'gfiksq:' 'global', 'force', 'independent', 'no-cache', 'skip', 'quiet'
if($err) { "scoop update: $err"; exit 1 }
$global = $opt.g -or $opt.global
$force = $opt.f -or $opt.force
$check_hash = !($opt.s -or $opt.skip)
$use_cache = !($opt.k -or $opt.'no-cache')
$quiet = $opt.q -or $opt.quiet
$independent = $opt.i -or $opt.independent
Expand Down Expand Up @@ -104,11 +107,10 @@ function update_scoop() {
success 'Scoop was updated successfully!'
}

function update($app, $global, $quiet = $false, $independent, $suggested, $use_cache = $true) {
function update($app, $global, $quiet = $false, $independent, $suggested, $use_cache = $true, $check_hash = $true) {
$old_version = current_version $app $global
$old_manifest = installed_manifest $app $old_version $global
$install = install_info $app $old_version $global
$check_hash = $true

# re-use architecture, bucket and url from first install
$architecture = ensure_architecture $install.architecture
Expand All @@ -118,7 +120,7 @@ function update($app, $global, $quiet = $false, $independent, $suggested, $use_c
if(!$independent) {
# check dependencies
$deps = @(deps $app $architecture) | Where-Object { !(installed $_) }
$deps | ForEach-Object { install_app $_ $architecture $global $suggested $use_cache }
$deps | ForEach-Object { install_app $_ $architecture $global $suggested $use_cache $check_hash }
}

$version = latest_version $app $bucket $url
Expand Down Expand Up @@ -161,7 +163,7 @@ function update($app, $global, $quiet = $false, $independent, $suggested, $use_c
# add bucket name it was installed from
$app = "$bucket/$app"
}
install_app $app $architecture $global $suggested $use_cache
install_app $app $architecture $global $suggested $use_cache $check_hash
}

if(!$apps) {
Expand Down Expand Up @@ -210,7 +212,7 @@ if(!$apps) {

$suggested = @{};
# # $outdated is a list of ($app, $global) tuples
$outdated | ForEach-Object { update @_ $quiet $independent $suggested $use_cache }
$outdated | ForEach-Object { update @_ $quiet $independent $suggested $use_cache $check_hash }
}

exit 0

0 comments on commit f8f9b75

Please sign in to comment.