Skip to content

Commit afd83af

Browse files
AVaksmanBenjamin E. Coe
authored andcommitted
docs(samples): sample for upload directory (googleapis#770)
1 parent 25eb0d7 commit afd83af

3 files changed

Lines changed: 134 additions & 0 deletions

File tree

handwritten/storage/samples/files.js

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,84 @@ async function uploadFileWithKmsKey(bucketName, filename, kmsKeyName) {
155155
// [END storage_upload_with_kms_key]
156156
}
157157

158+
// sample-metadata:
159+
// title: Upload a diretory to a bucket.
160+
// description: Uploads full hierarchy of a local directory to a bucket.
161+
// usage: node files.js upload-directory <bucketName> <directoryPath>
162+
163+
async function uploadDirectory(bucketName, directoryPath) {
164+
// [START upload_directory]
165+
// Imports the Google Cloud client library
166+
const {Storage} = require('@google-cloud/storage');
167+
const fs = require('fs');
168+
const path = require('path');
169+
170+
// Creates a client
171+
const storage = new Storage();
172+
173+
/**
174+
* TODO(developer): Uncomment the following lines before running the sample.
175+
*/
176+
// const bucketName = 'Name of a bucket, e.g. my-bucket';
177+
// const directoryPath = 'Local directory to upload, e.g. ./local/path/to/direcotry';
178+
179+
// get the list of files from the specified directory
180+
const fileList = [];
181+
let dirCtr = 1;
182+
let itemCtr = 0;
183+
const pathDirName = path.dirname(directoryPath);
184+
185+
getFiles(directoryPath);
186+
187+
function getFiles(directory) {
188+
fs.readdir(directory, (err, items) => {
189+
dirCtr--;
190+
itemCtr += items.length;
191+
items.forEach(item => {
192+
const fullPath = path.join(directory, item);
193+
fs.stat(fullPath, (err, stat) => {
194+
itemCtr--;
195+
if (stat.isFile()) {
196+
fileList.push(fullPath);
197+
} else if (stat.isDirectory()) {
198+
dirCtr++;
199+
getFiles(fullPath);
200+
}
201+
if (dirCtr === 0 && itemCtr === 0) {
202+
onComplete();
203+
}
204+
});
205+
});
206+
});
207+
}
208+
209+
async function onComplete() {
210+
const resp = await Promise.all(
211+
fileList.map(filePath => {
212+
let destination = path.relative(pathDirName, filePath);
213+
// If running on Windows
214+
if (process.platform === 'win32') {
215+
destination = destination.replace(/\\/g, '/');
216+
}
217+
return storage
218+
.bucket(bucketName)
219+
.upload(filePath, {destination})
220+
.then(
221+
uploadResp => ({fileName: destination, status: uploadResp[0]}),
222+
err => ({fileName: destination, response: err})
223+
);
224+
})
225+
);
226+
227+
const successfulUploads =
228+
fileList.length - resp.filter(r => r.status instanceof Error).length;
229+
console.log(
230+
`${successfulUploads} files uploaded to ${bucketName} successfully.`
231+
);
232+
}
233+
// [END upload_directory]
234+
}
235+
158236
async function downloadFile(bucketName, srcFilename, destFilename) {
159237
// [START storage_download_file]
160238
// Imports the Google Cloud client library
@@ -474,6 +552,12 @@ require(`yargs`)
474552
opts =>
475553
uploadFileWithKmsKey(opts.bucketName, opts.srcFileName, opts.kmsKeyName)
476554
)
555+
.command(
556+
`upload-directory <bucketName> <srcDirectoryPath>`,
557+
`Uploads full hierarchy of a local directory to a bucket.`,
558+
{},
559+
opts => uploadDirectory(opts.bucketName, opts.srcDirectoryPath)
560+
)
477561
.command(
478562
`download <bucketName> <srcFileName> <destFileName>`,
479563
`Downloads a file from a bucket.`,
@@ -547,6 +631,10 @@ require(`yargs`)
547631
`node $0 upload-with-kms-key my-bucket ./file.txt my-key`,
548632
`Uploads "./file.txt" to "my-bucket" using "my-key".`
549633
)
634+
.example(
635+
`node $0 upload-directory my-bucket ./my-folder`,
636+
`Uploads full hierarchy of "./my-folder directory to "my-bucket.`
637+
)
550638
.example(
551639
`node $0 download my-bucket file.txt ./file.txt`,
552640
`Downloads "gs://my-bucket/file.txt" to "./file.txt".`
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Sub1
2+
Hello World!

handwritten/storage/samples/system-test/files.test.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ const copiedFileName = 'test3.txt';
3737
const signedFileName = 'signed-upload.txt';
3838
const kmsKeyName = process.env.GOOGLE_CLOUD_KMS_KEY_US;
3939
const filePath = path.join(cwd, 'resources', fileName);
40+
const folderPath = path.join(cwd, 'resources');
4041
const downloadFilePath = path.join(cwd, 'downloaded.txt');
4142
const cmd = `node files.js`;
4243

@@ -73,6 +74,49 @@ it('should upload a file with a kms key', async () => {
7374
assert.strictEqual(exists, true);
7475
});
7576

77+
it('should upload a local directory', done => {
78+
const output = execSync(
79+
`${cmd} upload-directory ${bucketName} ${folderPath}`
80+
);
81+
82+
const fileList = [];
83+
getFileList(folderPath);
84+
85+
function getFileList(directory) {
86+
const items = fs.readdirSync(directory);
87+
items.forEach(item => {
88+
const fullPath = path.join(directory, item);
89+
const stat = fs.lstatSync(fullPath);
90+
if (stat.isFile()) {
91+
fileList.push(fullPath);
92+
} else {
93+
getFileList(fullPath);
94+
}
95+
});
96+
}
97+
98+
assert.match(
99+
output,
100+
new RegExp(
101+
`${fileList.length} files uploaded to ${bucketName} successfully.`
102+
)
103+
);
104+
105+
Promise.all(
106+
fileList.map(file =>
107+
bucket
108+
.file(path.relative(path.dirname(folderPath), file).replace(/\\/g, '/'))
109+
.exists()
110+
)
111+
).then(resps => {
112+
const ctr = resps.reduce((acc, cur) => {
113+
return acc + cur[0];
114+
}, 0);
115+
assert.strictEqual(ctr, fileList.length);
116+
done();
117+
}, assert.ifError);
118+
});
119+
76120
it('should download a file', () => {
77121
const output = execSync(
78122
`${cmd} download ${bucketName} ${fileName} ${downloadFilePath}`

0 commit comments

Comments
 (0)