main.go

  1// Package main is the entry point for the soft-serve CLI.
  2package main
  3
  4import (
  5	"context"
  6	"fmt"
  7	"os"
  8	"runtime/debug"
  9	"strconv"
 10
 11	"github.com/charmbracelet/colorprofile"
 12	"github.com/charmbracelet/log/v2"
 13	"github.com/charmbracelet/soft-serve/cmd/soft/admin"
 14	"github.com/charmbracelet/soft-serve/cmd/soft/browse"
 15	"github.com/charmbracelet/soft-serve/cmd/soft/hook"
 16	"github.com/charmbracelet/soft-serve/cmd/soft/serve"
 17	"github.com/charmbracelet/soft-serve/pkg/config"
 18	logr "github.com/charmbracelet/soft-serve/pkg/log"
 19	"github.com/charmbracelet/soft-serve/pkg/ui/common"
 20	"github.com/charmbracelet/soft-serve/pkg/version"
 21	mcobra "github.com/muesli/mango-cobra"
 22	"github.com/muesli/roff"
 23	"github.com/spf13/cobra"
 24	"go.uber.org/automaxprocs/maxprocs"
 25)
 26
 27var (
 28	// Version contains the application version number. It's set via ldflags
 29	// when building.
 30	Version = ""
 31
 32	// CommitSHA contains the SHA of the commit that this application was built
 33	// against. It's set via ldflags when building.
 34	CommitSHA = ""
 35
 36	// CommitDate contains the date of the commit that this application was
 37	// built against. It's set via ldflags when building.
 38	CommitDate = ""
 39
 40	rootCmd = &cobra.Command{
 41		Use:          "soft",
 42		Short:        "A self-hostable Git server for the command line",
 43		Long:         "Soft Serve is a self-hostable Git server for the command line.",
 44		SilenceUsage: true,
 45		RunE: func(cmd *cobra.Command, args []string) error {
 46			return browse.Command.RunE(cmd, args)
 47		},
 48	}
 49
 50	manCmd = &cobra.Command{
 51		Use:    "man",
 52		Short:  "Generate man pages",
 53		Args:   cobra.NoArgs,
 54		Hidden: true,
 55		RunE: func(_ *cobra.Command, _ []string) error {
 56			manPage, err := mcobra.NewManPage(1, rootCmd) //.
 57			if err != nil {
 58				return err //nolint:wrapcheck
 59			}
 60
 61			manPage = manPage.WithSection("Copyright", "(C) 2021-2023 Charmbracelet, Inc.\n"+
 62				"Released under MIT license.")
 63			fmt.Println(manPage.Build(roff.NewDocument()))
 64			return nil
 65		},
 66	}
 67)
 68
 69func init() {
 70	if noColor, _ := strconv.ParseBool(os.Getenv("SOFT_SERVE_NO_COLOR")); noColor {
 71		common.DefaultColorProfile = colorprofile.NoTTY
 72	}
 73
 74	rootCmd.AddCommand(
 75		manCmd,
 76		serve.Command,
 77		hook.Command,
 78		admin.Command,
 79		browse.Command,
 80	)
 81	rootCmd.CompletionOptions.HiddenDefaultCmd = true
 82
 83	if len(CommitSHA) >= 7 {
 84		vt := rootCmd.VersionTemplate()
 85		rootCmd.SetVersionTemplate(vt[:len(vt)-1] + " (" + CommitSHA[0:7] + ")\n")
 86	}
 87	if Version == "" {
 88		if info, ok := debug.ReadBuildInfo(); ok && info.Main.Sum != "" {
 89			Version = info.Main.Version
 90		} else {
 91			Version = "unknown (built from source)"
 92		}
 93	}
 94	rootCmd.Version = Version
 95
 96	version.Version = Version
 97	version.CommitSHA = CommitSHA
 98	version.CommitDate = CommitDate
 99}
100
101func main() {
102	ctx := context.Background()
103	cfg := config.DefaultConfig()
104	if cfg.Exist() {
105		if err := cfg.Parse(); err != nil {
106			log.Fatal(err)
107		}
108	}
109
110	if err := cfg.ParseEnv(); err != nil {
111		log.Fatal(err)
112	}
113
114	ctx = config.WithContext(ctx, cfg)
115	logger, f, err := logr.NewLogger(cfg)
116	if err != nil {
117		log.Errorf("failed to create logger: %v", err)
118	}
119
120	ctx = log.WithContext(ctx, logger)
121	if f != nil {
122		defer f.Close() //nolint: errcheck
123	}
124
125	// Set global logger
126	log.SetDefault(logger)
127
128	var opts []maxprocs.Option
129	if config.IsVerbose() {
130		opts = append(opts, maxprocs.Logger(log.Debugf))
131	}
132
133	// Set the max number of processes to the number of CPUs
134	// This is useful when running soft serve in a container
135	if _, err := maxprocs.Set(opts...); err != nil {
136		log.Warn("couldn't set automaxprocs", "error", err)
137	}
138
139	if err := rootCmd.ExecuteContext(ctx); err != nil {
140		os.Exit(1)
141	}
142}