Skip to content

Commit ccfc3a2

Browse files
committed
chore: wip
1 parent 38200e4 commit ccfc3a2

9 files changed

Lines changed: 139 additions & 164 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.projenrc.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,12 @@ const project = new awscdk.AwsCdkConstructLibrary({
2929
jestOptions: {
3030
extraCliOptions: ['--testTimeout=300000'],
3131
},
32+
gitignore: [
33+
".vscode/",
34+
],
3235
eslint: false,
3336
});
37+
3438
const biomeWorkflow = project.github?.addWorkflow('biome');
3539
biomeWorkflow?.on({
3640
pullRequest: {

resources/Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
ARG IMAGE_ARCH=arm64 # or x86_64 (not amd64 as per Docker platform)
22
ARG UV_VERSION=0.5.27
33
ARG PYTHON_VERSION=3.12
4+
ARG BUNDLING_IMAGE=public.ecr.aws/sam/build-python${PYTHON_VERSION}:latest-${IMAGE_ARCH}
45
FROM ghcr.io/astral-sh/uv:${UV_VERSION} AS uv
5-
FROM public.ecr.aws/sam/build-python${PYTHON_VERSION}:latest-${IMAGE_ARCH}
6+
FROM ${BUNDLING_IMAGE}
67
# FROM public.ecr.aws/lambda/python:3.12-$IMAGE_ARCH
78
COPY --from=uv /uv /uvx /bin/
89
COPY *.sh /root

resources/entrypoint.sh

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,11 @@ rm -f $LOCK_FILE
1212
# Changing the default UV_LINK_MODE silences warnings about not being able to use hard links
1313
# since the cache and sync target may be on separate file systems.
1414
export UV_LINK_MODE=copy
15-
mkdir -p /src/uvbuild/uvcache
15+
mkdir -p /uvbuild/uvcache
1616
mkdir -p /root/.cache
17-
ln -sf /src/uvbuild/uvcache /root/.cache/uv
17+
ln -sf /uvbuild/uvcache /root/.cache/uv
1818

1919
# Set up overlay filesystem
20-
#mkdir -p /src/uvbuild/overlay/upper /src/uvbuild/overlay/work /src/uvbuild/overlay/merged
2120
mkdir -p /tmp/overlay
2221
mount -t tmpfs tmpfs /tmp/overlay
2322
mkdir -p /tmp/overlay/{upper,work,merged}

resources/export.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,16 @@ then
1717
exit 1
1818
fi
1919

20-
opts=$(getopt --name "$NAME" --options hpo:vd --longoptions help,package,output:,verbose,debug -- "$@") || print_help
20+
opts=$(getopt --name "$NAME" --options hp:o:vd --longoptions help,package:,output:,verbose,debug -- "$@") || print_help
2121
eval set -- "$opts"
2222

2323
declare package="" output="" verbose=0 debug=0
2424
while (($#))
2525
do
2626
case $1 in
2727
-h|--help) print_help;;
28-
-p|--package) package=$2; shift;;
29-
-o|--output) output=$2; shift;;
28+
-p|--package) package=$2; shift;;
29+
-o|--output) output=$2; shift;;
3030
-v|--verbose) ((++verbose));;
3131
-d|--debug) debug=1;;
3232
--) shift; break;;

