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 AllowKeyless bool `yaml:"allow-keyless"`
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 Private bool `yaml:"private"`
38}
39
40func NewConfig(host string, port int, pk string, rs *git.RepoSource) (*Config, error) {
41 var anonAccess string
42 var yamlUsers string
43 var displayHost string
44 cfg := &Config{}
45 cfg.Host = host
46 cfg.Port = port
47 cfg.Source = rs
48 if pk == "" {
49 anonAccess = "read-write"
50 } else {
51 anonAccess = "no-access"
52 }
53 if host == "" {
54 displayHost = "localhost"
55 } else {
56 displayHost = host
57 }
58 yamlConfig := fmt.Sprintf(defaultConfig, displayHost, port, anonAccess)
59 if pk != "" {
60 yamlUsers = fmt.Sprintf(hasKeyUserConfig, pk)
61 } else {
62 yamlUsers = defaultUserConfig
63 }
64 yaml := fmt.Sprintf("%s%s%s", yamlConfig, yamlUsers, exampleUserConfig)
65 err := cfg.createDefaultConfigRepo(yaml)
66 if err != nil {
67 return nil, err
68 }
69 return cfg, nil
70}
71
72func (cfg *Config) reload() error {
73 err := cfg.Source.LoadRepos()
74 if err != nil {
75 return err
76 }
77 cr, err := cfg.Source.GetRepo("config")
78 if err != nil {
79 return err
80 }
81 cs, err := cr.LatestFile("config.yaml")
82 if err != nil {
83 return err
84 }
85 err = yaml.Unmarshal([]byte(cs), cfg)
86 if err != nil {
87 return fmt.Errorf("bad yaml in config.yaml: %s", err)
88 }
89 return nil
90}
91
92func createFile(path string, content string) error {
93 f, err := os.Create(path)
94 if err != nil {
95 return err
96 }
97 defer f.Close()
98 _, err = f.WriteString(content)
99 if err != nil {
100 return err
101 }
102 return f.Sync()
103}
104
105func (cfg *Config) createDefaultConfigRepo(yaml string) error {
106 cn := "config"
107 rs := cfg.Source
108 err := rs.LoadRepos()
109 if err != nil {
110 return err
111 }
112 _, err = rs.GetRepo(cn)
113 if err == git.ErrMissingRepo {
114 cr, err := rs.InitRepo(cn, false)
115 if err != nil {
116 return err
117 }
118
119 rp := filepath.Join(rs.Path, cn, "README.md")
120 err = createFile(rp, defaultReadme)
121 if err != nil {
122 return err
123 }
124 cp := filepath.Join(rs.Path, cn, "config.yaml")
125 err = createFile(cp, yaml)
126 if err != nil {
127 return err
128 }
129 wt, err := cr.Repository.Worktree()
130 if err != nil {
131 return err
132 }
133 _, err = wt.Add("README.md")
134 if err != nil {
135 return err
136 }
137 _, err = wt.Add("config.yaml")
138 if err != nil {
139 return err
140 }
141 _, err = wt.Commit("Default init", &gg.CommitOptions{
142 All: true,
143 Author: &object.Signature{
144 Name: "Soft Serve Server",
145 Email: "vt100@charm.sh",
146 },
147 })
148 if err != nil {
149 return err
150 }
151 if err != nil {
152 return err
153 }
154 } else if err != nil {
155 return err
156 }
157 return cfg.reload()
158}
159
160func (cfg *Config) isPrivate(repo string) bool {
161 for _, r := range cfg.Repos {
162 if r.Repo == repo {
163 return r.Private
164 }
165 }
166 return false
167}