about summary refs log tree commit diff
path: root/tools/symlinkManager
diff options
context:
space:
mode:
authorWilliam Carroll <wpcarro@gmail.com>2020-02-12T16·58+0000
committerWilliam Carroll <wpcarro@gmail.com>2020-02-12T16·58+0000
commitfabf1c9334a86d55be133da851cafccc9e6319fe (patch)
treee5c07cbe676c4955d9a48742d00e0081b16b3446 /tools/symlinkManager
parent5ec5a6da8cbfe3c35558fd2c17ef779b5d0ccb54 (diff)
Tidy up structure of briefcase
I had a spare fifteen minutes and decided that I should tidy up my
monorepo. The work of tidying up is not finished; this is a small step in the
right direction.

TL;DR
- Created a tools directory
- Created a scratch directory (see README.md for more information)
- Added README.md to third_party
- Renamed delete_dotfile_symlinks -> symlinkManager
- Packaged symlinkManager as an executable symlink-mgr using buildGo
Diffstat (limited to 'tools/symlinkManager')
-rw-r--r--tools/symlinkManager/README.md14
-rw-r--r--tools/symlinkManager/default.nix15
-rw-r--r--tools/symlinkManager/main.go83
3 files changed, 112 insertions, 0 deletions
diff --git a/tools/symlinkManager/README.md b/tools/symlinkManager/README.md
new file mode 100644
index 000000000000..b0fc58c8e989
--- /dev/null
+++ b/tools/symlinkManager/README.md
@@ -0,0 +1,14 @@
+# Dotfile Symlink Manager
+
+Find and delete all symlinks to the dotfiles defined in `$BRIEFCASE`.
+
+Oftentimes I corrupt the state of my configuration files. The intention with
+this script is to help me clean things up when this happens. An example workflow
+might look like:
+
+```shell
+> symlink-mgr --audit
+> symlink-mgr --seriously
+> briefcase # changes directory to $BRIEFCASE
+> make install
+```
diff --git a/tools/symlinkManager/default.nix b/tools/symlinkManager/default.nix
new file mode 100644
index 000000000000..6500991babb9
--- /dev/null
+++ b/tools/symlinkManager/default.nix
@@ -0,0 +1,15 @@
+{
+  depot ? import <depot> {},
+  briefcase ? import <briefcase> {},
+  ...
+}:
+
+depot.buildGo.program {
+  name = "symlink-mgr";
+  srcs = [
+    ./main.go
+  ];
+  deps = with briefcase.gopkgs; [
+    utils
+  ];
+}
diff --git a/tools/symlinkManager/main.go b/tools/symlinkManager/main.go
new file mode 100644
index 000000000000..5d133e37d97b
--- /dev/null
+++ b/tools/symlinkManager/main.go
@@ -0,0 +1,83 @@
+package main
+
+import (
+	"errors"
+	"flag"
+	"fmt"
+	"log"
+	"os"
+	"path/filepath"
+	"strings"
+	"utils"
+)
+
+var hostnames = map[string]string{
+	os.Getenv("DESKTOP"):  "desktop",
+	os.Getenv("LAPTOP"):   "work_laptop",
+	os.Getenv("CLOUDTOP"): "cloudtop",
+}
+
+func main() {
+	audit := flag.Bool("audit", false, "Output all symlinks that would be deleted. This is the default behavior. This option is mutually exclusive with the --seriously option.")
+	seriously := flag.Bool("seriously", false, "Actually delete the symlinks. This option is mutually exclusive with the --audit option.")
+	repoName := flag.String("repo-name", "briefcase", "The name of the repository.")
+	deviceOnly := flag.Bool("device-only", false, "Only output the device-specific dotfiles.")
+	flag.Parse()
+
+	if !*audit && !*seriously {
+		log.Fatal(errors.New("Either -audit or -seriously needs to be set."))
+	}
+	if *audit == *seriously {
+		log.Fatal(errors.New("Arguments -audit and -seriously are mutually exclusive"))
+	}
+
+	home, err := os.UserHomeDir()
+	utils.FailOn(err)
+	count := 0
+
+	err = filepath.Walk(home, func(path string, info os.FileInfo, err error) error {
+		if utils.IsSymlink(info.Mode()) {
+			dest, err := os.Readlink(path)
+			utils.FailOn(err)
+
+			var predicate func(string) bool
+
+			if *deviceOnly {
+				predicate = func(dest string) bool {
+					var hostname string
+					hostname, err = os.Hostname()
+					utils.FailOn(err)
+					seeking, ok := hostnames[hostname]
+					if !ok {
+						log.Fatal(fmt.Sprintf("Hostname \"%s\" not supported in the hostnames map.", hostname))
+					}
+					return strings.Contains(dest, *repoName) && strings.Contains(dest, seeking)
+				}
+			} else {
+				predicate = func(dest string) bool {
+					return strings.Contains(dest, *repoName)
+				}
+			}
+
+			if predicate(dest) {
+				if *audit {
+					fmt.Printf("%s -> %s\n", path, dest)
+				} else if *seriously {
+					fmt.Printf("rm %s\n", path)
+					err = os.Remove(path)
+					utils.FailOn(err)
+				}
+				count += 1
+			}
+		}
+		return nil
+	})
+	utils.FailOn(err)
+	if *audit {
+		fmt.Printf("Would have deleted %d symlinks.\n", count)
+	} else if *seriously {
+		fmt.Printf("Successfully deleted %d symlinks.\n", count)
+	}
+
+	os.Exit(0)
+}