From 64631a503f50fe50fb54cd21bdcdeaa097fe3d0a Mon Sep 17 00:00:00 2001 From: Leavening Agent Date: Sun, 7 Apr 2019 09:35:13 -0700 Subject: [PATCH 1/3] Translate Pipfiles to Requirements in modules The plugin does not properly handle Pipfiles that sit in submodules since the pipenv integration does not anticipate submodules. This commit reworks the pipenv integration such that submodules are supported. This changes will convert Pipfiles into requirements as they are parsed by `pip.js` instead of doing it as a pre-processing step. This is done since the submodule discovery logic sits in pip.js. --- index.js | 2 -- lib/pip.js | 23 +++++++++++++---------- lib/pipenv.js | 23 ++++++++++++++--------- test.js | 14 ++++++++++---- 4 files changed, 37 insertions(+), 25 deletions(-) diff --git a/index.js b/index.js index b5200285..1df382b2 100644 --- a/index.js +++ b/index.js @@ -12,7 +12,6 @@ const { const { injectAllRequirements } = require('./lib/inject'); const { layerRequirements } = require('./lib/layer'); const { installAllRequirements } = require('./lib/pip'); -const { pipfileToRequirements } = require('./lib/pipenv'); const { pyprojectTomlToRequirements } = require('./lib/poetry'); const { cleanup, cleanupCache } = require('./lib/clean'); @@ -165,7 +164,6 @@ class ServerlessPythonRequirements { return; } return BbPromise.bind(this) - .then(pipfileToRequirements) .then(pyprojectTomlToRequirements) .then(addVendorHelper) .then(installAllRequirements) diff --git a/lib/pip.js b/lib/pip.js index 3da432af..49911f8c 100644 --- a/lib/pip.js +++ b/lib/pip.js @@ -13,6 +13,7 @@ const { getRequirementsWorkingPath, getUserCachePath } = require('./shared'); +const { pipfileToRequirements } = require('./pipenv'); /** * Omit empty commands. @@ -55,6 +56,7 @@ function mergeCommands(commands) { */ function generateRequirementsFile( requirementsPath, + modulePath, targetFile, serverless, servicePath, @@ -74,13 +76,10 @@ function generateRequirementsFile( ); } else if ( options.usePipenv && - fse.existsSync(path.join(servicePath, 'Pipfile')) + fse.existsSync(path.join(servicePath, modulePath, 'Pipfile')) ) { - filterRequirementsFile( - path.join(servicePath, '.serverless/requirements.txt'), - targetFile, - options - ); + pipfileToRequirements(modulePath, targetFile, serverless, options); + filterRequirementsFile(targetFile, targetFile, options); serverless.cli.log( `Parsed requirements.txt from Pipfile in ${targetFile}...` ); @@ -398,7 +397,7 @@ function copyVendors(vendorFolder, targetFolder, serverless) { * @param {Object} options * @param {string} fileName */ -function requirementsFileExists(servicePath, options, fileName) { +function requirementsFileExists(servicePath, modulePath, options) { if ( options.usePoetry && fse.existsSync(path.join(servicePath, 'pyproject.toml')) @@ -406,11 +405,14 @@ function requirementsFileExists(servicePath, options, fileName) { return true; } - if (options.usePipenv && fse.existsSync(path.join(servicePath, 'Pipfile'))) { + if ( + options.usePipenv && + fse.existsSync(path.join(servicePath, modulePath, 'Pipfile')) + ) { return true; } - if (fse.existsSync(fileName)) { + if (fse.existsSync(path.join(servicePath, modulePath, options.fileName))) { return true; } @@ -439,7 +441,7 @@ function installRequirementsIfNeeded( const fileName = path.join(servicePath, modulePath, options.fileName); // Skip requirements generation, if requirements file doesn't exist - if (!requirementsFileExists(servicePath, options, fileName)) { + if (!requirementsFileExists(servicePath, modulePath, options)) { return false; } @@ -459,6 +461,7 @@ function installRequirementsIfNeeded( generateRequirementsFile( fileName, + modulePath, slsReqsTxt, serverless, servicePath, diff --git a/lib/pipenv.js b/lib/pipenv.js index 6718844c..021250e2 100644 --- a/lib/pipenv.js +++ b/lib/pipenv.js @@ -6,23 +6,29 @@ const { EOL } = require('os'); /** * pipenv install */ -function pipfileToRequirements() { - if ( - !this.options.usePipenv || - !fse.existsSync(path.join(this.servicePath, 'Pipfile')) - ) { +function pipfileToRequirements( + modulePath, + outputRequirements, + serverless, + options +) { + const pipenvPath = path.join(modulePath, 'Pipfile'); + + // Stop if Pipfile file does not exist + if (!options.usePipenv || !fse.existsSync(pipenvPath)) { return; } - this.serverless.cli.log('Generating requirements.txt from Pipfile...'); + serverless.cli.log('Generating requirements.txt from Pipfile...'); const res = spawnSync( 'pipenv', ['lock', '--requirements', '--keep-outdated'], { - cwd: this.servicePath + cwd: modulePath } ); + if (res.error) { if (res.error.code === 'ENOENT') { throw new Error( @@ -34,9 +40,8 @@ function pipfileToRequirements() { if (res.status !== 0) { throw new Error(res.stderr); } - fse.ensureDirSync(path.join(this.servicePath, '.serverless')); fse.writeFileSync( - path.join(this.servicePath, '.serverless/requirements.txt'), + outputRequirements, removeEditableFlagFromRequirementsString(res.stdout) ); } diff --git a/test.js b/test.js index 78f60aad..d0e89dab 100644 --- a/test.js +++ b/test.js @@ -1582,8 +1582,11 @@ test( 'foobar has retained its executable file permissions' ); - const zipfiles_hello2 = listZipFilesWithMetaData('.serverless/module2-sls-py-req-test-indiv-dev-hello2.zip'); - const flaskPerm = statSync('.serverless/module2/requirements/bin/flask').mode; + const zipfiles_hello2 = listZipFilesWithMetaData( + '.serverless/module2-sls-py-req-test-indiv-dev-hello2.zip' + ); + const flaskPerm = statSync('.serverless/module2/requirements/bin/flask') + .mode; t.true( zipfiles_hello2['bin/flask'].unixPermissions === flaskPerm, @@ -1616,8 +1619,11 @@ test( 'foobar has retained its executable file permissions' ); - const zipfiles_hello2 = listZipFilesWithMetaData('.serverless/module2-sls-py-req-test-indiv-dev-hello2.zip'); - const flaskPerm = statSync('.serverless/module2/requirements/bin/flask').mode; + const zipfiles_hello2 = listZipFilesWithMetaData( + '.serverless/module2-sls-py-req-test-indiv-dev-hello2.zip' + ); + const flaskPerm = statSync('.serverless/module2/requirements/bin/flask') + .mode; t.true( zipfiles_hello2['bin/flask'].unixPermissions === flaskPerm, From d84ed9f09f72440ee52d589ace24ee9e72a75f0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20Garc=C3=ADa?= <673420+palmerabollo@users.noreply.github.com> Date: Sun, 21 Apr 2019 12:27:46 +0200 Subject: [PATCH 2/3] docs: fix minor typo in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 37254fd3..4f34a38f 100644 --- a/README.md +++ b/README.md @@ -198,7 +198,7 @@ custom: pythonRequirements: layer: name: ${self:provider.stage}-layerName - description: Python requirements lamba layer + description: Python requirements lambda layer compatibleRuntimes: - python3.7 licenseInfo: GPLv3 From ebae488086721cedeb74f7b2069e87c40bdd51f6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Tue, 23 Apr 2019 10:14:33 +0000 Subject: [PATCH 3/3] Update is-wsl requirement from ^1.1.0 to ^2.0.0 Updates the requirements on [is-wsl](https://github.com/sindresorhus/is-wsl) to permit the latest version. - [Release notes](https://github.com/sindresorhus/is-wsl/releases) - [Commits](https://github.com/sindresorhus/is-wsl/compare/v1.1.0...v2.0.0) Signed-off-by: dependabot[bot] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e105fead..4fc4f0de 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "bluebird": "^3.0.6", "fs-extra": "^7.0.0", "glob-all": "^3.1.0", - "is-wsl": "^1.1.0", + "is-wsl": "^2.0.0", "jszip": "^3.1.0", "lodash.get": "^4.4.2", "lodash.set": "^4.3.2",