| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- using GLib;
- namespace Spry.Cli {
- /**
- * `spry docker` — generates the multi-stage `Dockerfile` (and
- * `.dockerignore`) for a spry application and optionally assembles the
- * build context and runs podman/docker.
- *
- * The Web-Stack trees carry fixes not present on their remotes, so the
- * image build COPYs every stack library from the local Web-Stack
- * checkout. The context layout the Dockerfile expects is invercargill/,
- * invercargill-json/, astralis/, invercargill-sql/,
- * invercargill-sql-inversion/, statum/, spry/ and the application as
- * app/; inversion, the one dependency outside Web-Stack, is cloned
- * inside the image pinned to a reviewed commit.
- */
- public class Docker : Object {
- /**
- * The Web-Stack projects COPYed into the build context, in the
- * dependency order the Dockerfile builds them.
- */
- private const string[] STACK_PROJECTS = {
- "Invercargill", "Invercargill-Json", "Astralis", "Invercargill-Sql",
- "Invercargill-Sql-Inversion", "Statum", "Spry"
- };
- /** Writes `Dockerfile` and `.dockerignore` into `app_dir`. */
- public static void generate(string app_dir, string app_name) throws Error {
- var vars = new HashTable<string, string>(str_hash, str_equal);
- vars.insert("APP_NAME", app_name);
- Generator.write_file(Path.build_filename(app_dir, "Dockerfile"),
- Generator.fill(Templates.DOCKERFILE, vars));
- Generator.write_file(Path.build_filename(app_dir, ".dockerignore"),
- Templates.DOCKERIGNORE);
- stdout.printf("Generated %s\n", Path.build_filename(app_dir, "Dockerfile"));
- stdout.printf("Generated %s\n", Path.build_filename(app_dir, ".dockerignore"));
- }
- /**
- * Assembles the build context under `app_dir/.docker-build/context`
- * (every Web-Stack project from `stack_dir`, the app itself as
- * app/) and builds the image with podman or docker, whichever is
- * found.
- */
- public static void build(string app_dir, string app_name, string image_tag, string stack_dir) throws Error {
- var staging = Path.build_filename(app_dir, ".docker-build");
- Generator.remove_tree(staging);
- var context = Path.build_filename(staging, "context");
- foreach (var project in STACK_PROJECTS) {
- Generator.copy_tree(find_stack_project(stack_dir, project),
- Path.build_filename(context, project.down()));
- }
- Generator.copy_tree(app_dir, Path.build_filename(context, "app"));
- Generator.write_file(Path.build_filename(context, ".dockerignore"),
- "*/builddir/\n*/.git/\n*.sqlite*\napp/.docker-build/\napp/web-config.json\n");
- var builder = Environment.find_program_in_path("podman")
- ?? Environment.find_program_in_path("docker");
- if (builder == null) {
- throw Generator.cli_error("neither podman nor docker found on PATH");
- }
- var dockerfile = Path.build_filename(context, "app", "Dockerfile");
- stdout.printf("Running: %s build -t %s -f %s %s\n", (!)builder, image_tag, dockerfile, context);
- var launcher = new SubprocessLauncher(SubprocessFlags.NONE);
- var process = launcher.spawnv({ (!)builder, "build", "-t", image_tag, "-f", dockerfile, context });
- process.wait_check();
- stdout.printf("Built %s\n", image_tag);
- }
- private static string find_stack_project(string stack_dir, string name) throws Error {
- foreach (var candidate in new string[] { name, name.down() }) {
- var path = Path.build_filename(stack_dir, candidate);
- if (FileUtils.test(path, FileTest.IS_DIR) && has_meson_manifest(path)) {
- return path;
- }
- }
- throw Generator.cli_error("%s not found in %s — pass --stack-dir <path-to-Web-Stack>", name, stack_dir);
- }
- /**
- * True when `path` carries a meson manifest, either at its root or
- * in `src/` (Invercargill and Invercargill-Json build from src/).
- */
- private static bool has_meson_manifest(string path) {
- return FileUtils.test(Path.build_filename(path, "meson.build"), FileTest.EXISTS)
- || FileUtils.test(Path.build_filename(path, "src", "meson.build"), FileTest.EXISTS);
- }
- }
- }
|