Skip to content

Commit 841f090

Browse files
committed
Implement a prereqCmd option for installing system deps
closes #101
1 parent f2c1119 commit 841f090

File tree

6 files changed

+70
-0
lines changed

6 files changed

+70
-0
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,16 @@ custom:
113113
pythonBin: /opt/python3.6/bin/python
114114
```
115115

116+
### Run Custom extra packaging scripts
117+
As a convenience method for if you need to install system dependencies for your python package you
118+
can specify a command to do so. It honors the `dockerizePip` command so you can `yum install`
119+
anything available in Amazon Linux if using that option. Example config:
120+
```yaml
121+
custom:
122+
pythonRequirements:
123+
prereqCmd: bash -c "yum install mysql-devel && cp /usr/lib64/mysql/libmysqlclient.so.18.0.0 ./libmysqlclient.so.18"
124+
```
125+
116126
## Manual invocations
117127

118128
The `.requirements` and `requirements.zip`(if using zip support) files are left

example/prereq

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/bin/bash
2+
echo foobar > foobar

example/serverless.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ custom:
1111
zip: false
1212
cleanupZipHelper: true
1313
dockerizePip: false
14+
prereqCmd: null
1415

1516
package:
1617
exclude:

index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const BbPromise = require('bluebird');
55
const fse = require('fs-extra');
66
const {addVendorHelper, removeVendorHelper, packRequirements} = require('./lib/zip');
77
const {installRequirements} = require('./lib/pip');
8+
const {runPrereqCmd} = require('./lib/prereqCmd');
89
const {pipfileToRequirements} = require('./lib/pipenv');
910
const {linkRequirements, unlinkRequirements} = require('./lib/link');
1011
const {cleanup} = require('./lib/clean');
@@ -30,6 +31,7 @@ class ServerlessPythonRequirements {
3031
dockerizePip: false,
3132
dockerImage: `lambci/lambda:build-${this.serverless.service.provider.runtime}`,
3233
pipCmdExtraArgs: [],
34+
prereqCmd: null,
3335
noDeploy: [
3436
'boto3',
3537
'botocore',
@@ -80,6 +82,7 @@ class ServerlessPythonRequirements {
8082
.then(pipfileToRequirements)
8183
.then(addVendorHelper)
8284
.then(installRequirements)
85+
.then(runPrereqCmd)
8386
.then(packRequirements)
8487
.then(linkRequirements);
8588

@@ -105,6 +108,7 @@ class ServerlessPythonRequirements {
105108
'requirements:install:install': () => BbPromise.bind(this)
106109
.then(pipfileToRequirements)
107110
.then(addVendorHelper)
111+
.then(runPrereqCmd)
108112
.then(installRequirements)
109113
.then(packRequirements),
110114
'requirements:clean:clean': () => BbPromise.bind(this)

lib/prereqCmd.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
const fse = require('fs-extra');
2+
const path = require('path');
3+
const {spawnSync} = require('child_process');
4+
5+
/**
6+
* run a prerequisite script if provided
7+
* @return {Promise}
8+
*/
9+
function runPrereqCmd() {
10+
const {prereqCmd} = this.options;
11+
this.serverless.cli.log(`Running prerequisite script: ${prereqCmd}`);
12+
if (!prereqCmd)
13+
return;
14+
this.serverless.cli.log(`Running prerequisite script: ${prereqCmd}`);
15+
let options = [];
16+
if (this.options.dockerizePip) {
17+
cmd = 'docker';
18+
options = [
19+
'run', '--rm',
20+
'-v', `${this.servicePath}:/var/task:z`,
21+
prereqCmd,
22+
];
23+
if (process.platform === 'linux')
24+
options.push('-u', `${process.getuid()}:${process.getgid()}`);
25+
options.push(this.options.dockerImage);
26+
options.push(...pipCmd);
27+
} else {
28+
cmd = prereqCmd;
29+
}
30+
const res = spawnSync(cmd, options, {cwd: this.servicePath});
31+
if (res.error) {
32+
if (res.error.code === 'ENOENT') {
33+
if (this.options.dockerizePip) {
34+
throw new Error('docker not found! Please install it.');
35+
} else {
36+
throw new Error(`${prereqCmd} not found!`);
37+
}
38+
}
39+
throw new Error(res.error);
40+
}
41+
if (res.status != 0)
42+
throw new Error(res.stderr);
43+
};
44+
45+
module.exports = {runPrereqCmd};

test.bats

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ setup() {
1414
teardown() {
1515
sls requirements clean
1616
rm -rf puck node_modules
17+
rm -f foobar
1718
if [ -f serverless.yml.bak ]; then mv serverless.yml.bak serverless.yml; fi
1819
}
1920

@@ -148,3 +149,10 @@ teardown() {
148149
unzip .serverless/sls-py-req-test.zip -d puck
149150
ls puck/.requirements.zip puck/unzip_requirements.py
150151
}
152+
153+
@test "py3.6 runs prereq script" {
154+
sed -i'.bak' -e 's;prereqCmd: *null;prereqCmd: ./prereq;' serverless.yml
155+
sls package
156+
unzip .serverless/sls-py-req-test.zip -d puck
157+
ls foobar
158+
}

0 commit comments

Comments
 (0)