Compare commits

..

143 Commits

Author SHA1 Message Date
AJ ONeal
1f6e574030 WIP feroxbuster 2023-11-07 09:43:36 -07:00
AJ ONeal
6626a0df86 WIP: psscriptanalyzer 2023-11-07 09:43:36 -07:00
AJ ONeal
b61a678371 doc(pwsh): update modules dirs, add ToC 2023-11-07 09:43:36 -07:00
Don Johnson
eba10b52e6 feat: add feroxbuster (forced browsing security tool) 2023-11-07 09:43:35 -07:00
AJ ONeal
90aafc1df1 feat: bring in bootstrap renderer 2023-11-07 00:45:00 -07:00
AJ ONeal
b1d7df199f feat(webi): add webi.sh to own installer 2023-11-07 00:25:18 -07:00
AJ ONeal
50f98f2928 ref: rename module 'serveInstaller' => 'Installers' 2023-11-06 23:55:34 -07:00
AJ ONeal
0afe701dd8 ref!: move regexp to list 2023-11-06 19:13:21 -07:00
AJ ONeal
a4b324f3dc ref(goreleaser): don't use hacky echo where 'tr -d " "' will do 2023-11-06 19:12:57 -07:00
AJ ONeal
18217b2f17 chore: remove junk files 2023-11-06 18:59:57 -07:00
AJ ONeal
525d1bd8cb chore: expose helper function & update test 2023-11-06 18:50:02 -07:00
AJ ONeal
fc36f3e93e ref(webi): add explicit libc detection 2023-11-06 18:50:02 -07:00
AJ ONeal
ffa49401aa feat(windows): set libc=mvsc via User-Agent and query params 2023-11-06 18:50:02 -07:00
AJ ONeal
5ab83fcb37 feat(node): add explicit libc detection 2023-11-06 18:50:01 -07:00
AJ ONeal
b2dec6d467 ref(cmake): add explicit libc detection 2023-11-06 18:50:01 -07:00
AJ ONeal
156e8ddc5e fix(cmake): fix windows dir copy and path update 2023-11-06 18:50:01 -07:00
AJ ONeal
1ac39b70fe feat(AtomicParsley): add explicit libc detection 2023-11-06 18:50:01 -07:00
AJ ONeal
53d023aac9 ref(api): use await to de-indent some async functions 2023-11-06 16:26:49 -07:00
AJ ONeal
a0222527c0 feat: add TinyGo 2023-11-06 16:23:12 -07:00
AJ ONeal
4fe71af9d0 fix(windows): use home directory, not current directory 2023-11-05 11:39:32 -07:00
AJ ONeal
a2c694fd8a fix(webi): remove incorrect regex escape 2023-11-05 11:38:37 -07:00
AJ ONeal
bf5482c453 ref+fix(vim-commentary): fix inconsistencies in install files 2023-11-02 17:30:34 -06:00
AJ ONeal
bd47c3bfb5 feat(vim-zig): add zig.vim alias 2023-11-02 17:30:33 -06:00
AJ ONeal
81d2eb4288 feat: add vim-zig 2023-11-02 17:30:33 -06:00
AJ ONeal
8bf2fffa1a feat(git-tag): add HEAD, which is beta as long as any other tags are available 2023-11-02 17:30:33 -06:00
AJ ONeal
8a16909813 feat(git-tag): if already cloned, fetch to update 2023-11-02 17:30:33 -06:00
AJ ONeal
3f29c43513 ref!(git-tag): clone(url, path) => clone(path, url) so that repoPath is always first 2023-11-02 17:30:33 -06:00
AJ ONeal
c95f2924cc ref(git-tag): cleanup tag handling 2023-11-02 17:30:33 -06:00
AJ ONeal
dcc2034f88 fix(git-tag): resolve 'repoBaseDir' relative to cwd 2023-11-02 17:30:33 -06:00
AJ ONeal
5ab26dbb36 test(git-tag): show output from simpler, better targeted repos 2023-11-02 17:30:32 -06:00
RubenRam
1d9dadd8cf doc(zoxide): update README Files section 2023-11-02 17:28:49 -06:00
RubenRam
22b5298091 doc(yq): update README Files section 2023-11-02 17:28:49 -06:00
RubenRam
f0d730ad35 doc(xz): update README Files section 2023-11-02 17:28:49 -06:00
RubenRam
69ea717e06 doc(webi): update README Files section 2023-11-02 17:28:48 -06:00
RubenRam
d3b7959451 doc(watchexec): update README Files section 2023-11-02 17:28:48 -06:00
RubenRam
0a71df82b3 doc(vps-utils): update README Files section 2023-11-02 17:28:48 -06:00
RubenRam
605ebf1234 doc(vps-addswap): update README Files section 2023-11-02 17:28:48 -06:00
RubenRam
9cb6550371 doc(vim-whitespace): update README Files section 2023-11-02 17:28:48 -06:00
RubenRam
f44554392b doc(vim-viminfo): update README Files section 2023-11-02 17:28:48 -06:00
RubenRam
99e2ac7708 doc(vim-syntastic): update README Files section 2023-11-02 17:28:48 -06:00
RubenRam
929b920c28 doc(vim-sensible): update README Files section 2023-11-02 17:28:48 -06:00
RubenRam
15f72de19b doc(vim-rust): update README Files section 2023-11-02 17:28:47 -06:00
RubenRam
a41b1e4300 doc(vim-nerdtree): update README Files section 2023-11-02 17:28:47 -06:00
RubenRam
2b5e3e4cb9 doc(vim-leader): update README Files section 2023-11-02 17:28:47 -06:00
RubenRam
b3b685b2e1 doc(vim-lastplace): update README Files section 2023-11-02 17:28:47 -06:00
RubenRam
50bae5dd8b doc(vim-gui): update README Files section 2023-11-02 17:28:47 -06:00
RubenRam
c057e4be94 doc(vim-go): update README Files section 2023-11-02 17:28:47 -06:00
RubenRam
62e717900c doc(vim-devicons): update README Files section 2023-11-02 17:28:47 -06:00
RubenRam
b347f406f5 doc(vim-beyondcode): update README Files section 2023-11-02 17:28:46 -06:00
RubenRam
f2ef731cd3 doc(vim-ale): update README Files section 2023-11-02 17:28:46 -06:00
AJ ONeal
23cbb707e9 doc(serviceman): add service file locations, revamped cheat sheet, add ToC 2023-11-02 10:42:27 -06:00
AJ ONeal
29a9a16a4b doc(pathman): add shell config info, cheat sheet, and add ToC 2023-11-02 10:42:27 -06:00
RubenRam
262ba70ab3 doc(syncthing): update README Files section 2023-11-02 10:42:27 -06:00
RubenRam
fe797329d2 doc(sttr): update README Files section 2023-11-02 10:42:27 -06:00
RubenRam
27edb0599f doc(sshd-prohibit-password): update README Files section 2023-11-02 10:42:27 -06:00
RubenRam
1188bcb99c doc(ssh-utils): update README Files section 2023-11-02 10:42:26 -06:00
RubenRam
1124f0d72d doc(ssh-setpass): update README Files section 2023-11-02 10:42:26 -06:00
RubenRam
8c24a907c3 doc(ssh-pubkey): update README Files section 2023-11-02 10:42:26 -06:00
RubenRam
c747baa9a8 doc(ssh-authorize): update README Files section 2023-11-02 09:59:08 -06:00
RubenRam
124aa60197 doc(ssh-adduser): update README Files section 2023-11-02 09:59:07 -06:00
RubenRam
cb5b355c07 doc(serviceman): update README Files section 2023-11-02 09:59:07 -06:00
RubenRam
b1af98ed37 doc(setcap-netbind): update README Files section
Add Files section and fix broken homepage link
2023-11-02 09:59:07 -06:00
RubenRam
67aa55017d doc(sd): update README Files section 2023-11-02 09:59:07 -06:00
RubenRam
f934f2b75d doc(sclient): update README Files section 2023-11-02 09:59:07 -06:00
RubenRam
bdbb3b9b92 doc(sass): update README Files section 2023-11-02 09:59:07 -06:00
RubenRam
133af72ad7 doc(rustlang): update README Files section 2023-11-02 09:59:07 -06:00
RubenRam
0a3bdf0708 doc(postgres): update README Files section 2023-11-02 09:59:06 -06:00
RubenRam
5a6599412f doc(pathman): update README Files section 2023-11-02 09:34:23 -06:00
RubenRam
b93c8f8d8d doc(pandoc): update README Files section 2023-11-02 09:34:22 -06:00
AJ ONeal
6c696d7e46 ref!(vim-commentary): use git source releases 2023-10-31 15:09:48 -06:00
AJ ONeal
9c075ee60d ref: add WEBI_PKG_PATHNAME to replace WEBI_PKG_FILE (which is sometimes a dir) 2023-10-31 15:09:48 -06:00
AJ ONeal
7996a52dfe fix(pkg_no_exec): also guard against linking and adding to PATH 2023-10-31 15:09:48 -06:00
AJ ONeal
d34101aa80 fix(powershell): always create the downloads folder 2023-10-31 15:09:48 -06:00
AJ ONeal
fb1790dde0 ref!(test): show release info for git tags 2023-10-31 15:09:48 -06:00
AJ ONeal
5dd3a79faa ref!: release info from git tags 2023-10-31 15:09:48 -06:00
AJ ONeal
8926e27d41 feat: add raw git tags support (generated by GPT) 2023-10-31 15:09:47 -06:00
AJ ONeal
927151100a fix(xcaddy): use updated PATH after installing Go 2023-10-31 15:07:58 -06:00
AJ ONeal
46d2c358a7 fix(xcaddy): check for 'go' with 'Get-Command' in PowerShell rather than exact path 2023-10-31 15:07:58 -06:00
AJ ONeal
f68f5b2c13 fix(webi): reserve RED for ERROR in powershell too 2023-10-31 15:07:57 -06:00
AJ ONeal
4359bfd87e ref!(webi_download): separate error to complete transition to 2 args 2023-10-30 18:03:42 -06:00
AJ ONeal
ad1cdd1eac ref(webi_download): always use 2-3 args on as many lines 2023-10-30 18:03:41 -06:00
AJ ONeal
433ae9065b ref(template.sh): check exit code or size rather than stdout 2023-10-30 18:02:55 -06:00
AJ ONeal
ecee9dbb34 ref(setcap-netbind): check exit code rather than stdout 2023-10-30 18:02:55 -06:00
AJ ONeal
afd490e47f ref(sh): check exit code rather than stdout 2023-10-30 18:02:55 -06:00
AJ ONeal
9f391b30be feat(webi): add preliminary --list and --info 2023-10-30 01:35:39 -06:00
AJ ONeal
317b94cbbc feat: guard 'xattr' & 'chmod' with 'pkg_no_exec' 2023-10-30 01:35:39 -06:00
AJ ONeal
81e4007715 lint(webi): SC2086,SC2155 (exports and quotes) 2023-10-30 01:35:39 -06:00
AJ ONeal
bfb7a437d0 ref: un-expand $HOME to ~ for printed paths 2023-10-30 01:35:39 -06:00
AJ ONeal
8373df5e50 chore: update or remove old comments 2023-10-30 01:35:38 -06:00
AJ ONeal
480dc0801c fix: use single quotes for WEBI_VERSION 2023-10-30 01:35:38 -06:00
AJ ONeal
e6713da28d chore: whitespace 2023-10-30 01:35:38 -06:00
AJ ONeal
37bd443310 doc(git): various minor corrections, including git switch 2023-10-28 19:59:34 -06:00
RubenRam
f36cf182b3 doc(mutagen): update README Files section 2023-10-28 19:59:34 -06:00
RubenRam
0172c186af doc(myip): update README Files section 2023-10-28 19:59:33 -06:00
RubenRam
714d48dd89 doc(kubens): update README Files section 2023-10-28 19:59:33 -06:00
RubenRam
7bb4be510b doc(kubectx): update README Files section 2023-10-28 19:59:33 -06:00
RubenRam
bcdfcb6807 doc(kind): update README Files section 2023-10-28 19:59:33 -06:00
RubenRam
875e95818b doc(keypairs): update README Files section 2023-10-28 19:59:33 -06:00
RubenRam
89a05179ea doc(jq): update README Files section 2023-10-28 19:59:33 -06:00
RubenRam
3f74b451ec doc(hexyl): update README Files section 2023-10-28 19:59:32 -06:00
RubenRam
cd2d49383a doc(gprox): update README Files section 2023-10-28 19:59:32 -06:00
RubenRam
a71402d1ba doc(goreleaser): update README Files section 2023-10-28 19:59:32 -06:00
RubenRam
223ed22513 doc(gitea): update README Files section 2023-10-28 19:56:13 -06:00
RubenRam
de5c671edb doc(gitdeploy): update README Files section 2023-10-28 19:47:32 -06:00
RubenRam
e2b3f3370a doc(git): update README Files section 2023-10-28 19:47:32 -06:00
RubenRam
6579be2474 doc(gh): update README Files section 2023-10-28 19:47:32 -06:00
AJ ONeal
32242220b4 doc(ollama): update README 2023-10-28 17:05:12 -06:00
AJ ONeal
57aa98404a chore: whitespace 2023-10-28 17:05:12 -06:00
AJ ONeal
b3e2f0c2d1 workaround(ollama): filter out v0.0.x releases that are sorting too high 2023-10-28 17:05:12 -06:00
Tod Hansmann
ccc0ed17b9 feat: add ollama (LLM, like ChatGPT) 2023-10-28 17:05:12 -06:00
AJ ONeal
4dc9e2d699 fix(crabz): fix installers, update README 2023-10-28 15:53:54 -06:00
Don Johnson
81d1e16d0e feat: add crabz (multi-threaded gzip compression) 2023-10-28 15:39:23 -06:00
AJ ONeal
b8c97dd9e0 chore(lint): don't create a function in a loop 2023-10-28 01:43:55 -06:00
AJ ONeal
70cc64e8fc fix: better (lazier) 'stable' vs 'beta' detection 2023-10-28 01:43:55 -06:00
AJ ONeal
1bc66676a5 fix(macOS): handle ./CMake.app/Contents/ 2023-10-28 01:36:25 -06:00
AJ ONeal
ed41ce092b doc(sclient): add '--alpn <proto>' 2023-10-28 01:35:06 -06:00
AJ ONeal
1c96c5d366 doc(goreleaser): update for goreleaser v1.x 2023-10-28 01:35:06 -06:00
AJ ONeal
f89ba373a6 chore: alias 'trip' (command name) as 'trippy' (package name) 2023-10-28 01:30:15 -06:00
AJ ONeal
51ccfab586 ref: move 'trippy' to 'trip', as that's the command name 2023-10-28 01:30:15 -06:00
AJ ONeal
30f161f032 fix(sudo): always create sudo.cmd in Windows user's home directory 2023-10-28 01:30:15 -06:00
AJ ONeal
a22af8815e fix(trip): various installer fixes and doc updates 2023-10-28 01:30:15 -06:00
Don Johnson
f2b9533fd3 feat: add network tool trip (trippy) 2023-10-28 01:24:02 -06:00
AJ ONeal
b63a9cb686 chore(fmt): whitespace 2023-10-28 01:24:02 -06:00
Sean Alter
5502cb912d fix: add missing WEBI_WELCOME=true & welcome message check 2023-10-27 22:57:27 -06:00
AJ ONeal
3501e891c5 chore: fmt whitespace 2023-10-25 11:48:09 -06:00
AJ ONeal
d592d338df chore(windows): remove .bat cruft 2023-10-25 11:48:09 -06:00
AJ ONeal
37705a7b4f chore(lint): only run checks on latest node 2023-10-25 11:12:11 -06:00
AJ ONeal
0109e612e4 feat: add xcaddy 2023-10-25 11:12:11 -06:00
Shovit
7020cf494e fix(brew): add --workdir flag to updater service 2023-10-25 11:10:10 -06:00
AJ ONeal
874f081401 doc(redis-commander): style updates 2023-10-24 22:58:57 -06:00
AJ ONeal
73d8f673ff feat(redis-commander): add PowerShell installer + update POSIX installer 2023-10-24 22:58:57 -06:00
Mr.Online
fb8e5ea740 feat(redis-commander): add redis commander and cleanup based on guidelines 2023-10-24 22:58:56 -06:00
AJ ONeal
29fa3551b3 feat(prettier): add PowerShell installer 2023-10-24 22:58:56 -06:00
AJ ONeal
389c67805d doc(py*): consistent Files & Install, add libzma-dev 2023-10-24 13:16:54 -06:00
AJ ONeal
1306fd6ebc fix: replace leftover 'pathman add' with 'webi_path_add' 2023-10-24 13:16:54 -06:00
AJ ONeal
4b8f62a1b8 doc(caddy): add conditional logic example 2023-10-22 21:31:31 -06:00
AJ ONeal
4ddf971a24 doc(caddy): correct and expand CORS examples 2023-10-22 21:30:19 -06:00
AJ ONeal
5d1e975b5e doc(caddy): remove mistaken nesting / indentation 2023-10-22 15:00:41 -06:00
AJ ONeal
47e675b92f doc(caddy): alias Snippets as Macros for easier search 2023-10-22 15:00:41 -06:00
AJ ONeal
5acb130bc2 doc!(caddy): complete cheat sheet rewrite + extras 2023-10-20 17:23:26 -06:00
AJ ONeal
9194866f38 doc(node): and fmt + lint + ci workflows 2023-10-20 17:21:52 -06:00
AJ ONeal
264dbec4ff doc(node): more service examples + lint + fmt 2023-10-20 17:21:52 -06:00
AJ ONeal
251920a67c doc(node): add serviceman examples 2023-10-20 17:21:52 -06:00
147 changed files with 6188 additions and 963 deletions

View File

@@ -10,7 +10,7 @@ jobs:
strategy:
matrix:
node-version:
- 20.x
#- 20.x
- latest
steps:
- uses: actions/checkout@v3

196
_common/git-tag.js Normal file
View File

