diff --git a/docs/features/containers.md b/docs/features/containers.md index 2b45a32b8..ed04e68fe 100644 --- a/docs/features/containers.md +++ b/docs/features/containers.md @@ -133,6 +133,10 @@ const container = await new GenericContainer("alpine") content: "hello world", target: "/remote/file2.txt" }]) + .withCopyArchivesToContainer([{ + tar: nodeReadable, + target: "/some/nested/remotedir" + }]) .start(); ``` @@ -153,6 +157,7 @@ container.copyContentToContainer([{ content: "hello world", target: "/remote/file2.txt" }]) +container.copyArchiveToContainer(nodeReadable, "/some/nested/remotedir"); ``` An optional `mode` can be specified in octal for setting file permissions: diff --git a/packages/testcontainers/src/generic-container/abstract-started-container.ts b/packages/testcontainers/src/generic-container/abstract-started-container.ts index 43d09232f..1ccac33b7 100644 --- a/packages/testcontainers/src/generic-container/abstract-started-container.ts +++ b/packages/testcontainers/src/generic-container/abstract-started-container.ts @@ -83,6 +83,10 @@ export class AbstractStartedContainer implements StartedTestContainer { return this.startedTestContainer.copyContentToContainer(contentsToCopy); } + public copyArchiveToContainer(tar: Readable, target = "/"): Promise { + return this.startedTestContainer.copyArchiveToContainer(tar, target); + } + public copyArchiveFromContainer(path: string): Promise { return this.startedTestContainer.copyArchiveFromContainer(path); } diff --git a/packages/testcontainers/src/generic-container/generic-container.ts b/packages/testcontainers/src/generic-container/generic-container.ts index 870840eb7..5655884ea 100644 --- a/packages/testcontainers/src/generic-container/generic-container.ts +++ b/packages/testcontainers/src/generic-container/generic-container.ts @@ -10,6 +10,7 @@ import { PortForwarderInstance, SSHD_IMAGE } from "../port-forwarder/port-forwar import { getReaper, REAPER_IMAGE } from "../reaper/reaper"; import { StartedTestContainer, TestContainer } from "../test-container"; import { + ArchiveToCopy, BindMount, ContentToCopy, DirectoryToCopy, @@ -57,6 +58,7 @@ export class GenericContainer implements TestContainer { protected filesToCopy: FileToCopy[] = []; protected directoriesToCopy: DirectoryToCopy[] = []; protected contentsToCopy: ContentToCopy[] = []; + protected archivesToCopy: ArchiveToCopy[] = []; protected healthCheck?: HealthCheck; constructor(image: string) { @@ -180,6 +182,10 @@ export class GenericContainer implements TestContainer { await client.container.putArchive(container, archive, "/"); } + for (const archive of this.archivesToCopy) { + await client.container.putArchive(container, archive.tar, archive.target); + } + log.info(`Starting container for image "${this.createOpts.Image}"...`, { containerId: container.id }); if (this.containerCreated) { await this.containerCreated(container.id); @@ -458,6 +464,11 @@ export class GenericContainer implements TestContainer { return this; } + public withCopyArchivesToContainer(archivesToCopy: ArchiveToCopy[]): this { + this.archivesToCopy = [...this.archivesToCopy, ...archivesToCopy]; + return this; + } + public withWorkingDir(workingDir: string): this { this.createOpts.WorkingDir = workingDir; return this; diff --git a/packages/testcontainers/src/generic-container/started-generic-container.ts b/packages/testcontainers/src/generic-container/started-generic-container.ts index 51e4e25d5..b0bc42cd6 100644 --- a/packages/testcontainers/src/generic-container/started-generic-container.ts +++ b/packages/testcontainers/src/generic-container/started-generic-container.ts @@ -200,6 +200,13 @@ export class StartedGenericContainer implements StartedTestContainer { log.debug(`Copied content to container`, { containerId: this.container.id }); } + public async copyArchiveToContainer(tar: Readable, target = "/"): Promise { + log.debug(`Copying archive to container...`, { containerId: this.container.id }); + const client = await getContainerRuntimeClient(); + await client.container.putArchive(this.container, tar, target); + log.debug(`Copied archive to container`, { containerId: this.container.id }); + } + public async copyArchiveFromContainer(path: string): Promise { log.debug(`Copying archive "${path}" from container...`, { containerId: this.container.id }); const client = await getContainerRuntimeClient(); diff --git a/packages/testcontainers/src/test-container.ts b/packages/testcontainers/src/test-container.ts index 82a12a25f..84e9633de 100644 --- a/packages/testcontainers/src/test-container.ts +++ b/packages/testcontainers/src/test-container.ts @@ -1,6 +1,7 @@ import { Readable } from "stream"; import { StartedNetwork } from "./network/network"; import { + ArchiveToCopy, BindMount, CommitOptions, ContentToCopy, @@ -44,6 +45,7 @@ export interface TestContainer { withCopyFilesToContainer(filesToCopy: FileToCopy[]): this; withCopyDirectoriesToContainer(directoriesToCopy: DirectoryToCopy[]): this; withCopyContentToContainer(contentsToCopy: ContentToCopy[]): this; + withCopyArchivesToContainer(archivesToCopy: ArchiveToCopy[]): this; withWorkingDir(workingDir: string): this; withResourcesQuota(resourcesQuota: ResourcesQuota): this; @@ -77,6 +79,7 @@ export interface StartedTestContainer { getNetworkId(networkName: string): string; getIpAddress(networkName: string): string; copyArchiveFromContainer(path: string): Promise; + copyArchiveToContainer(tar: Readable, target?: string): Promise; copyDirectoriesToContainer(directoriesToCopy: DirectoryToCopy[]): Promise; copyFilesToContainer(filesToCopy: FileToCopy[]): Promise; copyContentToContainer(contentsToCopy: ContentToCopy[]): Promise; diff --git a/packages/testcontainers/src/types.ts b/packages/testcontainers/src/types.ts index 5d078eb73..6b5961326 100644 --- a/packages/testcontainers/src/types.ts +++ b/packages/testcontainers/src/types.ts @@ -39,6 +39,11 @@ export type ContentToCopy = { mode?: number; }; +export type ArchiveToCopy = { + tar: Readable; + target: string; +}; + export type TmpFs = { [dir in string]: string }; export type Ulimits = { [name: string]: { hard: number | undefined; soft: number | undefined } };