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