@@ -2,6 +2,7 @@ package config
import (
"bytes"
+ "encoding/json"
"errors"
"io/fs"
"log"
@@ -17,6 +18,7 @@ import (
"fmt"
"os"
+ "github.com/charmbracelet/soft-serve/git"
"github.com/charmbracelet/soft-serve/server/config"
"github.com/go-git/go-billy/v5/memfs"
ggit "github.com/go-git/go-git/v5"
@@ -25,35 +27,40 @@ import (
"github.com/go-git/go-git/v5/storage/memory"
)
+var (
+ // ErrNoConfig is returned when no config file is found.
+ ErrNoConfig = errors.New("no config file found")
+)
+
// Config is the Soft Serve configuration.
type Config struct {
- Name string `yaml:"name"`
- Host string `yaml:"host"`
- Port int `yaml:"port"`
- AnonAccess string `yaml:"anon-access"`
- AllowKeyless bool `yaml:"allow-keyless"`
- Users []User `yaml:"users"`
- Repos []MenuRepo `yaml:"repos"`
- Source *RepoSource `yaml:"-"`
- Cfg *config.Config `yaml:"-"`
+ Name string `yaml:"name" json:"name"`
+ Host string `yaml:"host" json:"host"`
+ Port int `yaml:"port" json:"port"`
+ AnonAccess string `yaml:"anon-access" json:"anon-access"`
+ AllowKeyless bool `yaml:"allow-keyless" json:"allow-keyless"`
+ Users []User `yaml:"users" json:"users"`
+ Repos []MenuRepo `yaml:"repos" json:"repos"`
+ Source *RepoSource `yaml:"-" json:"-"`
+ Cfg *config.Config `yaml:"-" json:"-"`
mtx sync.Mutex
}
// User contains user-level configuration for a repository.
type User struct {
- Name string `yaml:"name"`
- Admin bool `yaml:"admin"`
- PublicKeys []string `yaml:"public-keys"`
- CollabRepos []string `yaml:"collab-repos"`
+ Name string `yaml:"name" json:"name"`
+ Admin bool `yaml:"admin" json:"admin"`
+ PublicKeys []string `yaml:"public-keys" json:"public-keys"`
+ CollabRepos []string `yaml:"collab-repos" json:"collab-repos"`
}
// Repo contains repository configuration information.
type MenuRepo struct {
- Name string `yaml:"name"`
- Repo string `yaml:"repo"`
- Note string `yaml:"note"`
- Private bool `yaml:"private"`
- Readme string `yaml:"readme"`
+ Name string `yaml:"name" json:"name"`
+ Repo string `yaml:"repo" json:"repo"`
+ Note string `yaml:"note" json:"note"`
+ Private bool `yaml:"private" json:"private"`
+ Readme string `yaml:"readme" json:"readme"`
}
// NewConfig creates a new internal Config struct.
@@ -133,13 +140,26 @@ func (cfg *Config) Reload() error {
if err != nil {
return err
}
- cs, _, err := cr.LatestFile("config.yaml")
- if err != nil {
- return err
+ cy, _, err := cr.LatestFile("config.yaml")
+ if err != nil && !errors.Is(err, git.ErrFileNotFound) {
+ return fmt.Errorf("error reading config.yaml: %w", err)
}
- err = yaml.Unmarshal([]byte(cs), cfg)
- if err != nil {
- return fmt.Errorf("bad yaml in config.yaml: %s", err)
+ cj, _, err := cr.LatestFile("config.json")
+ if err != nil && !errors.Is(err, git.ErrFileNotFound) {
+ return fmt.Errorf("error reading config.json: %w", err)
+ }
+ if cy != "" {
+ err = yaml.Unmarshal([]byte(cy), cfg)
+ if err != nil {
+ return fmt.Errorf("bad yaml in config.yaml: %s", err)
+ }
+ } else if cj != "" {
+ err = json.Unmarshal([]byte(cj), cfg)
+ if err != nil {
+ return fmt.Errorf("bad json in config.json: %s", err)
+ }
+ } else {
+ return ErrNoConfig
}
for _, r := range cfg.Source.AllRepos() {
name := r.Name()
@@ -66,6 +66,7 @@ require (
github.com/rivo/uniseg v0.2.0 // indirect
github.com/sahilm/fuzzy v0.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
+ github.com/stretchr/testify v1.8.0 // indirect
github.com/xanzy/ssh-agent v0.3.1 // indirect
github.com/yuin/goldmark v1.5.2 // indirect
github.com/yuin/goldmark-emoji v1.0.1 // indirect
@@ -128,7 +128,6 @@ github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWV
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75 h1:Pijfgr7ZuvX7QIQiEwLdRVr3RoMG+i0SbBO1Qu+7yVk=
github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75/go.mod h1:76rfSfYPWj01Z85hUf/ituArm797mNKcvINh1OlsZKo=
-github.com/microcosm-cc/bluemonday v1.0.19 h1:OI7hoF5FY4pFz2VA//RN8TfM0YJ2dJcl4P4APrCWy6c=
github.com/microcosm-cc/bluemonday v1.0.19/go.mod h1:QNzV2UbLK2/53oIIwTOyLUSABMkjZ4tqiyC1g/DyqxE=
github.com/microcosm-cc/bluemonday v1.0.21 h1:dNH3e4PSyE4vNX+KlRGHT5KrSvjeUkoNPwEORjffHJg=
github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM=
@@ -183,16 +182,18 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
+github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
github.com/xanzy/ssh-agent v0.3.1 h1:AmzO1SSWxw73zxFZPRwaMN1MohDw8UyHnmuxyceTEGo=
github.com/xanzy/ssh-agent v0.3.1/go.mod h1:QIE4lCeL7nkC25x+yA3LBIYfwCc1TFziCtG7cBAac6w=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.4.4 h1:zNWRjYUW32G9KirMXYHQHVNFkXvMI7LpgNW2AgYAoIs=
github.com/yuin/goldmark v1.4.4/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
github.com/yuin/goldmark v1.5.2 h1:ALmeCk/px5FSm1MAcFBAsVKZjDuMVj8Tm7FFIlMJnqU=
github.com/yuin/goldmark v1.5.2/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
@@ -210,7 +211,6 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b h1:ZmngSVLe/wycRns9MKikG9OWIEjGcGAkacif7oYQaUY=
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20221002022538-bcab6841153b h1:6e93nYa3hNqAvLr0pD4PN1fFS+gKzp2zAXqrnTCstqU=
golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=