-
Notifications
You must be signed in to change notification settings - Fork 18
/
storage_metadata_add.go
135 lines (104 loc) · 3.32 KB
/
storage_metadata_add.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
134
135
package cmd
import (
"fmt"
"strings"
"github.com/aws/aws-sdk-go-v2/aws"
s3types "github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/spf13/cobra"
)
const storageMetadataForbiddenCharset = `()<>@,;!:\\'&"/[]?_={} `
var storageMetadataAddCmd = &cobra.Command{
Use: "add sos://BUCKET/(OBJECT|PREFIX/) KEY=VALUE...",
Short: "Add key/value metadata to an object",
Long: fmt.Sprintf(`This command adds key/value metadata to an object.
Example:
exo storage metadata add sos://my-bucket/object-a \
k1=v1 \
k2=v2
Notes:
* Adding an already existing key will overwrite its value.
* The following characters are not allowed in keys: %s
Supported output template annotations: %s`,
strings.Join(strings.Split(storageMetadataForbiddenCharset, ""), " "),
strings.Join(outputterTemplateAnnotations(&storageShowObjectOutput{}), ", ")),
PreRunE: func(cmd *cobra.Command, args []string) error {
if len(args) < 2 {
cmdExitOnUsageError(cmd, "invalid arguments")
}
args[0] = strings.TrimPrefix(args[0], storageBucketPrefix)
if !strings.Contains(args[0], "/") {
cmdExitOnUsageError(cmd, fmt.Sprintf("invalid argument: %q", args[0]))
}
for _, kv := range args[1:] {
if !strings.Contains(kv, "=") {
cmdExitOnUsageError(cmd, fmt.Sprintf("invalid argument: %q", kv))
}
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
var (
bucket string
prefix string
metadata = make(map[string]string)
)
certsFile, err := cmd.Flags().GetString("certs-file")
if err != nil {
return err
}
recursive, err := cmd.Flags().GetBool("recursive")
if err != nil {
return err
}
parts := strings.SplitN(args[0], "/", 2)
bucket, prefix = parts[0], parts[1]
for _, kv := range args[1:] {
parts = strings.Split(kv, "=")
metadata[parts[0]] = parts[1]
}
storage, err := newStorageClient(
storageClientOptWithCertsFile(certsFile),
storageClientOptZoneFromBucket(bucket),
)
if err != nil {
return fmt.Errorf("unable to initialize storage client: %v", err)
}
if err := storage.addObjectsMetadata(bucket, prefix, metadata, recursive); err != nil {
return fmt.Errorf("unable to add metadata to object: %s", err)
}
if !gQuiet && !recursive && !strings.HasSuffix(prefix, "/") {
return output(storage.showObject(bucket, prefix))
}
if !gQuiet {
fmt.Println("Metadata added successfully")
}
return nil
},
}
func init() {
storageMetadataAddCmd.Flags().BoolP("recursive", "r", false,
"add metadata recursively (with object prefix only)")
storageMetadataCmd.AddCommand(storageMetadataAddCmd)
}
func (c *storageClient) addObjectMetadata(bucket, key string, metadata map[string]string) error {
object, err := c.copyObject(bucket, key)
if err != nil {
return err
}
if len(object.Metadata) == 0 {
object.Metadata = make(map[string]string)
}
for k, v := range metadata {
if strings.ContainsAny(k, storageMetadataForbiddenCharset) {
return fmt.Errorf("%s: invalid value", k)
}
object.Metadata[k] = v
}
_, err = c.CopyObject(gContext, object)
return err
}
func (c *storageClient) addObjectsMetadata(bucket, prefix string, metadata map[string]string, recursive bool) error {
return c.forEachObject(bucket, prefix, recursive, func(o *s3types.Object) error {
return c.addObjectMetadata(bucket, aws.ToString(o.Key), metadata)
})
}