src/build-container.ts

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ import { spawn, exec, spawnSync, execSync } from "node:child_process";
1111
*/
1212
export function runDockerContainerAndWait(name: string, args: string[], logLine: string): string {
1313
// kill any old container that might be running from previous builds
14-
// spawnSync("docker", ["rm", "-f", name]) TODO
14+
spawnSync("docker", ["rm", "-f", name])
1515
// Start the container in detached mode
16-
console.log("Spawning Docker container...", name, args);
16+
console.log("Spawning Docker container...", name, args, logLine);
1717
const dockerRun = spawnSync("docker", args);
1818
if (dockerRun.error) {
1919
console.error(`Failed to start Docker process: ${dockerRun.error}`);
@@ -32,9 +32,10 @@ export function runDockerContainerAndWait(name: string, args: string[], logLine:
3232
// Wait for the container to be running
3333
console.log("Waiting for container to be ready...");
3434
waitForContainer(containerId);
35-
console.log("Container is ready. Waiting for log line...");
36-
waitForLogLine(containerId, logLine);
37-
console.log("Log line found.");
35+
console.log("Container is ready");
36+
// waitForLogLine(containerId, logLine);
37+
// console.log("Log line found.");
38+
// TODO - rm -f container if it didn't run successfully
3839
return containerId;
3940
}
4041

@@ -48,6 +49,7 @@ function waitForContainer(containerId: string) {
4849
const stdout = execSync(`docker inspect -f '{{.State.Running}}' ${containerId}`)
4950
if (stdout.toString().trim() === "true") {
5051
console.log(`Container ${containerId} is running.`);
52+
sleep(60000);
5153
return;
5254
}
5355
console.log(`Container ${containerId} is not yet running.`);
@@ -62,32 +64,33 @@ function waitForContainer(containerId: string) {
6264
* @param containerId - The container ID.
6365
* @param logLine - The line to wait for.
6466
*/
65-
function waitForLogLine(containerId: string, logLine: string) {
66-
let attempts = 60;
67-
while (attempts > 0) {
68-
const logProcess = spawnSync("docker", ["logs", containerId]);
69-
if (logProcess.error) {
70-
const message = `Failed to get container logs: ${containerId} ${logProcess.error}`;
71-
console.error(message);
72-
throw new Error(message);
73-
}
74-
if (logProcess.status !== 0) {
75-
const message = `Docker process exited with code ${logProcess.status}, ${logProcess.stderr.toString()}`;
76-
console.error(message);
77-
throw new Error(message);
78-
}
67+
// function waitForLogLine(containerId: string, logLine: string) {
68+
// let attempts = 60;
69+
// while (attempts > 0) {
70+
// console.log(`Checking logs for ${containerId}... ${attempts} attempts remaining.`);
71+
// const logProcess = spawnSync("docker", ["logs", containerId]);
72+
// if (logProcess.error) {
73+
// const message = `Failed to get container logs: ${containerId} ${logProcess.error}`;
74+
// console.error(message);
75+
// throw new Error(message);
76+
// }
77+
// if (logProcess.status !== 0) {
78+
// const message = `Docker process exited with code ${logProcess.status}, ${logProcess.stderr.toString()}`;
79+
// console.error(message);
80+
// throw new Error(message);
81+
// }
7982

80-
const logs = logProcess.stdout.toString();
81-
console.log('LOGS', logs);
82-
if (logs.includes(logLine)) {
83-
return;
84-
}
85-
attempts--;
86-
sleep(1000);
87-
}
83+
// const logs = logProcess.stdout.toString();
84+
// console.log('LOGS', logs);
85+
// if (logs.includes(logLine)) {
86+
// return;
87+
// }
88+
// attempts--;
89+
// sleep(1000);
90+
// }
8891

89-
throw new Error(`Log line not found: ${logLine}`);
90-
}
92+
// throw new Error(`Log line not found: ${logLine}`);
93+
// }
9194

9295
/**
9396
* Stops the container.

src/bundling.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
type Runtime,
1616
} from 'aws-cdk-lib/aws-lambda';
1717
import type { BundlingOptions } from './types';
18+
import { mkdirSync } from 'node:fs';
1819

1920
export const HASHABLE_DEPENDENCIES_EXCLUDE = [
2021
'*.pyc',
@@ -93,8 +94,11 @@ export class Bundling {
9394
throw new Error("Bundling container not found");
9495
}
9596

97+
const hostFunctionOutputDir = `${process.env.CDK_OUTDIR}/${bundling.containerBuilderKey}/${bundling.functionOutDir}`;
98+
// mkdirSync(hostFunctionOutputDir, { recursive: true });
99+
96100
return Code.fromCustomCommand(
97-
options.rootDir,
101+
hostFunctionOutputDir,
98102
[
99103
"docker",
100104
"exec",
@@ -103,10 +107,10 @@ export class Bundling {
103107
"--package",
104108
options.workspacePackage ?? "uh-oh", // TODO - add support for root package
105109
"--output",
106-
bundling.functionOutDir,
110+
`/uvbuild/${bundling.functionOutDir}/`,
107111
],
108112
{
109-
assetHashType: AssetHashType.OUTPUT,
113+
assetHashType: AssetHashType.SOURCE,
110114
exclude: hashableAssetExclude,
111115
// bundling: new Bundling(bundlingOptions),
112116
});
@@ -185,29 +189,32 @@ export class Bundling {
185189

186190
// Create a hash of the props to use as a key for the build container cache
187191
this.containerBuilderKey = `uv-bundling-${hash(hashableProperties)}`;
188-
this.functionOutDir = `${this.containerBuilderKey}_${props.workspacePackage ?? "$$root"}`;
189-
192+
this.functionOutDir = props.workspacePackage ?? "";
190193
const existingBuilder = Bundling.containerBuilders[this.containerBuilderKey];
191194
if (!existingBuilder) {
192195
const buildImage = DockerImage.fromBuild(path.resolve(__dirname, '..', 'resources'), {
193196
buildArgs: {
194197
...props.buildArgs,
195198
IMAGE: props.runtime.bundlingImage.image,
196199
IMAGE_ARCH: props.architecture === Architecture.X86_64 ? 'x86_64' : 'arm64',
200+
PYTHON_VERSION: props.runtime.name.slice(6),
201+
BUNDLING_IMAGE: props.runtime.bundlingImage.image,
197202
},
198203
platform: (props.architecture ?? Architecture.ARM_64).dockerPlatform,
199204
});
200205

206+
const hostUvBuildDir = `${process.env.CDK_OUTDIR}/${this.containerBuilderKey}`;
207+
mkdirSync(hostUvBuildDir, { recursive: true });
208+
201209
// Spawn a docker run process in -d daemon mode using buildImage.image
202210
const dockerArgs = [
203211
"run",
204212
"-d",
205213
"--cap-add=SYS_ADMIN", // required for overlay fs
206214
"--name",
207215
this.containerBuilderKey,
208-
"--rm",
209216
"-v",
210-
`${process.env.CDK_OUTDIR}/${this.functionOutDir}:/uvbuild`,
217+
`${hostUvBuildDir}:/uvbuild`,
211218
"-v",
212219
`${props.rootDir}:/src`,
213220
buildImage.image,

src/function.ts

Lines changed: 2 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import * as fs from 'node:fs';
21
import * as path from 'node:path';
32
import { Stack } from 'aws-cdk-lib';
43
import {
@@ -96,46 +95,7 @@ export class PythonFunction extends Function {
9695
code,
9796
handler: resolvedHandler,
9897
});
99-
100-
if (skip) {
101-
return;
102-
}
103-
104-
const assetPath = (this.node.defaultChild as CfnFunction).getMetadata(
105-
'aws:asset:path',
106-
);
107-
if (!assetPath) {
108-
return;
109-
}
110-
111-
const codePath = path.join(process.env.CDK_OUTDIR as string, assetPath);
112-
const pythonPaths = getPthFilePaths(codePath);
113-
114-
if (pythonPaths.length > 0) {
115-
let pythonPathValue = environment.PYTHONPATH;
116-
const addedPaths = pythonPaths.join(':');
117-
pythonPathValue = pythonPathValue
118-
? `${pythonPathValue}:${addedPaths}`
119-
: addedPaths;
120-
this.addEnvironment('PYTHONPATH', pythonPathValue);
121-
}
122-
}
123-
}
124-
125-
function getPthFilePaths(basePath: string): string[] {
126-
const pthFiles = fs
127-
.readdirSync(basePath)
128-
.filter((file) => file.endsWith('.pth'));
129-
const pythonPaths: string[] = [];
130-
for (const pthFile of pthFiles) {
131-
const filePath = path.join(basePath, pthFile);
132-
const content = fs.readFileSync(filePath, 'utf-8');
133-
const dirs = content.split('\n').filter((line) => line.trim() !== '');
134-
pythonPaths.push(
135-
...dirs.map((dir) =>
136-
path.join('/var/task', path.relative('/asset-output', dir)),
137-
),
138-
);
98+
const assetRelPath = path.relative(process.env.CDK_OUTDIR ?? "", code.path);
99+
(this.node.defaultChild as CfnFunction).addMetadata('uv-python-lambda:asset-path', assetRelPath);
139100
}
140-
return pythonPaths;
141101
}

0 commit comments

Comments
 (0)