From 0384a39b595e3e9d0781d90b1dba611a9b806a21 Mon Sep 17 00:00:00 2001 From: Orion C Date: Tue, 16 Apr 2024 17:11:02 +0200 Subject: [PATCH] Enhancements --- README.md | 19 +++++++++---------- cmd/docker.go | 9 +++++---- cmd/files.go | 16 +++++++++------- cmd/root.go | 36 +++++++++++++++++++++--------------- cmd/search.go | 26 ++++++++++++-------------- go.mod | 3 +++ go.sum | 14 ++++++++++++++ 7 files changed, 73 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index c629dd8..bddc0e2 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ # 🐤 Compose from anywhere -Small utility to run `docker-compose` commands on your projects without having to `cd` into them. +Small utility to run `docker compose` commands on your projects without having to `cd` into them. -It is heavily inspired from [Captain](https://github.com/jenssegers/captain) but aims at being fully transparent by forwarding commands to the `docker-compose` [CLI](https://docs.docker.com/compose/reference/), so that all the commad you already use and know keep working out of the box. +It is heavily inspired from [Captain](https://github.com/jenssegers/captain) but aims at being fully transparent by forwarding commands to the `docker compose` [CLI](https://docs.docker.com/compose/reference/), so that all the commad you already use and know keep working out of the box. ```bash # Replace $ cd path/to/my/project1 -$ docker-compose down +$ docker compose down $ cd other/path/project2 -$ docker-compose up -d +$ docker compose up -d # By $ cfa project1 down @@ -19,7 +19,7 @@ $ cfa project2 up -d **cfa** scans your directories looking for a `docker-compose.yml` file. Every folder meeting the condition are marked as candidate projects that you can operate on from anywhere. -Note that the project names are fuzzy searched. If several projects have a similar name, `cfa` will give you a list to chose from +Note that the project names are fuzzy searched. If several projects have a similar name, `cfa` will give you a list to chose from. ## Installing @@ -34,18 +34,18 @@ If you don't have Go installed on your machine you can download the executables. ### MacOSX ``` -curl -L https://github.com/riron/cfa/releases/download/v0.0.2/cfa_darwin_amd64 > /usr/local/bin/cfa && chmod +x /usr/local/bin/cfa +curl -L https://github.com/riron/cfa/releases/download/v1/cfa_darwin_amd64 > /usr/local/bin/cfa && chmod +x /usr/local/bin/cfa ``` ### Linux ``` -curl -L https://github.com/riron/cfa/releases/download/v0.0.2/cfa_linux_amd64 > /usr/local/bin/cfa && chmod +x /usr/local/bin/cfa +curl -L https://github.com/riron/cfa/releases/download/v1/cfa_linux_amd64 > /usr/local/bin/cfa && chmod +x /usr/local/bin/cfa ``` ### Windows -Download [the executable](https://github.com/riron/cfa/releases/download/v0.0.2/cfa_windows_amd64.exe), rename it to `cfa.exe` and add it to your path +Download [the executable](https://github.com/riron/cfa/releases/download/v1/cfa_windows_amd64.exe), rename it to `cfa.exe` and add it to your path ## Usage @@ -68,12 +68,11 @@ cfa -f=my_pro cfa -s Flags: - -D, --dev Shorthand for -u=dev -f, --find string List projects corresponding to search -h, --help help for cfa -l, --list List all available projects -s, --stop Stop all running containers - -u, --suffix string Use a suffixed compose file (ex: -s=dev will use the docker-compose.dev.yml file) + -u, --suffix string Use a suffixed compose file (ex: -u=dev will use the docker-compose.dev.yml file) ``` ## Config diff --git a/cmd/docker.go b/cmd/docker.go index 2a2422e..e112bad 100644 --- a/cmd/docker.go +++ b/cmd/docker.go @@ -5,12 +5,13 @@ import ( "os/exec" ) -func composeCommand(project Project, devEnv string, args []string) error { - if devEnv != "" { - args = append([]string{"-f", "docker-compose." + devEnv + ".yml"}, args...) +func composeCommand(project Project, composeSuffix string, args []string) error { + if composeSuffix != "" { + args = append([]string{"-f", "docker-compose." + composeSuffix + ".yml"}, args...) } - return run(project.Path, "docker-compose", args...) + args = append([]string{"compose"}, args...) + return run(project.Path, "docker", args...) } func stopContainers() error { diff --git a/cmd/files.go b/cmd/files.go index 7178699..5630246 100644 --- a/cmd/files.go +++ b/cmd/files.go @@ -2,7 +2,7 @@ package cmd import ( "fmt" - "io/ioutil" + "os" "path/filepath" "strings" "sync" @@ -34,7 +34,7 @@ func scan(wg *sync.WaitGroup, folder string, depth int, results chan Project) { defer wg.Done() // Get all files and subdirectories in this directory. - files, _ := ioutil.ReadDir(folder) + files, _ := os.ReadDir(folder) var directories []string for _, file := range files { @@ -43,13 +43,17 @@ func scan(wg *sync.WaitGroup, folder string, depth int, results chan Project) { // Add subdirectories to list of yet to be scanned directories. if file.IsDir() { // Check if folder is in blacklist. + isBlackListed := false for _, blacklist := range config.Blacklist { - if blacklist == path { + if blacklist == path || strings.Contains(path, blacklist) { + isBlackListed = true continue } } - directories = append(directories, path) + if !isBlackListed { + directories = append(directories, path) + } continue } @@ -72,8 +76,6 @@ func scan(wg *sync.WaitGroup, folder string, depth int, results chan Project) { go scan(wg, folder, depth-1, results) } } - - return } func printList(pattern string) { @@ -92,6 +94,6 @@ func printList(pattern string) { fmt.Printf("%d project(s) found:\n", len(ps)) cyan := color.New(color.FgCyan).SprintFunc() for _, project := range ps { - fmt.Fprintf(color.Output,"* %s (%s)\n", project.Name, cyan(project.Path+"\\docker-compose.yml")) + fmt.Fprintf(color.Output, "* %s (%s)\n", project.Name, cyan(project.Path+"/docker-compose.yml")) } } diff --git a/cmd/root.go b/cmd/root.go index 2d50b3e..451614b 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -6,13 +6,12 @@ import ( "os/user" "strconv" - "github.com/spf13/cobra" "github.com/fatih/color" + "github.com/spf13/cobra" ) var config Config -var composeEnv string -var devEnv bool +var composeSuffix string var list bool var stop bool var find string @@ -23,7 +22,7 @@ var rootCmd = &cobra.Command{ cfa -u=dev my_project exec my_container sh cfa -f=my_pro cfa -s`, - Short: "Docker-compose from anywhere", + Short: "docker compose from anywhere", Long: `Manage your compose projects from anywhere cfa allows you to use the same compose CLI you already know @@ -59,13 +58,9 @@ and run your compose command on it.`, } cyan := color.New(color.FgCyan).SprintFunc() - fmt.Fprintf(color.Output,"Using project %s...\n", cyan(project.Name)) - - if devEnv { - composeEnv = "dev" - } + fmt.Fprintf(color.Output, "Using project %s...\n", cyan(project.Name)) - composeCommand(project, composeEnv, args[1:]) + composeCommand(project, composeSuffix, args[1:]) }, } @@ -74,8 +69,7 @@ func init() { rootCmd.Flags().BoolVarP(&list, "list", "l", false, "List all available projects") rootCmd.Flags().BoolVarP(&stop, "stop", "s", false, "Stop all running containers") - rootCmd.Flags().StringVarP(&composeEnv, "suffix", "u", "", "Use a suffixed compose file (ex: -s=dev will use the docker-compose.dev.yml file)") - rootCmd.Flags().BoolVarP(&devEnv, "dev", "D", false, "Shorthand for -u=dev") + rootCmd.Flags().StringVarP(&composeSuffix, "suffix", "u", "", "Use a suffixed compose file (ex: -u=dev will use the docker-compose.dev.yml file)") rootCmd.Flags().StringVarP(&find, "find", "f", "", "List projects corresponding to search") rootCmd.Flags().SetInterspersed(false) } @@ -84,9 +78,21 @@ func initConfig() { usr, _ := user.Current() config = Config{ - Blacklist: []string{usr.HomeDir + "/Library", usr.HomeDir + "/Applications"}, - Root: usr.HomeDir, - Depth: 5, + Blacklist: []string{ + usr.HomeDir + "/Library", + usr.HomeDir + "/Applications", + "/node_modules", + "/vendor", + "/target", + ".cache", + ".git", + ".github", + ".idea", + ".vscode", + ".terraform", + }, + Root: usr.HomeDir, + Depth: 7, } depth, ok := os.LookupEnv("CFA_DEPTH") diff --git a/cmd/search.go b/cmd/search.go index 6c8d200..c6865a8 100644 --- a/cmd/search.go +++ b/cmd/search.go @@ -2,9 +2,9 @@ package cmd import ( "errors" - "fmt" "github.com/fatih/color" + "github.com/manifoldco/promptui" "github.com/sahilm/fuzzy" ) @@ -22,7 +22,7 @@ func match(projects []Project, pattern string) ([]Project, error) { matches := fuzzy.Find(pattern, list) if matches.Len() == 0 { - return []Project{}, errors.New("No match found") + return []Project{}, errors.New("no match found") } filteredProjects := make([]Project, 0, len(matches)) @@ -41,25 +41,23 @@ func search(pattern string) (Project, error) { } if len(matches) > 1 { - fmt.Println("The following projects are candidates:") cyan := color.New(color.FgCyan).SprintFunc() + items := make([]string, len(matches)) for idx, match := range matches { - fmt.Fprintf(color.Output, "%d. %s (%s)\n", idx+1, match.Name, cyan(match.Path)) + items[idx] = match.Name + " " + cyan(match.Path) } - - fmt.Println("Which one do you want to use ?") - var choice int - n, err := fmt.Scanf("%d\n", &choice) - - if err != nil || n != 1 { - return Project{}, errors.New("Invalid choice selected") + prompt := promptui.Select{ + Label: "The following projects are candidates", + Items: items, } - if choice <= len(matches) && choice > 0 { - return matches[choice-1], nil + choice, _, err := prompt.Run() + + if err != nil { + return Project{}, errors.New("invalid choice selected") } - return Project{}, errors.New("This is not an acceptable choice") + return matches[choice], nil } return matches[0], nil diff --git a/go.mod b/go.mod index aeb7ae4..104d392 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,11 @@ module github.com/riron/cfa +go 1.15 + require ( github.com/fatih/color v1.9.0 github.com/kylelemons/godebug v1.1.0 // indirect + github.com/manifoldco/promptui v0.8.0 github.com/mitchellh/gox v1.0.1 // indirect github.com/sahilm/fuzzy v0.1.0 github.com/spf13/cobra v1.0.0 diff --git a/go.sum b/go.sum index 6cc3373..bee2473 100644 --- a/go.sum +++ b/go.sum @@ -7,6 +7,10 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -44,6 +48,8 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU= +github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= @@ -54,9 +60,15 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a h1:weJVJJRzAJBFRlAiJQROKQs8oC9vOxvm4rZmBBk0ONw= +github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/manifoldco/promptui v0.8.0 h1:R95mMF+McvXZQ7j1g8ucVZE1gLP3Sv6j9vlF9kyRqQo= +github.com/manifoldco/promptui v0.8.0/go.mod h1:n4zTdgP0vr0S3w7/O/g98U+e0gwLScEXGwov2nIKuGQ= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= @@ -124,8 +136,10 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=