diff --git a/.dockerignore b/.dockerignore index 20d6bb3..ce09fd5 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,4 +4,5 @@ **/.terraform **/debs **/node_modules +**/pkg **/work diff --git a/.gitignore b/.gitignore index c6900f9..1b2e42d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ *.log .env .terraform -debs +build node_modules -work diff --git a/Makefile b/Makefile index 98c21e2..3b5dfcd 100644 --- a/Makefile +++ b/Makefile @@ -32,17 +32,23 @@ app-image: .PHONY: pkg pkg: @: $${L} - node src/packager/main.js --lang $(L) + mkdir -p build/$(L) + node src/packager/make-script $(L) > build/$(L)/build.bash + chmod +x build/$(L)/build.bash + rm -rf build/$(L)/src build/$(L)/pkg + mkdir -p build/$(L)/src build/$(L)/pkg + cd build/$(L)/src && pkg="$(PWD)/build/$(L)/pkg" ../build.bash + fakeroot dpkg-deb --build build/$(L)/pkg build/$(L)/$(L).deb ### Run things inside Docker .PHONY: packaging-shell packaging-shell: - docker run -it --rm -v $(PWD):/src riju:packaging + docker run -it --rm -v $(PWD):/src riju-packaging .PHONY: runtime-shell runtime-shell: - docker run -it --rm -v $(PWD):/src riju:runtime + docker run -it --rm -v $(PWD):/src riju-runtime ### Fetch things from registries @@ -64,8 +70,8 @@ fetch-app-image: .PHONY: fetch-pkg fetch-pkg: @: $${L} - mkdir -p debs - aws s3 cp s3://$(S3_BUCKET_BASE)-debs/debs/$(L).deb debs/$(L).deb + mkdir -p build/$(L) + aws s3 cp s3://$(S3_BUCKET_BASE)-debs/debs/$(L).deb build/$(L)/$(L).deb ### Publish things to registries @@ -87,7 +93,7 @@ publish-app-image: .PHONY: publish-pkg publish-pkg: @: $${L} - aws s3 cp debs/$(L).deb s3://$(S3_BUCKET_BASE)-debs/debs/$(L).deb + aws s3 cp build/$(L)/$(L).deb s3://$(S3_BUCKET_BASE)-debs/debs/$(L).deb ### Miscellaneous diff --git a/docker/packaging/install.bash b/docker/packaging/install.bash index 6e2407b..b8ba126 100755 --- a/docker/packaging/install.bash +++ b/docker/packaging/install.bash @@ -23,8 +23,12 @@ deb https://dl.yarnpkg.com/debian/ stable main EOF apt-get update -apt-get install -y fakeroot less make man nodejs yarn +apt-get install -y fakeroot less make man nodejs sudo yarn rm -rf /var/lib/apt/lists/* +tee /etc/sudoers.d/90-riju >/dev/null <<"EOF" +%sudo ALL=(ALL:ALL) NOPASSWD: ALL +EOF + rm "$0" diff --git a/docker/packaging/pid1.bash b/docker/packaging/pid1.bash index 66337bf..0689f59 100755 --- a/docker/packaging/pid1.bash +++ b/docker/packaging/pid1.bash @@ -3,6 +3,8 @@ set -euo pipefail groupadd -g "$(stat -c %g "$PWD")" -o -p '!' -r riju -useradd -u "$(stat -c %u "$PWD")" -g "$(stat -c %g "$PWD")" -o -m -N -l -s /usr/bin/bash riju +useradd -u "$(stat -c %u "$PWD")" -g "$(stat -c %g "$PWD")" -o -m -N -l -s /usr/bin/bash -G sudo riju -exec runuser -u riju -g riju "$@" +runuser -u riju touch /home/riju/.sudo_as_admin_successful + +exec runuser -u riju "$@" diff --git a/langs/python.yaml b/langs/python.yaml index 608d390..0be4bc9 100644 --- a/langs/python.yaml +++ b/langs/python.yaml @@ -10,16 +10,15 @@ install: apt: - python3 - python3-pip - pip: - black manual: - | - xml="$(curl -sSL "https://pvsc.blob.core.windows.net/python-language-server-stable?restype=container&comp=list&prefix=Python-Language-Server-linux-x64")" - url="$(echo "${xml}" | grep -Eo 'https://[^<]+\.nupkg' | tail -n1)" - wget "${url}" + install -d "${pkg}/opt/mspyls" + install -d "${pkg}/usr/local/bin" + wget "$(curl -sSL "https://pvsc.blob.core.windows.net/python-language-server-stable?restype=container&comp=list&prefix=Python-Language-Server-linux-x64" | grep -Eo 'https://[^<]+\.nupkg' | tail -n1)" unzip -d "${pkg}/opt/mspyls" Python-Language-Server-linux-x64.*.nupkg chmod +x "${pkg}/opt/mspyls/Microsoft.Python.LanguageServer" - ln -s "${pkg}/opt/mspyls/Microsoft.Python.LanguageServer" /usr/local/bin/Microsoft.Python.LanguageServer + ln -s "${pkg}/opt/mspyls/Microsoft.Python.LanguageServer" "${pkg}/usr/local/bin/Microsoft.Python.LanguageServer" repl: >- python3 -u diff --git a/package.json b/package.json index 7b0e167..f83d9a0 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.0.0", "license": "MIT", "private": true, + "type": "module", "dependencies": { "yaml": "^1.10.0" } diff --git a/src/config.js b/src/config.js new file mode 100644 index 0000000..bfecf20 --- /dev/null +++ b/src/config.js @@ -0,0 +1,27 @@ +import _fs from "fs"; +const fs = _fs.promises; + +import YAML from "yaml"; + +// The build scripts in the language configs assume a specific build +// environment, with these parameters: +// +// * the working directory starts out empty +// * the ${pkg} environment variable has been set to an absolute path +// to the directory where the package should be built; this +// directory also starts out empty +// * we are using bash with 'set -euxo pipefail' + +// Read the YAML config file for the language with the given string ID +// and return it as an object. +export async function readLangConfig(lang) { + const langConfig = YAML.parse( + await fs.readFile(`langs/${lang}.yaml`, "utf-8") + ); + if (langConfig.id !== lang) { + throw new Error( + `lang config id ${langConfig.id} doesn't match expected ${lang}` + ); + } + return langConfig; +} diff --git a/src/packager/build.js b/src/packager/build.js index 522ae89..c13f333 100644 --- a/src/packager/build.js +++ b/src/packager/build.js @@ -13,20 +13,6 @@ const YAML = require("yaml"); // to the directory where the package should be built // * we are using bash with 'set -euo pipefail' -// Read the YAML config file for the language with the given string ID -// and return it as an object. -async function readLangConfig(lang) { - const langConfig = YAML.parse( - await fs.readFile(`langs/${lang}.yaml`, "utf-8") - ); - if (langConfig.id !== lang) { - throw new Error( - `lang config id ${langConfig.id} doesn't match expected ${lang}` - ); - } - return langConfig; -} - // Used to log all progress messages. Not sure what this should do // quite yet. function log(message) { diff --git a/src/packager/make-script.js b/src/packager/make-script.js new file mode 100644 index 0000000..38dc328 --- /dev/null +++ b/src/packager/make-script.js @@ -0,0 +1,55 @@ +import process from "process"; + +import { readLangConfig } from "../config.js"; + +// Given a language config object, return the text of a Bash script +// that will build the (unpacked) Debian package into ${pkg} when run in an +// appropriate environment. +function makeScript(langConfig) { + const { + id, + name, + install: { apt, pip, manual }, + } = langConfig; + const timestamp = new Date().getTime(); + let parts = []; + parts.push(`\ +#!/usr/bin/env bash + +set -euxo pipefail`); + let debianControlData = `\ +Package: riju-lang-${id} +Version: ${timestamp} +Architecture: amd64 +Maintainer: Radon Rosborough +Description: The ${name} language packaged for Riju`; + if (apt.length > 0) { + debianControlData += `\ +Depends: ${apt.join(", ")}`; + } + parts.push(`\ +install -d "\${pkg}/DEBIAN" +cat <<"EOF" > "\${pkg}/DEBIAN/control" +${debianControlData} +EOF`); + for (const part of manual || []) { + parts.push(part.trim()); + } + return parts.join("\n\n"); +} + +async function main() { + const args = process.argv.slice(2); + if (args.length !== 1) { + console.error("usage: script-maker.js LANG"); + process.exit(1); + } + const [lang] = args; + console.log(makeScript(await readLangConfig(lang))); + process.exit(0); +} + +main().catch((err) => { + console.error(err); + process.exit(1); +});