1package config
2
3import (
4 "gopkg.in/yaml.v2"
5
6 "fmt"
7 "os"
8 "path/filepath"
9
10 "github.com/charmbracelet/soft/git"
11 gg "github.com/go-git/go-git/v5"
12 "github.com/go-git/go-git/v5/plumbing/object"
13)
14
15type Config struct {
16 Name string `yaml:"name"`
17 Host string `yaml:"host"`
18 Port int `yaml:"port"`
19 AnonAccess string `yaml:"anon-access"`
20 AllowNoKeys bool `yaml:"allow-no-keys"`
21 Users []User `yaml:"users"`
22 Repos []Repo `yaml:"repos"`
23 Source *git.RepoSource
24}
25
26type User struct {
27 Name string `yaml:"name"`
28 Admin bool `yaml:"admin"`
29 PublicKey string `yaml:"public-key"`
30 CollabRepos []string `yaml:"collab-repos"`
31}
32
33type Repo struct {
34 Name string `yaml:"name"`
35 Repo string `yaml:"repo"`
36 Note string `yaml:"note"`
37}
38
39func NewConfig(host string, port int, pk string, rs *git.RepoSource) (*Config, error) {
40 var anonAccess string
41 var yamlUsers string
42 var displayHost string
43 cfg := &Config{}
44 cfg.Host = host
45 cfg.Port = port
46 cfg.Source = rs
47 if pk == "" {
48 anonAccess = "read-write"
49 } else {
50 anonAccess = "no-access"
51 }
52 if host == "" {
53 displayHost = "localhost"
54 } else {
55 displayHost = host
56 }
57 yamlConfig := fmt.Sprintf(defaultConfig, displayHost, port, anonAccess)
58 if pk != "" {
59 yamlUsers = fmt.Sprintf(hasKeyUserConfig, pk)
60 } else {
61 yamlUsers = defaultUserConfig
62 }
63 yaml := fmt.Sprintf("%s%s%s", yamlConfig, yamlUsers, exampleUserConfig)
64 err := cfg.createDefaultConfigRepo(yaml)
65 if err != nil {
66 return nil, err
67 }
68 return cfg, nil
69}
70
71func (cfg *Config) reload() error {
72 err := cfg.Source.LoadRepos()
73 if err != nil {
74 return err
75 }
76 cr, err := cfg.Source.GetRepo("config")
77 if err != nil {
78 return err
79 }
80 cs, err := cr.LatestFile("config.yaml")
81 if err != nil {
82 return err
83 }
84 err = yaml.Unmarshal([]byte(cs), cfg)
85 if err != nil {
86 return fmt.Errorf("bad yaml in config.yaml: %s", err)
87 }
88 return nil
89}
90
91func createFile(path string, content string) error {
92 f, err := os.Create(path)
93 if err != nil {
94 return err
95 }
96 defer f.Close()
97 _, err = f.WriteString(content)
98 if err != nil {
99 return err
100 }
101 return f.Sync()
102}
103
104func (cfg *Config) createDefaultConfigRepo(yaml string) error {
105 cn := "config"
106 rs := cfg.Source
107 err := rs.LoadRepos()
108 if err != nil {
109 return err
110 }
111 _, err = rs.GetRepo(cn)
112 if err == git.ErrMissingRepo {
113 cr, err := rs.InitRepo(cn, false)
114 if err != nil {
115 return err
116 }
117
118 rp := filepath.Join(rs.Path, cn, "README.md")
119 err = createFile(rp, defaultReadme)
120 if err != nil {
121 return err
122 }
123 cp := filepath.Join(rs.Path, cn, "config.yaml")
124 err = createFile(cp, yaml)
125 if err != nil {
126 return err
127 }
128 wt, err := cr.Repository.Worktree()
129 if err != nil {
130 return err
131 }
132 _, err = wt.Add("README.md")
133 if err != nil {
134 return err
135 }
136 _, err = wt.Add("config.yaml")
137 if err != nil {
138 return err
139 }
140 _, err = wt.Commit("Default init", &gg.CommitOptions{
141 All: true,
142 Author: &object.Signature{
143 Name: "Soft Serve Server",
144 Email: "vt100@charm.sh",
145 },
146 })
147 if err != nil {
148 return err
149 }
150 if err != nil {
151 return err
152 }
153 } else if err != nil {
154 return err
155 }
156 return cfg.reload()
157}