Improve sandbox env, add shared dep support
This commit is contained in:
parent
5752918068
commit
670fabe177
5
Makefile
5
Makefile
|
@ -60,7 +60,7 @@ pkg-clean:
|
|||
|
||||
pkg-build:
|
||||
@: $${L} $${T}
|
||||
cd $(BUILD)/src && pkg="$(PWD)/$(BUILD)/pkg" $(or $(CMD),../build.bash)
|
||||
cd $(BUILD)/src && pkg="$(PWD)/$(BUILD)/pkg" src="$(PWD)/$(BUILD)/src" $(or $(CMD),../build.bash)
|
||||
|
||||
pkg-debug:
|
||||
@: $${L} $${T}
|
||||
|
@ -148,7 +148,8 @@ test:
|
|||
node backend/test-runner.js $(F)
|
||||
|
||||
sandbox:
|
||||
node backend/sandbox.js
|
||||
@: $${L}
|
||||
L=$(L) node backend/sandbox.js
|
||||
|
||||
### Fetch artifacts from registries
|
||||
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
# This script is sourced by Bash within 'make sandbox'.
|
||||
|
||||
if [[ -z "$L" ]]; then
|
||||
echo 'environment variable unset: $L' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cfg="$(< "/opt/riju/langs/$L.json")" || exit 1
|
||||
|
||||
function get {
|
||||
jq -r ".$1" <<< "${cfg}"
|
||||
}
|
||||
|
||||
function has {
|
||||
get "$@" | grep -vq '^null$'
|
||||
}
|
||||
|
||||
function daemon {
|
||||
has daemon && eval "$(get daemon)"
|
||||
}
|
||||
|
||||
function setup {
|
||||
has setup && eval "$(get setup)"
|
||||
}
|
||||
|
||||
function repl {
|
||||
has repl && eval "$(get repl)"
|
||||
}
|
||||
|
||||
function main {
|
||||
: > "$(get main)"
|
||||
has prefix && get prefix >> "$(get main)"
|
||||
get template >> "$(get main)"
|
||||
has suffix && get suffix >> "$(get main)"
|
||||
}
|
||||
|
||||
function compile {
|
||||
has compile && echo "$(get compile)" && eval "$(get compile)"
|
||||
}
|
||||
|
||||
function run-only {
|
||||
has run && echo "$(get run)" && eval "$(get run)"
|
||||
}
|
||||
|
||||
function run {
|
||||
compile && run-only
|
||||
}
|
||||
|
||||
function format {
|
||||
has format && echo "$(get format.run)" && eval "( $(get format.run) ) < $(get main)"
|
||||
}
|
||||
|
||||
function lsp {
|
||||
has lsp.setup && echo "$(get lsp.setup)" && eval "$(get lsp.setup)"
|
||||
has lsp && echo "$(get lsp.start)" && eval "$(get lsp.start)"
|
||||
}
|
||||
|
||||
if [[ -z "$NS" ]]; then
|
||||
main
|
||||
setup
|
||||
fi
|
|
@ -1,6 +1,8 @@
|
|||
import { spawn } from "child_process";
|
||||
import { promises as fs } from "fs";
|
||||
import process from "process";
|
||||
|
||||
import { quote } from "shell-quote";
|
||||
import { v4 as getUUID } from "uuid";
|
||||
|
||||
import { borrowUser } from "./users.js";
|
||||
|
@ -21,10 +23,19 @@ function log(msg) {
|
|||
}
|
||||
|
||||
async function main() {
|
||||
const sandboxScript = await fs.readFile("backend/sandbox.bash", "utf-8");
|
||||
const lang = process.env.L;
|
||||
if (!lang) {
|
||||
die("environment variable unset: $L");
|
||||
}
|
||||
const uuid = getUUID();
|
||||
const { uid, returnUser } = await borrowUser(log);
|
||||
await run(privilegedSetup({ uid, uuid }), log);
|
||||
const args = privilegedSpawn({ uid, uuid }, ["bash"]);
|
||||
const args = privilegedSpawn({ uid, uuid }, [
|
||||
"bash",
|
||||
"-c",
|
||||
`exec env L='${lang}' bash --rcfile <(cat <<< ${quote([sandboxScript])})`,
|
||||
]);
|
||||
const proc = spawn(args[0], args.slice(1), {
|
||||
stdio: "inherit",
|
||||
});
|
||||
|
|
|
@ -37,10 +37,19 @@ async function getCreatedUsers() {
|
|||
}
|
||||
|
||||
async function getActiveUsers() {
|
||||
let dirents;
|
||||
try {
|
||||
dirents = await fs.readdir("/tmp/riju");
|
||||
} catch (err) {
|
||||
if (err.code === "ENOENT") {
|
||||
return new Set();
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
return new Set(
|
||||
(
|
||||
await Promise.all(
|
||||
(await fs.readdir("/tmp/riju"))
|
||||
dirents
|
||||
.filter((name) => name.match(uuidRegexp))
|
||||
.map((name) => fs.stat(`/tmp/riju/${name}`))
|
||||
)
|
||||
|
|
|
@ -34,6 +34,7 @@ ripgrep
|
|||
sudo
|
||||
tmux
|
||||
unzip
|
||||
vim
|
||||
wget
|
||||
yarn
|
||||
|
||||
|
|
|
@ -20,6 +20,14 @@ export async function getLangs() {
|
|||
.map((lang) => path.parse(lang).name);
|
||||
}
|
||||
|
||||
// Return a list of the IDs of all the configured shared dependencies.
|
||||
// Each such ID can be passed to readSharedDepConfig.
|
||||
export async function getSharedDeps() {
|
||||
return (await fs.readdir("shared"))
|
||||
.filter((lang) => lang.endsWith(".yaml"))
|
||||
.map((lang) => path.parse(lang).name);
|
||||
}
|
||||
|
||||
// Return a list of objects representing the packages to be built. See
|
||||
// the function implementation for the full list of keys.
|
||||
export async function getPackages() {
|
||||
|
@ -36,6 +44,17 @@ export async function getPackages() {
|
|||
});
|
||||
}
|
||||
}
|
||||
for (const dep of await getSharedDeps()) {
|
||||
const type = "shared";
|
||||
const name = `riju-${type}-${lang}`;
|
||||
packages.push({
|
||||
lang,
|
||||
type,
|
||||
name,
|
||||
buildScriptPath: `build/${type}/${lang}/build.bash`,
|
||||
debPath: `build/${type}/${lang}/${name}.deb`,
|
||||
});
|
||||
}
|
||||
return packages;
|
||||
}
|
||||
|
||||
|
@ -71,3 +90,17 @@ export async function readLangConfig(lang) {
|
|||
}
|
||||
return fixupLangConfig(langConfig);
|
||||
}
|
||||
|
||||
// Read the YAML config file for the shared dependency with the given
|
||||
// string ID and return it as an object.
|
||||
export async function readSharedDepConfig(lang) {
|
||||
const langConfig = YAML.parse(
|
||||
await fs.readFile(`shared/${lang}.yaml`, "utf-8")
|
||||
);
|
||||
if (langConfig.id !== lang) {
|
||||
throw new Error(
|
||||
`shared dependency config id ${langConfig.id} doesn't match expected ${lang}`
|
||||
);
|
||||
}
|
||||
return fixupLangConfig(langConfig);
|
||||
}
|
||||
|
|
|
@ -3,18 +3,22 @@ import process from "process";
|
|||
import { Command } from "commander";
|
||||
import YAML from "yaml";
|
||||
|
||||
import { readLangConfig } from "./config.js";
|
||||
import { readLangConfig, readSharedDepConfig } from "./config.js";
|
||||
|
||||
// Given a language config object, return the text of a Bash script
|
||||
// that will build the (unpacked) riju-lang-foo Debian package into
|
||||
// ${pkg} when run in an appropriate environment. This is a package
|
||||
// that will install the language interpreter/compiler and associated
|
||||
// tools.
|
||||
function makeLangScript(langConfig) {
|
||||
//
|
||||
// isShared (optional) truthy means to generate a shared dependency
|
||||
// package riju-shared-foo rather than a language installation
|
||||
// package.
|
||||
function makeLangScript(langConfig, isShared) {
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
install: { prepare, apt, pip, manual, deb },
|
||||
install: { prepare, apt, riju, pip, manual, deb },
|
||||
} = langConfig;
|
||||
let parts = [];
|
||||
parts.push(`\
|
||||
|
@ -45,6 +49,9 @@ sudo apt-get install -y ${apt.join(" ")}`);
|
|||
if (apt) {
|
||||
depends = depends.concat(apt);
|
||||
}
|
||||
if (riju) {
|
||||
depends = depends.concat(riju.map((name) => `riju-shared-${name}`));
|
||||
}
|
||||
if (deb) {
|
||||
depends = depends.concat(
|
||||
deb.map((fname) => `\$(dpkg-deb -f "${fname}" Depends)`)
|
||||
|
@ -52,11 +59,13 @@ sudo apt-get install -y ${apt.join(" ")}`);
|
|||
}
|
||||
parts.push(`depends=(${depends.map((dep) => `"${dep}"`).join(" ")})`);
|
||||
let debianControlData = `\
|
||||
Package: riju-lang-${id}
|
||||
Package: riju-${isShared ? "shared" : "lang"}-${id}
|
||||
Version: \$(date +%s%3N)
|
||||
Architecture: amd64
|
||||
Maintainer: Radon Rosborough <radon.neon@gmail.com>
|
||||
Description: The ${name} language packaged for Riju
|
||||
Description: The ${name} ${
|
||||
isShared ? "shared dependency" : "language"
|
||||
} packaged for Riju
|
||||
Depends: \$(IFS=,; echo "\${depends[*]}")
|
||||
Riju-Script-Hash: \$(sha1sum "\$0" | awk '{ print \$1 }')`;
|
||||
parts.push(`\
|
||||
|
@ -107,7 +116,7 @@ EOF`);
|
|||
// that installs tools used by multiple languages, and can be declared
|
||||
// as a dependency.
|
||||
function makeSharedScript(langConfig) {
|
||||
throw new Error("shared script generation not implemented yet");
|
||||
return makeLangScript(langConfig, true);
|
||||
}
|
||||
|
||||
// Parse command-line arguments, run main functionality, and exit.
|
||||
|
@ -129,7 +138,13 @@ async function main() {
|
|||
console.error(`make-script.js: unsupported --type ${program.type}`);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(scriptMaker(await readLangConfig(program.lang)));
|
||||
console.log(
|
||||
scriptMaker(
|
||||
program.type === "shared"
|
||||
? await readSharedDepConfig(program.lang)
|
||||
: await readLangConfig(program.lang)
|
||||
)
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue