diff --git a/cli/app.go b/cli/app.go index 28f74150..8fbb6e41 100644 --- a/cli/app.go +++ b/cli/app.go @@ -5,13 +5,15 @@ import ( "fmt" "strings" + "coopcloud.tech/abra/client" + "coopcloud.tech/abra/config" + "github.com/docker/cli/cli/command/formatter" "github.com/docker/cli/cli/command/idresolver" - - "coopcloud.tech/abra/client" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/schultz-is/passgen" + "github.com/sirupsen/logrus" "github.com/urfave/cli/v2" ) @@ -50,6 +52,24 @@ var appListCommand = &cli.Command{ Name: "list", Aliases: []string{"ls"}, Flags: []cli.Flag{StatusFlag, ServerFlag, TypeFlag}, + Action: func(c *cli.Context) error { + // FIXME: Needs to use flags + // TODO: Sorting of output to make servers in alphabetical + // Looks like sorting a 2d slice of strings might be messy though + apps := config.LoadAppFiles() + tableCol := []string{"Name", "Type", "Server"} + table := createTable(tableCol) + for name, appFile := range apps { + app, err := config.GetApp(apps, name) + if err != nil { + logrus.Fatal(err.Error()) + } + tableRow := []string{name, app.Type, appFile.Server} + table.Append(tableRow) + } + table.Render() + return nil + }, } var appCheckCommand = &cli.Command{ Name: "check", diff --git a/config/env.go b/config/env.go index f3cef527..240cd289 100644 --- a/config/env.go +++ b/config/env.go @@ -7,17 +7,15 @@ import ( "io/ioutil" "log" "os" - "os/user" "path" "path/filepath" + "strings" "github.com/joho/godotenv" "github.com/sirupsen/logrus" ) -// TODO: envvar -const ABRA_DIR = ".abra" - +var ABRA_DIR = os.ExpandEnv("$HOME/.abra") var ABRA_SERVER_FOLDER = path.Join(ABRA_DIR, "servers") // Type aliases to make code hints easier to understand @@ -31,25 +29,42 @@ type App struct { Env AppEnv } type AppFile struct { - Path string + Path string + Server string } type AppFiles = map[AppName]AppFile -// func LoadAppFiles() (AppFiles, error) { - -// } +func LoadAppFiles() AppFiles { + appFiles := make(AppFiles) + servers := getAllFoldersInDirectory(ABRA_SERVER_FOLDER) + for _, server := range servers { + serverDir := path.Join(ABRA_SERVER_FOLDER, server) + files := getAllFilesInDirectory(serverDir) + for _, file := range files { + appName := strings.TrimSuffix(file.Name(), ".env") + appFilePath := path.Join(ABRA_SERVER_FOLDER, server, file.Name()) + appFiles[appName] = AppFile{ + Path: appFilePath, + Server: server, + } + } + } + return appFiles +} // GetApp loads an apps settings, reading it from file, in preparation to use it // // ONLY use when ready to use the env file to keep IO down and // because this exits with code 1 if the file cannot be found or is malformed +// FIXME: Cannot read files with multiline vars func GetApp(apps AppFiles, name AppName) (App, error) { appFile, exists := apps[name] if !exists { return App{}, fmt.Errorf("cannot find app file with name '%s'", name) } app, err := readAppFile(appFile, name) + if err != nil { log.Fatalf(err.Error()) } @@ -92,19 +107,36 @@ func makeApp(env AppEnv, name string) (App, error) { }, nil } -func getHomeDir() string { - // Future: Windows support? - user, err := user.Current() - if err != nil { - log.Fatalf(err.Error()) - } - return user.HomeDir +func ReadServerNames() []string { + serverNames := getAllFoldersInDirectory(ABRA_SERVER_FOLDER) + return serverNames } -func ReadServerNames() []string { - serverDir := path.Join(getHomeDir(), ABRA_SERVER_FOLDER) - serverNames := getAllFoldersInDirectory(serverDir) - return serverNames +// getAllFilesInDirectory returns filenames of all files in directory +func getAllFilesInDirectory(directory string) []fs.FileInfo { + var realFiles []fs.FileInfo + files, err := ioutil.ReadDir(directory) + if err != nil { + logrus.Fatal(err.Error()) + } + for _, file := range files { + // Follow any symlinks + filePath := path.Join(directory, file.Name()) + realPath, err := filepath.EvalSymlinks(filePath) + if err != nil { + logrus.Warningf("broken symlink in your abra config folders: '%s'", filePath) + } else { + realFile, err := os.Stat(realPath) + if err != nil { + logrus.Fatal(err.Error()) + } + if !realFile.IsDir() { + realFiles = append(realFiles, file) + } + } + + } + return realFiles } // getAllFoldersInDirectory returns both folder and symlink paths @@ -118,7 +150,7 @@ func getAllFoldersInDirectory(directory string) []string { logrus.Fatal("directory is empty: '%s'", directory) } for _, file := range files { - // Check if file is directory or symlink to one + // Check if file is directory or symlink if file.IsDir() || file.Mode()&fs.ModeSymlink != 0 { filePath := path.Join(directory, file.Name()) realDir, err := filepath.EvalSymlinks(filePath) @@ -128,7 +160,6 @@ func getAllFoldersInDirectory(directory string) []string { // path is a directory folders = append(folders, file.Name()) } - } } return folders