Skip to main content

Interacting with the client

dagger.#Plan has a client field that allows interaction with the local machine where the dagger command line client is run. You can:

  • Read and write files and directories;
  • Use local sockets;
  • Load environment variables;
  • Run commands;
  • Get current platform.

Accessing the file system

You may need to load a local directory as a dagger.#FS type in your plan:

dagger.#Plan & {
// Path may be absolute, or relative to current working directory
client: filesystem: ".": read: {
// CUE type defines expected content
contents: dagger.#FS
exclude: ["node_modules"]
}

actions: {
copy: docker.#Copy & {
contents: client.filesystem.".".read.contents
}
// ...
}
}

It’s also easy to write a file locally:

import (
"encoding/yaml"
// ...
)

dagger.#Plan & {
client: filesystem: "config.yaml": write: {
// Convert a CUE value into a YAML formatted string
contents: yaml.Marshal(actions.pull.output.config)
}
}

Using a local socket

You can use a local socket in an action:

Environment variables

Environment variables can be read from the local machine as strings or secrets, just specify the type:

package main

import (
"dagger.io/dagger"
"universe.dagger.io/docker"
)

dagger.#Plan & {
client: env: {
// load as a string
REGISTRY_USER: string
// load as a secret
REGISTRY_TOKEN: dagger.#Secret
}

actions: pull: docker.#Pull & {
source: "registry.example.com/image"
auth: {
username: client.env.REGISTRY_USER
secret: client.env.REGISTRY_TOKEN
}
}
}

You can provide a default value for strings, or mark any environment variable as optional so they don't fail if not defined in the host:

package main

import (
"dagger.io/dagger"
"universe.dagger.io/docker"
)

dagger.#Plan & {
client: env: {
// load as a string, using a default if not defined
REGISTRY_USER: string | *"_token_"
// load as a secret, but don't fail if not defined
REGISTRY_TOKEN?: dagger.#Secret
}

actions: pull: docker.#Pull & {
source: "registry.example.com/image"
if client.env.REGISTRY_TOKEN != _|_ {
auth: {
username: client.env.REGISTRY_USER
secret: client.env.REGISTRY_TOKEN
}
}
}
}

Running commands

Sometimes you need something more advanced that only a local command can give you:

dagger.#Plan & {
client: commands: {
os: {
name: "uname"
args: ["-s"]
}
arch: {
name: "uname"
args: ["-m"]
}
}

actions: build: go.#Build & {
os: client.commands.os.stdout
arch: client.commands.arch.stdout
// ...
}
}
tip

You can also capture stderr for errors and provide stdin for input.

Platform

If you need the current platform though, there’s a more portable way than running uname like in the previous example:

dagger.#Plan & {
client: _

actions: build: go.#Build & {
os: client.platform.os
arch: client.platform.arch
// ...
}
}