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