config.go

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