-
Notifications
You must be signed in to change notification settings - Fork 20
/
storage_download.go
133 lines (106 loc) · 3 KB
/
storage_download.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package cmd
import (
"fmt"
"strings"
s3types "github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/spf13/cobra"
"github.com/exoscale/cli/pkg/storage/sos"
)
var storageDownloadCmd = &cobra.Command{
Use: "download sos://BUCKET/[OBJECT|PREFIX/] [DESTINATION]",
Aliases: []string{"get"},
Short: "Download files from a bucket",
Long: `This command downloads files from a bucket.
If no destination argument is provided, files will be stored into the current
directory.
Examples:
# Download a single file
exo storage download sos://my-bucket/file-a
# Download a single file and rename it locally
exo storage download sos://my-bucket/file-a file-z
# Download a prefix recursively
exo storage download -r sos://my-bucket/public/ /tmp/public/
`,
PreRunE: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 || len(args) > 2 {
cmdExitOnUsageError(cmd, "invalid arguments")
}
args[0] = strings.TrimPrefix(args[0], sos.BucketPrefix)
// Append implicit root prefix ("/") if only a bucket name is specified in the source
if !strings.Contains(args[0], "/") {
args[0] += "/"
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
var (
bucket string
prefix string
src = args[0]
dst = "./"
)
dryRun, err := cmd.Flags().GetBool("dry-run")
if err != nil {
return err
}
force, err := cmd.Flags().GetBool("force")
if err != nil {
return err
}
recursive, err := cmd.Flags().GetBool("recursive")
if err != nil {
return err
}
parts := strings.SplitN(src, "/", 2)
bucket = parts[0]
if len(parts) > 1 {
prefix = parts[1]
if prefix == "" {
prefix = "/"
}
}
if len(args) == 2 {
dst = args[1]
}
if strings.HasSuffix(src, "/") && !recursive {
return fmt.Errorf("%q is a directory, use flag `-r` to download recursively", src)
}
storage, err := sos.NewStorageClient(
gContext,
sos.ClientOptZoneFromBucket(gContext, bucket),
)
if err != nil {
return fmt.Errorf("unable to initialize storage client: %v", err)
}
objects := make([]*s3types.Object, 0)
if err := storage.ForEachObject(gContext, bucket, prefix, recursive, func(o *s3types.Object) error {
objects = append(objects, o)
return nil
}); err != nil {
return fmt.Errorf("error listing objects: %s", err)
}
if len(objects) == 0 {
fmt.Printf("no objects exist at %q\n", prefix)
return nil
}
return storage.DownloadFiles(gContext, &sos.DownloadConfig{
Bucket: bucket,
Prefix: prefix,
Source: src,
Objects: objects,
Destination: dst,
Recursive: recursive,
Overwrite: force,
DryRun: dryRun,
})
},
}
func init() {
storageDownloadCmd.Flags().BoolP("force", "f", false,
"overwrite existing destination files")
storageDownloadCmd.Flags().BoolP("dry-run", "n", false,
"simulate files download, don't actually do it")
storageDownloadCmd.Flags().BoolP("recursive", "r", false,
"download prefix recursively")
storageCmd.AddCommand(storageDownloadCmd)
}