Skip to content
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

Strange behaviour with fs-extra, archiver and mock-fs combination #349

Open
patrickdawson opened this issue Feb 14, 2022 · 1 comment
Open

Comments

@patrickdawson
Copy link

patrickdawson commented Feb 14, 2022

Hey there,

I have a strange problem with fs-extra, archiver and mock-fs in combination. I am running on node 16.13.2 but it seems to be broken on all nodejs 16 and 17 versions.

Here is the code example

const fs = require("fs-extra");
const { promisify } = require("util");
const { pipeline } = require("stream/promises");
const { setImmediate } = require("timers/promises");
const pEvent = require("p-event");
const archiver = require("archiver");
const StreamZip = require("node-stream-zip");
const mockfs = require("mock-fs");

async function unzip(filePath, targetDir) {
    const zip = new StreamZip({
        file: filePath,
        storeEntries: true,
    });
    const extract = promisify(zip.extract).bind(zip);

    await pEvent(zip, "ready");
    const count = await extract(null, targetDir);
    zip.close();
    return count;
}


async function main() {
    mockfs({
        "someFile.txt": "Content 1",
    });
    
    await setImmediate(); // without setImmediate no problem

    fileReadStream = fs.createReadStream("someFile.txt", { encoding: "utf-8" });
    const output = fs.createWriteStream("foo.zip");

    const archive = archiver("zip", {
        zlib: { level: 0 },
    });
    const pipelinePromise = pipeline(archive, output);
    const entryEvent = pEvent(archive, "entry");
    archive.append(fileReadStream, { name: "someFile.txt" });

    await entryEvent;
    await archive.finalize();
    await pipelinePromise;

    await unzip("foo.zip", ".");
};

main().catch(e => console.log(e));

With this code sample I get the following error: Invalid local header.

The error does NOT occur:

  • If I run the app without mock-fs and real files.
  • If I replace fs-extra with fs.
  • If I dont call setImmediate

Does anyone know what is going on here?

package.json

{
  "name": "archiver-and-mockfs",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "archiver": "5.3.0",
    "fs-extra": "10.0.0",
    "lodash": "4.17.21",
    "mock-fs": "5.1.2",
    "node-stream-zip": "1.15.0",
    "p-event": "4.2.0",
    "p-map": "4.0.0"
  }
}
@3cp
Copy link
Collaborator

3cp commented Mar 30, 2022

If nodejs v14 has no issue, it's related to the readstream timing breaking change in nodejs v16. We don't fully understand some side effect. I am particularly puzzled by the effect of await setImmediate();.
#338

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants