Compare commits

..

81 Commits

Author SHA1 Message Date
AJ ONeal
a3ce080c37 fix(flutter): set full download string directly on build info 2024-01-02 04:06:40 +00:00
AJ ONeal
5a5f12d8e7 fix(go): set full download string directly on build info 2024-01-02 03:59:25 +00:00
AJ ONeal
9a3cfbb573 fix(zig): filter out legacy armv6kz (RPi 1) one-off 2023-12-17 03:20:48 -07:00
AJ ONeal
50069182eb fix(pwsh): arch = 'musl' should be libc = 'musl' 2023-12-17 03:20:24 -07:00
AJ ONeal
546aee8fbb ref: releases.js => installers.js 2023-12-12 02:57:03 -07:00
AJ ONeal
7c61a19e20 ref(internal): packages.js => projects.js 2023-12-12 02:57:02 -07:00
AJ ONeal
e92081b08c fix(sd): update for v1 package structure 2023-12-12 02:56:40 -07:00
AJ ONeal
281c004445 ref(webi): show supported OSes, Arches, Libcs & Packages more clearly on error 2023-12-12 02:56:01 -07:00
AJ ONeal
e2300c6999 fix: fn_get_os for bootstrap & install 2023-12-12 01:58:58 -07:00
AJ ONeal
c116cb417f fix: remove extra / in doc url 2023-12-12 01:58:58 -07:00
AJ ONeal
c080b96fcc fix(git-tag): repo => _repo to distinguish from installers 2023-12-12 01:58:57 -07:00
AJ ONeal
e9a473d14a fix(git-tag): circumvent race condition on simultaneous duplicate git clone 2023-12-12 01:58:57 -07:00
AJ ONeal
3966d3adf8 fix(releases): bump timeout to 15s for uncached github requests 2023-12-12 01:44:11 -07:00
AJ ONeal
2fe6824472 chore: bump version to 1.2.8 2023-11-22 10:08:18 -07:00
AJ ONeal
4510a61cf0 fix(envman): split non-portable function.env => function.sh, function.fish 2023-11-22 10:05:12 -07:00
AJ ONeal
0da4b5d7cd chore: bump version to 1.2.7 2023-11-21 14:17:42 -07:00
AJ ONeal
948030b9cb ref: move shell integrations to their own functions 2023-11-21 13:56:15 -07:00
AJ ONeal
faaed1d2ec feat(completions): add --<option>s to the list 2023-11-21 13:56:15 -07:00
AJ ONeal
6875648daf feat(webi): save install options for shell completions 2023-11-21 13:56:15 -07:00
AJ ONeal
e8ba56e75f fix(zsh): must 'compinit' before 'compdef' 2023-11-21 13:56:15 -07:00
RubenRam
1f858bca4d feat(webi): add webi init option
Add shell package completion for bash, zsh and fish
2023-11-21 13:55:57 -07:00
AJ ONeal
f10be58d64 ref: move 'webi --info' to its own function 2023-11-21 13:52:56 -07:00
AJ ONeal
79ded46033 doc(webi-essentials): fix typo in sudo prompt 2023-11-21 13:35:21 -07:00
AJ ONeal
7eec48ea20 fix(posix): detect current/login shell even when rc file is absent 2023-11-21 11:28:17 -07:00
AJ ONeal
74676206f1 feat+ref!(posix): rewrite to load ENVs only once for all shells 2023-11-21 11:28:17 -07:00
Lockszmith
b6a02eaf21 ref: use cat << EOF > load.sh rather than echo 2023-11-21 11:28:17 -07:00
Lockszmith
ea99790768 fix(posix): run load.sh only once when .bashrc sources .profile 2023-11-21 11:28:17 -07:00
AJ ONeal
ec33462ae0 chore: fix typo in PATH.env message 2023-11-21 11:28:17 -07:00
AJ ONeal
89c437700e fix(posix): ensure PATH.env exists before checking contents 2023-11-21 11:28:16 -07:00
AJ ONeal
c75bbe7bd9 doc(webi-essentials): show command before running it 2023-11-21 11:28:16 -07:00
AJ ONeal
0767db7a7b doc(webi-essentials): clarify as per feedback in #768 2023-11-20 09:20:10 -07:00
AJ ONeal
b71a824e13 feat: distinguish between ACTION REQUIRED types 2023-11-20 09:20:09 -07:00
AJ ONeal
b3506079ac feat: add webi-essentials - a quick way to install curl, git, zip, etc 2023-11-20 09:20:09 -07:00
AJ ONeal
6fa045a4f9 fix(busybox): prefer curl over wget, limit wget options on busybox 2023-11-20 09:18:35 -07:00
AJ ONeal
64b58cf246 fix(pwsh): correctly classify musl, ignore c# builds 2023-11-19 12:52:32 -07:00
AJ ONeal
a4a386dd8a ref: rename to package-install.tpl.sh to match namespace style 2023-11-18 23:57:33 -07:00
AJ ONeal
e39e9722d7 ref(posix): various whitespace and text style updates 2023-11-18 23:00:26 -07:00
AJ ONeal
b56229ca62 ref(install): minor tweaks to differences from bootstrap 2023-11-18 23:00:25 -07:00
AJ ONeal
98ed726ec4 ref(install): bring into parity with curl-pipe-bootstrap 2023-11-18 23:00:25 -07:00
AJ ONeal
37201dc257 ref(bootstrap): organize functions into commented sections 2023-11-18 19:04:37 -07:00
AJ ONeal
4f53a412e5 ref(bootstrap): word order, wording, & style cleanup 2023-11-18 19:04:37 -07:00
AJ ONeal
e4c4fd8c08 fix(bootstrap): preserve file handle: mv & rm rather overwrite webi 2023-11-18 19:04:37 -07:00
AJ ONeal
7fe17220b7 ref(bootstrap): use -- in printf -- '%s' "${foo}" just to be safe 2023-11-18 19:04:37 -07:00
AJ ONeal
24f6703a2d fix(bootstrap): POSIX doesn't define 'interactive', detect TTY instead 2023-11-18 19:04:37 -07:00
AJ ONeal
6296dece2a ref(bootstrap): organize text styles 2023-11-18 19:04:36 -07:00
AJ ONeal
3908a7df9f fix(bootstrap): only apply text style & color to TTYs 2023-11-18 19:04:36 -07:00
AJ ONeal
1267272902 fix(bootstrap): track if just upgraded to limit upgrade attempts 2023-11-18 19:04:36 -07:00
AJ ONeal
4869336b24 fix(webi): track if welcome message was already shown 2023-11-18 19:04:36 -07:00
AJ ONeal
ddda72daac fix(bootstrap): track if welcome message was already shown 2023-11-18 19:03:45 -07:00
AJ ONeal
bfb54691e8 fix(bootstrap): typo '-f sSL' => '-f -sSL' 2023-11-18 18:09:32 -07:00
AJ ONeal
8aa665be56 fix(posix): set WEBI_CHECKSUM in both bootstrap and installer 2023-11-18 18:09:31 -07:00
AJ ONeal
c0c7e61cb5 fix: revert curl --fail-with-body to --fail 2023-11-17 08:57:24 -07:00
AJ ONeal
993e2dd75b fix!(chromedriver): rewrite for latest releases URL 2023-11-15 21:59:33 -07:00
AJ ONeal
286efb7898 fix(yq): filter out special non-build files 2023-11-15 21:31:20 -07:00
AJ ONeal
5ee4ecde56 fix(terraform): remove incorrect arch detection 2023-11-15 21:31:20 -07:00
AJ ONeal
af645df848 fix(kube*): filter out companion util and legacy scripts 2023-11-15 21:31:20 -07:00
AJ ONeal
18b1effadd fix(jq): filter out special non-build files 2023-11-15 21:31:20 -07:00
AJ ONeal
0f96b709f0 fix(go): filter out typoed beta release 2023-11-15 21:31:20 -07:00
AJ ONeal
b908672f12 fix(flutter): add _version to match version in filepath 2023-11-15 21:31:20 -07:00
AJ ONeal
b925ebe746 fix(flutter): remove incorrect os/arch detection 2023-11-15 21:31:19 -07:00
AJ ONeal
777b28a924 fix(fd): filter out unmatchable legacy build 2023-11-15 21:31:19 -07:00
AJ ONeal
46374beb68 ref(dashcore): remove custom filtering on generic asset type 2023-11-15 21:31:19 -07:00
AJ ONeal
852bae9d3d fix(dashcore): add _version to match version in filepath 2023-11-15 21:31:19 -07:00
AJ ONeal
afbebb8676 fix(cmake): add _version to match version in filepath 2023-11-15 21:31:19 -07:00
AJ ONeal
b63eb6d839 fix(ssh-adduser): check if SSH_ADDUSER_AUTO is set 2023-11-14 14:46:04 -07:00
AJ ONeal
8ea2e01f4c fix(iterm2): don't update to the same version 2023-11-14 13:58:34 -07:00
AJ ONeal
b843c689a0 ref(releases): filter out various one-offs and non-builds 2023-11-14 12:10:04 -07:00
AJ ONeal
dc1ab03aeb ref(releases): add classification helpers: _names, _version, _filenames 2023-11-14 12:10:04 -07:00
AJ ONeal
e9485d85ad chore: burn junk comments 2023-11-14 12:10:04 -07:00
AJ ONeal
42f9e73b55 ref(flutter): cleanup releases.js, add hash, don't resort 2023-11-14 12:10:04 -07:00
AJ ONeal
e49ba2ba92 fix(flutter): update release URLs for v3.x 2023-11-14 12:09:53 -07:00
AJ ONeal
3d2280b026 fix(pwsh): '$pkg_dst' is a link, not a directory 2023-11-14 12:08:18 -07:00
AJ ONeal
aa03b9e4f1 fix(flutter): fix bad 'v' match: don't replace 'dev' with 'de' 2023-11-14 10:55:08 -07:00
AJ ONeal
e0820b5517 fix(gitea): check for and install 'git' on Windows 2023-11-14 10:55:07 -07:00
AJ ONeal
e05551cb06 fix(zig): use semver version for beta / 'master' 2023-11-14 10:55:07 -07:00
AJ ONeal
cf621183b4 fix(windows): use -L with curl (for redirects from Github assets, etc) 2023-11-14 10:55:07 -07:00
AJ ONeal
3c05298c6a fix(arm): don't match 'arm64' for 'arm' without bit or version specifier 2023-11-14 10:55:07 -07:00
AJ ONeal
0c438aff8f ref!: make 'pwsh' canonical package for PowerShell Core 2023-11-12 02:32:27 -07:00
AJ ONeal
fc8cef1308 ref!: add 'powershell' as alias for 'pwsh' 2023-11-12 02:32:27 -07:00
AJ ONeal
8ed7909e15 ref!: transitory rename of 'powershell' to 'pwsh' 2023-11-12 02:32:27 -07:00
AJ ONeal
de36cf6b10 ref!: delete alias 'pwsh' in prep for powershell => pwsh transition 2023-11-12 02:32:27 -07:00
137 changed files with 2904 additions and 1541 deletions

View File

