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