@@ -68,12 +68,13 @@ func get(cmd *cobra.Command, args []string) (err error) {
6868 return invalidArgumentsErrorWithDetails ("`get` requires `src` and/or `dst` arguments" , argumentsErrorDetails ("src" , "dst" ))
6969 }
7070
71- src , err := validatePath (args [0 ])
72- if err != nil {
73- return
74- }
71+ srcRef := newDropboxReference (args [0 ])
72+ src := srcRef .String ()
7573
76- dst := path .Base (src )
74+ dst := ""
75+ if srcRef .isPath () {
76+ dst = path .Base (src )
77+ }
7778 if len (args ) == 2 {
7879 dst = args [1 ]
7980 }
@@ -92,11 +93,15 @@ func get(cmd *cobra.Command, args []string) (err error) {
9293
9394 meta , err := dbx .GetMetadataContext (currentContext (), files .NewGetMetadataArg (src ))
9495 if err != nil {
95- if recursive {
96- return withJSONErrorDetails (fmt .Errorf ("get metadata for %s: %v" , src , err ), operationErrorDetails ("download" ), pathErrorDetails (src ))
96+ metadataErr := withJSONErrorDetails (fmt .Errorf ("get metadata for %s: %v" , src , err ), operationErrorDetails ("download" ), pathErrorDetails (src ))
97+ if recursive || dst == "" {
98+ return metadataErr
9799 }
98100 // For non-recursive, fall through to download (will fail with proper error)
99101 if f , statErr := os .Stat (dst ); statErr == nil && f .IsDir () {
102+ if ! srcRef .isPath () {
103+ return metadataErr
104+ }
100105 dst = filepath .Join (dst , path .Base (src ))
101106 }
102107 result , err := downloadFileWithResult (dbx , src , dst , opts )
@@ -111,15 +116,26 @@ func get(cmd *cobra.Command, args []string) (err error) {
111116 }, []getResult {result })
112117 }
113118
119+ sourceName := path .Base (src )
120+ if ! srcRef .isPath () {
121+ sourceName = metadataName (meta )
122+ if sourceName == "" {
123+ return withJSONErrorDetails (fmt .Errorf ("get metadata for %s did not include a name" , src ), operationErrorDetails ("download" ), pathErrorDetails (src ))
124+ }
125+ if dst == "" {
126+ dst = sourceName
127+ }
128+ }
129+
114130 if _ , ok := meta .(* files.FolderMetadata ); ok {
115131 if ! recursive {
116132 return invalidArgumentsErrorfWithDetails ("%s is a folder (use --recursive to download folders)" , mergeJSONErrorDetails (operationErrorDetails ("download" ), pathErrorDetails (src )), src )
117133 }
118134 if f , statErr := os .Stat (dst ); statErr == nil && f .IsDir () {
119- dst = filepath .Join (dst , path . Base ( src ) )
135+ dst = filepath .Join (dst , sourceName )
120136 }
121137 if commandOutputFormat (cmd ) == output .FormatText {
122- return withJSONErrorDetails (getRecursive (dbx , src , dst ), operationErrorDetails ("download" ), pathErrorDetails (src ), relocationErrorDetails (src , dst ))
138+ return withJSONErrorDetails (getRecursiveWithRootMetadata (dbx , src , dst , meta ), operationErrorDetails ("download" ), pathErrorDetails (src ), relocationErrorDetails (src , dst ))
123139 }
124140 results , err := getRecursiveWithResults (dbx , src , dst , meta , opts )
125141 if err != nil {
@@ -134,7 +150,7 @@ func get(cmd *cobra.Command, args []string) (err error) {
134150 }
135151
136152 if f , statErr := os .Stat (dst ); statErr == nil && f .IsDir () {
137- dst = filepath .Join (dst , path . Base ( src ) )
153+ dst = filepath .Join (dst , sourceName )
138154 }
139155
140156 result , err := downloadFileWithResult (dbx , src , dst , opts )
@@ -214,32 +230,16 @@ func getStdout(cmd *cobra.Command, src string, recursive bool) error {
214230 return withJSONErrorDetails (downloadToStdout (dbx , src , cmd .OutOrStdout ()), operationErrorDetails ("download" ), pathErrorDetails (src ))
215231}
216232
217- func getWithClient (dbx filesClient , args []string ) (err error ) {
218- if len (args ) == 0 || len (args ) > 2 {
219- return invalidArgumentsErrorWithDetails ("`get` requires `src` and/or `dst` arguments" , argumentsErrorDetails ("src" , "dst" ))
220- }
221-
222- src , err := validatePath (args [0 ])
223- if err != nil {
224- return
225- }
226-
227- dst := path .Base (src )
228- if len (args ) == 2 {
229- dst = args [1 ]
230- }
231- if f , err := os .Stat (dst ); err == nil && f .IsDir () {
232- dst = filepath .Join (dst , path .Base (src ))
233- }
234-
235- return withJSONErrorDetails (downloadFile (dbx , src , dst ), operationErrorDetails ("download" ), pathErrorDetails (src ), relocationErrorDetails (src , dst ))
236- }
237-
238233func getRecursive (dbx filesClient , src , dst string ) error {
239234 _ , err := getRecursiveInternal (dbx , src , dst , nil , getOptions {}, false )
240235 return err
241236}
242237
238+ func getRecursiveWithRootMetadata (dbx filesClient , src , dst string , rootMeta files.IsMetadata ) error {
239+ _ , err := getRecursiveInternal (dbx , src , dst , rootMeta , getOptions {}, false )
240+ return err
241+ }
242+
243243func getRecursiveWithResults (dbx filesClient , src , dst string , rootMeta files.IsMetadata , opts getOptions ) ([]getResult , error ) {
244244 return getRecursiveInternal (dbx , src , dst , rootMeta , opts , true )
245245}
@@ -265,6 +265,10 @@ func getRecursiveInternal(dbx filesClient, src, dst string, rootMeta files.IsMet
265265 }
266266
267267 var results []getResult
268+ rootPath := src
269+ if metadataPath := metadataPathDisplay (rootMeta ); metadataPath != "" {
270+ rootPath = metadataPath
271+ }
268272
269273 if collectResults {
270274 result , err := ensureLocalDirectoryResult (src , dst , rootMeta )
@@ -283,7 +287,7 @@ func getRecursiveInternal(dbx filesClient, src, dst string, rootMeta files.IsMet
283287 for _ , entry := range entries {
284288 switch f := entry .(type ) {
285289 case * files.FolderMetadata :
286- relPath , err := relativeTo (src , f .PathDisplay )
290+ relPath , err := relativeTo (rootPath , f .PathDisplay )
287291 if err != nil {
288292 downloadErrors = append (downloadErrors , err )
289293 continue
@@ -305,7 +309,7 @@ func getRecursiveInternal(dbx filesClient, src, dst string, rootMeta files.IsMet
305309 }
306310 }
307311 case * files.FileMetadata :
308- relPath , err := relativeTo (src , f .PathDisplay )
312+ relPath , err := relativeTo (rootPath , f .PathDisplay )
309313 if err != nil {
310314 downloadErrors = append (downloadErrors , err )
311315 continue
@@ -493,11 +497,14 @@ var getCmd = &cobra.Command{
493497 Use : "get [flags] <source> [<target>]" ,
494498 Short : "Download a file or folder" ,
495499 Long : `Download a file or folder from Dropbox.
500+ - Source may be a Dropbox path, file ID (id:), revision (rev:), or
501+ namespace-relative path (ns:).
496502 - Use --recursive (-r) to download entire directories.
497503 - Use - as target to write file bytes to stdout.
498504 Stdout is byte-clean: all progress and errors go to stderr.
499505` ,
500506 Example : ` dbxcli get /remote/file.txt ./local-file.txt
507+ dbxcli get rev:a1c10ce0dd78 ./historical-file.txt
501508 dbxcli get -r /remote/folder ./local-folder
502509 dbxcli get /backups/src.tgz - | tar tz
503510 dbxcli get /file.txt - > local-copy.txt` ,
0 commit comments