-
Notifications
You must be signed in to change notification settings - Fork 3.9k
/
bundling.ts
154 lines (138 loc) · 4.79 KB
/
bundling.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import * as path from 'path';
import { Architecture, AssetCode, Code, Runtime } from 'aws-cdk-lib/aws-lambda';
import { AssetStaging, BundlingFileAccess, BundlingOptions as CdkBundlingOptions, DockerImage, DockerVolume } from 'aws-cdk-lib/core';
import { Packaging, DependenciesFile } from './packaging';
import { BundlingOptions, ICommandHooks } from './types';
/**
* Dependency files to exclude from the asset hash.
*/
export const DEPENDENCY_EXCLUDES = ['*.pyc'];
/**
* The location in the image that the bundler image caches dependencies.
*/
export const BUNDLER_DEPENDENCIES_CACHE = '/var/dependencies';
/**
* Options for bundling
*/
export interface BundlingProps extends BundlingOptions {
/**
* Entry path
*/
readonly entry: string;
/**
* The runtime environment.
*/
readonly runtime: Runtime;
/**
* The system architecture of the lambda function
*
* @default Architecture.X86_64
*/
readonly architecture?: Architecture;
/**
* Whether or not the bundling process should be skipped
*
* @default - Does not skip bundling
*/
readonly skip?: boolean;
/**
* Which option to use to copy the source files to the docker container and output files back
* @default - BundlingFileAccess.BIND_MOUNT
*/
bundlingFileAccess?: BundlingFileAccess;
}
/**
* Produce bundled Lambda asset code
*/
export class Bundling implements CdkBundlingOptions {
public static bundle(options: BundlingProps): AssetCode {
return Code.fromAsset(options.entry, {
assetHash: options.assetHash,
assetHashType: options.assetHashType,
exclude: DEPENDENCY_EXCLUDES,
bundling: options.skip ? undefined : new Bundling(options),
});
}
public readonly image: DockerImage;
public readonly entrypoint?: string[]
public readonly command: string[];
public readonly volumes?: DockerVolume[];
public readonly volumesFrom?: string[];
public readonly environment?: { [key: string]: string };
public readonly workingDirectory?: string;
public readonly user?: string;
public readonly securityOpt?: string;
public readonly network?: string;
public readonly bundlingFileAccess?: BundlingFileAccess;
constructor(props: BundlingProps) {
const {
entry,
runtime,
architecture = Architecture.X86_64,
outputPathSuffix = '',
image,
poetryIncludeHashes,
poetryWithoutUrls,
commandHooks,
assetExcludes = [],
} = props;
const outputPath = path.posix.join(AssetStaging.BUNDLING_OUTPUT_DIR, outputPathSuffix);
const bundlingCommands = this.createBundlingCommand({
entry,
inputDir: AssetStaging.BUNDLING_INPUT_DIR,
outputDir: outputPath,
poetryIncludeHashes,
poetryWithoutUrls,
commandHooks,
assetExcludes,
});
this.image = image ?? DockerImage.fromBuild(path.join(__dirname, '..', 'lib'), {
buildArgs: {
...props.buildArgs,
IMAGE: runtime.bundlingImage.image,
},
platform: architecture.dockerPlatform,
});
this.command = props.command ?? ['bash', '-c', chain(bundlingCommands)];
this.entrypoint = props.entrypoint;
this.volumes = props.volumes;
this.volumesFrom = props.volumesFrom;
this.environment = props.environment;
this.workingDirectory = props.workingDirectory;
this.user = props.user;
this.securityOpt = props.securityOpt;
this.network = props.network;
this.bundlingFileAccess = props.bundlingFileAccess;
}
private createBundlingCommand(options: BundlingCommandOptions): string[] {
const packaging = Packaging.fromEntry(options.entry, options.poetryIncludeHashes, options.poetryWithoutUrls);
let bundlingCommands: string[] = [];
bundlingCommands.push(...options.commandHooks?.beforeBundling(options.inputDir, options.outputDir) ?? []);
const exclusionStr = options.assetExcludes?.map(item => `--exclude='${item}'`).join(' ');
bundlingCommands.push([
'rsync', '-rLv', exclusionStr ?? '', `${options.inputDir}/`, options.outputDir,
].filter(item => item).join(' '));
bundlingCommands.push(`cd ${options.outputDir}`);
bundlingCommands.push(packaging.exportCommand ?? '');
if (packaging.dependenciesFile) {
bundlingCommands.push(`python -m pip install -r ${DependenciesFile.PIP} -t ${options.outputDir}`);
}
bundlingCommands.push(...options.commandHooks?.afterBundling(options.inputDir, options.outputDir) ?? []);
return bundlingCommands;
}
}
interface BundlingCommandOptions {
readonly entry: string;
readonly inputDir: string;
readonly outputDir: string;
readonly assetExcludes?: string[];
readonly poetryIncludeHashes?: boolean;
readonly poetryWithoutUrls?: boolean;
readonly commandHooks?: ICommandHooks;
}
/**
* Chain commands
*/
function chain(commands: string[]): string {
return commands.filter(c => !!c).join(' && ');
}