diff --git a/cmd/gf/internal/cmd/cmd_build.go b/cmd/gf/internal/cmd/cmd_build.go index edb7c382e96..182ee370b78 100644 --- a/cmd/gf/internal/cmd/cmd_build.go +++ b/cmd/gf/internal/cmd/cmd_build.go @@ -217,7 +217,7 @@ func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, e if !gfile.Exists(in.PackDst) { // Remove the go file that is automatically packed resource. defer func() { - _ = gfile.Remove(in.PackDst) + _ = gfile.RemoveFile(in.PackDst) mlog.Printf(`remove the automatically generated resource go file: %s`, in.PackDst) }() } diff --git a/cmd/gf/internal/cmd/cmd_doc.go b/cmd/gf/internal/cmd/cmd_doc.go index 9b1b855ed8a..7139a75d21c 100644 --- a/cmd/gf/internal/cmd/cmd_doc.go +++ b/cmd/gf/internal/cmd/cmd_doc.go @@ -106,10 +106,10 @@ func NewDocSetting(ctx context.Context, in cDocInput) *DocSetting { } -// Clean clean the temporary directory +// Clean cleans the temporary directory func (d *DocSetting) Clean() error { if _, err := os.Stat(d.TempDir); err == nil { - err = gfile.Remove(d.TempDir) + err = gfile.RemoveAll(d.TempDir) if err != nil { mlog.Print("Failed to delete temporary directory:", err) return err @@ -168,7 +168,7 @@ func (d *DocSetting) DownloadDoc() error { err := gcompress.UnZipFile(d.DocZipFile, d.TempDir) if err != nil { mlog.Print("Failed to unzip the file, please run again:", err) - gfile.Remove(d.DocZipFile) + _ = gfile.RemoveFile(d.DocZipFile) return err } diff --git a/cmd/gf/internal/cmd/cmd_run.go b/cmd/gf/internal/cmd/cmd_run.go index 8c30c4e3484..490a93a8b45 100644 --- a/cmd/gf/internal/cmd/cmd_run.go +++ b/cmd/gf/internal/cmd/cmd_run.go @@ -93,6 +93,12 @@ type ( ) func (c cRun) Index(ctx context.Context, in cRunInput) (out *cRunOutput, err error) { + if !gfile.Exists(in.File) { + mlog.Fatalf(`given file "%s" not found`, in.File) + } + if !gfile.IsFile(in.File) { + mlog.Fatalf(`given "%s" is not a file`, in.File) + } // Necessary check. if gproc.SearchBinary("go") == "" { mlog.Fatalf(`command "go" not found in your environment, please install golang first to proceed this command`) @@ -205,7 +211,7 @@ func (app *cRunApp) End(ctx context.Context, sig os.Signal, outputPath string) { mlog.Debugf("kill process error: %s", err.Error()) } } - if err := gfile.Remove(outputPath); err != nil { + if err := gfile.RemoveFile(outputPath); err != nil { mlog.Printf("delete binary file error: %s", err.Error()) } else { mlog.Printf("deleted binary file: %s", outputPath) diff --git a/cmd/gf/internal/cmd/cmd_up.go b/cmd/gf/internal/cmd/cmd_up.go index 8fb232ddd21..2bef38896f9 100644 --- a/cmd/gf/internal/cmd/cmd_up.go +++ b/cmd/gf/internal/cmd/cmd_up.go @@ -192,7 +192,7 @@ func (c cUp) doUpgradeCLI(ctx context.Context) (err error) { defer func() { mlog.Printf(`new version cli binary is successfully installed to "%s"`, gfile.SelfPath()) mlog.Printf(`remove temporary buffer file "%s"`, localSaveFilePath) - _ = gfile.Remove(localSaveFilePath) + _ = gfile.RemoveFile(localSaveFilePath) }() // It fails if file not exist or its size is less than 1MB. diff --git a/cmd/gf/internal/cmd/genctrl/genctrl.go b/cmd/gf/internal/cmd/genctrl/genctrl.go index d6788620aa2..87d87766ee2 100644 --- a/cmd/gf/internal/cmd/genctrl/genctrl.go +++ b/cmd/gf/internal/cmd/genctrl/genctrl.go @@ -128,7 +128,7 @@ func (c CGenCtrl) generateByWatchFile(watchFile, sdkPath string, sdkStdVersion, return } } - defer gfile.Remove(flockFilePath) + defer gfile.RemoveFile(flockFilePath) _ = gfile.PutContents(flockFilePath, gtime.TimestampStr()) // check this updated file is an api file. diff --git a/cmd/gf/internal/cmd/genctrl/genctrl_generate_ctrl_clear.go b/cmd/gf/internal/cmd/genctrl/genctrl_generate_ctrl_clear.go index 73d562648b6..af328f8dd6e 100644 --- a/cmd/gf/internal/cmd/genctrl/genctrl_generate_ctrl_clear.go +++ b/cmd/gf/internal/cmd/genctrl/genctrl_generate_ctrl_clear.go @@ -49,7 +49,7 @@ func (c *controllerClearer) doClear(dstModuleFolderPath string, item apiItem) (e `remove unimplemented and of no api definitions controller file: %s`, methodFilePath, ) - err = gfile.Remove(methodFilePath) + err = gfile.RemoveFile(methodFilePath) } } return diff --git a/cmd/gf/internal/cmd/gendao/gendao_clear.go b/cmd/gf/internal/cmd/gendao/gendao_clear.go index ad05918c37b..181804641b7 100644 --- a/cmd/gf/internal/cmd/gendao/gendao_clear.go +++ b/cmd/gf/internal/cmd/gendao/gendao_clear.go @@ -40,7 +40,7 @@ func doClearItem(item CGenDaoInternalGenItem, allGeneratedFilePaths []string) { } for _, filePath := range generatedFilePaths { if !gstr.InArray(allGeneratedFilePaths, filePath) { - if err := gfile.Remove(filePath); err != nil { + if err := gfile.RemoveFile(filePath); err != nil { mlog.Print(err) } } diff --git a/cmd/gf/internal/cmd/genservice/genservice.go b/cmd/gf/internal/cmd/genservice/genservice.go index 392cd4308e4..e02ed91ea4a 100644 --- a/cmd/gf/internal/cmd/genservice/genservice.go +++ b/cmd/gf/internal/cmd/genservice/genservice.go @@ -114,7 +114,7 @@ func (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGe return } } - defer gfile.Remove(flockFilePath) + defer gfile.RemoveFile(flockFilePath) _ = gfile.PutContents(flockFilePath, gtime.TimestampStr()) // It works only if given WatchFile is in SrcFolder. @@ -253,7 +253,7 @@ func (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGe utils.IsFileDoNotEdit(relativeFilePath) { mlog.Printf(`remove no longer used service file: %s`, relativeFilePath) - if err = gfile.Remove(file); err != nil { + if err = gfile.RemoveFile(file); err != nil { return nil, err } } diff --git a/contrib/registry/file/file_discovery.go b/contrib/registry/file/file_discovery.go index 5fd21a7418e..b5c03d977b4 100644 --- a/contrib/registry/file/file_discovery.go +++ b/contrib/registry/file/file_discovery.go @@ -99,7 +99,7 @@ func (r *Registry) getServices(ctx context.Context) (services []gsvc.Service, er `service "%s" is expired, update at: %s, current: %s, sub duration: %s`, s.GetKey(), updateAt.String(), nowTime.String(), subDuration.String(), ) - _ = gfile.Remove(filePath) + _ = gfile.RemoveFile(filePath) continue } services = append(services, s) diff --git a/contrib/registry/file/file_registrar.go b/contrib/registry/file/file_registrar.go index d98098779d3..d7bdfb8eedc 100644 --- a/contrib/registry/file/file_registrar.go +++ b/contrib/registry/file/file_registrar.go @@ -44,7 +44,7 @@ func (r *Registry) Register(ctx context.Context, service gsvc.Service) (register // Deregister off-lines and removes `service` from the Registry. func (r *Registry) Deregister(ctx context.Context, service gsvc.Service) error { - return gfile.Remove(r.getServiceFilePath(service)) + return gfile.RemoveFile(r.getServiceFilePath(service)) } func (r *Registry) getServiceFilePath(service gsvc.Service) string { diff --git a/os/gfile/gfile.go b/os/gfile/gfile.go index 7222ed900fb..ee1c902f150 100644 --- a/os/gfile/gfile.go +++ b/os/gfile/gfile.go @@ -252,6 +252,10 @@ func Glob(pattern string, onlyNames ...bool) ([]string, error) { // If parameter `path` is directory, it deletes it recursively. // // It does nothing if given `path` does not exist or is empty. +// +// Deprecated: +// As the name Remove for files deleting is ambiguous, +// please use RemoveFile or RemoveAll for explicit usage instead. func Remove(path string) (err error) { // It does nothing if `path` is empty. if path == "" { @@ -263,6 +267,25 @@ func Remove(path string) (err error) { return } +// RemoveFile removes the named file or (empty) directory. +func RemoveFile(path string) (err error) { + if err = os.Remove(path); err != nil { + err = gerror.Wrapf(err, `os.Remove failed for path "%s"`, path) + } + return +} + +// RemoveAll removes path and any children it contains. +// It removes everything it can but returns the first error +// it encounters. If the path does not exist, RemoveAll +// returns nil (no error). +func RemoveAll(path string) (err error) { + if err = os.RemoveAll(path); err != nil { + err = gerror.Wrapf(err, `os.RemoveAll failed for path "%s"`, path) + } + return +} + // IsReadable checks whether given `path` is readable. func IsReadable(path string) bool { result := true @@ -270,7 +293,9 @@ func IsReadable(path string) bool { if err != nil { result = false } - file.Close() + if file != nil { + _ = file.Close() + } return result } @@ -294,7 +319,9 @@ func IsWritable(path string) bool { if err != nil { result = false } - _ = file.Close() + if file != nil { + _ = file.Close() + } } return result } @@ -406,15 +433,17 @@ func IsEmpty(path string) bool { if err != nil { return true } + if file == nil { + return true + } defer file.Close() names, err := file.Readdirnames(-1) if err != nil { return true } return len(names) == 0 - } else { - return stat.Size() == 0 } + return stat.Size() == 0 } // Ext returns the file name extension used by path. diff --git a/os/gfile/gfile_z_unit_test.go b/os/gfile/gfile_z_unit_test.go index 4760ce1abff..40696d871de 100644 --- a/os/gfile/gfile_z_unit_test.go +++ b/os/gfile/gfile_z_unit_test.go @@ -16,6 +16,7 @@ import ( "github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/test/gtest" "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/util/guid" ) func Test_IsDir(t *testing.T) { @@ -213,7 +214,6 @@ func Test_OpenWithFlagPerm(t *testing.T) { } func Test_Exists(t *testing.T) { - gtest.C(t, func(t *gtest.T) { var ( flag bool @@ -685,3 +685,43 @@ func Test_MTimestamp(t *testing.T) { t.Assert(gfile.MTimestamp(gfile.Temp()) > 0, true) }) } + +func Test_RemoveFile_RemoveAll(t *testing.T) { + // safe deleting single file. + gtest.C(t, func(t *gtest.T) { + path := gfile.Temp(guid.S()) + err := gfile.PutContents(path, "1") + t.AssertNil(err) + t.Assert(gfile.Exists(path), true) + + err = gfile.RemoveFile(path) + t.AssertNil(err) + t.Assert(gfile.Exists(path), false) + }) + // error deleting dir which is not empty. + gtest.C(t, func(t *gtest.T) { + var ( + err error + dirPath = gfile.Temp(guid.S()) + filePath1 = gfile.Join(dirPath, guid.S()) + filePath2 = gfile.Join(dirPath, guid.S()) + ) + err = gfile.PutContents(filePath1, "1") + t.AssertNil(err) + t.Assert(gfile.Exists(filePath1), true) + + err = gfile.PutContents(filePath2, "2") + t.AssertNil(err) + t.Assert(gfile.Exists(filePath2), true) + + err = gfile.RemoveFile(dirPath) + t.AssertNE(err, nil) + t.Assert(gfile.Exists(filePath1), true) + t.Assert(gfile.Exists(filePath2), true) + + err = gfile.RemoveAll(dirPath) + t.AssertNil(err) + t.Assert(gfile.Exists(filePath1), false) + t.Assert(gfile.Exists(filePath2), false) + }) +} diff --git a/os/glog/glog_logger_rotate.go b/os/glog/glog_logger_rotate.go index 4df261d1a53..7e840361663 100644 --- a/os/glog/glog_logger_rotate.go +++ b/os/glog/glog_logger_rotate.go @@ -55,7 +55,7 @@ func (l *Logger) doRotateFile(ctx context.Context, filePath string) error { // No backups, it then just removes the current logging file. if l.config.RotateBackupLimit == 0 { - if err := gfile.Remove(filePath); err != nil { + if err := gfile.RemoveFile(filePath); err != nil { return err } intlog.Printf( @@ -216,7 +216,7 @@ func (l *Logger) rotateChecksTimely(ctx context.Context) { err := gcompress.GzipFile(path, path+".gz") if err == nil { intlog.Printf(ctx, `compressed done, remove original logging file: %s`, path) - if err = gfile.Remove(path); err != nil { + if err = gfile.RemoveFile(path); err != nil { intlog.Print(ctx, err) } } else { @@ -264,7 +264,7 @@ func (l *Logger) rotateChecksTimely(ctx context.Context) { for i := 0; i < diff; i++ { path, _ := backupFiles.PopLeft() intlog.Printf(ctx, `remove exceeded backup limit file: %s`, path) - if err := gfile.Remove(path.(string)); err != nil { + if err = gfile.RemoveFile(path.(string)); err != nil { intlog.Errorf(ctx, `%+v`, err) } } @@ -284,7 +284,7 @@ func (l *Logger) rotateChecksTimely(ctx context.Context) { `%v - %v = %v > %v, remove expired backup file: %s`, now, mtime, subDuration, l.config.RotateBackupExpire, path, ) - if err := gfile.Remove(path); err != nil { + if err = gfile.RemoveFile(path); err != nil { intlog.Errorf(ctx, `%+v`, err) } return true diff --git a/os/gsession/gsession_storage_file.go b/os/gsession/gsession_storage_file.go index fdf5b54c3f3..27c83dcd662 100644 --- a/os/gsession/gsession_storage_file.go +++ b/os/gsession/gsession_storage_file.go @@ -128,7 +128,7 @@ func (s *StorageFile) sessionFilePath(sessionId string) string { // RemoveAll deletes all key-value pairs from storage. func (s *StorageFile) RemoveAll(ctx context.Context, sessionId string) error { - return gfile.Remove(s.sessionFilePath(sessionId)) + return gfile.RemoveAll(s.sessionFilePath(sessionId)) } // GetSession returns the session data as *gmap.StrAnyMap for given session id from storage. @@ -262,7 +262,7 @@ func (s *StorageFile) checkAndClearSessionFile(ctx context.Context, path string) path, gtime.NewFromTimeStamp(fileTimestampMilli), s.ttl, ) }) - return gfile.Remove(path) + return gfile.RemoveFile(path) } return nil }