diff --git a/bin/checkver.ps1 b/bin/checkver.ps1 index 385050070..9871d435a 100644 --- a/bin/checkver.ps1 +++ b/bin/checkver.ps1 @@ -1,10 +1,22 @@ # checks websites for newer versions using an (optional) regular expression defined in the manifest # use $dir to specify a manifest directory to check from, otherwise ./bucket is used -param($app, $dir) +param( + [String]$app, + [String]$dir, + [Switch]$update = $false +) + +if (!$app -and $update) { + # While developing the feature we only allow specific updates + Write-Host "[ERROR] AUTOUPDATE CAN ONLY BE USED WITH A APP SPECIFIED" -f DarkRed + exit +} . "$psscriptroot\..\lib\core.ps1" . "$psscriptroot\..\lib\manifest.ps1" . "$psscriptroot\..\lib\config.ps1" +. "$psscriptroot\..\lib\buckets.ps1" +. "$psscriptroot\..\lib\autoupdate.ps1" if(!$dir) { $dir = "$psscriptroot\..\bucket" } $dir = resolve-path $dir @@ -79,6 +91,10 @@ while($in_progress -gt 0) { } else { write-host "$ver" -f darkred -nonewline write-host " (scoop version is $expected_ver)" + + if($update -and $json.autoupdate) { + autoupdate $app $json $ver + } } } else { diff --git a/bucket/nodejs.json b/bucket/nodejs.json index bb0df2ccc..d37b5d3ae 100644 --- a/bucket/nodejs.json +++ b/bucket/nodejs.json @@ -1,24 +1,32 @@ -{ - "homepage": "http://nodejs.org", - "version": "7.1.0", - "license": "MIT", - "architecture": { - "64bit": { - "url": "https://nodejs.org/dist/v7.1.0/node-v7.1.0-x64.msi", - "hash": "853936FE0AA946E16BBAB10D1C7E964BBF7A1820D12ADBFD748D7CF9F8059FA3" - }, - "32bit": { - "url": "https://nodejs.org/dist/v7.1.0/node-v7.1.0-x86.msi", - "hash": "5D95A909788239B4ED97C5F79B2D16837EA577A1A68E34E014D0A45DE7F27B1D" - } - }, - "env_add_path": "nodejs", - "post_install": " -# Remove npmrc that makes global modules get installed in AppData\\Roaming\\npm -rm $dir\\nodejs\\node_modules\\npm\\npmrc -npm update -g", - "checkver": { - "url": "https://nodejs.org/en/download/current/", - "re": "Current version: v([\\d.]+)" - } +{ + "homepage": "http://nodejs.org", + "version": "7.2.0", + "license": "MIT", + "architecture": { + "64bit": { + "url": "https://nodejs.org/dist/v7.2.0/node-v7.2.0-x64.msi", + "hash": "728047841ee8ef46c0273b57dd1f7ed0fc97e89c0d970c1be5387bcf2be5eaa8" + }, + "32bit": { + "url": "https://nodejs.org/dist/v7.2.0/node-v7.2.0-x86.msi", + "hash": "3518b031bed17dfe2334981fd4ed3f0c8b71315a42462e6ccd4e949de3e06bc0" + } + }, + "env_add_path": "nodejs", + "post_install": "\r\n# Remove npmrc that makes global modules get installed in AppData\\Roaming\\npm\r\nrm $dir\\nodejs\\node_modules\\npm\\npmrc\r\nnpm update -g", + "checkver": { + "url": "https://nodejs.org/en/download/current/", + "re": "Current version: \u003cstrong\u003ev([\\d.]+)\u003c/strong\u003e" + }, + "autoupdate": { + "url": { + "64bit": "https://nodejs.org/dist/v$version/node-v$version-x64.msi", + "32bit": "https://nodejs.org/dist/v$version/node-v$version-x86.msi" + }, + "hash": { + "mode": "extract", + "url": "https://nodejs.org/dist/v$version/SHASUMS256.txt.asc", + "find": "([a-z0-9]{64})\\s+(?:$basename)" + } + } } diff --git a/lib/autoupdate.ps1 b/lib/autoupdate.ps1 new file mode 100644 index 000000000..9e7615486 --- /dev/null +++ b/lib/autoupdate.ps1 @@ -0,0 +1,94 @@ +<# +TODO + - add a github release autoupdate type + - tests (single arch, without hashes etc.) + - clean up +#> + +function substitute([String] $str, [Hashtable] $params) { + $params.GetEnumerator() | % { + $str = $str.Replace($_.Name, $_.Value); + } + + return $str +} + +function check_url([String] $url) { + $response = Invoke-WebRequest -Uri $url -Method HEAD + if ($response.StatusCode.Equals(200)) { # redirects might be ok + return $true + } + + return $false +} + +function autoupdate([String] $app, $json, [String] $version) +{ + Write-Host -f DarkCyan "Autoupdating $app" + $has_changes = $false + $has_errors = $false + + $json.architecture | Get-Member -MemberType NoteProperty | % { + [Bool]$valid = $true + $architecture = $_.Name + + # create new url + <# + TODO There should be a second option to extract the url from the page + #> + $template = $json.autoupdate.url.$architecture; + $url = substitute $template @{'$version' = $version} + + # check url + if (!(check_url $url)) { + $valid = $false + Write-Host -f DarkRed "URL $url is not valid" + } + + # create hash + <# + TODO implement more hashing types + `extract` Should be able to extract from origin page source (checkver) + `download` Last resort, download the real file and hash it + #> + $hashmode = $json.autoupdate.hash.mode; + if ($hashmode -eq "extract") { + $hashfile_url = substitute $json.autoupdate.hash.url @{'$version' = $version}; + $hashfile = (new-object net.webclient).downloadstring($hashfile_url) + + $basename = fname($url) + $regex = substitute $json.autoupdate.hash.find @{'$basename' = [regex]::Escape($basename)} + + if ($hashfile -match $regex) { + $hash = $matches[1] + } else { + $valid = $false + Write-Error "could no find hash in hashfile" + } + } + + # write changes to the json object + if ($valid) { + $has_changes = $true + $json.version = $version + $json.architecture.$architecture.url = $url + $json.architecture.$architecture.hash = $hash + } else { + $has_errors = $true + Write-Host -f DarkRed "Could not update $app $architecture" + } + } + + if ($has_changes -and !$has_errors) { + # write file + Write-Host -f DarkGreen "Writing updated $app manifest" + + $path = manifest_path $app + <# + TODO improve json formatting + #> + $json | convertto-json | out-file -filepath $path -encoding utf8 + } else { + Write-Host -f DarkGray "No updates for $app" + } +}