@@ -0,0 +1,196 @@
'use strict';
require('dotenv').config({ path: '.env' });
var Crypto = require('crypto');
var util = require('util');
var exec = util.promisify(require('child_process').exec);
var Fs = require('node:fs/promises');
var Path = require('node:path');
var repoBaseDir = process.env.REPO_BASE_DIR || '';
if (!repoBaseDir) {
repoBaseDir = Path.resolve('./repos');
// for stderr
console.error(`[Warn] REPO_BASE_DIR= not set, ${repoBaseDir}`);
}
var Repos = {};
Repos.clone = async function (repoPath, gitUrl) {
let uuid = Crypto.randomUUID();
let tmpPath = `${repoPath}.${uuid}.tmp`;
await exec(`git clone --bare --filter=tree:0 ${gitUrl} ${tmpPath}`);
await Fs.rename(tmpPath, repoPath);
};
Repos.checkExists = async function (repoPath) {
let err = await Fs.access(repoPath).catch(Object);
if (!err) {
return true;
}
if (err.code !== 'ENOENT') {
throw err;
}
return false;
};
Repos.fetch = async function (repoPath) {
await exec(`git --git-dir=${repoPath} fetch`);
};
Repos.getTags = async function (repoPath) {
var { stdout } = await exec(`git --git-dir=${repoPath} tag`);
var rawTags = stdout.trim().split('\n');
let tags = [];
for (let tag of rawTags) {
// ex: v1, v2, v1.1, 1.1.0-rc
let maybeVersionRe = /^(v\d+|v?\d+\.\d+)/;
let maybeVersion = maybeVersionRe.test(tag);
if (maybeVersion) {
tags.push(tag);
}
}
tags = tags.reverse();
return tags;
};
Repos.getTipInfo = async function (repoPath) {
var { stdout } = await exec(
`git --git-dir=${repoPath} rev-parse --abbrev-ref HEAD`,
);
var branch = stdout.trim();
var info = await Repos.getCommitInfo(repoPath, 'HEAD');
info.commitish = branch;
return info;
};
Repos.getCommitInfo = async function (repoPath, commitish) {
var { stdout } = await exec(
`git --git-dir=${repoPath} log -1 --format="%h %H %ad %cd" --date=iso-strict ${commitish}`,
);
stdout = stdout.trim();
var commitParts = stdout.split(/\s+/g);
return {
commitish: commitish,
commit_id: `${commitParts[0]}`,
commit: `${commitParts[1]}`,
date: commitParts[2],
date_authored: commitParts[3],
};
};
/**
* Lists GitHub Releases (w/ uploaded assets)
*
* @param request
* @param {string} owner
* @param {string} gitUrl
* @returns {PromiseLike<any> | Promise<any>}
*/
async function getAllReleases(gitUrl) {
let all = {
releases: [],
download: '',
};
let repoName = gitUrl.split('/').pop();
repoName = repoName.replace(/\.git$/, '');
let repoPath = `${repoBaseDir}/${repoName}.git`;
let isCloned = await Repos.checkExists(repoPath);
if (!isCloned) {
await Repos.clone(repoPath, gitUrl);
} else {
await Repos.fetch(repoPath);
}
let commitInfos = [];
let tags = await Repos.getTags(repoPath);
for (let tag of tags) {
let commitInfo = await Repos.getCommitInfo(repoPath, tag);
Object.assign(commitInfo, { version: tag, channel: '' });
commitInfos.push(commitInfo);
}
{
let tipInfo = await Repos.getTipInfo(repoPath);
// "2024-01-01T00:00:00-05:00" => "2024-01-01T05:00:00"
let date = new Date(tipInfo.date);
// "2024-01-01T05:00:00" => "v2024.01.01-05.00.00"
let version = date.toISOString();
// strip '.000Z'
version = version.replace(/\.\d+Z/, '');
version = version.replace(/[:\-]/g, '.');
version = version.replace(/T/, '-');
Object.assign(tipInfo, { version: `v${version}`, channel: '' });
if (commitInfos.length > 1) {
tipInfo.channel = 'beta';
}
commitInfos.push(tipInfo);
}
let releases = [];
for (let commitInfo of commitInfos) {
let version = commitInfo.version.replace(/^v/, '');
let date = new Date(commitInfo.date);
let isoDate = date.toISOString();
isoDate = isoDate.replace(/\.\d+Z/, '');
// tags and HEAD qualify for '--branch <branchish>'
let branch = commitInfo.commitish;
let rel = {
name: `${repoName}-v${version}`,
version: version,
git_tag: branch,
git_commit_hash: commitInfo.commit_id,
lts: false,
channel: commitInfo.channel,
date: isoDate,
os: '*',
arch: '*',
ext: 'git',
download: gitUrl,
};
releases.push(rel);
}
all.releases = releases;
return all;
}
module.exports = getAllReleases;
if (module === require.main) {
(async function main() {
let testRepos = [
// just a few tags, and a different HEAD
'https://github.com/tpope/vim-commentary.git',
// no tags, just HEAD
'https://github.com/ziglang/zig.vim.git',
// many, many tags
//'https://github.com/dense-analysis/ale.git',
];
for (let url of testRepos) {
let all = await getAllReleases(url);
all = require('../_webi/normalize.js')(all);
console.info(JSON.stringify(all, null, 2));
}
})()
.then(function () {
process.exit(0);
})
.catch(function (err) {
console.error(err);
});
}

View File

@@ -3,8 +3,7 @@
require('dotenv').config();
/**
* Gets the releases for 'ripgrep'. This function could be trimmed down and made
* for use with any github release.
* Lists GitHub Releases (w/ uploaded assets)
*
* @param request
* @param {string} owner
@@ -61,20 +60,32 @@ async function getAllReleases(
}
function transformReleases(release) {
release['assets'].forEach(function (asset) {
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: release['tag_name'], // TODO tags aren't always semver / sensical
lts: /(\b|_)(lts)(\b|_)/.test(release['tag_name']),
channel: !release['prerelease'] ? 'stable' : 'beta',
date: (release['published_at'] || '').replace(/T.*/, ''),
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: asset['browser_download_url'],
download: download,
});
});
}
}
return all;

View File

@@ -1,28 +0,0 @@
setlocal
@echo off
pushd "%userprofile%" || goto :error
IF NOT EXIST .local (
mkdir .local || goto :error
)
IF NOT EXIST .local\bin (
mkdir .local\bin || goto :error
)
rem {{ baseurl }}
rem {{ version }}
pushd .local\bin || goto :error
if NOT EXIST webi.bat (
rem without SilentlyContinue this is SLOOOOOOOOOOOOOOOW!
powershell $ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest https://webinstall.dev/packages/_webi/webi.bat -OutFile webi.bat || goto :error
)
call .\webi {{ exename }} || goto :error
rem pathman add "%userprofile%\.local\bin" >nul 2>&1 || goto :error
pathman add "%userprofile%\.local\bin" || goto :error
popd || goto :error
popd
goto :EOF
:error
echo Failed with error #%errorlevel%.
exit /b %errorlevel%

View File

