From 94df5ba5929a6d05757a53ee3a7b85f90eb4e333 Mon Sep 17 00:00:00 2001 From: tomasmota Date: Thu, 8 Feb 2024 20:14:02 +0100 Subject: [PATCH] feat: add WithFiles to Directory and Container Signed-off-by: tomasmota --- .../unreleased/Added-20240201-183804.yaml | 6 + core/container.go | 13 +++ core/directory.go | 27 +++++ core/integration/container_test.go | 28 +++++ core/integration/directory_test.go | 58 ++++++++++ core/schema/container.go | 28 +++++ core/schema/directory.go | 24 ++++ docs/docs-graphql/schema.graphqls | 37 +++++++ sdk/elixir/lib/dagger/gen/container.ex | 27 +++++ sdk/elixir/lib/dagger/gen/directory.ex | 20 ++++ sdk/go/dagger.gen.go | 58 ++++++++++ sdk/php/generated/Container.php | 17 +++ sdk/php/generated/Directory.php | 14 +++ sdk/python/src/dagger/client/gen.py | 63 +++++++++++ sdk/rust/crates/dagger-sdk/src/gen.rs | 104 ++++++++++++++++++ sdk/typescript/api/client.gen.ts | 74 +++++++++++++ 16 files changed, 598 insertions(+) create mode 100644 .changes/unreleased/Added-20240201-183804.yaml diff --git a/.changes/unreleased/Added-20240201-183804.yaml b/.changes/unreleased/Added-20240201-183804.yaml new file mode 100644 index 00000000000..dabb3b635c4 --- /dev/null +++ b/.changes/unreleased/Added-20240201-183804.yaml @@ -0,0 +1,6 @@ +kind: Added +body: add `Directory.WithFiles` and `Container.WithFiles` +time: 2024-02-01T18:38:04.314455612+01:00 +custom: + Author: tomasmota + PR: "6556" diff --git a/core/container.go b/core/container.go index bdd4fbdffa7..fa4b96becda 100644 --- a/core/container.go +++ b/core/container.go @@ -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() diff --git a/core/directory.go b/core/directory.go index 7d20273222e..f86b46614a5 100644 --- a/core/directory.go +++ b/core/directory.go @@ -503,6 +503,33 @@ func (dir *Directory) WithFile( return dir, nil } +// TODO: address https://github.com/dagger/dagger/pull/6556/files#r1482830091 +func (dir *Directory) WithFiles( + ctx context.Context, + destDir string, + src []*File, + permissions *int, + owner *Ownership, +) (*Directory, error) { + dir = dir.Clone() + + var err error + for _, file := range src { + dir, err = dir.WithFile( + ctx, + path.Join(destDir, path.Base(file.File)), + file, + permissions, + owner, + ) + if err != nil { + return nil, err + } + } + + return dir, nil +} + type mergeStateInput struct { Dest llb.State DestDir string diff --git a/core/integration/container_test.go b/core/integration/container_test.go index 53630ce159b..053d4085b86 100644 --- a/core/integration/container_test.go +++ b/core/integration/container_test.go @@ -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() diff --git a/core/integration/directory_test.go b/core/integration/directory_test.go index b2434630bb2..8241323ef84 100644 --- a/core/integration/directory_test.go +++ b/core/integration/directory_test.go @@ -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", dir) + 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) diff --git a/core/schema/container.go b/core/schema/container.go index aae92094d9a..05b46bd81fd 100644 --- a/core/schema/container.go +++ b/core/schema/container.go @@ -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("sources", `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").`). @@ -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.Sources { + 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:""` diff --git a/core/schema/directory.go b/core/schema/directory.go index d0f15f14dae..045f580e9d2 100644 --- a/core/schema/directory.go +++ b/core/schema/directory.go @@ -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("sources", `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").`). @@ -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 + Sources []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.Sources { + 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 } diff --git a/docs/docs-graphql/schema.graphqls b/docs/docs-graphql/schema.graphqls index ede705bd440..3684f7e23d9 100644 --- a/docs/docs-graphql/schema.graphqls +++ b/docs/docs-graphql/schema.graphqls @@ -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( + """ + 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 + + """Identifiers of the files to copy.""" + sources: [FileID!]! + ): Container! + """ Indicate that subsequent operations should be featured more prominently in the UI. """ @@ -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( + """Location where copied files should be placed (e.g., "/src").""" + path: String! + + """Permission given to the copied files (e.g., 0600).""" + permissions: Int + + """Identifiers of the files to copy.""" + sources: [FileID!]! + ): Directory! + """ Retrieves this directory plus a new directory created at the given path. """ diff --git a/sdk/elixir/lib/dagger/gen/container.ex b/sdk/elixir/lib/dagger/gen/container.ex index 9c8e17d0bf6..f0f030ac714 100644 --- a/sdk/elixir/lib/dagger/gen/container.ex +++ b/sdk/elixir/lib/dagger/gen/container.ex @@ -695,6 +695,33 @@ defmodule Dagger.Container do end ) + ( + @doc "Retrieves this container plus the contents of the given files copied to the given path.\n\n## Required Arguments\n\n* `path` - Location where copied files should be placed (e.g., \"/src\").\n* `sources` - Identifiers of the files to copy.\n\n## Optional Arguments\n\n* `permissions` - Permission given to the copied files (e.g., 0600).\n* `owner` - A user:group to set for the files.\n\nThe user and group can either be an ID (1000:1000) or a name (foo:bar).\n\nIf the group is omitted, it defaults to the same as the user." + @spec with_files(t(), Dagger.String.t(), [Dagger.FileID.t()], keyword()) :: + Dagger.Container.t() + def with_files(%__MODULE__{} = container, path, sources, optional_args \\ []) do + selection = select(container.selection, "withFiles") + selection = arg(selection, "path", path) + selection = arg(selection, "sources", sources) + + selection = + if is_nil(optional_args[:permissions]) do + selection + else + arg(selection, "permissions", optional_args[:permissions]) + end + + selection = + if is_nil(optional_args[:owner]) do + selection + else + arg(selection, "owner", optional_args[:owner]) + end + + %Dagger.Container{selection: selection, client: container.client} + end + ) + ( @doc "Indicate that subsequent operations should be featured more prominently in the UI." @spec with_focus(t()) :: Dagger.Container.t() diff --git a/sdk/elixir/lib/dagger/gen/directory.ex b/sdk/elixir/lib/dagger/gen/directory.ex index 3ee0a5547ef..44e8b754d31 100644 --- a/sdk/elixir/lib/dagger/gen/directory.ex +++ b/sdk/elixir/lib/dagger/gen/directory.ex @@ -244,6 +244,26 @@ defmodule Dagger.Directory do end ) + ( + @doc "Retrieves this directory plus the contents of the given files copied to the given path.\n\n## Required Arguments\n\n* `path` - Location where copied files should be placed (e.g., \"/src\").\n* `sources` - Identifiers of the files to copy.\n\n## Optional Arguments\n\n* `permissions` - Permission given to the copied files (e.g., 0600)." + @spec with_files(t(), Dagger.String.t(), [Dagger.FileID.t()], keyword()) :: + Dagger.Directory.t() + def with_files(%__MODULE__{} = directory, path, sources, optional_args \\ []) do + selection = select(directory.selection, "withFiles") + selection = arg(selection, "path", path) + selection = arg(selection, "sources", sources) + + selection = + if is_nil(optional_args[:permissions]) do + selection + else + arg(selection, "permissions", optional_args[:permissions]) + end + + %Dagger.Directory{selection: selection, client: directory.client} + end + ) + ( @doc "Retrieves this directory plus a new directory created at the given path.\n\n## Required Arguments\n\n* `path` - Location of the directory created (e.g., \"/logs\").\n\n## Optional Arguments\n\n* `permissions` - Permission granted to the created directory (e.g., 0777)." @spec with_new_directory(t(), Dagger.String.t(), keyword()) :: Dagger.Directory.t() diff --git a/sdk/go/dagger.gen.go b/sdk/go/dagger.gen.go index c232251b746..b11c41c081b 100644 --- a/sdk/go/dagger.gen.go +++ b/sdk/go/dagger.gen.go @@ -1245,6 +1245,40 @@ func (r *Container) WithFile(path string, source *File, opts ...ContainerWithFil } } +// ContainerWithFilesOpts contains options for Container.WithFiles +type ContainerWithFilesOpts struct { + // Permission given to the copied files (e.g., 0600). + Permissions int + // 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 +} + +// Retrieves this container plus the contents of the given files copied to the given path. +func (r *Container) WithFiles(path string, sources []*File, opts ...ContainerWithFilesOpts) *Container { + q := r.q.Select("withFiles") + for i := len(opts) - 1; i >= 0; i-- { + // `permissions` optional argument + if !querybuilder.IsZeroValue(opts[i].Permissions) { + q = q.Arg("permissions", opts[i].Permissions) + } + // `owner` optional argument + if !querybuilder.IsZeroValue(opts[i].Owner) { + q = q.Arg("owner", opts[i].Owner) + } + } + q = q.Arg("path", path) + q = q.Arg("sources", sources) + + return &Container{ + q: q, + c: r.c, + } +} + // Indicate that subsequent operations should be featured more prominently in the UI. func (r *Container) WithFocus() *Container { q := r.q.Select("withFocus") @@ -2140,6 +2174,30 @@ func (r *Directory) WithFile(path string, source *File, opts ...DirectoryWithFil } } +// DirectoryWithFilesOpts contains options for Directory.WithFiles +type DirectoryWithFilesOpts struct { + // Permission given to the copied files (e.g., 0600). + Permissions int +} + +// Retrieves this directory plus the contents of the given files copied to the given path. +func (r *Directory) WithFiles(path string, sources []*File, opts ...DirectoryWithFilesOpts) *Directory { + q := r.q.Select("withFiles") + for i := len(opts) - 1; i >= 0; i-- { + // `permissions` optional argument + if !querybuilder.IsZeroValue(opts[i].Permissions) { + q = q.Arg("permissions", opts[i].Permissions) + } + } + q = q.Arg("path", path) + q = q.Arg("sources", sources) + + return &Directory{ + q: q, + c: r.c, + } +} + // DirectoryWithNewDirectoryOpts contains options for Directory.WithNewDirectory type DirectoryWithNewDirectoryOpts struct { // Permission granted to the created directory (e.g., 0777). diff --git a/sdk/php/generated/Container.php b/sdk/php/generated/Container.php index 05923391e44..86c134681e7 100644 --- a/sdk/php/generated/Container.php +++ b/sdk/php/generated/Container.php @@ -547,6 +547,23 @@ public function withFile( return new \Dagger\Container($this->client, $this->queryBuilderChain->chain($innerQueryBuilder)); } + /** + * Retrieves this container plus the contents of the given files copied to the given path. + */ + public function withFiles(string $path, array $sources, ?int $permissions = null, ?string $owner = ''): Container + { + $innerQueryBuilder = new \Dagger\Client\QueryBuilder('withFiles'); + $innerQueryBuilder->setArgument('path', $path); + $innerQueryBuilder->setArgument('sources', $sources); + if (null !== $permissions) { + $innerQueryBuilder->setArgument('permissions', $permissions); + } + if (null !== $owner) { + $innerQueryBuilder->setArgument('owner', $owner); + } + return new \Dagger\Container($this->client, $this->queryBuilderChain->chain($innerQueryBuilder)); + } + /** * Indicate that subsequent operations should be featured more prominently in the UI. */ diff --git a/sdk/php/generated/Directory.php b/sdk/php/generated/Directory.php index 6420920530e..2ef39555097 100644 --- a/sdk/php/generated/Directory.php +++ b/sdk/php/generated/Directory.php @@ -187,6 +187,20 @@ public function withFile(string $path, FileId|File $source, ?int $permissions = return new \Dagger\Directory($this->client, $this->queryBuilderChain->chain($innerQueryBuilder)); } + /** + * Retrieves this directory plus the contents of the given files copied to the given path. + */ + public function withFiles(string $path, array $sources, ?int $permissions = null): Directory + { + $innerQueryBuilder = new \Dagger\Client\QueryBuilder('withFiles'); + $innerQueryBuilder->setArgument('path', $path); + $innerQueryBuilder->setArgument('sources', $sources); + if (null !== $permissions) { + $innerQueryBuilder->setArgument('permissions', $permissions); + } + return new \Dagger\Directory($this->client, $this->queryBuilderChain->chain($innerQueryBuilder)); + } + /** * Retrieves this directory plus a new directory created at the given path. */ diff --git a/sdk/python/src/dagger/client/gen.py b/sdk/python/src/dagger/client/gen.py index 7700276b14f..b9a771e07cf 100644 --- a/sdk/python/src/dagger/client/gen.py +++ b/sdk/python/src/dagger/client/gen.py @@ -1291,6 +1291,41 @@ def with_file( _ctx = self._select("withFile", _args) return Container(_ctx) + @typecheck + def with_files( + self, + path: str, + sources: Sequence["File"], + *, + permissions: int | None = None, + owner: str | None = "", + ) -> "Container": + """Retrieves this container plus the contents of the given files copied + to the given path. + + Parameters + ---------- + path: + Location where copied files should be placed (e.g., "/src"). + sources: + Identifiers of the files to copy. + permissions: + Permission given to the copied files (e.g., 0600). + 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. + """ + _args = [ + Arg("path", path), + Arg("sources", sources), + Arg("permissions", permissions, None), + Arg("owner", owner, ""), + ] + _ctx = self._select("withFiles", _args) + return Container(_ctx) + @typecheck def with_focus(self) -> "Container": """Indicate that subsequent operations should be featured more @@ -2291,6 +2326,34 @@ def with_file( _ctx = self._select("withFile", _args) return Directory(_ctx) + @typecheck + def with_files( + self, + path: str, + sources: Sequence["File"], + *, + permissions: int | None = None, + ) -> "Directory": + """Retrieves this directory plus the contents of the given files copied + to the given path. + + Parameters + ---------- + path: + Location where copied files should be placed (e.g., "/src"). + sources: + Identifiers of the files to copy. + permissions: + Permission given to the copied files (e.g., 0600). + """ + _args = [ + Arg("path", path), + Arg("sources", sources), + Arg("permissions", permissions, None), + ] + _ctx = self._select("withFiles", _args) + return Directory(_ctx) + @typecheck def with_new_directory( self, diff --git a/sdk/rust/crates/dagger-sdk/src/gen.rs b/sdk/rust/crates/dagger-sdk/src/gen.rs index c07b9d25041..8efab8bcf18 100644 --- a/sdk/rust/crates/dagger-sdk/src/gen.rs +++ b/sdk/rust/crates/dagger-sdk/src/gen.rs @@ -774,6 +774,17 @@ pub struct ContainerWithFileOpts<'a> { pub permissions: Option, } #[derive(Builder, Debug, PartialEq)] +pub struct ContainerWithFilesOpts<'a> { + /// 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. + #[builder(setter(into, strip_option), default)] + pub owner: Option<&'a str>, + /// Permission given to the copied files (e.g., 0600). + #[builder(setter(into, strip_option), default)] + pub permissions: Option, +} +#[derive(Builder, Debug, PartialEq)] pub struct ContainerWithMountedCacheOpts<'a> { /// A user:group to set for the mounted cache directory. /// Note that this changes the ownership of the specified mount along with the initial filesystem provided by source (if any). It does not have any effect if/when the cache has already been created. @@ -1693,6 +1704,51 @@ impl Container { graphql_client: self.graphql_client.clone(), }; } + /// Retrieves this container plus the contents of the given files copied to the given path. + /// + /// # Arguments + /// + /// * `path` - Location where copied files should be placed (e.g., "/src"). + /// * `sources` - Identifiers of the files to copy. + /// * `opt` - optional argument, see inner type for documentation, use _opts to use + pub fn with_files(&self, path: impl Into, sources: Vec) -> Container { + let mut query = self.selection.select("withFiles"); + query = query.arg("path", path.into()); + query = query.arg("sources", sources); + return Container { + proc: self.proc.clone(), + selection: query, + graphql_client: self.graphql_client.clone(), + }; + } + /// Retrieves this container plus the contents of the given files copied to the given path. + /// + /// # Arguments + /// + /// * `path` - Location where copied files should be placed (e.g., "/src"). + /// * `sources` - Identifiers of the files to copy. + /// * `opt` - optional argument, see inner type for documentation, use _opts to use + pub fn with_files_opts<'a>( + &self, + path: impl Into, + sources: Vec, + opts: ContainerWithFilesOpts<'a>, + ) -> Container { + let mut query = self.selection.select("withFiles"); + query = query.arg("path", path.into()); + query = query.arg("sources", sources); + if let Some(permissions) = opts.permissions { + query = query.arg("permissions", permissions); + } + if let Some(owner) = opts.owner { + query = query.arg("owner", owner); + } + return Container { + proc: self.proc.clone(), + selection: query, + graphql_client: self.graphql_client.clone(), + }; + } /// Indicate that subsequent operations should be featured more prominently in the UI. pub fn with_focus(&self) -> Container { let query = self.selection.select("withFocus"); @@ -2517,6 +2573,12 @@ pub struct DirectoryWithFileOpts { pub permissions: Option, } #[derive(Builder, Debug, PartialEq)] +pub struct DirectoryWithFilesOpts { + /// Permission given to the copied files (e.g., 0600). + #[builder(setter(into, strip_option), default)] + pub permissions: Option, +} +#[derive(Builder, Debug, PartialEq)] pub struct DirectoryWithNewDirectoryOpts { /// Permission granted to the created directory (e.g., 0777). #[builder(setter(into, strip_option), default)] @@ -2852,6 +2914,48 @@ impl Directory { graphql_client: self.graphql_client.clone(), }; } + /// Retrieves this directory plus the contents of the given files copied to the given path. + /// + /// # Arguments + /// + /// * `path` - Location where copied files should be placed (e.g., "/src"). + /// * `sources` - Identifiers of the files to copy. + /// * `opt` - optional argument, see inner type for documentation, use _opts to use + pub fn with_files(&self, path: impl Into, sources: Vec) -> Directory { + let mut query = self.selection.select("withFiles"); + query = query.arg("path", path.into()); + query = query.arg("sources", sources); + return Directory { + proc: self.proc.clone(), + selection: query, + graphql_client: self.graphql_client.clone(), + }; + } + /// Retrieves this directory plus the contents of the given files copied to the given path. + /// + /// # Arguments + /// + /// * `path` - Location where copied files should be placed (e.g., "/src"). + /// * `sources` - Identifiers of the files to copy. + /// * `opt` - optional argument, see inner type for documentation, use _opts to use + pub fn with_files_opts( + &self, + path: impl Into, + sources: Vec, + opts: DirectoryWithFilesOpts, + ) -> Directory { + let mut query = self.selection.select("withFiles"); + query = query.arg("path", path.into()); + query = query.arg("sources", sources); + if let Some(permissions) = opts.permissions { + query = query.arg("permissions", permissions); + } + return Directory { + proc: self.proc.clone(), + selection: query, + graphql_client: self.graphql_client.clone(), + }; + } /// Retrieves this directory plus a new directory created at the given path. /// /// # Arguments diff --git a/sdk/typescript/api/client.gen.ts b/sdk/typescript/api/client.gen.ts index d2a013d1e53..f98b9b04818 100644 --- a/sdk/typescript/api/client.gen.ts +++ b/sdk/typescript/api/client.gen.ts @@ -306,6 +306,22 @@ export type ContainerWithFileOpts = { owner?: string } +export type ContainerWithFilesOpts = { + /** + * Permission given to the copied files (e.g., 0600). + */ + permissions?: number + + /** + * 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 +} + export type ContainerWithMountedCacheOpts = { /** * Identifier of the directory to use as the cache volume's root. @@ -515,6 +531,13 @@ export type DirectoryWithFileOpts = { permissions?: number } +export type DirectoryWithFilesOpts = { + /** + * Permission given to the copied files (e.g., 0600). + */ + permissions?: number +} + export type DirectoryWithNewDirectoryOpts = { /** * Permission granted to the created directory (e.g., 0777). @@ -1984,6 +2007,34 @@ export class Container extends BaseClient { }) } + /** + * Retrieves this container plus the contents of the given files copied to the given path. + * @param path Location where copied files should be placed (e.g., "/src"). + * @param sources Identifiers of the files to copy. + * @param opts.permissions Permission given to the copied files (e.g., 0600). + * @param opts.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. + */ + withFiles = ( + path: string, + sources: File[], + opts?: ContainerWithFilesOpts + ): Container => { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withFiles", + args: { path, sources, ...opts }, + }, + ], + ctx: this._ctx, + }) + } + /** * Indicate that subsequent operations should be featured more prominently in the UI. */ @@ -2947,6 +2998,29 @@ export class Directory extends BaseClient { }) } + /** + * Retrieves this directory plus the contents of the given files copied to the given path. + * @param path Location where copied files should be placed (e.g., "/src"). + * @param sources Identifiers of the files to copy. + * @param opts.permissions Permission given to the copied files (e.g., 0600). + */ + withFiles = ( + path: string, + sources: File[], + opts?: DirectoryWithFilesOpts + ): Directory => { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "withFiles", + args: { path, sources, ...opts }, + }, + ], + ctx: this._ctx, + }) + } + /** * Retrieves this directory plus a new directory created at the given path. * @param path Location of the directory created (e.g., "/logs").