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}