diff --git a/cmd/cli/cli/const.go b/cmd/cli/cli/const.go index b7360d8b41b..e9ae3cd0fab 100644 --- a/cmd/cli/cli/const.go +++ b/cmd/cli/cli/const.go @@ -528,7 +528,7 @@ var ( Usage: "list also objects that were _not_ matched by regex and/or template (range)", } verChangedFlag = cli.BoolFlag{ - Name: "check-version", + Name: "check-versions", Usage: "check whether listed remote objects and their in-cluster copies are identical, ie., have the same versions\n" + indent4 + "\t- applies to remote buckets only\n" + indent4 + "\t- see related: 'ais get --latest', 'ais cp --sync', 'ais prefetch --latest'", @@ -592,8 +592,9 @@ var ( Name: "latest", Usage: "GET, prefetch, or copy the latest object version from the associated remote bucket;\n" + indent1 + "\tprovides operation-level control over object versioning (and version synchronization)\n" + - indent1 + "\t_without_ requiring to change bucket configuration\n" + - indent1 + "\t(the latter can be done using 'ais bucket props set BUCKET versioning')", + indent1 + "\twithout requiring to change bucket configuration\n" + + indent1 + "\t- the latter can be done using 'ais bucket props set BUCKET versioning'\n" + + indent1 + "\t- see also: 'ais ls --check-versions', 'ais cp', 'ais prefetch', 'ais get'", } syncFlag = cli.BoolFlag{ Name: "sync", diff --git a/cmd/cli/cli/ls.go b/cmd/cli/cli/ls.go index f2a218c227c..e5581b26cd7 100644 --- a/cmd/cli/cli/ls.go +++ b/cmd/cli/cli/ls.go @@ -312,6 +312,7 @@ func listObjects(c *cli.Context, bck cmn.Bck, prefix string, listArch bool) erro props = splitCsv(propsStr) // split apc.LsPropsSepa } + // add _implied_ props into control lsmsg if flagIsSet(c, nameOnlyFlag) { if flagIsSet(c, verChangedFlag) { return fmt.Errorf(errFmtExclusive, qflprn(verChangedFlag), qflprn(nameOnlyFlag)) @@ -327,8 +328,6 @@ func listObjects(c *cli.Context, bck cmn.Bck, prefix string, listArch bool) erro msg.AddProps(apc.GetPropsName) msg.AddProps(apc.GetPropsSize) msg.SetFlag(apc.LsNameSize) - } else if flagIsSet(c, verChangedFlag) { - msg.AddProps(apc.GetPropsDefaultCloud...) // TODO: maybe too crude } else { msg.AddProps(apc.GetPropsMinimal...) } @@ -345,10 +344,21 @@ func listObjects(c *cli.Context, bck cmn.Bck, prefix string, listArch bool) erro // (due to mirroring, EC). The status helps to tell an object from its replica(s). msg.AddProps(apc.GetPropsStatus) } + propsStr = msg.Props // show these and only these props + // and finally: + if flagIsSet(c, verChangedFlag) { + if !msg.WantProp(apc.GetPropsCustom) { + msg.AddProps(apc.GetPropsCustom) + } + if !msg.WantProp(apc.GetPropsVersion) { + msg.AddProps(apc.GetPropsVersion) + } + } + + // set page if flagIsSet(c, startAfterFlag) { msg.StartAfter = parseStrFlag(c, startAfterFlag) } - pageSize, limit, err := _setPage(c, bck) if err != nil { return err @@ -372,7 +382,7 @@ func listObjects(c *cli.Context, bck cmn.Bck, prefix string, listArch bool) erro } else { toPrint = objList.Entries } - err = printLso(c, toPrint, lstFilter, msg.Props, + err = printLso(c, toPrint, lstFilter, propsStr, addCachedCol, bck.IsRemote(), msg.IsFlagSet(apc.LsVerChanged)) if err != nil { return err @@ -411,7 +421,7 @@ func listObjects(c *cli.Context, bck cmn.Bck, prefix string, listArch bool) erro if err != nil { return lsoErr(msg, err) } - return printLso(c, objList.Entries, lstFilter, msg.Props, + return printLso(c, objList.Entries, lstFilter, propsStr, addCachedCol, bck.IsRemote(), msg.IsFlagSet(apc.LsVerChanged)) } diff --git a/cmn/objattrs.go b/cmn/objattrs.go index 065240bc4cc..702b55bf5a5 100644 --- a/cmn/objattrs.go +++ b/cmn/objattrs.go @@ -1,7 +1,7 @@ // Package cmn provides common constants, types, and utilities for AIS clients // and AIStore. /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package cmn @@ -93,14 +93,14 @@ func (oa *ObjAttrs) SetSize(size int64) { func CustomMD2S(md cos.StrKVs) string { return fmt.Sprintf("%+v", md) } -func S2CustomMD(custom string) (md cos.StrKVs) { +func S2CustomMD(custom, version string) (md cos.StrKVs) { if len(custom) < 8 || !strings.HasPrefix(custom, "map[") { // Sprintf above return nil } s := custom[4 : len(custom)-1] lst := strings.Split(s, " ") md = make(cos.StrKVs, len(lst)) - parseCustom(md, lst, VersionObjMD) + md[VersionObjMD] = version parseCustom(md, lst, SourceObjMD) parseCustom(md, lst, CRC32CObjMD) parseCustom(md, lst, MD5ObjMD) diff --git a/xact/xs/wanted_lso.go b/xact/xs/wanted_lso.go index b0510da0327..c53939dfe02 100644 --- a/xact/xs/wanted_lso.go +++ b/xact/xs/wanted_lso.go @@ -1,7 +1,7 @@ // Package xs contains most of the supported eXtended actions (xactions) with some // exceptions that include certain storage services (mirror, EC) and extensions (downloader, lru). /* - * Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved. */ package xs @@ -38,6 +38,10 @@ func wanted(msg *apc.LsoMsg) (flags cos.BitFlags) { } func (wi *walkInfo) setWanted(e *cmn.LsoEntry, lom *core.LOM) { + var ( + custom = e.Custom + version = e.Version + ) for name, fl := range allmap { if !wi.wanted.IsSet(fl) { continue @@ -81,7 +85,7 @@ func (wi *walkInfo) setWanted(e *cmn.LsoEntry, lom *core.LOM) { // // extensive version-changed check // - md := cmn.S2CustomMD(e.Custom) + md := cmn.S2CustomMD(custom, version) if len(md) > 0 { var oa cmn.ObjAttrs oa.CustomMD = md