@@ -6,11 +6,12 @@ var Crypto = require('crypto');
var util = require('util');
var exec = util.promisify(require('child_process').exec);
var Fs = require('node:fs/promises');
var FsSync = require('node:fs');
var Path = require('node:path');
var repoBaseDir = process.env.REPO_BASE_DIR || '';
if (!repoBaseDir) {
repoBaseDir = Path.resolve('./repos');
repoBaseDir = Path.resolve('./_repos');
// for stderr
console.error(`[Warn] REPO_BASE_DIR= not set, ${repoBaseDir}`);
}
@@ -20,8 +21,29 @@ var Repos = {};
Repos.clone = async function (repoPath, gitUrl) {
let uuid = Crypto.randomUUID();
let tmpPath = `${repoPath}.${uuid}.tmp`;
let bakPath = `${repoPath}.${uuid}.dup`;
await exec(`git clone --bare --filter=tree:0 ${gitUrl} ${tmpPath}`);
await Fs.rename(tmpPath, repoPath);
try {
FsSync.accessSync(repoPath);
return;
} catch (e) {
if (e.code !== 'ENOENT') {
throw e;
}
}
// sync to avoid race conditions
try {
FsSync.renameSync(repoPath, bakPath);
} catch (e) {
if (e.code !== 'ENOENT') {
throw e;
}
}
FsSync.renameSync(tmpPath, repoPath);
await Fs.rm(bakPath, { force: true, recursive: true });
};
Repos.checkExists = async function (repoPath) {

View File

@@ -30,7 +30,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\foobar-v*" -Recurse -ErrorAction Ignore

View File

@@ -16,39 +16,45 @@ export WEBI_CHECKSUM=06a7fb9f
# #
#########################################
# shellcheck disable=SC2005
fn_show_welcome() { (
echo ""
printf "%s %s\n" \
"$(t_strong 'Welcome to') $(t_stronger 'Webi')$(t_strong '!')" \
"$(t_dim "- Modern tools, instant installs.")"
echo "We expect your experience to be $(t_em 'absolutely perfect')!"
echo ""
echo " $(t_yellow 'Have a problem?') Please $(t_em 'let us know'):"
echo " $(t_url 'https://github.com/webinstall/webi-installers/issues')"
echo " $(t_dim "(your system is $(t_yellow "$(uname -s)")/$(t_yellow "$(uname -m)") with $(t_yellow "$(fn_get_libc)") & $(t_yellow "$(fn_get_http)"))")"
# invert t_task and t_pkg for top-level welcome message
printf -- ">>> %s %s <<<\n" \
"$(t_pkg 'Welcome to') $(t_task 'Webi')$(t_pkg '!')" \
"$(t_dim "- modern tools, instant installs.")"
echo " We expect your experience to be $(t_em 'absolutely perfect')!"
echo ""
echo " $(t_yellow 'Love it?') Star it!"
echo " $(t_url 'https://github.com/webinstall/webi-installers')"
echo " $(t_attn 'Success')? Star it! $(t_url 'https://github.com/webinstall/webi-installers')"
echo " $(t_attn 'Problem')? Report it: $(t_url 'https://github.com/webinstall/webi-installers/issues')"
echo " $(t_dim "(your system is") $(t_host "$(fn_get_os)")/$(t_host "$(uname -m)") $(t_dim "with") $(t_host "$(fn_get_libc)") $(t_dim "&") $(t_host "$(fn_get_http_client_name)")$(t_dim ")")"
sleep 0.2
); }
t_strong() { (printf '\e[36m%s\e[39m' "${1}"); }
t_stronger() { (printf '\e[1m\e[32m%s\e[39m\e[22m' "${1}"); }
t_url() { (printf '\e[2m%s\e[22m' "${1}"); }
t_path() { (printf '\e[2m\e[32m%s\e[39m\e[22m' "${1}"); }
t_cmd() { (printf '\e[2m\e[35m%s\e[39m\e[22m' "${1}"); }
t_err() { (printf '\e[31m%s\e[39m' "${1}"); }
fn_get_os() { (
# Ex:
# GNU/Linux
# Android
# Linux (often Alpine, musl)
# Darwin
b_os="$(uname -o 2> /dev/null || echo '')"
b_sys="$(uname -s)"
if test -z "${b_os}" || test "${b_os}" = "${b_sys}"; then
# ex: 'Darwin' (and plain, non-GNU 'Linux')
echo "${b_sys}"
return 0
fi
t_bold() { (printf '\e[1m%s\e[22m' "${1}"); }
t_dim() { (printf '\e[2m%s\e[22m' "${1}"); }
t_em() { (printf '\e[3m%s\e[23m' "${1}"); }
t_under() { (printf '\e[4m%s\e[24m' "${1}"); }
t_green() { (printf '\e[32m%s\e[39m' "${1}"); }
t_yellow() { (printf '\e[33m%s\e[39m' "${1}"); }
t_magenta() { (printf '\e[35m%s\e[39m' "${1}"); }
t_cyan() { (printf '\e[36m%s\e[39m' "${1}"); }
if echo "${b_os}" | grep -q "${b_sys}"; then
# ex: 'GNU/Linux'
echo "${b_os}"
return 0
fi
# ex: 'Android/Linux'
echo "${b_os}/${b_sys}"
); }
fn_get_libc() { (
# Ex:
@@ -56,14 +62,14 @@ fn_get_libc() { (
# libc
if ldd /bin/ls 2> /dev/null | grep -q 'musl' 2> /dev/null; then
echo 'musl'
elif uname -o | grep -q 'GNU' || uname -s | grep -q 'Linux'; then
elif fn_get_os | grep -q 'GNU|Linux'; then
echo 'gnu'
else
echo 'libc'
fi
); }
fn_get_http() { (
fn_get_http_client_name() { (
# Ex:
# curl
# curl+wget
@@ -82,6 +88,56 @@ fn_get_http() { (
echo "${b_client}"
); }
#########################################
# #
# For Making the Display Nice #
# #
#########################################
# Term Types
t_cmd() { (fn_printf '\e[2m\e[35m%s\e[39m\e[22m' "${1}"); }
t_host() { (fn_printf '\e[2m\e[33m%s\e[39m\e[22m' "${1}"); }
t_link() { (fn_printf '\e[1m\e[36m%s\e[39m\e[22m' "${1}"); }
t_path() { (fn_printf '\e[2m\e[32m%s\e[39m\e[22m' "${1}"); }
t_pkg() { (fn_printf '\e[1m\e[32m%s\e[39m\e[22m' "${1}"); }
t_task() { (fn_printf '\e[36m%s\e[39m' "${1}"); }
t_url() { (fn_printf '\e[2m%s\e[22m' "${1}"); }
# Levels
t_info() { (fn_printf '\e[1m\e[36m%s\e[39m\e[22m' "${1}"); }
t_attn() { (fn_printf '\e[1m\e[33m%s\e[39m\e[22m' "${1}"); }
t_warn() { (fn_printf '\e[1m\e[33m%s\e[39m\e[22m' "${1}"); }
t_err() { (fn_printf '\e[31m%s\e[39m' "${1}"); }
# Styles
t_bold() { (fn_printf '\e[1m%s\e[22m' "${1}"); }
t_dim() { (fn_printf '\e[2m%s\e[22m' "${1}"); }
t_em() { (fn_printf '\e[3m%s\e[23m' "${1}"); }
t_under() { (fn_printf '\e[4m%s\e[24m' "${1}"); }
# FG Colors
t_cyan() { (fn_printf '\e[36m%s\e[39m' "${1}"); }
t_green() { (fn_printf '\e[32m%s\e[39m' "${1}"); }
t_magenta() { (fn_printf '\e[35m%s\e[39m' "${1}"); }
t_yellow() { (fn_printf '\e[33m%s\e[39m' "${1}"); }
fn_printf() { (
a_style="${1}"
a_text="${2}"
if fn_is_tty; then
#shellcheck disable=SC2059
printf -- "${a_style}" "${a_text}"
else
printf -- '%s' "${a_text}"
fi
); }
fn_sub_home() { (
my_rel=${HOME}
my_abs=${1}
echo "${my_abs}" | sed "s:^${my_rel}:~:"
); }
###################################
# #
# Detect HTTP Client #
@@ -94,9 +150,14 @@ fn_wget() { (
a_url="${1}"
a_path="${2}"
cmd_wget="wget -q --user-agent"
if fn_is_interactive; then
cmd_wget="wget -q --show-progress --user-agent"
cmd_wget="wget -c -q --user-agent"
if fn_is_tty; then
cmd_wget="wget -c -q --show-progress --user-agent"
fi
# busybox wget doesn't support --show-progress
# See <https://github.com/webinstall/webi-installers/pull/772>
if readlink "$(command -v wget)" | grep -q busybox; then
cmd_wget="wget --user-agent"
fi
b_triple_ua="$(fn_get_target_triple_user_agent)"
@@ -105,9 +166,9 @@ fn_wget() { (
b_agent="webi/wget+curl ${b_triple_ua}"
fi
if ! $cmd_wget "${b_agent}" -c "${a_url}" -O "${a_path}"; then
if ! $cmd_wget "${b_agent}" "${a_url}" -O "${a_path}"; then
echo >&2 " $(t_err "failed to download (wget)") '$(t_url "${a_url}")'"
echo >&2 " $cmd_wget '${b_agent}' -c '${a_url}' -O '${a_path}'"
echo >&2 " $cmd_wget '${b_agent}' '${a_url}' -O '${a_path}'"
echo >&2 " $(wget -V)"
return 1
fi
@@ -119,9 +180,9 @@ fn_curl() { (
a_url="${1}"
a_path="${2}"
cmd_curl="curl --fail-with-body -sSL -#"
if fn_is_interactive; then
cmd_curl="curl --fail-with-body sSL"
cmd_curl="curl -f -sSL -#"
if fn_is_tty; then
cmd_curl="curl -f -sSL"
fi
b_triple_ua="$(fn_get_target_triple_user_agent)"
@@ -138,21 +199,11 @@ fn_curl() { (
fi
); }
fn_is_interactive() {
# Ex:
# himBH
# hBc
case $- in
*i*) return 0 ;;
*) return 1 ;;
esac
}
fn_get_target_triple_user_agent() { (
# Ex:
# x86_64/unknown Linux/5.15.107-2-pve gnu
# x86_64/unknown GNU/Linux/5.15.107-2-pve gnu
# arm64/unknown Darwin/22.6.0 libc
echo "$(uname -m)/unknown $(uname -s)/$(uname -r) $(fn_get_libc)"
echo "$(uname -m)/unknown $(fn_get_os)/$(uname -r) $(fn_get_libc)"
); }
fn_download_to_path() { (
@@ -160,10 +211,10 @@ fn_download_to_path() { (
a_path="${2}"
mkdir -p "$(dirname "${a_path}")"
if command -v wget > /dev/null; then
fn_wget "${a_url}" "${a_path}.part"
elif command -v curl > /dev/null; then
if command -v curl > /dev/null; then
fn_curl "${a_url}" "${a_path}.part"
elif command -v wget > /dev/null; then
fn_wget "${a_url}" "${a_path}.part"
else
echo >&2 " $(t_err "failed to detect HTTP client (curl, wget)")"
return 1
@@ -177,31 +228,40 @@ fn_download_to_path() { (
# #
##############################################
webi_upgrade() { (
webi_bootstrap() { (
a_path="${1}"
echo ""
echo "$(t_strong 'Bootstrapping') $(t_stronger 'Webi')"
echo "$(t_task 'Bootstrapping') $(t_pkg 'Webi')"
b_path_rel="$(fn_sub_home "${a_path}")"
b_checksum=""
if test -r "${a_path}"; then
echo " $(t_dim 'Found') $(t_path "${b_path_rel}")"
b_checksum="$(fn_checksum "${a_path}")"
fi
if test "$b_checksum" = "${WEBI_CHECKSUM}"; then
echo " $(t_dim 'Found') $(t_path "${b_path_rel}")"
sleep 0.1
return 0
fi
b_webi_file_url="${WEBI_HOST}/packages/webi/webi.sh"
b_tmp=''
if test -r "${a_path}"; then
b_ts="$(date -u '+%s')"
b_tmp="${a_path}.${b_ts}.bak"
mv "${a_path}" "${b_tmp}"
echo " Updating $(t_path "${b_path_rel}")"
fi
echo " Downloading $(t_url "${b_webi_file_url}")"
echo " to $(t_path "${b_path_rel}")"
fn_download_to_path "${b_webi_file_url}" "${a_path}"
chmod u+x "${a_path}"
if test -r "${b_tmp}"; then
rm -f "${b_tmp}"
fi
); }
fn_checksum() {
@@ -215,29 +275,64 @@ fn_checksum() {
$cmd_shasum "${a_filepath}" | cut -d' ' -f1 | cut -c 1-8
}
fn_sub_home() { (
my_rel=${HOME}
my_abs=${1}
echo "${my_abs}" | sed "s:^${my_rel}:~:"
##############################################
# #
# Detect TTY and run main #
# #
##############################################
fn_is_tty() {
if test "${WEBI_TTY}" = 'tty'; then
return 0
fi
return 1
}
fn_detect_tty() { (
# stdin will NOT be a tty if it's being piped
# stdout & stderr WILL be a tty even when piped
# they are not a tty if being captured or redirected
# 'set -i' is NOT available in sh
if test -t 1 && test -t 2; then
return 0
fi
return 1
); }
main() { (
fn_show_welcome
export WEBI_WELCOME=true
set -e
set -u
WEBI_TTY="${WEBI_TTY:-}"
if test -z "${WEBI_TTY}"; then
if fn_detect_tty; then
WEBI_TTY="tty"
fi
export WEBI_TTY
fi
if test -z "${WEBI_WELCOME:-}"; then
fn_show_welcome
fi
export WEBI_WELCOME='shown'
# note: we may support custom locations in the future
export WEBI_HOME="${HOME}/.local"
b_home="$(fn_sub_home "${WEBI_HOME}")"
b_webi_path="${WEBI_HOME}/bin/webi"
b_webi_path_rel="${b_home}/bin/webi"
webi_upgrade "${b_webi_path}"
echo ""
echo "$(t_strong 'Installing') $(t_stronger "${WEBI_PKG}") $(t_strong '...')"
WEBI_CURRENT="${WEBI_CURRENT:-}"
if test "${WEBI_CURRENT}" != "${WEBI_CHECKSUM}"; then
webi_bootstrap "${b_webi_path}"
export WEBI_CURRENT="${WEBI_CHECKSUM}"
fi
echo " Running $(t_cmd "${b_webi_path_rel} ${WEBI_PKG}")"
echo ""
"${b_webi_path}" "${WEBI_PKG}"
); }
set -e
set -u
main

View File

@@ -1,695 +0,0 @@
#!/bin/sh
__bootstrap_webi() {
set -e
set -u
#set -x
my_libc=''
if ldd /bin/ls 2> /dev/null | grep -q 'musl' 2> /dev/null; then
my_libc='musl'
elif uname -o | grep -q 'GNU' || uname -s | grep -q 'Linux'; then
my_libc='gnu'
else
my_libc='libc'
fi
WEBI_UA="$(uname -s)/$(uname -r) $(uname -m)/unknown ${my_libc}"
#WEBI_PKG=
#PKG_NAME=
#WEBI_OS=
#WEBI_ARCH=
#WEBI_LIBC=
#WEBI_HOST=
#WEBI_RELEASES=
#WEBI_CSV=
#WEBI_TAG=
#WEBI_VERSION=
#WEBI_MAJOR=
#WEBI_MINOR=
#WEBI_PATCH=
# TODO not sure if BUILD is the best name for this
#WEBI_BUILD=
#WEBI_GIT_TAG=
#WEBI_LTS=
#WEBI_CHANNEL=
#WEBI_EXT=
#WEBI_FORMATS=
#WEBI_PKG_URL=
#WEBI_PKG_FILE=
#WEBI_PKG_PATHNAME=
#PKG_OSES=
#PKG_ARCHES=
#PKG_LIBCS=
#PKG_FORMATS=
WEBI_UA="$(uname -s)/$(uname -r) $(uname -m)/unknown ${my_libc}"
WEBI_PKG_DOWNLOAD=""
WEBI_DOWNLOAD_DIR="${HOME}/Downloads"
if command -v xdg-user-dir > /dev/null; then
WEBI_DOWNLOAD_DIR="$(xdg-user-dir DOWNLOAD)"
if [ "${WEBI_DOWNLOAD_DIR}" = "${HOME}" ]; then
WEBI_DOWNLOAD_DIR="${HOME}/Downloads"
fi
fi
WEBI_PKG_PATH="${WEBI_DOWNLOAD_DIR}/webi/${PKG_NAME:-error}/${WEBI_VERSION:-latest}"
export WEBI_HOST
##
## Set up tmp, download, and install directories
##
WEBI_TMP=${WEBI_TMP:-"$(mktemp -d -t webinstall-"${WEBI_PKG-}".XXXXXXXX)"}
export _webi_tmp="${_webi_tmp:-"$HOME/.local/opt/webi-tmp.d"}"
mkdir -p "${WEBI_PKG_PATH}"
mkdir -p "$HOME/.local/bin"
mkdir -p "$HOME/.local/opt"
if test -e ~/.local/bin; then
echo "Found ~/.local/bin"
else
echo "Creating ~/.local/bin"
mkdir -p "$HOME/.local/bin"
fi
if test -e ~/.local/bin/webi; then
echo "Found ~/.local/bin/webi"
else
echo "Creating ~/.local/bin"
mkdir -p "$HOME/.local/bin"
fi
##
## Detect http client
##
set +e
WEBI_CURL="$(command -v curl)"
export WEBI_CURL
WEBI_WGET="$(command -v wget)"
export WEBI_WGET
set -e
# get the special formatted version
# (i.e. "go is go1.14" while node is "node v12.10.8")
my_versioned_name=""
_webi_canonical_name() {
if [ -n "$my_versioned_name" ]; then
echo "$my_versioned_name"
return 0
fi
if command -v pkg_format_cmd_version > /dev/null; then
my_versioned_name="'$(pkg_format_cmd_version "$WEBI_VERSION")'"
else
my_versioned_name="'$pkg_cmd_name v$WEBI_VERSION'"
fi
echo "$my_versioned_name"
}
# Update symlinks as per $HOME/.local/opt and $HOME/.local/bin install paths.
webi_link() {
if command -v pkg_link > /dev/null; then
pkg_link
return 0
fi
if test -n "${WEBI_SINGLE}"; then
rm -rf "$pkg_dst_cmd"
ln -s "$pkg_src_cmd" "$pkg_dst_cmd"
else
# 'pkg_dst' will default to $HOME/.local/opt/<pkg>
# 'pkg_src' will be the installed version,
# such as to $HOME/.local/opt/<pkg>-<version>
rm -rf "$pkg_dst"
ln -s "$pkg_src" "$pkg_dst"
fi
}
# detect if this program is already installed
# or if an installed version may cause conflict
webi_check_installed() {
# Test for existing version
set +e
my_path="$PATH"
PATH="$(dirname "$pkg_dst_cmd"):$PATH"
export PATH
my_current_cmd="$(command -v "$pkg_cmd_name")"
set -e
if [ -n "$my_current_cmd" ]; then
my_canonical_name="$(_webi_canonical_name)"
if [ "$my_current_cmd" != "$pkg_dst_cmd" ]; then
echo >&2 "WARN: possible PATH conflict between $my_canonical_name and currently installed version"
echo >&2 " ${pkg_dst_cmd} (new)"
echo >&2 " ${my_current_cmd} (existing)"
#my_current_version=false
fi
# 'readlink' can't read links in paths on macOS 🤦
# but that's okay, 'cmp -s' is good enough for us
if cmp -s "${pkg_src_cmd}" "${my_current_cmd}"; then
echo "${my_canonical_name} already installed:"
my_dst_rel="$(
webi_sub_home "${pkg_dst}"
)"
printf " %s" "${my_dst_rel}"
if [ "${pkg_src_cmd}" != "${my_current_cmd}" ]; then
my_src_rel="$(
webi_sub_home "${pkg_src}"
)"
printf " => %s" "${my_src_rel}"
fi
echo ""
exit 0
fi
if [ -x "$pkg_src_cmd" ]; then
webi_link
echo "switched to $my_canonical_name:"
my_src_rel="$(
webi_sub_home "${pkg_src}"
)"
my_dst_rel="$(
webi_sub_home "${pkg_dst}"
)"
echo " ${my_dst_rel} => ${my_src_rel}"
exit 0
fi
fi
export PATH="$my_path"
}
webi_check_available() {
if test "$WEBI_CHANNEL" != "error"; then
return 0
fi
echo >&2 "Error: no '${PKG_NAME:-"Unknown Package"}@${WEBI_TAG:-"Unknown Tag"}' release for '${WEBI_OS:-"Unknown OS"}' (${WEBI_LIBC:-"Unknown Libc"}) on '${WEBI_ARCH:-"Unknown CPU"}' as one of '${WEBI_FORMATS:-"Unknown File Type"}'"
echo >&2 " '$PKG_NAME' is available for '$PKG_OSES' ($PKG_LIBCS) on '$PKG_ARCHES' as one of '$PKG_FORMATS'"
echo >&2 " (check that the package name and version are correct)"
echo >&2 ""
my_release_url="$(
echo "$WEBI_RELEASES" |
sed 's:?.*::'
)"
my_release_params="$(
echo "$WEBI_RELEASES" |
sed 's:.*?:?:'
)"
echo >&2 " Double check at ${my_release_url}"
echo >&2 " ${my_release_params}"
echo >&2 ""
exit 1
}
is_interactive_shell() {
# $- shows shell flags (error,unset,interactive,etc)
case $- in
*i*) return 0 ;;
*) return 1 ;;
esac
}
webi_sub_home() { (
my_rel=${HOME}
my_abs=${1}
echo "${my_abs}" | sed "s:^${my_rel}:~:"
); }
# detect if file is downloaded, and how to download it
webi_download() {
my_url="${1}"
my_dl="${2}"
my_dl_name="${3:-${PKG_NAME}}"
my_dl_rel="$(
webi_sub_home "${my_dl}"
)"
WEBI_PKG_DOWNLOAD="${my_dl}"
export WEBI_PKG_DOWNLOAD
if [ -e "${my_dl}" ]; then
echo "Found ${my_dl_rel}"
return 0
fi
echo "Downloading ${my_dl_name} from"
echo "$my_url"
# It's only 2020, we can't expect to have reliable CLI tools
# to tell us the size of a file as part of a base system...
if [ -n "$WEBI_WGET" ]; then
# wget has resumable downloads
# TODO wget -c --content-disposition "$my_url"
set +e
my_show_progress=""
if is_interactive_shell; then
my_show_progress="--show-progress"
fi
if ! wget -q $my_show_progress --user-agent="wget $WEBI_UA" -c "$my_url" -O "$my_dl.part"; then
echo >&2 "failed to download from $WEBI_PKG_URL"
exit 1
fi
set -e
else
# Neither GNU nor BSD curl have sane resume download options, hence we don't bother
my_show_progress="-#"
if is_interactive_shell; then
my_show_progress=""
fi
# shellcheck disable=SC2086
# we want the flags to be split
curl -fSL $my_show_progress -H "User-Agent: curl $WEBI_UA" "$my_url" -o "$my_dl.part"
fi
mv "$my_dl.part" "$my_dl"
echo ""
echo "Saved as ${my_dl_rel}"
}
webi_git_clone() { (
my_url="${1}"
my_dl="${2}"
my_dl_rel="$(
webi_sub_home "${my_dl}"
)"
if [ -e "${my_dl}" ]; then
echo "Found ${my_dl_rel}"
cp -RPp "${my_dl}" "${WEBI_TMP}/${WEBI_PKG_FILE}/"
return 0
fi
echo "Cloning ${my_url}"
cmd_git="git clone --config advice.detachedHead=false --quiet --depth=1 --single-branch"
rm -rf "${my_dl}.part"
if ! $cmd_git "${my_url}" --branch "${WEBI_GIT_TAG}" "${my_dl}.part"; then
echo >&2 "failed to git clone ${WEBI_PKG_URL}"
exit 1
fi
mv "${my_dl}.part" "${my_dl}"
cp -RPp "${my_dl}" "${WEBI_TMP}/${WEBI_PKG_FILE}/"
); }
# detect which archives can be used
webi_extract() {
(
cd "$WEBI_TMP"
my_dl_rel="$(
webi_sub_home "${WEBI_PKG_PATH}/${WEBI_PKG_FILE}"
)"
if [ "tar" = "$WEBI_EXT" ]; then
echo "Extracting ${my_dl_rel}"
tar xf "${WEBI_PKG_PATH}/$WEBI_PKG_FILE"
elif [ "zip" = "$WEBI_EXT" ]; then
echo "Extracting ${my_dl_rel}"
unzip "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" > __unzip__.log
elif [ "exe" = "$WEBI_EXT" ]; then
echo "Moving ${my_dl_rel}"
mv "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" .
elif [ "git" = "$WEBI_EXT" ]; then
echo "Moving ${my_dl_rel}"
mv "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" .
elif [ "xz" = "$WEBI_EXT" ]; then
echo "Inflating ${my_dl_rel}"
unxz -c "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" > "$(basename "$WEBI_PKG_FILE")"
else
echo "Failed to extract ${WEBI_PKG_PATH}/$WEBI_PKG_FILE"
exit 1
fi
)
}
# use 'pathman' to update $HOME/.config/envman/PATH.env
webi_path_add() {
my_path="${1}"
fn_envman_init
# \v was chosen as it is extremely unlikely for a filename
# \1 could be an even better choice, but needs more testing.
# (currently tested working on: linux & mac)
# "\0001" should also work
my_delim="$(
printf '\v'
)"
my_path_expanded="$(
echo "${my_path}" |
sed -e "s${my_delim}\$HOME${my_delim}$HOME${my_delim}g" \
-e "s${my_delim}\${HOME}${my_delim}$HOME${my_delim}g" \
-e "s${my_delim}^~/${my_delim}$HOME/${my_delim}g"
)"
# A gift for @adamcstephens.
# See https://github.com/webinstall/webi-installers/issues/322
case "${PATH}" in
# matches whether the first, a middle, the last, or the only PATH entry
"${my_path_expanded}":* | \
*:"${my_path_expanded}":* | \
*:"${my_path_expanded}" | \
"${my_path_expanded}")
if fn_is_defined_in_all_shells "${my_path}"; then
return 0
fi
;;
*) ;;
esac
my_path_export="$(
echo "${my_path}" |
sed -e "s${my_delim}${HOME}${my_delim}\$HOME${my_delim}g" \
-e "s${my_delim}\${HOME}${my_delim}\$HOME${my_delim}g" \
-e "s${my_delim}^~/${my_delim}\$HOME/${my_delim}g"
)"
my_export="export PATH=\"$my_path_export:\$PATH\""
if grep -q -F "${my_export}" ~/.config/envman/PATH.env; then
return 0
fi
echo "${my_export}" >> ~/.config/envman/PATH.env
mkdir -p "$_webi_tmp"
my_path_tilde="$(
echo "${my_path}" |
sed -e "s${my_delim}${HOME}${my_delim}~${my_delim}g"
)"
if ! test -f "$_webi_tmp/.PATH.env" ||
! grep -q -F "${my_path_tilde}" "$_webi_tmp/.PATH.env"; then
echo "${my_path_tilde}" >> "$_webi_tmp/.PATH.env"
fi
}
fn_envman_init() {
mkdir -p ~/.config/envman/
if ! test -e ~/.config/envman/PATH.env; then
touch ~/.config/envman/PATH.env
fi
if ! test -e ~/.config/envman/load.sh; then
# shellcheck disable=SC2016
{
echo '# Generated for envman. Do not edit.'
echo 'for x in ~/.config/envman/*.env; do'
echo ' my_basename="$(basename "${x}")"'
echo ' if [ "*.env" = "${my_basename}" ]; then'
echo ' continue'
echo ' fi'
echo ''
echo ' # shellcheck source=/dev/null'
echo ' . "${x}"'
echo 'done'
} > ~/.config/envman/load.sh
fi
if command -v sh > /dev/null; then
if test -e ~/.profile; then
if ! grep -q -F '/.config/envman/load.sh' ~/.profile; then
fn_echo_load_sh >> ~/.profile
fi
fi
fi
if command -v bash > /dev/null; then
if test -e ~/.bashrc; then
if ! grep -q -F '/.config/envman/load.sh' ~/.bashrc; then
fn_echo_load_sh >> ~/.bashrc
fi
fi
fi
if command -v zsh > /dev/null; then
if test -e ~/.zshrc; then
if ! grep -q -F '/.config/envman/load.sh' ~/.zshrc; then
fn_echo_load_sh >> ~/.zshrc
fi
fi
fi
if command -v fish > /dev/null; then
if test ! -e ~/.config/envman/load.fish; then
# shellcheck disable=SC2016
{
echo '# Generated for envman. Do not edit.'
echo 'for x in ~/.config/envman/*.env'
echo ' source "$x"'
echo 'end'
} > ~/.config/envman/load.fish
fi
mkdir -p ~/.config/fish
if test -e ~/.config/fish/config.fish; then
touch ~/.config/fish/config.fish
fi
if ! grep -q -F '/.config/envman/load.fish' ~/.config/fish/config.fish; then
fn_echo_load_fish >> ~/.config/fish/config.fish
fi
fi
}
fn_echo_load_fish() {
echo ''
echo '# Generated for envman. Do not edit.'
# shellcheck disable=SC2016
echo 'test -s "$HOME/.config/envman/load.fish"; and source "$HOME/.config/envman/load.fish"'
}
fn_echo_load_sh() {
echo ''
echo '# Generated for envman. Do not edit.'
# shellcheck disable=SC2016
echo '[ -s "$HOME/.config/envman/load.sh" ] && source "$HOME/.config/envman/load.sh"'
}
fn_is_defined_in_all_shells() {
my_path="${1}"
my_path_expanded="$(
echo "${my_path}" |
sed -e "s${my_delim}\$HOME|${my_delim}$HOME${my_delim}g" \
-e "s${my_delim}\${HOME}${my_delim}$HOME${my_delim}g" \
-e "s${my_delim}^~/${my_delim}$HOME/${my_delim}g"
)"
my_paths="$(
echo "${my_path_expanded}"
# $HOME/foo
echo "${my_path_expanded}" |
sed "s${my_delim}${HOME}${my_delim}\$HOME${my_delim}g"
# ${HOME}/foo
echo "${my_path_expanded}" |
sed "s${my_delim}${HOME}${my_delim}\${HOME}${my_delim}g"
echo "${my_path}"
)"
my_confs="$(
echo "${HOME}/.profile"
echo "${HOME}/.bashrc"
echo "${HOME}/.zshrc"
echo "${HOME}/.config/fish/config.fish"
)"
for my_conf in $my_confs; do
if test -e "${my_conf}"; then
if ! grep -q -F "${my_paths}" "${my_conf}"; then
return 1
fi
fi
done
}
# group common pre-install tasks as default
webi_pre_install() {
webi_check_installed
webi_check_available
if test "git" = "${WEBI_EXT}"; then
webi_git_clone \
"${WEBI_PKG_URL}" \
"${WEBI_PKG_PATH}/${WEBI_PKG_FILE}"
return 0
fi
webi_download \
"${WEBI_PKG_URL}" \
"${WEBI_PKG_PATH}/${WEBI_PKG_FILE}"
webi_extract
}
# move commands from the extracted archive directory
# to $HOME/.local/opt or $HOME/.local/bin
webi_install() {
if test -n "${WEBI_SINGLE}"; then
mkdir -p "$(dirname "$pkg_src_cmd")"
mv ./"$pkg_cmd_name"* "$pkg_src_cmd"
else
rm -rf "$pkg_src"
mv ./"$pkg_cmd_name"* "$pkg_src"
fi
}
# run post-install functions - just updating PATH by default
webi_post_install() {
if test -n "${pkg_no_exec}"; then
return 0
fi
webi_path_add "$(dirname "$pkg_dst_cmd")"
}
_webi_enable_exec() {
if command -v spctl > /dev/null && command -v xattr > /dev/null; then
# note: some packages contain files that cannot be affected by xattr
xattr -r -d com.apple.quarantine "$pkg_src" || true
return 0
fi
}
_webi_done_message() {
my_dst_rel="$(
webi_sub_home "${pkg_dst_cmd}"
)"
my_canonical_name="$(
_webi_canonical_name
)"
echo "Installed ${my_canonical_name} as ${my_dst_rel}"
}
##
##
## BEGIN custom override functions from <package>/install.sh
##
##
WEBI_SINGLE=
if [ -z "${WEBI_WELCOME-}" ]; then
echo ""
printf "Thanks for using webi to install '\e[32m%s\e[0m' on '\e[33m%s (%s) %s\e[0m'.\n" "${WEBI_PKG:-"Unknown Package"}" "$(uname -s)" "${WEBI_LIBC:-"Unknown Libc"}" "$(uname -m)"
echo "Have a problem? Experience a bug? Please let us know:"
printf " \e[2m\e[36mhttps://github.com/webinstall/webi-installers/issues\e[0m\n"
echo ""
printf "\e[35mLovin'\e[0m it? Say thanks with a \e[1m\e[33mStar on GitHub\e[0m:\n"
printf " \e[36mhttps://github.com/webinstall/webi-installers\e[0m\n"
echo ""
fi
WEBI_WELCOME=true
export WEBI_WELCOME
__init_installer() {
# the installer will be injected here
# {{ installer }}
return 0
}
__init_installer
##
##
## END custom override functions
##
##
# run everything with defaults or overrides as needed
if command -v pkg_install > /dev/null ||
command -v pkg_link > /dev/null ||
command -v pkg_post_install > /dev/null ||
command -v pkg_done_message > /dev/null ||
command -v pkg_format_cmd_version > /dev/null ||
[ -n "${WEBI_SINGLE-}" ] ||
[ -n "${pkg_cmd_name-}" ] ||
[ -n "${pkg_dst_cmd-}" ] ||
[ -n "${pkg_dst_dir-}" ] ||
[ -n "${pkg_dst-}" ] ||
[ -n "${pkg_src_cmd-}" ] ||
[ -n "${pkg_src_dir-}" ] ||
[ -n "${pkg_src-}" ]; then
pkg_cmd_name="${pkg_cmd_name:-$PKG_NAME}"
pkg_no_exec="${pkg_no_exec:-}"
if [ -n "${pkg_no_exec}" ]; then
pkg_dst_cmd="${pkg_dst}"
pkg_src="${pkg_dst}"
pkg_src_cmd="${pkg_dst}"
elif [ -n "${WEBI_SINGLE}" ]; then
pkg_dst_cmd="${pkg_dst_cmd:-$HOME/.local/bin/$pkg_cmd_name}"
pkg_dst="$pkg_dst_cmd"
#pkg_src_cmd="${pkg_src_cmd:-$HOME/.local/opt/$pkg_cmd_name-v$WEBI_VERSION/bin/$pkg_cmd_name-v$WEBI_VERSION}"
pkg_src_cmd="${pkg_src_cmd:-$HOME/.local/opt/$pkg_cmd_name-v$WEBI_VERSION/bin/$pkg_cmd_name}"
pkg_src="$pkg_src_cmd"
else
pkg_dst="${pkg_dst:-$HOME/.local/opt/$pkg_cmd_name}"
pkg_dst_cmd="${pkg_dst_cmd:-$pkg_dst/bin/$pkg_cmd_name}"
pkg_src="${pkg_src:-$HOME/.local/opt/$pkg_cmd_name-v$WEBI_VERSION}"
pkg_src_cmd="${pkg_src_cmd:-$pkg_src/bin/$pkg_cmd_name}"
fi
# shellcheck disable=SC2034 # used in ${WEBI_PKG}/install.sh
pkg_src_bin="$(dirname "$pkg_src_cmd")"
# shellcheck disable=SC2034 # used in ${WEBI_PKG}/install.sh
pkg_dst_bin="$(dirname "$pkg_dst_cmd")"
if command -v pkg_pre_install > /dev/null; then pkg_pre_install; else webi_pre_install; fi
(
cd "$WEBI_TMP"
my_src_rel="$(
webi_sub_home "${pkg_src_cmd}"
)"
if test -e "${pkg_src_cmd}"; then
echo "Found ${my_src_rel} (remove to force reinstall)"
else
echo "Installing to ${my_src_rel}"
if command -v pkg_install > /dev/null; then pkg_install; else webi_install; fi
chmod a+x "$pkg_src"
chmod a+x "$pkg_src_cmd"
fi
)
if test -z "${pkg_no_exec}"; then
webi_link
_webi_enable_exec
fi
(
cd "$WEBI_TMP"
if command -v pkg_post_install > /dev/null; then pkg_post_install; else webi_post_install; fi
)
(
cd "$WEBI_TMP"
if command -v pkg_done_message > /dev/null; then pkg_done_message; else _webi_done_message; fi
)
echo ""
fi
webi_path_add "$HOME/.local/bin"
if [ -z "${_WEBI_CHILD-}" ] && [ -f "$_webi_tmp/.PATH.env" ]; then
if test -s "$_webi_tmp/.PATH.env"; then
printf 'PATH.env updated with:\n'
sort -u "$_webi_tmp/.PATH.env" | while read -r my_new_path; do
echo " ${my_new_path}"
done
printf "\n"
rm -f "$_webi_tmp/.PATH.env"
printf "\e[1m\e[35mTO FINISH\e[0m: copy, paste & run the following command:\n"
printf "\n"
printf " \e[1m\e[32msource ~/.config/envman/PATH.env\e[0m\n"
printf " (newly opened terminal windows will update automatically)\n"
fi
fi
rm -rf "$WEBI_TMP"
}
__bootstrap_webi

