Skip to content

transferManager.downloadManyFiles not writing files locally #2200

@hochoy

Description

@hochoy

Issue summary

I hesitated to split this into 2 issues because they are rather tightly coupled

  1. Issue 1: When prefix is not set, transferManager.downloadManyFiles does not actually write files locally. This is because destination is undefined.
  2. Related issue 2: When prefix is set, file.download(...) attempts to write the file, but is unable to recursively create directory structure on local machine.

Proposed draft PR

#2199

Standard questions

  1. Is this a client library issue or a product issue? - client library
  2. Did someone already solve this? - it hasn't been asked yet in the Issue or Stack overflow
  3. Do you have a support contract? - At work yes, but this is a personal contribution outside work

Environment details

  • OS: macOS Catalina
  • Node.js version: v16.15.0
  • npm version: 8.5.5
  • @google-cloud/storage version: 6.10.1

Steps to reproduce

Issue 1:

  1. Implement code example for 'downloadManyFiles' without prefix
async function downloadDirectory({ bucketId, sourceDirectory }) {
  const storage = new Storage();
  const transferManager = new TransferManager(storage.bucket(bucketId));
  const options = {};

  async function downloadFolderWithTransferManager() {
    await transferManager.downloadManyFiles(sourceDirectory, options);
  }
  const res = await downloadFolderWithTransferManager();
}
  1. Running the function returns no error. However, no files are written locally, and a well-placed console.warn shows that this is because the destination is undefined. The draft PR contains a suggestion to always generate the destination.

Screen Shot 2023-05-18 at 12 53 20 AM

Issue 2:

  1. Implement same example for 'downloadManyFiles', except we now set prefix
async function downloadDirectory({ bucketId, sourceDirectory }) {
  const storage = new Storage();
  const transferManager = new TransferManager(storage.bucket(bucketId));

  const options = {
    prefix: "hello",
  };
  async function downloadFolderWithTransferManager() {
    await transferManager.downloadManyFiles(sourceDirectory, options);
  }
  const res = await downloadFolderWithTransferManager();
}
  1. Running the function returns
ENOENT: no such file or directory, open 'hello/test-folder/'

Screen Shot 2023-05-18 at 12 38 18 AM

This is due to the file stream at

nodejs-storage/src/file.ts

Lines 2108 to 2111 in fe9e3a4

fileStream
.pipe(writable)
.on('error', callback)
.on('finish', callback);
attempting to save a directory object locally. It appears that google storage api returns empty directory objects according to google docs here https://cloud.google.com/knowledge/kb/listing-only-objects-using-gsutil-and-not-directories-000004568. The draft PR proposes to filter out these empty directory objects from the final write.

Thanks, it is my first issue and fork of the repo! Open to feedback. I've already signed the CLA, but kept the PR as draft until the codeowner reviews the issue/intention of the existing design.

Metadata

Metadata

Labels

api: storageIssues related to the googleapis/nodejs-storage API.priority: p3Desirable enhancement or fix. May not be included in next release.type: feature request‘Nice-to-have’ improvement, new feature or different behavior or design.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions