diff --git a/app/handler/blob.go b/app/handler/blob.go index 6a474b1..f71aae9 100644 --- a/app/handler/blob.go +++ b/app/handler/blob.go @@ -216,7 +216,7 @@ func (hand *Handler) GetBlob(rctx *router.Context) { defer res.ReadCloser.Close() _, err = io.Copy(rctx.Writer, res.ReadCloser) if err != nil { - hand.logg.Errorf("GetFile error: %v", err) + hand.logg.Errorf("GetBlob error: %v", err) rctx.SetStatus(http.StatusInternalServerError) return } diff --git a/app/handler/file.go b/app/handler/file.go index e809310..be2c24a 100644 --- a/app/handler/file.go +++ b/app/handler/file.go @@ -162,7 +162,7 @@ func (hand *Handler) DeleteFile(rctx *router.Context) { ctx := rctx.GetContext() code, _, err := hand.oper.DeleteFile(ctx, operatorID, params) if err != nil { - hand.logg.Errorf("GetFile error: %v", err) + hand.logg.Errorf("DeleteFIle error: %v", err) } rctx.SetStatus(code) diff --git a/app/operator/file.go b/app/operator/file.go index 8bd2a4f..fc3a459 100644 --- a/app/operator/file.go +++ b/app/operator/file.go @@ -259,12 +259,17 @@ func (oper *Operator) DeleteFile(ctx context.Context, operID string, param *Dele filename := path.Base(xfilepath) collection := path.Dir(xfilepath) - exist, _, err := oper.mdb.GetFileByCollectionName(ctx, collection, filename) + descrExists, _, err := oper.mdb.GetFileByCollectionName(ctx, collection, filename) if err != nil { code = http.StatusInternalServerError return code, res, err } - if exist { + if !descrExists { + code := http.StatusNotFound + return code, res, err + } + + if descrExists { err = oper.mdb.DeleteFileByCollectionName(ctx, collection, filename) if err != nil { code = http.StatusInternalServerError @@ -282,42 +287,76 @@ func (oper *Operator) DeleteFile(ctx context.Context, operID string, param *Dele // ListFiles type ListFilesParams struct { Filepath string + PathAs terms.PathAs `param:"pathAs"` } type ListFilesResult struct { Files []descr.File `json:"files,omitempty"` } -func (oper *Operator) ListFiles(ctx context.Context, operID string, param *ListFilesParams) (int, *ListFilesResult, error) { +func (oper *Operator) ListFiles(ctx context.Context, operID string, params *ListFilesParams) (int, *ListFilesResult, error) { var err error res := &ListFilesResult{ Files: make([]descr.File, 0), } - param.Filepath, err = cleanFilepath(param.Filepath) + params.Filepath, err = cleanFilepath(params.Filepath) if err != nil { code := http.StatusInternalServerError return code, res, err } - - fileDescrs, err := oper.mdb.ListAllFiles(ctx) - if err != nil { - code := http.StatusInternalServerError - return code, res, err - } - rFilepath := filepath.Join("/", param.Filepath) - for _, item := range fileDescrs { - cFilepath := filepath.Join("/", item.Collection, item.Name) - if strings.HasPrefix(cFilepath, rFilepath) { - res.Files = append(res.Files, item) + switch params.PathAs { + case terms.AsPrefix: + files, err := oper.listFilesWithPrefix(ctx, params.Filepath) + if err != nil { + code := http.StatusInternalServerError + return code, res, err } + res.Files = files + + default: // Fine + files, err := oper.listFilesInOneCollection(ctx, params.Filepath) + if err != nil { + code := http.StatusInternalServerError + return code, res, err + } + res.Files = files + } code := http.StatusOK return code, res, err } +func (oper *Operator) listFilesInOneCollection(ctx context.Context, collection string) ([]descr.File, error) { + var err error + res := make([]descr.File, 0) + files, err := oper.mdb.ListFilesByCollection(ctx, collection) + if err != nil { + return res, err + } + res = files + return res, err +} + +func (oper *Operator) listFilesWithPrefix(ctx context.Context, prefix string) ([]descr.File, error) { + var err error + res := make([]descr.File, 0) + files, err := oper.mdb.ListAllFiles(ctx) + if err != nil { + return res, err + } + for _, file := range files { + fullpath := filepath.Join(file.Collection, file.Name) + if strings.HasPrefix(fullpath, prefix) { + res = append(res, file) + } + } + return res, err +} + // ListCollections type ListCollectionsParams struct { - Path string + Path string + PathAS terms.PathAs `param:"pathAs"` } type ListCollectionsResult struct { Collections []string `json:"collection,omitempty"` @@ -333,37 +372,83 @@ func (oper *Operator) ListCollections(ctx context.Context, operID string, param code := http.StatusInternalServerError return code, res, err } - fileDescrs, err := oper.mdb.ListAllFiles(ctx) - if err != nil { - code := http.StatusInternalServerError - return code, res, err - } - cmap := make(map[string]bool) - for _, item := range fileDescrs { - cPath := filepath.Join("/", item.Collection) - pattern := filepath.Join("/", param.Path) - if strings.HasPrefix(cPath, pattern) { - _, exists := cmap[cPath] - if !exists { - cmap[cPath] = true - } + collectionList := make([]string, 0) + switch param.PathAS { + case terms.AsPrefix: + collectionList, err = oper.listCollectionsWithPrefix(ctx, param.Path) + if err != nil { + code := http.StatusInternalServerError + return code, res, err } + default: + collectionList, err = oper.listAllCollections(ctx) + if err != nil { + code := http.StatusInternalServerError + return code, res, err + } + } - for key, _ := range cmap { - res.Collections = append(res.Collections, key) - } - slices.Sort(res.Collections) + res.Collections = collectionList code := http.StatusOK return code, res, err } +func (oper *Operator) listCollectionsWithPrefix(ctx context.Context, prefix string) ([]string, error) { + var err error + res := make([]string, 0) + + fileDescrs, err := oper.mdb.ListAllFiles(ctx) // TODO + if err != nil { + return res, err + } + collMap := make(map[string]bool) + for _, item := range fileDescrs { + _, exists := collMap[item.Collection] + if !exists { + collMap[item.Collection] = true + } + } + res = make([]string, len(collMap)) + for key, _ := range collMap { + if strings.HasPrefix(key, prefix) { + res = append(res, key) + } + } + slices.Sort(res) + return res, err +} + +func (oper *Operator) listAllCollections(ctx context.Context) ([]string, error) { + var err error + res := make([]string, 0) + + fileDescrs, err := oper.mdb.ListAllFiles(ctx) // TODO + if err != nil { + return res, err + } + collMap := make(map[string]bool) + for _, item := range fileDescrs { + _, exists := collMap[item.Collection] + if !exists { + collMap[item.Collection] = true + } + } + res = make([]string, len(collMap)) + for key, _ := range collMap { + res = append(res, key) + } + slices.Sort(res) + return res, err +} + // DeleteColletion type DeleteColletionParams struct { Path string PathAs string `param:"pathAs"` + DryRun bool `param:"dryRun"` } type DeleteColletionResult struct { - Files []descr.File `json:"collection,omitempty"` + Files []descr.File `json:"files,omitempty"` } func (oper *Operator) DeleteColletion(ctx context.Context, operID string, param *DeleteColletionParams) (int, *DeleteColletionResult, error) { @@ -376,59 +461,47 @@ func (oper *Operator) DeleteColletion(ctx context.Context, operID string, param code := http.StatusInternalServerError return code, res, err } - oper.logg.Debugf("=== Use path as %s", param.PathAs) + //oper.logg.Debugf("DeleteCollection: Use path as %s", param.PathAs) switch terms.PathAs(param.PathAs) { case terms.AsPrefix: - fileDescrs, err := oper.mdb.ListAllFiles(ctx) + collections, err := oper.listCollectionsWithPrefix(ctx, param.Path) if err != nil { code := http.StatusInternalServerError return code, res, err } - - collMap := make(map[string]bool) - for _, item := range fileDescrs { - _, exists := collMap[item.Collection] - if !exists { - collMap[item.Collection] = true - } - } - collections := make([]string, len(collMap)) - for key, _ := range collMap { - collections = append(collections, key) - } + allfiles := make([]descr.File, 0) for _, collection := range collections { - if strings.HasPrefix(collection, param.Path) { - - fileDescrs, err := oper.mdb.ListFilesByCollection(ctx, collection) - if err != nil { - code := http.StatusInternalServerError - return code, res, err - } - // TODO: transaction - for _, file := range fileDescrs { - err = oper.store.DeleteFile(file.Collection, file.Name) - if err != nil { - oper.logg.Warningf("%v", err) - err = nil - } - err = oper.mdb.DeleteFileByCollectionName(ctx, file.Collection, file.Name) - if err != nil { - code := http.StatusInternalServerError - return code, res, err - } - res.Files = append(res.Files, file) - } + files, err := oper.deleteFilesInCollection(ctx, collection, param.DryRun) + if err != nil { + code := http.StatusInternalServerError + return code, res, err } + allfiles = append(allfiles, files...) } - default: - fileDescrs, err := oper.mdb.ListFilesByCollection(ctx, param.Path) + res.Files = allfiles + default: // Fine + collection := param.Path + files, err := oper.deleteFilesInCollection(ctx, collection, param.DryRun) if err != nil { code := http.StatusInternalServerError return code, res, err } + res.Files = files + } + code := http.StatusOK + return code, res, err +} - // TODO: transaction - for _, file := range fileDescrs { +func (oper *Operator) deleteFilesInCollection(ctx context.Context, collection string, dryRun bool) ([]descr.File, error) { + var err error + res := make([]descr.File, 0) + files, err := oper.mdb.ListFilesByCollection(ctx, collection) + if err != nil { + return res, err + } + for _, file := range files { + oper.logg.Debugf("Delete file %s/%s", file.Collection, file.Name) + if !dryRun { err = oper.store.DeleteFile(file.Collection, file.Name) if err != nil { oper.logg.Warningf("%v", err) @@ -436,12 +509,11 @@ func (oper *Operator) DeleteColletion(ctx context.Context, operID string, param } err = oper.mdb.DeleteFileByCollectionName(ctx, file.Collection, file.Name) if err != nil { - code := http.StatusInternalServerError - return code, res, err + return res, err } - res.Files = append(res.Files, file) } + + res = append(res, file) } - code := http.StatusOK - return code, res, err + return res, err } diff --git a/cmd/mstorectl/filecmd.go b/cmd/mstorectl/filecmd.go index 9ef89ed..18b45de 100644 --- a/cmd/mstorectl/filecmd.go +++ b/cmd/mstorectl/filecmd.go @@ -16,6 +16,7 @@ import ( "io/fs" "net/url" "path/filepath" + "slices" "strings" "time" @@ -132,7 +133,8 @@ func (util *FileUtil) CreateCollectionCmds() *cobra.Command { Run: util.DeleteCollection, } deleteCollectionCmd.Flags().BoolVarP(&util.deleteCollectionParams.Detail, "detail", "D", false, "Show detail file information") - deleteCollectionCmd.Flags().BoolVarP(&util.deleteCollectionParams.AsPrefix, "asPrefix", "P", true, "Use path as collection path prefix") + deleteCollectionCmd.Flags().BoolVarP(&util.deleteCollectionParams.AsPrefix, "asprefix", "P", false, "Use path as collection path prefix") + deleteCollectionCmd.Flags().BoolVarP(&util.deleteCollectionParams.DryRun, "dryrun", "Y", false, "Simulate process, don't delete files") subCmd.AddCommand(deleteCollectionCmd) @@ -432,6 +434,7 @@ type DeleteCollectionParams struct { Path string Detail bool AsPrefix bool + DryRun bool } type DeleteCollectionResult struct { @@ -462,7 +465,7 @@ func (util *FileUtil) deleteCollection(common *CommonFileParams, params *DeleteC default: pathAs = terms.AsFinePath } - files, err := client.NewClient().DeleteCollection(ctx, params.Path, pathAs) + files, err := client.NewClient().DeleteCollection(ctx, params.Path, pathAs, params.DryRun) if err != nil { return res, err } @@ -472,6 +475,7 @@ func (util *FileUtil) deleteCollection(common *CommonFileParams, params *DeleteC for _, file := range files { res.Filenames = append(res.Filenames, filepath.Join(file.Collection, file.Name)) } + slices.Sort(res.Filenames) } return res, err } diff --git a/pkg/client/file.go b/pkg/client/file.go index e7b7e9a..fb6d5fc 100644 --- a/pkg/client/file.go +++ b/pkg/client/file.go @@ -325,7 +325,7 @@ func (cli *Client) ListCollections(ctx context.Context, catalogURI string) ([]st return res, err } -func (cli *Client) DeleteCollection(ctx context.Context, catalogURI string, usePathAs terms.PathAs) ([]descr.File, error) { +func (cli *Client) DeleteCollection(ctx context.Context, catalogURI string, usePathAs terms.PathAs, dryRun bool) ([]descr.File, error) { var err error res := make([]descr.File, 0) @@ -337,10 +337,14 @@ func (cli *Client) DeleteCollection(ctx context.Context, catalogURI string, useP if err != nil { return res, err } + // Add values values := url.Values{} if usePathAs != "" { values.Add("pathAs", string(usePathAs)) } + if dryRun { + values.Add("dryRun", "true") + } encodedValues := values.Encode() if encodedValues != "" { catalogURI = catalogURI + "?" + encodedValues