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/logger"
19 "gitroot.dev/server/plugin"
20 "gitroot.dev/server/repository"
21 "gitroot.dev/server/user"
22)
23
24var version string = "next" // set at build time
25var commit string // set at build time
26
27func main() {
28 log := logger.NewLoggerCtx("root", context.Background())
29 var rootPath string
30 flag.StringVar(&rootPath, "data", "./data", "path to store data")
31 var rootRemote string
32 flag.StringVar(&rootRemote, "remote", "", "optional repository for root repo, only used at init")
33 var showVersion bool
34 flag.BoolVar(&showVersion, "version", false, "show current version and build time")
35 var initConfig string
36 flag.StringVar(&initConfig, "initConfig", "", "generate a config file to configure GitRoot before the first start")
37 var config string
38 flag.StringVar(&config, "config", "", "use a config file to configure GitRoot before the first start")
39 flag.Parse()
40
41 conf := configuration.NewConfiguration(rootPath)
42
43 if config != "" {
44 configContent, err := os.ReadFile(config)
45 if err != nil {
46 log.Error("can't read conf", err, logger.NewLoggerPair("path", config))
47 os.Exit(1)
48 return
49 }
50 conf.LoadFromFile(configContent)
51 }
52
53 if showVersion || initConfig != "" {
54 if showVersion {
55 if commit == "" {
56 commit = plumbing.ZeroHash.String()
57 }
58 log.Warn(fmt.Sprintf("Version `%s` for commit `%s`", version, commit))
59 }
60 if initConfig != "" {
61 confMarshalled, err := yaml.Marshal(conf)
62 if err != nil {
63 log.Error("can't marshal conf", err)
64 os.Exit(1)
65 return
66 }
67 if err := os.WriteFile(initConfig, confMarshalled, 0666); err != nil {
68 log.Error("can't write initConfif file", err, logger.NewLoggerPair("path", initConfig))
69 os.Exit(1)
70 return
71 }
72 log.Warn(fmt.Sprintf("File %s created, please edit it and launch gitroot with --config=%s to use it", initConfig, initConfig))
73 }
74 return
75 }
76
77 if err := conf.LoadFromOrStoreToRootConf(filepath.Join(rootPath, "gitroot.yml"), version); err != nil {
78 log.Error("Initialisation of root conf failed", err)
79 os.Exit(1)
80 }
81
82 userManager, err := user.NewManager(conf)
83 if err != nil {
84 log.Error("Initialisation failed", err)
85 os.Exit(1)
86 }
87
88 var backgroundManager *background.Manager
89 repoManager := repository.NewManager(conf, userManager)
90 pluginManager := plugin.NewManager(conf, repoManager, userManager)
91 backgroundManager = background.NewManager(context.Background(), conf, repoManager, userManager, pluginManager)
92 repoManager.SetBackgroundManager(backgroundManager)
93
94 if !repoManager.Exists(conf.ForgeConfigName()) {
95 go func() {
96 if err := repoManager.CreateRootRepoIfNeeded(context.Background(), rootRemote); err != nil {
97 log.Error("Error in CreateRootRepoIfNeeded", err)
98 }
99 }()
100 } else {
101 rootRepo, err := repoManager.OpenForgeRepo(context.Background())
102 if err != nil {
103 log.Error("Can't open root repo", err)
104 return
105 }
106 c, err := rootRepo.Content(conf.PathFileForgeConfig())
107 if err != nil {
108 log.Error("Can't read root conf", err)
109 return
110 }
111 if err := conf.LoadFromFile(c); err != nil {
112 log.Error("Can't unmarshal root conf", err)
113 return
114 }
115 rootRepo.Close()
116 }
117
118 go func() {
119 if err := NewServerHttp(conf, repoManager).ListenAndServe(); err != nil {
120 log.Error("Http closed", err)
121 }
122 }()
123
124 if err := NewServerSsh(conf, repoManager, userManager, pluginManager, backgroundManager).ListenAndServe(); err != nil {
125 log.Error("Ssh closed", err)
126 }
127}