Skip to content

Commit

Permalink
fix: preserve mtime when zipping with the node zipper
Browse files Browse the repository at this point in the history
This means it's possible for code to retrieve the correct mtime, for
example to return in a `Last-Modified` header.

Since we have a test which verifies a checksum of a zip file created by
this function, we can be sure the results are deterministic. To support
this, update the test inputs to have specified mtimes.
  • Loading branch information
iainlane committed May 25, 2024
1 parent 7dc3b64 commit 8446c7a
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 17 deletions.
40 changes: 32 additions & 8 deletions src/tests/util.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,29 @@ describe('utils/findProjectRoot', () => {
});

describe('utils/zip', () => {
const mtime = new Date(2024, 0, 1, 0, 0, 0, 0);

beforeEach(() => {
mockFs({
'/src': {
'test.txt': 'lorem ipsum',
modules: {
'module.txt': 'lorem ipsum 2',
'/src': mockFs.directory({
mtime,
items: {
'test.txt': mockFs.file({
mtime,
content: 'lorem ipsum',
}),
modules: mockFs.directory({
mtime,
items: {
'module.txt': mockFs.file({
mtime,
content: 'lorem ipsum 2',
}),
},
}),
},
},
'/dist': {},
}),
'/dist': mockFs.directory({ mtime }),
});
});

Expand Down Expand Up @@ -67,7 +81,17 @@ describe('utils/zip', () => {
},
];

await zip(zipPath, filesPathList, useNativeZip);
// Check the mtimes are set correctly
const sourceStat = fs.statSync(source);
expect(sourceStat.mtime).toEqual(mtime);

const testStat = fs.statSync('/src/test.txt');
expect(testStat.mtime).toEqual(mtime);

const moduleStat = fs.statSync('/src/modules/module.txt');
expect(moduleStat.mtime).toEqual(mtime);

await expect(zip(zipPath, filesPathList, useNativeZip)).resolves.toBeUndefined();

expect(fs.existsSync(zipPath)).toEqual(true);

Expand All @@ -81,7 +105,7 @@ describe('utils/zip', () => {
if (!useNativeZip) {
const data = fs.readFileSync(zipPath);
const fileHash = crypto.createHash('sha256').update(data).digest('base64');
expect(fileHash).toEqual('iCZdyHJ7ON2LLwBIE6gQmRvBTzXBogSqJTMvHSenzGk=');
expect(fileHash).toEqual('PHu2gv7OIMv+lAOCXYPNd30X8/7EKYTuV7KYJjw3Qd4=');
}
}
);
Expand Down
18 changes: 9 additions & 9 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
import { bestzip } from 'bestzip';
import archiver from 'archiver';
import execa from 'execa';
import { pipe } from 'fp-ts/lib/function';
import * as IO from 'fp-ts/lib/IO';
import * as IOO from 'fp-ts/lib/IOOption';
import * as TE from 'fp-ts/lib/TaskEither';
import fs from 'fs-extra';
import path from 'path';
import os from 'os';

import type { IFile, IFiles } from './types';
import {
copyTask,
mkdirpTask,
Expand All @@ -18,7 +12,13 @@ import {
taskFromPromise,
} from './utils/fp-fs';

import type { IFile, IFiles } from './types';
import archiver from 'archiver';
import { bestzip } from 'bestzip';
import execa from 'execa';
import fs from 'fs-extra';
import os from 'os';
import path from 'path';
import { pipe } from 'fp-ts/lib/function';

export class SpawnError extends Error {
constructor(message: string, public stdout: string, public stderr: string) {
Expand Down Expand Up @@ -118,7 +118,7 @@ function nodeZip(zipPath: string, filesPathList: IFiles): Promise<void> {
zipArchive.append(fs.readFileSync(file.rootPath), {
name: file.localPath,
mode: stats.mode,
date: new Date(0), // necessary to get the same hash when zipping the same content
date: new Date(stats.mtime),
});
});

Expand Down

0 comments on commit 8446c7a

Please sign in to comment.