mirror of
https://github.com/webinstall/webi-installers.git
synced 2026-05-31 13:02:46 +00:00
Compare commits
29 Commits
ref-ssh-pu
...
feat-windo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6859ab4c2b | ||
|
|
f216ab69b4 | ||
|
|
941453677e | ||
|
|
556697ad67 | ||
|
|
595a0b8ef9 | ||
|
|
66ba82181c | ||
|
|
9d1cde0ced | ||
|
|
566b5c047f | ||
|
|
c71126fcd8 | ||
|
|
3263196360 | ||
|
|
5c12cb1fa7 | ||
|
|
b1738741d1 | ||
|
|
125ffa96dc | ||
|
|
dca40ff2ed | ||
|
|
36af48aceb | ||
|
|
9e9c3a610d | ||
|
|
fefeb076f2 | ||
|
|
e54262cf13 | ||
|
|
6c5b040b8c | ||
|
|
e872442f3b | ||
|
|
2d65bb14ff | ||
|
|
5ead8362c0 | ||
|
|
88a9319431 | ||
|
|
7b70ab8538 | ||
|
|
974e2cfc9c | ||
|
|
3810cd621e | ||
|
|
8ffba627f3 | ||
|
|
1a3f22e2ba | ||
|
|
48574168a8 |
@@ -98,9 +98,10 @@ You just fill in the blanks.
|
||||
Just create an empty directory and run the tests until you get a good result.
|
||||
|
||||
```sh
|
||||
git clone git@github.com:webinstall/packages.git
|
||||
pushd packages
|
||||
npm install
|
||||
git clone git@github.com:webinstall/webi-installers.git
|
||||
pushd ./webi-installers/
|
||||
git submodule update --init
|
||||
npm clean-install
|
||||
```
|
||||
|
||||
```sh
|
||||
|
||||
@@ -1,35 +1,46 @@
|
||||
'use strict';
|
||||
|
||||
var ghRelease = require('./github.js');
|
||||
var GitHubish = require('./githubish.js');
|
||||
|
||||
/**
|
||||
* Gets the releases for 'ripgrep'. This function could be trimmed down and made
|
||||
* for use with any github release.
|
||||
* Lists Gitea Releases (w/ uploaded assets)
|
||||
*
|
||||
* @param request
|
||||
* @param {string} owner
|
||||
* @param {string} repo
|
||||
* @returns {PromiseLike<any> | Promise<any>}
|
||||
* @param {any} _request - deprecated
|
||||
* @param {String} owner
|
||||
* @param {String} repo
|
||||
* @param {String} baseurl
|
||||
* @param {String} [username]
|
||||
* @param {String} [token]
|
||||
*/
|
||||
function getAllReleases(request, owner, repo, baseurl) {
|
||||
if (!baseurl) {
|
||||
return Promise.reject('missing baseurl');
|
||||
}
|
||||
return ghRelease(request, owner, repo, baseurl + '/api/v1').then(
|
||||
function (all) {
|
||||
return all;
|
||||
},
|
||||
);
|
||||
async function getAllReleases(
|
||||
_request,
|
||||
owner,
|
||||
repo,
|
||||
baseurl,
|
||||
username = '',
|
||||
token = '',
|
||||
) {
|
||||
baseurl = `${baseurl}/api/v1`;
|
||||
let all = await GitHubish.getAllReleases({
|
||||
owner,
|
||||
repo,
|
||||
baseurl,
|
||||
username,
|
||||
token,
|
||||
});
|
||||
return all;
|
||||
}
|
||||
|
||||
module.exports = getAllReleases;
|
||||
|
||||
if (module === require.main) {
|
||||
getAllReleases(
|
||||
require('@root/request'),
|
||||
'coolaj86',
|
||||
'go-pathman',
|
||||
'https://git.coolaj86.com',
|
||||
null,
|
||||
'root',
|
||||
'pathman',
|
||||
'https://git.rootprojects.org',
|
||||
'',
|
||||
'',
|
||||
).then(
|
||||
//getAllReleases(require('@root/request'), 'root', 'serviceman', 'https://git.rootprojects.org').then(
|
||||
function (all) {
|
||||
|
||||
@@ -1,102 +1,41 @@
|
||||
'use strict';
|
||||
|
||||
require('dotenv').config();
|
||||
require('dotenv').config({ path: '.env' });
|
||||
|
||||
let GitHubish = require('./githubish.js');
|
||||
|
||||
/**
|
||||
* Lists GitHub Releases (w/ uploaded assets)
|
||||
*
|
||||
* @param request
|
||||
* @param {string} owner
|
||||
* @param {string} repo
|
||||
* @returns {PromiseLike<any> | Promise<any>}
|
||||
* @param {any} _request - deprecated
|
||||
* @param {String} owner
|
||||
* @param {String} repo
|
||||
* @param {String} [baseurl]
|
||||
* @param {String} [username]
|
||||
* @param {String} [token]
|
||||
*/
|
||||
async function getAllReleases(
|
||||
request,
|
||||
_request,
|
||||
owner,
|
||||
repo,
|
||||
baseurl = 'https://api.github.com',
|
||||
username = process.env.GITHUB_USERNAME || '',
|
||||
token = process.env.GITHUB_TOKEN || '',
|
||||
) {
|
||||
if (!owner) {
|
||||
throw new Error('missing owner for repo');
|
||||
}
|
||||
if (!repo) {
|
||||
throw new Error('missing repo name');
|
||||
}
|
||||
|
||||
var req = {
|
||||
url: `${baseurl}/repos/${owner}/${repo}/releases`,
|
||||
json: true,
|
||||
};
|
||||
|
||||
// TODO I really don't like global config, find a way to do better
|
||||
if (process.env.GITHUB_USERNAME) {
|
||||
req.auth = {
|
||||
user: process.env.GITHUB_USERNAME,
|
||||
pass: process.env.GITHUB_TOKEN,
|
||||
};
|
||||
}
|
||||
|
||||
let resp = await request(req);
|
||||
if (!resp.ok) {
|
||||
console.error('Bad Resp Headers:', resp.headers);
|
||||
console.error('Bad Resp Body:', resp.body);
|
||||
throw new Error('the elusive releases BOOGEYMAN strikes again');
|
||||
}
|
||||
|
||||
let gHubResp = resp.body;
|
||||
let all = {
|
||||
releases: [],
|
||||
// todo make this ':baseurl' + ':releasename'
|
||||
download: '',
|
||||
};
|
||||
|
||||
try {
|
||||
gHubResp.forEach(transformReleases);
|
||||
} catch (e) {
|
||||
console.error(e.message);
|
||||
console.error('Error Headers:', resp.headers);
|
||||
console.error('Error Body:', resp.body);
|
||||
throw e;
|
||||
}
|
||||
|
||||
function transformReleases(release) {
|
||||
for (let asset of release['assets']) {
|
||||
let name = asset['name'];
|
||||
let date = release['published_at']?.replace(/T.*/, '');
|
||||
let download = asset['browser_download_url'];
|
||||
|
||||
// TODO tags aren't always semver / sensical
|
||||
let version = release['tag_name'];
|
||||
let channel;
|
||||
if (release['prerelease']) {
|
||||
// -rcX, -preview, -beta, etc will be checked in _webi/normalize.js
|
||||
channel = 'beta';
|
||||
}
|
||||
let lts = /(\b|_)(lts)(\b|_)/.test(release['tag_name']);
|
||||
|
||||
all.releases.push({
|
||||
name: name,
|
||||
version: version,
|
||||
lts: lts,
|
||||
channel: channel,
|
||||
date: date,
|
||||
os: '', // will be guessed by download filename
|
||||
arch: '', // will be guessed by download filename
|
||||
ext: '', // will be normalized
|
||||
download: download,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let all = await GitHubish.getAllReleases({
|
||||
owner,
|
||||
repo,
|
||||
baseurl,
|
||||
username,
|
||||
token,
|
||||
});
|
||||
return all;
|
||||
}
|
||||
|
||||
module.exports = getAllReleases;
|
||||
|
||||
if (module === require.main) {
|
||||
getAllReleases(require('@root/request'), 'BurntSushi', 'ripgrep').then(
|
||||
function (all) {
|
||||
console.info(JSON.stringify(all, null, 2));
|
||||
},
|
||||
);
|
||||
getAllReleases(null, 'BurntSushi', 'ripgrep').then(function (all) {
|
||||
console.info(JSON.stringify(all, null, 2));
|
||||
});
|
||||
}
|
||||
|
||||
124
_common/githubish.js
Normal file
124
_common/githubish.js
Normal file
@@ -0,0 +1,124 @@
|
||||
'use strict';
|
||||
|
||||
let GitHubish = module.exports;
|
||||
|
||||
/**
|
||||
* Lists GitHub-Like Releases (w/ uploaded assets)
|
||||
*
|
||||
* @param {Object} opts
|
||||
* @param {String} opts.owner
|
||||
* @param {String} opts.repo
|
||||
* @param {String} opts.baseurl
|
||||
* @param {String} [opts.username]
|
||||
* @param {String} [opts.token]
|
||||
*/
|
||||
GitHubish.getAllReleases = async function ({
|
||||
owner,
|
||||
repo,
|
||||
baseurl,
|
||||
username = '',
|
||||
token = '',
|
||||
}) {
|
||||
if (!owner) {
|
||||
throw new Error('missing owner for repo');
|
||||
}
|
||||
if (!repo) {
|
||||
throw new Error('missing repo name');
|
||||
}
|
||||
if (!baseurl) {
|
||||
throw new Error('missing baseurl');
|
||||
}
|
||||
|
||||
let url = `${baseurl}/repos/${owner}/${repo}/releases`;
|
||||
let opts = {
|
||||
headers: {
|
||||
'Content-Type': 'appplication/json',
|
||||
},
|
||||
};
|
||||
|
||||
if (token) {
|
||||
let userpass = `${username}:${token}`;
|
||||
let basicAuth = btoa(userpass);
|
||||
Object.assign(opts.headers, {
|
||||
Authorization: `Basic ${basicAuth}`,
|
||||
});
|
||||
}
|
||||
|
||||
let resp = await fetch(url, opts);
|
||||
if (!resp.ok) {
|
||||
let headers = Array.from(resp.headers);
|
||||
console.error('Bad Resp Headers:', headers);
|
||||
let text = await resp.text();
|
||||
console.error('Bad Resp Body:', text);
|
||||
let msg = `failed to fetch releases from '${baseurl}' with user '${username}'`;
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
||||
let respText = await resp.text();
|
||||
let gHubResp;
|
||||
try {
|
||||
gHubResp = JSON.parse(respText);
|
||||
} catch (e) {
|
||||
console.error('Bad Resp JSON:', respText);
|
||||
console.error(e.message);
|
||||
let msg = `failed to parse releases from '${baseurl}' with user '${username}'`;
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
||||
let all = {
|
||||
releases: [],
|
||||
// todo make this ':baseurl' + ':releasename'
|
||||
download: '',
|
||||
};
|
||||
|
||||
try {
|
||||
gHubResp.forEach(transformReleases);
|
||||
} catch (e) {
|
||||
console.error(e.message);
|
||||
console.error('Error Headers:', resp.headers);
|
||||
console.error('Error Body:', resp.body);
|
||||
let msg = `failed to transform releases from '${baseurl}' with user '${username}'`;
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
||||
function transformReleases(release) {
|
||||
for (let asset of release['assets']) {
|
||||
let name = asset['name'];
|
||||
let date = release['published_at']?.replace(/T.*/, '');
|
||||
let download = asset['browser_download_url'];
|
||||
|
||||
// TODO tags aren't always semver / sensical
|
||||
let version = release['tag_name'];
|
||||
let channel;
|
||||
if (release['prerelease']) {
|
||||
// -rcX, -preview, -beta, etc will be checked in _webi/normalize.js
|
||||
channel = 'beta';
|
||||
}
|
||||
let lts = /(\b|_)(lts)(\b|_)/.test(release['tag_name']);
|
||||
|
||||
all.releases.push({
|
||||
name: name,
|
||||
version: version,
|
||||
lts: lts,
|
||||
channel: channel,
|
||||
date: date,
|
||||
os: '', // will be guessed by download filename
|
||||
arch: '', // will be guessed by download filename
|
||||
ext: '', // will be normalized
|
||||
download: download,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return all;
|
||||
};
|
||||
|
||||
if (module === require.main) {
|
||||
GitHubish.getAllReleases({
|
||||
owner: 'BurntSushi',
|
||||
repo: 'ripgrep',
|
||||
baseurl: 'https://api.github.com',
|
||||
}).then(function (all) {
|
||||
console.info(JSON.stringify(all, null, 2));
|
||||
});
|
||||
}
|
||||
@@ -23,7 +23,7 @@ install:
|
||||
```text
|
||||
~/.config/envman/PATH.env
|
||||
~/.local/bin/foo
|
||||
~/.local/opt/foo
|
||||
~/.local/opt/foo/
|
||||
```
|
||||
|
||||
## Cheat Sheet
|
||||
|
||||
@@ -12,17 +12,19 @@ var repo = 'ripgrep';
|
||||
/** **/
|
||||
/******************************************************************************/
|
||||
|
||||
module.exports = function (request) {
|
||||
return github(request, owner, repo).then(function (all) {
|
||||
return all;
|
||||
});
|
||||
module.exports = async function (request) {
|
||||
let all = await github(request, owner, repo);
|
||||
return all;
|
||||
};
|
||||
|
||||
if (module === require.main) {
|
||||
module.exports(require('@root/request')).then(function (all) {
|
||||
all = require('../_webi/normalize.js')(all);
|
||||
(async function () {
|
||||
let request = require('@root/request');
|
||||
let normalize = require('../_webi/normalize.js');
|
||||
let all = await module.exports(request);
|
||||
all = normalize(all);
|
||||
// just select the first 5 for demonstration
|
||||
all.releases = all.releases.slice(0, 5);
|
||||
console.info(JSON.stringify(all, null, 2));
|
||||
});
|
||||
})();
|
||||
}
|
||||
|
||||
Submodule _webi/build-classifier updated: 54843f08f4...6b626a6d08
@@ -189,9 +189,10 @@ BuildsCacher.create = function ({ ALL_TERMS, installers, caches }) {
|
||||
}
|
||||
|
||||
let bc = {};
|
||||
bc.usedTerms = {};
|
||||
bc.orphanTerms = Object.assign({}, ALL_TERMS);
|
||||
bc.ALL_TERMS = ALL_TERMS;
|
||||
bc.orphanTerms = Object.assign({}, bc.ALL_TERMS);
|
||||
bc.unknownTerms = {};
|
||||
bc.usedTerms = {};
|
||||
bc.formats = [];
|
||||
bc._triplets = {};
|
||||
bc._targetsByBuildIdCache = {};
|
||||
@@ -381,7 +382,14 @@ BuildsCacher.create = function ({ ALL_TERMS, installers, caches }) {
|
||||
if (!projInfo) {
|
||||
projInfo = await getLatestBuilds(Releases, installersDir, cacheDir, name);
|
||||
}
|
||||
transformAndUpdate(name, projInfo, meta, tsDate);
|
||||
let latestProjInfo = await BuildsCacher.transformAndUpdate(
|
||||
name,
|
||||
projInfo,
|
||||
meta,
|
||||
tsDate,
|
||||
bc,
|
||||
);
|
||||
bc._caches[name] = latestProjInfo;
|
||||
|
||||
process.nextTick(async function () {
|
||||
let now = date.valueOf();
|
||||
@@ -393,103 +401,19 @@ BuildsCacher.create = function ({ ALL_TERMS, installers, caches }) {
|
||||
}
|
||||
|
||||
projInfo = await getLatestBuilds(Releases, installersDir, cacheDir, name);
|
||||
transformAndUpdate(name, projInfo, meta, date);
|
||||
let latestProjInfo = BuildsCacher.transformAndUpdate(
|
||||
name,
|
||||
projInfo,
|
||||
meta,
|
||||
date,
|
||||
bc,
|
||||
);
|
||||
bc._caches[name] = latestProjInfo;
|
||||
});
|
||||
|
||||
return projInfo;
|
||||
};
|
||||
|
||||
function transformAndUpdate(name, projInfo, meta, date) {
|
||||
meta.packages = [];
|
||||
|
||||
let updated = date.valueOf();
|
||||
|
||||
Object.assign(projInfo, { name, updated }, meta);
|
||||
for (let build of projInfo.releases) {
|
||||
let buildTarget = bc.classify(projInfo, build);
|
||||
if (!buildTarget) {
|
||||
// ignore known, non-package extensions
|
||||
continue;
|
||||
}
|
||||
|
||||
if (buildTarget.error) {
|
||||
let err = buildTarget.error;
|
||||
let code = err.code || '';
|
||||
console.error(`[ERROR]: ${code} ${projInfo.name}: ${build.name}`);
|
||||
console.error(`>>> ${err.message} <<<`);
|
||||
console.error(projInfo);
|
||||
console.error(build);
|
||||
console.error(`^^^ ${err.message} ^^^`);
|
||||
console.error(err.stack);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!build.name) {
|
||||
build.name = build.download.replace(/.*\//, '');
|
||||
}
|
||||
|
||||
build.target = buildTarget;
|
||||
meta.packages.push(build);
|
||||
}
|
||||
|
||||
updateReleasesByTriplet(meta);
|
||||
updateAndSortVersions(projInfo, meta);
|
||||
|
||||
Object.assign(projInfo, { name, updated }, meta);
|
||||
bc._caches[name] = projInfo;
|
||||
}
|
||||
|
||||
function updateReleasesByTriplet(meta) {
|
||||
for (let build of meta.packages) {
|
||||
let target = build.target;
|
||||
|
||||
let triplet = `${target.os}-${target.arch}-${target.libc}`;
|
||||
if (!meta.releasesByTriplet[triplet]) {
|
||||
meta.releasesByTriplet[triplet] = {};
|
||||
}
|
||||
|
||||
let buildsByRelease = meta.releasesByTriplet[triplet];
|
||||
if (!buildsByRelease[build.version]) {
|
||||
buildsByRelease[build.version] = [];
|
||||
}
|
||||
|
||||
let packages = buildsByRelease[build.version];
|
||||
packages.push(build);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
// - tag channels
|
||||
function updateAndSortVersions(projInfo, meta) {
|
||||
for (let build of projInfo.packages) {
|
||||
let hasVersion = meta.versions.includes(build.version);
|
||||
if (!hasVersion) {
|
||||
build.lexver = Lexver.parseVersion(build.version);
|
||||
meta.lexversMap[build.lexver] = build.version;
|
||||
}
|
||||
}
|
||||
|
||||
meta.lexvers = Object.keys(meta.lexversMap);
|
||||
meta.lexvers.sort();
|
||||
meta.lexvers.reverse();
|
||||
|
||||
meta.versions = [];
|
||||
for (let lexver of meta.lexvers) {
|
||||
let version = meta.lexversMap[lexver];
|
||||
meta.versions.push(version);
|
||||
}
|
||||
|
||||
projInfo.packages.sort(function (a, b) {
|
||||
if (a.lexver > b.lexver) {
|
||||
return -1;
|
||||
}
|
||||
if (a.lexver < b.lexver) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
// Makes sure that packages are updated once an hour, on average
|
||||
bc._staleNames = [];
|
||||
bc._freshenTimeout = null;
|
||||
@@ -525,134 +449,6 @@ BuildsCacher.create = function ({ ALL_TERMS, installers, caches }) {
|
||||
bc._freshenTimeout.unref();
|
||||
};
|
||||
|
||||
bc.classify = function (projInfo, build) {
|
||||
/* jshint maxcomplexity: 25 */
|
||||
let maybeInstallable = Triplet.maybeInstallable(projInfo, build);
|
||||
if (!maybeInstallable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (LEGACY_OS_MAP[build.os]) {
|
||||
build.os = LEGACY_OS_MAP[build.os];
|
||||
}
|
||||
if (LEGACY_ARCH_MAP[build.arch]) {
|
||||
build.arch = LEGACY_ARCH_MAP[build.arch];
|
||||
}
|
||||
|
||||
// because some packages are shimmed to match a single download against
|
||||
let preTarget = Object.assign({ os: '', arch: '', libc: '' }, build);
|
||||
|
||||
let targetId = `${preTarget.os}:${preTarget.arch}:${preTarget.libc}`;
|
||||
let buildId = `${projInfo.name}:${targetId}@${build.download}`;
|
||||
let target = bc._targetsByBuildIdCache[buildId];
|
||||
if (target) {
|
||||
Object.assign(build, { target: target, triplet: target.triplet });
|
||||
return target;
|
||||
}
|
||||
|
||||
let pattern = Triplet.toPattern(projInfo, build);
|
||||
if (!pattern) {
|
||||
let err = new Error(`no pattern generated for ${projInfo.name}`);
|
||||
err.code = 'E_BUILD_NO_PATTERN';
|
||||
target = { error: err };
|
||||
bc._targetsByBuildIdCache[buildId] = target;
|
||||
return target;
|
||||
}
|
||||
|
||||
let rawTerms = pattern.split(/[_\{\}\/\.\-]+/g);
|
||||
for (let term of rawTerms) {
|
||||
delete bc.orphanTerms[term];
|
||||
bc.usedTerms[term] = true;
|
||||
}
|
||||
|
||||
// {NAME}/{NAME}-{VER}-Windows-x86_64_v2-musl.exe =>
|
||||
// {NAME}.windows.x86_64v2.musl.exe
|
||||
let terms = Triplet.patternToTerms(pattern);
|
||||
if (!terms.length) {
|
||||
let err = new Error(`'${terms}' was trimmed to ''`);
|
||||
target = { error: err };
|
||||
bc._targetsByBuildIdCache[buildId] = target;
|
||||
return target;
|
||||
}
|
||||
|
||||
for (let term of terms) {
|
||||
if (!term) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ALL_TERMS[term]) {
|
||||
delete bc.orphanTerms[term];
|
||||
bc.usedTerms[term] = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
bc.unknownTerms[term] = true;
|
||||
}
|
||||
|
||||
// {NAME}.windows.x86_64v2.musl.exe
|
||||
// windows-x86_64_v2-musl
|
||||
target = { triplet: '' };
|
||||
void Triplet.termsToTarget(target, projInfo, build, terms);
|
||||
|
||||
target.triplet = `${target.arch}-${target.vendor}-${target.os}-${target.libc}`;
|
||||
|
||||
{
|
||||
// TODO I don't love this hidden behavior
|
||||
// perhaps classify should just happen when the package is loaded
|
||||
// (and the sanity error should be removed, or thrown after the loop is complete)
|
||||
let hasTriplet = projInfo.triplets.includes(target.triplet);
|
||||
if (!hasTriplet) {
|
||||
projInfo.triplets.push(target.triplet);
|
||||
}
|
||||
let hasOs = projInfo.oses.includes(target.os);
|
||||
if (!hasOs) {
|
||||
projInfo.oses.push(target.os);
|
||||
}
|
||||
let hasArch = projInfo.arches.includes(target.arch);
|
||||
if (!hasArch) {
|
||||
projInfo.arches.push(target.arch);
|
||||
}
|
||||
let hasLibc = projInfo.libcs.includes(target.libc);
|
||||
if (!hasLibc) {
|
||||
projInfo.libcs.push(target.libc);
|
||||
}
|
||||
|
||||
if (!build.ext) {
|
||||
build.ext = Triplet.buildToPackageType(build);
|
||||
}
|
||||
if (build.ext) {
|
||||
if (!build.ext.startsWith('.')) {
|
||||
build.ext = `.${build.ext}`;
|
||||
}
|
||||
}
|
||||
let hasExt = projInfo.formats.includes(build.ext);
|
||||
if (!hasExt) {
|
||||
projInfo.formats.push(build.ext);
|
||||
}
|
||||
let hasGlobalExt = bc.formats.includes(build.ext);
|
||||
if (!hasGlobalExt) {
|
||||
bc.formats.push(build.ext);
|
||||
}
|
||||
}
|
||||
|
||||
bc._triplets[target.triplet] = true;
|
||||
bc._targetsByBuildIdCache[buildId] = target;
|
||||
|
||||
let triple = [target.arch, target.vendor, target.os, target.libc];
|
||||
for (let term of triple) {
|
||||
if (!ALL_TERMS[term]) {
|
||||
throw new Error(
|
||||
`[SANITY FAIL] '${projInfo.name}' '${target.triplet}' generated unknown term '${term}'`,
|
||||
);
|
||||
}
|
||||
|
||||
delete bc.orphanTerms[term];
|
||||
bc.usedTerms[term] = true;
|
||||
}
|
||||
|
||||
return target;
|
||||
};
|
||||
|
||||
/**
|
||||
* Given a list of acceptable formats, get the sorted list of of formats.
|
||||
* Actually used (as per node _webi/lint-builds.js):
|
||||
@@ -967,3 +763,233 @@ BuildsCacher.create = function ({ ALL_TERMS, installers, caches }) {
|
||||
|
||||
return bc;
|
||||
};
|
||||
|
||||
BuildsCacher._classify = function (bc, projInfo, build) {
|
||||
/* jshint maxcomplexity: 25 */
|
||||
let maybeInstallable = Triplet.maybeInstallable(projInfo, build);
|
||||
if (!maybeInstallable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (LEGACY_OS_MAP[build.os]) {
|
||||
build.os = LEGACY_OS_MAP[build.os];
|
||||
}
|
||||
if (LEGACY_ARCH_MAP[build.arch]) {
|
||||
build.arch = LEGACY_ARCH_MAP[build.arch];
|
||||
}
|
||||
|
||||
// because some packages are shimmed to match a single download against
|
||||
let preTarget = Object.assign({ os: '', arch: '', libc: '' }, build);
|
||||
|
||||
let targetId = `${preTarget.os}:${preTarget.arch}:${preTarget.libc}`;
|
||||
let buildId = `${projInfo.name}:${targetId}@${build.download}`;
|
||||
//console.log(`dbg: buildId`, buildId);
|
||||
let target = bc._targetsByBuildIdCache[buildId];
|
||||
if (target) {
|
||||
Object.assign(build, { target: target, triplet: target.triplet });
|
||||
return target;
|
||||
}
|
||||
|
||||
let pattern = Triplet.toPattern(projInfo, build);
|
||||
//console.log(`dbg: pattern`, pattern);
|
||||
if (!pattern) {
|
||||
let err = new Error(`no pattern generated for ${projInfo.name}`);
|
||||
err.code = 'E_BUILD_NO_PATTERN';
|
||||
target = { error: err };
|
||||
bc._targetsByBuildIdCache[buildId] = target;
|
||||
return target;
|
||||
}
|
||||
|
||||
let rawTerms = pattern.split(/[_\{\}\/\.\-]+/g);
|
||||
//console.log(`dbg: rawTerms`, rawTerms);
|
||||
for (let term of rawTerms) {
|
||||
delete bc.orphanTerms[term];
|
||||
bc.usedTerms[term] = true;
|
||||
}
|
||||
|
||||
// {NAME}/{NAME}-{VER}-Windows-x86_64_v2-musl.exe =>
|
||||
// {NAME}.windows.x86_64v2.musl.exe
|
||||
let terms = Triplet.patternToTerms(pattern);
|
||||
//console.log(`dbg: terms`, terms);
|
||||
if (!terms.length) {
|
||||
let err = new Error(`'${terms}' was trimmed to ''`);
|
||||
target = { error: err };
|
||||
bc._targetsByBuildIdCache[buildId] = target;
|
||||
return target;
|
||||
}
|
||||
|
||||
for (let term of terms) {
|
||||
if (!term) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bc.ALL_TERMS[term]) {
|
||||
delete bc.orphanTerms[term];
|
||||
bc.usedTerms[term] = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
bc.unknownTerms[term] = true;
|
||||
}
|
||||
|
||||
// {NAME}.windows.x86_64v2.musl.exe
|
||||
// windows-x86_64_v2-musl
|
||||
target = { triplet: '' };
|
||||
try {
|
||||
void Triplet.termsToTarget(target, projInfo, build, terms);
|
||||
} catch (e) {
|
||||
console.error(`PACKAGE FORMAT CHANGE for '${projInfo.name}':`);
|
||||
console.error(e.message);
|
||||
console.error(build);
|
||||
return null;
|
||||
}
|
||||
|
||||
target.triplet = `${target.arch}-${target.vendor}-${target.os}-${target.libc}`;
|
||||
|
||||
{
|
||||
// TODO I don't love this hidden behavior
|
||||
// perhaps classify should just happen when the package is loaded
|
||||
// (and the sanity error should be removed, or thrown after the loop is complete)
|
||||
let hasTriplet = projInfo.triplets.includes(target.triplet);
|
||||
if (!hasTriplet) {
|
||||
projInfo.triplets.push(target.triplet);
|
||||
}
|
||||
let hasOs = projInfo.oses.includes(target.os);
|
||||
if (!hasOs) {
|
||||
projInfo.oses.push(target.os);
|
||||
}
|
||||
let hasArch = projInfo.arches.includes(target.arch);
|
||||
if (!hasArch) {
|
||||
projInfo.arches.push(target.arch);
|
||||
}
|
||||
let hasLibc = projInfo.libcs.includes(target.libc);
|
||||
if (!hasLibc) {
|
||||
projInfo.libcs.push(target.libc);
|
||||
}
|
||||
|
||||
if (!build.ext) {
|
||||
build.ext = Triplet.buildToPackageType(build);
|
||||
}
|
||||
if (build.ext) {
|
||||
if (!build.ext.startsWith('.')) {
|
||||
build.ext = `.${build.ext}`;
|
||||
}
|
||||
}
|
||||
let hasExt = projInfo.formats.includes(build.ext);
|
||||
if (!hasExt) {
|
||||
projInfo.formats.push(build.ext);
|
||||
}
|
||||
let hasGlobalExt = bc.formats.includes(build.ext);
|
||||
if (!hasGlobalExt) {
|
||||
bc.formats.push(build.ext);
|
||||
}
|
||||
}
|
||||
|
||||
bc._triplets[target.triplet] = true;
|
||||
bc._targetsByBuildIdCache[buildId] = target;
|
||||
|
||||
let triple = [target.arch, target.vendor, target.os, target.libc];
|
||||
for (let term of triple) {
|
||||
if (!bc.ALL_TERMS[term]) {
|
||||
throw new Error(
|
||||
`[SANITY FAIL] '${projInfo.name}' '${target.triplet}' generated unknown term '${term}'`,
|
||||
);
|
||||
}
|
||||
|
||||
delete bc.orphanTerms[term];
|
||||
bc.usedTerms[term] = true;
|
||||
}
|
||||
|
||||
return target;
|
||||
};
|
||||
|
||||
BuildsCacher.transformAndUpdate = function (name, projInfo, meta, date, bc) {
|
||||
meta.packages = [];
|
||||
|
||||
let updated = date.valueOf();
|
||||
|
||||
Object.assign(projInfo, { name, updated }, meta);
|
||||
for (let build of projInfo.releases) {
|
||||
let buildTarget = BuildsCacher._classify(bc, projInfo, build);
|
||||
if (!buildTarget) {
|
||||
// ignore known, non-package extensions
|
||||
continue;
|
||||
}
|
||||
|
||||
if (buildTarget.error) {
|
||||
let err = buildTarget.error;
|
||||
let code = err.code || '';
|
||||
console.error(`[ERROR]: ${code} ${projInfo.name}: ${build.name}`);
|
||||
console.error(`>>> ${err.message} <<<`);
|
||||
console.error(projInfo);
|
||||
console.error(build);
|
||||
console.error(`^^^ ${err.message} ^^^`);
|
||||
console.error(err.stack);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!build.name) {
|
||||
build.name = build.download.replace(/.*\//, '');
|
||||
}
|
||||
|
||||
build.target = buildTarget;
|
||||
meta.packages.push(build);
|
||||
}
|
||||
|
||||
BuildsCacher.updateReleasesByTriplet(meta);
|
||||
BuildsCacher.updateAndSortVersions(projInfo, meta);
|
||||
|
||||
Object.assign(projInfo, { name, updated }, meta);
|
||||
return projInfo;
|
||||
};
|
||||
|
||||
// TODO
|
||||
// - tag channels
|
||||
BuildsCacher.updateAndSortVersions = function (projInfo, meta) {
|
||||
for (let build of projInfo.packages) {
|
||||
let hasVersion = meta.versions.includes(build.version);
|
||||
if (!hasVersion) {
|
||||
build.lexver = Lexver.parseVersion(build.version);
|
||||
meta.lexversMap[build.lexver] = build.version;
|
||||
}
|
||||
}
|
||||
|
||||
meta.lexvers = Object.keys(meta.lexversMap);
|
||||
meta.lexvers.sort();
|
||||
meta.lexvers.reverse();
|
||||
|
||||
meta.versions = [];
|
||||
for (let lexver of meta.lexvers) {
|
||||
let version = meta.lexversMap[lexver];
|
||||
meta.versions.push(version);
|
||||
}
|
||||
|
||||
projInfo.packages.sort(function (a, b) {
|
||||
if (a.lexver > b.lexver) {
|
||||
return -1;
|
||||
}
|
||||
if (a.lexver < b.lexver) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
};
|
||||
|
||||
BuildsCacher.updateReleasesByTriplet = function (meta) {
|
||||
for (let build of meta.packages) {
|
||||
let target = build.target;
|
||||
|
||||
let triplet = `${target.os}-${target.arch}-${target.libc}`;
|
||||
if (!meta.releasesByTriplet[triplet]) {
|
||||
meta.releasesByTriplet[triplet] = {};
|
||||
}
|
||||
|
||||
let buildsByRelease = meta.releasesByTriplet[triplet];
|
||||
if (!buildsByRelease[build.version]) {
|
||||
buildsByRelease[build.version] = [];
|
||||
}
|
||||
|
||||
let packages = buildsByRelease[build.version];
|
||||
packages.push(build);
|
||||
}
|
||||
};
|
||||
|
||||
92
_webi/classify-one.js
Normal file
92
_webi/classify-one.js
Normal file
@@ -0,0 +1,92 @@
|
||||
'use strict';
|
||||
|
||||
let Path = require('node:path');
|
||||
|
||||
// let Builds = require('./builds.js');
|
||||
let BuildsCacher = require('./builds-cacher.js');
|
||||
let Triplet = require('./build-classifier/triplet.js');
|
||||
|
||||
let request = require('@root/request');
|
||||
|
||||
async function main() {
|
||||
let projName = process.argv[2];
|
||||
if (!projName) {
|
||||
console.error(``);
|
||||
console.error(`USAGE`);
|
||||
console.error(``);
|
||||
console.error(` classify-one <project-name>`);
|
||||
console.error(``);
|
||||
console.error(`EXAMPLE`);
|
||||
console.error(``);
|
||||
console.error(` classify-one caddy`);
|
||||
console.error(``);
|
||||
return;
|
||||
}
|
||||
|
||||
let tsDate = new Date(0);
|
||||
let meta = {
|
||||
// version info
|
||||
versions: [],
|
||||
lexvers: [],
|
||||
lexversMap: {},
|
||||
// culled release assets
|
||||
packages: [],
|
||||
releasesByTriplet: {},
|
||||
// target info
|
||||
triplets: [],
|
||||
oses: [],
|
||||
arches: [],
|
||||
libcs: [],
|
||||
formats: [],
|
||||
// TODO channels: [],
|
||||
};
|
||||
|
||||
let installersDir = Path.join(__dirname, '..');
|
||||
let Releases = require(`${installersDir}/${projName}/releases.js`);
|
||||
if (!Releases.latest) {
|
||||
Releases.latest = Releases;
|
||||
}
|
||||
|
||||
let projInfo = await Releases.latest(request);
|
||||
|
||||
// let packages = await Builds.getPackage({ name: projName });
|
||||
// console.log(packages);
|
||||
|
||||
let bc = {};
|
||||
bc.ALL_TERMS = Triplet.TERMS_PRIMARY_MAP;
|
||||
bc.orphanTerms = Object.assign({}, bc.ALL_TERMS);
|
||||
bc.unknownTerms = {};
|
||||
bc.usedTerms = {};
|
||||
bc.formats = [];
|
||||
bc._targetsByBuildIdCache = {};
|
||||
bc._triplets = {};
|
||||
|
||||
let transformed = BuildsCacher.transformAndUpdate(
|
||||
projName,
|
||||
projInfo,
|
||||
meta,
|
||||
tsDate,
|
||||
bc,
|
||||
);
|
||||
|
||||
console.log(`[DEBUG] transformed`);
|
||||
let sample = transformed.packages.slice(0, 20);
|
||||
console.log('packages:', sample, ':packages');
|
||||
console.log(
|
||||
'releasesByTriplet:',
|
||||
transformed.releasesByTriplet['linux-x86_64-none'][transformed.versions[0]],
|
||||
':releasesByTriplet',
|
||||
);
|
||||
console.log('versions:', transformed.versions, ':versions');
|
||||
console.log('triplets:', transformed.triplets, ':triplets');
|
||||
console.log('oses:', transformed.oses, ':oses');
|
||||
console.log('arches:', transformed.arches, ':arches');
|
||||
console.log('libcs:', transformed.libcs, ':libcs');
|
||||
console.log('formats:', transformed.formats, ':formats');
|
||||
console.log(Object.keys(transformed));
|
||||
}
|
||||
|
||||
main().catch(function (err) {
|
||||
console.error('Error:');
|
||||
console.error(err);
|
||||
});
|
||||
@@ -202,7 +202,7 @@ __bootstrap_webi() {
|
||||
unzstd -c --keep "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" | tar xf -
|
||||
elif test "$WEBI_EXT" = "tar.xz"; then
|
||||
echo " Extracting $(t_path "${my_dl_rel}")"
|
||||
unxz -c --keep "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" | tar xf -
|
||||
unxz -c -k "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" | tar xf -
|
||||
elif test "$WEBI_EXT" = "tar.gz"; then
|
||||
echo " Extracting $(t_path "${my_dl_rel}")"
|
||||
tar xzf "${WEBI_PKG_PATH}/$WEBI_PKG_FILE"
|
||||
@@ -235,8 +235,6 @@ __bootstrap_webi() {
|
||||
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)
|
||||
@@ -399,7 +397,6 @@ __bootstrap_webi() {
|
||||
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
|
||||
@@ -408,6 +405,7 @@ __bootstrap_webi() {
|
||||
echo " Creating$(t_path ' ~/.local/bin')"
|
||||
mkdir -p "$HOME/.local/bin"
|
||||
fi
|
||||
fn_envman_init
|
||||
|
||||
##
|
||||
##
|
||||
|
||||
47
cilium/README.md
Normal file
47
cilium/README.md
Normal file
@@ -0,0 +1,47 @@
|
||||
---
|
||||
title: cilium
|
||||
homepage: https://github.com/cilium/cilium-cli
|
||||
tagline: |
|
||||
cilium: manage & troubleshoot Kubernetes clusters running Cilium
|
||||
---
|
||||
|
||||
To update or switch versions, run `webi cilium@stable` (or `@v2`, `@beta`,etc).
|
||||
|
||||
### Files
|
||||
|
||||
These are the files / directories that are created and/or modified with this
|
||||
install:
|
||||
|
||||
```text
|
||||
~/.config/envman/PATH.env
|
||||
~/.local/bin/cilium
|
||||
~/.local/opt/cilium/
|
||||
```
|
||||
|
||||
## Cheat Sheet
|
||||
|
||||
> Cilium is an open source, cloud native solution for providing, securing, and
|
||||
> observing network connectivity between workloads, fueled by the revolutionary
|
||||
> Kernel technology eBPF.
|
||||
|
||||
Quick Start User Guide:
|
||||
|
||||
<https://docs.cilium.io/en/stable/gettingstarted/k8s-install-default/#k8s-install-quick>
|
||||
|
||||
To install the default version of the Cilium image:
|
||||
|
||||
```sh
|
||||
cilium install
|
||||
```
|
||||
|
||||
To upgrade to a specific version of the Cilium image:
|
||||
|
||||
```sh
|
||||
cilium upgrade --version v1.15.3
|
||||
```
|
||||
|
||||
To check the status of the current Cilium deployment:
|
||||
|
||||
```sh
|
||||
cilium status
|
||||
```
|
||||
45
cilium/install.ps1
Normal file
45
cilium/install.ps1
Normal file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env pwsh
|
||||
|
||||
##################
|
||||
# Install cilium #
|
||||
##################
|
||||
|
||||
$pkg_cmd_name = "cilium"
|
||||
|
||||
$pkg_dst_cmd = "$Env:USERPROFILE\.local\bin\cilium.exe"
|
||||
$pkg_dst = "$pkg_dst_cmd"
|
||||
|
||||
$pkg_src_cmd = "$Env:USERPROFILE\.local\opt\cilium-v$Env:WEBI_VERSION\bin\cilium.exe"
|
||||
$pkg_src_bin = "$Env:USERPROFILE\.local\opt\cilium-v$Env:WEBI_VERSION\bin"
|
||||
$pkg_src_dir = "$Env:USERPROFILE\.local\opt\cilium-v$Env:WEBI_VERSION"
|
||||
$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"
|
||||
|
||||
IF (!(Test-Path -Path "$Env:USERPROFILE\Downloads\webi\$Env:WEBI_PKG_FILE")) {
|
||||
Write-Output "Downloading cilium from $Env:WEBI_PKG_URL to $pkg_download"
|
||||
& curl.exe -A "$Env:WEBI_UA" -fsSL "$Env:WEBI_PKG_URL" -o "$pkg_download.part"
|
||||
& Move-Item "$pkg_download.part" "$pkg_download"
|
||||
}
|
||||
|
||||
IF (!(Test-Path -Path "$pkg_src_cmd")) {
|
||||
Write-Output "Installing cilium"
|
||||
Push-Location .local\tmp
|
||||
|
||||
Remove-Item -Path ".\cilium-v*" -Recurse -ErrorAction Ignore
|
||||
Remove-Item -Path ".\cilium.exe" -Recurse -ErrorAction Ignore
|
||||
|
||||
Write-Output "Unpacking $pkg_download"
|
||||
& tar xf "$pkg_download"
|
||||
|
||||
Write-Output "Install Location: $pkg_src_cmd"
|
||||
New-Item "$pkg_src_bin" -ItemType Directory -Force
|
||||
Move-Item -Path ".\cilium-*\cilium.exe" -Destination "$pkg_src_bin"
|
||||
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
Write-Output "Copying into '$pkg_dst_cmd' from '$pkg_src_cmd'"
|
||||
Remove-Item -Path "$pkg_dst_cmd" -Recurse -ErrorAction Ignore
|
||||
Copy-Item -Path "$pkg_src" -Destination "$pkg_dst" -Recurse
|
||||
39
cilium/install.sh
Normal file
39
cilium/install.sh
Normal file
@@ -0,0 +1,39 @@
|
||||
#!/bin/sh
|
||||
|
||||
__init_cilium() {
|
||||
set -e
|
||||
set -u
|
||||
|
||||
##################
|
||||
# Install cilium #
|
||||
##################
|
||||
|
||||
pkg_cmd_name="cilium"
|
||||
|
||||
pkg_dst_cmd="$HOME/.local/bin/cilium"
|
||||
pkg_dst="$pkg_dst_cmd"
|
||||
|
||||
pkg_src_cmd="$HOME/.local/opt/cilium-v$WEBI_VERSION/bin/cilium"
|
||||
pkg_src_dir="$HOME/.local/opt/cilium-v$WEBI_VERSION"
|
||||
pkg_src="$pkg_src_cmd"
|
||||
|
||||
WEBI_SINGLE=true
|
||||
|
||||
# pkg_install must be defined by every package
|
||||
pkg_install() {
|
||||
# ~/.local/opt/cilium-v0.16.16/bin
|
||||
mkdir -p "$(dirname "${pkg_src_cmd}")"
|
||||
|
||||
# mv ./hugo ~/.local/opt/cilium-v0.16.16/bin/
|
||||
mv ./cilium "${pkg_src_cmd}"
|
||||
}
|
||||
|
||||
pkg_get_current_version() {
|
||||
cilium version 2> /dev/null |
|
||||
head -n 1 |
|
||||
cut -d ' ' -f 2
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
__init_cilium
|
||||
22
cilium/releases.js
Normal file
22
cilium/releases.js
Normal file
@@ -0,0 +1,22 @@
|
||||
'use strict';
|
||||
|
||||
var github = require('../_common/github.js');
|
||||
var owner = 'cilium';
|
||||
var repo = 'cilium-cli';
|
||||
|
||||
module.exports = async function (request) {
|
||||
let all = await github(request, owner, repo);
|
||||
return all;
|
||||
};
|
||||
|
||||
if (module === require.main) {
|
||||
(async function () {
|
||||
let request = require('@root/request');
|
||||
let normalize = require('../_webi/normalize.js');
|
||||
let all = await module.exports(request);
|
||||
all = normalize(all);
|
||||
// just select the first 5 for demonstration
|
||||
all.releases = all.releases.slice(0, 5);
|
||||
console.info(JSON.stringify(all, null, 2));
|
||||
})();
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: koji
|
||||
homepage: https://github.com/its-danny/koji
|
||||
homepage: https://github.com/cococonscious/koji
|
||||
tagline: |
|
||||
🦊 An interactive CLI for creating conventional commits.
|
||||
---
|
||||
@@ -13,7 +13,7 @@ To update or switch versions, run `webi koji@stable` (or `@v2`, `@beta`, etc).
|
||||
|
||||
> `koji` is an interactive CLI for creating [conventional commits][cc].
|
||||
|
||||

|
||||

|
||||
|
||||
[cc]: https://conventionalcommits.org/en/v1.0.0/
|
||||
|
||||
@@ -105,4 +105,4 @@ description = "A new feature"
|
||||
```
|
||||
|
||||
The default emoji can be seen in
|
||||
[koji-default.toml](https://github.com/its-danny/koji/blob/main/meta/config/koji-default.toml).
|
||||
[default.toml](https://github.com/cococonscious/koji/blob/main/meta/config/default.toml).
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var github = require('../_common/github.js');
|
||||
var owner = 'its-danny';
|
||||
var owner = 'cococonscious';
|
||||
var repo = 'koji';
|
||||
|
||||
module.exports = function (request) {
|
||||
|
||||
@@ -45,8 +45,10 @@ __init_pwsh() {
|
||||
}
|
||||
|
||||
pkg_done_message() {
|
||||
echo "Installed 'pwsh' at $pkg_dst"
|
||||
pwsh -V
|
||||
# We print the version here to ensure the install completed without
|
||||
# errors - no missing libraries, not incompatible arch, etc
|
||||
echo ""
|
||||
"$pkg_dst_cmd" -V
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -74,26 +74,24 @@ main() {
|
||||
else
|
||||
my_keytype='rsa'
|
||||
echo >&2 ""
|
||||
echo >&2 "Generating public/private rsa key pair."
|
||||
ssh-keygen -b 4096 -t rsa -f ~/.ssh/id_rsa -q -N ""
|
||||
ssh-keygen -y -f ~/.ssh/id_rsa > ~/.ssh/id_rsa.pub
|
||||
fi
|
||||
|
||||
my_comment="$(tr '[:space:]' '\n' < "$HOME/.ssh/id_${my_keytype}.pub" | grep '\w' | tail -n 1)"
|
||||
if test -z "${my_comment}" || test "${my_comment#}" -gt 100; then
|
||||
my_comment="$(id -u -n)"
|
||||
fi
|
||||
# TODO use the comment (if any) for the name of the file
|
||||
echo >&2 ""
|
||||
#shellcheck disable=SC2088
|
||||
echo >&2 "~/Downloads/id_${my_keytype}.${my_comment}.pub":
|
||||
echo >&2 "~/Downloads/id_${my_keytype}.$(whoami).pub":
|
||||
echo >&2 ""
|
||||
rm -f "$HOME/Downloads/id_${my_keytype}.${my_comment}.pub"
|
||||
cp -RPp "$HOME/.ssh/id_${my_keytype}.pub" "$HOME/Downloads/id_${my_keytype}.${my_comment}.pub"
|
||||
cat "$HOME/Downloads/id_${my_keytype}.${my_comment}.pub"
|
||||
rm -f "$HOME/Downloads/id_${my_keytype}.$(whoami).pub"
|
||||
cp -RPp "$HOME/.ssh/id_${my_keytype}.pub" "$HOME/Downloads/id_${my_keytype}.$(whoami).pub"
|
||||
cat "$HOME/Downloads/id_${my_keytype}.$(whoami).pub"
|
||||
echo >&2 ""
|
||||
|
||||
if test -f ~/.ssh/id_rsa; then
|
||||
my_rsa_size="$(wc < ~/.ssh/id_rsa | rev | cut -d' ' -f1 | rev)"
|
||||
if test "${my_rsa_size}" -lt 2500; then
|
||||
my_rsa_chars="$(cat ~/.ssh/id_rsa)"
|
||||
if test "${#my_rsa_chars}" -lt 2500; then
|
||||
fn_warn_rsa >&2
|
||||
echo >&2 ""
|
||||
fi
|
||||
|
||||
30
sshd/README.md
Normal file
30
sshd/README.md
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
title: OpenSSH (for Windows)
|
||||
homepage: https://webinstall.dev/sshd
|
||||
tagline: |
|
||||
OpenSSH: Window's built-in SSH implementation for remote login
|
||||
---
|
||||
|
||||
To update (replacing the current version) run `webi sudo`.
|
||||
|
||||
## Cheat Sheet
|
||||
|
||||
> Does the tedious work of installing, registering, and starting Windows' built-in OpenSSH Server (`sshd`)
|
||||
|
||||
As this requires Administrator permissions, you must run the command yourself:
|
||||
|
||||
```sh
|
||||
sshd-service-install
|
||||
```
|
||||
|
||||
### Files
|
||||
|
||||
These are the files / directories that are created and/or modified with this
|
||||
install:
|
||||
|
||||
```text
|
||||
~/.local/bin/sudo.bat
|
||||
~/.local/bin/sshd-service-install.bat
|
||||
```
|
||||
|
||||
|
||||
52
sshd/install.ps1
Normal file
52
sshd/install.ps1
Normal file
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env pwsh
|
||||
|
||||
$ErrorActionPreference = 'stop'
|
||||
|
||||
function Repair-MissingCommand {
|
||||
Param(
|
||||
[string]$Name,
|
||||
[string]$Package,
|
||||
[string]$Command
|
||||
)
|
||||
|
||||
Write-Host " Checking for $Name ..."
|
||||
$HasCommand = Get-Command -Name $Command -ErrorAction Silent
|
||||
IF ($HasCommand) {
|
||||
Return
|
||||
}
|
||||
|
||||
& $HOME\.local\bin\webi-pwsh.ps1 $Package
|
||||
$null = Sync-EnvPath
|
||||
}
|
||||
|
||||
function Install-WebiHostedScript () {
|
||||
Param(
|
||||
[string]$Package,
|
||||
[string]$ScriptName
|
||||
)
|
||||
$PwshName = "_${ScriptName}.ps1"
|
||||
$PwshUrl = "${Env:WEBI_HOST}/packages/${Package}/${ScriptName}.ps1"
|
||||
$PwshPath = "$HOME\.local\bin\${PwshName}"
|
||||
$OldPath = "$HOME\.local\bin\${ScriptName}.ps1"
|
||||
|
||||
$BatPath = "$HOME\.local\bin\${ScriptName}.bat"
|
||||
$PwshExec = "powershell -ExecutionPolicy Bypass"
|
||||
$Bat = "@echo off`r`n$PwshExec %USERPROFILE%\.local\bin\${PwshName} %*"
|
||||
|
||||
Invoke-DownloadUrl -Force -URL $PwshUrl -Path $PwshPath
|
||||
Set-Content -Path $BatPath -Value $Bat
|
||||
Write-Host " Created alias ${BatPath}"
|
||||
Write-Host " to run ${PwshPath}"
|
||||
|
||||
# fix for old installs
|
||||
Remove-Item -Path $OldPath -Force -ErrorAction Ignore
|
||||
}
|
||||
|
||||
|
||||
Repair-MissingCommand -Name "sudo (RunAs alias)" -Package "sudo" -Command "sudo"
|
||||
Install-WebiHostedScript -Package "sshd" -ScriptName "sshd-service-install"
|
||||
|
||||
Write-Output ""
|
||||
Write-Output "${TTask}Copy, paste, and run${TReset} the following to install sshd as a system service"
|
||||
Write-Output " ${TCmd}sshd-service-install${TReset}"
|
||||
Write-Output ""
|
||||
35
sshd/install.sh
Normal file
35
sshd/install.sh
Normal file
@@ -0,0 +1,35 @@
|
||||
__install_sshd() {
|
||||
my_os="$(uname -s)"
|
||||
if test "Darwin" = "${my_os}"; then
|
||||
echo >&2 ""
|
||||
echo >&2 "Copy, paste, and run the following to enable the built-in sshd:"
|
||||
echo >&2 " sudo systemsetup -f -setremotelogin on"
|
||||
echo >&2 " sudo systemsetup -getremotelogin"
|
||||
echo >&2 ""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo >&2 "Install and enable sshd using your system package manager:"
|
||||
my_cmd=""
|
||||
if test command -v sudo > /dev/null; then
|
||||
my_cmd="sudo "
|
||||
fi
|
||||
|
||||
if test command -v apt > /dev/null; then
|
||||
echo " ${my_cmd}apt install -y openssh-server"
|
||||
echo " ${my_cmd}systemctl enable ssh"
|
||||
echo " ${my_cmd}systemctl start ssh"
|
||||
elif test command -v yum > /dev/null; then
|
||||
echo " ${my_cmd}yum -y install openssh-server"
|
||||
echo " ${my_cmd}systemctl enable ssh"
|
||||
echo " ${my_cmd}systemctl start ssh"
|
||||
elif test command -v apk > /dev/null; then
|
||||
echo " ${my_cmd}apk add --no-cache openssh"
|
||||
echo " ${my_cmd}service sshd added to runlevel default"
|
||||
echo " ${my_cmd}service sshd start"
|
||||
else
|
||||
echo " (unknown package manager / init daemon)"
|
||||
fi
|
||||
|
||||
exit 1
|
||||
}
|
||||
62
sshd/sshd-service-install.ps1
Normal file
62
sshd/sshd-service-install.ps1
Normal file
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env pwsh
|
||||
|
||||
$Esc = [char]27
|
||||
$Warn = "${Esc}[1m[33m"
|
||||
$ResetAll = "${Esc}[0m"
|
||||
|
||||
# See
|
||||
# - <https://gist.github.com/HacDan/026fa8d7d4130fbbc2409d84c2d04143#load-public-keys>
|
||||
# - <https://techcommunity.microsoft.com/t5/itops-talk-blog/installing-and-configuring-openssh-on-windows-server-2019/ba-p/309540>
|
||||
# - <https://learn.microsoft.com/windows-server/administration/openssh/openssh_install_firstuse>
|
||||
|
||||
function InstallOpenSSHServer {
|
||||
$OpenSSHServer = Get-WindowsCapability -Online | `
|
||||
Where-Object -Property Name -Like "OpenSSH.Server*"
|
||||
IF (-Not ($OpenSSHServer.State -eq "Installed")) {
|
||||
Add-WindowsCapability -Online -Name $sshd.Name
|
||||
}
|
||||
|
||||
$Sshd = Get-Service -Name "sshd"
|
||||
IF (-Not ($Sshd.Status -eq "Running")) {
|
||||
Start-Service "sshd"
|
||||
}
|
||||
IF (-Not ($Sshd.StartupType -eq "Automatic")) {
|
||||
Set-Service -Name "sshd" -StartupType "Automatic"
|
||||
}
|
||||
|
||||
$SshAgent = Get-Service -Name "ssh-agent"
|
||||
IF (-Not ($SshAgent.Status -eq "Running")) {
|
||||
Start-Service "ssh-agent"
|
||||
}
|
||||
IF (-Not ($SshAgent.StartupType -eq "Automatic")) {
|
||||
Set-Service -Name "ssh-agent" -StartupType "Automatic"
|
||||
}
|
||||
|
||||
Install-Module -Force OpenSSHUtils -Scope AllUsers
|
||||
}
|
||||
|
||||
function SelfElevate {
|
||||
Write-Host "${Warn}Installing 'sshd' requires Admin privileges${ResetAll}"
|
||||
Write-Host "Install will continue automatically in 5 seconds..."
|
||||
Sleep 5.0
|
||||
|
||||
# Self-elevate the script if required
|
||||
$CurUser = New-Object Security.Principal.WindowsPrincipal(
|
||||
[Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
)
|
||||
$IsAdmin = $CurUser.IsInRole(
|
||||
[Security.Principal.WindowsBuiltInRole]::Administrator
|
||||
)
|
||||
if ($IsAdmin) {
|
||||
Return 0
|
||||
}
|
||||
|
||||
$CurLoc = Get-Location
|
||||
$CommandLine = "-File `"" + $MyInvocation.MyCommand.Path + "`" " + $MyInvocation.UnboundArguments
|
||||
Start-Process -FilePath PowerShell.exe -Verb Runas -ArgumentList $CommandLine
|
||||
Set-Location $CurLoc
|
||||
Exit 0
|
||||
}
|
||||
|
||||
SelfElevate
|
||||
InstallOpenSSHServer
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: vim-devicons
|
||||
homepage: https://github.com/ryanoasis/devicons
|
||||
homepage: https://github.com/ryanoasis/vim-devicons
|
||||
tagline: |
|
||||
VimDevIcons: Adds Icons to Your Plugins.
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user