mirror of
https://github.com/webinstall/webi-installers.git
synced 2026-02-14 17:49:53 +00:00
234 lines
6.3 KiB
JavaScript
234 lines
6.3 KiB
JavaScript
'use strict';
|
|
|
|
var Installers = module.exports;
|
|
|
|
var Crypto = require('crypto');
|
|
var Fs = require('node:fs/promises');
|
|
var path = require('node:path');
|
|
|
|
var reInstallTpl = /\s*#?\s*{{ installer }}/;
|
|
|
|
function padScript(txt) {
|
|
return txt.replace(/^/g, ' ');
|
|
}
|
|
|
|
var BAD_SH_RE = /[<>'"`$\\]/;
|
|
Installers.renderBash = async function (
|
|
pkgdir,
|
|
rel,
|
|
{ baseurl, pkg, tag, ver, os = '', arch = '', libc = '', formats },
|
|
) {
|
|
if (!Array.isArray(formats)) {
|
|
formats = [];
|
|
}
|
|
if (!tag) {
|
|
tag = '';
|
|
}
|
|
let installTxt = await Fs.readFile(path.join(pkgdir, 'install.sh'), 'utf8');
|
|
installTxt = padScript(installTxt);
|
|
var vers = rel.version.split('.');
|
|
var v = {
|
|
major: vers.shift() || '',
|
|
minor: vers.shift() || '',
|
|
patch: vers.join('.').replace(/[+\-].*/, ''),
|
|
build: vers
|
|
.join('.')
|
|
.replace(/[^+\-]*/, '')
|
|
.replace(/^-/, ''),
|
|
};
|
|
var pkgFile = rel.filename || rel.name;
|
|
let tplTxt = await Fs.readFile(
|
|
path.join(__dirname, 'package-install.tpl.sh'),
|
|
'utf8',
|
|
);
|
|
// ex: 'node@lts' or 'node'
|
|
var webiPkg = pkg;
|
|
if (ver) {
|
|
webiPkg += `@${ver}`;
|
|
}
|
|
|
|
let releaseParams = new URLSearchParams({
|
|
os: rel.os,
|
|
arch: rel.arch,
|
|
libc: rel.libc,
|
|
formats: formats.join(','),
|
|
pretty: true,
|
|
});
|
|
let releaseSearch = releaseParams.toString();
|
|
releaseSearch = releaseSearch.replace(/%2C/g, ',');
|
|
let releaseUrl = `/api/releases/${pkg}@${tag}.tab?${releaseSearch}`;
|
|
let releaseCsv = [
|
|
rel.version,
|
|
rel.lts,
|
|
rel.channel,
|
|
rel.date,
|
|
rel.os,
|
|
rel.arch,
|
|
rel.ext,
|
|
'-',
|
|
rel.download,
|
|
rel.name,
|
|
rel.comment || '',
|
|
]
|
|
.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_CSV', releaseCsv],
|
|
['WEBI_VERSION', rel.version],
|
|
['WEBI_MAJOR', v.major],
|
|
['WEBI_MINOR', v.minor],
|
|
['WEBI_PATCH', v.patch],
|
|
['WEBI_BUILD', v.build],
|
|
['WEBI_GIT_BRANCH', rel.git_branch || rel.git_tag],
|
|
['WEBI_GIT_TAG', rel.git_tag], // TODO replace with branch
|
|
['WEBI_LTS', rel.lts],
|
|
['WEBI_CHANNEL', rel.channel],
|
|
['WEBI_EXT', rel.ext],
|
|
['WEBI_FORMATS', formats.join(',')],
|
|
['WEBI_PKG_URL', rel.download],
|
|
['WEBI_PKG_PATHNAME', pkgFile],
|
|
['WEBI_PKG_FILE', pkgFile], // TODO replace with pathname
|
|
['PKG_NAME', pkg],
|
|
['PKG_STABLE', rel.stable],
|
|
['PKG_LATEST', rel.latest],
|
|
['PKG_OSES', (rel.oses || []).join(' ')],
|
|
['PKG_ARCHES', (rel.arches || []).join(' ')],
|
|
['PKG_LIBCS', (rel.libcs || []).join(' ')],
|
|
['PKG_FORMATS', (rel.formats || []).join(' ')],
|
|
];
|
|
|
|
for (let env of envReplacements) {
|
|
let name = env[0];
|
|
let value = env[1];
|
|
// Ex:
|
|
// #export WEBI_FOO=xyz => export WEBI_FOO='123'
|
|
// export WEBI_FOO= => export WEBI_FOO='123'
|
|
let envRe = new RegExp(
|
|
`^[ \\t]*#?[ \\t]*(export[ \\t])?[ \\t]*(${name})=.*`,
|
|
'm',
|
|
);
|
|
if (BAD_SH_RE.test(value)) {
|
|
throw new Error(`key '${name}' has invalid value '${value}'`);
|
|
}
|
|
tplTxt = tplTxt.replace(envRe, `$1$2='${value}'`);
|
|
}
|
|
|
|
tplTxt = tplTxt
|
|
.replace(/CHEATSHEET_URL/g, `${baseurl}/${pkg}`)
|
|
// $', $0, ... $9, $`, $&, and $_ all have special meaning
|
|
// (see https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RegExp)
|
|
// However, it can be escaped with $$ (which must be escaped with $$)
|
|
.replace(reInstallTpl, '\n' + installTxt.replace(/\$/g, '$$$$'));
|
|
return tplTxt;
|
|
};
|
|
|
|
Installers.renderPowerShell = async function (
|
|
pkgdir,
|
|
rel,
|
|
{ baseurl, pkg, tag, ver, os, arch, libc = '', formats },
|
|
) {
|
|
if (!Array.isArray(formats)) {
|
|
formats = [];
|
|
}
|
|
if (!tag) {
|
|
tag = '';
|
|
}
|
|
let installTxt = await Fs.readFile(path.join(pkgdir, 'install.ps1'), 'utf8');
|
|
installTxt = padScript(installTxt);
|
|
/*
|
|
var vers = rel.version.split('.');
|
|
var v = {
|
|
major: vers.shift() || '',
|
|
minor: vers.shift() || '',
|
|
patch: vers.join('.').replace(/[+\-].*$/, ''),
|
|
build: vers
|
|
.join('.')
|
|
.replace(/[^+\-]*()/, '')
|
|
.replace(/^-/, '')
|
|
};
|
|
*/
|
|
let tplTxt = await Fs.readFile(
|
|
path.join(__dirname, 'package-install.tpl.ps1'),
|
|
'utf8',
|
|
);
|
|
var pkgver = pkg + '@' + ver;
|
|
return (
|
|
tplTxt
|
|
.replace(
|
|
/^(#)?\$Env:WEBI_LIBC\s*=.*/im,
|
|
"$Env:WEBI_LIBC = '" + libc + "'",
|
|
)
|
|
.replace(
|
|
/^(#)?\$Env:WEBI_HOST\s*=.*/im,
|
|
"$Env:WEBI_HOST = '" + baseurl + "'",
|
|
)
|
|
.replace(
|
|
/^(#)?\$Env:WEBI_PKG\s*=.*/im,
|
|
"$Env:WEBI_PKG = '" + pkgver + "'",
|
|
)
|
|
.replace(/^(#)?\$Env:PKG_NAME\s*=.*/im, "$Env:PKG_NAME = '" + pkg + "'")
|
|
.replace(
|
|
/^(#)?\$Env:WEBI_VERSION\s*=.*/im,
|
|
"$Env:WEBI_VERSION = '" + rel.version + "'",
|
|
)
|
|
.replace(
|
|
/^(#)?\$Env:WEBI_GIT_TAG\s*=.*/im,
|
|
"$Env:WEBI_GIT_TAG = '" + rel.git_tag + "'",
|
|
)
|
|
.replace(
|
|
/^(#)?\$Env:WEBI_PKG_URL\s*=.*/im,
|
|
"$Env:WEBI_PKG_URL = '" + rel.download + "'",
|
|
)
|
|
// TODO replace WEBI_PKG_FILE (which is sometimes a dir)
|
|
.replace(
|
|
/^(#)?\$Env:WEBI_PKG_PATHNAME\s*=.*/im,
|
|
"$Env:WEBI_PKG_PATHNAME = '" + rel.name + "'",
|
|
)
|
|
// TODO deprecate
|
|
.replace(
|
|
/^(#)?\$Env:WEBI_PKG_FILE\s*=.*/im,
|
|
"$Env:WEBI_PKG_FILE = '" + rel.name + "'",
|
|
)
|
|
.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;
|
|
};
|