From fffcecaff0d0a87304922f5ada9e7e5d2e1def06 Mon Sep 17 00:00:00 2001 From: Maxime Bouillot Date: Mon, 23 May 2022 08:53:46 +0200 Subject: [PATCH 1/5] Tried to comply to the XDG specifications. The trash directory by default is $XDG_DATA_HOME/remTrash. If XDG_DATA_HOME is not set, the choice of the trash directory is made in a smart-ish way. I know that I will definitively not use this software if it is going to add clutter to my home directory and I might not be the only one in that case. Following the XDG specification could let REM be used by more people. --- rem.go | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/rem.go b/rem.go index c582a92..767393e 100644 --- a/rem.go +++ b/rem.go @@ -31,8 +31,7 @@ Options: --disable-copy if files are on a different fs, don't rename by copy -h/--help print this help message -v/--version print Rem version` - home, _ = os.UserHomeDir() - trashDir = home + "/.remTrash" + trashDir string logFileName = ".trash.log" logFile map[string]string renameByCopyIsAllowed = true @@ -42,7 +41,7 @@ Options: // TODO: Multiple Rem instances could clobber log file. Fix using either file locks or tcp port locks. func main() { - trashDir, _ = filepath.Abs(trashDir) + trashDir, _ = filepath.Abs(chooseTrashDir()) if len(os.Args) == 1 { handleErrStr("too few arguments") fmt.Println(helpMsg) @@ -300,6 +299,35 @@ func ensureTrashDir() { } } +// Choose the best directory for the REM trash and returns it +// The choice is the following; +// * If the environment variable REM_TRASH exists, it is used as the path for +// the trash. +// * If the environment variable XDG_DATA_HOME exists, $XDG_DATA_HOME/remTrash +// is used as the path for the trash. +// * If ~/.local/share exists and is a directory, ~/.local/share/remTrash is +// used as the path for the trash. +// * If no other option works, ~/.remTrash is used as the path for the trash. +func chooseTrashDir() string { + home, _ := os.UserHomeDir() + remEnv := os.Getenv("REM_TRASH") + if remEnv != "" { + return remEnv + } + dataHome := os.Getenv("XDG_DATA_HOME") + if dataHome != "" { + return dataHome + "/remTrash" + } + dirtyDataHome := home + "/.local/share" + stats, err := os.Stat(dirtyDataHome) + if !(os.IsNotExist(err)) { + if stats.IsDir() { + return dirtyDataHome + "/remTrash" + } + } + return home + "/.remTrash" +} + func permanentlyDeleteFile(fileName string) { err := os.RemoveAll(fileName) if err != nil { From c7f61d642149da3f6997d777af3ac2dcb940cf5e Mon Sep 17 00:00:00 2001 From: Maxime Bouillot Date: Mon, 23 May 2022 09:44:41 +0200 Subject: [PATCH 2/5] Updated README to speak about directory selection. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c809e38..e395568 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ Simply remove the executable or use: brew uninstall rem ``` -Rem stores its trash by default at `~/.remTrash`. +Rem stores its trash by default at `$XDG_DATA_HOME/remTrash`. Alternatively, you can supply the path to the trash in the environment variable `REM_TRASH`, or supplying it with the `-d` command line argument. ## Usage From a16ba61d56bc4f2e092a5aeb1e892bd80bba8e6c Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Mon, 23 May 2022 17:09:24 +0000 Subject: [PATCH 3/5] Use a data directory in which the log and trash exist, improve brevity --- README.md | 10 ++++---- rem.go | 77 ++++++++++++++++++++++++++----------------------------- 2 files changed, 42 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index e395568..e2c971f 100644 --- a/README.md +++ b/README.md @@ -58,25 +58,25 @@ Simply remove the executable or use: brew uninstall rem ``` -Rem stores its trash by default at `$XDG_DATA_HOME/remTrash`. Alternatively, you can supply the path to the trash in the environment variable `REM_TRASH`, or supplying it with the `-d` command line argument. - ## Usage ```text -Usage: rem [-t/--set-trash ] [--disable-copy] [--permanent | -u/--undo] ... +Usage: rem [-t/--set-dir ] [--disable-copy] [--permanent | -u/--undo] ... rem [-d/--directory | --empty | -h/--help | -v/--version | -l/--list] Options: -u/--undo restore a file -l/--list list files in trash --empty empty the trash permanently --permanent delete a file permanently - -d/--directory show path to trash - -t/--set-trash set trash to dir and continue + -d/--directory show path to the data dir + -t/--set-dir set the data dir and continue --disable-copy if files are on a different fs, don't rename by copy -h/--help print this help message -v/--version print Rem version ``` +Rem stores its data at `$XDG_DATA_HOME/rem` or `.local/share/rem` by default. Alternatively, set the data directory using `$REM_TRASH` or with the `-d` option. + ## Thanks Thanks to [u/skeeto](https://www.reddit.com/user/skeeto/) for helping me with race conditions and design [here](https://www.reddit.com/r/golang/comments/lixr6k/rem_the_trash_cli_that_makes_it_ridiculously_easy/gn7z86z?utm_source=share&utm_medium=web2x&context=3) diff --git a/rem.go b/rem.go index 767393e..df771f6 100644 --- a/rem.go +++ b/rem.go @@ -19,19 +19,19 @@ var ( version = "dev" // this is set on release build (check .goreleaser.yml) helpMsg = `Rem - Get some rem sleep knowing your files are safe Rem is a CLI Trash -Usage: rem [-t/--set-trash ] [--disable-copy] [--permanent | -u/--undo] ... +Usage: rem [-t/--set-dir ] [--disable-copy] [--permanent | -u/--undo] ... rem [-d/--directory | --empty | -h/--help | -v/--version | -l/--list] Options: -u/--undo restore a file -l/--list list files in trash --empty empty the trash permanently --permanent delete a file permanently - -d/--directory show path to trash - -t/--set-trash set trash to dir and continue + -d/--directory show path to the data dir + -t/--set-dir set the data dir and continue --disable-copy if files are on a different fs, don't rename by copy -h/--help print this help message -v/--version print Rem version` - trashDir string + dataDir string logFileName = ".trash.log" logFile map[string]string renameByCopyIsAllowed = true @@ -41,7 +41,6 @@ Options: // TODO: Multiple Rem instances could clobber log file. Fix using either file locks or tcp port locks. func main() { - trashDir, _ = filepath.Abs(chooseTrashDir()) if len(os.Args) == 1 { handleErrStr("too few arguments") fmt.Println(helpMsg) @@ -69,13 +68,16 @@ func main() { } return } - if hasOption, i := argsHaveOption("set-trash", "t"); hasOption { + + dataDir, _ = filepath.Abs(chooseDataDir()) + + if hasOption, i := argsHaveOption("set-dir", "t"); hasOption { if !(len(os.Args) > i+1) { - handleErrStr("Not enough arguments for --set-trash") + handleErrStr("Not enough arguments for --set-dir") return } //fmt.Println("Using " + os.Args[i+1] + " as trash") - trashDir = os.Args[i+1] + dataDir = os.Args[i+1] os.Args = removeElemFromSlice(os.Args, i+1) // remove the specified dir too os.Args = removeElemFromSlice(os.Args, i) main() @@ -83,7 +85,7 @@ func main() { } if hasOption, _ := argsHaveOption("directory", "d"); hasOption { - fmt.Println(trashDir) + fmt.Println(dataDir) return } if hasOption, _ := argsHaveOption("list", "l"); hasOption { @@ -91,7 +93,7 @@ func main() { return } if hasOption, _ := argsHaveOptionLong("empty"); hasOption { - color.Red("Warning, permanently deleting all files in " + trashDir) + color.Red("Warning, permanently deleting all files in " + dataDir + "/trash") if promptBool("Confirm delete?") { emptyTrash() } @@ -149,7 +151,7 @@ func trashFile(path string) { var toMoveTo string var err error path = filepath.Clean(path) - toMoveTo = trashDir + "/" + filepath.Base(path) + toMoveTo = dataDir + "/trash/" + filepath.Base(path) if path == toMoveTo { // small edge case when trashing a file from trash handleErrStr(color.YellowString(path) + " is already in trash") return @@ -233,7 +235,8 @@ func listFilesInTrash() []string { } func emptyTrash() { - permanentlyDeleteFile(trashDir) + permanentlyDeleteFile(dataDir + "/trash") + permanentlyDeleteFile(dataDir + "/" + logFileName) } func getLogFile() map[string]string { @@ -241,7 +244,7 @@ func getLogFile() map[string]string { return logFile } ensureTrashDir() - file, err := os.OpenFile(trashDir+"/"+logFileName, os.O_CREATE|os.O_RDONLY, 0644) + file, err := os.OpenFile(dataDir+"/"+logFileName, os.O_CREATE|os.O_RDONLY, 0644) if err != nil { handleErr(err) return nil @@ -259,7 +262,7 @@ func getLogFile() map[string]string { func setLogFile(m map[string]string) { //f, err := os.OpenFile(trashDir+"/"+logFileName, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644) // truncate to empty, create if not exist, write only ensureTrashDir() - f, err := os.Create(trashDir + "/" + logFileName) + f, err := os.Create(dataDir + "/" + logFileName) if err != nil { handleErr(err) return @@ -284,9 +287,9 @@ func existsInLog(elem string) bool { } func ensureTrashDir() { - i, _ := os.Stat(trashDir) - if !exists(trashDir) { - err := os.MkdirAll(trashDir, os.ModePerm) + i, _ := os.Stat(dataDir + "/trash") + if !exists(dataDir + "/trash") { + err := os.MkdirAll(dataDir+"/trash", os.ModePerm) if err != nil { handleErr(err) return @@ -294,38 +297,32 @@ func ensureTrashDir() { return } if !i.IsDir() { - permanentlyDeleteFile(trashDir) // not a dir so delete - ensureTrashDir() // then make it + permanentlyDeleteFile(dataDir + "/trash") // not a dir so delete + ensureTrashDir() // then make it } } -// Choose the best directory for the REM trash and returns it -// The choice is the following; -// * If the environment variable REM_TRASH exists, it is used as the path for -// the trash. -// * If the environment variable XDG_DATA_HOME exists, $XDG_DATA_HOME/remTrash -// is used as the path for the trash. -// * If ~/.local/share exists and is a directory, ~/.local/share/remTrash is -// used as the path for the trash. -// * If no other option works, ~/.remTrash is used as the path for the trash. -func chooseTrashDir() string { +// chooseDataDir returns the best directory to store data based on $REM_TRASH and $XDG_DATA_HOME, +// using ~/.local/share/rem as the default if neither is set. +func chooseDataDir() string { home, _ := os.UserHomeDir() - remEnv := os.Getenv("REM_TRASH") + remEnv := os.Getenv("REM_DATADIR") if remEnv != "" { return remEnv } dataHome := os.Getenv("XDG_DATA_HOME") if dataHome != "" { - return dataHome + "/remTrash" - } - dirtyDataHome := home + "/.local/share" - stats, err := os.Stat(dirtyDataHome) - if !(os.IsNotExist(err)) { - if stats.IsDir() { - return dirtyDataHome + "/remTrash" - } - } - return home + "/.remTrash" + return dataHome + "/rem/trash" + } + return home + "/.local/share/rem" + // dirtyDataHome := home + "/.local/share" + // stats, err := os.Stat(dirtyDataHome) + // if !(os.IsNotExist(err)) { + // if stats.IsDir() { + // return dirtyDataHome + "/rem/trash" + // } + // } + // return home + "/.remTrash" } func permanentlyDeleteFile(fileName string) { From 9c798782360075f113494e6e444dd1694ebad57a Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Mon, 23 May 2022 17:11:44 +0000 Subject: [PATCH 4/5] Remove commented-out code --- rem.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/rem.go b/rem.go index df771f6..41f16af 100644 --- a/rem.go +++ b/rem.go @@ -315,14 +315,6 @@ func chooseDataDir() string { return dataHome + "/rem/trash" } return home + "/.local/share/rem" - // dirtyDataHome := home + "/.local/share" - // stats, err := os.Stat(dirtyDataHome) - // if !(os.IsNotExist(err)) { - // if stats.IsDir() { - // return dirtyDataHome + "/rem/trash" - // } - // } - // return home + "/.remTrash" } func permanentlyDeleteFile(fileName string) { From 2eb9eaaa1b1fa1ad48b8692cb0f5ab63b1e74dc0 Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Mon, 23 May 2022 17:36:26 +0000 Subject: [PATCH 5/5] Fix lint error --- .goreleaser.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index 4fb679c..ead3ca1 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -18,7 +18,7 @@ builds: - amd64 - arm - arm64 - - 386 + - '386' ldflags: - -s -w -X main.version=v{{.Version}} ignore: # problems with build