github.com/exercism/v2-configlet@v3.9.2+incompatible/cmd/fmt.go (about) 1 package cmd 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 9 "github.com/exercism/configlet/track" 10 "github.com/exercism/configlet/ui" 11 multierror "github.com/hashicorp/go-multierror" 12 "github.com/pmezard/go-difflib/difflib" 13 "github.com/spf13/cobra" 14 ) 15 16 // verbose flag for fmt command. 17 var fmtVerbose bool 18 19 // fmtCmd defines the fmt command 20 var fmtCmd = &cobra.Command{ 21 Use: "fmt " + pathExample, 22 Short: "Format the track configuration files", 23 Long: `The fmt command formats the track's configuration files. 24 25 It ensures the following files have consistent JSON syntax and indentation: 26 config.json, maintainers.json 27 28 It also normalizes and alphabetizes the exercise topics in the config.json file. 29 `, 30 Example: fmt.Sprintf(" %s fmt %s --verbose", binaryName, pathExample), 31 Run: func(cmd *cobra.Command, args []string) { 32 if err := runFmt(args[0], args[0], fmtVerbose); err != nil { 33 ui.PrintError(err.Error()) 34 os.Exit(1) 35 } 36 }, 37 38 Args: cobra.ExactArgs(1), 39 } 40 41 func runFmt(inDir, outDir string, verbose bool) error { 42 if _, err := os.Stat(filepath.Join(outDir, "config")); os.IsNotExist(err) { 43 os.Mkdir(filepath.Join(outDir, "config"), os.ModePerm) 44 } 45 46 var fs = []struct { 47 inPath string 48 outPath string 49 cfg ConfigSerializer 50 }{ 51 { 52 filepath.Join(inDir, "config.json"), 53 filepath.Join(outDir, "config.json"), 54 &track.Config{}, 55 }, 56 { 57 filepath.Join(inDir, "config", "maintainers.json"), 58 filepath.Join(outDir, "config", "maintainers.json"), 59 &track.MaintainerConfig{}, 60 }, 61 } 62 63 var changes string 64 65 errs := &multierror.Error{} 66 for _, f := range fs { 67 diff, err := formatFile(f.cfg, f.inPath, f.outPath) 68 if err != nil { 69 errs = multierror.Append(errs, err) 70 continue 71 } 72 if diff != "" { 73 if verbose { 74 ui.Print(fmt.Sprintf("%s\n\n%s", f.inPath, diff)) 75 } 76 changes += fmt.Sprintf("%s\n", f.inPath) 77 } 78 } 79 if changes != "" { 80 ui.Print("changes made to:\n", changes) 81 } 82 if err := errs.ErrorOrNil(); err != nil { 83 return err 84 } 85 return nil 86 } 87 88 func formatFile(cfg ConfigSerializer, inPath, outPath string) (string, error) { 89 src, err := ioutil.ReadFile(inPath) 90 if err != nil { 91 return "", err 92 } 93 if err := cfg.LoadFromFile(inPath); err != nil { 94 return "", err 95 } 96 dst, err := cfg.ToJSON() 97 if err != nil { 98 return "", err 99 } 100 dst = []byte(string(fmt.Sprintf("%s\n", dst))) 101 102 a := difflib.SplitLines(string(src)) 103 b := difflib.SplitLines(string(dst)) 104 diff, err := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{A: a, B: b}) 105 if err != nil { 106 return "", err 107 } 108 if diff != "" { 109 if err := ioutil.WriteFile(outPath, dst, os.FileMode(0644)); err != nil { 110 return "", err 111 } 112 } 113 return diff, nil 114 } 115 116 func init() { 117 RootCmd.AddCommand(fmtCmd) 118 fmtCmd.Flags().BoolVarP(&fmtVerbose, "verbose", "v", false, "display the diff of the formatted changes.") 119 }