@@ -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+
158236async 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".`
0 commit comments