diff --git a/tools/depgraph.js b/tools/depgraph.js index 4126cf0..1a047d3 100644 --- a/tools/depgraph.js +++ b/tools/depgraph.js @@ -228,8 +228,9 @@ async function getDeployArtifact(langs) { dependencies: ["image:app"] .concat(langs.map((lang) => `image:lang-${lang}`)) .concat(langs.map((lang) => `test:lang-${lang}`)), - getLocalHash: async () => { - return null; + publishOnly: true, + publishToRegistry: async () => { + await runCommand(`tools/deploy.bash`); }, }; } @@ -273,6 +274,10 @@ async function getDepGraph() { return { informationalDependencies, artifacts }; } +async function executeDepGraph({ publish, yes, targets }) { + // +} + async function main() { const program = new Command(); program.usage("..."); @@ -293,7 +298,7 @@ async function main() { if (program.args.length === 0) { program.help({ error: true }); } - console.log("doing things now"); + await executeDepGraph({ publish, yes, targets: program.args }); } if (process.argv[1] === url.fileURLToPath(import.meta.url)) { diff --git a/tools/deploy.bash b/tools/deploy.bash index a72089d..effdb02 100755 --- a/tools/deploy.bash +++ b/tools/deploy.bash @@ -2,6 +2,13 @@ set -euo pipefail +if [[ -z "${DEPLOY_SSH_PRIVATE_KEY:-}" ]]; then + : ${DEPLOY_SSH_PUBLIC_KEY_FILE} + DEPLOY_SSH_PRIVATE_KEY="$(base64 < "${DEPLOY_SSH_PUBLIC_KEY_FILE%.pub}")" +fi + +: ${DOMAIN} + if (( $# != 1 )); then echo "usage: deploy.bash IMAGE" >&2 exit 1 @@ -30,4 +37,4 @@ chmod go-rwx "${tmpdir}/id" ssh -o IdentitiesOnly=yes \ -o StrictHostKeyChecking=no \ -o UserKnownHostsFile=/dev/null \ - -i "${tmpdir}/id" "deploy@${DOMAIN}" "${image}" + -i "${tmpdir}/id" "deploy@${DOMAIN}" diff --git a/tools/plan-publish.js b/tools/plan-publish.js index 635e46e..6ac8f68 100644 --- a/tools/plan-publish.js +++ b/tools/plan-publish.js @@ -17,192 +17,6 @@ import { import { hashDockerfile } from "./hash-dockerfile.js"; import { runCommand } from "./util.js"; -async function planDockerImage(name, dependentHashes, opts) { - const { deps, hashOpts } = opts || {}; - const DOCKER_REPO = getDockerRepo(); - const desired = await hashDockerfile(name, dependentHashes, hashOpts); - const local = await getLocalImageLabel(`riju:${name}`, "riju.image-hash"); - const remote = await getRemoteImageLabel( - `${DOCKER_REPO}:${name}`, - "riju.image-hash" - ); - dependentHashes[`riju:${name}`] = desired; - return { - id: getUUID(), - deps: deps || [], - artifact: "Docker image", - name, - desired, - local, - remote, - download: async () => { - if (name === "app") { - // Magic string parsed by publish.bash - console.log("[for publish script: plan-publish is tagging app image]"); - } - await runCommand(`make pull I=${name}`); - }, - build: async () => { - if (name === "app") { - // Magic string parsed by publish.bash - console.log("[for publish script: plan-publish is tagging app image]"); - } - await runCommand(`make image I=${name}`); - }, - upload: async () => { - if (name === "composite") { - await runCommand(`make shell I=composite CMD="make test"`); - } - await runCommand(`make push I=${name}`); - }, - }; -} - -async function planDebianPackages(opts) { - const { deps } = opts || {}; - const remoteHashes = Object.fromEntries( - JSON.parse( - ( - await runCommand( - `aws s3api list-objects-v2 --bucket riju-debs --prefix hashes`, - { getStdout: true } - ) - ).stdout - ).Contents.map(({ Key: key }) => { - const [_, remoteName, remoteHash] = key.split("/"); - return [remoteName, remoteHash]; - }) - ); - const packages = await getPackages(); - const uuids = Object.fromEntries( - packages.map(({ name }) => [name, getUUID()]) - ); - const langUUIDs = Object.fromEntries( - packages - .filter(({ type }) => type === "lang") - .map(({ lang, name }) => [lang, uuids[name]]) - ); - const sharedUUIDs = Object.fromEntries( - packages - .filter(({ type }) => type === "shared") - .map(({ lang }) => [lang, uuids[lang]]) - ); - const langConfigs = Object.fromEntries( - await Promise.all( - (await getLangs()).map(async (id) => [id, await readLangConfig(id)]) - ) - ); - const plan = await Promise.all( - packages.map(async ({ lang, type, name, buildScriptPath, debPath }) => { - const desired = crypto - .createHash("sha1") - .update(await fs.readFile(buildScriptPath, "utf-8")) - .digest("hex"); - let debExists = true; - try { - await fs.access(debPath); - } catch (err) { - debExists = false; - } - let local = null; - if (debExists) { - local = - ( - await runCommand(`dpkg-deb -f ${debPath} Riju-Script-Hash`, { - getStdout: true, - }) - ).stdout.trim() || null; - } - const remote = remoteHashes[name] || null; - let sharedDeps = []; - if (type === "lang") { - const cfg = langConfigs[lang]; - sharedDeps = ((cfg.install && cfg.install.riju) || []).map( - (id) => sharedUUIDs[id] - ); - } - return { - id: uuids[name], - deps: [ - ...(deps || []), - ...(type === "config" ? [langUUIDs[lang]] : []), - ...sharedDeps, - ], - artifact: "Debian package", - name, - desired, - local, - remote, - download: async () => { - await runCommand(`make download L=${lang} T=${type}`); - }, - build: async () => { - await runCommand( - `make shell I=packaging CMD="make pkg L=${lang} T=${type}"` - ); - }, - upload: async () => { - if (type === "config") { - const clauses = []; - for (const dep of (langConfigs[lang].install || {}).riju || []) { - clauses.push(`make install T=shared L=${dep}`); - } - clauses.push(`make installs L=${lang}`); - clauses.push("make test"); - await runCommand(`make shell I=base CMD="${clauses.join(" && ")}"`); - } - await runCommand(`make upload L=${lang} T=${type}`); - }, - type, - lang, - }; - }) - ); - const lazilyDownloadedLanguages = new Set(); - for (const { type, lang, desired, local, remote } of plan) { - if (type === "shared") { - continue; - } - // If *not* a shared package, and all we have to do is download - // it, then sort to the end. Unless of course this is the lang - // package, and we need to rebuild the config package, in which - // case the config package (which comes later) will remove that - // lang from the set again. - if (local !== desired && remote === desired) { - lazilyDownloadedLanguages.add(lang); - } else { - lazilyDownloadedLanguages.delete(lang); - } - } - return _.sortBy(plan, ({ type, lang }) => { - return type !== "shared" && lazilyDownloadedLanguages.has(lang); - }); -} - -async function computePlan() { - const dependentHashes = { - "ubuntu:rolling": await getLocalImageDigest("ubuntu:rolling"), - }; - const packaging = await planDockerImage("packaging", dependentHashes); - const base = await planDockerImage("base", dependentHashes); - const packages = await planDebianPackages({ - deps: [packaging.id, base.id], - }); - const composite = await planDockerImage("composite", dependentHashes, { - deps: [base.id, ...packages.map(({ id }) => id)], - hashOpts: { - salt: { - packageHashes: packages.map(({ desired }) => desired).sort(), - }, - }, - }); - const compile = await planDockerImage("compile", dependentHashes); - const app = await planDockerImage("app", dependentHashes, { - deps: [composite.id, compile.id], - }); - return [packaging, base, ...packages, composite, compile, app]; -} - function printTable(data, headers) { const widths = headers.map(({ key, title }) => Math.max(title.length, ...data.map((datum) => datum[key].length)) diff --git a/tools/publish.bash b/tools/publish.bash deleted file mode 100755 index a7eae52..0000000 --- a/tools/publish.bash +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -: ${DOCKER_REPO} -: ${DOMAIN} -: ${S3_BUCKET} - -if [[ -z "${DEPLOY_SSH_PRIVATE_KEY:-}" ]]; then - : ${DEPLOY_SSH_PUBLIC_KEY_FILE} - DEPLOY_SSH_PRIVATE_KEY="$(base64 < "${DEPLOY_SSH_PUBLIC_KEY_FILE%.pub}")" -fi - -tmpdir="$(mktemp -d)" - -function cleanup { - rm -rf "${tmpdir}" -} - -trap cleanup EXIT - -make pull-base all-scripts - -node tools/plan-publish.js --execute --publish --show-all --omit-unneeded-downloads \ - | tee "${tmpdir}/plan-publish.out" - -if ! grep -F "plan-publish is tagging app image" "${tmpdir}/plan-publish.out"; then - echo "publish.bash: no changes to app image, so not deploying" >&2 - exit 0 -fi - -sha="$(git describe --match=always-omit-tag --always --abbrev=40 --dirty)" - -image="${DOCKER_REPO}:app-${sha}" - -docker tag "${DOCKER_REPO}:app" "${image}" -docker push "${image}" - -exec tools/deploy.bash "${image}"