#Returning multiple folders to host

1 messages · Page 1 of 1 (latest)

teal remnant
#

I'm looking to automate my build process using dagger. My build outputs multiple folders such as ./artifacts ./results etc. I'd like to ensure that all of them are returned to the host. I've tried Directory.export but it seems to have no effect. Can anyone explain to me how this should be done, preferably using the typescript SDK?

signal oxide
teal remnant
#

is there an example documented somewhere?

#

I've tried with the Directory approach, however it didn't seem to work for me - I'm probably missunderstanding something fundamentally

signal oxide
teal remnant
#

sure, this is my latest attempt

import { dag, Container, Directory, object, func } from "@dagger.io/dagger"

@object()
export class NukeBuildOutput {
  artifacts: Directory
  results: Directory

  constructor(artifacts: Directory, results: Directory) {
    this.artifacts = artifacts;
    this.results = results;
  }

  // ✅ Add a function to export both directories
  @func()
  async export(hostPath: string): Promise<string> {
    // Export 'artifacts' to a subdirectory named 'artifacts' inside the hostPath
    await this.artifacts.export(`${hostPath}/artifacts`);

    // Export 'results' to a subdirectory named 'results' inside the hostPath
    await this.results.export(`${hostPath}/results`);

    // Return a message indicating success (or void, Dagger usually handles the success check)
    return `Successfully exported artifacts and results to ${hostPath}`;
  }
}

@object()
export class DaggerBuild {

  @func()
  async nukeBuild(
      directory: Directory,
      target: string = "All",
      image: string = "mcr.microsoft.com/dotnet/sdk:10.0"): Promise<NukeBuildOutput> {
    const container = dag
      .container()
      .from(image)
      .withMountedDirectory("/app", directory)
      .withWorkdir("/app")
 
      .withExec(["dotnet", "tool", "restore"])
      .withExec(["dotnet", "tool", "run", "nuke", "--target", target])
      ;

    const results: Directory = container.directory("./results");
    const artifacts: Directory = container.directory("./artifacts");

    await results.entries();
    await artifacts.entries();

    return new NukeBuildOutput(artifacts, results);
  }
}

I'm invoking this using: dagger call nuke-build --directory=. export --host-path=./output , however nothing is being created on my MacOS host

signal oxide
#

just to confirm, your goal is to create/update these directories in the caller's local directory right?

#

Do you also want to consume the build output programmatically? So 2 different uses right?

teal remnant
#

The answer to the 1st question is a definite "yes"
As to the 2nd question, I'm not yet sure how I can use it, but I suppose it wouldn't hurt - for learning's sake

signal oxide
#

@teal remnant I would start simple eg.

import {
  dag,
  object,
  func,
  argument,
  Directory,
  Container,
  Changeset,
} from "@dagger.io/dagger"

@object()
export class Nuke {
  @func()
  async build(
    @argument({ defaultPath: "." }) source: Directory,
    base?: Container,
    target: string = "All",
  ): Promise<Changeset> {

    const container = (base ?? dag
      .container()
      .from("mcr.microsoft.com/dotnet/sdk:10.0"))
      .withDirectory("/app", source)
      .withWorkdir("/app")
      .withExec(["dotnet", "tool", "restore"])
      .withExec(["dotnet", "tool", "run", "nuke", "--target", target])

    return container.directory("/app").changes(source)
  }
}

to call: dagger call build

teal remnant
#

Ok, this is interesting and seems like a step in the right direction. The returned changeset contains all the files that I'd have expected to be created, however:

  • I'm being prompted to toggle/submit/apply/discard (I've tried submitting and applying, I'm getting: cannot diff with different relative paths: "/" != "/app" - not yet sure what the problem is)
    • Can the prompt be skipped/auto-accepted? I'm pretty sure this behavior would hang my CI
  • You've added a Container argument to the build() function, I'm assuming this enables some sort of chaining behavior? How does this work?
signal oxide
teal remnant
#

still trying to wrap my head around the cannot diff with different relative paths: "/" != "/app" error. What is the dagger engine tryign to tell me?

signal oxide
#

@teal remnant this fixes it:

import {
  dag,
  object,
  func,
  argument,
  Directory,
  Container,
  Changeset,
} from "@dagger.io/dagger"

@object()
export class Nuke {
  @func()
  async build(
    @argument({ defaultPath: "." }) source: Directory,
    base?: Container,
    target: string = "All",
  ): Promise<Changeset> {

    const container = (base ?? dag.container().from("mcr.microsoft.com/dotnet/sdk:10.0").withWorkdir("/app"))
      .withDirectory(".", source)
    const before = container.directory(".")
    const after = container
      .withExec(["dotnet", "tool", "restore"])
      .withExec(["dotnet", "tool", "run", "nuke", "--target", target])
      .directory(".")
    return after.changes(before)
  }
}
teal remnant
#

this worked!~~ I'm still being prompted to accept the list of changes though. Can I auto-accept it somehow?~~ (found it, --auto-apply)
Also, it would appear that your usage of both Directory instances (before and after) is more like snapshots rather than filesystem references? Is my understanding correct?

main bay
teal remnant
main bay
#

i.e:

const ctr = dag.container().from("alpine")
const before = ctr.directory(".") // here `before` is a reference to the working-directory (".") of the snapshot `ctr`
const ctrAfterExec =  ctr.withExec(["sh", "-c", "echo hello > hello.txt"])
const after = ctrAfterExec.directory(".") // here `after` is refernece to the working-directory (".") of the snapshot `ctrAfterExec`
let changeSet = before.changes(after) // changesets between `before` and `after`
#

LMK if that makes sense

teal remnant
#

it totally does, I'm going through the docs trying to find where is this behavior documented