Finish up initial depgraph, remove dead code
This commit is contained in:
parent
1b975de021
commit
00c3a4117a
|
@ -228,8 +228,9 @@ async function getDeployArtifact(langs) {
|
||||||
dependencies: ["image:app"]
|
dependencies: ["image:app"]
|
||||||
.concat(langs.map((lang) => `image:lang-${lang}`))
|
.concat(langs.map((lang) => `image:lang-${lang}`))
|
||||||
.concat(langs.map((lang) => `test:lang-${lang}`)),
|
.concat(langs.map((lang) => `test:lang-${lang}`)),
|
||||||
getLocalHash: async () => {
|
publishOnly: true,
|
||||||
return null;
|
publishToRegistry: async () => {
|
||||||
|
await runCommand(`tools/deploy.bash`);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -273,6 +274,10 @@ async function getDepGraph() {
|
||||||
return { informationalDependencies, artifacts };
|
return { informationalDependencies, artifacts };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function executeDepGraph({ publish, yes, targets }) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const program = new Command();
|
const program = new Command();
|
||||||
program.usage("<target>...");
|
program.usage("<target>...");
|
||||||
|
@ -293,7 +298,7 @@ async function main() {
|
||||||
if (program.args.length === 0) {
|
if (program.args.length === 0) {
|
||||||
program.help({ error: true });
|
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)) {
|
if (process.argv[1] === url.fileURLToPath(import.meta.url)) {
|
||||||
|
|
|
@ -2,6 +2,13 @@
|
||||||
|
|
||||||
set -euo pipefail
|
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
|
if (( $# != 1 )); then
|
||||||
echo "usage: deploy.bash IMAGE" >&2
|
echo "usage: deploy.bash IMAGE" >&2
|
||||||
exit 1
|
exit 1
|
||||||
|
@ -30,4 +37,4 @@ chmod go-rwx "${tmpdir}/id"
|
||||||
ssh -o IdentitiesOnly=yes \
|
ssh -o IdentitiesOnly=yes \
|
||||||
-o StrictHostKeyChecking=no \
|
-o StrictHostKeyChecking=no \
|
||||||
-o UserKnownHostsFile=/dev/null \
|
-o UserKnownHostsFile=/dev/null \
|
||||||
-i "${tmpdir}/id" "deploy@${DOMAIN}" "${image}"
|
-i "${tmpdir}/id" "deploy@${DOMAIN}"
|
||||||
|
|
|
@ -17,192 +17,6 @@ import {
|
||||||
import { hashDockerfile } from "./hash-dockerfile.js";
|
import { hashDockerfile } from "./hash-dockerfile.js";
|
||||||
import { runCommand } from "./util.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) {
|
function printTable(data, headers) {
|
||||||
const widths = headers.map(({ key, title }) =>
|
const widths = headers.map(({ key, title }) =>
|
||||||
Math.max(title.length, ...data.map((datum) => datum[key].length))
|
Math.max(title.length, ...data.map((datum) => datum[key].length))
|
||||||
|
|
|
@ -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}"
|
|
Loading…
Reference in New Issue