Skip to content

Implement a prereqCmd option for installing system deps #103

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,16 @@ custom:
pythonBin: /opt/python3.6/bin/python
```

### Run Custom extra packaging scripts
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+### Run Custom extra packaging scripts

As a convenience method for if you need to install system dependencies for your python package you
can specify a command to do so. It honors the `dockerizePip` command so you can `yum install`
anything available in Amazon Linux if using that option. Example config:
```yaml
custom:
pythonRequirements:
prereqCmd: bash -c "yum install mysql-devel && cp /usr/lib64/mysql/libmysqlclient.so.18.0.0 ./libmysqlclient.so.18"
```

## Manual invocations

The `.requirements` and `requirements.zip`(if using zip support) files are left
Expand Down
2 changes: 2 additions & 0 deletions example/prereq
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
echo foobar > foobar
1 change: 1 addition & 0 deletions example/serverless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ custom:
zip: false
cleanupZipHelper: true
dockerizePip: false
prereqCmd: null

package:
exclude:
Expand Down
4 changes: 4 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const BbPromise = require('bluebird');
const fse = require('fs-extra');
const {addVendorHelper, removeVendorHelper, packRequirements} = require('./lib/zip');
const {installRequirements} = require('./lib/pip');
const {runPrereqCmd} = require('./lib/prereqCmd');
const {pipfileToRequirements} = require('./lib/pipenv');
const {linkRequirements, unlinkRequirements} = require('./lib/link');
const {cleanup} = require('./lib/clean');
Expand All @@ -30,6 +31,7 @@ class ServerlessPythonRequirements {
dockerizePip: false,
dockerImage: `lambci/lambda:build-${this.serverless.service.provider.runtime}`,
pipCmdExtraArgs: [],
prereqCmd: null,
noDeploy: [
'boto3',
'botocore',
Expand Down Expand Up @@ -80,6 +82,7 @@ class ServerlessPythonRequirements {
.then(pipfileToRequirements)
.then(addVendorHelper)
.then(installRequirements)
.then(runPrereqCmd)
.then(packRequirements)
.then(linkRequirements);

Expand All @@ -105,6 +108,7 @@ class ServerlessPythonRequirements {
'requirements:install:install': () => BbPromise.bind(this)
.then(pipfileToRequirements)
.then(addVendorHelper)
.then(runPrereqCmd)
.then(installRequirements)
.then(packRequirements),
'requirements:clean:clean': () => BbPromise.bind(this)
Expand Down
44 changes: 44 additions & 0 deletions lib/prereqCmd.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const fse = require('fs-extra');
const path = require('path');
const {spawnSync} = require('child_process');

/**
* run a prerequisite script if provided
* @return {Promise}
*/
function runPrereqCmd() {
const {prereqCmd} = this.options;
if (!prereqCmd)
return;
this.serverless.cli.log(`Running prerequisite script: ${prereqCmd}`);
let options = [];
if (this.options.dockerizePip) {
cmd = 'docker';
options = [
'run', '--rm',
'-v', `${this.servicePath}:/var/task:z`,
prereqCmd,
];
if (process.platform === 'linux')
options.push('-u', `${process.getuid()}:${process.getgid()}`);
options.push(this.options.dockerImage);
options.push(...pipCmd);
} else {
cmd = prereqCmd;
}
const res = spawnSync(`${cmd} ${options.join(' ')}`, {shell: true, cwd: this.servicePath});
if (res.error) {
if (res.error.code === 'ENOENT') {
if (this.options.dockerizePip) {
throw new Error('docker not found! Please install it.');
} else {
throw new Error(`${prereqCmd} not found!`);
}
}
throw new Error(res.error);
}
if (res.status != 0)
throw new Error(res.stderr);
};

module.exports = {runPrereqCmd};
15 changes: 15 additions & 0 deletions test.bats
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ setup() {
teardown() {
sls requirements clean
rm -rf puck node_modules
rm -f foobar
if [ -f serverless.yml.bak ]; then mv serverless.yml.bak serverless.yml; fi
}

Expand Down Expand Up @@ -148,3 +149,17 @@ teardown() {
unzip .serverless/sls-py-req-test.zip -d puck
ls puck/.requirements.zip puck/unzip_requirements.py
}

@test "py3.6 runs prereq script" {
sed -i'.bak' -e 's;prereqCmd: *null;prereqCmd: ./prereq;' serverless.yml
sls package
unzip .serverless/sls-py-req-test.zip -d puck
ls foobar
}

@test "py3.6 runs prereq command" {
sed -i'.bak' -e 's;prereqCmd: *null;prereqCmd: touch foobar;' serverless.yml
sls package
unzip .serverless/sls-py-req-test.zip -d puck
ls foobar
}