Work with the Host Filesystem
Introduction
This guide explains how to work with the host filesystem using the Dagger SDKs. You will learn how to:
- Set the working directory on the host
- List host directory entries with include/exclude filters
- Mount a host directory in a container
- Export a directory from a container to the host
Requirements
This guide assumes that:
- You have a Go, Python or Node.js development environment. If not, install Go, Python or Node.js.
- You have a Dagger SDK installed for one of the above languages. If not, follow the installation instructions for the Dagger Go, Python or Node.js SDK.
- You have Docker installed and running on the host system. If not, install Docker.
List directory contents
The easiest way to set the working directory for the Dagger CI pipeline is at the time of client instantiation, as a client configuration option. By default, Dagger uses the current directory on the host as the working directory.
The following example shows how to list the contents of the working directory:
- Go
- Node.js
- Python
package main
import (
"context"
"fmt"
"log"
"os"
"dagger.io/dagger"
)
func main() {
ctx := context.Background()
client, err := dagger.Connect(ctx, dagger.WithLogOutput(os.Stderr))
if err != nil {
log.Println(err)
return
}
defer client.Close()
entries, err := client.Host().Directory(".").Entries(ctx)
if err != nil {
log.Println(err)
return
}
fmt.Println(entries)
}
The Host
type provides information about the host's execution environment. Its Directory()
method accepts a path and returns a reference to the corresponding host directory as a Directory
struct. Entries in the directory can be obtained via the Directory.Entries()
function.
import Client, { connect } from "@dagger.io/dagger"
connect(async (client: Client) => {
const entries = await client.host().directory(".").entries()
console.log(entries)
}, {LogOutput: process.stderr})
The host
type provides information about the host's execution environment. Its directory()
method accepts a path and returns a reference to the corresponding host directory as a Directory
object. Entries in the directory can be obtained via the directory.entries()
function.
import sys
import anyio
import dagger
async def main():
async with dagger.Connection(dagger.Config(log_output=sys.stderr)) as client:
entries = await client.host().directory(".").entries()
print(entries)
anyio.run(main)
The host
type provides information about the host's execution environment. Its directory()
method accepts a path and returns a reference to the corresponding host directory as a Directory
object. Entries in the directory can be obtained via the directory.entries()
function.
When the Dagger pipeline code is in a sub-directory, it may be more useful to set the parent directory (the project's root directory) as the working directory. The following example revises the previous one, setting the parent directory as the working directory and listing its contents:
- Go
- Node.js
- Python
package main
import (
"context"
"fmt"
"log"
"os"
"dagger.io/dagger"
)
func main() {
ctx := context.Background()
client, err := dagger.Connect(ctx, dagger.WithLogOutput(os.Stderr), dagger.WithWorkdir(".."))
if err != nil {
log.Println(err)
return
}
defer client.Close()
entries, err := client.Host().Directory(".").Entries(ctx)
if err != nil {
log.Println(err)
return
}
fmt.Println(entries)
}
import Client, { connect } from "@dagger.io/dagger"
connect(async (client: Client) => {
const entries = await client.host().directory(".").entries()
console.log(entries)
}, {LogOutput: process.stderr, Workdir: ".."})
import sys
import anyio
import dagger
async def main():
async with dagger.Connection(dagger.Config(log_output=sys.stderr, workdir="..")) as client:
entries = await client.host().directory(".").entries()
print(entries)
anyio.run(main)
List directory contents with filters
It's possible to restrict a Directory
to a subset of directory entries, by specifying a list of filename patterns to include or exclude.
The following example shows how to obtain a reference to the host working directory containing only *.rar
files:
- Go
- Node.js
- Python
package main
import (
"context"
"fmt"
"log"
"os"
"path/filepath"
"dagger.io/dagger"
)
func main() {
dir := os.TempDir()
os.WriteFile(filepath.Join(dir, "foo.txt"), []byte("1"), 0600)
os.WriteFile(filepath.Join(dir, "bar.txt"), []byte("2"), 0600)
os.WriteFile(filepath.Join(dir, "baz.rar"), []byte("3"), 0600)
ctx := context.Background()
client, err := dagger.Connect(ctx, dagger.WithLogOutput(os.Stderr), dagger.WithWorkdir(dir))
if err != nil {
log.Println(err)
return
}
defer client.Close()
entries, err := client.Host().Directory(".", dagger.HostDirectoryOpts{
Include: []string{"*.rar"},
}).Entries(ctx)
if err != nil {
log.Println(err)
return
}
fmt.Println(entries)
}
import Client, { connect } from "@dagger.io/dagger"
import * as os from "os"
import * as path from "path"
import * as fs from "fs"
const dir = os.tmpdir()
const files = ["foo.txt", "bar.txt", "baz.rar"]
let count = 1
for (const file of files) {
fs.writeFileSync(path.join(dir, file), count.toString())
count = count+1
}
connect(async (client: Client) => {
const entries = await client.host().directory(".", {"include":["*.rar"]}).entries()
console.log(entries)
}, {LogOutput: process.stderr, Workdir: dir})
import sys
import tempfile
import anyio
import dagger
async def main(workdir: anyio.Path):
for i, file in enumerate(["foo.txt", "bar.txt", "baz.rar"]):
await (workdir / file).write_text(str(i + 1))
cfg = dagger.Config(log_output=sys.stderr, workdir=workdir)
async with dagger.Connection(cfg) as client:
entries = await client.host().directory(".", include=["*.rar"]).entries()
print(entries)
with tempfile.TemporaryDirectory() as workdir:
anyio.run(main, anyio.Path(workdir))
The following example shows how to obtain a reference to the host working directory containing all files except *.txt
files:
- Go
- Node.js
- Python
package main
import (
"context"
"fmt"
"log"
"os"
"path/filepath"
"dagger.io/dagger"
)
func main() {
dir := os.TempDir()
os.WriteFile(filepath.Join(dir, "foo.txt"), []byte("1"), 0600)
os.WriteFile(filepath.Join(dir, "bar.txt"), []byte("2"), 0600)
os.WriteFile(filepath.Join(dir, "baz.rar"), []byte("3"), 0600)
ctx := context.Background()
client, err := dagger.Connect(ctx, dagger.WithLogOutput(os.Stderr), dagger.WithWorkdir(dir))
if err != nil {
log.Println(err)
return
}
defer client.Close()
entries, err := client.Host().Directory(".", dagger.HostDirectoryOpts{
Exclude: []string{"*.txt"},
}).Entries(ctx)
if err != nil {
log.Println(err)
return
}
fmt.Println(entries)
}
import Client, { connect } from "@dagger.io/dagger"
import * as os from "os"
import * as path from "path"
import * as fs from "fs"
const dir = os.tmpdir()
const files = ["foo.txt", "bar.txt", "baz.rar"]
let count = 1
for (const file of files) {
fs.writeFileSync(path.join(dir, file), count.toString())
count = count+1
}
connect(async (client: Client) => {
const entries = await client.host().directory(".", {"exclude":["*.txt"]}).entries()
console.log(entries)
}, {LogOutput: process.stderr, Workdir: dir})
import sys
import tempfile
import anyio
import dagger
async def main(workdir: anyio.Path):
for i, file in enumerate(["foo.txt", "bar.txt", "baz.rar"]):
await (workdir / file).write_text(str(i + 1))
cfg = dagger.Config(log_output=sys.stderr, workdir=workdir)
async with dagger.Connection(cfg) as client:
entries = await client.host().directory(".", exclude=["*.txt"]).entries()
print(entries)
with tempfile.TemporaryDirectory() as workdir:
anyio.run(main, anyio.Path(workdir))
The exclusion pattern overrides the inclusion pattern, but not vice-versa. The following example demonstrates by obtaining a reference to the host working directory containing all files except *.rar
files:
- Go
- Node.js
- Python
package main
import (
"context"
"fmt"
"log"
"os"
"path/filepath"
"dagger.io/dagger"
)
func main() {
dir := os.TempDir()
os.WriteFile(filepath.Join(dir, "foo.txt"), []byte("1"), 0600)
os.WriteFile(filepath.Join(dir, "bar.txt"), []byte("2"), 0600)
os.WriteFile(filepath.Join(dir, "baz.rar"), []byte("3"), 0600)
ctx := context.Background()
client, err := dagger.Connect(ctx, dagger.WithLogOutput(os.Stderr), dagger.WithWorkdir(dir))
if err != nil {
log.Println(err)
return
}
defer client.Close()
entries, err := client.Host().Directory(".", dagger.HostDirectoryOpts{
Include: []string{"*.*"},
Exclude: []string{"*.rar"},
}).Entries(ctx)
if err != nil {
log.Println(err)
return
}
fmt.Println(entries)
}
import Client, { connect } from "@dagger.io/dagger"
import * as os from "os"
import * as path from "path"
import * as fs from "fs"
const dir = os.tmpdir()
const files = ["foo.txt", "bar.txt", "baz.rar"]
let count = 1
for (const file of files) {
fs.writeFileSync(path.join(dir, file), count.toString())
count = count+1
}
connect(async (client: Client) => {
const entries = await client.host().directory(".", {"include":["*.*"], "exclude":["*.rar"]}).entries()
console.log(entries)
}, {LogOutput: process.stderr, Workdir: dir})
import sys
import tempfile
import anyio
import dagger
async def main(workdir: anyio.Path):
for i, file in enumerate(["foo.txt", "bar.txt", "baz.rar"]):
await (workdir / file).write_text(str(i + 1))
cfg = dagger.Config(log_output=sys.stderr, workdir=workdir)
async with dagger.Connection(cfg) as client:
entries = await client.host().directory(".", exclude=["*.rar"], include=["*.*"]).entries()
print(entries)
with tempfile.TemporaryDirectory() as workdir:
anyio.run(main, anyio.Path(workdir))
Mount a host directory in a container
A common operation when working with containers is to mount a host directory to a path in the container and then perform operations on it. It is necessary to provide the mount point in the container and the directory to be mounted as method arguments.
The following example shows how to mount a host directory in a container at the /host
container path and then execute a command in the container referencing the mounted directory:
- Go
- Node.js
- Python
package main
import (
"context"
"fmt"
"log"
"os"
"dagger.io/dagger"
)
func main() {
ctx := context.Background()
client, err := dagger.Connect(ctx, dagger.WithLogOutput(os.Stderr))
if err != nil {
log.Println(err)
return
}
defer client.Close()
contents, err := client.Container().
From("alpine:latest").
WithDirectory("/host", client.Host().Directory(".")).
WithExec([]string{"ls", "/host"}).
Stdout(ctx)
if err != nil {
log.Println(err)
return
}
fmt.Println(contents)
}
import Client, { connect } from "@dagger.io/dagger"
connect(async (client: Client) => {
const contents = await client.container()
.from("alpine:latest")
.withDirectory("/host", client.host().directory("."))
.withExec(["ls", "/host"])
.stdout()
console.log(contents)
}, {LogOutput: process.stderr})
import sys
import anyio
import dagger
async def main():
async with dagger.Connection(dagger.Config(log_output=sys.stderr)) as client:
out = await (
client.container()
.from_("alpine:latest")
.with_directory("/host", client.host().directory("."))
.with_exec(["ls", "/host"])
.stdout()
)
print(out)
anyio.run(main)
Export a directory from a container to the host
A directory can be exported to a different path. The destination path is supplied to the method as an argument.
The following example creates a file in a container's /tmp
directory and then exports the contents of that directory to the host's temporary directory:
- Go
- Node.js
- Python
package main
import (
"context"
"fmt"
"log"
"os"
"path/filepath"
"dagger.io/dagger"
)
func main() {
hostdir := os.TempDir()
ctx := context.Background()
client, err := dagger.Connect(ctx, dagger.WithLogOutput(os.Stderr))
if err != nil {
log.Println(err)
return
}
defer client.Close()
_, err = client.Container().From("alpine:latest").
WithWorkdir("/tmp").
WithExec([]string{"wget", "https://dagger.io"}).
Directory(".").
Export(ctx, hostdir)
if err != nil {
log.Println(err)
return
}
contents, err := os.ReadFile(filepath.Join(hostdir, "index.html"))
if err != nil {
log.Println(err)
return
}
fmt.Println(string(contents))
}
import Client, { connect } from "@dagger.io/dagger"
import * as os from "os"
import * as path from "path"
import * as fs from "fs"
const hostdir = os.tmpdir()
connect(async (client: Client) => {
await client.container()
.from("alpine:latest")
.withWorkdir("/tmp")
.withExec(["wget", "https://dagger.io"])
.directory(".")
.export(hostdir)
const contents = fs.readFileSync(path.join(hostdir, "index.html"))
console.log(contents.toString())
}, {LogOutput: process.stderr})
import sys
import tempfile
import anyio
import dagger
async def main(hostdir: str):
async with dagger.Connection(dagger.Config(log_output=sys.stderr)) as client:
await (
client.container()
.from_("alpine:latest")
.with_workdir("/tmp")
.with_exec(["wget", "https://dagger.io"])
.directory(".")
.export(hostdir)
)
contents = await anyio.Path(hostdir, "index.html").read_text()
print(contents)
with tempfile.TemporaryDirectory() as hostdir:
anyio.run(main, hostdir)
Conclusion
This guide introduced you to the functions available in the Dagger SDKs to work with the host filesystem. It provided explanations and code samples demonstrating how to set the host working directory, read directory contents (with and without pathname filters), mount a host directory in a container and export a directory from a container to the host.
Use the Go, Node.js and Python SDK References to learn more about Dagger.