GitRoot
craft your forge, build your project, grow your community freely
1// SPDX-FileCopyrightText: 2025 Romain Maneschi <romain@gitroot.dev>
2//
3// SPDX-License-Identifier: EUPL-1.2
4
5package main
6
7import (
8 "context"
9 "flag"
10 "fmt"
11 "os"
12 "path/filepath"
13
14 "github.com/go-git/go-git/v5/plumbing"
15 "github.com/goccy/go-yaml"
16 "gitroot.dev/server/background"
17 "gitroot.dev/server/configuration"
18 "gitroot.dev/server/exec"
19 "gitroot.dev/server/logger"
20 "gitroot.dev/server/plugin"
21 "gitroot.dev/server/repository"
22 "gitroot.dev/server/user"
23)
24
25var version string = "next" // set at build time
26var commit string // set at build time
27
28func main() {
29 log := logger.NewLoggerCtx("root", context.Background())
30 var rootPath string
31 flag.StringVar(&rootPath, "data", "./data", "path to store data")
32 var rootRemote string
33 flag.StringVar(&rootRemote, "remote", "", "optional repository for root repo, only used at init")
34 var showVersion bool
35 flag.BoolVar(&showVersion, "version", false, "show current version and build time")
36 var initConfig string
37 flag.StringVar(&initConfig, "initConfig", "", "generate a config file to configure GitRoot before the first start")
38 var config string
39 flag.StringVar(&config, "config", "", "use a config file to configure GitRoot before the first start")
40 flag.Parse()
41
42 conf := configuration.NewConfiguration(rootPath)
43
44 if config != "" {
45 configContent, err := os.ReadFile(config)
46 if err != nil {
47 log.Error("can't read conf", err, logger.NewLoggerPair("path", config))
48 os.Exit(1)
49 return
50 }
51 conf.LoadFromFile(configContent)
52 }
53
54 if showVersion || initConfig != "" {
55 if showVersion {
56 if commit == "" {
57 commit = plumbing.ZeroHash.String()
58 }
59 log.Warn(fmt.Sprintf("Version `%s` for commit `%s`", version, commit))
60 }
61 if initConfig != "" {
62 confMarshalled, err := yaml.Marshal(conf)
63 if err != nil {
64 log.Error("can't marshal conf", err)
65 os.Exit(1)
66 return
67 }
68 if err := os.WriteFile(initConfig, confMarshalled, 0666); err != nil {
69 log.Error("can't write initConfif file", err, logger.NewLoggerPair("path", initConfig))
70 os.Exit(1)
71 return
72 }
73 log.Warn(fmt.Sprintf("File %s created, please edit it and launch gitroot with --config=%s to use it", initConfig, initConfig))
74 }
75 return
76 }
77
78 needUpdateConf, err := conf.LoadFromOrStoreToRootConf(filepath.Join(rootPath, "gitroot.yml"), version)
79 if err != nil {
80 log.Error("Initialisation of root conf failed", err)
81 os.Exit(1)
82 }
83
84 userManager, err := user.NewManager(conf)
85 if err != nil {
86 log.Error("Initialisation failed", err)
87 os.Exit(1)
88 }
89
90 var backgroundManager *background.Manager
91 repoManager := repository.NewManager(conf, userManager)
92 execManager := exec.NewManager(context.Background(), conf)
93 pluginManager := plugin.NewManager(conf, repoManager, userManager, execManager)
94 backgroundManager = background.NewManager(context.Background(), conf, repoManager, userManager, pluginManager)
95 pluginManager.SetBackgroundManager(backgroundManager)
96
97 if !repoManager.Exists(conf.ForgeConfigName()) {
98 go func() {
99 if err := repoManager.CreateRootRepoIfNeeded(context.Background(), rootRemote); err != nil {
100 log.Error("Error in CreateRootRepoIfNeeded", err)
101 }
102 }()
103 } else {
104 rootRepo, err := repoManager.OpenForgeRepo(context.Background())
105 if err != nil {
106 log.Error("Can't open root repo", err)
107 return
108 }
109 c, err := rootRepo.Content(conf.PathFileForgeConfig())
110 if err != nil {
111 log.Error("Can't read root conf", err)
112 return
113 }
114 if err := conf.LoadFromFile(c); err != nil {
115 log.Error("Can't unmarshal root conf", err)
116 return
117 }
118 if needUpdateConf {
119 log.Debug("will write conf", logger.NewLoggerPair("branch", conf.DefaultBranch))
120 rootRepoWrite, err := rootRepo.WillWrite(plumbing.NewBranchReferenceName(conf.DefaultBranch))
121 if err != nil {
122 log.Error("can't open root repository in write mode", err)
123 }
124 confMarshalled, err := conf.Marshall()
125 if err != nil {
126 log.Error("can't marshal conf", err)
127 }
128 err = rootRepoWrite.Write(conf.PathFileForgeConfig(), confMarshalled)
129 if err != nil {
130 log.Error("can't write conf", err)
131 }
132 if _, err := rootRepoWrite.CommitAll("Conf updated", userManager.RootCommiter()); err != nil {
133 log.Error("can't commit new conf", err)
134 }
135 log.Warn("update conf done", logger.NewLoggerPair("branch", conf.DefaultBranch))
136 }
137 rootRepo.Close()
138 }
139
140 go func() {
141 if err := NewServerHttp(conf, repoManager).ListenAndServe(); err != nil {
142 log.Error("Http closed", err)
143 }
144 }()
145
146 if err := NewServerSsh(conf, repoManager, userManager, pluginManager, backgroundManager).ListenAndServe(); err != nil {
147 log.Error("Ssh closed", err)
148 }
149}