View File

@@ -1,34 +1,19 @@
'use strict';
var fs = require('node:fs');
var Installers = module.exports;
var Crypto = require('crypto');
var Fs = require('node:fs/promises');
var path = require('node:path');
var request = require('@root/request');
var _normalize = require('../_webi/normalize.js');
var reInstallTpl = /\s*#?\s*{{ installer }}/;
var Releases = module.exports;
Releases.get = async function (pkgdir) {
let get;
try {
get = require(path.join(pkgdir, 'releases.js'));
} catch (e) {
let err = new Error('no releases.js for', pkgdir.split(/[\/\\]+/).pop());
err.code = 'E_NO_RELEASE';
throw err;
}
let all = await get(request);
return _normalize(all);
};
function padScript(txt) {
return txt.replace(/^/g, ' ');
}
var BAD_SH_RE = /[<>'"`$\\]/;
Releases.renderBash = async function (
Installers.renderBash = async function (
pkgdir,
rel,
{ baseurl, pkg, tag, ver, os = '', arch = '', libc = '', formats },
@@ -39,10 +24,7 @@ Releases.renderBash = async function (
if (!tag) {
tag = '';
}
let installTxt = await fs.promises.readFile(
path.join(pkgdir, 'install.sh'),
'utf8',
);
let installTxt = await Fs.readFile(path.join(pkgdir, 'install.sh'), 'utf8');
installTxt = padScript(installTxt);
var vers = rel.version.split('.');
var v = {
@@ -55,8 +37,8 @@ Releases.renderBash = async function (
.replace(/^-/, ''),
};
var pkgFile = rel.filename || rel.name;
let tplTxt = await fs.promises.readFile(
path.join(__dirname, 'install-package.tpl.sh'),
let tplTxt = await Fs.readFile(
path.join(__dirname, 'package-install.tpl.sh'),
'utf8',
);
// ex: 'node@lts' or 'node'
@@ -90,14 +72,17 @@ Releases.renderBash = async function (
]
.join(',')
.replace(/'/g, '');
let webiChecksum = await Installers.getWebiShChecksum();
let envReplacements = [
['WEBI_CHECKSUM', webiChecksum],
['WEBI_PKG', webiPkg],
['WEBI_HOST', baseurl],
['WEBI_OS', os],
['WEBI_ARCH', arch],
['WEBI_LIBC', libc],
['WEBI_TAG', tag],
['WEBI_RELEASES', `${baseurl}/${releaseUrl}`],
['WEBI_RELEASES', `${baseurl}${releaseUrl}`],
['WEBI_CSV', releaseCsv],
['WEBI_VERSION', rel.version],
['WEBI_MAJOR', v.major],
@@ -127,7 +112,7 @@ Releases.renderBash = async function (
// #export WEBI_FOO=xyz => export WEBI_FOO='123'
// export WEBI_FOO= => export WEBI_FOO='123'
let envRe = new RegExp(
`^[ \\t]*#?[ \\t]*(export\\s)?[ \\t]*(${name})=.*`,
`^[ \\t]*#?[ \\t]*(export[ \\t])?[ \\t]*(${name})=.*`,
'm',
);
if (BAD_SH_RE.test(value)) {
@@ -145,7 +130,7 @@ Releases.renderBash = async function (
return tplTxt;
};
Releases.renderPowerShell = async function (
Installers.renderPowerShell = async function (
pkgdir,
rel,
{ baseurl, pkg, tag, ver, os, arch, libc = '', formats },
@@ -156,10 +141,7 @@ Releases.renderPowerShell = async function (
if (!tag) {
tag = '';
}
let installTxt = await fs.promises.readFile(
path.join(pkgdir, 'install.ps1'),
'utf8',
);
let installTxt = await Fs.readFile(path.join(pkgdir, 'install.ps1'), 'utf8');
installTxt = padScript(installTxt);
/*
var vers = rel.version.split('.');
@@ -173,8 +155,8 @@ Releases.renderPowerShell = async function (
.replace(/^-/, '')
};
*/
let tplTxt = await fs.promises.readFile(
path.join(__dirname, 'install-package.tpl.ps1'),
let tplTxt = await Fs.readFile(
path.join(__dirname, 'package-install.tpl.ps1'),
'utf8',
);
var pkgver = pkg + '@' + ver;
@@ -218,3 +200,32 @@ Releases.renderPowerShell = async function (
.replace(reInstallTpl, '\n' + installTxt)
);
};
var _webiShMeta = {
stale: 10 * 1000,
updated_at: 0,
checksum: '',
mtime: 0,
};
Installers.getWebiShChecksum = async function () {
let now = Date.now();
let ago = now - _webiShMeta.updated_at;
if (ago <= _webiShMeta.stale) {
return _webiShMeta.checksum;
}
let webiPath = path.join(__dirname, '../webi/webi.sh');
let stat = await Fs.stat(webiPath);
if (stat.mtimeMs === _webiShMeta.mtime) {
return _webiShMeta.checksum;
}
let webiBuf = await Fs.readFile(webiPath, null);
let webiHash = Crypto.createHash('sha1').update(webiBuf).digest('hex');
let webiChecksum = webiHash.slice(0, 8);
_webiShMeta.mtime = stat.mtimeMs;
_webiShMeta.updated_at = now;
_webiShMeta.checksum = webiChecksum;
return _webiShMeta.checksum;
};

View File

@@ -29,14 +29,14 @@ formats.forEach(function (name) {
// evaluation order matters
// (i.e. otherwise x86 and x64 can cross match)
var arches = [
// arm 7 cannot be confused with arm64
'armv7l',
// amd64 is more likely than arm64
'amd64',
// arm6 has the same prefix as arm64
'armv6l',
// arm64 is more likely than arm6, and should be the default
// arm64/aarch64 has very high specificity, so it comes first
'arm64',
// arm 7 is also generic aarch/arm/arm32
'armv7l',
// arm6 can run on armv7
'armv6l',
// amd64 is more likely and less often specified than arm64
'amd64',
'x86',
'ppc64le',
'ppc64',
@@ -50,13 +50,13 @@ var arches = [
// https://git.com/org/foo/releases/v0.7.9/foo-x86_64-linux-musl.tar.gz
//
var archMap = {
armv7l: /(\b|_)(arm32|armv?7l?)/i,
arm64: /(\b|_)(aarch64|arm64)/i,
armv7l: /(\b|_)(arm32|arm[_\-]?v?7l?)/i,
armv6l: /(\b|_)(arm|aarch32|arm[_\-]?v?6l?)(\b|_)/i,
//amd64: /(amd.?64|x64|[_\-]64)/i,
amd64:
/(\b|_|amd|(dar)?win(dows)?|mac(os)?|linux|osx|x)64([_\-]?bit)?(\b|_)/i,
//x86: /(86)(\b|_)/i,
armv6l: /(\b|_)(aarch32|armv?6l?)(\b|_)/i,
arm64: /(\b|_)((aarch|arm)64|arm)/i,
x86: /(\b|_|amd|(dar)?win(dows)?|mac(os)?|linux|osx|x)(86|32)([_\-]?bit)(\b|_)/i,
ppc64le: /(\b|_)(ppc64le)/i,
ppc64: /(\b|_)(ppc64)(\b|_)/i,

View File

@@ -69,7 +69,7 @@ function Invoke-DownloadUrl {
Write-Host " ?$Params"
$URL = "${URL}?${Params}"
}
curl.exe '-#' --fail-with-body -sS -A $Env:WEBI_UA $URL | Out-File $TmpPath
curl.exe '-#' -f -sS -A $Env:WEBI_UA -L $URL | Out-File $TmpPath
Remove-Item -Path $Path -Force -ErrorAction Ignore
Move-Item $TmpPath $Path

View File

@@ -0,0 +1,984 @@
#!/bin/sh
__bootstrap_webi() {
#PKG_NAME=
#WEBI_OS=
#WEBI_ARCH=
#WEBI_LIBC=
#WEBI_RELEASES=
#WEBI_CSV=
#WEBI_TAG=
#WEBI_VERSION=
#WEBI_MAJOR=
#WEBI_MINOR=
#WEBI_PATCH=
# TODO not sure if BUILD is the best name for this
#WEBI_BUILD=
#WEBI_GIT_TAG=
#WEBI_LTS=
#WEBI_CHANNEL=
#WEBI_EXT=
#WEBI_FORMATS=
#WEBI_PKG_URL=
#WEBI_PKG_FILE=
#WEBI_PKG_PATHNAME=
#PKG_OSES=
#PKG_ARCHES=
#PKG_LIBCS=
#PKG_FORMATS=
#PKG_LATEST=
WEBI_PKG_DOWNLOAD=""
WEBI_DOWNLOAD_DIR="${HOME}/Downloads"
if command -v xdg-user-dir > /dev/null; then
WEBI_DOWNLOAD_DIR="$(xdg-user-dir DOWNLOAD)"
if [ "${WEBI_DOWNLOAD_DIR}" = "${HOME}" ]; then
WEBI_DOWNLOAD_DIR="${HOME}/Downloads"
fi
fi
WEBI_PKG_PATH="${WEBI_DOWNLOAD_DIR}/webi/${PKG_NAME:-error}/${WEBI_VERSION:-latest}"
# get the special formatted version
# (i.e. "go is go1.14" while node is "node v12.10.8")
my_versioned_name=""
_webi_canonical_name() {
if [ -n "$my_versioned_name" ]; then
echo "$my_versioned_name"
return 0
fi
if command -v pkg_format_cmd_version > /dev/null; then
my_versioned_name="'$(pkg_format_cmd_version "$WEBI_VERSION")'"
else
my_versioned_name="'$pkg_cmd_name v$WEBI_VERSION'"
fi
echo "$my_versioned_name"
}
# Update symlinks as per $HOME/.local/opt and $HOME/.local/bin install paths.
webi_link() {
if command -v pkg_link > /dev/null; then
pkg_link
return 0
fi
if test -n "${WEBI_SINGLE}"; then
rm -rf "$pkg_dst_cmd"
ln -s "$pkg_src_cmd" "$pkg_dst_cmd"
else
# 'pkg_dst' will default to $HOME/.local/opt/<pkg>
# 'pkg_src' will be the installed version,
# such as to $HOME/.local/opt/<pkg>-<version>
rm -rf "$pkg_dst"
ln -s "$pkg_src" "$pkg_dst"
fi
}
# detect if this program is already installed
# or if an installed version may cause conflict
webi_check_installed() {
# Test for existing version
set +e
my_path="$PATH"
PATH="$(dirname "$pkg_dst_cmd"):$PATH"
export PATH
my_current_cmd="$(command -v "$pkg_cmd_name")"
set -e
if [ -n "$my_current_cmd" ]; then
my_canonical_name="$(_webi_canonical_name)"
if [ "$my_current_cmd" != "$pkg_dst_cmd" ]; then
echo >&2 " $(t_err "WARN: possible PATH conflict between $my_canonical_name and currently installed version")"
echo >&2 " $(t_path "${pkg_dst_cmd}") (new)"
echo >&2 " $(t_path "${my_current_cmd}") (existing)"
#my_current_version=false
fi
# 'readlink' can't read links in paths on macOS 🤦
# but that's okay, 'cmp -s' is good enough for us
if cmp -s "${pkg_src_cmd}" "${my_current_cmd}"; then
echo " $(t_pkg "${my_canonical_name}") already installed:"
my_dst_rel="$(fn_sub_home "${pkg_dst}")"
printf " %s" "$(t_link "${my_dst_rel}")"
if [ "${pkg_src_cmd}" != "${my_current_cmd}" ]; then
my_src_rel="$(fn_sub_home "${pkg_src}")"
printf " => %s" "$(t_path "${my_src_rel}")"
fi
echo ""
exit 0
fi
if [ -x "$pkg_src_cmd" ]; then
webi_link
echo " Switched to ${my_canonical_name}:"
my_src_rel="$(fn_sub_home "${pkg_src}")"
my_dst_rel="$(fn_sub_home "${pkg_dst}")"
echo " $(t_link "${my_dst_rel}") => $(t_path "${my_src_rel}")"
exit 0
fi
fi
export PATH="$my_path"
}
webi_check_available() {
if test "$WEBI_CHANNEL" != "error"; then
return 0
fi
{
echo ""
echo " $(t_err "Error: no '${PKG_NAME:-"Unknown Package"}@${WEBI_TAG:-"Unknown Tag"}' release for '${WEBI_OS:-"Unknown OS"}' (${WEBI_LIBC:-"Unknown Libc"}) on '${WEBI_ARCH:-"Unknown CPU"}' as one of '${WEBI_FORMATS:-"Unknown File Type"}'")"
echo ""
echo " CPUs: $PKG_ARCHES"
echo " OSes: $PKG_OSES"
echo " libcs: $PKG_LIBCS"
echo " Package Formats: $PKG_FORMATS"
echo " (check that the package name and version are correct)"
echo ""
my_release_url="$(echo "$WEBI_RELEASES" | sed 's:?.*::')"
my_release_params="$(echo "$WEBI_RELEASES" | sed 's:.*?:?:')"
echo " Double check at ${my_release_url}"
echo " ${my_release_params}"
echo ""
} >&2
exit 1
}
# detect if file is downloaded, and how to download it
webi_download() {
my_url="${1}"
my_dl="${2}"
my_dl_name="${3:-${PKG_NAME}}"
my_dl_rel="$(fn_sub_home "${my_dl}")"
WEBI_PKG_DOWNLOAD="${my_dl}"
export WEBI_PKG_DOWNLOAD
if [ -e "${my_dl}" ]; then
echo " $(t_dim 'Found') $(t_path "${my_dl_rel}")"
return 0
fi
echo " Downloading $(t_pkg "${my_dl_name}") from"
echo " $(t_url "${my_url}")"
fn_download_to_path "${my_url}" "${my_dl}"
echo " $(t_dim 'Saved as') $(t_path "${my_dl_rel}")"
}
webi_git_clone() { (
my_url="${1}"
my_dl="${2}"
my_dl_rel="$(fn_sub_home "${my_dl}")"
if [ -e "${my_dl}" ]; then
echo " $(t_dim 'Found') $(t_path "${my_dl_rel}")"
cp -RPp "${my_dl}" "${WEBI_TMP}/${WEBI_PKG_FILE}/"
return 0
fi
echo " Cloning $(t_url "${my_url}")"
cmd_git="git clone --config advice.detachedHead=false --quiet --depth=1 --single-branch"
rm -rf "${my_dl}.part"
if ! $cmd_git "${my_url}" --branch "${WEBI_GIT_TAG}" "${my_dl}.part"; then
echo >&2 " $(t_err "failed to git clone ${WEBI_PKG_URL}")"
exit 1
fi
mv "${my_dl}.part" "${my_dl}"
cp -RPp "${my_dl}" "${WEBI_TMP}/${WEBI_PKG_FILE}/"
); }
# detect which archives can be used
webi_extract() { (
cd "$WEBI_TMP"
my_dl_rel="$(
fn_sub_home "${WEBI_PKG_PATH}/${WEBI_PKG_FILE}"
)"
if [ "tar" = "$WEBI_EXT" ]; then
echo " Extracting $(t_path "${my_dl_rel}")"
tar xf "${WEBI_PKG_PATH}/$WEBI_PKG_FILE"
elif [ "zip" = "$WEBI_EXT" ]; then
echo " Extracting $(t_path "${my_dl_rel}")"
unzip "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" > __unzip__.log
elif [ "exe" = "$WEBI_EXT" ]; then
echo " Moving $(t_path "${my_dl_rel}")"
echo " to $(t_path "$(fn_sub_home "$(pwd)")")"
mv "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" .
elif [ "git" = "$WEBI_EXT" ]; then
echo " Moving $(t_path "${my_dl_rel}")"
mv "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" .
elif [ "xz" = "$WEBI_EXT" ]; then
echo " Inflating $(t_path "${my_dl_rel}")"
unxz -c "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" > "$(basename "$WEBI_PKG_FILE")"
else
echo " $(t_err 'Failed to extract') $(t_path "${WEBI_PKG_PATH}/$WEBI_PKG_FILE")"
exit 1
fi
); }
# use 'pathman' to update $HOME/.config/envman/PATH.env
webi_path_add() {
my_path="${1}"
fn_envman_init
# \v was chosen as it is extremely unlikely for a filename
# \1 could be an even better choice, but needs more testing.
# (currently tested working on: linux & mac)
# "\0001" should also work
my_delim="$(
printf '\v'
)"
my_path_expanded="$(
echo "${my_path}" |
sed -e "s${my_delim}\$HOME${my_delim}$HOME${my_delim}g" \
-e "s${my_delim}\${HOME}${my_delim}$HOME${my_delim}g" \
-e "s${my_delim}^~/${my_delim}$HOME/${my_delim}g"
)"
# A gift for @adamcstephens.
# See https://github.com/webinstall/webi-installers/issues/322
case "${PATH}" in
# matches whether the first, a middle, the last, or the only PATH entry
"${my_path_expanded}":* | \
*:"${my_path_expanded}":* | \
*:"${my_path_expanded}" | \
"${my_path_expanded}")
if fn_is_defined_in_all_shells "${my_path}"; then
return 0
fi
;;
*) ;;
esac
my_path_export="$(
echo "${my_path}" |
sed -e "s${my_delim}${HOME}${my_delim}\$HOME${my_delim}g" \
-e "s${my_delim}\${HOME}${my_delim}\$HOME${my_delim}g" \
-e "s${my_delim}^~/${my_delim}\$HOME/${my_delim}g"
)"
my_export="export PATH=\"$my_path_export:\$PATH\""
touch -a ~/.config/envman/PATH.env
if grep -q -F "${my_export}" ~/.config/envman/PATH.env; then
return 0
fi
echo "${my_export}" >> ~/.config/envman/PATH.env
mkdir -p "$_webi_tmp"
my_path_tilde="$(
echo "${my_path}" |
sed -e "s${my_delim}${HOME}${my_delim}~${my_delim}g"
)"
if ! test -f "$_webi_tmp/.PATH.env" ||
! grep -q -F "${my_path_tilde}" "$_webi_tmp/.PATH.env"; then
echo "${my_path_tilde}" >> "$_webi_tmp/.PATH.env"
fi
}
fn_is_defined_in_all_shells() {
my_path="${1}"
my_path_expanded="$(
echo "${my_path}" |
sed -e "s${my_delim}\$HOME|${my_delim}$HOME${my_delim}g" \
-e "s${my_delim}\${HOME}${my_delim}$HOME${my_delim}g" \
-e "s${my_delim}^~/${my_delim}$HOME/${my_delim}g"
)"
my_paths="$(
echo "${my_path_expanded}"
# $HOME/foo
echo "${my_path_expanded}" |
sed "s${my_delim}${HOME}${my_delim}\$HOME${my_delim}g"
# ${HOME}/foo
echo "${my_path_expanded}" |
sed "s${my_delim}${HOME}${my_delim}\${HOME}${my_delim}g"
echo "${my_path}"
)"
my_confs="$(
echo "${HOME}/.profile"
echo "${HOME}/.bashrc"
echo "${HOME}/.zshrc"
echo "${HOME}/.config/fish/config.fish"
)"
for my_conf in $my_confs; do
if ! test -e "${my_conf}"; then
continue
fi
if ! grep -q -F "${my_paths}" "${my_conf}"; then
return 1
fi
done
}
# group common pre-install tasks as default
webi_pre_install() {
webi_check_installed
webi_check_available
if test "git" = "${WEBI_EXT}"; then
webi_git_clone \
"${WEBI_PKG_URL}" \
"${WEBI_PKG_PATH}/${WEBI_PKG_FILE}"
return 0
fi
webi_download \
"${WEBI_PKG_URL}" \
"${WEBI_PKG_PATH}/${WEBI_PKG_FILE}"
webi_extract
}
# move commands from the extracted archive directory
# to $HOME/.local/opt or $HOME/.local/bin
webi_install() {
b_src=''
if test -n "${WEBI_SINGLE}"; then
b_src="${pkg_src_cmd}"
mkdir -p "$(dirname "$pkg_src_cmd")"
else
echo " Removing $(t_path "${pkg_src}")"
rm -rf "$pkg_src"
b_src="${pkg_src}"
fi
echo " Moving $(t_path "${pkg_cmd_name}")"
echo " to $(t_path "$(fn_sub_home "${b_src}")")"
mv ./"${pkg_cmd_name}"* "${b_src}"
}
# run post-install functions - just updating PATH by default
webi_post_install() {
if test -n "${pkg_no_exec}"; then
return 0
fi
webi_path_add "$(dirname "$pkg_dst_cmd")"
}
_webi_enable_exec() {
if command -v spctl > /dev/null && command -v xattr > /dev/null; then
# note: some packages contain files that cannot be affected by xattr
xattr -r -d com.apple.quarantine "$pkg_src" || true
return 0
fi
}
_webi_done_message() {
my_dst_rel="$(fn_sub_home "${pkg_dst_cmd}")"
my_canonical_name="$(_webi_canonical_name)"
echo ""
echo " Installed $(t_pkg "${my_canonical_name}") as $(t_link "${my_dst_rel}")"
}
##
## Set up tmp, download, and install directories
##
WEBI_TMP=${WEBI_TMP:-"$(mktemp -d -t webinstall-"${WEBI_PKG-}".XXXXXXXX)"}
export _webi_tmp="${_webi_tmp:-"$HOME/.local/opt/webi-tmp.d"}"
mkdir -p "${WEBI_PKG_PATH}"
mkdir -p "$HOME/.local/bin"
mkdir -p "$HOME/.local/opt"
if test -e ~/.local/bin; then
echo " $(t_dim 'Found') $(t_path ' ~/.local/bin')"
else
echo " Creating$(t_path ' ~/.local/bin')"
mkdir -p "$HOME/.local/bin"
fi
##
##
## BEGIN custom override functions from <package>/install.sh
##
##
WEBI_SINGLE=
__init_installer() {
# the installer will be injected here
# {{ installer }}
return 0
}
__init_installer
##
##
## END custom override functions
##
##
# run everything with defaults or overrides as needed
if command -v pkg_install > /dev/null ||
command -v pkg_link > /dev/null ||
command -v pkg_post_install > /dev/null ||
command -v pkg_done_message > /dev/null ||
command -v pkg_format_cmd_version > /dev/null ||
[ -n "${WEBI_SINGLE-}" ] ||
[ -n "${pkg_cmd_name-}" ] ||
[ -n "${pkg_dst_cmd-}" ] ||
[ -n "${pkg_dst_dir-}" ] ||
[ -n "${pkg_dst-}" ] ||
[ -n "${pkg_src_cmd-}" ] ||
[ -n "${pkg_src_dir-}" ] ||
[ -n "${pkg_src-}" ]; then
pkg_cmd_name="${pkg_cmd_name:-$PKG_NAME}"
pkg_no_exec="${pkg_no_exec:-}"
if [ -n "${pkg_no_exec}" ]; then
pkg_dst_cmd="${pkg_dst}"
pkg_src="${pkg_dst}"
pkg_src_cmd="${pkg_dst}"
elif [ -n "${WEBI_SINGLE}" ]; then
pkg_dst_cmd="${pkg_dst_cmd:-$HOME/.local/bin/$pkg_cmd_name}"
pkg_dst="$pkg_dst_cmd"
#pkg_src_cmd="${pkg_src_cmd:-$HOME/.local/opt/$pkg_cmd_name-v$WEBI_VERSION/bin/$pkg_cmd_name-v$WEBI_VERSION}"
pkg_src_cmd="${pkg_src_cmd:-$HOME/.local/opt/$pkg_cmd_name-v$WEBI_VERSION/bin/$pkg_cmd_name}"
pkg_src="$pkg_src_cmd"
else
pkg_dst="${pkg_dst:-$HOME/.local/opt/$pkg_cmd_name}"
pkg_dst_cmd="${pkg_dst_cmd:-$pkg_dst/bin/$pkg_cmd_name}"
pkg_src="${pkg_src:-$HOME/.local/opt/$pkg_cmd_name-v$WEBI_VERSION}"
pkg_src_cmd="${pkg_src_cmd:-$pkg_src/bin/$pkg_cmd_name}"
fi
# shellcheck disable=SC2034 # used in ${WEBI_PKG}/install.sh
pkg_src_bin="$(dirname "$pkg_src_cmd")"
# shellcheck disable=SC2034 # used in ${WEBI_PKG}/install.sh
pkg_dst_bin="$(dirname "$pkg_dst_cmd")"
if command -v pkg_pre_install > /dev/null; then pkg_pre_install; else webi_pre_install; fi
(
cd "$WEBI_TMP"
my_src_rel="$(
fn_sub_home "${pkg_src_cmd}"
)"
if test -e "${pkg_src_cmd}"; then
echo " $(t_dim 'Found') $(t_path "${my_src_rel}") $(t_dim '(remove to force reinstall)')"
else
echo " Installing to $(t_path "${my_src_rel}")"
if command -v pkg_install > /dev/null; then pkg_install; else webi_install; fi
chmod a+x "$pkg_src"
chmod a+x "$pkg_src_cmd"
fi
)
if test -z "${pkg_no_exec}"; then
webi_link
_webi_enable_exec
fi
(
cd "$WEBI_TMP"
if command -v pkg_post_install > /dev/null; then pkg_post_install; else webi_post_install; fi
)
(
cd "$WEBI_TMP"
if command -v pkg_done_message > /dev/null; then pkg_done_message; else _webi_done_message; fi
)
echo ""
fi
webi_path_add "$HOME/.local/bin"
if [ -z "${_WEBI_CHILD-}" ] && [ -f "$_webi_tmp/.PATH.env" ]; then
if test -s "$_webi_tmp/.PATH.env"; then
# shellcheck disable=SC2088 # ~ should not expand here
echo " Edit $(t_path '~/.config/envman/PATH.env') to add:"
sort -u "$_webi_tmp/.PATH.env" | while read -r my_new_path; do
echo " $(t_path "${my_new_path}")"
done
echo ""
rm -f "$_webi_tmp/.PATH.env"
echo ">>> $(t_info 'ACTION REQUIRED') <<<"
echo " Copy, paste & run the following command:"
echo " $(t_attn 'source ~/.config/envman/PATH.env')"
echo " (newly opened terminal windows will update automatically)"
echo ""
fi
fi
rm -rf "$WEBI_TMP"
}
#########################################
# #
# Display Debug Info in Case of Failure #
# #
#########################################
fn_show_welcome_back() { (
if test -n "${WEBI_WELCOME:-}"; then
return 0
fi
echo ""
# invert t_task and t_pkg for top-level welcome message
printf -- ">>> %s %s <<<\n" \
"$(t_pkg 'Welcome to') $(t_task 'Webi')$(t_pkg '!')" \
"$(t_dim "- modern tools, instant installs.")"
echo " We expect your experience to be $(t_em 'absolutely perfect')!"
echo ""
echo " $(t_attn 'Success')? Star it! $(t_url 'https://github.com/webinstall/webi-installers')"
echo " $(t_attn 'Problem')? Report it: $(t_url 'https://github.com/webinstall/webi-installers/issues')"
echo " $(t_dim "(your system is") $(t_host "$(fn_get_os)")/$(t_host "$(uname -m)") $(t_dim "with") $(t_host "$(fn_get_libc)") $(t_dim "&") $(t_host "$(fn_get_http_client_name)")$(t_dim ")")"
sleep 0.2
); }
fn_get_os() { (
# Ex:
# GNU/Linux
# Android
# Linux (often Alpine, musl)
# Darwin
b_os="$(uname -o 2> /dev/null || echo '')"
b_sys="$(uname -s)"
if test -z "${b_os}" || test "${b_os}" = "${b_sys}"; then
# ex: 'Darwin' (and plain, non-GNU 'Linux')
echo "${b_sys}"
return 0
fi
if echo "${b_os}" | grep -q "${b_sys}"; then
# ex: 'GNU/Linux'
echo "${b_os}"
return 0
fi
# ex: 'Android/Linux'
echo "${b_os}/${b_sys}"
); }
fn_get_libc() { (
# Ex:
# musl
# libc
if ldd /bin/ls 2> /dev/null | grep -q 'musl' 2> /dev/null; then
echo 'musl'
elif fn_get_os | grep -q 'GNU|Linux'; then
echo 'gnu'
else
echo 'libc'
fi
); }
fn_get_http_client_name() { (
# Ex:
# curl
# curl+wget
b_client=""
if command -v curl > /dev/null; then
b_client="curl"
fi
if command -v wget > /dev/null; then
if test -z "${b_client}"; then
b_client="wget"
else
b_client="curl+wget"
fi
fi
echo "${b_client}"
); }
#########################################
# #
# For Making the Display Nice #
# #
#########################################
# Term Types
t_cmd() { (fn_printf '\e[2m\e[35m%s\e[39m\e[22m' "${1}"); }
t_host() { (fn_printf '\e[2m\e[33m%s\e[39m\e[22m' "${1}"); }
t_link() { (fn_printf '\e[1m\e[36m%s\e[39m\e[22m' "${1}"); }
t_path() { (fn_printf '\e[2m\e[32m%s\e[39m\e[22m' "${1}"); }
t_pkg() { (fn_printf '\e[1m\e[32m%s\e[39m\e[22m' "${1}"); }
t_task() { (fn_printf '\e[36m%s\e[39m' "${1}"); }
t_url() { (fn_printf '\e[2m%s\e[22m' "${1}"); }
# Levels
t_info() { (fn_printf '\e[1m\e[36m%s\e[39m\e[22m' "${1}"); }
t_attn() { (fn_printf '\e[1m\e[33m%s\e[39m\e[22m' "${1}"); }
t_warn() { (fn_printf '\e[1m\e[33m%s\e[39m\e[22m' "${1}"); }
t_err() { (fn_printf '\e[31m%s\e[39m' "${1}"); }
# Styles
t_bold() { (fn_printf '\e[1m%s\e[22m' "${1}"); }
t_dim() { (fn_printf '\e[2m%s\e[22m' "${1}"); }
t_em() { (fn_printf '\e[3m%s\e[23m' "${1}"); }
t_under() { (fn_printf '\e[4m%s\e[24m' "${1}"); }
# FG Colors
t_cyan() { (fn_printf '\e[36m%s\e[39m' "${1}"); }
t_green() { (fn_printf '\e[32m%s\e[39m' "${1}"); }
t_magenta() { (fn_printf '\e[35m%s\e[39m' "${1}"); }
t_yellow() { (fn_printf '\e[33m%s\e[39m' "${1}"); }
fn_printf() { (
a_style="${1}"
a_text="${2}"
if fn_is_tty; then
#shellcheck disable=SC2059
printf -- "${a_style}" "${a_text}"
else
printf -- '%s' "${a_text}"
fi
); }
fn_sub_home() { (
my_rel=${HOME}
my_abs=${1}
echo "${my_abs}" | sed "s:^${my_rel}:~:"
); }
###################################
# #
# Detect HTTP Client #
# #
###################################
fn_wget() { (
# Doc:
# Downloads the file at the given url to the given path
a_url="${1}"
a_path="${2}"
cmd_wget="wget -c -q --user-agent"
if fn_is_tty; then
cmd_wget="wget -c -q --show-progress --user-agent"
fi
# busybox wget doesn't support --show-progress
# See <https://github.com/webinstall/webi-installers/pull/772>
if readlink "$(command -v wget)" | grep -q busybox; then
cmd_wget="wget --user-agent"
fi
b_triple_ua="$(fn_get_target_triple_user_agent)"
b_agent="webi/wget ${b_triple_ua}"
if command -v curl > /dev/null; then
b_agent="webi/wget+curl ${b_triple_ua}"
fi
if ! $cmd_wget "${b_agent}" "${a_url}" -O "${a_path}"; then
echo >&2 " $(t_err "failed to download (wget)") '$(t_url "${a_url}")'"
echo >&2 " $cmd_wget '${b_agent}' '${a_url}' -O '${a_path}'"
echo >&2 " $(wget -V)"
return 1
fi
); }
fn_curl() { (
# Doc:
# Downloads the file at the given url to the given path
a_url="${1}"
a_path="${2}"
cmd_curl="curl -f -sSL -#"
if fn_is_tty; then
cmd_curl="curl -f -sSL"
fi
b_triple_ua="$(fn_get_target_triple_user_agent)"
b_agent="webi/curl ${b_triple_ua}"
if command -v wget > /dev/null; then
b_agent="webi/curl+wget ${b_triple_ua}"
fi
if ! $cmd_curl -A "${b_agent}" "${a_url}" -o "${a_path}"; then
echo >&2 " $(t_err "failed to download (curl)") '$(t_url "${a_url}")'"
echo >&2 " $cmd_curl -A '${b_agent}' '${a_url}' -o '${a_path}'"
echo >&2 " $(curl -V)"
return 1
fi
); }
fn_get_target_triple_user_agent() { (
# Ex:
# x86_64/unknown GNU/Linux/5.15.107-2-pve gnu
# arm64/unknown Darwin/22.6.0 libc
echo "$(uname -m)/unknown $(fn_get_os)/$(uname -r) $(fn_get_libc)"
); }
fn_download_to_path() { (
a_url="${1}"
a_path="${2}"
mkdir -p "$(dirname "${a_path}")"
if command -v curl > /dev/null; then
fn_curl "${a_url}" "${a_path}.part"
elif command -v wget > /dev/null; then
fn_wget "${a_url}" "${a_path}.part"
else
echo >&2 " $(t_err "failed to detect HTTP client (curl, wget)")"
return 1
fi
mv "${a_path}.part" "${a_path}"
); }
##############################################
# #
# Install or Update Webi and Install Package #
# #
##############################################
webi_upgrade() { (
a_path="${1}"
b_path_rel="$(fn_sub_home "${a_path}")"
b_checksum=""
if test -r "${a_path}"; then
b_checksum="$(fn_checksum "${a_path}")"
fi
if test "$b_checksum" = "${WEBI_CHECKSUM}"; then
sleep 0.1
return 0
fi
b_webi_file_url="${WEBI_HOST}/packages/webi/webi.sh"
b_tmp=''
if test -r "${a_path}"; then
b_ts="$(date -u '+%s')"
b_tmp="${a_path}.${b_ts}.bak"
mv "${a_path}" "${b_tmp}"
echo ""
echo "$(t_task 'Updating') $(t_pkg 'Webi')"
fi
echo " Downloading $(t_url "${b_webi_file_url}")"
echo " to $(t_path "${b_path_rel}")"
fn_download_to_path "${b_webi_file_url}" "${a_path}"
chmod u+x "${a_path}"
if test -r "${b_tmp}"; then
rm -f "${b_tmp}"
fi
); }
fn_checksum() {
a_filepath="${1}"
cmd_shasum='sha1sum'
if command -v shasum > /dev/null; then
cmd_shasum='shasum'
fi
$cmd_shasum "${a_filepath}" | cut -d' ' -f1 | cut -c 1-8
}
##############################################
# #
# Detect TTY and run main #
# #
##############################################
fn_is_tty() {
if test "${WEBI_TTY}" = 'tty'; then
return 0
fi
return 1
}
fn_detect_tty() { (
# stdin will NOT be a tty if it's being piped
# stdout & stderr WILL be a tty even when piped
# they are not a tty if being captured or redirected
# 'set -i' is NOT available in sh
if test -t 1 && test -t 2; then
return 0
fi
return 1
); }
main() { (
set -e
set -u
#set -x
export WEBI_HOST=
export WEBI_CHECKSUM=
export WEBI_PKG=
WEBI_TTY="${WEBI_TTY:-}"
if test -z "${WEBI_TTY}"; then
if fn_detect_tty; then
WEBI_TTY="tty"
fi
export WEBI_TTY
fi
if test -z "${WEBI_WELCOME:-}"; then
fn_show_welcome_back
fi
export WEBI_WELCOME='shown'
# note: we may support custom locations in the future
export WEBI_HOME="${HOME}/.local"
b_webi_path="${WEBI_HOME}/bin/webi"
WEBI_CURRENT="${WEBI_CURRENT:-}"
if test "${WEBI_CURRENT}" != "${WEBI_CHECKSUM}"; then
webi_upgrade "${b_webi_path}"
export WEBI_CURRENT="${WEBI_CHECKSUM}"
fi
echo "$(t_task 'Installing') $(t_pkg "${WEBI_PKG}") $(t_task '...')"
__bootstrap_webi
); }
##############################################
# #
# envman helper functions #
# #
##############################################
fn_envman_init() { (
if ! test -r ~/.config/envman/; then
echo " Initializing ~/.config/envman/"
mkdir -p ~/.config/envman/
fi
# Note: the variables $BASH, $ZSH_NAME, etc are always empty
# because the active shell is always sh when this script runs
fn_envman_init_load_sh
fn_envman_init_shell sh '.profile' '.ash_history'
fn_envman_init_shell bash '.bashrc' '.bash_history'
fn_envman_init_shell zsh '.zshrc' '.zsh_sessions'
if command -v fish > /dev/null; then
fn_envman_init_load_fish
fn_envman_init_fish
fi
); }
fn_envman_init_load_sh() { (
touch -a ~/.config/envman/load.sh
if grep -q -F 'ENVMAN_LOAD' ~/.config/envman/load.sh; then
return 0
fi
cat << LOAD_SH > ~/.config/envman/load.sh
# Generated for envman. Do not edit.
# shellcheck disable=SC1090
touch -a ~/.config/envman/PATH.env
touch -a ~/.config/envman/ENV.env
touch -a ~/.config/envman/alias.env
touch -a ~/.config/envman/function.sh
# ENV first because we may use it in PATH
test -z "\${ENVMAN_LOAD:-}" && . ~/.config/envman/ENV.env
test -z "\${ENVMAN_LOAD:-}" && . ~/.config/envman/PATH.env
export ENVMAN_LOAD='loaded'
# function first because we may use it in alias
test -z "\${g_envman_load_sh:-}" && . ~/.config/envman/function.sh
test -z "\${g_envman_load_sh:-}" && . ~/.config/envman/alias.env
g_envman_load_sh='loaded'
LOAD_SH
); }
fn_envman_init_shell() { (
a_shell="${1}"
a_rc="${2}"
a_history="${3:-_history_file_doesnt_exist}"
a_login_shell="$(basename "${SHELL:-}")"
if ! command -v "${a_shell}" > /dev/null; then
return 0
fi
# .bashrc and .zshrc no longer exist by default on macOS
if ! test -e ~/"${a_rc}" && ! test -e ~/"${a_history}"; then
if test "${a_login_shell}" != "${a_shell}"; then
return 0
fi
fi
touch -a ~/"${a_rc}"
if grep -q -F '/.config/envman/load.sh' ~/"${a_rc}"; then
return 0
fi
# shellcheck disable=SC2088 # ~ should not expand here
echo >&2 " Edit $(t_path "~/${a_rc}") to $(t_cmd "source ~/.config/envman/load.sh")"
{
echo ''
echo '# Generated for envman. Do not edit.'
#shellcheck disable=SC2016 # vars should not expand here
echo '[ -s "$HOME/.config/envman/load.sh" ] && source "$HOME/.config/envman/load.sh"'
} >> ~/"${a_rc}"
); }
fn_envman_init_load_fish() { (
mkdir -p ~/.config/envman/
touch -a ~/.config/envman/load.fish
if grep -q -F 'ENVMAN_LOAD' ~/.config/envman/load.fish; then
return 0
fi
echo >&2 " Create ~/.config/envman/load.fish"
cat << EOF > ~/.config/envman/load.fish
# Generated for envman. Do not edit.
touch -a ~/.config/envman/PATH.env
touch -a ~/.config/envman/ENV.env
touch -a ~/.config/envman/alias.env
touch -a ~/.config/envman/function.fish
not set -q ENVMAN_LOAD; and source ~/.config/envman/ENV.env
not set -q ENVMAN_LOAD; and source ~/.config/envman/PATH.env
set -x ENVMAN_LOAD 'loaded'
not set -q g_envman_load_fish; and source ~/.config/envman/function.fish
not set -q g_envman_load_fish; and source ~/.config/envman/alias.env
set -g g_envman_load_fish 'loaded'
EOF
); }
fn_envman_init_fish() {
mkdir -p ~/.config/fish/
touch -a ~/.config/fish/config.fish
if grep -q -F '/.config/envman/load.fish' ~/.config/fish/config.fish; then
return 0
fi
# shellcheck disable=SC2088 # ~ should not expand here
echo >&2 " Edit $(t_path "~/.config/fish/config.fish") to $(t_cmd "source ~/.config/envman/load.fish")"
cat << EOF >> ~/.config/fish/config.fish
# Generated for envman. Do not edit.
test -s ~/.config/envman/load.fish; and source ~/.config/envman/load.fish
EOF
}
main

View File

@@ -1,96 +0,0 @@
'use strict';
var frontmarker = require('./frontmarker.js');
var fs = require('fs');
var path = require('path');
var pkgs = module.exports;
pkgs.create = function (Pkgs, basepath) {
if (!Pkgs) {
Pkgs = {};
}
if (!basepath) {
basepath = path.join(__dirname, '../');
}
Pkgs.all = function () {
return fs.promises.readdir(basepath).then(function (nodes) {
var items = [];
return nodes
.reduce(function (p, node) {
return p.then(function () {
return pkgs.get(node).then(function (meta) {
if (meta && '_' !== node[0]) {
meta.name = node;
items.push(meta);
}
});
});
}, Promise.resolve())
.then(function () {
return items;
});
});
};
Pkgs.get = function (node) {
return fs.promises.access(path.join(basepath, node)).then(function () {
return Pkgs._get(node);
});
};
Pkgs._get = function (node) {
var curlbash = path.join(basepath, node, 'install.sh');
var readme = path.join(basepath, node, 'README.md');
var winstall = path.join(basepath, node, 'install.ps1');
return Promise.all([
fs.promises
.readFile(readme, 'utf-8')
.then(function (txt) {
// TODO
return frontmarker.parse(txt);
})
.catch(function (e) {
if ('ENOENT' !== e.code && 'ENOTDIR' !== e.code) {
console.error("failed to read '" + node + "/README.md'");
console.error(e);
}
}),
fs.promises.access(curlbash).catch(function (e) {
// no *nix installer
curlbash = '';
if ('ENOENT' !== e.code && 'ENOTDIR' !== e.code) {
console.error("failed to parse '" + node + "/install.sh'");
console.error(e);
}
}),
fs.promises.access(winstall).catch(function (e) {
// no winstaller
winstall = '';
if ('ENOENT' !== e.code && 'ENOTDIR' !== e.code) {
console.error("failed to read '" + node + "/install.ps1'");
console.error(e);
}
}),
]).then(function (items) {
var meta = items[0] || items[1];
if (!meta) {
// doesn't exist
return;
}
meta.windows = !!winstall;
meta.bash = !!curlbash;
return meta;
});
};
return Pkgs;
};
pkgs.create(pkgs);
if (module === require.main) {
pkgs.all().then(function (data) {
console.info('package info:');
console.info(data);
});
}

1
_webi/packages.js Symbolic link
View File

@@ -0,0 +1 @@
projects.js

96
_webi/projects.js Normal file
View File

@@ -0,0 +1,96 @@
'use strict';
var frontmarker = require('./frontmarker.js');
var fs = require('fs');
var path = require('path');
var pkgs = module.exports;
pkgs.create = function (Pkgs, basepath) {
if (!Pkgs) {
Pkgs = {};
}
if (!basepath) {
basepath = path.join(__dirname, '../');
}
Pkgs.all = function () {
return fs.promises.readdir(basepath).then(function (nodes) {
var items = [];
return nodes
.reduce(function (p, node) {
return p.then(function () {
return pkgs.get(node).then(function (meta) {
if (meta && '_' !== node[0]) {
meta.name = node;
items.push(meta);
}
});
});
}, Promise.resolve())
.then(function () {
return items;
});
});
};
Pkgs.get = function (node) {
return fs.promises.access(path.join(basepath, node)).then(function () {
return Pkgs._get(node);
});
};
Pkgs._get = function (node) {
var curlbash = path.join(basepath, node, 'install.sh');
var readme = path.join(basepath, node, 'README.md');
var winstall = path.join(basepath, node, 'install.ps1');
return Promise.all([
fs.promises
.readFile(readme, 'utf-8')
.then(function (txt) {
// TODO
return frontmarker.parse(txt);
})
.catch(function (e) {
if ('ENOENT' !== e.code && 'ENOTDIR' !== e.code) {
console.error("failed to read '" + node + "/README.md'");
console.error(e);
}
}),
fs.promises.access(curlbash).catch(function (e) {
// no *nix installer
curlbash = '';
if ('ENOENT' !== e.code && 'ENOTDIR' !== e.code) {
console.error("failed to parse '" + node + "/install.sh'");
console.error(e);
}
}),
fs.promises.access(winstall).catch(function (e) {
// no winstaller
winstall = '';
if ('ENOENT' !== e.code && 'ENOTDIR' !== e.code) {
console.error("failed to read '" + node + "/install.ps1'");
console.error(e);
}
}),
]).then(function (items) {
var meta = items[0] || items[1];
if (!meta) {
// doesn't exist
return;
}
meta.windows = !!winstall;
meta.bash = !!curlbash;
return meta;
});
};
return Pkgs;
};
pkgs.create(pkgs);
if (module === require.main) {
pkgs.all().then(function (data) {
console.info('package info:');
console.info(data);
});
}

View File

@@ -1,20 +1,19 @@
'use strict';
var Installers = module.exports;
var InstallerServer = module.exports;
var Crypto = require('crypto');
var Fs = require('fs/promises');
var path = require('path');
var uaDetect = require('./ua-detect.js');
var packages = require('./packages.js');
var Releases = require('./releases.js');
var Projects = require('./projects.js');
var Installers = require('./installers.js');
// handlers caching and transformation, probably should be broken down
var getReleases = require('./transform-releases.js');
var Releases = require('./transform-releases.js');
Installers.INSTALLERS_DIR = path.join(__dirname, '..');
Installers.serveInstaller = async function (
InstallerServer.INSTALLERS_DIR = path.join(__dirname, '..');
InstallerServer.serveInstaller = async function (
baseurl,
ua,
pkg,
@@ -23,7 +22,7 @@ Installers.serveInstaller = async function (
formats,
libc,
) {
let [rel, opts] = await Installers.helper({
let [rel, opts] = await InstallerServer.helper({
ua,
pkg,
tag,
@@ -34,13 +33,13 @@ Installers.serveInstaller = async function (
baseurl,
});
var pkgdir = path.join(Installers.INSTALLERS_DIR, pkg);
var pkgdir = path.join(InstallerServer.INSTALLERS_DIR, pkg);
if ('ps1' === ext) {
return Releases.renderPowerShell(pkgdir, rel, opts);
return Installers.renderPowerShell(pkgdir, rel, opts);
}
return Releases.renderBash(pkgdir, rel, opts);
return Installers.renderBash(pkgdir, rel, opts);
};
Installers.helper = async function ({ ua, pkg, tag, formats, libc }) {
InstallerServer.helper = async function ({ ua, pkg, tag, formats, libc }) {
// TODO put some of this in a middleware? or common function?
// TODO maybe move package/version/lts/channel detection into getReleases
@@ -85,7 +84,7 @@ Installers.helper = async function ({ ua, pkg, tag, formats, libc }) {
myLibc = 'libc';
}
let cfg = await packages.get(pkg);
let cfg = await Projects.get(pkg);
let releaseQuery = {
pkg: cfg.alias || pkg,
ver,
@@ -100,7 +99,7 @@ Installers.helper = async function ({ ua, pkg, tag, formats, libc }) {
limit: 1,
};
let rels = await getReleases(releaseQuery);
let rels = await Releases.getReleases(releaseQuery);
var rel = rels.releases[0];
var opts = {
@@ -132,7 +131,11 @@ var CURL_PIPE_PS1_BOOT = path.join(__dirname, 'curl-pipe-bootstrap.tpl.ps1');
var CURL_PIPE_SH_BOOT = path.join(__dirname, 'curl-pipe-bootstrap.tpl.sh');
var BAD_SH_RE = /[<>'"`$\\]/;
Installers.getPosixCurlPipeBootstrap = async function ({ baseurl, pkg, ver }) {
InstallerServer.getPosixCurlPipeBootstrap = async function ({
baseurl,
pkg,
ver,
}) {
let bootTxt = await Fs.readFile(CURL_PIPE_SH_BOOT, 'utf8');
var webiPkg = [pkg, ver].filter(Boolean).join('@');
@@ -149,7 +152,7 @@ Installers.getPosixCurlPipeBootstrap = async function ({ baseurl, pkg, ver }) {
// TODO create REs once, in higher scope
let envRe = new RegExp(
`^[ \\t]*#?[ \\t]*(export\\s)?[ \\t]*(${name})=.*`,
`^[ \\t]*#?[ \\t]*(export[ \\t])?[ \\t]*(${name})=.*`,
'm',
);
@@ -165,7 +168,7 @@ Installers.getPosixCurlPipeBootstrap = async function ({ baseurl, pkg, ver }) {
return bootTxt;
};
Installers.getPwshCurlPipeBootstrap = async function ({
InstallerServer.getPwshCurlPipeBootstrap = async function ({
baseurl,
pkg,
ver,
@@ -174,7 +177,7 @@ Installers.getPwshCurlPipeBootstrap = async function ({
let bootTxt = await Fs.readFile(CURL_PIPE_PS1_BOOT, 'utf8');
var webiPkg = [pkg, ver].filter(Boolean).join('@');
//var webiChecksum = await Installers.getWebiPs1Checksum();
//var webiChecksum = await InstallerServer.getWebiPs1Checksum();
var envReplacements = [
['Env:WEBI_PKG', webiPkg],
['Env:WEBI_HOST', baseurl],
@@ -209,32 +212,3 @@ Installers.getPwshCurlPipeBootstrap = async function ({
return bootTxt;
};
var _webiShMeta = {
stale: 10 * 1000,
updated_at: 0,
checksum: '',
mtime: 0,
};
Installers.getWebiShChecksum = async function () {
let now = Date.now();
let ago = now - _webiShMeta.updated_at;
if (ago <= _webiShMeta.stale) {
return _webiShMeta.checksum;
}
let webiPath = path.join(__dirname, '../webi/webi.sh');
let stat = await Fs.stat(webiPath);
if (stat.mtimeMs === _webiShMeta.mtime) {
return _webiShMeta.checksum;
}
let webiBuf = await Fs.readFile(webiPath, null);
let webiHash = Crypto.createHash('sha1').update(webiBuf).digest('hex');
let webiChecksum = webiHash.slice(0, 8);
_webiShMeta.mtime = stat.mtimeMs;
_webiShMeta.updated_at = now;
_webiShMeta.checksum = webiChecksum;
return _webiShMeta.checksum;
};

View File

@@ -32,7 +32,8 @@ if (/\b-?-h(elp)?\b/.test(process.argv.join(' '))) {
var os = require('os');
var fs = require('fs');
var path = require('path');
var Releases = require('./releases.js');
var Releases = require('./transform-releases.js');
var Installers = require('./installers.js');
var ServeInstaller = require('./serve-installer.js');
var pkg = process.argv[2].split('@');
@@ -116,8 +117,8 @@ Releases.get(path.join(process.cwd(), pkgdir)).then(async function (all) {
console.info('');
return Promise.all([
Releases.renderBash(pkgdir, rel, opts).catch(function () {}),
Releases.renderPowerShell(pkgdir, rel, opts).catch(function () {}),
Installers.renderBash(pkgdir, rel, opts).catch(function () {}),
Installers.renderPowerShell(pkgdir, rel, opts).catch(function () {}),
]).then(function (scripts) {
var bashTxt = scripts[0];
var ps1Txt = scripts[1];

View File

@@ -1,7 +1,10 @@
'use strict';
var Releases = module.exports;
var path = require('path');
var Releases = require('./releases.js');
var request = require('@root/request');
var _normalize = require('./normalize.js');
var cache = {};
//var staleAge = 5 * 1000;
@@ -11,6 +14,21 @@ var expiredAge = 15 * 60 * 1000;
let installerDir = path.join(__dirname, '..');
Releases.get = async function (pkgdir) {
let get;
try {
get = require(path.join(pkgdir, 'releases.js'));
} catch (e) {
let err = new Error('no releases.js for', pkgdir.split(/[\/\\]+/).pop());
err.code = 'E_NO_RELEASE';
throw err;
}
let all = await get(request);
return _normalize(all);
};
// TODO needs a proper test, and more accurate (though perhaps far less simple) code
function createFormatsSorter(formats) {
return function sortByVerExt(a, b) {
@@ -122,7 +140,7 @@ async function getCachedReleases(pkg) {
cache[pkg].all = all;
complete = true;
}),
sleep(5000).then(function () {
sleep(15000).then(function () {
if (complete) {
return;
}
@@ -242,7 +260,7 @@ async function filterReleases(
return sortedRels.slice(0, limit || 1000);
}
module.exports = function getReleases({
Releases.getReleases = function ({
_count,
pkg,
ver,
@@ -278,10 +296,19 @@ module.exports = function getReleases({
console.error(err);
})
.then(function (releases) {
if (!releases.length) {
if (releases.length) {
return {
oses: all.oses,
arches: all.arches,
libcs: all.libcs,
formats: all.formats,
releases: releases,
};
}
if (_count < 1) {
// Apple Silicon M1 hacky-do workaround fix
if ('macos' === os && 'arm64' === arch) {
return getReleases({
return Releases.getReleases({
pkg,
ver,
os,
@@ -295,7 +322,7 @@ module.exports = function getReleases({
}
// Windows ARM hacky-do workaround fix
if ('windows' === os && 'arm64' === arch) {
return getReleases({
return Releases.getReleases({
pkg,
ver,
os,
@@ -307,25 +334,9 @@ module.exports = function getReleases({
limit,
});
}
// Raspberry Pi 3+ on Raspbian x86 (not Ubuntu arm64)
if (!_count && 'linux' === os && 'armv7l' === arch) {
return getReleases({
_count: _count + 1,
pkg,
ver,
os,
arch: 'arm64',
libc,
lts,
channel,
formats,
limit,
});
}
// Raspberry Pi 3+ on Ubuntu arm64 (via Bionic?)
// (this may be the same as the prior search, that's okay)
if ('linux' === os && 'arm64' === arch) {
return getReleases({
return Releases.getReleases({
_count: _count + 1,
pkg,
ver,
@@ -338,9 +349,9 @@ module.exports = function getReleases({
limit,
});
}
// Raspberry Pi 3+ on Ubuntu arm64 (via Bionic?)
// armv7 can run armv6
if ('linux' === os && 'armv7l' === arch) {
return getReleases({
return Releases.getReleases({
_count: _count + 1,
pkg,
ver,
@@ -353,25 +364,43 @@ module.exports = function getReleases({
limit,
});
}
releases = [
{
name: 'doesntexist.ext',
version: '0.0.0',
lts: '-',
channel: 'error',
date: '1970-01-01',
os: os || '-',
arch: arch || '-',
libc: libc || '-',
ext: 'err',
download: 'https://example.com/doesntexist.ext',
comment:
'No matches found. Could be bad or missing version info' +
',' +
"Check query parameters. Should be something like '/api/releases/{package}@{version}.tab?os={macos|linux|windows|-}&arch={amd64|x86|aarch64|arm64|armv7l|-}&libc={musl|gnu|msvc|libc|static}&limit=10'",
},
];
}
if (_count < 2) {
// Raspberry Pi 3+ on Raspbian arm7 (not Ubuntu arm64)
// hail mary
if ('linux' === os && 'armv7l' === arch) {
return Releases.getReleases({
_count: _count + 1,
pkg,
ver,
os,
arch: 'arm64',
libc,
lts,
channel,
formats,
limit,
});
}
}
releases = [
{
name: 'doesntexist.ext',
version: '0.0.0',
lts: '-',
channel: 'error',
date: '1970-01-01',
os: os || '-',
arch: arch || '-',
libc: libc || '-',
ext: 'err',
download: 'https://example.com/doesntexist.ext',
comment:
'No matches found. Could be bad or missing version info' +
',' +
"Check query parameters. Should be something like '/api/releases/{package}@{version}.tab?os={macos|linux|windows|-}&arch={amd64|x86|aarch64|arm64|armv7l|-}&libc={musl|gnu|msvc|libc|static}&limit=10'",
},
];
return {
oses: all.oses,
arches: all.arches,

View File

@@ -69,7 +69,7 @@ function getArch(ua) {
return 'arm64';
} else if (/aarch|arm7|armv7|arm32/i.test(ua)) {
return 'armv7l';
} else if (/arm6|armv6/i.test(ua)) {
} else if (/arm6|armv6|arm(\b|_)/i.test(ua)) {
return 'armv6l';
} else if (/ppc64le/i.test(ua)) {
return 'ppc64le';

View File

@@ -17,6 +17,7 @@ module.exports = function (request) {
];
let oses = ['freebsd', 'linux', 'macos', 'posix'];
return githubSource(request, owner, repo, oses, arches).then(function (all) {
all._names = ['aliasman', 'legacy'];
return all;
});
};

View File

@@ -30,7 +30,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\arc-*" -Recurse -ErrorAction Ignore

View File

@@ -6,6 +6,7 @@ var repo = 'archiver';
module.exports = function (request) {
return github(request, owner, repo).then(function (all) {
all._names = ['archiver', 'arc'];
return all;
});
};

View File

@@ -34,7 +34,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\AtomicParsley-v*" -Recurse -ErrorAction Ignore

View File

@@ -65,6 +65,7 @@ module.exports = function (request) {
continue;
}
}
all._names = ['AtomicParsley', 'atomicparsley'];
return all;
});
};

View File

@@ -31,7 +31,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\awless-v*" -Recurse -ErrorAction Ignore

View File

@@ -20,7 +20,7 @@ IF (!(Test-Path -Path "$Env:USERPROFILE\.local\bin\$VERNAME")) {
# TODO: temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path "$Env:PKG_NAME-v*" -Recurse -ErrorAction Ignore

View File

@@ -8,10 +8,17 @@ module.exports = function (request) {
return github(request, owner, repo).then(function (all) {
all.releases = all.releases
.filter(function (r) {
let isDebug = /-profile/.test(r.name);
if (!isDebug) {
return true;
let isDebug = r.name.includes('-profile');
if (isDebug) {
return false;
}
let isAncient = r.name.includes('-baseline');
if (isAncient) {
return false;
}
return true;
})
.map(function (r) {
// bun-v0.5.1 => v0.5.1

View File

@@ -31,7 +31,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\caddy-v*" -Recurse -ErrorAction Ignore

View File

@@ -8,7 +8,12 @@ module.exports = function (request) {
return github(request, owner, repo).then(function (all) {
// remove checksums and .deb
all.releases = all.releases.filter(function (rel) {
return !/(\.txt)|(\.deb)$/i.test(rel.name);
let isOneOffAsset = rel.download.includes('buildable-artifact');
if (isOneOffAsset) {
return false;
}
return true;
});
return all;
});

View File

@@ -30,7 +30,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\chromedriver.exe" -Recurse -ErrorAction Ignore

View File

@@ -20,20 +20,28 @@ __init_chromedriver() {
# pkg_install must be defined by every package
pkg_install() {
# ~/.local/opt/chromedriver-v88.0.4324.96/bin
# ~/.local/opt/chromedriver-v121.0.6130.0/bin
mkdir -p "$(dirname "$pkg_src_cmd")"
# mv ./chromedriver-*/chromedriver ~/.local/opt/chromedriver-v88.0.4324.96/bin/chromedriver
mv ./chromedriver* "$pkg_src_cmd"
# mv ./chromedriver-macos-arm64/chromedriver \
# ~/.local/opt/chromedriver-v121.0.6130.0/bin/chromedriver
mv ./chromedriver-*/chromedriver "$pkg_src_cmd"
echo ""
echo " $(t_warn 'MANUAL STEPS TO FINISH:') you may need to install libnss3:"
echo " $(t_cmd 'sudo apt install -y') $(t_warn 'libnss3')"
}
# pkg_get_current_version is recommended, but (soon) not required
pkg_get_current_version() {
# 'chromedriver --version' has output in this format:
# ChromeDriver 88.0.4324.96 (68dba2d8a0b149a1d3afac56fa74648032bcf46b-refs/branch-heads/4324@{#1784})
# ChromeDriver 121.0.6130.0 (5fc19c7ab5e88bb674c2efc65db4b7890a52a4ec-refs/branch-heads/6130@{#1})
# This trims it down to just the version number:
# 88.0.4324.96
chromedriver --version 2> /dev/null | head -n 1 | cut -d ' ' -f 2
# 121.0.6130.0
chromedriver --version 2> /dev/null |
head -n 1 |
tr -s ' ' |
cut -d' ' -f2
}
}

View File

@@ -1,81 +1,77 @@
'use strict';
var matchers = {
key: /.*Key>(.*)<\/Key.*/,
generation: /.*Generation>(.*)<\/Generation.*/,
metaGeneration: /.*MetaGeneration>(.*)<\/MetaGeneration.*/,
lastModified: /.*LastModified>(.*)<\/LastModified.*/,
etag: /.*ETag>(.*)<\/ETag.*/,
size: /.*Size>(.*)<\/Size.*/,
};
var baseUrl = 'https://chromedriver.storage.googleapis.com';
// See <https://googlechromelabs.github.io/chrome-for-testing/>
var releaseApiUrl =
'https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json';
module.exports = function (request) {
var all = {
// {
// "timestamp": "2023-11-15T21:08:56.730Z",
// "versions": [
// {
// "version": "121.0.6120.0",
// "revision": "1222902",
// "downloads": {
// "chrome": [],
// "chromedriver": [
// {
// "platform": "linux64",
// "url": "https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/121.0.6120.0/linux64/chromedriver-linux64.zip"
// },
// {
// "platform": "mac-arm64",
// "url": "https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/121.0.6120.0/mac-arm64/chromedriver-mac-arm64.zip"
// },
// {
// "platform": "mac-x64",
// "url": "https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/121.0.6120.0/mac-x64/chromedriver-mac-x64.zip"
// },
// {
// "platform": "win32",
// "url": "https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/121.0.6120.0/win32/chromedriver-win32.zip"
// },
// {
// "platform": "win64",
// "url": "https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/121.0.6120.0/win64/chromedriver-win64.zip"
// }
// ],
// "chrome-headless-shell": []
// }
// }
// ]
// }
module.exports = async function (request) {
let resp = await request({
url: releaseApiUrl,
json: true,
});
let builds = [];
for (let release of resp.body.versions) {
if (!release.downloads.chromedriver) {
continue;
}
let version = release.version;
for (let asset of release.downloads.chromedriver) {
let build = {
version: version,
download: asset.url,
// I' not sure that this is actually statically built but it
// seems to be and at worst we'll just get bug reports for Apline
libc: 'none',
};
builds.push(build);
}
}
let all = {
download: '',
releases: [],
releases: builds,
};
// XML
return request({
url: 'https://chromedriver.storage.googleapis.com/',
json: false,
})
.then(function (resp) {
var body = resp.body;
var groups = body.split(/<\/?Contents>/g);
// get rid of leading and trailing junk
groups.shift();
groups.pop();
var metas = groups.map(function (group) {
return {
key: group.replace(matchers.key, '$1'),
//generation: group.replace(matchers.generation, '$1'),
//metaGeneration: group.replace(matchers.metaGeneration, '$1'),
lastModified: group.replace(matchers.lastModified, '$1'),
//etag: group.replace(matchers.etag, '$1'),
//size: group.replace(matchers.size, '$1')
};
});
all.download = baseUrl + '/{{ download }}';
metas.forEach(function (asset) {
if (!asset.key.includes('chromedriver')) {
// skip the indexes, images, etc
return null;
}
var osname = asset.key.replace(/.*(win|mac|linux)/, '$1');
var arch;
if (asset.key.includes('linux')) {
osname = 'linux';
} else if (asset.key.includes('mac64')) {
osname = 'macos';
if (asset.key.includes('_m1.')) {
arch = 'arm64';
}
} else if (asset.key.includes('win')) {
osname = 'windows';
arch = 'amd64';
}
all.releases.push({
// 87.0.4280.88/chromedriver_win32.zip => 87.0.4280.88
version: asset.key.replace(/(.*)\/.*/, '$1'),
lts: false,
channel: 'stable',
date: asset.lastModified.replace(/T.*/, '$1'),
os: osname,
arch: arch,
hash: '-', // not sure about including etag as hash yet
download: asset.key,
});
});
})
.then(function () {
all.releases.sort(function (a, b) {
return new Date(b.date).valueOf() - new Date(a.date).valueOf();
});
return all;
});
return all;
};
if (module === require.main) {

View File

@@ -31,7 +31,7 @@ IF (!(Test-Path -Path "$pkg_src_dir")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\cmake*" -Recurse -ErrorAction Ignore

View File

@@ -7,6 +7,10 @@ var repo = 'CMake';
module.exports = function (request) {
return github(request, owner, repo).then(function (all) {
for (let rel of all.releases) {
if (rel.version.startsWith('v')) {
rel._version = rel.version.slice(1);
}
{
let linuxRe = /(\b|_)(linux|gnu)(\b|_)/i;
let isLinux = linuxRe.test(rel.download) || linuxRe.test(rel.name);

View File

@@ -14,7 +14,7 @@ IF (!(Test-Path -Path "$Env:USERPROFILE\.local\opt\$Env:PKG_NAME-v$Env:WEBI_VERS
# TODO: temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path "$Env:PKG_NAME-v*" -Recurse -ErrorAction Ignore

View File

@@ -4,8 +4,28 @@ var github = require('../_common/github.js');
var owner = 'kivikakk';
var repo = 'comrak';
var ODDITIES = ['-musleabihf.1-'];
module.exports = function (request) {
return github(request, owner, repo).then(function (all) {
let builds = [];
loopBuilds: for (let build of all.releases) {
let isOddity;
for (let oddity of ODDITIES) {
isOddity = build.name.includes(oddity);
if (isOddity) {
break;
}
}
if (isOddity) {
continue;
}
builds.push(build);
}
all.releases = builds;
return all;
});
};

View File

@@ -31,7 +31,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Settle unpacked archive into place
Write-Output "Install Location: $pkg_src_cmd"

View File

@@ -14,7 +14,7 @@ IF (!(Test-Path -Path "$Env:USERPROFILE\.local\bin\$VERNAME")) {
# TODO: temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path "$Env:PKG_NAME-v*" -Recurse -ErrorAction Ignore

View File

@@ -6,6 +6,7 @@ var repo = 'curlie';
module.exports = function (request) {
return github(request, owner, repo).then(function (all) {
all._names = ['curlie', 'curl-httpie'];
return all;
});
};

View File

@@ -31,7 +31,7 @@ IF (!(Test-Path -Path "$pkg_src_dir")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\dashcore*" -Recurse -ErrorAction Ignore

View File

@@ -6,14 +6,17 @@ var repo = 'dash';
module.exports = function (request) {
return github(request, owner, repo).then(function (all) {
all.releases = all.releases.filter(function (rel) {
return !rel.name.endsWith('.asc');
});
all.releases.forEach(function (rel) {
if (rel.name.includes('osx64')) {
rel.os = 'macos';
}
if (rel.version.startsWith('v')) {
rel._version = rel.version.slice(1);
}
});
all._names = ['dashd', 'dashcore'];
return all;
});
};

View File

@@ -31,7 +31,7 @@ IF (!(Test-Path -Path "$pkg_src_dir")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\dashcore*" -Recurse -ErrorAction Ignore

View File

@@ -30,7 +30,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\dashmsg-v*" -Recurse -ErrorAction Ignore

View File

@@ -30,7 +30,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\delta-v*" -Recurse -ErrorAction Ignore

View File

@@ -13,7 +13,7 @@ IF (!(Test-Path -Path "$Env:USERPROFILE\.local\opt\$Env:PKG_NAME-v$Env:WEBI_VERS
# TODO: temp directory
# Enter opt
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path "deno-v*" -Recurse -ErrorAction Ignore

View File

@@ -11,7 +11,12 @@ module.exports = function (request) {
// remove checksums and .deb
all.releases = all.releases
.filter(function (rel) {
return !/(\.txt)|(\.deb)$/i.test(rel.name);
let isMeta = rel.name.endsWith('.d.ts');
if (isMeta) {
return false;
}
return true;
})
.map(function (rel) {
var ext;

View File

@@ -36,7 +36,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\dotenv-linter-v*" -Recurse -ErrorAction Ignore

View File

@@ -30,7 +30,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\dotenv-v*" -Recurse -ErrorAction Ignore

View File

@@ -17,6 +17,7 @@ module.exports = function (request) {
];
let oses = ['freebsd', 'linux', 'macos', 'posix'];
return githubSource(request, owner, repo, oses, arches).then(function (all) {
all._names = ['DuckDNS.sh', 'duckdns.sh', 'legacy'];
return all;
});
};

View File

@@ -14,7 +14,7 @@ IF (!(Test-Path -Path "$Env:USERPROFILE\.local\bin\$VERNAME")) {
# TODO: temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path "$Env:PKG_NAME-v*" -Recurse -ErrorAction Ignore

View File

@@ -6,6 +6,17 @@ var repo = 'fd';
module.exports = function (request) {
return github(request, owner, repo).then(function (all) {
let builds = [];
for (let build of all.releases) {
if (build.name === 'fd') {
continue;
}
builds.push(build);
}
all.releases = builds;
return all;
});
};

View File

@@ -30,7 +30,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\win32-*" -Recurse -ErrorAction Ignore

View File

@@ -10,6 +10,11 @@ module.exports = function (request) {
return github(request, owner, repo).then(function (all) {
all.releases = all.releases
.filter(function (rel) {
let isFfmpeg = rel.name.includes('ffmpeg');
if (!isFfmpeg) {
return;
}
// remove README and LICENSE
return !['.README', '.LICENSE'].includes(path.extname(rel.name));
})

View File

@@ -31,7 +31,7 @@ IF (-Not (Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\ffuf-v*" -Recurse -ErrorAction Ignore

View File

@@ -4,10 +4,19 @@ var github = require('../_common/github.js');
var owner = 'fish-shell';
var repo = 'fish-shell';
var ODDITIES = ['bundledpcre'];
module.exports = function (request) {
return github(request, owner, repo).then(function (all) {
all.releases = all.releases
.map(function (rel) {
for (let oddity of ODDITIES) {
let isOddity = rel.name.includes(oddity);
if (isOddity) {
return;
}
}
// We can extract the macos bins from the .app
if (/\.app\.zip$/.test(rel.name)) {
rel.os = 'macos';

View File

@@ -1,59 +1,98 @@
'use strict';
var map = {};
var FLUTTER_OSES = ['macos', 'linux', 'windows'];
module.exports = function (request) {
var all = {
// stable, beta, dev
var channelMap = {};
// This can be spot-checked against
// https://docs.flutter.dev/release/archive?tab=windows
// The release URLs are
// - https://storage.googleapis.com/flutter_infra_release/releases/releases_macos.json
// - https://storage.googleapis.com/flutter_infra_release/releases/releases_linux.json
// - https://storage.googleapis.com/flutter_infra_release/releases/releases_windows.json
// The old release URLs are
// - https://storage.googleapis.com/flutter_infra/releases/releases_macos.json
// - https://storage.googleapis.com/flutter_infra/releases/releases_linux.json
// - https://storage.googleapis.com/flutter_infra/releases/releases_windows.json
// The data looks like
// {
// "base_url": "https://storage.googleapis.com/flutter_infra/releases",
// "current_release": {
// "beta": "b22742018b3edf16c6cadd7b76d9db5e7f9064b5",
// "dev": "fa5883b78e566877613ad1ccb48dd92075cb5c23",
// "stable": "02c026b03cd31dd3f867e5faeb7e104cce174c5f"
// },
// "releases": [
// {
// "hash": "fa5883b78e566877613ad1ccb48dd92075cb5c23",
// "channel": "dev",
// "version": "2.3.0-16.0.pre",
// "release_date": "2021-05-27T23:58:47.683121Z",
// "archive": "dev/macos/flutter_macos_2.3.0-16.0.pre-dev.zip",
// "sha256": "f572b42d36714e6c58a3ed170b93bb414e2ced3ca4bde5094fbe18061cbcba6c"
// },
// {
// "hash": "02c026b03cd31dd3f867e5faeb7e104cce174c5f",
// "channel": "stable",
// "version": "2.2.1",
// "release_date": "2021-05-27T23:06:07.243882Z",
// "archive": "stable/macos/flutter_macos_2.2.1-stable.zip",
// "sha256": "6373d39ec563c337600baf42a42b258420208e4523d85479373e113d61d748df"
// },
// {
// "hash": "b22742018b3edf16c6cadd7b76d9db5e7f9064b5",
// "channel": "beta",
// "version": "2.2.0",
// "release_date": "2021-05-19T21:14:59.281482Z",
// "archive": "beta/macos/flutter_macos_2.2.0-beta.zip",
// "sha256": "31ab530e708f8d1274712211253a27a4ce7d676f139d30f2ec021df22382f052"
// }
// ]
// }
module.exports = async function (request) {
let all = {
download: '',
releases: [],
channels: [],
};
return Promise.all(
['macos', 'linux', 'windows'].map(function (osname) {
return request({
url:
'https://storage.googleapis.com/flutter_infra/releases/releases_' +
osname +
'.json',
json: true,
}).then(function (resp) {
var body = resp.body;
all.download = body.base_url + '/{{ download }}';
body.releases.forEach(function (asset) {
if (!map[asset.channel]) {
map[asset.channel] = true;
}
all.releases.push({
// nix leading 'v'
version: asset.version.replace(/v/, ''),
lts: false,
channel: asset.channel,
date: asset.release_date.replace(/T.*/, ''),
os: osname,
arch: 'amd64',
hash: '-', // not sure about including hash / sha256 yet
download: asset.archive,
});
});
});
}),
).then(function () {
all.releases.sort(function (a, b) {
if ('stable' === a.channel && a.channel !== b.channel) {
return -1;
}
if ('stable' === b.channel && a.channel !== b.channel) {
return 1;
}
if ('beta' === a.channel && a.channel !== b.channel) {
return -1;
}
if ('beta' === b.channel && a.channel !== b.channel) {
return 1;
}
return new Date(b.date).valueOf() - new Date(a.date).valueOf();
for (let osname of FLUTTER_OSES) {
let resp = await request({
url: `https://storage.googleapis.com/flutter_infra_release/releases/releases_${osname}.json`,
json: true,
});
return all;
});
let osBaseUrl = resp.body.base_url;
let osReleases = resp.body.releases;
for (let asset of osReleases) {
if (!channelMap[asset.channel]) {
channelMap[asset.channel] = true;
}
all.releases.push({
version: asset.version,
_version: `${asset.version}-${asset.channel}`,
lts: false,
channel: asset.channel,
date: asset.release_date.replace(/T.*/, ''),
//sha256: asset.sha256,
download: `${osBaseUrl}/${asset.archive}`,
});
}
}
all.channels = Object.keys(channelMap);
// note: versions have a waterfall relationship with channels:
// - a release that is in beta today may become stable tomorrow
// - semver prereleases are either beta or dev
return all;
};
if (module === require.main) {

View File

@@ -14,7 +14,7 @@ IF (!(Test-Path -Path "$Env:USERPROFILE\.local\bin\$VERNAME")) {
# TODO: temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path "$Env:PKG_NAME-v*" -Recurse -ErrorAction Ignore

View File

@@ -30,7 +30,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\gh-v*" -Recurse -ErrorAction Ignore

View File

@@ -22,7 +22,7 @@ IF (!(Test-Path -Path "$pkg_src")) {
# TODO: temp directory
# Enter opt
($none = Push-Location $HOME\.local\tmp) | Out-Null
($none = Push-Location .local\tmp) | Out-Null
# Remove any leftover tmp cruft
Remove-Item -Path "$pkg_cmd_name*" -Recurse -ErrorAction Ignore

View File

@@ -12,12 +12,15 @@ module.exports = function (request) {
all.releases = all.releases
.filter(function (rel) {
rel.os = 'windows';
rel._version = rel.version.replace(/\.windows.1.*/, '');
rel._version = rel._version.replace(/\.windows(\.\d)/, '$1');
return (
/MinGit/i.test(rel.name || rel.download) &&
!/busybox/i.test(rel.name || rel.download)
);
})
.slice(0, 20);
all._names = ['MinGit', 'git'];
return all;
});
};

View File

@@ -30,7 +30,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\gitdeploy-v*" -Recurse -ErrorAction Ignore

View File

@@ -18,6 +18,12 @@ $pkg_src = "$pkg_src_cmd"
New-Item "$Env:USERPROFILE\Downloads\webi" -ItemType Directory -Force | Out-Null
$pkg_download = "$Env:USERPROFILE\Downloads\webi\$Env:WEBI_PKG_FILE"
Write-Output "Checking for Git..."
IF (-Not (Get-Command -Name "git" -ErrorAction Silent)) {
& "$HOME\.local\bin\webi-pwsh.ps1" git
$null = Sync-EnvPath
}
# Fetch archive
IF (!(Test-Path -Path "$Env:USERPROFILE\Downloads\webi\$Env:WEBI_PKG_FILE")) {
Write-Output "Downloading gitea from $Env:WEBI_PKG_URL to $pkg_download"
@@ -30,7 +36,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\gitea-*" -Recurse -ErrorAction Ignore

View File

@@ -4,12 +4,24 @@ var github = require('../_common/github.js');
var owner = 'go-gitea';
var repo = 'gitea';
var ODDITIES = ['-gogit-', '-docs-'];
module.exports = function (request) {
return github(request, owner, repo).then(function (all) {
// remove checksums and .deb
all.releases = all.releases.filter(function (rel) {
return !/(\.txt)|(\.deb)|(\.asc)|(\.sha256)$/i.test(rel.name);
for (let oddity of ODDITIES) {
let isOddity = rel.name.includes(oddity);
if (isOddity) {
return false;
}
}
return true;
});
// "windows-4.0" as a nod to Windows NT ¯\_(ツ)_/¯
all._names = ['gitea', '-4.0-'];
return all;
});
};

View File

@@ -27,7 +27,7 @@ IF (!(Test-Path -Path "$pkg_src")) {
# TODO: temp directory
# Enter opt
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path "$pkg_cmd_name*" -Recurse -ErrorAction Ignore

View File

@@ -7,6 +7,17 @@ var archMap = {
386: 'x86',
};
let ODDITIES = ['bootstrap', '-arm6.'];
function isOdd(filename) {
for (let oddity of ODDITIES) {
let isOddity = filename.includes(oddity);
if (isOddity) {
return true;
}
}
}
function getAllReleases(request) {
/*
{
@@ -33,7 +44,7 @@ function getAllReleases(request) {
var goReleases = resp.body;
var all = {
releases: [],
download: 'https://dl.google.com/go/{{ download }}',
download: '',
};
goReleases.forEach((release) => {
@@ -43,13 +54,21 @@ function getAllReleases(request) {
parts.push('0');
}
var version = parts.join('.');
// nix 'go' prefix
var fileversion = release.version.slice(2);
release.files.forEach((asset) => {
let odd = isOdd(asset.filename);
if (odd) {
return;
}
var filename = asset.filename;
var os = osMap[asset.os] || asset.os || '-';
var arch = archMap[asset.arch] || asset.arch || '-';
all.releases.push({
version: version,
_version: fileversion,
// all go versions >= 1.0.0 are effectively LTS
lts: (parts[0] > 0 && release.stable) || false,
channel: (release.stable && 'stable') || 'beta',
@@ -58,7 +77,7 @@ function getAllReleases(request) {
arch: arch,
ext: '', // let normalize run the split/test/join
hash: '-', // not ready to standardize this yet
download: filename,
download: `https://dl.google.com/go/${filename}`,
});
});
});

View File

@@ -27,7 +27,7 @@ IF (!(Test-Path -Path "$pkg_src")) {
# TODO: temp directory
# Enter opt
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path "$pkg_cmd_name*" -Recurse -ErrorAction Ignore

View File

@@ -30,7 +30,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\goreleaser-v*" -Recurse -ErrorAction Ignore

View File

@@ -41,7 +41,6 @@ function transformReleases(links) {
let releases = links
.map(function (link) {
// strip 'go' prefix, standardize version
let isLts = ltsRe.test(link);
let parts = link.match(matcher);
if (!parts || !parts[2]) {
@@ -52,10 +51,12 @@ function transformReleases(links) {
if (segs.length > 3) {
version += '+' + segs.slice(3);
}
let fileversion = segs.join('.');
return {
name: parts[1],
version: version,
_version: fileversion,
// all go versions >= 1.0.0 are effectively LTS
lts: isLts,
channel: 'stable',
@@ -70,6 +71,7 @@ function transformReleases(links) {
.filter(Boolean);
return {
_names: ['GnuPG', 'gpgosx'],
releases: releases,
};
}

View File

@@ -30,7 +30,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\gprox-v*" -Recurse -ErrorAction Ignore

View File

@@ -31,7 +31,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\grype-v*" -Recurse -ErrorAction Ignore

View File

@@ -31,7 +31,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\hugo-extended-v*" -Recurse -ErrorAction Ignore

View File

@@ -13,12 +13,9 @@ module.exports = async function (request) {
return false;
}
// remove checksums and .deb
for (let ignorableExt of ['.txt', '.deb']) {
let isIgnorable = rel.name.endsWith(ignorableExt);
if (isIgnorable) {
return false;
}
let isOldAlias = rel.name.includes('Linux-64bit');
if (isOldAlias) {
return false;
}
return true;

View File

@@ -31,7 +31,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\hugo-v*" -Recurse -ErrorAction Ignore

View File

@@ -13,12 +13,9 @@ module.exports = async function (request) {
return false;
}
// remove checksums and .deb
for (let ignorableExt of ['.txt', '.deb']) {
let isIgnorable = rel.name.endsWith(ignorableExt);
if (isIgnorable) {
return false;
}
let isOldAlias = rel.name.includes('Linux-64bit');
if (isOldAlias) {
return false;
}
return true;

View File

@@ -16,9 +16,26 @@ _install_iterm2() {
exit 1
fi
if test -d /Applications/iTerm.app; then
my_curver="$(
grep -A 2 CFBundleShortVersionString \
/Applications/iTerm.app/Contents/Info.plist |
tr '<> \t' '\n' |
grep -E '\d\.\d\.\d'
)"
if test "${my_curver}" = "${WEBI_VERSION}"; then
echo " Found /Applications/iTerm.app/ (${my_curver})"
return 0
fi
echo " Replacing /Applications/iTerm.app/ (${my_curver})"
mv /Applications/iTerm.app "${WEBI_TMP}/iTerm.app-webi.bak"
fi
webi_download \
"${WEBI_PKG_URL}" \
"${WEBI_PKG_PATH}/${WEBI_PKG_FILE}"
webi_extract
if [ ! -d "${WEBI_TMP}/iTerm.app" ]; then
@@ -27,11 +44,9 @@ _install_iterm2() {
exit 1
fi
if [ -d /Applications/iTerm.app ]; then
mv /Applications/iTerm.app "${WEBI_TMP}/iTerm.app-webi.bak"
fi
mkdir -p /Applications/
mv "${WEBI_TMP}/iTerm.app" /Applications/
echo " Installed to /Applications/iTerm.app/"
}
_install_iterm2

View File

@@ -24,17 +24,24 @@ function transformReleases(links) {
//console.log(links.length);
return {
_names: ['iTerm2', 'iterm2'],
releases: links
.map(function (link) {
// strip 'go' prefix, standardize version
var channel = /\/stable\//.test(link) ? 'stable' : 'beta';
var parts = link
.replace(/.*\/iTerm2[-_]v?(\d_.*)\.zip/, '$1')
.split('_');
var version = parts.join('.').replace(/([_-])?beta/, '-beta');
// ex: 3.5.0-beta17 => 3_5_0beta17
// ex: 3.0.2-preview => 3_0_2-preview
let fileversion = version.replace(/\./g, '_');
fileversion = fileversion.replace(/-beta/g, 'beta');
return {
version: version,
_version: fileversion,
// all go versions >= 1.0.0 are effectively LTS
lts: 'stable' === channel,
channel: channel,

View File

@@ -14,7 +14,7 @@ IF (!(Test-Path -Path "$Env:USERPROFILE\.local\bin\$VERNAME")) {
# TODO: temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path "$Env:PKG_NAME-v*" -Recurse -ErrorAction Ignore

View File

@@ -4,11 +4,32 @@ var github = require('../_common/github.js');
var owner = 'stedolan';
var repo = 'jq';
let ODDITIES = ['-no-oniguruma'];
function isOdd(build) {
for (let oddity of ODDITIES) {
let isOddity = build.name.includes(oddity);
if (isOddity) {
return true;
}
}
}
module.exports = function (request) {
return github(request, owner, repo).then(function (all) {
all.releases.forEach(function (rel) {
rel.version = String(rel.version).replace(/^jq\-/, '');
});
let builds = [];
for (let build of all.releases) {
let odd = isOdd(build);
if (odd) {
continue;
}
build.version = build.version.replace(/^jq\-/, '');
builds.push(build);
}
all.releases = builds;
return all;
});
};

View File

@@ -30,7 +30,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\k9s-v*" -Recurse -ErrorAction Ignore

View File

@@ -30,7 +30,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\keypairs-v*" -Recurse -ErrorAction Ignore

View File

@@ -25,7 +25,7 @@ IF (!(Test-Path -Path "$Env:USERPROFILE\Downloads\webi\$Env:WEBI_PKG_FILE")) {
IF (!(Test-Path -Path "$pkg_src_cmd")) {
Write-Output "Installing kind"
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
Remove-Item -Path ".\kind-v*" -Recurse -ErrorAction Ignore
Remove-Item -Path ".\kind.exe" -Recurse -ErrorAction Ignore

View File

@@ -30,7 +30,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\kubectx-v*" -Recurse -ErrorAction Ignore

View File

@@ -4,16 +4,25 @@ var github = require('../_common/github.js');
var owner = 'ahmetb';
var repo = 'kubectx';
/******************************************************************************/
/** Note: Delete this Comment! **/
/** **/
/** Need a an example that filters out miscellaneous release files? **/
/** See `deno`, `gitea`, or `caddy` **/
/** **/
/******************************************************************************/
module.exports = function (request) {
return github(request, owner, repo).then(function (all) {
let builds = [];
for (let build of all.releases) {
// this installs separately
if (build.name.includes('kubens')) {
continue;
}
// this is the legacy bash script
if (build.name === 'kubectx') {
continue;
}
builds.push(build);
}
all.releases = builds;
return all;
});
};

View File

@@ -30,7 +30,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\kubens-v*" -Recurse -ErrorAction Ignore

View File

@@ -6,10 +6,23 @@ var repo = 'kubectx';
module.exports = function (request) {
return github(request, owner, repo).then(function (all) {
// remove kubectx, etc. from kubens list
all.releases = all.releases.filter(function (rel) {
return !/(\.txt)|(kubectx)|(kubectx_)$/i.test(rel.name);
});
let builds = [];
for (let build of all.releases) {
// this installs separately
if (build.name.includes('kubectx')) {
continue;
}
// this is the legacy bash script
if (build.name === 'kubens') {
continue;
}
builds.push(build);
}
all.releases = builds;
return all;
});
};

View File

@@ -26,7 +26,7 @@ IF (!(Test-Path -Path "$Env:USERPROFILE\Downloads\webi\$Env:WEBI_PKG_FILE")) {
IF (!(Test-Path -Path "$pkg_src_cmd")) {
Write-Output "Installing lf"
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
Remove-Item -Path ".\lf.exe" -Recurse -ErrorAction Ignore

View File

@@ -30,7 +30,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\lsd-v*" -Recurse -ErrorAction Ignore

View File

@@ -41,7 +41,11 @@ var headers = {
};
module.exports = function (request) {
var all = { download: '', releases: [] };
var all = {
_names: ['InstallOS'],
download: '',
releases: [],
};
return Promise.all(
oses.map(function (os) {

View File

@@ -26,7 +26,7 @@ IF (!(Test-Path -Path "$Env:USERPROFILE\Downloads\webi\$Env:WEBI_PKG_FILE")) {
IF (!(Test-Path -Path "$pkg_src_cmd")) {
Write-Output "Installing mutagen"
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
Remove-Item -Path ".\mutagen.exe" -Recurse -ErrorAction Ignore

View File

@@ -14,7 +14,7 @@ IF (!(Test-Path -Path "$Env:USERPROFILE\.local\opt\$Env:PKG_NAME-v$Env:WEBI_VERS
# TODO: temp directory
# Enter opt
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path "node-v*" -Recurse -ErrorAction Ignore

View File

@@ -40,5 +40,7 @@ pkg_link() {
}
pkg_done_message() {
echo "Installed 'node' and 'npm' at $pkg_dst"
b_dst="$(fn_sub_home "${pkg_dst}")"
echo ""
echo " Installed $(t_pkg 'node') and $(t_pkg 'npm') at $(t_path "${b_dst}/")"
}

View File

@@ -19,6 +19,7 @@ module.exports = async function (request) {
}
all.releases = releases;
all._names = ['Ollama', 'ollama'];
return all;
};

View File

@@ -27,7 +27,7 @@ IF (!(Test-Path -Path "$Env:USERPROFILE\Downloads\webi\$Env:WEBI_PKG_FILE")) {
IF (!(Test-Path -Path "$pkg_src_cmd")) {
Write-Output "Installing ots"
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\ots-v*" -Recurse -ErrorAction Ignore

View File

@@ -30,7 +30,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\pandoc-v*" -Recurse -ErrorAction Ignore

View File

@@ -30,7 +30,7 @@ IF (!(Test-Path -Path "$pkg_src_cmd")) {
# TODO: create package-specific temp directory
# Enter tmp
Push-Location $HOME\.local\tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\pathman-v*" -Recurse -ErrorAction Ignore

View File

@@ -8,7 +8,14 @@ var baseurl = 'https://git.rootprojects.org';
module.exports = function (request) {
return github(request, owner, repo, baseurl).then(function (all) {
all.releases = all.releases.filter(function (release) {
return !/debug/.test(release.name);
release._filename = release.name;
let isOldAlias = release.name.includes('armv8');
if (isOldAlias) {
return false;
}
return true;
});
return all;
});

View File

@@ -75,6 +75,7 @@ module.exports = async function () {
download: '',
},
].map(function (rel) {
rel._version = `${rel.version}-1`;
rel.download =
'https://get.enterprisedb.com/postgresql/' +
rel.name +
@@ -82,6 +83,7 @@ module.exports = async function () {
return rel;
}),
download: '',
_names: ['PostgreSQL', 'postgresql', 'Postgres', 'postgres', 'binaries'],
};
};

View File

@@ -1,98 +1,11 @@
---
title: Microsoft PowerShell
homepage: https://docs.microsoft.com/en-us/powershell/
title: PowerShell (pwsh alias)
homepage: https://webinstall.dev/pwsh
tagline: |
PowerShell Core is a cross-platform (Windows, Linux, and macOS) automation and configuration tool/framework.
Alias for https://webinstall.dev/pwsh
alias: pwsh
description: |
See https://webinstall.dev/pwsh
---
To update or switch versions, run `webi pwsh@stable` (or `@v7.4`, `@beta`, etc).
## Cheat Sheet
> The core benefit of running `pwsh` on Mac or Linux is that you get a way to
> debug Windows scripts without having to boot up Windows.
>
> The core benefit of running `pwsh` on Windows is that it's years ahead of
> pre-installed version.
For example, if you want to create a `curl.exe | powershell` script for Windows
(as we do), it's helpful to be able to do some level of debugging on other
platforms.
## Table of Contents
- Files
- ProTips
- vim
- lint
- fmt
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/opt/pwsh/
~/.local/share/powershell/Modules/
~/.local/opt/pwsh/Modules/
```
### ProTip: pwsh-essentials
Friends don't let friends PowerShell without
[pwsh-essentials](../pwsh-essentials/):
- [PSScriptAnalyzer](../psscriptanalyzer/)
- [pwsh-fmt](../pwsh-essentials/)
- [pwsh-lint](../pwsh-essentials/)
- [pwsh-fix](../pwsh-essentials/)
- [pwsh-run](../pwsh-essentials/)
Plus, important information for anyone **Getting Started with PowerShell**:
- Case-Sensitivity
- Returns vs Pipeline Streams
- Strict, Trace, & Verbose Modes
- The Call Operator "&"
- curl vs curl.exe
- Script Policies & Preferences
### How to Use PowerShell with Vim
Assuming you have [vim-ale](../vim-ale/) installed - which is included with
[vim-essentials](../vim-essentials/) - all you need to do is install the
`PSScriptAnalyzer` module.
See the "Lint & Fmt" section below.
### How to Use PowerShell with VSCode
_VS Code_ should also automatically recognize and use `PSScriptAnalyzer`.
### How to Lint, Fmt, & Fix ps1 Files
See [pwsh-essentials](../pwsh-essentials/) for more info but, in short:
```sh
pwsh -Command "Install-Module -Name PSScriptAnalyzer -Scope CurrentUser -AllowClobber"
```
```sh
my_ps1='./my-file.ps1'
pwsh -Command "Invoke-ScriptAnalyzer -Fix -ExcludeRule PSAvoidUsingWriteHost -Path '$my_ps1'"
```
To fmt:
```sh
my_ps1='./my-file.ps1'
my_text="$(
pwsh -Command "Invoke-Formatter -ScriptDefinition (Get-Content -Path '$my_ps1' -Raw)"
)"
printf '%s\n' "${my_text}" > "${my_ps1}"
```
Note: it is _several hundred times faster_ to lint and fmt from a native
PowerShell script than from invoking `pwsh -Command` each time.
Alias for https://webinstall.dev/pwsh

View File

@@ -1,56 +1,8 @@
#!/usr/bin/env pwsh
#!/bin/pwsh
#################
# Install pwsh #
#################
Write-Output "'powershell@$Env:WEBI_TAG' is an alias for 'pwsh@$Env:WEBI_VERSION'"
# Every package should define these variables
$pkg_cmd_name = "pwsh"
$pkg_dst_cmd = "$HOME\.local\opt\pwsh\${pkg_cmd_name}.exe"
$pkg_dst_bin = "$HOME\.local\opt\pwsh"
$pkg_dst_dir = "$HOME\.local\opt\pwsh"
$pkg_dst = "$pkg_dst_dir"
$pkg_src_cmd = "$HOME\.local\opt\pwsh-v$Env:WEBI_VERSION\${pkg_cmd_name}.exe"
$pkg_src_dir = "$HOME\.local\opt\pwsh-v$Env:WEBI_VERSION"
$pkg_src = "$pkg_src_dir"
New-Item "$HOME\Downloads\webi" -ItemType Directory -Force | Out-Null
$pkg_download = "$HOME\Downloads\webi\$Env:WEBI_PKG_FILE"
# Fetch archive
Invoke-DownloadURL -URL $Env:WEBI_PKG_URL -Path $pkg_download
IF (!(Test-Path -Path "$pkg_src_cmd")) {
Push-Location "$HOME\.local\tmp"
# Remove any leftover tmp cruft
Remove-Item -Path "$pkg_src_dir" -Recurse -ErrorAction Ignore | Out-Null
Remove-Item -Path "$HOME\.local\tmp\pwsh*" -Recurse -ErrorAction Ignore
# Unpack archive file into this temporary directory
# Windows BSD-tar handles zip. Imagine that.
New-Item ".\pwsh-v$Env:WEBI_VERSION" -ItemType Directory -Force | Out-Null
Push-Location ".\pwsh-v$Env:WEBI_VERSION"
Write-Output " Unpacking $pkg_download"
& tar xf "$pkg_download"
Pop-Location
# Settle unpacked archive into place
# TODO if .\pwsh-v$Env:WEBI_VERSION\pwsh*\ exists,
# then the nesting of the archive has changed
# so move either .\pwsh-v$Env:WEBI_VERSION\pwsh*\
# or .\pwsh-v$Env:WEBI_VERSION\ accordingly
Move-Item -Path ".\pwsh-v$Env:WEBI_VERSION" -Destination "$pkg_src_dir"
Write-Output " into ${TPath}${pkg_src_dir}${TReset}"
Pop-Location
}
Write-Output " Copying ${TDim}${pkg_src}${TReset}"
Write-Output " into ${TPath}${pkg_dst}${TReset}"
Remove-Item -Path "$pkg_dst" -Recurse -ErrorAction Ignore | Out-Null
Copy-Item -Path "$pkg_src" -Destination "$pkg_dst" -Recurse
webi_path_add "$pkg_dst_bin"
& "$pkg_dst_cmd" -V
$PwshBootUrl = "$Env:WEBI_HOST/pwsh@$Env:WEBI_VERSION"
$PwshBootScript = "$HOME\.local\tmp\install-pwsh-boot.ps1"
Invoke-DownloadUrl -Force -URL $PwshBootUrl -Path $PwshBootScript
pwsh -ExecutionPolicy Bypass $PwshBootScript

View File

@@ -2,45 +2,10 @@
set -e
set -u
__init_powershell() {
pkg_cmd_name="pwsh"
# no ./bin prefix
pkg_src_cmd="$HOME/.local/opt/pwsh-v$WEBI_VERSION/pwsh"
pkg_dst_cmd="$HOME/.local/opt/pwsh/pwsh"
pkg_get_current_version() {
# 'pwsh --version' has output in this format:
# PowerShell 7.0.2
# This trims it down to just the version number:
# 7.0.2
pwsh --version 2> /dev/null | head -n 1 | cut -d' ' -f2
}
pkg_install() {
# mv ./* "$HOME/.local/opt/pwsh-v7.0.2"
mkdir -p "$pkg_src"
mv ./* "$pkg_src"
# symlink powershell to pwsh
(
cd "$pkg_src" > /dev/null
ln -s pwsh powershell
)
}
pkg_link() {
# rm -f "$HOME/.local/opt/pwsh"
rm -f "$pkg_dst"
# ln -s "$HOME/.local/opt/pwsh-v7.0.2" "$HOME/.local/opt/pwsh"
ln -s "$pkg_src" "$pkg_dst"
}
pkg_done_message() {
echo "Installed 'pwsh' at $pkg_dst"
pwsh -V
}
__redirect_alias_pwsh() {
echo "'powershell@${WEBI_TAG:-stable}' is an alias for 'pwsh@${WEBI_VERSION-}'"
WEBI_HOST=${WEBI_HOST:-"https://webinstall.dev"}
curl -fsSL "$WEBI_HOST/pwsh@${WEBI_VERSION-}" | sh
}
__init_powershell
__redirect_alias_pwsh

View File

@@ -1,11 +1,98 @@
---
title: PowerShell (pwsh alias)
homepage: https://webinstall.dev/powershell
title: Microsoft PowerShell Core
homepage: https://docs.microsoft.com/powershell/
tagline: |
Alias for https://webinstall.dev/powershell
alias: powershell
description: |
See https://webinstall.dev/powershell
PowerShell Core is a cross-platform (Windows, Linux, and macOS) automation and configuration tool/framework.
---
Alias for https://webinstall.dev/powershell
To update or switch versions, run `webi pwsh@stable` (or `@v7.4`, `@beta`, etc).
## Cheat Sheet
> The core benefit of running `pwsh` on Mac or Linux is that you get a way to
> debug Windows scripts without having to boot up Windows.
>
> The core benefit of running `pwsh` on Windows is that it's years ahead of
> pre-installed version.
For example, if you want to create a `curl.exe | powershell` script for Windows
(as we do), it's helpful to be able to do some level of debugging on other
platforms.
## Table of Contents
- Files
- ProTips
- vim
- lint
- fmt
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/opt/pwsh/
~/.local/share/powershell/Modules/
~/.local/opt/pwsh/Modules/
```
### ProTip: pwsh-essentials
Friends don't let friends PowerShell without
[pwsh-essentials](../pwsh-essentials/):
- [PSScriptAnalyzer](../psscriptanalyzer/)
- [pwsh-fmt](../pwsh-essentials/)
- [pwsh-lint](../pwsh-essentials/)
- [pwsh-fix](../pwsh-essentials/)
- [pwsh-run](../pwsh-essentials/)
Plus, important information for anyone **Getting Started with PowerShell**:
- Case-Sensitivity
- Returns vs Pipeline Streams
- Strict, Trace, & Verbose Modes
- The Call Operator "&"
- curl vs curl.exe
- Script Policies & Preferences
### How to Use PowerShell with Vim
Assuming you have [vim-ale](../vim-ale/) installed - which is included with
[vim-essentials](../vim-essentials/) - all you need to do is install the
`PSScriptAnalyzer` module.
See the "Lint & Fmt" section below.
### How to Use PowerShell with VSCode
_VS Code_ should also automatically recognize and use `PSScriptAnalyzer`.
### How to Lint, Fmt, & Fix ps1 Files
See [pwsh-essentials](../pwsh-essentials/) for more info but, in short:
```sh
pwsh -Command "Install-Module -Name PSScriptAnalyzer -Scope CurrentUser -AllowClobber"
```
```sh
my_ps1='./my-file.ps1'
pwsh -Command "Invoke-ScriptAnalyzer -Fix -ExcludeRule PSAvoidUsingWriteHost -Path '$my_ps1'"
```
To fmt:
```sh
my_ps1='./my-file.ps1'
my_text="$(
pwsh -Command "Invoke-Formatter -ScriptDefinition (Get-Content -Path '$my_ps1' -Raw)"
)"
printf '%s\n' "${my_text}" > "${my_ps1}"
```
Note: it is _several hundred times faster_ to lint and fmt from a native
PowerShell script than from invoking `pwsh -Command` each time.

View File

@@ -1,8 +1,57 @@
#!/bin/pwsh
#!/usr/bin/env pwsh
Write-Output "'pwsh@$Env:WEBI_TAG' is an alias for 'powershell@$Env:WEBI_VERSION'"
################
# Install pwsh #
################
$PwshBootUrl = "$Env:WEBI_HOST/powershell@$Env:WEBI_VERSION"
$PwshBootScript = "$HOME\.local\tmp\install-pwsh-boot.ps1"
Invoke-DownloadUrl -Force -URL $PwshBootUrl -Path $PwshBootScript
powershell -ExecutionPolicy Bypass $PwshBootScript
# Every package should define these variables
$pkg_cmd_name = "pwsh"
$pkg_dst_cmd = "$HOME\.local\opt\pwsh\${pkg_cmd_name}.exe"
$pkg_dst_bin = "$HOME\.local\opt\pwsh"
$pkg_dst_dir = "$HOME\.local\opt\pwsh"
$pkg_dst = "$pkg_dst_dir"
$pkg_src_cmd = "$HOME\.local\opt\pwsh-v$Env:WEBI_VERSION\${pkg_cmd_name}.exe"
$pkg_src_dir = "$HOME\.local\opt\pwsh-v$Env:WEBI_VERSION"
$pkg_src = "$pkg_src_dir"
New-Item "$HOME\Downloads\webi" -ItemType Directory -Force | Out-Null
$pkg_download = "$HOME\Downloads\webi\$Env:WEBI_PKG_FILE"
# Fetch archive
Invoke-DownloadURL -URL $Env:WEBI_PKG_URL -Path $pkg_download
IF (!(Test-Path -Path "$pkg_src_cmd")) {
Push-Location "$HOME\.local\tmp"
# Remove any leftover tmp cruft
Remove-Item -Path "$pkg_src_dir" -Recurse -ErrorAction Ignore | Out-Null
Remove-Item -Path "$HOME\.local\tmp\pwsh*" -Recurse -ErrorAction Ignore
# Unpack archive file into this temporary directory
# Windows BSD-tar handles zip. Imagine that.
New-Item ".\pwsh-v$Env:WEBI_VERSION" -ItemType Directory -Force | Out-Null
Push-Location ".\pwsh-v$Env:WEBI_VERSION"
Write-Output " Unpacking $pkg_download"
& tar xf "$pkg_download"
Pop-Location
# Settle unpacked archive into place
# TODO if .\pwsh-v$Env:WEBI_VERSION\pwsh*\ exists,
# then the nesting of the archive has changed
# so move either .\pwsh-v$Env:WEBI_VERSION\pwsh*\
# or .\pwsh-v$Env:WEBI_VERSION\ accordingly
Move-Item -Path ".\pwsh-v$Env:WEBI_VERSION" -Destination "$pkg_src_dir"
Write-Output " into ${TPath}${pkg_src_dir}${TReset}"
Pop-Location
}
Write-Output " Copying ${TDim}${pkg_src}${TReset}"
Write-Output " into ${TPath}${pkg_dst}${TReset}"
Remove-Item -Path "$pkg_dst" -Recurse -ErrorAction Ignore | Out-Null
Copy-Item -Path "$pkg_src" -Destination "$pkg_dst" -Recurse
webi_path_add "$pkg_dst_bin"
& "$pkg_dst_cmd" -V

View File

@@ -2,10 +2,52 @@
set -e
set -u
__redirect_alias_powershell() {
echo "'pwsh@${WEBI_TAG:-stable}' is an alias for 'powershell@${WEBI_VERSION-}'"
WEBI_HOST=${WEBI_HOST:-"https://webinstall.dev"}
curl -fsSL "$WEBI_HOST/powershell@${WEBI_VERSION-}" | sh
__init_pwsh() {
pkg_cmd_name="pwsh"
# note: no ./bin prefix
pkg_src_cmd="$HOME/.local/opt/pwsh-v$WEBI_VERSION/pwsh"
pkg_src_dir="$HOME/.local/opt/pwsh-v$WEBI_VERSION/"
pkg_src="$HOME/.local/opt/pwsh-v$WEBI_VERSION/"
pkg_dst_cmd="$HOME/.local/opt/pwsh/pwsh"
pkg_dst_dir="$HOME/.local/opt/pwsh"
pkg_dst="$HOME/.local/opt/pwsh"
pkg_get_current_version() {
# 'pwsh --version' has output in this format:
# PowerShell 7.0.2
# This trims it down to just the version number:
# 7.0.2
pwsh --version 2> /dev/null | head -n 1 | cut -d' ' -f2
}
pkg_install() {
# mv ./* "$HOME/.local/opt/pwsh-v7.0.2"
mkdir -p "$pkg_src"
mv ./* "$pkg_src"
# symlink pwsh as powershell
(
cd "$pkg_src" > /dev/null
rm -rf powershell
ln -s pwsh powershell
)
}
pkg_link() {
# rm -f "$HOME/.local/opt/pwsh"
rm -rf "$pkg_dst"
# ln -s "$HOME/.local/opt/pwsh-v7.0.2" "$HOME/.local/opt/pwsh"
ln -s "$pkg_src" "$pkg_dst"
}
pkg_done_message() {
echo "Installed 'pwsh' at $pkg_dst"
pwsh -V
}
}
__redirect_alias_powershell
__init_pwsh

View File

@@ -4,17 +4,41 @@ var github = require('../_common/github.js');
var owner = 'powershell';
var repo = 'powershell';
let ODDITIES = ['-fxdependent'];
function isOdd(build) {
for (let oddity of ODDITIES) {
let isOddity = build.name.includes(oddity);
if (isOddity) {
return true;
}
}
}
module.exports = function (request) {
return github(request, owner, repo).then(function (all) {
// remove checksums and .deb
all.releases = all.releases.filter(function (rel) {
let odd = isOdd(rel);
if (odd) {
return false;
}
let isPreview = rel.name.includes('-preview.');
if (isPreview) {
rel.channel = 'beta';
}
return !/(alpine)|(fxdependent)|(\.deb)|(\.pkg)|(\.rpm)$/i.test(rel.name);
let isMusl = rel.download.match(/(\b|_)(musl|alpine)(\b|_)/i);
if (isMusl) {
// not a fully static build, not gnu-compatible
rel.libc = 'musl';
}
return true;
});
all._names = ['PowerShell', 'powershell'];
return all;
});
};

Some files were not shown because too many files have changed in this diff Show More