@@ -1,8 +1,10 @@
11package cmd
22
33import (
4+ "fmt"
45 "os"
56 "path/filepath"
7+ "strings"
68
79 "charm.land/lipgloss/v2"
810 "charm.land/lipgloss/v2/table"
@@ -17,16 +19,27 @@ var dirsCmd = &cobra.Command{
1719 Long: `Print the directories where Crush stores its configuration and data files.
1820This includes the global configuration directory and data directory.`,
1921 Example: `
20−# Print all directories
22+# Print all global directories
2123crush dirs
2224
23−# Print only the config directory
25+# Print data directory and all project specific config directories
26+crush dirs -p
27+
28+# Print only global config directory
2429crush dirs config
2530
31+# Print only project specific config directories
32+crush dirs -p config
33+
2634# Print only the data directory
2735crush dirs data
2836 `,
29− Run: func(cmd *cobra.Command, args []string) {
37+ RunE: func(cmd *cobra.Command, args []string) error {
38+ dirs, err := configDirs(cmd)
39+ if err != nil {
40+ return fmt.Errorf("cannot collect config directories: %w", err)
41+ }
42+
3043 if term.IsTerminal(os.Stdout.Fd()) {
3144 // We're in a TTY: make it fancy.
3245 t := table.New().
@@ -34,22 +47,29 @@ crush dirs data
3447 StyleFunc(func(row, col int) lipgloss.Style {
3548 return lipgloss.NewStyle().Padding(0, 2)
3649 }).
37− Row("Config", filepath.Dir(config.GlobalConfig())).
50+ Row("Config", dirs).
3851 Row("Data", filepath.Dir(config.GlobalConfigData()))
3952 lipgloss.Println(t)
40− return
53+ return nil
4154 }
4255 // Not a TTY.
43− cmd.Println(filepath.Dir(config.GlobalConfig()))
56+ cmd.Println(dirs)
4457 cmd.Println(filepath.Dir(config.GlobalConfigData()))
58+
59+ return nil
4560 },
4661}
4762
4863var configDirCmd = &cobra.Command{
4964 Use: "config",
5065 Short: "Print the configuration directory used by Crush",
51− Run: func(cmd *cobra.Command, args []string) {
52− cmd.Println(filepath.Dir(config.GlobalConfig()))
66+ RunE: func(cmd *cobra.Command, args []string) error {
67+ dirs, err := configDirs(cmd)
68+ if err != nil {
69+ return fmt.Errorf("cannot collect config directories: %w", err)
70+ }
71+ cmd.Println(dirs)
72+ return nil
5373 },
5474}
5575
@@ -61,6 +81,30 @@ var dataDirCmd = &cobra.Command{
6181 },
6282}
6383
84+// configDirs returns formatted string with one or more project config paths
85+func configDirs(cmd *cobra.Command) (string, error) {
86+ configDir := filepath.Dir(config.GlobalConfig())
87+ if ok, _ := cmd.Flags().GetBool("project"); !ok {
88+ return configDir, nil
89+ }
90+
91+ cwd, err := ResolveCwd(cmd)
92+ if err != nil {
93+ return "", fmt.Errorf("cannot resolve current working directory: %w", err)
94+ }
95+
96+ var sb strings.Builder
97+ for i, path := range config.ProjectConfigs(cwd) {
98+ if i > 0 {
99+ sb.WriteByte('\n')
100+ }
101+ sb.WriteString(filepath.Dir(path))
102+ }
103+ return sb.String(), nil
104+}
105+
64106func init() {
107+ dirsCmd.PersistentFlags().BoolP("project", "p", false, "Print project specific configs")
108+
65109 dirsCmd.AddCommand(configDirCmd, dataDirCmd)
66110}