Skip to content

Commit

Permalink
mc tag command
Browse files Browse the repository at this point in the history
  • Loading branch information
BigUstad committed Mar 20, 2020
2 parents c1207f7 + 91da0da commit 01b7dea
Show file tree
Hide file tree
Showing 9 changed files with 170 additions and 98 deletions.
7 changes: 7 additions & 0 deletions cmd/client-errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ func (e BucketNameEmpty) Error() string {
return "Bucket name cannot be empty."
}

// ObjectNameEmpty - object name empty.
type ObjectNameEmpty struct{}

func (e ObjectNameEmpty) Error() string {
return "Object name cannot be empty."
}

// BucketInvalid - bucket name invalid.
type BucketInvalid struct {
Bucket string
Expand Down
6 changes: 3 additions & 3 deletions cmd/client-fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -393,13 +393,13 @@ func (f *fsClient) put(reader io.Reader, size int64, metadata map[string][]strin
return totalWritten, probe.NewError(e)
}

ctime, e := strconv.ParseInt(attr["ctime"], 10, 64)
mtime, e := strconv.ParseInt(attr["mtime"], 10, 64)
if e != nil {
return totalWritten, probe.NewError(e)
}

// Attempt to change the access, modify and change time
if e := os.Chtimes(objectPath, time.Unix(atime, 0), time.Unix(ctime, 0)); e != nil {
// Attempt to change the access and modify time
if e := os.Chtimes(objectPath, time.Unix(atime, 0), time.Unix(mtime, 0)); e != nil {
return totalWritten, probe.NewError(e)
}
}
Expand Down
21 changes: 15 additions & 6 deletions cmd/client-s3.go
Original file line number Diff line number Diff line change
Expand Up @@ -2108,8 +2108,11 @@ func (c *s3Client) GetObjectTagging() (tagging.Tagging, *probe.Error) {
var err error
bucketName, objectName := c.url2BucketAndObject()
if bucketName == "" || objectName == "" {
err = errors.New("Bucket name or object name cannot be empty")
return tagging.Tagging{}, probe.NewError(err)
pErr := probe.NewError(BucketNameEmpty{})
if objectName == "" {
pErr = probe.NewError(ObjectNameEmpty{})
}
return tagging.Tagging{}, pErr
}
tagXML, err := c.api.GetObjectTagging(bucketName, objectName)
if err != nil {
Expand All @@ -2127,8 +2130,11 @@ func (c *s3Client) SetObjectTagging(tagMap map[string]string) *probe.Error {
var err error
bucket, object := c.url2BucketAndObject()
if bucket == "" || object == "" {
err = errors.New("Bucket name or object name cannot be empty")
return probe.NewError(err)
pErr := probe.NewError(BucketNameEmpty{})
if object == "" {
pErr = probe.NewError(ObjectNameEmpty{})
}
return pErr
}
if err = c.api.PutObjectTagging(bucket, object, tagMap); err != nil {
return probe.NewError(err)
Expand All @@ -2140,8 +2146,11 @@ func (c *s3Client) SetObjectTagging(tagMap map[string]string) *probe.Error {
func (c *s3Client) DeleteObjectTagging() *probe.Error {
bucket, object := c.url2BucketAndObject()
if bucket == "" || object == "" {
err := errors.New("Bucket name or object name cannot be empty")
return probe.NewError(err)
pErr := probe.NewError(BucketNameEmpty{})
if object == "" {
pErr = probe.NewError(ObjectNameEmpty{})
}
return pErr
}
if err := c.api.RemoveObjectTagging(bucket, object); err != nil {
return probe.NewError(err)
Expand Down
89 changes: 52 additions & 37 deletions cmd/tag-list.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ type tagList struct {
// tagsetListMessage container for displaying tag
type tagsetListMessage struct {
Tags []tagList `json:"tagset,omitempty"`
Status string `json:"status,omitempty"`
Status string `json:"status"`
Name string `json:"name"`
Err error `json:"err,omitempty"`
}

func (t tagsetListMessage) JSON() string {
Expand All @@ -75,34 +77,44 @@ func (t tagsetListMessage) JSON() string {

tagJSONbytes, err = json.MarshalIndent(t, "", " ")
tagJSONbytes = bytes.Replace(tagJSONbytes, []byte("\\u0026"), []byte("&"), -1)
fatalIf(probe.NewError(err), "Unable to marshal into JSON.")
fatalIf(probe.NewError(err), "Unable to marshal into JSON for "+t.Name)

return string(tagJSONbytes)
}

func (t tagsetListMessage) String() string {
return console.Colorize(tagPrintMsgTheme, t.Status)
var msg string
if t.Err == nil {
msg = console.Colorize(tagPrintMsgTheme, "Tag(s) set for "+t.Name)
} else {
msg = console.Colorize(tagPrintErrMsgTheme, "Failed to set tags for "+t.Name+". "+t.Err.Error())
}
return msg
}

const (
tagMainHeader string = "Main-Heading"
tagRowTheme string = "Row-Header"
tagPrintMsgTheme string = "Tag-PrintMsg"
tagMainHeader string = "Main-Heading"
tagRowTheme string = "Row-Header"
tagPrintMsgTheme string = "Tag-PrintMsg"
tagPrintErrMsgTheme string = "Tag-PrintMsgErr"
)

// tagStr is in the format key1=value1&key1=value2
func parseTagListMessage(tags string, urlStr string) tagsetListMessage {
// parseTagListMessage parses the tags(string) and initializes the structure tagsetListMessage.
// tags(string) is in the format key1=value1&key1=value2
func parseTagListMessage(tags string, urlStr string, err error) tagsetListMessage {
var t tagsetListMessage
var tagStr string
var kvPairStr []string
tagStr = strings.Replace(tags, "\\u0026", "&", -1)
t.Name = getTagObjectName(urlStr)
t.Err = nil
if tagStr != "" {
kvPairStr = strings.SplitN(tagStr, "&", -1)
t.Status = "success"
} else {
t.Status = "error"
t.Err = err
}
if len(kvPairStr) == 0 {
t.Status = "Tags not added or not available."
}

for _, kvPair := range kvPairStr {
kvPairSplit := splitStr(kvPair, "=", 2)
t.Tags = append(t.Tags, tagList{Key: kvPairSplit[0], Value: kvPairSplit[1]})
Expand All @@ -113,9 +125,11 @@ func parseTagListMessage(tags string, urlStr string) tagsetListMessage {

func getObjTagging(urlStr string) (tagging.Tagging, error) {
clnt, pErr := newClient(urlStr)
fatalIf(pErr.Trace(urlStr), "Unable to initialize target "+urlStr+".")
if pErr != nil {
fatalIf(pErr.Trace(urlStr), "Unable to initialize target "+urlStr+". Error: "+pErr.ToGoError().Error())
}
tagObj, pErr := clnt.GetObjectTagging()
fatalIf(pErr, "Failed to get tags for "+urlStr)
fatalIf(pErr, "Failed to get tags for "+getTagObjectName(urlStr))

return tagObj, nil
}
Expand All @@ -125,6 +139,7 @@ func setTagListColorScheme() {
console.SetColor(tagRowTheme, color.New(color.FgWhite))
console.SetColor(tagMainHeader, color.New(color.Bold, color.FgCyan))
console.SetColor(tagPrintMsgTheme, color.New(color.FgGreen))
console.SetColor(tagPrintErrMsgTheme, color.New(color.FgRed))
}

func checkListTagSyntax(ctx *cli.Context) {
Expand All @@ -134,22 +149,25 @@ func checkListTagSyntax(ctx *cli.Context) {
}
}

func getTagObjectName(urlStr string) string {
if !strings.Contains(urlStr, "/") {
urlStr = filepath.ToSlash(urlStr)
}
splits := splitStr(urlStr, "/", 3)
object := splits[2]

return object
}

func listTagInfoFieldMultiple(urlStr string, kvpairs []tagging.Tag) {
var object string
var splits []string
padLen := len("Name")
for _, kv := range kvpairs {
if len(kv.Key) > padLen {
padLen = len(kv.Key)
}
}
padLen = listTagPaddingSpace(padLen)
if !strings.Contains(urlStr, "/") {
urlStr = filepath.ToSlash(urlStr)
}
splits = splitStr(urlStr, "/", 3)
object = splits[2]
objectName := fmt.Sprintf("%-*s: %s", padLen, "Name", object)
objectName := fmt.Sprintf("%-*s: %s", padLen, "Name", getTagObjectName(urlStr))
console.Println(console.Colorize(tagMainHeader, objectName))
for idx := 0; idx < len(kvpairs); idx++ {
displayField := fmt.Sprintf("%-*s: %s", padLen, kvpairs[idx].Key, kvpairs[idx].Value)
Expand All @@ -176,26 +194,23 @@ func mainListTag(ctx *cli.Context) error {
setTagListColorScheme()
args := ctx.Args()
objectURL := args.Get(0)
tagObj, err := getObjTagging(objectURL)

if err != nil {
console.Errorln(err.Error() + ". Error getting tag for " + objectURL)
return err
var tagObj tagging.Tagging
var err error
if tagObj, err = getObjTagging(objectURL); err != nil {
fatal(probe.NewError(err), "Unable to get tags for target "+objectURL+".")
}

if globalJSON {
var tMsg tagsetListMessage
tMsg = parseTagListMessage(tagObj.String(), objectURL)
printMsg(tMsg)
return nil
}
switch len(tagObj.TagSet.Tags) {
case 0:
var tMsg tagsetListMessage
tMsg = parseTagListMessage(tagObj.String(), objectURL)
printMsg(tMsg)
errorIf(errDummy().Trace(objectURL), "Tags not set for "+getTagObjectName(objectURL)+".")
default:
listTagInfoFieldMultiple(objectURL, tagObj.TagSet.Tags)
if globalJSON {
var msg tagsetListMessage
msg = parseTagListMessage(tagObj.String(), objectURL, err)
printMsg(msg)
} else {
listTagInfoFieldMultiple(objectURL, tagObj.TagSet.Tags)
}
}

return nil
Expand Down
2 changes: 1 addition & 1 deletion cmd/tag-main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ var tagCmd = cli.Command{
Subcommands: []cli.Command{
tagListCmd,
tagRemoveCmd,
tagAddCmd,
tagSetCmd,
},
}

Expand Down
51 changes: 37 additions & 14 deletions cmd/tag-remove.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ import (
"os"

"github.com/minio/cli"
json "github.com/minio/mc/pkg/colorjson"
"github.com/minio/mc/pkg/probe"
"github.com/minio/minio/pkg/console"
)

var tagRemoveCmd = cli.Command{
Expand All @@ -42,42 +44,63 @@ DESCRIPTION:
Remove object tags assigned to an object .
EXAMPLES:
1. Remove the tags added to an existing object.
1. Remove the tags set to an existing object.
{{.Prompt}} {{.HelpName}} s3/testbucket/testobject
`,
}

func checkRemoveTagSyntax(ctx *cli.Context) {
if len(ctx.Args()) != 1 {
cli.ShowCommandHelp(ctx, "remove")
os.Exit(globalErrorExitStatus)
}
// tagSetTagMessage structure will show message depending on the type of console.
type tagRemoveMessage struct {
Status string `json:"status"`
Name string `json:"name"`
Err error `json:"err,omitempty"`
}

// tagRemoveMessage console colorized output.
func (t tagRemoveMessage) String() string {
return console.Colorize(tagPrintMsgTheme, "Tags removed for "+t.Name+".")
}

// JSON tagRemoveMessage.
func (t tagRemoveMessage) JSON() string {
msgBytes, e := json.MarshalIndent(t, "", " ")
fatalIf(probe.NewError(e), "Unable to marshal into JSON.")
return string(msgBytes)
}

func parseTagRemoveMessage(tags string, urlStr string, err error) tagsetListMessage {
var t tagsetListMessage
func parseTagRemoveMessage(tags string, urlStr string, err error) tagRemoveMessage {
var t tagRemoveMessage
t.Name = getTagObjectName(urlStr)
if err != nil {
t.Status = "Remove tags to target " + urlStr + ". Error " + err.Error()
t.Status = "error"
t.Err = err
} else {
t.Status = "Tags removed for " + urlStr + "."
t.Status = "success"
}
return t
}

func checkRemoveTagSyntax(ctx *cli.Context) {
if len(ctx.Args()) != 1 {
cli.ShowCommandHelp(ctx, "remove")
os.Exit(globalErrorExitStatus)
}
}

func mainRemoveTag(ctx *cli.Context) error {
checkRemoveTagSyntax(ctx)
setTagListColorScheme()
var pErr *probe.Error
var msg tagRemoveMessage
objectURL := ctx.Args().Get(0)
clnt, pErr := newClient(objectURL)
fatalIf(pErr.Trace(objectURL), "Unable to initialize target "+objectURL+".")
pErr = clnt.DeleteObjectTagging()
fatalIf(pErr, "Failed to remove tags")
fatalIf(pErr.Trace(objectURL), "Failed to remove tags")
tagObj, err := getObjTagging(objectURL)
var tMsg tagsetListMessage
tMsg = parseTagRemoveMessage(tagObj.String(), objectURL, err)
printMsg(tMsg)
msg = parseTagRemoveMessage(tagObj.String(), objectURL, err)
printMsg(msg)

return nil
}
Loading

0 comments on commit 01b7dea

Please sign in to comment.