package main import ( "context" "fmt" "log" "os" "time" "dagger.io/dagger" "github.com/joho/godotenv" ) func Build(ctx context.Context) error { client, err := dagger.Connect(ctx, dagger.WithLogOutput(os.Stdout)) if err != nil { return err } // Load environment variables from .env file _ = godotenv.Load() rustImage := "docker.io/rustlang/rust:nightly" workdir := client.Host().Directory(".", dagger.HostDirectoryOpts{ Exclude: []string{"target/", ".git/", ".shuttle/", "shuttletask/"}, }) minioURL := "https://github.com/mozilla/sccache/releases/download/v0.3.3/sccache-v0.3.3-x86_64-unknown-linux-musl.tar.gz" sccacheDownloadCache := client.CacheVolume("sccache_download") cargoCache := client.CacheVolume("cargo_cache") rustBase := client.Container().From(rustImage). WithExec([]string{"apt-get", "update"}). WithExec([]string{"apt-get", "install", "--yes", "libpq-dev", "wget"}). WithExec([]string{"mkdir", "-p", "/src/downloads"}). WithWorkdir("/src/downloads"). WithMountedCache("/src/downloads", sccacheDownloadCache). WithExec([]string{"wget", minioURL}). WithExec([]string{"tar", "xzf", "sccache-v0.3.3-x86_64-unknown-linux-musl.tar.gz"}). WithExec([]string{"mv", "sccache-v0.3.3-x86_64-unknown-linux-musl/sccache", "/usr/local/bin/sccache"}). WithExec([]string{"chmod", "+x", "/usr/local/bin/sccache"}). WithEnvVariable("RUSTC_WRAPPER", "/usr/local/bin/sccache"). WithEnvVariable("AWS_ACCESS_KEY_ID", os.Getenv("AWS_ACCESS_KEY_ID")). WithEnvVariable("AWS_SECRET_ACCESS_KEY", os.Getenv("AWS_SECRET_ACCESS_KEY")). WithEnvVariable("SCCACHE_BUCKET", "sccache"). WithEnvVariable("SCCACHE_REGION", "auto"). WithEnvVariable("SCCACHE_ENDPOINT", "https://api-minio.front.kjuulh.io"). WithMountedCache("~/.cargo", cargoCache). WithExec([]string{"cargo", "install", "cargo-chef"}). WithWorkdir("/app") if exitCode, err := rustBase.ExitCode(ctx); err != nil || exitCode != 0 { return fmt.Errorf("could not build base") } targetCache := client.CacheVolume("target_cache") rustPrepare := rustBase.WithMountedDirectory(".", workdir). WithMountedCache("target", targetCache). WithExec([]string{"cargo", "chef", "prepare", "--recipe-path", "recipe.json"}) if exitCode, err := rustPrepare.ExitCode(ctx); err != nil || exitCode != 0 { return fmt.Errorf("could not build prepare") } targetRustCache := client.CacheVolume("target_rust_cache") rustCacher := rustBase. WithExec([]string{"apt", "update"}). WithExec([]string{"apt", "install", "pkg-config", "openssl", "libssl-dev", "-y"}). WithFile("/recipe.json", rustPrepare.File("./recipe.json")). WithMountedCache("target", targetRustCache). WithExec([]string{"cargo", "chef", "cook", "--release", "--recipe-path", "/recipe.json"}). WithMountedDirectory(".", workdir) if exitCode, err := rustCacher.ExitCode(ctx); err != nil || exitCode != 0 { return fmt.Errorf("could not build cacher") } rustBuilder := rustCacher.WithExec([]string{"cargo", "build", "--release"}) if exitCode, err := rustBuilder.ExitCode(ctx); err != nil || exitCode != 0 { return fmt.Errorf("could not build builder") } tag := time.Now().UTC().Unix() prodImage := "debian:bullseye" prod := client.Container().From(prodImage). WithExec([]string{"apt", "update"}). WithExec([]string{"apt", "install", "-y", "zlib1g", "git"}). WithWorkdir("/app"). WithFile("/app/releaser", rustBuilder.File("/app/target/release/releaser")). WithExec([]string{"/app/releaser", "--help"}). WithEntrypoint([]string{"/app/releaser"}) imageTag := fmt.Sprintf("docker.io/kasperhermansen/releaser:%v", tag) version, err := prod.Publish(ctx, imageTag) if err != nil { return err } log.Printf("published image: %s\n", version) return nil }