github.com/goreleaser/goreleaser@v1.25.1/cmd/healthcheck.go (about) 1 package cmd 2 3 import ( 4 "fmt" 5 "io" 6 "os/exec" 7 "sync" 8 9 "github.com/caarlos0/ctrlc" 10 "github.com/caarlos0/log" 11 "github.com/charmbracelet/lipgloss" 12 "github.com/goreleaser/goreleaser/internal/middleware/skip" 13 "github.com/goreleaser/goreleaser/internal/pipe/defaults" 14 "github.com/goreleaser/goreleaser/pkg/context" 15 "github.com/goreleaser/goreleaser/pkg/healthcheck" 16 "github.com/spf13/cobra" 17 ) 18 19 type healthcheckCmd struct { 20 cmd *cobra.Command 21 config string 22 quiet bool 23 } 24 25 func newHealthcheckCmd() *healthcheckCmd { 26 root := &healthcheckCmd{} 27 cmd := &cobra.Command{ 28 Use: "healthcheck", 29 Aliases: []string{"hc"}, 30 Short: "Checks if needed tools are installed", 31 Long: `Check if the needed tools are available in your $PATH, exits 1 if any of them are missing.`, 32 SilenceUsage: true, 33 SilenceErrors: true, 34 Args: cobra.NoArgs, 35 ValidArgsFunction: cobra.NoFileCompletions, 36 RunE: func(_ *cobra.Command, _ []string) error { 37 if root.quiet { 38 log.Log = log.New(io.Discard) 39 } 40 41 cfg, err := loadConfig(root.config) 42 if err != nil { 43 return err 44 } 45 ctx := context.New(cfg) 46 47 if err := ctrlc.Default.Run(ctx, func() error { 48 log.Info(boldStyle.Render("checking tools...")) 49 50 err := defaults.Pipe{}.Run(ctx) 51 if err != nil { 52 return err 53 } 54 55 log.IncreasePadding() 56 defer log.ResetPadding() 57 58 var errs []error 59 for _, hc := range healthcheck.Healthcheckers { 60 _ = skip.Maybe(hc, func(ctx *context.Context) error { 61 for _, tool := range hc.Dependencies(ctx) { 62 if err := checkPath(tool); err != nil { 63 errs = append(errs, err) 64 } 65 } 66 return nil 67 })(ctx) 68 } 69 70 if len(errs) == 0 { 71 return nil 72 } 73 74 return fmt.Errorf("one or more needed tools are not present") 75 }); err != nil { 76 return err 77 } 78 79 log.Infof(boldStyle.Render("done!")) 80 return nil 81 }, 82 } 83 84 cmd.Flags().StringVarP(&root.config, "config", "f", "", "Configuration file") 85 _ = cmd.MarkFlagFilename("config", "yaml", "yml") 86 cmd.Flags().BoolVarP(&root.quiet, "quiet", "q", false, "Quiet mode: no output") 87 _ = cmd.Flags().MarkHidden("deprecated") 88 89 root.cmd = cmd 90 return root 91 } 92 93 var toolsChecked = &sync.Map{} 94 95 func checkPath(tool string) error { 96 if _, ok := toolsChecked.LoadOrStore(tool, true); ok { 97 return nil 98 } 99 if _, err := exec.LookPath(tool); err != nil { 100 st := log.Styles[log.ErrorLevel] 101 log.Warnf("%s %s - %s", st.Render("⚠"), codeStyle.Render(tool), st.Render("not present in path")) 102 return err 103 } 104 st := lipgloss.NewStyle().Foreground(lipgloss.Color("2")).Bold(true) 105 log.Infof("%s %s", st.Render("✓"), codeStyle.Render(tool)) 106 return nil 107 }