@@ -14,14 +14,25 @@ __install_webi() {
#WEBI_HOST=https://webinstall.dev
export WEBI_HOST
echo ""
printf "Thanks for using webi to install '\e[32m%s\e[0m' on '\e[33m%s/%s\e[0m'.\n" "${WEBI_PKG-}" "$(uname -s)/$(uname -r)" "$(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 ""
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
if test -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)" "${my_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
@@ -40,8 +51,11 @@ set -u
__webi_main() {
export WEBI_TIMESTAMP="\$(date +%F_%H-%M-%S)"
export _webi_tmp="\${_webi_tmp:-\$(mktemp -d -t webi-\$WEBI_TIMESTAMP.XXXXXXXX)}"
my_date="\$(date +%F_%H-%M-%S)"
export WEBI_TIMESTAMP="\${my_date}"
export _webi_tmp="\${_webi_tmp:-\$(
mktemp -d -t "webi-\$WEBI_TIMESTAMP.XXXXXXXX"
)}"
if [ -n "\${_WEBI_PARENT:-}" ]; then
export _WEBI_CHILD=true
@@ -50,6 +64,9 @@ __webi_main() {
fi
export _WEBI_PARENT=true
my_os="\$(uname -s)"
my_arch="\$(uname -m)"
##
## Detect acceptable package formats
##
@@ -88,18 +105,31 @@ __webi_main() {
##
set +e
export WEBI_CURL="\$(command -v curl)"
export WEBI_WGET="\$(command -v wget)"
WEBI_CURL="\$(command -v curl)"
export WEBI_URL
WEBI_WGET="\$(command -v wget)"
export WEBI_WGET
set -e
my_libc=''
if ldd /bin/ls 2> /dev/null | grep -q 'musl' 2> /dev/null; then
my_libc=' musl-native'
my_libc='musl'
elif uname -o | grep -q 'GNU' || uname -s | grep -q 'Linux'; then
my_libc='gnu'
else
my_libc='libc'
fi
export WEBI_HOST="\${WEBI_HOST:-https://webinstall.dev}"
export WEBI_UA="\$(uname -s)/\$(uname -r) \$(uname -m)/unknown\${my_libc}"
# ex: Darwin or Linux
my_sys="\$(uname -s)"
# ex: 22.6.0
my_rev="\$(uname -r)"
# ex: arm64
my_machine="\$(uname -m)"
export WEBI_UA="\${my_sys}/\${my_rev} \${my_machine}/unknown \${my_libc}"
webinstall() {
@@ -110,7 +140,10 @@ __webi_main() {
exit 1
fi
export WEBI_BOOT="\$(mktemp -d -t "\$my_package-bootstrap.\$WEBI_TIMESTAMP.XXXXXXXX")"
WEBI_BOOT="\$(
mktemp -d -t "\$my_package-bootstrap.\$WEBI_TIMESTAMP.XXXXXXXX"
)"
export WEBI_BOOT
my_installer_url="\$WEBI_HOST/api/installers/\$my_package.sh?formats=\$my_ext"
if [ -n "\$WEBI_CURL" ]; then
@@ -156,9 +189,20 @@ __webi_main() {
}
fn_checksum() {
cmd_shasum='sha1sum'
if command -v shasum > /dev/null; then
cmd_shasum='shasum'
fi
\$cmd_shasum "\${0}" | cut -d' ' -f1 | cut -c 1-8
}
version() {
my_version=v1.1.15
printf "\\e[35mwebi\\e[32m %s\\e[0m Copyright 2020+ AJ ONeal\\n" "\${my_version}"
my_checksum="\$(
fn_checksum
)"
my_version=v1.2.0
printf "\\e[35mwebi\\e[32m %s\\e[0m Copyright 2020+ AJ ONeal\\n" "\${my_version} (\${my_checksum})"
printf " \\e[36mhttps://webinstall.dev/webi\\e[0m\\n"
}
@@ -185,6 +229,19 @@ __webi_main() {
echo " Some packages have special uninstall instructions, check"
echo " https://webinstall.dev/<thing1> to be sure."
echo ""
printf "\\e[1mOPTIONS\\e[0m\\n"
echo " Generic Program Information"
echo " --help Output a usage message and exit."
echo ""
echo " -V, --version"
echo " Output the version number of webi and exit."
echo ""
echo " Helper Utilities"
echo " --list Show everything webi has to offer."
echo ""
echo " --info <package>"
echo " Show various links and example release."
echo ""
printf "\\e[1mFAQ\\e[0m\\n"
printf " See \\e[34mhttps://webinstall.dev/faq\\e[0m\\n"
echo ""
@@ -204,6 +261,74 @@ __webi_main() {
exit 0
fi
if echo "\$1" | grep -q -E '^(-l|--list|list)$'; then
echo >&2 "[warn] the format of --list output may change"
# because we don't have sitemap.xml for dev sites yet
my_host="https://webinstall.dev"
my_len="\${#my_host}"
# 6 because the field will looks like "loc>WEBI_HOST/PKG_NAME"
# and the count is 1-indexed
my_count="\$((my_len + 6))"
curl -fsS "\${my_host}/sitemap.xml" |
grep -F "\${my_host}" |
cut -d'<' -f2 |
cut -c "\${my_count}"-
exit 0
fi
if echo "\${1}" | grep -q -E '^(--info|info)$'; then
if test -z "\${2}"; then
echo >&2 "Usage: webi --info <package>"
exit 1
fi
echo >&2 "[warn] the output of --info is completely half-baked and will change"
my_pkg="\${2}"
# TODO need a way to check that it exists at all (readme, win, lin)
echo ""
echo " Cheat Sheet: \${WEBI_HOST}/\${my_pkg}"
echo " POSIX: curl -sS \${WEBI_HOST}/\${my_pkg} | sh"
echo " Windows: curl.exe -A MS \${WEBI_HOST}/\${my_pkg} | powershell"
echo "Releases (JSON): \${WEBI_HOST}/api/releases/\${my_pkg}.json"
echo " Releases (tsv): \${WEBI_HOST}/api/releases/\${my_pkg}.tab"
echo " (query params): ?channel=stable&limit=10"
echo " &os=\${my_os}&arch=\${my_arch}"
echo " Install Script: \${WEBI_HOST}/api/installers/\${my_pkg}.sh?formats=tar,zip,xz,git,dmg,pkg"
echo " Static Assets: \${WEBI_HOST}/packages/\${my_pkg}/README.md"
echo ""
# TODO os=linux,macos,windows (limit to tagged releases)
my_releases="\$(
curl -fsS "\${WEBI_HOST}/api/releases/\${my_pkg}.json?channel=stable&limit=1&pretty=true"
)"
if printf '%s\\n' "\${my_releases}" | grep -q "error"; then
my_releases_beta="\$(
curl -fsS "\${WEBI_HOST}/api/releases/\${my_pkg}.json?&limit=1&pretty=true"
)"
if printf '%s\\n' "\${my_releases_beta}" | grep -q "error"; then
echo >&2 "'\${my_pkg}' is a special case that does not have releases"
else
echo >&2 "ERROR no stable releases for '\${my_pkg}'!"
fi
exit 0
fi
echo >&2 "Stable '\${my_pkg}' releases:"
if command -v jq > /dev/null; then
printf '%s\\n' "\${my_releases}" |
jq
else
printf '%s\\n' "\${my_releases}"
fi
exit 0
fi
for pkgname in "\$@"; do
webinstall "\$pkgname"
done

View File

@@ -1,19 +0,0 @@
#!/bin/sh
set -e
set -u
# For installing from the extracted package tmp directory
pkg_install() {
(
cd "$WEBI_TMP"
if command -v rsync 2> /dev/null | grep -q rsync; then
rsync -Krl ./xmpl*/ "$pkg_src/" 2> /dev/null
else
cp -Hr ./xmpl*/* "$pkg_src/" 2> /dev/null
cp -Hr ./xmpl*/.* "$pkg_src/" 2> /dev/null
fi
rm -rf ./xmpl*
)
}

View File

@@ -13,6 +13,7 @@ var osMap = {
var maps = {
oses: {},
arches: {},
libcs: {},
formats: {},
};
@@ -20,7 +21,7 @@ Object.keys(osMap).forEach(function (name) {
maps.oses[name] = true;
});
var formats = ['zip', 'xz', 'tar', 'pkg', 'msi', 'git', 'exe', 'dmg'];
var formats = ['zip', 'xz', 'tar', 'pkg', 'msi', 'git', 'exe', 'dmg', 'git'];
formats.forEach(function (name) {
maps.formats[name] = true;
});
@@ -65,31 +66,39 @@ arches.forEach(function (name) {
maps.arches[name] = true;
});
var libcs = ['none', 'musl', 'gnu', 'msvc', 'libc'];
libcs.forEach(function (name) {
maps.libcs[name] = true;
});
function normalize(all) {
/* jshint maxcomplexity:50 */
/* jshint maxdepth:10 */
var supported = {
oses: {},
arches: {},
libcs: {},
formats: {},
};
all.releases.forEach(function (rel) {
/* jshint maxcomplexity:25 */
for (let rel of all.releases) {
rel.version = rel.version.replace(/^v/i, '');
if (!rel.name) {
rel.name = rel.download.replace(/.*\//, '');
}
if (!rel.os) {
rel.os =
Object.keys(osMap).find(function (regKey) {
return osMap[regKey].test(rel.name || rel.download);
}) || 'unknown';
}
// Hacky-doo for musl
// TODO some sort of glibc vs musl tag?
if (!rel._musl_native) {
if (!rel._musl) {
if (/(\b|\.|_|-)(musl)(\b|\.|_|-)/.test(rel.download)) {
rel._musl = true;
rel.os = 'unknown';
let osNames = Object.keys(osMap);
for (let osName of osNames) {
let relName = rel.name || rel.download;
let osRegExp = osMap[osName];
let matches = osRegExp.test(relName);
if (matches) {
rel.os = osName;
break;
}
}
}
@@ -112,6 +121,60 @@ function normalize(all) {
}
supported.arches[rel.arch] = true;
// note: depends on rel.os
if (!rel.libc) {
let isMusl;
let isMsvc;
let isStatic;
let isGnu;
// extra blocks to prevent copy pasta errors
{
let muslRe = /(\b|_)(musl)(\b|_)/i;
isMusl = muslRe.test(rel.download) || muslRe.test(rel.name);
}
{
let msvcRe = /(\b|_)(msvc)(\b|_)/i;
isMsvc = msvcRe.test(rel.download) || msvcRe.test(rel.name);
}
{
let staticRe = /(\b|_)(static)(\b|_)/i;
isStatic = staticRe.test(rel.download) || staticRe.test(rel.name);
}
{
let gnuRe = /(\b|_)(gnu|glibc|libc)(\b|_)/i;
isGnu = gnuRe.test(rel.download) || gnuRe.test(rel.name);
}
if (isMusl) {
// we specifically tag things that need musl++ in their own releases
rel.libc = 'none';
} else if (isStatic) {
rel.libc = 'none';
} else if (isGnu) {
rel.libc = 'gnu';
if (rel.os === 'windows') {
// windows gnu is static
rel.libc = 'none';
} else if (rel.os === 'darwin') {
// if glibc is required on macos, it'll be static
rel.libc = 'none';
}
} else if (isMsvc) {
rel.libc = 'msvc';
} else {
// The default is no requirement for any particular libc
// (Go, Zig, POSIX Shell, JS, etc)
// and hopefully we never have to worry about mingw and friends
rel.libc = 'none';
}
}
supported.libcs[rel.libc] = true;
var tarExt;
if (!rel.ext) {
// pkg-v1.0.tar.gz => ['gz', 'tar', '0', 'pkg-v1']
@@ -139,10 +202,28 @@ function normalize(all) {
}
supported.formats[tarExt || rel.ext] = true;
if (!rel.channel) {
// basically like this: (+.-_)(beta|rc)(0-9)(+.-_)
// matches:
// - v1.0-beta
// - v1.0-beta1.1
// - v1.0-beta-11
// won't match:
// - v1.0beta
// - v1.0-beta1b
let isBetaRe = /(\b|_)(preview|rc|beta|alpha)(\d+)(\b|_)/;
let isBeta = isBetaRe.test(rel.name);
if (isBeta) {
rel.channel = 'beta';
} else {
rel.channel = 'stable';
}
}
if (all.download) {
rel.download = all.download.replace(/{{ download }}/, rel.download);
}
});
}
all.oses = Object.keys(supported.oses).filter(function (name) {
return maps.oses[name];
@@ -150,6 +231,9 @@ function normalize(all) {
all.arches = Object.keys(supported.arches).filter(function (name) {
return maps.arches[name];
});
all.libcs = Object.keys(supported.libcs).filter(function (name) {
return maps.libcs[name];
});
all.formats = Object.keys(supported.formats).filter(function (name) {
return maps.formats[name];
});
@@ -170,4 +254,5 @@ module.exports._debug = function (all) {
// NOT in order of priority (which would be tar, xz, zip, ...)
module.exports.formats = formats;
module.exports.arches = arches;
module.exports.libcs = libcs;
module.exports.formatsMap = maps.formats;

View File

@@ -5,8 +5,6 @@ var path = require('node:path');
var request = require('@root/request');
var _normalize = require('../_webi/normalize.js');
// PowerShell: { { installer } }
// POSIX: {{ installer }}
var reInstallTpl = /\s*#?\s*{{ installer }}/;
var Releases = module.exports;
@@ -29,10 +27,11 @@ function padScript(txt) {
return txt.replace(/^/g, ' ');
}
var BAD_SH_RE = /[<>'"`$\\]/;
Releases.renderBash = async function (
pkgdir,
rel,
{ baseurl, pkg, tag, ver, os = '', arch = '', formats },
{ baseurl, pkg, tag, ver, os = '', arch = '', libc = '', formats },
) {
if (!Array.isArray(formats)) {
formats = [];
@@ -40,168 +39,116 @@ Releases.renderBash = async function (
if (!tag) {
tag = '';
}
return fs.promises
.readFile(path.join(pkgdir, 'install.sh'), 'utf8')
.then(function (installTxt) {
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;
return fs.promises
.readFile(path.join(__dirname, 'template.sh'), 'utf8')
.then(function (tplTxt) {
// ex: 'node@lts' or 'node'
var webiPkg = pkg;
if (ver) {
webiPkg += `@${ver}`;
}
return (
tplTxt
.replace(/CHEATSHEET_URL/g, `${baseurl}/${pkg}`)
.replace(/^\s*#?WEBI_PKG=.*/m, `WEBI_PKG='${webiPkg}'`)
.replace(/^\s*#?WEBI_HOST=.*/m, `WEBI_HOST='${baseurl}'`)
.replace(/^\s*#?WEBI_OS=.*/m, `WEBI_OS='${os}'`)
.replace(/^\s*#?WEBI_ARCH=.*/m, `WEBI_ARCH='${arch}'`)
.replace(/^\s*#?WEBI_TAG=.*/m, `WEBI_TAG='${tag}'`)
.replace(
/^\s*#?WEBI_RELEASES=.*/m,
"WEBI_RELEASES='" +
baseurl +
'/api/releases/' +
pkg +
'@' +
tag +
'.tab?os=' +
rel.os +
'&arch=' +
rel.arch +
'&formats=' +
formats.join(',') +
'&pretty=true' +
"'",
)
.replace(
/^\s*#?WEBI_CSV=.*/m,
"WEBI_CSV='" +
[
rel.version,
rel.lts,
rel.channel,
rel.date,
rel.os,
rel.arch,
rel.ext,
'-',
rel.download,
rel.name,
rel.comment || '',
]
.join(',')
.replace(/'/g, '') +
"'",
)
.replace(
/^\s*#?WEBI_VERSION=.*/m,
'WEBI_VERSION=' + JSON.stringify(rel.version),
)
.replace(/^\s*#?WEBI_MAJOR=.*/m, 'WEBI_MAJOR=' + v.major)
.replace(/^\s*#?WEBI_MINOR=.*/m, 'WEBI_MINOR=' + v.minor)
.replace(/^\s*#?WEBI_PATCH=.*/m, 'WEBI_PATCH=' + v.patch)
.replace(/^\s*#?WEBI_BUILD=.*/m, 'WEBI_BUILD=' + v.build)
.replace(/^\s*#?WEBI_LTS=.*/m, 'WEBI_LTS=' + rel.lts)
.replace(/^\s*#?WEBI_CHANNEL=.*/m, 'WEBI_CHANNEL=' + rel.channel)
.replace(
/^\s*#?WEBI_EXT=.*/m,
'WEBI_EXT=' + rel.ext.replace(/tar.*/, 'tar'),
)
.replace(
/^\s*#?WEBI_FORMATS=.*/m,
"WEBI_FORMATS='" + formats.join(',') + "'",
)
.replace(
/^\s*#?WEBI_PKG_URL=.*/m,
"WEBI_PKG_URL='" + rel.download + "'",
)
.replace(
/^\s*#?WEBI_PKG_FILE=.*/m,
"WEBI_PKG_FILE='" + pkgFile + "'",
)
// PKG details
.replace(/^\s*#?PKG_NAME=.*/m, "PKG_NAME='" + pkg + "'")
.replace(
/^\s*#?PKG_OSES=.*/m,
"PKG_OSES='" + ((rel && rel.oses) || []).join(',') + "'",
)
.replace(
/^\s*#?PKG_ARCHES=.*/m,
"PKG_ARCHES='" + ((rel && rel.arches) || []).join(',') + "'",
)
.replace(
/^\s*#?PKG_FORMATS=.*/m,
"PKG_FORMATS='" + ((rel && rel.formats) || []).join(',') + "'",
)
// $', $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, '$$$$'))
);
});
});
};
Releases.renderBatch = async function (
pkgdir,
rel,
{ baseurl, pkg, tag, ver, os, arch, formats },
) {
if (!Array.isArray(formats)) {
formats = [];
let installTxt = await fs.promises.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.promises.readFile(
path.join(__dirname, 'install-package.tpl.sh'),
'utf8',
);
// ex: 'node@lts' or 'node'
var webiPkg = pkg;
if (ver) {
webiPkg += `@${ver}`;
}
if (!tag) {
tag = '';
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 envReplacements = [
['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.replace(/tar.*/, 'tar')],
['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_OSES', rel.oses],
['PKG_ARCHES', rel.arches],
['PKG_LIBCS', rel.libcs],
['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\\s)?[ \\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}'`);
}
return fs.promises
.readFile(path.join(pkgdir, 'install.bat'), 'utf8')
.then(function (installTxt) {
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(/^-/, '')
};
*/
return fs.promises
.readFile(path.join(__dirname, 'template.bat'), 'utf8')
.then(function (tplTxt) {
return tplTxt
.replace(
/^(REM )?WEBI_PKG=.*/im,
"WEBI_PKG='" + pkg + '@' + ver + "'",
)
.replace(reInstallTpl, '\n' + installTxt);
});
});
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;
};
Releases.renderPowerShell = async function (
pkgdir,
rel,
{ baseurl, pkg, tag, ver, os, arch, formats },
{ baseurl, pkg, tag, ver, os, arch, libc = '', formats },
) {
if (!Array.isArray(formats)) {
formats = [];
@@ -209,52 +156,65 @@ Releases.renderPowerShell = async function (
if (!tag) {
tag = '';
}
return fs.promises
.readFile(path.join(pkgdir, 'install.ps1'), 'utf8')
.then(function (installTxt) {
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(/^-/, '')
};
*/
return fs.promises
.readFile(path.join(__dirname, 'template.ps1'), 'utf8')
.then(function (tplTxt) {
var pkgver = pkg + '@' + ver;
return tplTxt
.replace(
/^(#)?\$Env:WEBI_HOST\s*=.*/im,
"$Env:WEBI_HOST = '" + baseurl + "'",
)
.replace(
/^(#)?\$Env:WEBI_PKG\s*=.*/im,
"$Env:WEBI_PKG = '" + pkgver + "'",
)
.replace(
/^(#)?\$Env:PKG_NAME\s*=.*/im,
"$Env:PKG_NAME = '" + pkg + "'",
)
.replace(
/^(#)?\$Env:WEBI_VERSION\s*=.*/im,
"$Env:WEBI_VERSION = '" + rel.version + "'",
)
.replace(
/^(#)?\$Env:WEBI_PKG_URL\s*=.*/im,
"$Env:WEBI_PKG_URL = '" + rel.download + "'",
)
.replace(
/^(#)?\$Env:WEBI_PKG_FILE\s*=.*/im,
"$Env:WEBI_PKG_FILE = '" + rel.name + "'",
)
.replace(reInstallTpl, '\n' + installTxt);
});
});
let installTxt = await fs.promises.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.promises.readFile(
path.join(__dirname, 'install-package.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)
);
};

View File

@@ -1,5 +1,9 @@
'use strict';
var Installers = module.exports;
var Crypto = require('crypto');
var Fs = require('fs/promises');
var path = require('path');
var uaDetect = require('./ua-detect.js');
@@ -9,13 +13,37 @@ var Releases = require('./releases.js');
// handlers caching and transformation, probably should be broken down
var getReleases = require('./transform-releases.js');
var installersDir = path.join(__dirname, '..');
Installers.INSTALLERS_DIR = path.join(__dirname, '..');
Installers.serveInstaller = async function (
baseurl,
ua,
pkg,
tag,
ext,
formats,
libc,
) {
let [rel, opts] = await Installers.helper({
ua,
pkg,
tag,
formats,
libc,
});
Object.assign(opts, {
baseurl,
});
serveInstaller.serveInstaller = serveInstaller;
module.exports = serveInstaller;
async function serveInstaller(baseurl, ua, pkg, tag, ext, formats) {
var pkgdir = path.join(Installers.INSTALLERS_DIR, pkg);
if ('ps1' === ext) {
return Releases.renderPowerShell(pkgdir, rel, opts);
}
return Releases.renderBash(pkgdir, rel, opts);
};
Installers.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
var ver = tag.replace(/^v/, '');
var lts;
var channel;
@@ -44,12 +72,21 @@ async function serveInstaller(baseurl, ua, pkg, tag, ext, formats) {
break;
}
// TODO maybe move package/version/lts/channel detection into getReleases
var myOs = uaDetect.os(ua);
var myArch = uaDetect.arch(ua);
var myLibc = uaDetect.libc(ua);
var myLibc;
if (libc) {
myLibc = uaDetect.libc(libc);
}
if (!myLibc) {
myLibc = uaDetect.libc(ua);
}
if (!myLibc) {
myLibc = 'libc';
}
let cfg = await packages.get(pkg);
let rels = await getReleases({
let releaseQuery = {
pkg: cfg.alias || pkg,
ver,
os: myOs,
@@ -57,33 +94,147 @@ async function serveInstaller(baseurl, ua, pkg, tag, ext, formats) {
libc: myLibc,
lts,
channel,
// TODO use formats for sorting, not exclusion
// (it's better to install xz or report an error to install zip)
formats,
limit: 1,
});
};
let rels = await getReleases(releaseQuery);
var rel = rels.releases[0];
var pkgdir = path.join(installersDir, pkg);
var opts = {
baseurl,
pkg: cfg.alias || pkg,
ver,
tag,
os: myOs,
arch: myArch,
libc: myLibc,
lts,
channel,
formats,
limit: 1,
};
rel.oses = rels.oses;
rel.arches = rels.arches;
rel.formats = rels.formats;
rel = Object.assign(
{
oses: rels.oses,
arches: rels.arches,
libcs: rels.libcs,
formats: rels.formats,
},
rel,
);
if ('bat' === ext) {
return Releases.renderBatch(pkgdir, rel, opts);
return [rel, opts];
};
var CURL_PIPE_PS1_BOOT = path.join(__dirname, 'bootstrap.ps1');
var CURL_PIPE_SH_BOOT = path.join(__dirname, 'bootstrap.sh');
var BAD_SH_RE = /[<>'"`$\\]/;
Installers.getPosixCurlPipeBootstrap = async function ({ baseurl, pkg, ver }) {
let bootTxt = await Fs.readFile(CURL_PIPE_SH_BOOT, 'utf8');
var webiPkg = [pkg, ver].filter(Boolean).join('@');
var webiChecksum = await Installers.getWebiShChecksum();
var envReplacements = [
['WEBI_PKG', webiPkg],
['WEBI_HOST', baseurl],
['WEBI_CHECKSUM', webiChecksum],
];
for (let env of envReplacements) {
let name = env[0];
let value = env[1];
// TODO create REs once, in higher scope
let envRe = new RegExp(
`^[ \\t]*#?[ \\t]*(export\\s)?[ \\t]*(${name})=.*`,
'm',
);
if (BAD_SH_RE.test(value)) {
throw new Error(`key '${name}' has invalid value '${value}'`);
}
bootTxt = bootTxt.replace(envRe, `$1$2='${value}'`);
}
if ('ps1' === ext) {
return Releases.renderPowerShell(pkgdir, rel, opts);
// TODO init config here
//bootTxt.replace(/CHEATSHEET_URL/g, `${Config.cheatUrl}/${pkg}`);
return bootTxt;
};
Installers.getPwshCurlPipeBootstrap = async function ({
baseurl,
pkg,
ver,
exename,
}) {
let bootTxt = await Fs.readFile(CURL_PIPE_PS1_BOOT, 'utf8');
var webiPkg = [pkg, ver].filter(Boolean).join('@');
//var webiChecksum = await Installers.getWebiPs1Checksum();
var envReplacements = [
['Env:WEBI_PKG', webiPkg],
['Env:WEBI_HOST', baseurl],
//['Env:WEBI_CHECKSUM', webiChecksum],
['baseurl', baseurl],
['exename', exename],
['version', ver],
];
for (let env of envReplacements) {
let name = env[0];
let value = env[1];
if (BAD_SH_RE.test(value)) {
throw new Error(`key '${name}' has invalid value '${value}'`);
}
let tplRe = new RegExp(`{{ (${name}) }}`, 'g');
bootTxt = bootTxt.replace(tplRe, `${value}`);
// let envRe = new RegExp(`^[ \\t]*#?[ \\t]*($$${name})[ \\t]*=.*`, 'im');
// bootTxt = bootTxt.replace(envRe, `$$${name} = '${value}'`);
let setRe = new RegExp(
`(#[ \\t]*)?(\\$${name})[ \\t]*=[ \\t]['"].*['"][ \\t]`,
'im',
);
bootTxt = bootTxt.replace(setRe, `$$${name} = '${value}'`);
}
return Releases.renderBash(pkgdir, rel, opts);
}
// TODO init config here
//bootTxt.replace(/CHEATSHEET_URL/g, `${Config.cheatUrl}/${pkg}`);
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

@@ -1,5 +0,0 @@
REM REM debug
REM WEBI_PKG=
{{ installer }}

View File

@@ -28,16 +28,18 @@ $Env:WEBI_HOST = 'https://webinstall.dev'
#$Env:WEBI_PKG = 'node@lts'
#$Env:PKG_NAME = node
#$Env:WEBI_VERSION = v12.16.2
#$Env:WEBI_GIT_TAG = 12.16.2
#$Env:WEBI_PKG_URL = "https://.../node-....zip"
#$Env:WEBI_PKG_FILE = "node-v12.16.2-win-x64.zip"
#$Env:WEBI_PKG_PATHNAME = "node-v12.16.2-win-x64.zip"
# Switch to userprofile
Push-Location $Env:USERPROFILE
# Make paths
New-Item -Path Downloads -ItemType Directory -Force | Out-Null
New-Item -Path .local\bin -ItemType Directory -Force | Out-Null
New-Item -Path .local\opt -ItemType Directory -Force | Out-Null
New-Item -Path "$Env:USERPROFILE\Downloads" -ItemType Directory -Force | Out-Null
New-Item -Path "$Env:USERPROFILE\.local\bin" -ItemType Directory -Force | Out-Null
New-Item -Path "$Env:USERPROFILE\.local\opt" -ItemType Directory -Force | Out-Null
# {{ baseurl }}
# {{ version }}
@@ -84,29 +86,33 @@ function webi_path_add($pathname) {
}
}
if (-Not $in_session_path) {
$my_cmd = 'PATH ' + "$pathname" + ';%PATH%'
$my_pwsh = '$Env:Path = "' + "$pathname" + ';$Env:Path"'
Write-Host ''
Write-Host '**********************************' -ForegroundColor red -BackgroundColor white
Write-Host '* IMPORTANT -- READ ME *' -ForegroundColor red -BackgroundColor white
Write-Host '* (run the PATH command below) *' -ForegroundColor red -BackgroundColor white
Write-Host '**********************************' -ForegroundColor red -BackgroundColor white
Write-Host ''
Write-Output ""
Write-Output "Copy, paste, and run the appropriate command to update your PATH:"
Write-Output "(or close and reopen the terminal, or reboot)"
Write-Output ""
Write-Output "cmd.exe:"
Write-Output " $my_cmd"
Write-Output ""
Write-Output "PowerShell:"
Write-Output " $my_pwsh"
Write-Output ""
if (-Not ($in_session_path)) {
webi_path_add_followup $pathname
}
}
function webi_path_add_followup($pathname) {
$my_cmd = 'PATH ' + "$pathname" + ';%PATH%'
$my_pwsh = '$Env:Path = "' + "$pathname" + ';$Env:Path"'
Write-Host ''
Write-Host '**********************************' -ForegroundColor yellow -BackgroundColor black
Write-Host '* IMPORTANT -- READ ME *' -ForegroundColor yellow -BackgroundColor black
Write-Host '* (run the PATH command below) *' -ForegroundColor yellow -BackgroundColor black
Write-Host '**********************************' -ForegroundColor yellow -BackgroundColor black
Write-Host ''
Write-Output ""
Write-Output "Copy, paste, and run the appropriate command to update your PATH:"
Write-Output "(or close and reopen the terminal, or reboot)"
Write-Output ""
Write-Output "cmd.exe:"
Write-Host " $my_cmd" -ForegroundColor yellow -BackgroundColor black
Write-Output ""
Write-Output "PowerShell:"
Write-Host " $my_pwsh" -ForegroundColor yellow -BackgroundColor black
Write-Output ""
}
#$has_local_bin = echo "$Env:PATH" | Select-String -Pattern '\.local.bin'
#if (!$has_local_bin)
#{

View File

@@ -8,14 +8,18 @@ __bootstrap_webi() {
my_libc=''
if ldd /bin/ls 2> /dev/null | grep -q 'musl' 2> /dev/null; then
my_libc=' musl-native'
my_libc='musl'
elif uname -o | grep -q 'GNU' || uname -s | grep -q 'Linux'; then
my_libc='gnu'
else
my_libc='libc'
fi
#WEBI_PKG=
#PKG_NAME=
# TODO should this be BASEURL instead?
#WEBI_OS=
#WEBI_ARCH=
#WEBI_LIBC=
#WEBI_HOST=
#WEBI_RELEASES=
#WEBI_CSV=
@@ -26,16 +30,19 @@ __bootstrap_webi() {
#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_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
@@ -70,7 +77,8 @@ __bootstrap_webi() {
export WEBI_WGET
set -e
# get the special formatted version (i.e. "go is go1.14" while node is "node v12.10.8")
# 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
@@ -78,7 +86,7 @@ __bootstrap_webi() {
return 0
fi
if [ -n "$(command -v pkg_format_cmd_version)" ]; then
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'"
@@ -87,28 +95,28 @@ __bootstrap_webi() {
echo "$my_versioned_name"
}
# update symlinks according to $HOME/.local/opt and $HOME/.local/bin install paths.
# shellcheck disable=2120
# webi_link may be used in the templated install script
# Update symlinks as per $HOME/.local/opt and $HOME/.local/bin install paths.
webi_link() {
if [ -n "$(command -v pkg_link)" ]; then
if command -v pkg_link > /dev/null; then
pkg_link
return 0
fi
if [ -n "$WEBI_SINGLE" ] || [ "single" = "${1-}" ]; then
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>
# '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() {
# 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"
@@ -128,25 +136,59 @@ __bootstrap_webi() {
# 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:"
printf " %s" "${pkg_dst}"
my_dst_rel="$(
webi_sub_home "${pkg_dst}"
)"
printf " %s" "${my_dst_rel}"
if [ "${pkg_src_cmd}" != "${my_current_cmd}" ]; then
printf " => %s" "${pkg_src}"
my_src_rel="$(
webi_sub_home "${pkg_src}"
)"
printf " => %s" "${my_src_rel}"
fi
echo ""
exit 0
fi
if [ -x "$pkg_src_cmd" ]; then
# shellcheck disable=2119
# this function takes no args
webi_link
echo "switched to $my_canonical_name:"
echo " ${pkg_dst} => ${pkg_src}"
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
@@ -161,47 +203,27 @@ __bootstrap_webi() {
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() {
# determine the url to download
if [ -n "${1-}" ]; then
my_url="${1}"
else
if [ "error" = "$WEBI_CHANNEL" ]; then
# TODO pass back requested OS / Arch / Version
echo >&2 "Error: no '$PKG_NAME' release for '${WEBI_OS-}' on '$WEBI_ARCH' as one of '$WEBI_FORMATS' by the tag '${WEBI_TAG-}'"
echo >&2 " '$PKG_NAME' is available for '$PKG_OSES' 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:\?.*::'
)"
echo >&2 " Double check at ${my_release_url}"
echo >&2 ""
exit 1
fi
my_url="$WEBI_PKG_URL"
fi
my_url="${1}"
my_dl="${2}"
my_dl_name="${3:-${PKG_NAME}}"
# determine the location to download to
if [ -n "${2-}" ]; then
my_dl="${2}"
else
my_dl="${WEBI_PKG_PATH}/$WEBI_PKG_FILE"
fi
if [ -n "${3-}" ]; then
my_dl_name="${3}"
else
my_dl_name="${PKG_NAME}"
fi
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"
if [ -e "${my_dl}" ]; then
echo "Found ${my_dl_rel}"
return 0
fi
@@ -225,7 +247,6 @@ __bootstrap_webi() {
set -e
else
# Neither GNU nor BSD curl have sane resume download options, hence we don't bother
# TODO curl -fsSL --remote-name --remote-header-name --write-out "$my_url"
my_show_progress="-#"
if is_interactive_shell; then
my_show_progress=""
@@ -237,27 +258,59 @@ __bootstrap_webi() {
mv "$my_dl.part" "$my_dl"
echo ""
echo "Saved as $my_dl"
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 ${WEBI_PKG_PATH}/$WEBI_PKG_FILE"
echo "Extracting ${my_dl_rel}"
tar xf "${WEBI_PKG_PATH}/$WEBI_PKG_FILE"
elif [ "zip" = "$WEBI_EXT" ]; then
echo "Extracting ${WEBI_PKG_PATH}/$WEBI_PKG_FILE"
echo "Extracting ${my_dl_rel}"
unzip "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" > __unzip__.log
elif [ "exe" = "$WEBI_EXT" ]; then
echo "Moving ${WEBI_PKG_PATH}/$WEBI_PKG_FILE"
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 ${WEBI_PKG_PATH}/$WEBI_PKG_FILE"
echo "Inflating ${my_dl_rel}"
unxz -c "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" > "$(basename "$WEBI_PKG_FILE")"
else
# do nothing
echo "Failed to extract ${WEBI_PKG_PATH}/$WEBI_PKG_FILE"
exit 1
fi
@@ -443,16 +496,24 @@ __bootstrap_webi() {
# group common pre-install tasks as default
webi_pre_install() {
webi_check
webi_download
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
# shellcheck disable=2120
# webi_install may be sourced and used elsewhere
# move commands from the extracted archive directory
# to $HOME/.local/opt or $HOME/.local/bin
webi_install() {
if [ -n "$WEBI_SINGLE" ] || [ "single" = "${1-}" ]; then
if test -n "${WEBI_SINGLE}"; then
mkdir -p "$(dirname "$pkg_src_cmd")"
mv ./"$pkg_cmd_name"* "$pkg_src_cmd"
else
@@ -463,39 +524,29 @@ __bootstrap_webi() {
# 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 [ -n "$(command -v spctl)" ] && [ -n "$(command -v xattr)" ]; then
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
# TODO need to test that the above actually worked
# (and proceed to this below if it did not)
if [ -n "$(command -v spctl)" ]; then
echo "Checking permission to execute '$pkg_cmd_name' on macOS 11+"
set +e
is_allowed="$(spctl -a "$pkg_src_cmd" 2>&1 | grep valid)"
set -e
if [ -z "$is_allowed" ]; then
echo ""
echo "##########################################"
echo "# IMPORTANT: Permission Grant Required #"
echo "##########################################"
echo ""
echo "Requesting permission to execute '$pkg_cmd_name' on macOS 10.14+"
echo ""
sleep 3
spctl --add "$pkg_src_cmd"
fi
fi
}
# a friendly message when all is well, showing the final install path in $HOME/.local
_webi_done_message() {
echo "Installed $(_webi_canonical_name) as $pkg_dst_cmd"
my_dst_rel="$(
webi_sub_home "${pkg_dst_cmd}"
)"
my_canonical_name="$(
_webi_canonical_name
)"
echo "Installed ${my_canonical_name} as ${my_dst_rel}"
}
##
@@ -508,7 +559,7 @@ __bootstrap_webi() {
if [ -z "${WEBI_WELCOME-}" ]; then
echo ""
printf "Thanks for using webi to install '\e[32m%s\e[0m' on '\e[33m%s/%s\e[0m'.\n" "${WEBI_PKG-}" "$(uname -s)" "$(uname -m)"
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 ""
@@ -517,13 +568,14 @@ __bootstrap_webi() {
echo ""
fi
WEBI_WELCOME=true
export WEBI_WELCOME
__init_installer() {
# do nothing - to satisfy parser prior to templating
printf ""
# the installer will be injected here
# {{ installer }}
return 0
}
__init_installer
@@ -551,13 +603,19 @@ __bootstrap_webi() {
pkg_cmd_name="${pkg_cmd_name:-$PKG_NAME}"
if [ -n "$WEBI_SINGLE" ]; then
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" # "$(dirname "$(dirname $pkg_dst_cmd)")"
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" # "$(dirname "$(dirname $pkg_src_cmd)")"
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}"
@@ -565,33 +623,40 @@ __bootstrap_webi() {
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
# this script is templated and these are used elsewhere
# shellcheck disable=SC2034
# shellcheck disable=SC2034 # used in ${WEBI_PKG}/install.sh
pkg_src_bin="$(dirname "$pkg_src_cmd")"
# shellcheck disable=SC2034
# shellcheck disable=SC2034 # used in ${WEBI_PKG}/install.sh
pkg_dst_bin="$(dirname "$pkg_dst_cmd")"
if [ -n "$(command -v pkg_pre_install)" ]; then pkg_pre_install; else webi_pre_install; fi
if command -v pkg_pre_install > /dev/null; then pkg_pre_install; else webi_pre_install; fi
(
cd "$WEBI_TMP"
echo "Installing to $pkg_src_cmd"
if [ -n "$(command -v pkg_install)" ]; then pkg_install; else webi_install; fi
chmod a+x "$pkg_src"
chmod a+x "$pkg_src_cmd"
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
)
webi_link
_webi_enable_exec
if test -z "${pkg_no_exec}"; then
webi_link
_webi_enable_exec
fi
(
cd "$WEBI_TMP"
if [ -n "$(command -v pkg_post_install)" ]; then pkg_post_install; else webi_post_install; fi
if command -v pkg_post_install > /dev/null; then pkg_post_install; else webi_post_install; fi
)
(
cd "$WEBI_TMP"
if [ -n "$(command -v pkg_done_message)" ]; then pkg_done_message; else _webi_done_message; fi
if command -v pkg_done_message > /dev/null; then pkg_done_message; else _webi_done_message; fi
)
echo ""
@@ -599,7 +664,7 @@ __bootstrap_webi() {
webi_path_add "$HOME/.local/bin"
if [ -z "${_WEBI_CHILD-}" ] && [ -f "$_webi_tmp/.PATH.env" ]; then
if [ -n "$(cat "$_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}"
@@ -615,11 +680,7 @@ __bootstrap_webi() {
fi
fi
# cleanup the temp directory
rm -rf "$WEBI_TMP"
# See? No magic. Just downloading and moving files.
}
__bootstrap_webi

View File

@@ -33,7 +33,8 @@ var os = require('os');
var fs = require('fs');
var path = require('path');
var Releases = require('./releases.js');
var uaDetect = require('./ua-detect.js');
var ServeInstaller = require('./serve-installer.js');
var pkg = process.argv[2].split('@');
var pkgdir = pkg[0];
var pkgtag = pkg[1] || '';
@@ -42,6 +43,7 @@ var nodes = fs.readdirSync(pkgdir);
nodes.forEach(function (node) {
nodesMap[node] = true;
});
var baseurl = 'https://webinstall.dev';
var maxLen = 0;
console.info('');
@@ -62,31 +64,48 @@ console.info('Has the necessary files?');
});
console.info('');
Releases.get(path.join(process.cwd(), pkgdir)).then(function (all) {
Releases.get(path.join(process.cwd(), pkgdir)).then(async function (all) {
var pkgname = path.basename(pkgdir.replace(/\/$/, ''));
var osrel = os.platform() + '-' + os.release();
var arch = os.arch();
var formats = ['exe', 'xz', 'tar', 'zip'];
var nodeOs = os.platform();
var nodeOsRelease = os.release();
var nodeArch = os.arch();
var nodeLibc = 'libc';
if (process.platform === 'linux') {
nodeLibc = 'gnu';
let isUnofficial =
process.config.variables.node_release_urlbase.includes('unofficial');
if (isUnofficial) {
nodeLibc = 'musl';
}
}
var formats = ['exe', 'xz', 'tar', 'zip', 'git'];
var rel = all.releases.filter(function (rel) {
return (
formats.filter(function (ext) {
return rel.ext.match(ext);
})[0] &&
'stable' === rel.channel &&
rel.os === uaDetect.os(osrel) &&
rel.arch === uaDetect.arch(arch) &&
(!pkgtag ||
rel.tag === pkgtag ||
new RegExp('^' + pkgtag).test(rel.version))
);
})[0];
rel.oses = all.oses;
rel.arches = all.arches;
rel.formats = all.formats;
let [rel, opts] = await ServeInstaller.helper({
ua: `${nodeOs}/${nodeOsRelease} ${nodeArch}/unknown ${nodeLibc}`,
pkg: pkgname,
tag: pkgtag || '',
formats: formats,
libc: nodeLibc,
});
Object.assign(
{
ver: '',
lts: null,
channel: '',
os: '',
arch: '',
limit: 0,
},
opts,
{
baseurl,
},
);
if (!rel) {
console.error('Error: ❌ no release found for current os, arch, and tag');
console.error(
`Error: ❌ no release found for @${pkgtag}?os=${nodeOs}&arch=${nodeArch}&libc=${nodeLibc}&formats=${formats}`,
);
process.exit(1);
return;
}
@@ -97,24 +116,8 @@ Releases.get(path.join(process.cwd(), pkgdir)).then(function (all) {
console.info('');
return Promise.all([
Releases.renderBash(pkgdir, rel, {
baseurl: 'https://webinstall.dev',
pkg: pkgname,
tag: pkgtag || '',
ver: '',
os: osrel,
arch,
formats: formats,
}).catch(function () {}),
Releases.renderPowerShell(pkgdir, rel, {
baseurl: 'https://webinstall.dev',
pkg: pkgname,
tag: pkgtag || '',
ver: '',
os: osrel,
arch,
formats: formats,
}).catch(function () {}),
Releases.renderBash(pkgdir, rel, opts).catch(function () {}),
Releases.renderPowerShell(pkgdir, rel, opts).catch(function () {}),
]).then(function (scripts) {
var bashTxt = scripts[0];
var ps1Txt = scripts[1];
@@ -138,5 +141,9 @@ Releases.get(path.join(process.cwd(), pkgdir)).then(function (all) {
console.info('\tNEEDS MANUAL TEST: powershell.exe %s', ps1File);
}
console.info('');
setTimeout(function () {
console.warn(`[warn] dangling event loop handle`);
process.exit(0);
}, 300).unref();
});
});

View File

@@ -2,7 +2,6 @@
var path = require('path');
var Releases = require('./releases.js');
var uaDetect = require('./ua-detect.js');
var cache = {};
//var staleAge = 5 * 1000;
@@ -54,21 +53,14 @@ function createFormatsSorter(formats) {
return 1;
}
// Hacky-doo for musl-native: prefer non-musl
if (a._musl_native && !b._musl_native) {
return 1;
}
if (!a._musl_native && b._musl_native) {
// rank builds that don't depend on any form of libc first
if (a.libc === 'none' && b.libc !== 'none') {
return -1;
}
if (a.libc !== 'none' && b.libc === 'none') {
return 1;
}
// Hacky-doo for linux: prefer musl
if (a._musl && !b._musl) {
return -1;
}
if (!a._musl && b._musl) {
return 1;
}
return 0;
};
}
@@ -182,24 +174,35 @@ async function filterReleases(
function selectMatches(rel) {
if (os) {
if (rel.os !== os) {
return false;
if (rel.os !== '*') {
if (rel.os !== os) {
return false;
}
}
}
if (arch) {
if (rel.arch !== arch) {
return false;
if (rel.arch !== '*') {
if (rel.arch !== arch) {
return false;
}
}
}
// Hacky-doo for linux musl
if (libc === uaDetect.MUSL_NATIVE) {
if (!rel._musl && !rel._musl_native) {
if (rel.libc !== 'none') {
let releaseRequiresMusl = rel.libc === 'musl';
// goal: handle non-glibc (Alpine / Docker / musl)
let osHasMusl = libc === 'musl';
if (osHasMusl) {
// goal: fail if dependent on libc
let releaseRequiresLibc = rel.libc === 'gnu';
if (releaseRequiresLibc) {
return false;
}
} else if (releaseRequiresMusl) {
// goal: don't use musl++ on glibc (Ubuntu, GNU, etc)
return false;
}
} else if (rel._musl_native) {
return false;
}
if (lts) {
@@ -359,20 +362,20 @@ module.exports = function getReleases({
date: '1970-01-01',
os: os || '-',
arch: arch || '-',
_musl: undefined,
_musl_native: undefined,
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|-}&limit=100'",
"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,
libcs: all.libcs,
formats: all.formats,
releases: releases,
};
@@ -388,7 +391,7 @@ if (require.main === module) {
os: 'macos',
arch: 'amd64',
lts: true,
libc: '',
libc: 'libc',
channel: 'stable',
formats: ['tar', 'exe', 'zip', 'xz', 'dmg', 'pkg'],
limit: 10,

View File

@@ -2,10 +2,6 @@
var uaDetect = module.exports;
const MUSL_NATIVE = 'musl-native';
uaDetect.MUSL_NATIVE = MUSL_NATIVE;
function getRequest(req) {
var ua = req.headers['user-agent'] || '';
var os = req.query.os;
@@ -100,19 +96,55 @@ function getLibc(ua) {
return '-';
}
// Use native 'libc' information, if provided
//
// How to see a bunch of target host quadruples:
// go tool dist list
// rustup target list
// zig targets | jq -r '.libc[]' | sort -
// Generally, we prefer 'musl' builds because they DO work on glibc systems (Ubuntu),
// but 'glibc' builds will NOT work on musl systems (Alpine / Docker).
//
// However, there are a few instances (ex: Node.js), where the 'musl' builds
// DO NOT work on glibc systems.
if (ua.match(MUSL_NATIVE)) {
return MUSL_NATIVE;
{
let muslRe = /(\b|_)(musl)(\b|_)/i;
if (muslRe.test(ua)) {
return 'musl';
}
}
// TODO handle explicit invalid different
return '';
{
let msvcRe = /(\b|_)(msvc|windows|microsoft)(\b|_)/i;
if (msvcRe.test(ua)) {
return 'msvc';
}
}
{
let gnuRe = /(\b|_)(gnu|glibc|linux)(\b|_)/i;
if (gnuRe.test(ua)) {
return 'gnu';
}
}
{
let libcRe = /(\b|_)(libc)(\b|_)/i;
if (libcRe.test(ua)) {
return 'libc';
}
}
{
let darwinRe = /(\b|_)(darwin)(\b|_)/i;
if (darwinRe.test(ua)) {
// not sure whether this should be "darwin" or "libc" or "none"
// https://opensource.apple.com/source/Libc/
return 'libc';
}
}
return 'libc';
}
uaDetect.os = getOs;

View File

@@ -28,7 +28,7 @@ IF ($my_arch -eq "AMD64") {
}
}
$Env:WEBI_UA = "Windows/10 $my_arch"
$Env:WEBI_UA = "Windows/10+ $my_arch msvc"
$exename = $args[0]
# Switch to userprofile
@@ -100,7 +100,7 @@ if ($exename -eq "-V" -or $exename -eq "--version" -or $exename -eq "version" -o
# Fetch <whatever>.ps1
# TODO detect formats
$PKG_URL = "$Env:WEBI_HOST/api/installers/$exename.ps1?formats=zip,exe,tar"
$PKG_URL = "$Env:WEBI_HOST/api/installers/$exename.ps1?formats=zip,exe,tar,git&libc=msvc"
Write-Output "Downloading $PKG_URL"
# Invoke-WebRequest -UserAgent "Windows amd64" "$PKG_URL" -OutFile ".\.local\tmp\$exename.install.ps1"
& curl.exe -fsSL -A "$Env:WEBI_UA" "$PKG_URL" -o .\.local\tmp\$exename.install.ps1

View File

@@ -1,27 +0,0 @@
@echo off
pushd "%userprofile%" || goto :error
IF NOT EXIST .local (
mkdir .local || goto :error
)
IF NOT EXIST .local\bin (
mkdir .local\bin || goto :error
)
IF NOT EXIST .local\opt (
mkdir .local\opt || goto :error
)
echo Downloading and installing %1
powershell $ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest https://webinstall.dev/packages/%1/install.ps1 -OutFile %1-webinstall.bat || goto :error
rem TODO only add if it's not in there already
PATH .local\bin;%PATH%
call %1-webinstall.bat || goto :error
del %1-webinstall.bat || goto :error
popd
goto :EOF
:error
echo Failed with error #%errorlevel%.
exit /b %errorlevel%

View File

@@ -1 +0,0 @@
powershell -ExecutionPolicy Bypass .\.local\bin\webi-pwsh.ps1 %1

View File

@@ -8,10 +8,13 @@ let targets = {
x86win: {
os: 'windows',
arch: 'x86',
libc: 'msvc',
},
x64win: {
os: 'windows',
arch: 'amd64',
// https://github.com/wez/atomicparsley/issues/6#issuecomment-1364523028
libc: 'msvc',
},
x64mac: {
os: 'macos',
@@ -20,11 +23,12 @@ let targets = {
x64lin: {
os: 'linux',
arch: 'amd64',
libc: 'gnu',
},
x64musl: {
os: 'linux',
arch: 'amd64',
_musl_native: true,
libc: 'musl',
},
};

View File

@@ -7,6 +7,7 @@ main() { (
chmod a+x ~/.local/bin/brew-update-hourly
env PATH="$PATH" serviceman add --user \
--workdir ~/.local/opt/brew/ \
--name sh.brew.updater -- \
~/.local/bin/brew-update-hourly
); }

File diff suppressed because it is too large Load Diff

View File

@@ -8,19 +8,19 @@
$pkg_cmd_name = "cmake"
$pkg_dst_cmd = "$Env:USERPROFILE\.local\opt\cmake\bin\cmake.exe"
$pkg_dst_bin = "$Env:USERPROFILE\.local\opt\cmake\bin"
$pkg_dst_dir = "$Env:USERPROFILE\.local\opt\cmake"
$pkg_dst = "$pkg_dst_cmd"
$pkg_dst = "$pkg_dst_dir"
$pkg_src_cmd = "$Env:USERPROFILE\.local\opt\cmake-v$Env:WEBI_VERSION\bin\cmake.exe"
$pkg_src_bin = "$Env:USERPROFILE\.local\opt\cmake-v$Env:WEBI_VERSION\bin"
$pkg_src_dir = "$Env:USERPROFILE\.local\opt\cmake-v$Env:WEBI_VERSION"
$pkg_src = "$pkg_src_cmd"
$pkg_src = "$pkg_src_dir"
New-Item "$Env:USERPROFILE\Downloads\webi" -ItemType Directory -Force | Out-Null
$pkg_download = "$Env:USERPROFILE\Downloads\webi\$Env:WEBI_PKG_FILE"
# Fetch archive
IF (!(Test-Path -Path "$Env:USERPROFILE\Downloads\webi\$Env:WEBI_PKG_FILE")) {
IF (!(Test-Path -Path "$pkg_download")) {
Write-Output "Downloading cmake 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"
@@ -49,6 +49,8 @@ IF (!(Test-Path -Path "$pkg_src_dir")) {
Pop-Location
}
Write-Output "Copying into '$pkg_dst_cmd' from '$pkg_src_cmd'"
Remove-Item -Path "$pkg_dst_cmd" -Recurse -ErrorAction Ignore | Out-Null
Write-Output "Copying into '$pkg_dst' from '$pkg_src'"
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" --version

View File

@@ -28,7 +28,11 @@ __init_cmake() {
mkdir -p "$(dirname "${pkg_src_dir}")"
# mv ./cmake-*/ ~/.local/opt/cmake-v3.27.0/
mv ./cmake-*/ "${pkg_src_dir}"
if test -e ./cmake-*/CMake.app/Contents/; then
mv ./cmake-*/CMake.app/Contents/ "${pkg_src_dir}"
else
mv ./cmake-*/ "${pkg_src_dir}"
fi
}
# pkg_get_current_version is recommended, but not required

View File

@@ -6,6 +6,35 @@ var repo = 'CMake';
module.exports = function (request) {
return github(request, owner, repo).then(function (all) {
for (let rel of all.releases) {
{
let linuxRe = /(\b|_)(linux|gnu)(\b|_)/i;
let isLinux = linuxRe.test(rel.download) || linuxRe.test(rel.name);
if (isLinux) {
let muslRe = /(\b|_)(musl|alpine)(\b|_)/i;
let isMusl = muslRe.test(rel.download) || muslRe.test(rel.name);
if (isMusl) {
rel.libc = 'musl';
} else {
rel.libc = 'gnu';
}
continue;
}
}
{
let windowsRe = /(\b|_)(win\d*|windows\d*)(\b|_)/i;
let isWindows =
windowsRe.test(rel.download) || windowsRe.test(rel.name);
if (isWindows) {
rel.libc = 'msvc';
continue;
}
}
}
return all;
});
};

116
crabz/README.md Normal file
View File

@@ -0,0 +1,116 @@
---
title: Crabz
homepage: https://github.com/sstadick/crabz
tagline: |
crabz: multi-threaded gzip (like pigz, but in Rust)
---
To update or switch versions, run `webi crabz@stable` (or `@0.8`, `@beta`, etc).
## Cheat Sheet
> `crabz` brings the power of multi-core compression to gzip and deflate. \
> (and a few other formats + other useful features)
gzip, faster.
```sh
crabz -I ./example.json
crabz -d -I ./example.json.gz
```
```text
Compressing (gzip) with 8 threads at compression level 6.
Decompressing (gzip) with 8 threads available.
```
## Table of Contents
- Files
- Tar
- Other Formats
### Files
These are the files/directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/crabz
```
#### How to Optimize
| Flag | Value | Comments |
| ----------------------------- | ----- | ------------------------------------------ |
| `-l`, `--compression-level` | 1-9 | higher is slower |
| `-p`, `--compression-threads` | 8 | set to the number of available cores |
| | | (but no more than 4 for decompression) |
| `-P`, `--pin-at` | 0 | pin to physical cores, starting at N |
| | | (so 4 threads starting at 0 is 0, 1, 2, 3) |
```sh
crabz -l 9 -p 8 -I ./example.tar
crabz -d -p 4 -I ./example.tar.gz
```
#### How to use with Tar
Tar and then compress:
```sh
tar cv ./example/ | crabz -o ./example.tar.gz
```
Or decompress and then untar:
```sh
crabz -d ./example.tar.gz | tar xv
```
#### How to use with other formats
`crabz` supports most of the _LZ77 with Huffman coding_ compression formats:
| Format | Extension | Notes |
| ---------------- | --------- | ------------------------------------ |
| `gzip` | `.gz` | of GNU fame |
| [`bgzf`][bgzf] | `.gz` | supports random-access decompression |
| [`mgzip`][mgzip] | `.gz` | of python fame |
| `zlib` | `.zz` | of PNG fame, also `.z` |
| [`snap`][snap] | `.sz` | of LevelDB and MongoDB fame |
| `deflate` | `.gz` | the O.G. LZ77 |
```sh
crabz --format mgzip -I ./example.tar
```
```sh
# DO NOT decompress in-place
crabz --format mgzip -d ./example.tar.gz -o ./example.tar
# verify before removing the original
tar tf ./example.tar
```
⚠️ **Warnings**:
- DO NOT deflate in-place with non-standard formats: \
Although `gunzip` will work correctly on files compressed with `mgzip` or
`bgzf`, some combinations (ex: decompressing from `mgzip` with `bgzf`) could
result in corruption!
- `tar xvf` and `gzip -l` may report incorrect information, even though `gunzip`
will work
See also:
- https://dev.to/biellls/compression-clearing-the-confusion-on-zip-gzip-zlib-and-deflate-15g1
(p.s. `zip` isn't in the list because it's a container format like `tar`, not a
zip format)
[snap]: https://github.com/google/snappy/blob/main/format_description.txt
[bgzf]: https://samtools.github.io/hts-specs/SAMv1.pdf
[mgzip]: https://pypi.org/project/mgzip/

48
crabz/install.ps1 Normal file
View File

@@ -0,0 +1,48 @@
#!/usr/bin/env pwsh
#################
# Install crabz #
#################
# Every package should define these variables
$pkg_cmd_name = "crabz"
$pkg_dst_cmd = "$Env:USERPROFILE\.local\bin\crabz.exe"
$pkg_dst_bin = "$Env:USERPROFILE\.local\bin"
$pkg_dst = "$pkg_dst_cmd"
$pkg_src_cmd = "$Env:USERPROFILE\.local\opt\crabz-v$Env:WEBI_VERSION\bin\crabz.exe"
$pkg_src_bin = "$Env:USERPROFILE\.local\opt\crabz-v$Env:WEBI_VERSION\bin"
$pkg_src_dir = "$Env:USERPROFILE\.local\opt\crabz-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"
# Fetch archive
IF (!(Test-Path -Path "$pkg_download")) {
Write-Output "Downloading crabz 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 crabz"
# TODO: create package-specific temp directory
# Enter tmp
Push-Location .local\tmp
# Settle unpacked archive into place
Write-Output "Install Location: $pkg_src_cmd"
New-Item "$pkg_src_bin" -ItemType Directory -Force | Out-Null
Copy-Item -Path "$pkg_download" -Destination "$pkg_src_cmd"
# Exit tmp
Pop-Location
}
Write-Output "Copying into '$pkg_dst_cmd' from '$pkg_src_cmd'"
Remove-Item -Path "$pkg_dst_cmd" -Recurse -ErrorAction Ignore | Out-Null
New-Item "$pkg_dst_bin" -ItemType Directory -Force | Out-Null
Copy-Item -Path "$pkg_src" -Destination "$pkg_dst" -Recurse

49
crabz/install.sh Normal file
View File

@@ -0,0 +1,49 @@
#!/bin/sh
# The generic functions - version checks, download, extract, etc - are here:
# - https://github.com/webinstall/packages/branches/master/_webi/template.sh
set -e
set -u
pkg_cmd_name="crabz"
# IMPORTANT: this let's other functions know to expect this to be a single file
WEBI_SINGLE=true
# Every package should define these 6 variables
pkg_cmd_name="crabz"
pkg_dst_cmd="$HOME/.local/bin/crabz"
#pkg_dst="$pkg_dst_cmd"
pkg_src_cmd="$HOME/.local/opt/crabz-v$WEBI_VERSION/bin/crabz"
#pkg_src_dir="$HOME/.local/opt/crabz-v$WEBI_VERSION/bin"
#pkg_src="$pkg_src_cmd"
pkg_get_current_version() {
# 'crabz version' has output in this format:
# crabz git:xxxxxxx
# Since that's not sortable, this prints v0.0.0
# v0.0.0
echo "v0.0.0"
}
pkg_install() {
# $HOME/.local/opt/crabz-v0.3.5/bin
mkdir -p "${pkg_src_bin}"
# mv ./crabz* "$HOME/.local/opt/crabz-v0.3.5/bin/crabz"
mv ./"${pkg_cmd_name}"* "${pkg_src_cmd}"
# chmod a+x "$HOME/.local/opt/crabz-v0.3.5/bin/crabz"
chmod a+x "${pkg_src_cmd}"
}
pkg_link() {
# rm -f "$HOME/.local/bin/crabz"
rm -f "${pkg_dst_cmd}"
# ln -s "$HOME/.local/opt/crabz-v0.3.5/bin/crabz" "$HOME/.local/bin/crabz"
ln -s "${pkg_src_cmd}" "${pkg_dst_cmd}"
}

31
crabz/releases.js Normal file
View File

@@ -0,0 +1,31 @@
'use strict';
var github = require('../_common/github.js');
var owner = 'sstadick';
var repo = 'crabz';
module.exports = async function (request) {
let all = await github(request, owner, repo);
let releases = [];
for (let rel of all.releases) {
let isSrc = rel.download.includes('-src.');
if (isSrc) {
continue;
}
releases.push(rel);
}
all.releases = releases;
return all;
};
if (module === require.main) {
module.exports(require('@root/request')).then(function (all) {
all = require('../_webi/normalize.js')(all);
// just select the first 5 for demonstration
all.releases = all.releases.slice(0, 5);
console.info(JSON.stringify(all, null, 2));
});
}

47
feroxbuster/README.md Normal file
View File

@@ -0,0 +1,47 @@
---
title: feroxbuster
homepage: https://github.com/epi052/feroxbuster
tagline: |
feroxbuster: A tool designed to perform Forced Browsing.
---
To update or switch versions, run `webi feroxbuster@stable` (or `@v2`, `@beta`,
etc).
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/feroxbuster/ferox-config.toml
~/.local/bin/feroxbuster
```
## Cheat Sheet
> `feroxbuster` is a tool designed for Forced Browsing. Forced browsing is an
> attack where the aim is to enumerate and access resources that are not
> referenced by the web application but are still accessible by an attacker.
To run feroxbuster:
```sh
feroxbuster -u [target]
```
### Include Headers
To run feroxbuster with custom headers:
```sh
feroxbuster -u [target] -H Accept:application/json "Authorization: Bearer {token}"
```
### Proxy Traffic Through Burp
To proxy traffic through Burp:
```sh
feroxbuster -u [target] --insecure --proxy http://127.0.0.1:8080
```

55
feroxbuster/install.ps1 Normal file
View File

@@ -0,0 +1,55 @@
#!/usr/bin/env pwsh
#######################
# Install feroxbuster #
#######################
# Every package should define these variables
$pkg_cmd_name = "feroxbuster"
$pkg_dst_cmd = "$Env:USERPROFILE\.local\bin\feroxbuster.exe"
$pkg_dst = "$pkg_dst_cmd"
$pkg_src_cmd = "$Env:USERPROFILE\.local\opt\feroxbuster-v$Env:WEBI_VERSION\bin\feroxbuster.exe"
$pkg_src_bin = "$Env:USERPROFILE\.local\opt\feroxbuster-v$Env:WEBI_VERSION\bin"
$pkg_src_dir = "$Env:USERPROFILE\.local\opt\feroxbuster-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"
# Fetch archive
IF (!(Test-Path -Path "$pkg_download")) {
Write-Host "Downloading feroxbuster from $Env:WEBI_PKG_URL to $pkg_download"
& curl.exe -A "$Env:WEBI_UA" -fsSL "$Env:WEBI_PKG_URL" -o "$pkg_download.part"
& move "$pkg_download.part" "$pkg_download"
}
IF (!(Test-Path -Path "$pkg_src_cmd")) {
Write-Verbose "Installing feroxbuster"
# TODO: create package-specific temp directory
# Enter tmp
pushd .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\feroxbuster-v*" -Recurse -ErrorAction Ignore
Remove-Item -Path ".\feroxbuster.exe" -Recurse -ErrorAction Ignore
# Unpack archive file into this temporary directory
# Windows BSD-tar handles zip. Imagine that.
Write-Verbose "Unpacking $pkg_download"
& tar xf "$pkg_download"
# Settle unpacked archive into place
Write-Verbose "Install Location: $pkg_src_cmd"
New-Item "$pkg_src_bin" -ItemType Directory -Force | Out-Null
Move-Item -Path ".\feroxbuster-*\feroxbuster.exe" -Destination "$pkg_src_bin"
# Exit tmp
popd
}
Write-Host "Copying into '$pkg_dst_cmd' from '$pkg_src_cmd'"
Remove-Item -Path "$pkg_dst_cmd" -Recurse -ErrorAction Ignore | Out-Null
Copy-Item -Path "$pkg_src" -Destination "$pkg_dst" -Recurse

46
feroxbuster/install.sh Normal file
View File

@@ -0,0 +1,46 @@
#!/bin/sh
# shellcheck disable=SC2034
# "'pkg_cmd_name' appears unused. Verify it or export it."
__init_feroxbuster() {
set -e
set -u
##################
# Install feroxbuster #
##################
# Every package should define these 6 variables
pkg_cmd_name="feroxbuster"
pkg_dst_cmd="$HOME/.local/bin/feroxbuster"
pkg_dst="$pkg_dst_cmd"
pkg_src_cmd="$HOME/.local/opt/feroxbuster-v$WEBI_VERSION/bin/feroxbuster"
pkg_src_dir="$HOME/.local/opt/feroxbuster-v$WEBI_VERSION"
pkg_src="$pkg_src_cmd"
# pkg_install must be defined by every package
pkg_install() {
# ~/.local/opt/feroxbuster-v0.99.9/bin
mkdir -p "$(dirname "${pkg_src_cmd}")"
# mv ./feroxbuster-*/feroxbuster ~/.local/opt/feroxbuster-v0.99.9/bin/feroxbuster
mv ./feroxbuster "${pkg_src_cmd}"
}
# pkg_get_current_version is recommended, but not required
pkg_get_current_version() {
# 'feroxbuster --version' has output in this format:
# feroxbuster 0.99.9 (rev abcdef0123)
# This trims it down to just the version number:
# 0.99.9
feroxbuster --version 2> /dev/null |
head -n 1 |
cut -d ' ' -f 2
}
}
__init_feroxbuster

20
feroxbuster/releases.js Normal file
View File

@@ -0,0 +1,20 @@
'use strict';
var github = require('../_common/github.js');
var owner = 'epi052';
var repo = 'feroxbuster';
module.exports = function (request) {
return github(request, owner, repo).then(function (all) {
return all;
});
};
if (module === require.main) {
module.exports(require('@root/request')).then(function (all) {
all = require('../_webi/normalize.js')(all);
// just select the first 5 for demonstration
all.releases = all.releases.slice(0, 5);
console.info(JSON.stringify(all, null, 2));
});
}

View File

@@ -7,6 +7,17 @@ tagline: |
To update or switch versions, run `webi gh@stable` (or `@v1`, `@beta`, etc).
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/gh
~/.config/gh/
```
## Cheat Sheet
> `gh` is cross-platform Github command-line. You can perform pull requests

View File

@@ -6,7 +6,9 @@ __install_git_gpg_init() {
MY_CMD="git-config-gpg"
rm -f "$HOME/.local/bin/$MY_CMD"
webi_download "$WEBI_HOST/packages/$MY_CMD/$MY_CMD.sh" "$HOME/.local/bin/$MY_CMD"
webi_download \
"$WEBI_HOST/packages/$MY_CMD/$MY_CMD.sh" \
"$HOME/.local/bin/$MY_CMD"
chmod a+x "$HOME/.local/bin/$MY_CMD"
}

View File

@@ -16,6 +16,28 @@ To update or switch versions, run `webi git@stable` (or `@v2.30`, `@beta`, etc).
Github's [Git 'Hello World'](https://guides.github.com/activities/hello-world/)
is a good place to get started if you're new to git.
## Table of Contents
- Files
- Commit Files
- Ignore Files
- Create Branch
- Rebase by Default
- Rebase
- Auth via Token
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.gitconfig
~/.local/opt/git/ # Windows
/Library/Developer/CommandLineTools/ # macOS
```
### How to commit files
```sh
@@ -41,7 +63,7 @@ ignore
This will branch from the branch you're currently on.
```sh
git checkout -b my-branch-name
git switch -c my-branch-name
```
### How to rebase by default
@@ -66,11 +88,11 @@ Rebase a feature branch from master before a merge
```sh
# update master
git fetch
git checkout master
git switch master
git pull
# go back to your feature branch
git checkout my-feature
git switch my-feature
# start the rebase
git rebase master
@@ -97,14 +119,14 @@ git config --global url."https://git@github.com/".insteadOf "git@github.com:"
Next, create a `.git-askpass`:
```sh
echo 'echo $MY_GIT_TOKEN' > $HOME/.git-askpass
chmod +x $HOME/.git-askpass
echo 'echo "${MY_GIT_TOKEN}"' > ~/.git-askpass
chmod +x ~/.git-askpass
```
Finally, add the following ENVs to your deployment environment:
```sh
GIT_ASKPASS=$HOME/.git-askpass
GIT_ASKPASS="${HOME}/.git-askpass"
# Relpace xxxx... with your deploy token
MY_GIT_TOKEN=xxxxxxxxxxxxxxxx

View File

@@ -4,20 +4,21 @@ set -u
__init_git() {
if [ -z "$(command -v git)" ]; then
if [ "Darwin" = "$(uname -s)" ]; then
echo >&2 "Error: 'git' not found. You may have to re-install 'git' on Mac after every major update."
echo >&2 " for example, try: xcode-select --install"
# sudo xcodebuild -license accept
else
echo >&2 "Error: to install 'git' on Linux use the built-in package manager."
echo >&2 " for example, try: sudo apt install -y git"
fi
exit 1
else
if command -v git > /dev/null; then
echo "'git' already installed"
return 0
fi
if [ "Darwin" = "$(uname -s)" ]; then
echo >&2 "Error: 'git' not found. You may have to re-install 'git' on Mac after every major update."
echo >&2 " for example, try: xcode-select --install"
# sudo xcodebuild -license accept
else
echo >&2 "Error: to install 'git' on Linux use the built-in package manager."
echo >&2 " for example, try: sudo apt install -y git"
fi
exit 1
}
__init_git

View File

@@ -7,6 +7,20 @@ tagline: |
To update or switch versions, run `webi gitdeploy@stable`.
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/gitdeploy
~/.gitconfig
<PROJECT-DIR>/.env
<PROJECT-DIR>/.gitdeploy/
<PROJECT-DIR>/scripts/
```
## Cheat Sheet
> gitdeploy makes it easy to build and deploy static sites (or anything else)

View File

@@ -10,6 +10,16 @@ etc).
**Windows users**: You must [install git](/git) first.
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/opt/gitea/
```
## Cheat Sheet
> Gitea is a clean, lightweight self-hosted Github clone. It only uses a few

View File

@@ -17,6 +17,7 @@ To update or switch versions, run `webi goreleaser@stable` (or `@v0.174`,
There's a lot that you can do with GoReleaser. These are the things that we've
found the most useful for the majority of projects:
- Files
- Basic Usage & Versioning
- Publishing Builds to GitHub
- Publishing to Gitea and Gitlab
@@ -25,18 +26,32 @@ found the most useful for the majority of projects:
- Cross-Compiling with cgo
- Full `.goreleaser.yml` example
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.config/goreleaser/github_token
~/.local/bin/goreleaser
<PROJECT-DIR>/.goreleaser.yaml
```
## Basic Usage & Versioning
To create an example `.goreleaser.yaml` file, and test the configuration:
```sh
goreleaser init
goreleaser --snapshot --skip-publish --rm-dist
# dry run
goreleaser --snapshot --skip=publish --clean
```
- `--snapshot` allows "dirty" builds (when the repo has uncommitted changes)
- `--skip-publish` will NOT publish to GitHub, etc
- `--rm-dist` will automatically remove the `./dist/` directory
- `--skip=publish` will NOT publish to GitHub, etc
- `--clean` will automatically remove the `./dist/` directory
The default `.goreleaser.yml` works well for projects for which `package main`
is at the root.
@@ -49,14 +64,17 @@ package main
var (
// these will be replaced by goreleaser
version = "v0.0.0"
version = "0.0.0"
date = "0001-01-01T00:00:00Z"
commit = "0000000"
)
func main() {
if len(os.Args) >= 2 && "version" == strings.TrimPrefix(os.Args[1]) {
fmt.Printf("YOUR_CLI_NAME v%s %s (%s)\n", version, commit[:7], date)
if len(os.Args) >= 2 {
if os.Args[1] == "-V" || strings.TrimPrefix(os.Args[1]) == "version" {
fmt.Printf("CHANGE_ME v%s %s (%s)\n", version, commit[:7], date)
os.Exit(0)
}
}
// ...
@@ -96,10 +114,10 @@ git tag -a v1.0.0 -m "First release"
git push origin v1.0.0
```
Running GoReleaser without `--skip-publish` will publish the builds:
Running GoReleaser without `--skip=publish` will publish the builds:
```sh
goreleaser --rm-dist
goreleaser --clean
```
Check the console output to make sure that there are no messages about a failed
@@ -319,21 +337,19 @@ builds:
- linux
- windows
- darwin
- freebsd
- js
goarch:
- 386
- amd64
- arm
- arm64
- wasm
goarm:
- 6
- 7
archives:
- replacements:
darwin: Darwin
linux: Linux
windows: Windows
386: i386
amd64: x86_64
- id: my-binary
format: tar.xz
format_overrides:
- goos: windows
format: zip

View File

@@ -20,20 +20,40 @@ __init_goreleaser() {
# pkg_install must be defined by every package
pkg_install() {
# ~/.local/opt/goreleaser-v0.99.9/bin
# ~/.local/opt/goreleaser-v1.21.2/bin
mkdir -p "$(dirname "$pkg_src_cmd")"
# mv ./goreleaser-*/goreleaser ~/.local/opt/goreleaser-v0.99.9/bin/goreleaser
# mv ./goreleaser-*/goreleaser ~/.local/opt/goreleaser-v1.21.2/bin/goreleaser
mv ./goreleaser "$pkg_src_cmd"
}
# pkg_get_current_version is recommended, but (soon) not required
pkg_get_current_version() {
# 'goreleaser --version' has output in this format:
# goreleaser 0.99.9 (rev abcdef0123)
# ____ ____ _
# / ___| ___ | _ \ ___| | ___ __ _ ___ ___ _ __
# | | _ / _ \| |_) / _ \ |/ _ \/ _` / __|/ _ \ '__|
# | |_| | (_) | _ < __/ | __/ (_| \__ \ __/ |
# \____|\___/|_| \_\___|_|\___|\__,_|___/\___|_|
# goreleaser: Deliver Go Binaries as fast and easily as possible
# https://goreleaser.com
#
# GitVersion: 1.21.2
# GitCommit: 26fed97a0defe4e73e3094cb903225d5445e5f0d
# GitTreeState: false
# BuildDate: 2023-09-26T11:20:15Z
# BuiltBy: goreleaser
# GoVersion: go1.21.1
# Compiler: gc
# ModuleSum: h1:dgYtIS7aZlQuRMUMLCjDCOs4lWss85Oh60RDSO0rbWU=
# Platform: darwin/arm64
# This trims it down to just the version number:
# 0.99.9
goreleaser --version 2> /dev/null | head -n 1 | cut -d ' ' -f 2
# 1.21.2
# shellcheck disable=SC2046,SC2005 # unquoted echo trims whitespace
goreleaser --version 2> /dev/null |
grep 'GitVersion:' |
cut -d':' -f2 |
tr -d ' '
}
}

View File

@@ -6,7 +6,9 @@ __install_gpg_pubkey() {
MY_CMD="gpg-pubkey"
rm -f "$HOME/.local/bin/$MY_CMD"
webi_download "$WEBI_HOST/packages/$MY_CMD/$MY_CMD.sh" "$HOME/.local/bin/$MY_CMD"
webi_download \
"$WEBI_HOST/packages/$MY_CMD/$MY_CMD.sh" \
"$HOME/.local/bin/$MY_CMD"
chmod a+x "$HOME/.local/bin/$MY_CMD"
}
@@ -15,7 +17,9 @@ __install_gpg_pubkey_id() {
MY_SUBCMD="gpg-pubkey-id"
rm -f "$HOME/.local/bin/$MY_SUBCMD"
webi_download "$WEBI_HOST/packages/$MY_CMD/$MY_SUBCMD.sh" "$HOME/.local/bin/$MY_SUBCMD"
webi_download \
"$WEBI_HOST/packages/$MY_CMD/$MY_SUBCMD.sh" \
"$HOME/.local/bin/$MY_SUBCMD"
chmod a+x "$HOME/.local/bin/$MY_SUBCMD"
}

View File

@@ -12,7 +12,9 @@ _install_gpg() {
# Download the latest LTS
#curl -fsSL -o ~/Downloads/webi/GnuPG-2.2.32.dmg 'https://sourceforge.net/projects/gpgosx/files/GnuPG-2.2.32.dmg/download'
webi_download
webi_download \
"${WEBI_PKG_URL}" \
"${WEBI_PKG_PATH}/${WEBI_PKG_FILE}"
chmod a-w "${WEBI_PKG_DOWNLOAD}"
# Mount the DMG in /Volumes
@@ -34,7 +36,7 @@ _install_gpg() {
rm -rf ~/.local/opt/gnupg
ln -s gnupg-"${WEBI_VERSION}" ~/.local/opt/gnupg
pathman add ~/.local/opt/gnupg/bin
webi_path_add ~/.local/opt/gnupg/bin
export PATH="$HOME/.local/opt/gnupg/bin:$PATH"
export PATH="$HOME/.local/opt/gnupg/bin/pinentry-mac.app/Contents/MacOS:$PATH"

View File

@@ -9,6 +9,16 @@ tagline: |
`webi gprox`
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/gprox
```
## Cheat Sheet
`gprox` was built to be a no-dependency development tool for simply proxying

View File

@@ -8,6 +8,16 @@ tagline: |
To update or switch versions, run `webi hexyl@stable` (or `@v0.9`, `@beta`,
etc).
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/hexyl
```
## Cheat Sheet
![](https://camo.githubusercontent.com/1f71ee7031e1962b23f21c8cc89cb837e1201238/68747470733a2f2f692e696d6775722e636f6d2f4d574f3975534c2e706e67)

View File

@@ -16,7 +16,9 @@ _install_iterm2() {
exit 1
fi
webi_download
webi_download \
"${WEBI_PKG_URL}" \
"${WEBI_PKG_PATH}/${WEBI_PKG_FILE}"
webi_extract
if [ ! -d "${WEBI_TMP}/iTerm.app" ]; then

View File

@@ -7,6 +7,16 @@ tagline: |
To update or switch versions, run `webi jq@stable` (or `@v1.6`, `@beta`, etc).
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/jq
```
## Cheat Sheet
> `jq` is like `sed` for JSON data - you can use it to slice and filter and map

View File

@@ -7,6 +7,16 @@ tagline: |
To update or switch versions, run `webi keypairs@stable`.
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/keypairs
```
## Cheat Sheet
> keypairs is like JWT.io, at your fingertips.

View File

@@ -7,6 +7,17 @@ tagline: |
To update or switch versions, run `webi kind@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/kind
<PROJECT-DIR>/kind-config.yaml
```
## Cheat Sheet
> Kind uses a single docker container to run a lightweight kubernetes cluster

View File

@@ -8,6 +8,16 @@ tagline: |
To update or switch versions, run `webi kubectx@stable` (or `@v0.9`, `@beta`,
etc).
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/kubectx
```
## Cheat Sheet
> `kubectx` kubectx helps you switch between Kubernetes clusters back and forth

View File

@@ -8,6 +8,16 @@ tagline: |
To update or switch versions, run `webi kubens@stable` (or `@v0.9`, `@beta`,
etc).
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/kubens
```
## Cheat Sheet
> `kubens` kubens helps you switch between Kubernetes namespaces

View File

@@ -3,7 +3,9 @@ set -e
set -u
main() {
webi_download
webi_download \
"${WEBI_PKG_URL}" \
"${WEBI_PKG_PATH}/${WEBI_PKG_FILE}"
(
cd ~/Downloads/webi

View File

@@ -8,6 +8,17 @@ tagline: |
To update or switch versions, run `webi mutagen@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/mutagen
~/.mutagen.yml
```
## Cheat Sheet
> Mutagen is a new kind of remote development tool that enables your existing

View File

@@ -11,6 +11,16 @@ tagline: |
webi myip
```
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/myip
```
## Cheat Sheet
`myip` will contact ipify.org to tell you your IP addresses:

View File

@@ -5,7 +5,9 @@ set -u
__init_myip() {
rm -f "$HOME/.local/bin/myip"
webi_download "$WEBI_HOST/packages/myip/myip.sh" "$HOME/.local/bin/myip"
webi_download \
"$WEBI_HOST/packages/myip/myip.sh" \
"$HOME/.local/bin/myip"
chmod a+x "$HOME/.local/bin/myip"
"$HOME/.local/bin/myip"

View File

@@ -41,6 +41,35 @@ node -e 'console.log("Hello, World!")'
> Hello, World!
```
### How to Lint and Fmt Node Code
Just by installing these alone, most code editors (vim, VS Code, etc) can
automatically use them for JavaScript:
```sh
npm install --location=global fixjson@1 jshint@2 prettier@3
```
To run them manually on your code;
- prettier (fmt)
```sh
touch .prettierrc.json .prettierignore
prettier -w '**/*.{md,js,jsx,html}'
```
- jshintrc (lint)
```sh
touch .jshintrc .jshintignore
jhint -c ./.jshintrc *.js */*.js
```
- fixjson \
(turns JavaScript Objects with comments, trailing commas, etc into actual json)
```sh
fixjson -i 2 -w ./package.json
```
To run with **GitHub Actions on PRs** see "Fmt & Lint Automatically" below.
### A Simple Web Server
`server.js`:
@@ -114,3 +143,224 @@ http.createServer(app).listen(8080, function () {
```sh
npm start
```
### How to Reverse Proxy to Node
You can use [caddy](../caddy/):
`./Caddyfile`:
```Caddyfile
localhost {
# Reverse Proxy to your Node app's API
handle /api/* {
reverse_proxy localhost:3000
}
# Handle static files directly with Caddy
handle /* {
root * ./public/
file_server
}
}
```
```sh
caddy run --config ./Caddyfile
```
See the [Caddy Cheat Sheet](../caddy/) for more info, such as how to use
`X-SendFile` to .
### How to Allow Node to bind on 80 & 443
You can... but should you?
#### Are You Sure?
Typically you should use [`caddy`](../caddy/) as a _Reverse Proxy_ (see above).
#### Yes
On macOS all programs have permissions to use privileged ports by default.
On Linux there are several ways to add network _capabilities_ for privileged
ports:
1. Use `setcap-netbind`
```sh
webi setcap-netbind
setcap-netbind caddy
```
2. Use `setcap` directly
```sh
my_caddy_path="$( command -v caddy )"
my_caddy_absolute="$( readlink -f "${my_caddy_path}" )"
sudo setcap cap_net_bind_service=+ep "${my_caddy_absolute}"
```
3. Add the `--set-cap-net-bind` option to [`serviceman`](../serviceman/) (see
below)
4. Update the `systemd` config directly:
```sh
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
```
### How to run a Node app as a User Service
Also called "Login Item", "Startup Item" or "User Unit", this is how you run a
Node app as a Non-System (Unprivileged) Service on Mac, Windows, and Linux:
1. Install [`serviceman`](../serviceman/)
```sh
webi serviceman
```
2. Use Serviceman to create a _Launch Agent_ (macOS), _Startup Item_ (Windows),
or _User Unit_ (Linux):
```sh
my_username="$( id -u -n )"
serviceman add --user --name my-node-project -- \
caddy run --config ./Caddyfile --envfile ~/.config/caddy/env
```
3. Manage the service
- On macOS
```sh
# Manage (-w to disable/enable on login)
launchctl unload -w ~/Library/LaunchAgents/my-node-project.plist
launchctl load -w ~/Library/LaunchAgents/my-node-project.plist
# View Logs
tail -f ~/.local/share/my-node-project/var/log/my-node-project.log
```
- On Windows
```sh
# Manage
serviceman stop caddy
serviceman start caddy
# View Logs
type ~/.local/share/my-node-project/var/log/my-node-project.log | more
```
- On Linux
```sh
# Manage
systemctl --user disable my-node-project
systemctl --user stop my-node-project
systemctl --user enable my-node-project
systemctl --user start my-node-project
# View Logs
journalctl --user -xef -u my-node-project
```
### How to run a Node app as a System Service
```sh
pushd ./my-node-project/
my_username="$( id -u -n )"
sudo env PATH="$PATH" \
serviceman add --system --path "$PATH" --cap-net-bind \
--name my-node-project --username "${my_username}" -- \
npm run start
```
#### ... with auto-reload in Dev
```sh
pushd ./my-node-project/
sudo env PATH="$PATH" \
serviceman add --system --path "$PATH" --cap-net-bind \
--name my-node-project --username "$(id -u -n)" -- \
npx -p nodemon@3 -- nodemon ./server.js
```
#### View Logs & Restart
```sh
sudo journalctl -xef -u my-node-project
sudo systemctl restart my-node-project
```
### How to Fmt & Lint Automatically
Here are some useful scripts to have in your `package.json`, and a sample file
to run them with GitHub Actions (Workflows):
```sh
npm run
fmt
lint
bump <major|minor|patch|prerelease>
prepublish # also runs after npm install
```
```sh
# bump
npm pkg set scripts.bump='npm version -m "chore(release): bump to v%s"'
# fmt
npm pkg set scripts.fmt='npm run fixjson && npm run prettier'
npm pkg set scripts.prettier="npx -p prettier@2 -- prettier --write '**/*.{md,js,jsx,json,css,html,vue}'"
npm pkg set scripts.fixjson="npx -p fixjson@1 -- fixjson -i 2 -w '*.json' '*/*.json'"
echo 'node_modules' >> .prettierignore
# lint
npm pkg set scripts.lint='npm run jshint'
npm pkg set scripts.jshint="npx -p jshint@2 -- jshint -c ./.jshintrc ./*.js ./*/*.json"
echo 'node_modules' >> .jshintignore
# prepublish
npm pkg set scripts.prepublish='npm run lint && npm run fmt'
```
To run these automatically for all PRs on GitHub:
`.github/workflows/node.js.yml`:
```sh
name: Node.js CI
on:
push:
branches: ['main']
pull_request:
jobs:
build:
name: "Fmt, Lint, & Test"
runs-on: ubuntu-latest
strategy:
matrix:
node-version:
- 20.x
- latest
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: "Webi: Install 'shfmt' and 'shellcheck', and update PATH"
run: |
#sh ./_scripts/install-ci-deps
echo "${HOME}/.local/bin" >> $GITHUB_PATH
- run: node --version
- run: npm run fmt
- run: npm clean-install
- run: npm run lint
- run: npm run test
```

View File

@@ -1,23 +0,0 @@
@echo off
setlocal
pushd "%userprofile%" || goto :error
pushd "%userprofile%\.local\opt" || goto :error
powershell $ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest https://nodejs.org/dist/v12.16.2/node-v12.16.2-win-x64.zip -OutFile node-v12.16.2-win-x64.zip || goto :error
rem Windows BSD-tar handles zip. Imagine that.
tar xf node-v12.16.2-win-x64.zip || goto :error
dir
rename node-v12.16.2-win-x64 node-v12.16.2 || goto :error
rmdir node-v12.16.2-win-x64
del node-v12.16.2-win-x64.zip || goto :error
popd || goto :error
rem make npm not act stupid about which node to use... ugh (this should be the default)
.\.local\opt\node-v12.16.2\npm.cmd" --scripts-prepend-node-path=true config set scripts-prepend-node-path true || goto :error
pathman add .local\opt\node-v12.16.2 || goto :error
popd || goto :error
goto :EOF
:error
echo Failed with error #%errorlevel%.
exit /b %errorlevel%

View File

@@ -119,6 +119,7 @@ async function getAllReleases(request) {
let os = osMap[osPart];
let archPart = fileParts[1];
let arch = archMap[archPart];
let libc = '';
let pkgPart = fileParts[2];
let pkgs = pkgMap[pkgPart];
if (!pkgPart) {
@@ -133,13 +134,16 @@ async function getAllReleases(request) {
if (fileParts[2] === 'musl') {
extra = '-musl';
muslNative = true;
libc = 'musl';
} else if (os === 'linux') {
libc = 'gnu';
}
if (osPart === 'osx') {
osPart = 'darwin';
}
pkgs.forEach(function (pkg) {
if (osPart === 'osx') {
osPart = 'darwin';
}
let filename = `node-${build.version}-${osPart}-${archPart}${extra}.${pkg}`;
if ('msi' === pkg) {
filename = `node-${build.version}-${archPart}${extra}.${pkg}`;
@@ -156,7 +160,7 @@ async function getAllReleases(request) {
arch: arch,
ext: pkg,
download: downloadUrl,
_musl_native: muslNative,
libc: libc,
};
all.releases.push(release);

127
ollama/README.md Normal file
View File

@@ -0,0 +1,127 @@
---
title: ollama
homepage: https://github.com/jmorganca/ollama
tagline: |
ollama is a golang LLM server built for ease of use.
---
To update or switch versions, run `webi ollama@stable` (or `@v0.1.5`, etc).
## Cheat Sheet
> `ollama` is an LLM serving platform written in golang. It makes LLMs built on
> Llama standards easy to run with an API.
To get started quickly with the open source LLM Mistral-7b as an example is two
commands.
1. Open **TWO Terminals**
2. In the **first**, start the `ollama` server
```sh
OLLAMA_ORIGINS='*' OLLAMA_HOST=localhost:11434 ollama serve
```
3. In the **second**, run the `ollama` CLI (using the Mistral-7b model)
```sh
ollama pull mistral
ollama run mistral
```
![](https://user-images.githubusercontent.com/122831/278840139-eb3987b3-aeda-45ee-8cd2-06045c632386.png)
## Table of Contents
- Files
- ChatGPT-style Web UI
- System Notes
- Models to Try
- As a Network API
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/ollama
~/.ollama/models/
```
### How to Use a ChatGPT-style Web Interface
There are [many Ollama UIs][ollama-uis] to choose from, but `ollama-webui` is
easy to start with (and can be built as a static page):
![](https://user-images.githubusercontent.com/122831/278840488-684ffdb9-c527-4671-9072-8f5c5e823437.png)
[ollama-uis]:
https://github.com/jmorganca/ollama/issues/875#issuecomment-1778045758
1. Install [`node`](../node/)
```sh
webi node@lts
source ~/.config/envman/PATH.env
```
2. Clone and enter the `ollama-webui` repo
```sh
git clone https://github.com/ollama-webui/ollama-webui.git ./ollama-webui/
pushd ./ollama-webui/
```
3. Install and start the project
```sh
cp -RPp ./example.env ./.env
npm clean-install
npm run dev
```
4. Enjoy!
- <http://localhost:5173/>
Note: Be sure to run `ollama` with CORS enabled:
```sh
OLLAMA_ORIGINS='*' OLLAMA_HOST=localhost:11434 ollama serve
```
## System Notes
You'll need a fairly modern computer. An Apple M1 Air works great.
- 8GB+ RAM
- 4GB+ Storage
- Models range between 3GB and 30GB+ \
(they can take a while to download, and _several_ seconds to initialize)
### How to Downloads Other Models
See the list at <https://ollama.ai/library>.
For example, we could try `sqlcoder`, or `orca-mini` (because it's small):
```sh
ollama pull sqlcoder
ollama run sqlcoder
```
```sh
ollama pull orca-mini
ollama run orca-mini
```
### How to Use as an API on a Network
If you'd like `ollama` to be accessible beyond `localhost` (`127.0.0.1`):
- set the host to `0.0.0.0`, which makes it accessible to _ALL_ networks
- you may wish to **limit origins**
```sh
# fully open to all
OLLAMA_ORIGINS='*' OLLAMA_HOST=0.0.0.0:11435 ollama serve
# restrict browsers (not APIs) to requests from https://example.com
OLLAMA_ORIGINS='https://example.com' OLLAMA_HOST=0.0.0.0:11435 ollama serve
```
See also:
- API Docs: <https://github.com/jmorganca/ollama/blob/main/docs/api.md>

5
ollama/install.ps1 Normal file
View File

@@ -0,0 +1,5 @@
#!/usr/bin/env pwsh
Write-Host "Error: ollama doesn't have Windows support yet:"
Write-Host "See https://github.com/jmorganca/ollama/issues/403"
exit 1

22
ollama/install.sh Normal file
View File

@@ -0,0 +1,22 @@
#!/bin/sh
set -e
set -u
__init_ollama() {
##############
# Install ollama #
##############
WEBI_SINGLE=true
pkg_get_current_version() {
# 'ollama --version' has output in this format:
# ollama version 0.1.3
# This trims it down to just the version number:
# 0.1.3
ollama --version 2> /dev/null | head -n 1 | sed 's:^ollama version ::'
}
}
__init_ollama

31
ollama/releases.js Normal file
View File

@@ -0,0 +1,31 @@
'use strict';
var github = require('../_common/github.js');
var owner = 'jmorganca';
var repo = 'ollama';
module.exports = async function (request) {
let all = await github(request, owner, repo);
// TODO why are the 0.0.x releases sorting so high?
let releases = [];
for (let rel of all.releases) {
let isLow = rel.version.startsWith('v0.0.');
if (isLow) {
continue;
}
releases.push(rel);
}
all.releases = releases;
return all;
};
if (module === require.main) {
module.exports(require('@root/request')).then(function (all) {
all = require('../_webi/normalize.js')(all);
console.info(JSON.stringify(all));
//console.info(JSON.stringify(all, null, 2));
});
}

View File

@@ -8,6 +8,16 @@ tagline: |
To update or switch versions, run `webi pandoc@stable` (or `@v2.14`, `@beta`,
etc).
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/pandoc
```
## Cheat Sheet
> Pandoc is a Haskell library for converting from one markup format to another,

View File

@@ -5,26 +5,61 @@ tagline: |
Pathman: cross-platform PATH management for bash, zsh, fish, cmd.exe, and PowerShell.
---
## Updating `pathman`
```sh
webi pathman
```
To update or switch versions, run `webi pathman@stable` (or `@v0.5`, `@beta`,
etc).
## Cheat Sheet
Manages PATH on various OSes and shells
- Mac, Windows, Linux
- Bash, Zsh, Fish
- POSIX Shell, Bash, Zsh, Fish
- Command, Powershell
```sh
pathman add ~/bin/
```
<pre>
Saved changes to <code>~/.config/envman/PATH.env</code>
Copy, paste, and run the following command:
<strong><em><code>PATH="$HOME/bin:$PATH"</code></em></strong>
(newly opened terminal windows will have the updated PATH)
</pre>
**Windows Users**: use POSIX-style `/` (for paths) and `~` (for
`%USERPROFILE%`) - they'll be adjusted automatically.
## Table of Contents
- Files
- Add, Remove, List, etc
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/pathman
# 'source ~/.config/envman/PATH.env' will be added to
~/.profile
~/.bashrc
~/.zshrc
~/.config/fish/config.fish
```
### Usage
```sh
pathman help
```
### Usage
```sh
pathman add ~/.local/bin
```
@@ -33,9 +68,6 @@ pathman add ~/.local/bin
pathman remove ~/.local/bin
```
Note: Even on Windows it is best to use Unix-style `/` paths and `~` for
`%USERPROFILE%`.
```sh
pathman list
```

View File

@@ -8,6 +8,17 @@ tagline: |
To update or switch versions, run `webi postgres@stable` (or `@v10`, `@beta`,
etc).
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/opt/postgres/
~/.local/share/postgres/var/postgresql.conf
```
## Cheat Sheet
> Postgres is the all-in-one database for beginners and experts alike. It

View File

@@ -7,17 +7,6 @@ tagline: |
To update or switch versions, run `webi pwsh@stable` (or `@v7.4`, `@beta`, etc).
### 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
```
## Cheat Sheet
> The core benefit of running `pwsh` on Mac or Linux is that you get a way to
@@ -27,6 +16,25 @@ For example, if you want to create a `curl.exe -A "windows" | 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
- 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/
```
### How to Use PowerShell with Vim
Assuming you have [vim-ale](../vim-ale/) installed - which is included with
@@ -35,6 +43,10 @@ Assuming you have [vim-ale](../vim-ale/) installed - which is included with
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 ps1 Files
You must install `PSScriptAnalyzer`. Then you can use `Invoke-ScriptAnalyzer`

60
prettier/install.ps1 Normal file
View File

@@ -0,0 +1,60 @@
#!/usr/bin/env pwsh
####################
# Install prettier #
####################
function command-v-silent($cmdname) {
$my_cmd = Get-Command $command -ErrorAction SilentlyContinue
# $my_path = $my_cmd | Select-Object -ExpandProperty Definition
if ($my_cmd) {
return True
}
return False
}
function mktemp-d-t() {
# create random suffix for dirname
$my_bytes = New-Object byte[] 4
$my_rng = [Security.Cryptography.RNGCryptoServiceProvider]::Create()
$my_rng.GetBytes($bytes)
$my_hex_delimited = [BitConverter]::ToString($bytes)
$my_hex = $my_hex_delimited -replace "-", ""
# create random directory
$my_systmpdir = [System.IO.Path]::GetTempPath()
$my_tmpdir = Join-Path "$my_systmpdir" "$my_hex"
New-Item -ItemType Directory -Path "$my_tmpdir"
return "$my_tmpdir"
}
function npm-install-global($pkgname) {
# Fetch npm package manager
Write-Output "Checking for npm..."
if (-Not (command-v-silent("npm"))) {
& "$Env:USERPROFILE\.local\bin\webi-pwsh.ps1" node
}
if (command-v-silent($pkgname)) {
$my_cmd = Get-Command $pkgname
$my_cmd Select-Object -ExpandProperty Definition
Write-Host "Found '$my_cmd'"
return
}
$my_tmpdir = mktemp-d-t()
# npm install works best from a directory with no package.json
Push-Location "$my_tmpdir"
if (command-v-silent("npm")) {
& npm --location-golbal prettier
}
else {
& "$Env:USERPROFILE\.local\opt\node\npm" --location-golbal "$pkgname"
}
Pop-Location
}
npm-install-global prettier

View File

@@ -0,0 +1,25 @@
---
title: PSScriptAnalyzer
homepage: https://github.com/PowerShell/PSScriptAnalyzer
tagline: |
PSScriptAnalyzer is Formatter & Linter for PowerShell.
---
To update or switch versions, run `webi psscriptanalyzer`.
## Cheat Sheet
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.local/share/powershell/Modules/
```
## Check the Installed Version
```pwsh
Get-Module -ListAvailable
```

View File

@@ -0,0 +1,15 @@
#!/bin/sh
set -e
set -x
__install_psscriptanalyzer() {
echo "Checking for pwsh (PowerShell Core)..."
if ! command -v pwsh > /dev/null; then
"$HOME/.local/bin/webi" pwsh
export PATH="$HOME/.local/opt/pwsh:$PATH"
fi
pwsh -Command "Install-Module -Name PSScriptAnalyzer -Scope CurrentUser -AllowClobber"
}
__install_psscriptanalyzer

View File

@@ -7,9 +7,25 @@ tagline: |
To update run `pyenv update`.
### Files
These are the files / directories that are created and/or modified with this
install:
```sh
~/.config/envman/PATH.env
~/.pyenv/bin/
~/.pyenv/shims/
# pyenv also loads shell hooks via
~/.bashrc
~/.config/fish/config.fish
~/.zshrc
```
### How to Install pyenv on macOS
Make sure that you already have Xcode tools installed:
Install Xcode tools first:
```sh
xcode-select --install
@@ -25,7 +41,8 @@ sudo apt update
sudo apt install -y build-essential zlib1g-dev libssl-dev
# recommended
sudo apt install -y libreadline-dev libbz2-dev libsqlite3-dev libffi-dev
sudo apt install -y libreadline-dev libsqlite3-dev \
libffi-dev libbz2-dev liblzma-dev
```
## Cheat Sheet

View File

@@ -17,7 +17,7 @@ __init_pyenv() {
} >> ~/.bashrc
fi
if [ -n "$(command -v zsh)" ]; then
if command -v zsh > /dev/null; then
touch ~/.zshrc
if ! grep -q 'pyenv init' ~/.zshrc; then
{
@@ -31,7 +31,7 @@ __init_pyenv() {
fi
fi
if [ -n "$(command -v fish)" ]; then
if command -v fish > /dev/null; then
mkdir -p ~/.config/fish
touch ~/.config/fish/config.fish
if ! grep -q 'pyenv init' ~/.config/fish/config.fish; then
@@ -45,10 +45,10 @@ __init_pyenv() {
fi
mkdir -p ~/.pyenv/bin
pathman add ~/.pyenv/bin
webi_path_add ~/.pyenv/bin
mkdir -p ~/.pyenv/shims
pathman add ~/.pyenv/shims
webi_path_add ~/.pyenv/shims
echo "NOTE: You may also need to CLOSE and RE-OPEN your terminal for pyenv to take effect."
}

View File

@@ -7,16 +7,30 @@ tagline: |
To update or switch versions, run `pyenv install -v 3` (or `3.10`, etc).
### Files
These are the files / directories that are created and/or modified with this
install:
```sh
~/.config/envman/PATH.env
~/.pyenv/bin/
~/.pyenv/shims/
# pyenv also loads shell hooks via
~/.bashrc
~/.config/fish/config.fish
~/.zshrc
```
### How to Install python3 on macOS
Make sure that you already have Xcode tools installed:
Install Xcode tools first:
```sh
xcode-select --install
```
You may also need to install Xcode proper from the App Store.
### How to Install python3 on Linux
Make sure that you already have the necessary build tools installed:
@@ -27,18 +41,8 @@ sudo apt update
sudo apt install -y build-essential zlib1g-dev libssl-dev
# recommended
sudo apt install -y libreadline-dev libbz2-dev libsqlite3-dev
```
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.bashrc (or your shell's equivalent)
~/.config/envman/PATH.env
~/.pyenv
sudo apt install -y libreadline-dev libsqlite3-dev \
libffi-dev libbz2-dev liblzma-dev
```
## Cheat Sheet

View File

@@ -7,16 +7,30 @@ tagline: |
To update or switch versions, run `pyenv install -v 2` (or `2.6`, etc).
### Files
These are the files / directories that are created and/or modified with this
install:
```sh
~/.config/envman/PATH.env
~/.pyenv/bin/
~/.pyenv/shims/
# pyenv also loads shell hooks via
~/.bashrc
~/.config/fish/config.fish
~/.zshrc
```
### How to Install python2 on macOS
Make sure that you already have Xcode tools installed:
Install Xcode tools first:
```sh
xcode-select --install
```
You may also need to install Xcode proper from the App Store.
### How to Install python2 on Linux
Make sure that you already have the necessary build tools installed:
@@ -27,18 +41,8 @@ sudo apt update
sudo apt install -y build-essential zlib1g-dev libssl-dev
# recommended
sudo apt install -y libreadline-dev libbz2-dev libsqlite3-dev
```
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.bashrc (or your shell's equivalent)
~/.config/envman/PATH.env
~/.pyenv
sudo apt install -y libreadline-dev libsqlite3-dev \
libffi-dev libbz2-dev liblzma-dev
```
## Cheat Sheet

View File

@@ -8,4 +8,4 @@ description: |
See https://webinstall.dev/python
---
Alias for https://webinstall.dev/python
Alias for [python](../python/).

48
redis-commander/README.md Normal file
View File

@@ -0,0 +1,48 @@
---
title: Redis Commander
homepage: https://joeferner.github.io/redis-commander/
tagline: |
Redis-Commander is a node.js web application used to view, edit, and manage a Redis Database.
---
To update or switch versions, run `npm install -g redis-commander@latest`.
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/opt/node/bin/redis-commander
```
If [`node`](../node/) is not found, it will also be installed.
## Cheat Sheet
> Web-UI to display and edit data within multiple different Redis servers. It
> has support for the following data types to view, add, update and delete data:
- Strings
- Lists
- Sets
- Sorted Set
- Streams (Basic support based on HFXBus project from
<https://github.com/exocet-engineering/hfx-bus>, only view/add/delete data)
- ReJSON documents (Basic support, only for viewing values of ReJSON type keys)
List available commands:
```sh
redis-commander --help
```
Start redis commander with default settings:
```sh
redis-commander
```
This will open up web app at <http://127.0.0.1:8081> and will be connected to
local redis server at default port!

View File

@@ -0,0 +1,60 @@
#!/usr/bin/env pwsh
###########################
# Install redis-commander #
###########################
function command-v-silent($cmdname) {
$my_cmd = Get-Command $command -ErrorAction SilentlyContinue
# $my_path = $my_cmd | Select-Object -ExpandProperty Definition
if ($my_cmd) {
return True
}
return False
}
function mktemp-d-t() {
# create random suffix for dirname
$my_bytes = New-Object byte[] 4
$my_rng = [Security.Cryptography.RNGCryptoServiceProvider]::Create()
$my_rng.GetBytes($bytes)
$my_hex_delimited = [BitConverter]::ToString($bytes)
$my_hex = $my_hex_delimited -replace "-", ""
# create random directory
$my_systmpdir = [System.IO.Path]::GetTempPath()
$my_tmpdir = Join-Path "$my_systmpdir" "$my_hex"
New-Item -ItemType Directory -Path "$my_tmpdir"
return "$my_tmpdir"
}
function npm-install-global($pkgname) {
# Fetch npm package manager
Write-Output "Checking for npm..."
if (-Not (command-v-silent("npm"))) {
& "$Env:USERPROFILE\.local\bin\webi-pwsh.ps1" node
}
if (command-v-silent($pkgname)) {
$my_cmd = Get-Command $pkgname
$my_cmd Select-Object -ExpandProperty Definition
Write-Host "Found '$my_cmd'"
return
}
$my_tmpdir = mktemp-d-t()
# npm install works best from a directory with no package.json
Push-Location "$my_tmpdir"
if (command-v-silent("npm")) {
& npm --location-golbal redis-commander
}
else {
& "$Env:USERPROFILE\.local\opt\node\npm" --location-golbal "$pkgname"
}
Pop-Location
}
npm-install-global redis-commander

View File

@@ -0,0 +1,21 @@
#!/bin/sh
set -e
set -u
__init_redis_commander() {
if test -z "$(npm --version 2> /dev/null)"; then
~/.local/bin/webi node
export PATH="$HOME/.local/opt/node/bin:$PATH"
fi
# In recent versions of node (~v18+), npm:
# - requires '--location=global' rather than '-g'
# - will modify 'package.json' when it shouldn't
my_tmpdir="$(mktemp -d -t "webi-npm-tmp.XXXXXXXXXX")"
(
cd "${my_tmpdir}" || exit 1
npm install --location=global redis-commander@latest
)
}
__init_redis_commander

View File

@@ -13,6 +13,20 @@ rustup update
You can `rustup use x.y.z` for a specific version or toolchain.
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.cargo/
~/.rustup/
<PROJECT-DIR>/Cargo.toml
<PROJECT-DIR>/src/main.rs
<PROJECT-DIR>/src/lib.rs
```
## Cheat Sheet
> Rust is what C++ and D were trying to do, but didn't. It's a modern, safe,

View File

@@ -9,7 +9,7 @@ __install_rust() {
# Straight from https://rustup.rs/
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
pathman add "$HOME/.cargo/bin"
webi_path_add "$HOME/.cargo/bin"
}
__install_rust

View File

@@ -7,6 +7,17 @@ tagline: |
To update or switch versions, run `webi sass@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/sass
<PROJECT-DIR>/main.scss
```
## Cheat Sheet
> Dart Sass has replaced Ruby Sass as the canonical implementation of the Sass

View File

@@ -7,6 +7,16 @@ tagline: |
To update or switch versions, run `webi sclient@stable`.
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/sclient
```
## Cheat Sheet
> sclient unwraps encrypted connections (HTTPS/TLS/SSL) so that you can work
@@ -45,7 +55,7 @@ curl -H "Host: example.com" http://localhost:3000
SSH can be tunneled within HTTPS, TLS, SSL, WebSockets, etc.
```sh
ssh -o ProxyCommand="sclient %h" jon.telebit.io
ssh -o ProxyCommand="sclient --alpn ssh %h" jon.telebit.io
```
This is useful to be able to connect to SSH even from behind a corporate
@@ -65,7 +75,7 @@ telnet localhost 3000
### How to unwrap TLS for SMTP/SMTPS/STARTTLS
```sh
sclient smtp.gmail.com:465 localhost:2525
sclient --alpn smtp smtp.gmail.com:465 localhost:2525
```
```sh

View File

@@ -7,6 +7,16 @@ tagline: |
To update or switch versions, run `webi sd@stable` (or `@v0.7`, `@beta`, etc).
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/sd
```
## Cheat Sheet
> sd is a productive and faster replacement of sed and awk command used for

View File

@@ -2,33 +2,78 @@
title: Serviceman
homepage: https://git.rootprojects.org/root/serviceman
tagline: |
Serviceman: cross-platform service management for Linux, Mac, and Windows.
Serviceman generates and enables startup files on Linux, Mac, and Windows.
---
To update or switch versions, run `webi serviceman@stable`
To update or switch versions, run `webi serviceman@stable` (or `@v0.8`, `beta`,
etc).
## Cheat Sheet
> Serviceman is a hassle-free wrapper around your system launcher. It works with
> the default system launcher to make it easy to start _user_- and
> _system_-level services, such as webservers, backup scripts, network and
> system tools, etc.
> A **lightweight, cross-platform wrapper** to more easily \
> use your **native init system** to control system **service daemons** \
> and user **launch agents**. \
>
> Works for web servers, backup scripts, network and system tools, etc, in all
> languages.
Supports
- Launchd (macOS)
- Systemd (Linux)
- OpenRC (Alpine, Docker)
- Windows: Startup Registry
Works for _any program_, written in _any language_.
## Table of Contents
- Files
- User Agents & System Daemons
- Bash, Node, Go, etc
- Service Management
- Dry Run
- Unit File Examples
- systemd, launchd, openrc
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/serviceman
```
This will also generate init system unit files according to your OS:
(use the `--dryrun` option to learn what `serviceman` does without making any
changes)
- `launchctl` (macOS)
```sh
~/Library/LaunchAgents/<AGENT>.plist
/Library/LaunchDaemons/<DAEMON>.plist
```
- `systemctl` (Linux)
```sh
/etc/systemd/system/<DAEMON>.service
~/.config/systemd/user/<AGENT>.service
```
- `openrc` (Alpine, Docker)
```text
/etc/init.d/<DAEMON>
```
- The Registry (Windows)
Serviceman can run an app in just about any programming language very simply.
If you'd like to learn what `serviceman` does without actually making changes,
add the `--dryrun` option.
```text
HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run <AGENT>
```
### Example: Bash
```sh
sudo env PATH="$PATH" serviceman add bash ./backup.sh /mnt/data
sudo env PATH="$PATH" \
serviceman add --system --path="$PATH" -- \
bash ./backup.sh /mnt/data
```
### Example: Node.js
@@ -39,7 +84,8 @@ sudo env PATH="$PATH" serviceman add bash ./backup.sh /mnt/data
pushd ./my-node-app/
sudo env PATH="$PATH" \
serviceman add --system --cap-net-bind \
serviceman add --system --path="$PATH" \
--cap-net-bind -- \
npx nodemon ./server.js
```
@@ -49,7 +95,8 @@ sudo env PATH="$PATH" \
pushd ./my-node-app/
sudo env PATH="$PATH" \
serviceman add --system --cap-net-bind \
serviceman add --system --path="$PATH" \
--cap-net-bind -- \
npm start
```
@@ -59,7 +106,8 @@ sudo env PATH="$PATH" \
pushd ./my-go-package/
sudo env PATH="$PATH" \
serviceman add --system \
serviceman add --system --path="$PATH" \
-- \
go run -mod=vendor cmd/my-service/*.go --port 3000
```
@@ -68,7 +116,8 @@ pushd ./my-go-package/
go build -mod=vendor cmd/my-service
sudo env PATH="$PATH" \
serviceman add --cap-net-bind --system \
serviceman add --system --path="$PATH" \
--cap-net-bind -- \
./my-service --port 80
```
@@ -95,7 +144,33 @@ sudo env PATH="$PATH" serviceman stop example-service
sudo env PATH="$PATH" serviceman start example-service
```
## What a typical systemd .service file looks like
### See the (sub)command help
The main help, showing all subcommands:
```sh
serviceman --help
```
Sub-command specific help:
```sh
serviceman add --help
```
### Use `--dryrun` to see the generated launcher config:
```sh
sudo env PATH="$PATH" \
serviceman add --system --path="$PATH" \
--dryrun -- \
bash ./backup.sh /mnt/data
```
### What a typical systemd .service file looks like
`systemd` is the init system on cloud-init enabled server distros, and most
desktop distros.
```text
[Unit]
@@ -124,7 +199,63 @@ NoNewPrivileges=true
WantedBy=multi-user.target
```
## What a typical launchd .plist file looks like
### What a typical `init.d` service script looks like
`openrc` is the `init` system on Alpine and other Docker and
_container-friendly_ Linuxes.
`/etc/init.d/exampled`:
```sh
#!/sbin/openrc-run
supervisor=supervise-daemon
name="Example System Daemon"
description="A Service for Logging 'Hello, World', a lot!"
description_checkconfig="Check configuration"
description_reload="Reload configuration without downtime"
# example:
# exampled run --port 1337 --envfile /path/to/env
# exampled check-config --port 1337 --envfile /path/to/env
# exampled reload --port 1337 --envfile /path/to/env
# for setting Config
: ${exampled_opts:="--envfile /root/.config/exampled/env"}
command=/root/bin/exampled
command_args="run --port 1337 $exampled_opts"
command_user=root:root
extra_commands="checkconfig"
extra_started_commands="reload"
output_log=/var/log/exampled.log
error_log=/var/log/exampled.err
depend() {
need net localmount
after firewall
}
checkconfig() {
ebegin "Checking configuration for $name"
su ${command_user%:*} -s /bin/sh -c "$command check-config $exampled_opts"
eend $?
}
reload() {
ebegin "Reloading $name"
su ${command_user%:*} -s /bin/sh -c "$command reload $exampled_opts"
eend $?
}
stop_pre() {
if [ "$RC_CMD" = restart ]; then
checkconfig || return $?
fi
}
```
### What a typical launchd .plist file looks like
```text
<?xml version="1.0" encoding="UTF-8"?>
@@ -155,25 +286,3 @@ WantedBy=multi-user.target
</dict>
</plist>
```
### Use `--dryrun` to see the generated launcher config:
```sh
sudo env PATH="$PATH" \
serviceman add --system --dryrun \
bash ./backup.sh /mnt/data
```
### See the (sub)command help
The main help, showing all subcommands:
```sh
serviceman --help
```
Sub-command specific help:
```sh
serviceman add --help
```

View File

@@ -1,10 +1,20 @@
---
title: setcap-netbind
homepage: https://github.com/webinstall/webi-installers/setcap-netbind/
homepage: https://webinstall.dev/setcap-netbind/
tagline: |
setcap-netbind: Give a binary the ability to bind to privileged ports.
---
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/setcap-netbind
```
## Cheat Sheet
> Because no one can ever remember `setcap 'cap_net_bind_service=+ep'`.

View File

@@ -5,13 +5,13 @@ set -u
main() {
my_bin="${1}"
# ex: node
if [ -z "$(command -v "${my_bin}")" ]; then
if ! command -v "${my_bin}" > /dev/null; then
echo "setcap-netbind: '${my_bin}' not found"
exit 1
fi
my_sudo=""
if [ -n "$(command -v sudo)" ]; then
if command -v sudo > /dev/null; then
my_sudo=sudo
fi

View File

@@ -6,6 +6,17 @@ tagline: |
linux: true
---
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/ssh-adduser
~/.local/bin/sshd-prohibit-password
```
## Cheat Sheet
> Many modern web programs (`npm` and `postgres`, for example) will not function

View File

@@ -5,6 +5,17 @@ tagline: |
Add to your SSH Authorized Keys from a string, file, or url.
---
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/ssh-authorize
~/.ssh/authorized_keys
```
## Cheat Sheet
> Does the tedious work of making sure your `.ssh/authorized_keys` exists with

View File

@@ -5,6 +5,19 @@ tagline: |
Get your SSH public key.
---
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/ssh-pubkey
~/.ssh/id_rsa
~/.ssh/id_rsa.pub
~/Downloads/id_rsa.<USERNAME>.pub
```
## Cheat Sheet
> Your SSH Public Key is used for secure login from your laptop to servers and

View File

@@ -6,6 +6,17 @@ tagline: |
linux: true
---
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/ssh-setpass
~/.ssh/id_rsa
```
## Cheat Sheet
> `ssh-setpass` will ask you for your old passphrase and then for the new one to

View File

@@ -5,6 +5,20 @@ tagline: |
SSH Utils: Because --help takes too long.
---
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/sshd-prohibit-password
~/.local/bin/ssh-authorize
~/.local/bin/ssh-adduser
~/.local/bin/ssh-pubkey
~/.local/bin/ssh-setpass
```
## Cheat Sheet
> SSH Utils includes shortcut commands for common tasks.

View File

@@ -6,6 +6,17 @@ tagline: |
linux: true
---
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/sshd-prohibit-password
/etc/ssh/sshd_config
```
## Cheat Sheet
> Will check if your system This will check if your Modern SSH deployments are

View File

@@ -7,6 +7,16 @@ tagline: |
To update or switch versions, run `webi sttr@stable` (or `@v0.2.16` etc).
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/sttr
```
## Cheat Sheet
> `sttr` makes it easy to perform various operations on string.

View File

@@ -3,7 +3,7 @@
Write-Output "Installing sudo.cmd..."
# Couldn't figure out how to get this to work with "here strings", so forgive the ugly, but at least it works
Set-Content -Path .local\bin\sudo.cmd -Value "@echo off`r`npowershell -Command ""Start-Process cmd -Verb RunAs -ArgumentList '/c cd /d %CD% && %*'""`r`n@echo on"
Set-Content -Path "$Env:USERPROFILE\.local\bin\sudo.cmd" -Value "@echo off`r`npowershell -Command ""Start-Process cmd -Verb RunAs -ArgumentList '/c cd /d %CD% && %*'""`r`n@echo on"
Write-Output "Installed to '$Env:USERPROFILE\.local\bin\sudo.cmd'"
Write-Output ""

View File

@@ -4,14 +4,20 @@ set -u
__init_sudo() {
if [ -z "$(command -v sudo)" ]; then
echo >&2 "Error: on Linux and BSD you should install sudo via the native package manager"
echo >&2 " for example: apt install -y sudo"
exit 1
else
if command -v sudo > /dev/null; then
echo "'sudo' already installed"
exit 0
fi
echo >&2 "Error: on Linux & BSD use the native package manager to install sudo:"
echo >&2 " For Ubuntu / Debian:"
echo >&2 " apt install -y sudo"
echo >&2 ""
echo >&2 " For Alpine / Docker:"
echo >&2 " apk add sudo"
echo >&2 ""
exit 1
}
__init_sudo

View File

@@ -8,6 +8,17 @@ tagline: |
To update or switch versions, run `webi syncthing@stable` (or use `@beta` for
pre-releases).
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/bin/syncthing
~/.config/syncthing/
```
## Cheat Sheet
> Syncthing is like a self-hosted Dropbox or Google Drive. It keeps data safe,

94
tinygo/README.md Normal file
View File

@@ -0,0 +1,94 @@
---
title: TinyGo
homepage: https://tinygo.org
tagline: |
TinyGo: The Power of Go, in Kilobytes.
---
To update or switch versions, run `webi tinygo@stable` (or `@v0.30`, `@beta`,
etc).
## Cheat Sheet
> TinyGo is an alternate, llvm-based compiler for Go with a much smaller and
> simpler runtime with a minimum size of _kilobytes_ - suitable for
> micro-controllers, embedded devices, and good old fashioned CLI utilities that
> don't need a high-performance garbage collector.
```sh
GOOS=linux GOARCH=arm64 \
tinygo build -short -no-debug \
-o hello-v1.0.0-linux-arm64
```
You may also want to install the Go IDE tooling:
[go-essentials](/go-essentials).
## Table of Contents
- Files
- Effective TinyGo
- Compatibility
- Gotchas
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/envman/PATH.env
~/.local/opt/tinygo/
~/.local/opt/go/
~/go/
```
### Effective TinyGo
Core differences from Go's self-hosted compiler:
- optimizes for stack usage over heap usage
- avoids reflection
- simpler (but slower) garbage collection
- reimplements some of Go's standard library for performance
By following certain patterns, you can avoid forcing heap allocation and get
better memory usage and performance.
See:
- TinyGo: Heap Allocation:
<https://tinygo.org/docs/concepts/compiler-internals/heap-allocation/>.
- TinyGo: A New Compiler:
<https://tinygo.org/docs/concepts/faq/why-a-new-compiler/>
### Go Compatibility
Your _Go_, _TinyGo_, and dependency versions (particularly `golang.org/x`) will
need to be paired.
See the [Go Compatibility Matrix][go-compat]
[go-compat]: https://tinygo.org/docs/reference/go-compat-matrix/
### Gotchas
**Standard Library**
- avoid packages that rely heavily on reflection, like `encoding/json`
**Windows**:
- not all Windows syscalls are implemented
**macOS**:
- you may need to install a conflict-free version of `llvm` from
[conflict-free brew](../brew/) to get small sizes when cross-compiling
See also:
- TinyGo: Language Support: <https://tinygo.org/docs/reference/lang-support/>
- TinyGo: Gotchas: <https://tinygo.org/docs/guides/tips-n-tricks/>
- TinyGo: Differences from Go:
<https://tinygo.org/docs/concepts/compiler-internals/differences-from-go/>

67
tinygo/install.ps1 Normal file
View File

@@ -0,0 +1,67 @@
#!/usr/bin/env pwsh
#################
# Install tinygo #
#################
# Every package should define these variables
$pkg_cmd_name = "tinygo"
$pkg_dst_cmd = "$HOME\.local\opt\tinygo\bin\tinygo.exe"
$pkg_dst_dir = "$HOME\.local\opt\tinygo"
$pkg_dst = "$pkg_dst_dir"
$pkg_src_cmd = "$HOME\.local\opt\tinygo-v$Env:WEBI_VERSION\bin\tinygo.exe"
$pkg_src_bin = "$HOME\.local\opt\tinygo-v$Env:WEBI_VERSION\bin"
$pkg_src_dir = "$HOME\.local\opt\tinygo-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_PATHNAME"
# Fetch archive
IF (!(Test-Path -Path "$pkg_download")) {
Write-Output "Downloading tinygo 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"
}
# Fetch Go compiler
Write-Output "Checking for Go compiler..."
IF (-Not (Get-Command -Name "go" -ErrorAction Silent)) {
& "$Env:USERPROFILE\.local\bin\webi-pwsh.ps1" go
$Env:Path = "$HOME\.local\opt\go\bin;$Env:Path"
$Env:Path = "$HOME\go\bin;$Env:Path"
[System.Environment]::SetEnvironmentVariable(
"Path",
$env:Path,
[System.EnvironmentVariableTarget]::User)
}
IF (!(Test-Path -Path "$pkg_src")) {
Write-Output "Installing tinygo"
# TODO: create package-specific temp directory
# Enter tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\tinygo*" -Recurse -ErrorAction Ignore
# Unpack archive file into this temporary directory
# Windows BSD-tar handles zip. Imagine that.
Write-Output "Unpacking $pkg_download"
& tar xf "$pkg_download"
# Settle unpacked archive into place
Write-Output "Install Location: $pkg_src"
Move-Item -Path ".\tinygo*" -Destination "$pkg_src_dir"
# Exit tmp
Pop-Location
}
Write-Output "Copying into '$pkg_dst' from '$pkg_src'"
Remove-Item -Path "$pkg_dst" -Recurse -ErrorAction Ignore | Out-Null
# no New-Item because $HOME\.local\opt" always exists
Copy-Item -Path "$pkg_src" -Destination "$pkg_dst" -Recurse

53
tinygo/install.sh Normal file
View File

@@ -0,0 +1,53 @@
#!/bin/sh
# shellcheck disable=SC2034
# "'pkg_cmd_name' appears unused. Verify it or export it."
__init_tinygo() {
set -e
set -u
##################
# Install tinygo #
##################
# Every package should define these 6 variables
pkg_cmd_name="tinygo"
pkg_dst_cmd="$HOME/.local/opt/tinygo/bin/tinygo"
pkg_dst_dir="$HOME/.local/opt/tinygo"
pkg_dst="$pkg_dst_dir"
pkg_src_cmd="$HOME/.local/opt/tinygo-v$WEBI_VERSION/bin/tinygo"
pkg_src_dir="$HOME/.local/opt/tinygo-v$WEBI_VERSION"
pkg_src="$pkg_src_dir"
# pkg_install must be defined by every package
pkg_install() {
echo "Checking for Go compiler..."
if ! command -v go 2> /dev/null; then
"$HOME/.local/bin/webi" go
export PATH="$HOME/.local/opt/go/bin:$PATH"
fi
# ~/.local/opt/tinygo-v0.30.0/
mkdir -p "$(dirname "${pkg_src_dir}")"
# mv ./tinygo*/ ~/.local/opt/tinygo-v0.30.0/
mv ./tinygo*/ "${pkg_src_dir}"
}
# pkg_get_current_version is recommended, but not required
pkg_get_current_version() {
# 'tinygo --version' has output in this format:
# tinygo version 0.30.0 darwin/amd64 (using go version go1.21.1 and LLVM version 16.0.1)
# This trims it down to just the version number:
# 0.30.0
tinygo version 2> /dev/null |
head -n 1 |
cut -d' ' -f3
}
}
__init_tinygo

23
tinygo/releases.js Normal file
View File

@@ -0,0 +1,23 @@
'use strict';
var github = require('../_common/github.js');
var owner = 'tinygo-org';
var repo = 'tinygo';
module.exports = function (request) {
return github(request, owner, repo).then(function (all) {
// all.releases = all.releases.filter(function (rel) {
// return !rel.name.endsWith('.deb');
// });
return all;
});
};
if (module === require.main) {
module.exports(require('@root/request')).then(function (all) {
all = require('../_webi/normalize.js')(all);
// just select the first 5 for demonstration
all.releases = all.releases.slice(0, 5);
console.info(JSON.stringify(all, null, 2));
});
}

107
trip/README.md Normal file
View File

@@ -0,0 +1,107 @@
---
title: Trippy
homepage: https://github.com/fujiapple852/trippy
tagline: |
Trippy: A tool that combines the functionality of traceroute and ping designed for networking issue analysis.
---
To update or switch versions, run `webi trip@stable` (or `@v0.8`, `@beta`, etc).
## Cheat Sheet
> Trippy combines the functionality of `traceroute` and `ping` to assist in
> analyzing networking issues. It supports multiple protocols such as ICMP, UDP,
> and TCP, and is equipped with a Tui interface for detailed analysis.
```sh
sudo env PATH="$PATH" trip example.com
```
![](https://github.com/fujiapple852/trippy/blob/0.8.0/assets/0.8.0/hop_details.png?raw=true)
## Table of Contents
- Files
- Granting Root
- Tracing Protocols
- Tracing Options
- GoeIP Map
### Files
These are the files / directories that are created and/or modified with this
install:
```text
~/.config/trippy.toml
~/.local/bin/trip
<PROJECT-DIR>/.trippy.toml
# Windows
~/.local/bin/sudo.cmd
/Windows/System32/vcruntime140.dll (msvc runtime)
```
### How to Always Run as Root
Due to the nature of raw network access, `trip` always needs to run with
elevated network privileges.
On Linux `setcap` can be used to limit its root privileges to the network only.
On other systems it may need full root access.
**Linux**
```sh
trip_bin="$( readlink -f "$( command -v trip )" )"
sudo setcap 'CAP_NET_RAW+p' "${trip_bin}"
```
**macOS**
```sh
trip_bin="$( command -v trip )"
sudo chown root "${trip_bin}" && \
sudo chmod +s "${trip_bin}"
```
**Windows**
1. You need to add a firewall rule to allow ICMP
```pwsh
New-NetFirewallRule -DisplayName "ICMP Trippy Allow" -Name ICMP_TRIPPY_ALLOW -Protocol ICMPv4 -Action Allow
```
2. You'll need to run with an Administrator shell, or `sudo.cmd` **every time**:
```sh
sudo.cmd trip.exe example.com
```
### How to Trace with Various Protocols
You can use `icmp`, `tcp`, or `udp`:
```sh
trip --protocol icmp example.com
```
### How to set Tracing Options
You can pick a payload byte pattern (0-255) and packet size:
```sh
trip --packet-size 64 --payload-pattern 255
```
### How to View GeoIP Mapping
You'll need to download a geoip map database, such as this:
- <https://dev.maxmind.com/geoip/geolite2-free-geolocation-data>
```sh
trip example.com --geoip-mmdb-file ./GeoLite2-City.mmdb --tui-geoip-mode long
```
![](https://github.com/fujiapple852/trippy/raw/0.8.0/assets/0.8.0/world_map.png)

88
trip/install.ps1 Normal file
View File

@@ -0,0 +1,88 @@
#!/usr/bin/env pwsh
##################
# Install trippy #
##################
# Every package should define these variables
$pkg_cmd_name = "trip"
$pkg_dst_cmd = "$Env:USERPROFILE\.local\bin\trip.exe"
$pkg_dst_bin = "$Env:USERPROFILE\.local\bin"
$pkg_dst = "$pkg_dst_bin"
$pkg_src_cmd = "$Env:USERPROFILE\.local\opt\trippy-v$Env:WEBI_VERSION\bin\trip.exe"
$pkg_src_bin = "$Env:USERPROFILE\.local\opt\trippy-v$Env:WEBI_VERSION\bin"
$pkg_src_dir = "$Env:USERPROFILE\.local\opt\trippy-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"
# Fetch MSVC Runtime
Write-Output "Checking for MSVC Runtime..."
IF (-not (Test-Path "\Windows\System32\vcruntime140.dll")) {
& "$Env:USERPROFILE\.local\bin\webi-pwsh.ps1" vcruntime
}
# Fetch sudo Runtime
Write-Output "Checking for sudo.cmd..."
IF (-not (Test-Path "$Env:USERPROFILE\.local\bin\sudo.cmd")) {
Set-Content -Path "$Env:USERPROFILE\.local\bin\sudo.cmd" -Value "@echo off`r`npowershell -Command ""Start-Process cmd -Verb RunAs -ArgumentList '/c cd /d %CD% && %*'""`r`n@echo on"
}
# Fetch archive
IF (!(Test-Path -Path "$pkg_download")) {
Write-Output "Downloading trippy 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 trippy"
# TODO: create package-specific temp directory
# Enter tmp
Push-Location .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\trippy-v*" -Recurse -ErrorAction Ignore
Remove-Item -Path ".\trip.exe" -Recurse -ErrorAction Ignore
# NOTE: DELETE THIS COMMENT IF NOT USED
# Move single binary into root of temporary folder
#& move "$pkg_download" "trippy.exe"
# Unpack archive file into this temporary directory
# Windows BSD-tar handles zip. Imagine that.
Write-Output "Unpacking $pkg_download"
& tar xf "$pkg_download"
# Settle unpacked archive into place
Write-Output "Install Location: $pkg_src_cmd"
New-Item "$pkg_src_bin" -ItemType Directory -Force | Out-Null
Move-Item -Path ".\trippy-*\trip.exe" -Destination "$pkg_src_bin"
# Exit tmp
Pop-Location
}
Write-Output "Copying into '$pkg_dst_cmd' from '$pkg_src_cmd'"
Remove-Item -Path "$pkg_dst_cmd" -Recurse -ErrorAction Ignore | Out-Null
New-Item "$pkg_dst_bin" -ItemType Directory -Force | Out-Null
Copy-Item -Path "$pkg_src_cmd" -Destination "$pkg_dst_cmd" -Recurse
Write-Output "IMPORTANT"
Write-Output ""
Write-Output " 1. Open PowerShell as Administrator"
Write-Output ""
Write-Output " sudo.cmd powershell"
Write-Output ""
Write-Output " 2. As Administrator, set a firewall rule to allow ICMP"
Write-Output ""
Write-Output " New-NetFirewallRule -DisplayName ""ICMP Trippy Allow"" -Name ICMP_TRIPPY_ALLOW -Protocol ICMPv4 -Action Allow"
Write-Output ""
Write-Output " 3. Run with sudo.cmd (or an Administrator shell)"
Write-Output ""
Write-Output " sudo.cmd trip.exe example.com"
Write-Output ""

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