From 5ff8effc1b067b8b183c14ab39cccadd0be88cf1 Mon Sep 17 00:00:00 2001 From: Ben Lovy Date: Wed, 4 Dec 2024 11:57:55 -0500 Subject: [PATCH] refactor(std/image): use pre-sdk support tools --- packages/std/image.tg.ts | 10 +++--- packages/std/image/container.tg.ts | 53 ++++++++++++++++++++++------- packages/std/tangram.ts | 2 +- packages/std/utils/patch_cmds.tg.ts | 2 +- 4 files changed, 47 insertions(+), 20 deletions(-) diff --git a/packages/std/image.tg.ts b/packages/std/image.tg.ts index 488ba5ce..7aa487b6 100644 --- a/packages/std/image.tg.ts +++ b/packages/std/image.tg.ts @@ -48,16 +48,16 @@ export const testBasicRootfs = tg.target(async () => { return imageFile; }); -export const testOciBasicEnv = tg.target(async () => { +export const testBasicEnv = tg.target(async () => { const detectedHost = await std.triple.host(); const host = bootstrap.toolchainTriple(detectedHost); - const utils = await std.utils.env({ host, sdk: bootstrap.sdk.arg() }); - const basicEnv = await std.env(utils, { NAME: "Tangram" }, { utils: true }); + const utils = await std.utils.env({ host, sdk: false, env: bootstrap.sdk() }); + const basicEnv = await std.env(utils, { NAME: "Tangram" }, { utils: false }); return basicEnv; }); export const testBasicEnvImageDocker = tg.target(async () => { - const basicEnv = await testOciBasicEnv(); + const basicEnv = await testBasicEnv(); const imageFile = await image(basicEnv, { cmd: ["bash"], }); @@ -65,7 +65,7 @@ export const testBasicEnvImageDocker = tg.target(async () => { }); export const testBasicEnvImageOci = tg.target(async () => { - const basicEnv = await testOciBasicEnv(); + const basicEnv = await testBasicEnv(); const imageFile = await image(basicEnv, { cmd: ["bash"], format: "oci", diff --git a/packages/std/image/container.tg.ts b/packages/std/image/container.tg.ts index ac63463a..37bd092c 100644 --- a/packages/std/image/container.tg.ts +++ b/packages/std/image/container.tg.ts @@ -1,5 +1,5 @@ import * as std from "../tangram.ts"; -import { $ } from "../tangram.ts"; +import * as bootstrap from "../bootstrap.tg.ts"; import zstd from "../sdk/dependencies/zstd.tg.ts"; /* @@ -222,7 +222,7 @@ export const dockerImageFromLayers = async ( // Add each layer file to the image directory. const layerFilenames = await Promise.all( layers.map(async (layer) => { - const bytes = await layer.tar.bytes(); + const bytes = await layer.tarball.bytes(); const size = bytes.length; const checksum = await tg.checksum(bytes, "sha256"); const checksumValue = checksum.slice("sha256:".length); @@ -230,7 +230,7 @@ export const dockerImageFromLayers = async ( // Add the layer to the image directory, along with the legacy metadata used by older versions of the Docker image spec. image = tg.directory(image, { [checksumValue]: { - "layer.tar": layer.tar, + "layer.tar": layer.tarball, json: tg.encoding.json.encode({ // Use the checksum as a unique layer ID. id: checksumValue, @@ -269,7 +269,7 @@ export const dockerImageFromLayers = async ( }); // Create a `.tar` file of the Docker image. This is the format that `docker load` expects. - return await $`tar -cf $OUTPUT -C ${image} .`.then(tg.File.expect); + return await createTarball(image); }; export const ociImageFromLayers = async ( @@ -310,11 +310,24 @@ export const ociImageFromLayers = async ( layerCompression === "gzip" ? MediaTypeV1.imageLayerTarGzip : MediaTypeV1.imageLayerTarZstd; - const additionalEnv = layerCompression === "gzip" ? [] : [zstd()]; + const additionalEnv: tg.Unresolved> = [ + std.utils.env({ sdk: false, env: bootstrap.sdk() }), + ]; + if (layerCompression === "zstd") { + additionalEnv.push( + zstd({ + sdk: false, + env: await std.env.arg(additionalEnv, bootstrap.sdk()), + }), + ); + } const layerDescriptors = await Promise.all( layers.map(async (layer) => { - const file = await $`${compressionCmd} $(realpath ${layer.tar}) > $OUTPUT` - .env(additionalEnv) + const file = await tg + .target(tg`${compressionCmd} $(realpath ${layer.tarball}) > $OUTPUT`, { + env: std.env.arg(additionalEnv), + }) + .then((target) => target.output()) .then(tg.File.expect); const descriptor: ImageDescriptor = { mediaType, @@ -359,7 +372,7 @@ export const ociImageFromLayers = async ( }); // Tar the result and return it. - return await $`tar -cf $OUTPUT -C ${directory} .`.then(tg.File.expect); + return await createTarball(directory); }; /** @@ -386,17 +399,31 @@ type ImageDescriptor = { }; export type Layer = { - tar: tg.File; + tarball: tg.File; diffId: string; }; export const layer = tg.target( async (directory: tg.Directory): Promise => { - const bundle = tg.Artifact.bundle(directory); - const tar = await $`tar -cf $OUTPUT -C ${bundle} .`.then(tg.File.expect); - const bytes = await tar.bytes(); + const bundle = tg.Artifact.bundle(directory).then(tg.Directory.expect); + const tarball = await createTarball(bundle); + const bytes = await tarball.bytes(); const diffId = await tg.checksum(bytes, "sha256"); - return { tar, diffId }; + return { tarball, diffId }; + }, +); + +export const createTarball = tg.target( + async (directory: tg.Directory): Promise => { + const tarArtifact = await std.utils.tar.build({ + sdk: false, + env: bootstrap.sdk(), + }); + const script = tg`tar -cf $OUTPUT -C ${directory} .`; + return await tg + .target(script, { env: await std.env.arg(tarArtifact) }) + .then((target) => target.output()) + .then(tg.File.expect); }, ); diff --git a/packages/std/tangram.ts b/packages/std/tangram.ts index 53ae839e..5cab2eed 100644 --- a/packages/std/tangram.ts +++ b/packages/std/tangram.ts @@ -145,7 +145,7 @@ const testActions = (): Record Promise> => { crossWorkspace: workspace.testCross, imageWrappedEntrypoint: image.testWrappedEntrypoint, imageBasicRootfs: image.testBasicRootfs, - imageBasicEnv: image.testOciBasicEnv, + imageBasicEnv: image.testBasicEnv, imageBasicEnvImageDocker: image.testBasicEnvImageDocker, imageBasicEnvImageOci: image.testBasicEnvImageOci, image: image.test, diff --git a/packages/std/utils/patch_cmds.tg.ts b/packages/std/utils/patch_cmds.tg.ts index 9ad1909f..5066a778 100644 --- a/packages/std/utils/patch_cmds.tg.ts +++ b/packages/std/utils/patch_cmds.tg.ts @@ -69,7 +69,7 @@ export const macOsPatchCmds = tg.target(async (arg?: Arg) => { const result = await tg .target(script, { host: std.triple.archAndOs(build), - env: std.env.arg(arg.env ?? {}, bootstrap.sdk.env()), + env: std.env.arg(arg?.env ?? {}, bootstrap.sdk.env()), }) .then((target) => target.output()) .then(tg.Directory.expect);