diff --git a/internal/cmd/dirs.go b/internal/cmd/dirs.go index 334a7742a1f2a72f31de964913727b68964d3b89..42fa20b3f931493664b7d9d26d7496e0fb28f10e 100644 --- a/internal/cmd/dirs.go +++ b/internal/cmd/dirs.go @@ -1,8 +1,10 @@ package cmd import ( + "fmt" "os" "path/filepath" + "strings" "charm.land/lipgloss/v2" "charm.land/lipgloss/v2/table" @@ -17,16 +19,27 @@ var dirsCmd = &cobra.Command{ Long: `Print the directories where Crush stores its configuration and data files. This includes the global configuration directory and data directory.`, Example: ` -# Print all directories +# Print all global directories crush dirs -# Print only the config directory +# Print data directory and all project specific config directories +crush dirs -p + +# Print only global config directory crush dirs config +# Print only project specific config directories +crush dirs -p config + # Print only the data directory crush dirs data `, - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { + dirs, err := configDirs(cmd) + if err != nil { + return fmt.Errorf("cannot collect config directories: %w", err) + } + if term.IsTerminal(os.Stdout.Fd()) { // We're in a TTY: make it fancy. t := table.New(). @@ -34,22 +47,29 @@ crush dirs data StyleFunc(func(row, col int) lipgloss.Style { return lipgloss.NewStyle().Padding(0, 2) }). - Row("Config", filepath.Dir(config.GlobalConfig())). + Row("Config", dirs). Row("Data", filepath.Dir(config.GlobalConfigData())) lipgloss.Println(t) - return + return nil } // Not a TTY. - cmd.Println(filepath.Dir(config.GlobalConfig())) + cmd.Println(dirs) cmd.Println(filepath.Dir(config.GlobalConfigData())) + + return nil }, } var configDirCmd = &cobra.Command{ Use: "config", Short: "Print the configuration directory used by Crush", - Run: func(cmd *cobra.Command, args []string) { - cmd.Println(filepath.Dir(config.GlobalConfig())) + RunE: func(cmd *cobra.Command, args []string) error { + dirs, err := configDirs(cmd) + if err != nil { + return fmt.Errorf("cannot collect config directories: %w", err) + } + cmd.Println(dirs) + return nil }, } @@ -61,6 +81,30 @@ var dataDirCmd = &cobra.Command{ }, } +// configDirs returns formatted string with one or more project config paths +func configDirs(cmd *cobra.Command) (string, error) { + configDir := filepath.Dir(config.GlobalConfig()) + if ok, _ := cmd.Flags().GetBool("project"); !ok { + return configDir, nil + } + + cwd, err := ResolveCwd(cmd) + if err != nil { + return "", fmt.Errorf("cannot resolve current working directory: %w", err) + } + + var sb strings.Builder + for i, path := range config.ProjectConfigs(cwd) { + if i > 0 { + sb.WriteByte('\n') + } + sb.WriteString(filepath.Dir(path)) + } + return sb.String(), nil +} + func init() { + dirsCmd.PersistentFlags().BoolP("project", "p", false, "Print project specific configs") + dirsCmd.AddCommand(configDirCmd, dataDirCmd) } diff --git a/internal/config/load.go b/internal/config/load.go index 05637278952b03bddcb1e51015c59352b58015c9..2b7358662393b42a4a2ee2db730403b019bdbd01 100644 --- a/internal/config/load.go +++ b/internal/config/load.go @@ -849,6 +849,11 @@ func GlobalCacheDir() string { return filepath.Join(home.Dir(), ".cache", appName) } +// ProjectConfigs returns list of current project configs paths. +func ProjectConfigs(cwd string) []string { + return lookupConfigs(cwd) +} + // GlobalConfigData returns the path to the main data directory for the application. // this config is used when the app overrides configurations instead of updating the global config. func GlobalConfigData() string {