package object import ( "fmt" "os" "strings" internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/client" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key" commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" oidSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" "github.com/spf13/cobra" ) var ( searchFilters []string objectSearchCmd = &cobra.Command{ Use: "search", Short: "Search object", Long: "Search object", Run: searchObject, } ) func initObjectSearchCmd() { commonflags.Init(objectSearchCmd) initFlagSession(objectSearchCmd, "SEARCH") flags := objectSearchCmd.Flags() flags.String(commonflags.CIDFlag, "", commonflags.CIDFlagUsage) _ = objectSearchCmd.MarkFlagRequired(commonflags.CIDFlag) flags.StringSliceVarP(&searchFilters, "filters", "f", nil, "Repeated filter expressions or files with protobuf JSON") flags.Bool("root", false, "Search for user objects") flags.Bool("phy", false, "Search physically stored objects") flags.String(commonflags.OIDFlag, "", "Search object by identifier") } func searchObject(cmd *cobra.Command, _ []string) { var cnr cid.ID readCID(cmd, &cnr) sf, err := parseSearchFilters(cmd) commonCmd.ExitOnErr(cmd, "", err) pk := key.GetOrGenerate(cmd) cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC) var prm internalclient.SearchObjectsPrm prm.SetClient(cli) Prepare(cmd, &prm) readSessionGlobal(cmd, &prm, pk, cnr) prm.SetContainerID(cnr) prm.SetFilters(sf) res, err := internalclient.SearchObjects(cmd.Context(), prm) commonCmd.ExitOnErr(cmd, "rpc error: %w", err) ids := res.IDList() cmd.Printf("Found %d objects.\n", len(ids)) for i := range ids { cmd.Println(ids[i].String()) } } var searchUnaryOpVocabulary = map[string]object.SearchMatchType{ "NOPRESENT": object.MatchNotPresent, } var searchBinaryOpVocabulary = map[string]object.SearchMatchType{ "EQ": object.MatchStringEqual, "NE": object.MatchStringNotEqual, "COMMON_PREFIX": object.MatchCommonPrefix, } func parseSearchFilters(cmd *cobra.Command) (object.SearchFilters, error) { var fs object.SearchFilters for i := range searchFilters { words := strings.Fields(searchFilters[i]) switch len(words) { default: return nil, fmt.Errorf("invalid field number: %d", len(words)) case 1: data, err := os.ReadFile(words[0]) if err != nil { return nil, fmt.Errorf("could not read attributes filter from file: %w", err) } subFs := object.NewSearchFilters() if err := subFs.UnmarshalJSON(data); err != nil { return nil, fmt.Errorf("could not unmarshal attributes filter from file: %w", err) } fs = append(fs, subFs...) case 2: m, ok := searchUnaryOpVocabulary[words[1]] if !ok { return nil, fmt.Errorf("unsupported unary op: %s", words[1]) } fs.AddFilter(words[0], "", m) case 3: m, ok := searchBinaryOpVocabulary[words[1]] if !ok { return nil, fmt.Errorf("unsupported binary op: %s", words[1]) } fs.AddFilter(words[0], words[2], m) } } root, _ := cmd.Flags().GetBool("root") if root { fs.AddRootFilter() } phy, _ := cmd.Flags().GetBool("phy") if phy { fs.AddPhyFilter() } oid, _ := cmd.Flags().GetString(commonflags.OIDFlag) if oid != "" { var id oidSDK.ID if err := id.DecodeString(oid); err != nil { return nil, fmt.Errorf("could not parse object ID: %w", err) } fs.AddObjectIDFilter(object.MatchStringEqual, id) } return fs, nil }