Skip to content

Commit bf415be

Browse files
setu4993TikiTDO
authored andcommitted
fix(lambda-python): bundle asset files correctly (aws#18335)
Asset files are incorrectly being bundled under the `asset-input` directory instead of the root of the bundle. To also copy over hidden files (aws#18306 (comment)), I switched from using `-R` to `-a` based on what I found on [SO](https://stackoverflow.com/a/13020113) and the [man page](https://linux.die.net/man/1/cp). (`-a` is equivalent to `-dR`.) Fixes aws#18301 and @chrispykim's comment: aws#18082 (comment). ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 401caa7 commit bf415be

File tree

2 files changed

+35
-13
lines changed

2 files changed

+35
-13
lines changed

Diff for: packages/@aws-cdk/aws-lambda-python/lib/bundling.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ export class Bundling implements CdkBundlingOptions {
8787
if (packaging.dependenciesFile) {
8888
bundlingCommands.push(`python -m pip install -r ${DependenciesFile.PIP} -t ${options.outputDir}`);
8989
}
90-
bundlingCommands.push(`cp -R ${options.inputDir}/ ${options.outputDir}`);
90+
bundlingCommands.push(`cp -rT ${options.inputDir}/ ${options.outputDir}`);
9191
return bundlingCommands;
9292
}
9393
}

Diff for: packages/@aws-cdk/aws-lambda-python/test/bundling.test.ts

+34-12
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import * as fs from 'fs';
12
import * as path from 'path';
23
import { Architecture, Code, Runtime } from '@aws-cdk/aws-lambda';
34
import { DockerImage } from '@aws-cdk/core';
@@ -25,7 +26,7 @@ beforeEach(() => {
2526

2627
test('Bundling a function without dependencies', () => {
2728
const entry = path.join(__dirname, 'lambda-handler-nodeps');
28-
Bundling.bundle({
29+
const assetCode = Bundling.bundle({
2930
entry: entry,
3031
runtime: Runtime.PYTHON_3_7,
3132
architecture: Architecture.X86_64,
@@ -36,7 +37,7 @@ test('Bundling a function without dependencies', () => {
3637
bundling: expect.objectContaining({
3738
command: [
3839
'bash', '-c',
39-
'cp -R /asset-input/ /asset-output',
40+
'cp -rT /asset-input/ /asset-output',
4041
],
4142
}),
4243
}));
@@ -47,11 +48,14 @@ test('Bundling a function without dependencies', () => {
4748
}),
4849
platform: 'linux/amd64',
4950
}));
51+
52+
const files = fs.readdirSync(assetCode.path);
53+
expect(files).toContain('index.py');
5054
});
5155

5256
test('Bundling a function with requirements.txt', () => {
5357
const entry = path.join(__dirname, 'lambda-handler');
54-
Bundling.bundle({
58+
const assetCode = Bundling.bundle({
5559
entry: entry,
5660
runtime: Runtime.PYTHON_3_7,
5761
architecture: Architecture.X86_64,
@@ -62,10 +66,14 @@ test('Bundling a function with requirements.txt', () => {
6266
bundling: expect.objectContaining({
6367
command: [
6468
'bash', '-c',
65-
'python -m pip install -r requirements.txt -t /asset-output && cp -R /asset-input/ /asset-output',
69+
'python -m pip install -r requirements.txt -t /asset-output && cp -rT /asset-input/ /asset-output',
6670
],
6771
}),
6872
}));
73+
74+
const files = fs.readdirSync(assetCode.path);
75+
expect(files).toContain('index.py');
76+
expect(files).toContain('requirements.txt');
6977
});
7078

7179
test('Bundling Python 2.7 with requirements.txt installed', () => {
@@ -81,7 +89,7 @@ test('Bundling Python 2.7 with requirements.txt installed', () => {
8189
bundling: expect.objectContaining({
8290
command: [
8391
'bash', '-c',
84-
'python -m pip install -r requirements.txt -t /asset-output && cp -R /asset-input/ /asset-output',
92+
'python -m pip install -r requirements.txt -t /asset-output && cp -rT /asset-input/ /asset-output',
8593
],
8694
}),
8795
}));
@@ -101,7 +109,7 @@ test('Bundling a layer with dependencies', () => {
101109
bundling: expect.objectContaining({
102110
command: [
103111
'bash', '-c',
104-
'python -m pip install -r requirements.txt -t /asset-output/python && cp -R /asset-input/ /asset-output/python',
112+
'python -m pip install -r requirements.txt -t /asset-output/python && cp -rT /asset-input/ /asset-output/python',
105113
],
106114
}),
107115
}));
@@ -121,7 +129,7 @@ test('Bundling a python code layer', () => {
121129
bundling: expect.objectContaining({
122130
command: [
123131
'bash', '-c',
124-
'cp -R /asset-input/ /asset-output/python',
132+
'cp -rT /asset-input/ /asset-output/python',
125133
],
126134
}),
127135
}));
@@ -130,7 +138,7 @@ test('Bundling a python code layer', () => {
130138
test('Bundling a function with pipenv dependencies', () => {
131139
const entry = path.join(__dirname, 'lambda-handler-pipenv');
132140

133-
Bundling.bundle({
141+
const assetCode = Bundling.bundle({
134142
entry: path.join(entry, '.'),
135143
runtime: Runtime.PYTHON_3_9,
136144
architecture: Architecture.X86_64,
@@ -141,16 +149,23 @@ test('Bundling a function with pipenv dependencies', () => {
141149
bundling: expect.objectContaining({
142150
command: [
143151
'bash', '-c',
144-
'PIPENV_VENV_IN_PROJECT=1 pipenv lock -r > requirements.txt && rm -rf .venv && python -m pip install -r requirements.txt -t /asset-output/python && cp -R /asset-input/ /asset-output/python',
152+
'PIPENV_VENV_IN_PROJECT=1 pipenv lock -r > requirements.txt && rm -rf .venv && python -m pip install -r requirements.txt -t /asset-output/python && cp -rT /asset-input/ /asset-output/python',
145153
],
146154
}),
147155
}));
156+
157+
const files = fs.readdirSync(assetCode.path);
158+
expect(files).toContain('index.py');
159+
expect(files).toContain('Pipfile');
160+
expect(files).toContain('Pipfile.lock');
161+
// Contains hidden files.
162+
expect(files).toContain('.gitignore');
148163
});
149164

150165
test('Bundling a function with poetry dependencies', () => {
151166
const entry = path.join(__dirname, 'lambda-handler-poetry');
152167

153-
Bundling.bundle({
168+
const assetCode = Bundling.bundle({
154169
entry: path.join(entry, '.'),
155170
runtime: Runtime.PYTHON_3_9,
156171
architecture: Architecture.X86_64,
@@ -161,10 +176,17 @@ test('Bundling a function with poetry dependencies', () => {
161176
bundling: expect.objectContaining({
162177
command: [
163178
'bash', '-c',
164-
'poetry export --with-credentials --format requirements.txt --output requirements.txt && python -m pip install -r requirements.txt -t /asset-output/python && cp -R /asset-input/ /asset-output/python',
179+
'poetry export --with-credentials --format requirements.txt --output requirements.txt && python -m pip install -r requirements.txt -t /asset-output/python && cp -rT /asset-input/ /asset-output/python',
165180
],
166181
}),
167182
}));
183+
184+
const files = fs.readdirSync(assetCode.path);
185+
expect(files).toContain('index.py');
186+
expect(files).toContain('pyproject.toml');
187+
expect(files).toContain('poetry.lock');
188+
// Contains hidden files.
189+
expect(files).toContain('.gitignore');
168190
});
169191

170192
test('Bundling a function with custom bundling image', () => {
@@ -184,7 +206,7 @@ test('Bundling a function with custom bundling image', () => {
184206
image,
185207
command: [
186208
'bash', '-c',
187-
'python -m pip install -r requirements.txt -t /asset-output/python && cp -R /asset-input/ /asset-output/python',
209+
'python -m pip install -r requirements.txt -t /asset-output/python && cp -rT /asset-input/ /asset-output/python',
188210
],
189211
}),
190212
}));

0 commit comments

Comments
 (0)