Skip to content

Commit

Permalink
feat: add WithFiles to Directory and Container
Browse files Browse the repository at this point in the history
  • Loading branch information
tomasmota committed Feb 1, 2024
1 parent 73a7394 commit acdfe96
Show file tree
Hide file tree
Showing 15 changed files with 604 additions and 0 deletions.
13 changes: 13 additions & 0 deletions core/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,19 @@ func (container *Container) WithFile(ctx context.Context, destPath string, src *
})
}

func (container *Container) WithFiles(ctx context.Context, destDir string, src []*File, permissions *int, owner string) (*Container, error) {
container = container.Clone()

return container.writeToPath(ctx, path.Dir(destDir), func(dir *Directory) (*Directory, error) {
ownership, err := container.ownership(ctx, owner)
if err != nil {
return nil, err
}

return dir.WithFiles(ctx, destDir, src, permissions, ownership)
})
}

func (container *Container) WithNewFile(ctx context.Context, dest string, content []byte, permissions fs.FileMode, owner string) (*Container, error) {
container = container.Clone()

Expand Down
39 changes: 39 additions & 0 deletions core/directory.go
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,45 @@ func (dir *Directory) WithFile(
return dir, nil
}

func (dir *Directory) WithFiles(
ctx context.Context,
destDir string,
src []*File,
permissions *int,
owner *Ownership,
) (*Directory, error) {
dir = dir.Clone()

for _, file := range src {
destSt, err := dir.State()
if err != nil {
return nil, err
}

srcSt, err := file.State()
if err != nil {
return nil, err
}

if err := dir.SetState(ctx, mergeStates(mergeStateInput{
Dest: destSt,
DestDir: path.Join(dir.Dir, destDir),
DestFileName: path.Base(file.File),
Src: srcSt,
SrcDir: path.Dir(file.File),
SrcFileName: path.Base(file.File),
Permissions: permissions,
Owner: owner,
})); err != nil {
return nil, err
}

dir.Services.Merge(file.Services)
}

return dir, nil
}

type mergeStateInput struct {
Dest llb.State
DestDir string
Expand Down
28 changes: 28 additions & 0 deletions core/integration/container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1766,6 +1766,34 @@ func TestContainerWithFile(t *testing.T) {
require.Equal(t, "some-content", contents)
}

func TestContainerWithFiles(t *testing.T) {
t.Parallel()

c, ctx := connect(t)

file1 := c.Directory().
WithNewFile("first-file", "file1 content").
File("first-file")
file2 := c.Directory().
WithNewFile("second-file", "file2 content").
File("second-file")
files := []*dagger.File{file1, file2}

ctr := c.Container().
From(alpineImage).
WithFiles("myfiles", files)

contents, err := ctr.WithExec([]string{"cat", "/myfiles/first-file"}).
Stdout(ctx)
require.NoError(t, err)
require.Equal(t, "file1 content", contents)

contents, err = ctr.WithExec([]string{"cat", "/myfiles/second-file"}).
Stdout(ctx)
require.NoError(t, err)
require.Equal(t, "file2 content", contents)
}

func TestContainerWithNewFile(t *testing.T) {
t.Parallel()

Expand Down
58 changes: 58 additions & 0 deletions core/integration/directory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,64 @@ func TestDirectoryWithFile(t *testing.T) {
})
}

func TestDirectoryWithFiles(t *testing.T) {
t.Parallel()
c, ctx := connect(t)

file1 := c.Directory().
WithNewFile("first-file", "file1 content").
File("first-file")
file2 := c.Directory().
WithNewFile("second-file", "file2 content").
File("second-file")
files := []*dagger.File{file1, file2}
dir := c.Directory().
WithFiles("/", files)

// check file1 contents
content, err := dir.File("/first-file").Contents(ctx)
require.Equal(t, "file1 content", content)
require.NoError(t, err)

// check file2 contents
content, err = dir.File("/second-file").Contents(ctx)
require.Equal(t, "file2 content", content)
require.NoError(t, err)

_, err = dir.File("/some-other-file").Contents(ctx)
require.Error(t, err)

// test sub directory
subDir := c.Directory().
WithFiles("/a/b/c", files)
content, err = subDir.File("/a/b/c/first-file").Contents(ctx)
require.Equal(t, "file1 content", content)
require.NoError(t, err)

t.Run("respects permissions", func(t *testing.T) {
file1 := c.Directory().
WithNewFile("file-set-permissions", "this should have rwxrwxrwx permissions", dagger.DirectoryWithNewFileOpts{Permissions: 0o777}).
File("file-set-permissions")
file2 := c.Directory().
WithNewFile("file-default-permissions", "this should have rw-r--r-- permissions").
File("file-default-permissions")
files := []*dagger.File{file1, file2}
dir := c.Directory().
WithFiles("/", files)

ctr := c.Container().From("alpine").WithDirectory("/permissions-test", dir)

stdout, err := ctr.WithExec([]string{"ls", "-l", "/permissions-test/file-set-permissions"}).Stdout(ctx)
require.NoError(t, err)
require.Contains(t, stdout, "rwxrwxrwx")

ctr2 := c.Container().From("alpine").WithDirectory("/permissions-test", dir2)

Check failure on line 451 in core/integration/directory_test.go

View workflow job for this annotation

GitHub Actions / lint / dagger-runner

undefined: dir2 (typecheck)

Check failure on line 451 in core/integration/directory_test.go

View workflow job for this annotation

GitHub Actions / test / dagger-runner

undefined: dir2

Check failure on line 451 in core/integration/directory_test.go

View workflow job for this annotation

GitHub Actions / test / dagger-runner

undefined: dir2

Check failure on line 451 in core/integration/directory_test.go

View workflow job for this annotation

GitHub Actions / testdev / dagger-runner

undefined: dir2

Check failure on line 451 in core/integration/directory_test.go

View workflow job for this annotation

GitHub Actions / testdev / dagger-runner

undefined: dir2
stdout2, err := ctr2.WithExec([]string{"ls", "-l", "/permissions-test/file-default-permissions"}).Stdout(ctx)
require.NoError(t, err)
require.Contains(t, stdout2, "rw-r--r--")
})
}

func TestDirectoryWithTimestamps(t *testing.T) {
t.Parallel()
c, ctx := connect(t)
Expand Down
28 changes: 28 additions & 0 deletions core/schema/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,16 @@ func (s *containerSchema) Install() {
`The user and group can either be an ID (1000:1000) or a name (foo:bar).`,
`If the group is omitted, it defaults to the same as the user.`),

dagql.Func("withFiles", s.withFiles).
Doc(`Retrieves this container plus the contents of the given files copied to the given path.`).
ArgDoc("path", `Location where copied files should be placed (e.g., "/src").`).
ArgDoc("files", `Identifiers of the files to copy.`).
ArgDoc("permissions", `Permission given to the copied files (e.g., 0600).`).
ArgDoc("owner",
`A user:group to set for the files.`,
`The user and group can either be an ID (1000:1000) or a name (foo:bar).`,
`If the group is omitted, it defaults to the same as the user.`),

dagql.Func("withNewFile", s.withNewFile).
Doc(`Retrieves this container plus a new file written at the given path.`).
ArgDoc("path", `Location of the written file (e.g., "/tmp/file.txt").`).
Expand Down Expand Up @@ -1062,6 +1072,24 @@ func (s *containerSchema) withFile(ctx context.Context, parent *core.Container,
return parent.WithFile(ctx, args.Path, file.Self, args.Permissions, args.Owner)
}

type containerWithFilesArgs struct {
WithFilesArgs
Owner string `default:""`
}

func (s *containerSchema) withFiles(ctx context.Context, parent *core.Container, args containerWithFilesArgs) (*core.Container, error) {
files := []*core.File{}
for _, id := range args.Files {
file, err := id.Load(ctx, s.srv)
if err != nil {
return nil, err
}
files = append(files, file.Self)
}

return parent.WithFiles(ctx, args.Path, files, args.Permissions, args.Owner)
}

type containerWithNewFileArgs struct {
Path string
Contents string `default:""`
Expand Down
24 changes: 24 additions & 0 deletions core/schema/directory.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ func (s *directorySchema) Install() {
ArgDoc("path", `Location of the copied file (e.g., "/file.txt").`).
ArgDoc("source", `Identifier of the file to copy.`).
ArgDoc("permissions", `Permission given to the copied file (e.g., 0600).`),
dagql.Func("withFiles", s.withFiles).
Doc(`Retrieves this directory plus the contents of the given files copied to the given path.`).
ArgDoc("path", `Location where copied files should be placed (e.g., "/src").`).
ArgDoc("files", `Identifiers of the files to copy.`).
ArgDoc("permissions", `Permission given to the copied files (e.g., 0600).`),
dagql.Func("withNewFile", s.withNewFile).
Doc(`Retrieves this directory plus a new file written at the given path.`).
ArgDoc("path", `Location of the written file (e.g., "/file.txt").`).
Expand Down Expand Up @@ -212,6 +217,25 @@ func (s *directorySchema) withFile(ctx context.Context, parent *core.Directory,
return parent.WithFile(ctx, args.Path, file.Self, args.Permissions, nil)
}

type WithFilesArgs struct {
Path string
Files []core.FileID
Permissions *int
}

func (s *directorySchema) withFiles(ctx context.Context, parent *core.Directory, args WithFilesArgs) (*core.Directory, error) {
files := []*core.File{}
for _, id := range args.Files {
file, err := id.Load(ctx, s.srv)
if err != nil {
return nil, err
}
files = append(files, file.Self)
}

return parent.WithFiles(ctx, args.Path, files, args.Permissions, nil)
}

type withoutDirectoryArgs struct {
Path string
}
Expand Down
37 changes: 37 additions & 0 deletions docs/docs-graphql/schema.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,29 @@ type Container {
source: FileID!
): Container!

"""
Retrieves this container plus the contents of the given files copied to the given path.
"""
withFiles(
"""Identifier of the files to copy."""
files: [FileID!]!

"""
A user:group to set for the files.
The user and group can either be an ID (1000:1000) or a name (foo:bar).
If the group is omitted, it defaults to the same as the user.
"""
owner: String = ""

"""Location where copied files should be placed (e.g., "/src")."""
path: String!

"""Permission given to the copied files (e.g., 0600)."""
permissions: Int
): Container!

"""
Indicate that subsequent operations should be featured more prominently in the UI.
"""
Expand Down Expand Up @@ -1000,6 +1023,20 @@ type Directory {
source: FileID!
): Directory!

"""
Retrieves this directory plus the contents of the given files copied to the given path.
"""
withFiles(
"""Identifiers of the files to copy."""
files: [FileID!]!

"""Location where copied files should be placed (e.g., "/src")."""
path: String!

"""Permission given to the copied files (e.g., 0600)."""
permissions: Int
): Directory!

"""
Retrieves this directory plus a new directory created at the given path.
"""
Expand Down
27 changes: 27 additions & 0 deletions sdk/elixir/lib/dagger/gen/container.ex

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions sdk/elixir/lib/dagger/gen/directory.ex

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit acdfe96

Please sign in to comment.