Skip to content

Preserve binary file permissions in zip #335

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

Merged
merged 1 commit into from
Mar 21, 2019
Merged
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
2 changes: 2 additions & 0 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ jobs:
sudo ./install.sh /usr/local
# other deps
- run: sudo apt -y update && sudo apt -y install python-pip python2.7 curl unzip
# upgrade python3.6 pip to latest
- run: sudo python3.6 -m pip install -U pip
# instal pipenv
- run: sudo python3.6 -m pip install pipenv pip-tools
# install poetry
Expand Down
7 changes: 6 additions & 1 deletion lib/inject.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,12 @@ function injectRequirements(requirementsPath, packagePath, options) {
!noDeploy.has(relativeFile.split(/([-\\/]|\.py$|\.pyc$)/, 1)[0])
)
.map(([file, relativeFile]) =>
zipFile(zip, relativeFile, fse.readFileAsync(file))
Promise.all([file, relativeFile, fse.statAsync(file)])
)
.map(([file, relativeFile, fileStat]) =>
zipFile(zip, relativeFile, fse.readFileAsync(file), {
unixPermissions: fileStat.mode
})
)
.then(() => writeZip(zip, packagePath))
);
Expand Down
19 changes: 14 additions & 5 deletions lib/zipTree.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,23 @@ function writeZip(zip, targetPath) {
* @param {string} zipPath the target path in the zip.
* @param {Promise} bufferPromise a promise providing a nodebuffer.
* @return {Promise} a promise providing the JSZip object.
* @param {object} fileOpts an object with the opts to save for the file in the zip.
*/
function zipFile(zip, zipPath, bufferPromise) {
function zipFile(zip, zipPath, bufferPromise, fileOpts) {
return bufferPromise
.then(buffer =>
zip.file(zipPath, buffer, {
// necessary to get the same hash when zipping the same content
date: new Date(0)
})
zip.file(
zipPath,
buffer,
Object.assign(
{},
{
// necessary to get the same hash when zipping the same content
date: new Date(0)
},
fileOpts
)
)
)
.then(() => zip);
}
Expand Down
27 changes: 25 additions & 2 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const {
readFileSync,
copySync,
writeFileSync,
statSync,
pathExistsSync
} = require('fs-extra');
const { quote } = require('shell-quote');
Expand Down Expand Up @@ -875,6 +876,12 @@ test(
'foobar has retained its executable file permissions'
);

const flaskPerm = statSync('.serverless/requirements/bin/flask').mode;
t.true(
zipfiles_with_metadata['bin/flask'].unixPermissions === flaskPerm,
'bin/flask has retained its executable file permissions'
);

t.end();
},
{ skip: process.platform === 'win32' }
Expand Down Expand Up @@ -1566,15 +1573,23 @@ test(
npm(['i', path]);
sls(['package']);

const zipfiles_hello = listZipFilesWithMetaData('.serverless/hello1.zip');
const zipfiles_hello1 = listZipFilesWithMetaData('.serverless/hello1.zip');

t.true(
zipfiles_hello['module1/foobar'].unixPermissions
zipfiles_hello1['module1/foobar'].unixPermissions
.toString(8)
.slice(3, 6) === perm,
'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;

t.true(
zipfiles_hello2['bin/flask'].unixPermissions === flaskPerm,
'bin/flask has retained its executable file permissions'
);

t.end();
},
{ skip: process.platform === 'win32' }
Expand All @@ -1601,6 +1616,14 @@ 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;

t.true(
zipfiles_hello2['bin/flask'].unixPermissions === flaskPerm,
'bin/flask has retained its executable file permissions'
);

t.end();
},
{ skip: !canUseDocker() || process.platform === 'win32' }
Expand Down