config.go

  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:"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, 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		err = rs.LoadRepos()
161		if err != nil {
162			return err
163		}
164	} else if err != nil {
165		return err
166	}
167	return nil
168}