pitr/cli/internal/pkg/local-storage.go (166 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package pkg import ( "encoding/json" "errors" "fmt" "os" "strings" "time" "github.com/apache/shardingsphere-on-cloud/pitr/cli/internal/pkg/model" "github.com/apache/shardingsphere-on-cloud/pitr/cli/internal/pkg/xerr" strutil "github.com/apache/shardingsphere-on-cloud/pitr/cli/pkg/stringutil" ) type ( localStorage struct { rootDir string backupDir string } ILocalStorage interface { WriteByJSON(name string, contents *model.LsBackup) error GenFilename(extn Extension) string ReadAll() ([]*model.LsBackup, error) ReadByID(id string) (*model.LsBackup, error) ReadByCSN(csn string) (*model.LsBackup, error) DeleteByName(name string) error } Extension string ) const ( ExtnJSON Extension = "JSON" ) func NewLocalStorage(root string) (ILocalStorage, error) { ls := &localStorage{ rootDir: root, backupDir: fmt.Sprintf("%s/%s", root, "backup"), } if err := ls.init(); err != nil { return nil, err } return ls, nil } func DefaultRootDir() string { return fmt.Sprintf("%s/%s", os.Getenv("HOME"), ".gs_pitr") } func (ls *localStorage) init() error { // root dir fi, err := os.Stat(ls.rootDir) if err != nil { if os.IsNotExist(err) { if err := os.Mkdir(ls.rootDir, 0777); err != nil { return fmt.Errorf("create root dir failure,dir=%s,err=%s", ls.rootDir, err) } } else if os.IsExist(err) { if !fi.IsDir() { return fmt.Errorf("file has already exist,name=%s", ls.rootDir) } } else { return fmt.Errorf("failed to get file info,root dir=%s,err=%s", ls.rootDir, err) } } // backup dir fi, err = os.Stat(ls.backupDir) if err != nil { if os.IsNotExist(err) { if err := os.Mkdir(ls.backupDir, 0777); err != nil { return fmt.Errorf("create backup dir failure,dir=%s,err=%s", ls.backupDir, err) } } else if os.IsExist(err) { if !fi.IsDir() { return fmt.Errorf("backup:file has already exist,name=%s", ls.backupDir) } } else { return fmt.Errorf("failed to get file info,backup dir=%s,err=%s", ls.backupDir, err) } } return nil } func (ls *localStorage) WriteByJSON(name string, contents *model.LsBackup) error { if !strings.HasSuffix(name, ".json") { return fmt.Errorf("wrong file extension,file name is %s", name) } data, err := json.MarshalIndent(contents, "", " ") if err != nil { return err } path := fmt.Sprintf("%s/%s", ls.backupDir, name) fi, err := os.Create(path) if err != nil { return fmt.Errorf("create file failure,file path is %s", path) } _, err = fi.Write(data) if err != nil { return fmt.Errorf("write to file failure,err=%s,data is %s", err, data) } return nil } func (ls *localStorage) ReadAll() ([]*model.LsBackup, error) { entries, err := os.ReadDir(ls.backupDir) if err != nil { return nil, xerr.NewCliErr(fmt.Sprintf("read the dir[path:%s] failed,err=%s", ls.backupDir, err)) } backups := make([]*model.LsBackup, 0, len(entries)) for _, entry := range entries { if entry.IsDir() { continue } info, err := entry.Info() if errors.Is(err, os.ErrNotExist) { return nil, xerr.NewCliErr("The file does not exist or has changed") } else if err != nil { return nil, xerr.NewCliErr(fmt.Sprintf("Unknown err:get entry info failed,err=%s", err)) } if !strings.HasSuffix(info.Name(), ".json") { continue } path := fmt.Sprintf("%s/%s", ls.backupDir, info.Name()) file, err := os.ReadFile(path) if err != nil { return nil, xerr.NewCliErr(fmt.Sprintf("read file failed,err=%s", err)) } b := &model.LsBackup{} if err := json.Unmarshal(file, b); err != nil { return nil, xerr.NewCliErr(fmt.Sprintf("invalid contents[filePath=%s],err=%s", path, err)) } backups = append(backups, b) } return backups, nil } func (ls *localStorage) ReadByCSN(csn string) (*model.LsBackup, error) { list, err := ls.ReadAll() if err != nil { return nil, err } for _, v := range list { if v.Info.CSN == csn { return v, nil } } return nil, xerr.NewCliErr(xerr.NotFound) } func (ls *localStorage) ReadByID(id string) (*model.LsBackup, error) { list, err := ls.ReadAll() if err != nil { return nil, err } for _, v := range list { if v.Info.ID == id { return v, nil } } return nil, xerr.NewCliErr(xerr.NotFound) } /* GenFilename gen a filename based on the file extension if extn is empty,return a postfix-free filename if extn=JSON,return the JSON filename like **.json */ func (ls *localStorage) GenFilename(extn Extension) string { prefix := time.Now().UTC().Format("20060102150405") suffix := strutil.Random(8) switch extn { case ExtnJSON: return fmt.Sprintf("%s_%s.json", prefix, suffix) default: return fmt.Sprintf("%s_%s", prefix, suffix) } } func (ls *localStorage) DeleteByName(name string) error { path := fmt.Sprintf("%s/%s", ls.backupDir, name) if err := os.Remove(path); err != nil { return xerr.NewCliErr(fmt.Sprintf("delete file failed,err=%s", err)) } return nil }