From 681cccd4d5f2adb81470ee99ede927a6de896c3b Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Sun, 28 Jun 2020 01:26:32 -0600 Subject: [PATCH] switch from bat to ps1 --- README.md | 29 +++++++++++++++++++++++ _webi/bootstrap.ps1 | 42 ++++++++++++++++++++++++++++++++ _webi/packages.js | 4 ++-- _webi/releases.js | 58 +++++++++++++++++++++++++++++++++++++++++++++ _webi/template.ps1 | 37 +++++++++++++++++++++++++++++ _webi/test.js | 14 +++++------ _webi/ua-detect.js | 2 +- _webi/webi.bat | 2 +- _webi/webi.ps1 | 51 +++++++++++++++++++++++++++++++++++++++ _webi/webi.ps1.bat | 1 + node/install.ps1 | 47 ++++++++++++++++++++++++++++++++++++ node/releases.js | 4 ++-- pathman/install.ps1 | 1 + 13 files changed, 279 insertions(+), 13 deletions(-) create mode 100644 _webi/bootstrap.ps1 create mode 100644 _webi/template.ps1 create mode 100644 _webi/webi.ps1 create mode 100644 _webi/webi.ps1.bat create mode 100644 node/install.ps1 create mode 100644 pathman/install.ps1 diff --git a/README.md b/README.md index f83b776..6d9a43b 100644 --- a/README.md +++ b/README.md @@ -252,3 +252,32 @@ webi_post_install # Runs `webi_add_path $pkg_dst_bin` - [ ] Support arbitrary git urls (i.e. `@github.com/node/node`) - (maybe `ghi node/node` for github specifically) - [ ] Support git as an archive format + +# Windows Notes + +```bat +set WEBI_HOST=https://webinstall.dev +``` + +Windows 10 has curl too!? + +```bat +curl.exe -sL -A "MS" https://webinstall.dev/node | powershell +``` + +And it's easy enough to ignore the execution policy + +```bat +powershell -ExecutionPolicy Bypass install.ps1 +``` + +And if we want something that looks as complicated as we expect Windows to be, +historically, we have options: + +```bat +powershell "Invoke-Expression ( Invoke-WebRequest -UseBasicParsing https://webinstall.dev/node ).Contents" +``` + +```bat +powershell ( Invoke-WebRequest -UseBasicParsing https://webinstall.dev/node ).Contents | powershell +``` diff --git a/_webi/bootstrap.ps1 b/_webi/bootstrap.ps1 new file mode 100644 index 0000000..c01089b --- /dev/null +++ b/_webi/bootstrap.ps1 @@ -0,0 +1,42 @@ +# If a command returns an error, halt the script. +$ErrorActionPreference = 'Stop' + +# Ignore progress events from cmdlets so Invoke-WebRequest is not painfully slow +$ProgressPreference = 'SilentlyContinue' + +# Switch to userprofile +pushd $Env:USERPROFILE + +# Make paths if needed +if (!(Test-Path -Path .local\bin)) +{ + New-Item -Path .local\bin -ItemType Directory +} + +# {{ baseurl }} +# {{ version }} + +# Enter path +pushd .local\bin + +# TODO SetStrictMode +# TODO Test-Path variable:global:Env:WEBI_HOST ??? +IF(!$Env:WEBI_HOST) +{ + $Env:WEBI_HOST = "https://webinstall.dev" +} + +# Fetch webi.bat +Invoke-WebRequest "$Env:WEBI_HOST/packages/_webi/webi.ps1.bat" -OutFile webi.bat +Invoke-WebRequest "$Env:WEBI_HOST/packages/_webi/webi.ps1" -OutFile webi.ps1 + +popd + +# Run webi.bat +& .\.local\bin\webi.bat {{ exename }} + +# Run pathman to set up the folder +& "$Env:USERPROFILE\.local\bin\pathman.exe" add "$Env:USERPROFILE\.local\.bin" + +# Done +popd diff --git a/_webi/packages.js b/_webi/packages.js index b6ed221..279e940 100644 --- a/_webi/packages.js +++ b/_webi/packages.js @@ -38,7 +38,7 @@ pkgs.create = function (Pkgs, basepath) { var yash = path.join(basepath, node, 'package.yash'); var curlbash = path.join(basepath, node, 'install.sh'); var readme = path.join(basepath, node, 'README.md'); - var winstall = path.join(basepath, node, 'install.bat'); + var winstall = path.join(basepath, node, 'install.ps1'); return Promise.all([ fs.promises .readFile(readme, 'utf-8') @@ -80,7 +80,7 @@ pkgs.create = function (Pkgs, basepath) { // no winstaller winstall = ''; if ('ENOENT' !== e.code && 'ENOTDIR' !== e.code) { - console.error("failed to read '" + node + "/install.bat'"); + console.error("failed to read '" + node + "/install.ps1'"); console.error(e); } }) diff --git a/_webi/releases.js b/_webi/releases.js index dc30ce1..83eeb14 100644 --- a/_webi/releases.js +++ b/_webi/releases.js @@ -166,3 +166,61 @@ Releases.renderBatch = function ( }); }); }; + +Releases.renderPowerShell = function ( + pkgdir, + rel, + { baseurl, pkg, tag, ver, os, arch, formats } +) { + if (!Array.isArray(formats)) { + formats = []; + } + if (!tag) { + tag = ''; + } + return fs.promises + .readFile(path.join(pkgdir, 'install.ps1'), 'utf8') + .then(function (installTxt) { + var vers = rel.version.split('.'); + var v = { + major: vers.shift() || '', + minor: vers.shift() || '', + patch: vers.join('.').replace(/[+\-].*/, ''), + build: vers + .join('.') + .replace(/[^+\-]*/, '') + .replace(/^-/, '') + }; + return fs.promises + .readFile(path.join(__dirname, 'template.ps1'), 'utf8') + .then(function (tplTxt) { + var pkgver = pkg + '@' + ver; + return tplTxt + .replace( + /^(#)?\$Env:WEBI_HOST\s*=.*/im, + "$Env:WEBI_HOST = '" + baseurl + "'" + ) + .replace( + /^(#)?\$Env:WEBI_PKG\s*=.*/im, + "$Env:WEBI_PKG = '" + pkgver + "'" + ) + .replace( + /^(#)?\$Env:PKG_NAME\s*=.*/im, + "$Env:PKG_NAME = '" + pkg + "'" + ) + .replace( + /^(#)?\$Env:WEBI_VERSION\s*=.*/im, + "$Env:WEBI_VERSION = '" + rel.version + "'" + ) + .replace( + /^(#)?\$Env:WEBI_PKG_URL\s*=.*/im, + "$Env:WEBI_PKG_URL = '" + rel.download + "'" + ) + .replace( + /^(#)?\$Env:WEBI_PKG_FILE\s*=.*/im, + "$Env:WEBI_PKG_FILE = '" + rel.name + "'" + ) + .replace(/{{ installer }}/, installTxt); + }); + }); +}; diff --git a/_webi/template.ps1 b/_webi/template.ps1 new file mode 100644 index 0000000..1ccc5c6 --- /dev/null +++ b/_webi/template.ps1 @@ -0,0 +1,37 @@ +# If a command returns an error, halt the script. +$ErrorActionPreference = 'Stop' + +# Ignore progress events from cmdlets so Invoke-WebRequest is not painfully slow +$ProgressPreference = 'SilentlyContinue' + +$Env:WEBI_HOST = 'https://webinstall.dev' +#$Env:WEBI_PKG = 'node@lts' +#$Env:PKG_NAME = node +#$Env:WEBI_VERSION = v12.16.2 +#$Env:WEBI_PKG_URL = "https://.../node-....zip" +#$Env:WEBI_PKG_FILE = "node-v12.16.2-win-x64.zip" + +# Switch to userprofile +pushd $Env:USERPROFILE + +# Make paths if needed +if (!(Test-Path -Path Downloads)) +{ + New-Item -Path Downloads -ItemType Directory +} +if (!(Test-Path -Path .local\bin)) +{ + New-Item -Path .local\bin -ItemType Directory +} +if (!(Test-Path -Path .local\opt)) +{ + New-Item -Path .local\opt -ItemType Directory +} + +# {{ baseurl }} +# {{ version }} + +{{ installer }} + +# Done +popd diff --git a/_webi/test.js b/_webi/test.js index 947fbb1..d45b87f 100755 --- a/_webi/test.js +++ b/_webi/test.js @@ -46,7 +46,7 @@ nodes.forEach(function (node) { var maxLen = 0; console.info(''); console.info('Has the necessary files?'); -['README.md', 'releases.js', 'install.sh', 'install.bat'] +['README.md', 'releases.js', 'install.sh', 'install.ps1'] .map(function (node) { maxLen = Math.max(maxLen, node.length); return node; @@ -106,7 +106,7 @@ Releases.get(path.join(process.cwd(), pkgdir)).then(function (all) { arch, formats: formats }).catch(function () {}), - Releases.renderBatch(pkgdir, rel, { + Releases.renderPowerShell(pkgdir, rel, { baseurl: 'https://webinstall.dev', pkg: pkgname, tag: pkgtag || '', @@ -117,13 +117,13 @@ Releases.get(path.join(process.cwd(), pkgdir)).then(function (all) { }).catch(function () {}) ]).then(function (scripts) { var bashTxt = scripts[0]; - var batTxt = scripts[1]; + var ps1Txt = scripts[1]; var bashFile = 'install-' + pkgname + '.sh'; - var batFile = 'install-' + pkgname + '.bat'; + var ps1File = 'install-' + pkgname + '.ps1'; if (debug) { bashTxt = (bashTxt || 'echo ERROR').replace(/#set -x/g, 'set -x'); - batTxt = (batTxt || 'echo ERROR').replace( + ps1Txt = (ps1Txt || 'echo ERROR').replace( /REM REM todo debug/g, 'REM todo debug' ); @@ -131,8 +131,8 @@ Releases.get(path.join(process.cwd(), pkgdir)).then(function (all) { console.info('Has the necessary files?'); fs.writeFileSync(bashFile, bashTxt, 'utf-8'); console.info('\tNEEDS MANUAL TEST: bash %s', bashFile); - fs.writeFileSync(batFile, batTxt, 'utf-8'); - console.info('\tNEEDS MANUAL TEST: cmd.exe %s', batFile); + fs.writeFileSync(ps1File, ps1Txt, 'utf-8'); + console.info('\tNEEDS MANUAL TEST: powershell.exe %s', ps1File); console.info(''); }); }); diff --git a/_webi/ua-detect.js b/_webi/ua-detect.js index fb0a316..27d772a 100644 --- a/_webi/ua-detect.js +++ b/_webi/ua-detect.js @@ -10,7 +10,7 @@ function getOs(ua) { return 'android'; } else if (/iOS|iPhone|Macintosh|Darwin|OS\s*X|macOS|mac/i.test(ua)) { return 'macos'; - } else if (/Microsoft|Windows|win32|win|PowerShell/.test(ua)) { + } else if (/^ms$|Microsoft|Windows|win32|win|PowerShell/i.test(ua)) { // 'win' must be tested after 'darwin' return 'windows'; } else if (/Linux|curl|wget/i.test(ua)) { diff --git a/_webi/webi.bat b/_webi/webi.bat index ed56295..6023b92 100644 --- a/_webi/webi.bat +++ b/_webi/webi.bat @@ -22,7 +22,7 @@ pushd "%userprofile%" || goto :error .\.local\bin\pathman add ".local\bin" || goto :error echo downloading and installing %1 - powershell $ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest https://webinstall.dev/packages/%1/install.bat -OutFile %1-webinstall.bat || goto :error + powershell $ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest https://webinstall.dev/packages/%1/install.ps1 -OutFile %1-webinstall.bat || goto :error rem TODO only add if it's not in there already PATH .local\bin;%PATH% diff --git a/_webi/webi.ps1 b/_webi/webi.ps1 new file mode 100644 index 0000000..3e30242 --- /dev/null +++ b/_webi/webi.ps1 @@ -0,0 +1,51 @@ +# If a command returns an error, halt the script. +$ErrorActionPreference = 'Stop' + +# Ignore progress events from cmdlets so Invoke-WebRequest is not painfully slow +$ProgressPreference = 'SilentlyContinue' + +# TODO get arch +$Env:WEBI_UA = 'Windows/10 amd64' +$exename = $args[0] + +# Switch to userprofile +pushd $Env:USERPROFILE + +# Make paths if needed +if (!(Test-Path -Path .local\bin)) +{ + New-Item -Path .local\bin -ItemType Directory +} +if (!(Test-Path -Path .local\opt)) +{ + New-Item -Path .local\opt -ItemType Directory +} +# TODO windows version of mktemp -d +if (!(Test-Path -Path .local\tmp)) +{ + New-Item -Path .local\tmp -ItemType Directory +} + +if (!(Test-Path -Path .local\bin\pathman.exe)) +{ + & curl.exe -fsSL -A "$Env:WEBI_UA" "$Env:WEBI_HOST/packages/pathman/install.ps1" -o .\.local\tmp\pathman-setup.ps1 + powershell .\.local\tmp\pathman-setup.ps1 + # TODO del .\.local\tmp\pathman-setup.bat +} + +# {{ baseurl }} +# {{ version }} + +# Fetch .ps1 +echo "$Env:WEBI_HOST/packages/$exename/install.ps1" +echo "$exename.install.ps1" + +# TODO detect formats +# Invoke-WebRequest -UserAgent "Windows amd64" "$Env:WEBI_HOST/api/installers/$exename.ps1?formats=zip,tar" -OutFile ".\.local\tmp\$exename.install.ps1" +& curl.exe -fsSL -A "$Env:WEBI_UA" "$Env:WEBI_HOST/api/installers/$exename.ps1?formats=zip,tar" -o .\.local\tmp\$exename.install.ps1 + +# Run .ps1 +powershell .\.local\tmp\$exename.install.ps1 + +# Done +popd diff --git a/_webi/webi.ps1.bat b/_webi/webi.ps1.bat new file mode 100644 index 0000000..17915ad --- /dev/null +++ b/_webi/webi.ps1.bat @@ -0,0 +1 @@ +powershell -ExecutionPolicy Bypass .\.local\bin\webi.ps1 %1 diff --git a/node/install.ps1 b/node/install.ps1 new file mode 100644 index 0000000..64a6096 --- /dev/null +++ b/node/install.ps1 @@ -0,0 +1,47 @@ +# Fetch archive + +IF (!(Test-Path -Path "$Env:USERPROFILE\Downloads\$Env:WEBI_PKG_FILE")) +{ + # TODO: arch detection + echo "Downloading $Env:PKG_NAME from $Env:WEBI_PKG_URL to $Env:USERPROFILE\Downloads\$Env:WEBI_PKG_FILE" + #Invoke-WebRequest https://nodejs.org/dist/v12.16.2/node-v12.16.2-win-x64.zip -OutFile node-v12.16.2-win-x64.zip + & curl.exe -A "$Env:WEBI_UA" -fsSL "$Env:WEBI_PKG_URL" -o "$Env:USERPROFILE\Downloads\$Env:WEBI_PKG_FILE.part" + & move "$Env:USERPROFILE\Downloads\$Env:WEBI_PKG_FILE.part" "$Env:USERPROFILE\Downloads\$Env:WEBI_PKG_FILE" +} + +IF (!(Test-Path -Path "$Env:USERPROFILE\.local\opt\$Env:PKG_NAME-v$Env:WEBI_VERSION")) +{ + echo "Installing $Env:PKG_NAME" + # TODO: temp directory + + # Enter opt + pushd .local\tmp + + echo "Remove leftover node-v* stuffs" + Remove-Item -Path "node-v*" -Recurse -ErrorAction Ignore + + # Unpack archive + # Windows BSD-tar handles zip. Imagine that. + echo "Unpacking $Env:USERPROFILE\Downloads\$Env:WEBI_PKG_FILE" + & tar xf "$Env:USERPROFILE\Downloads\$Env:WEBI_PKG_FILE" + Get-ChildItem "node-v*" + + # Settle unpacked archive into place + echo "New Name: $Env:PKG_NAME-v$Env:WEBI_VERSION" + Get-ChildItem "node-v*" | Select -f 1 | Rename-Item -NewName "$Env:PKG_NAME-v$Env:WEBI_VERSION" + echo "New Location: $Env:USERPROFILE\.local\opt\$Env:PKG_NAME-v$Env:WEBI_VERSION" + Move-Item -Path "$Env:PKG_NAME-v$Env:WEBI_VERSION" -Destination "$Env:USERPROFILE\.local\opt" + + # Exit tmp + popd +} + +echo "Versioning $Env:PKG_NAME" +Remove-Item -Path "$Env:USERPROFILE\.local\opt\node" -Recurse -ErrorAction Ignore +Copy-Item -Path "$Env:USERPROFILE\.local\opt\$Env:PKG_NAME-v$Env:WEBI_VERSION" -Destination "$Env:USERPROFILE\.local\opt\$Env:PKG_NAME" -Recurse + +# make npm not act stupid about which node to use... ugh (this should be the default) +& .\.local\opt\node\npm.cmd --scripts-prepend-node-path=true config set scripts-prepend-node-path true + +# Add to path +& "$Env:USERPROFILE\.local\bin\pathman.exe" add .local\opt\node diff --git a/node/releases.js b/node/releases.js index 44f4cad..04c6a54 100644 --- a/node/releases.js +++ b/node/releases.js @@ -5,7 +5,7 @@ var map = { // OSes osx: 'macos', linux: 'linux', - win: 'windows', + win: 'windows', // windows sunos: 'sunos', aix: 'aix', // CPU architectures @@ -104,7 +104,7 @@ function getAllReleases(request) { if ('macos' === os) { r.download += '-darwin'; - } else if ('win' === os) { + } else if ('windows' === os) { r.download += '-win'; } else { r.download += '-' + os; diff --git a/pathman/install.ps1 b/pathman/install.ps1 new file mode 100644 index 0000000..dd729e4 --- /dev/null +++ b/pathman/install.ps1 @@ -0,0 +1 @@ +curl.exe -fsSL -A "$Env:WEBI_UA" "https://rootprojects.org/pathman/dist/windows/amd64/pathman.exe" -o "$Env:USERPROFILE\.local\bin\pathman.exe" -- 2.25.1