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