Skip to content

Commit ac4a047

Browse files
authored
Merge branch 'master' into docker_windows_paths
2 parents 2077e91 + ee990d7 commit ac4a047

9 files changed

+118
-46
lines changed

.editorconfig

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
root = true
2+
3+
[*]
4+
end_of_line = lf
5+
insert_final_newline = true
6+
7+
[*.{js,json,yml}]
8+
charset = utf-8
9+
10+
[*.js]
11+
indent_style = space
12+
indent_size = 2
13+
14+
[package.json]
15+
indent_style = space
16+
indent_size = 2

.gitattributes

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.js text eol=lf
2+
*.json text eol=lf

README.md

+8
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,14 @@ custom:
119119
- .requirements-cache
120120
```
121121

122+
When using `--cache-dir` don't forget to also exclude it from the package.
123+
124+
```yaml
125+
package:
126+
exclude:
127+
- .requirements-cache/**
128+
```
129+
122130
### Customize requirements file name
123131
[Some `pip` workflows involve using requirements files not named
124132
`requirements.txt`](https://www.kennethreitz.org/essays/a-better-pip-workflow).

circle.yml

+4-2
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ jobs:
1313
- run: python3.6 -m pip install pipenv
1414
# install nodejs
1515
- run: curl -sL https://deb.nodesource.com/setup_6.x | bash - && apt -y install nodejs
16-
# install serverless
17-
- run: npm install -g serverless
16+
# install serverless & depcheck
17+
- run: npm install -g serverless depcheck
1818
# install deps
1919
- run: npm i
20+
# depcheck
21+
- run: depcheck .
2022
# lint:
2123
- run: npm run lint
2224
# test!

lib/docker.js

+52-19
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ function dockerCommand(options) {
1818
throw new Error(ps.stderr);
1919
}
2020
return ps;
21-
}
21+
};
2222

2323
/**
2424
* Build the custom Docker image
@@ -34,34 +34,67 @@ function buildImage(dockerFile) {
3434
return imageName;
3535
};
3636

37+
/**
38+
* Test bind path to make sure it's working
39+
* @param {string} bindPath
40+
* @return {boolean}
41+
*/
42+
function tryBindPath(bindPath) {
43+
const options = ['run', '--rm', '-v', `${bindPath}:/test`,
44+
'alpine', 'ls', '/test/serverless.yml'];
45+
try {
46+
const ps = dockerCommand(options);
47+
return ps.stdout.trim() === '/test/serverless.yml';
48+
} catch (err) {
49+
return false;
50+
}
51+
};
52+
3753
/**
3854
* Get bind path depending on os platform
3955
* @param {string} servicePath
4056
* @return {string} The bind path.
4157
*/
4258
function getBindPath(servicePath) {
43-
// Determine os platform of docker CLI from 'docker version'
44-
const options = ['version', '--format', '{{with .Client}}{{.Os}}{{end}}'];
45-
const ps = dockerCommand(options);
46-
const cliPlatform = ps.stdout.trim();
47-
4859
// Determine bind path
49-
let bindPath;
50-
if (process.platform === 'win32') {
51-
bindPath = servicePath.replace(/\\([^\s])/g, '/$1');
52-
if (cliPlatform === 'windows') {
53-
bindPath = bindPath.replace(/^\/(\w)\//i, '$1:/');
54-
}
55-
} else if (isWsl) {
56-
bindPath = servicePath.replace(/^\/mnt\//, '/');
57-
if (cliPlatform === 'windows') {
58-
bindPath = bindPath.replace(/^\/(\w)\//i, '$1:/');
59-
}
60+
if (process.platform !== 'win32' && !isWsl) {
61+
return servicePath;
62+
}
63+
64+
let bindPaths = [];
65+
let baseBindPath = servicePath.replace(/\\([^\s])/g, '/$1');
66+
let drive;
67+
let path;
68+
69+
bindPaths.push(baseBindPath);
70+
if (baseBindPath.startsWith('/mnt/')) { // cygwin "/mnt/C/users/..."
71+
baseBindPath = baseBindPath.replace(/^\/mnt\//, '/');
72+
}
73+
if (baseBindPath[1] == ':') { // normal windows "c:/users/..."
74+
drive = baseBindPath[0];
75+
path = baseBindPath.substring(3);
76+
} else if (baseBindPath[0] == '/' && baseBindPath[2] == '/') { // gitbash "/c/users/..."
77+
drive = baseBindPath[1];
78+
path = baseBindPath.substring(3);
6079
} else {
61-
bindPath = servicePath;
80+
throw new Error(`Unknown path format ${baseBindPath.substr(10)}...`);
81+
}
82+
83+
bindPaths.push(`/${drive.toLowerCase()}/${path}`);
84+
bindPaths.push(`/${drive.toUpperCase()}/${path}`);
85+
bindPaths.push(`/mnt/${drive.toLowerCase()}/${path}`);
86+
bindPaths.push(`/mnt/${drive.toUpperCase()}/${path}`);
87+
bindPaths.push(`${drive.toLowerCase()}:/${path}`);
88+
bindPaths.push(`${drive.toUpperCase()}:/${path}`);
89+
90+
for (let i = 0; i < bindPaths.length; i++) {
91+
const bindPath = bindPaths[i];
92+
if (tryBindPath(bindPath)) {
93+
return bindPath;
94+
}
6295
}
6396

64-
return bindPath;
97+
throw new Error('Unable to find good bind path format');
6598
};
6699

67100
module.exports = {buildImage, getBindPath};

lib/link.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ function makeSymlink(source, target) {
1616
try {
1717
fse.symlinkSync(source, target);
1818
} catch (exception) {
19-
if (exception.code === 'EPERM' && process.platform !== 'win32') {
19+
if (exception.code === 'EPERM' && process.platform === 'win32') {
2020
fse.copySync(source, target);
2121
} else {
2222
let linkDest = null;
@@ -36,14 +36,14 @@ function makeSymlink(source, target) {
3636
* @param {string} sourceFolder
3737
* @param {string} targetFolder
3838
* @param {boolean} isPython
39-
* @param {Object} package
39+
* @param {Object} packageObj
4040
* @param {Object} serverless
4141
* @param {string} servicePath
4242
* @param {Object} options
4343
* @return {undefined}
4444
*/
4545
function linkRequirements(
46-
sourceFolder, targetFolder, isPython, package, serverless, servicePath, options
46+
sourceFolder, targetFolder, isPython, packageObj, serverless, servicePath, options
4747
) {
4848
const requirementsDir = path.join(servicePath, sourceFolder);
4949
if (fse.existsSync('__pycache__')) {
@@ -59,12 +59,12 @@ function linkRequirements(
5959

6060
// don't include python deps in non-python functions
6161
if (isPython) {
62-
if (!package.exclude.includes(file)) {
63-
package.include.push(file);
64-
package.include.push(`${file}/**`);
62+
if (!packageObj.exclude.includes(file)) {
63+
packageObj.include.push(file);
64+
packageObj.include.push(`${file}/**`);
6565
makeSymlink(`${requirementsDir}/${file}`, `${targetFolder}/${file}`);
6666
} else {
67-
package.exclude.push(`${file}/**`);
67+
packageObj.exclude.push(`${file}/**`);
6868
}
6969
}
7070
});

lib/pip.js

+18-10
Original file line numberDiff line numberDiff line change
@@ -22,26 +22,20 @@ function installRequirements(requirementsPath, targetFolder, serverless, service
2222
fse.ensureDirSync(targetRequirementsFolder);
2323

2424
const dotSlsReqs = path.join(targetFolder, 'requirements.txt');
25-
let fileName = requirementsPath;
2625
if (options.usePipenv && fse.existsSync(path.join(servicePath, 'Pipfile'))) {
27-
fileName = dotSlsReqs;
26+
generateRequirementsFile(dotSlsReqs, dotSlsReqs, options);
27+
} else {
28+
generateRequirementsFile(requirementsPath, dotSlsReqs, options);
2829
}
2930

3031
serverless.cli.log(`Installing requirements of ${requirementsPath} in ${targetFolder}...`);
3132

32-
// In case the requirements file is a symlink, copy it to targetFolder
33-
// if using docker to avoid errors
34-
if (options.dockerizePip && fileName !== dotSlsReqs) {
35-
fse.copySync(fileName, dotSlsReqs);
36-
fileName = dotSlsReqs;
37-
}
38-
3933
let cmd;
4034
let cmdOptions;
4135
let pipCmd = [
4236
options.pythonBin, '-m', 'pip', '--isolated', 'install',
4337
'-t', dockerPathForWin(options, targetRequirementsFolder),
44-
'-r', dockerPathForWin(options, fileName),
38+
'-r', dockerPathForWin(options, dotSlsReqs),
4539
...options.pipCmdExtraArgs,
4640
];
4741
if (!options.dockerizePip) {
@@ -136,6 +130,20 @@ function dockerPathForWin(options, path) {
136130
return path;
137131
}
138132

133+
/** create a filtered requirements.txt without anything from noDeploy
134+
* @param {string} source requirements
135+
* @param {string} target requirements where results are written
136+
* @param {Object} options
137+
*/
138+
function generateRequirementsFile(source, target, options) {
139+
const noDeploy = new Set(options.noDeploy || []);
140+
const requirements = fse.readFileSync(source, {encoding: 'utf-8'}).split(/\r?\n/);
141+
const filteredRequirements = requirements.filter((req) => {
142+
return !noDeploy.has(req.split(/[=<> \t]/)[0].trim());
143+
});
144+
fse.writeFileSync(target, filteredRequirements.join('\n'));
145+
}
146+
139147
/**
140148
* pip install the requirements to the .serverless/requirements directory
141149
* @return {undefined}

package.json

-3
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,8 @@
4646
"eslint-config-google": "^0.7.1"
4747
},
4848
"dependencies": {
49-
"archiver": "^1.3.0",
5049
"bluebird": "^3.0.6",
5150
"fs-extra": "^3.0.1",
52-
"glob-all": "^3.1.0",
53-
"graceful-fs": "^4.1.11",
5451
"is-wsl": "^1.1.0",
5552
"lodash.get": "^4.4.2",
5653
"lodash.set": "^4.3.2",

unzip_requirements.py

+11-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
import os
2+
import shutil
23
import sys
34
import zipfile
45

56

6-
zip_requirements = os.path.join(
7-
os.environ.get('LAMBDA_TASK_ROOT', os.getcwd()), '.requirements.zip')
7+
pkgdir = '/tmp/sls-py-req'
88

9-
tempdir = '/tmp/sls-py-req'
9+
sys.path.append(pkgdir)
1010

11-
sys.path.append(tempdir)
11+
if not os.path.exists(pkgdir):
12+
tempdir = '/tmp/_temp-sls-py-req'
13+
if os.path.exists(tempdir):
14+
shutil.rmtree(tempdir)
15+
16+
zip_requirements = os.path.join(
17+
os.environ.get('LAMBDA_TASK_ROOT', os.getcwd()), '.requirements.zip')
1218

13-
if not os.path.exists(tempdir):
1419
zipfile.ZipFile(zip_requirements, 'r').extractall(tempdir)
20+
os.rename(tempdir, pkgdir) # Atomic

0 commit comments

Comments
 (0)