~emersion/hut-dev

config: use scfg decoder to read config file v1 SUPERSEDED

Simon Ser: 1
 config: use scfg decoder to read config file

 4 files changed, 50 insertions(+), 55 deletions(-)
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~emersion/hut-dev/patches/47508/mbox | git am -3
Learn more about email & git

[PATCH] config: use scfg decoder to read config file Export this patch

---
 client.go |  5 ++-
 config.go | 94 +++++++++++++++++++++++++------------------------------
 go.mod    |  2 +-
 go.sum    |  4 +--
 4 files changed, 50 insertions(+), 55 deletions(-)

diff --git a/client.go b/client.go
index 337cad3d4f6d..352b2a04c799 100644
--- a/client.go
+++ b/client.go
@@ -73,7 +73,10 @@ func createClientWithInstance(service string, cmd *cobra.Command, instanceName s
		token = inst.AccessToken
	}

	baseURL := inst.Origins[service]
	var baseURL string
	if serviceCfg := inst.Services()[service]; serviceCfg != nil {
		baseURL = serviceCfg.Origin
	}
	if baseURL == "" && strings.Contains(inst.Name, ".") && net.ParseIP(inst.Name) == nil {
		baseURL = fmt.Sprintf("https://%s.%s", service, inst.Name)
	}
diff --git a/config.go b/config.go
index 11f2f37de2f0..790e5e48adbf 100644
--- a/config.go
+++ b/config.go
@@ -18,67 +18,80 @@ import (
)

type Config struct {
	Instances []*InstanceConfig
	Instances []*InstanceConfig `scfg:"instance"`
}

type InstanceConfig struct {
	Name string

	AccessToken    string
	AccessTokenCmd []string

	Origins map[string]string
	Name string `scfg:",param"`

	AccessToken    string   `scfg:"access-token"`
	AccessTokenCmd []string `scfg:"access-token-cmd"`

	Builds *ServiceConfig `scfg:"builds"`
	Git    *ServiceConfig `scfg:"git"`
	Hg     *ServiceConfig `scfg:"hg"`
	Lists  *ServiceConfig `scfg:"lists"`
	Meta   *ServiceConfig `scfg:"meta"`
	Pages  *ServiceConfig `scfg:"pages"`
	Paste  *ServiceConfig `scfg:"paste"`
	Todo   *ServiceConfig `scfg:"todo"`
}

func (instance InstanceConfig) match(name string) bool {
func (instance *InstanceConfig) match(name string) bool {
	if instancesEqual(name, instance.Name) {
		return true
	}

	for _, origin := range instance.Origins {
		if stripProtocol(origin) == name {
	for _, service := range instance.Services() {
		if service.Origin != "" && stripProtocol(service.Origin) == name {
			return true
		}
	}
	return false
}

func (instance *InstanceConfig) Services() map[string]*ServiceConfig {
	return map[string]*ServiceConfig{
		"builds": instance.Builds,
		"git":    instance.Git,
		"hg":     instance.Hg,
		"lists":  instance.Lists,
		"meta":   instance.Meta,
		"pages":  instance.Pages,
		"paste":  instance.Paste,
		"todo":   instance.Todo,
	}
}

type ServiceConfig struct {
	Origin string `scfg:"origin"`
}

func instancesEqual(a, b string) bool {
	return a == b || strings.HasSuffix(a, "."+b) || strings.HasSuffix(b, "."+a)
}

func loadConfigFile(filename string) (*Config, error) {
	rootBlock, err := scfg.Load(filename)
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	cfg := new(Config)
	instanceNames := make(map[string]struct{})
	for _, instanceDir := range rootBlock.GetAll("instance") {
		instance := &InstanceConfig{
			Origins: make(map[string]string),
		}

		if err := instanceDir.ParseParams(&instance.Name); err != nil {
			return nil, err
		}
	if err := scfg.NewDecoder(f).Decode(cfg); err != nil {
		return nil, err
	}

	instanceNames := make(map[string]struct{})
	for _, instance := range cfg.Instances {
		if _, ok := instanceNames[instance.Name]; ok {
			return nil, fmt.Errorf("duplicate instance name %q", instance.Name)
		}
		instanceNames[instance.Name] = struct{}{}

		if dir := instanceDir.Children.Get("access-token"); dir != nil {
			if err := dir.ParseParams(&instance.AccessToken); err != nil {
				return nil, err
			}
		}
		if dir := instanceDir.Children.Get("access-token-cmd"); dir != nil {
			if len(dir.Params) == 0 {
				return nil, fmt.Errorf("instance %q: missing command name in access-token-cmd directive", instance.Name)
			}
			instance.AccessTokenCmd = dir.Params
		if instance.AccessTokenCmd != nil && len(instance.AccessTokenCmd) == 0 {
			return nil, fmt.Errorf("instance %q: missing command name in access-token-cmd directive", instance.Name)
		}
		if instance.AccessToken == "" && len(instance.AccessTokenCmd) == 0 {
			return nil, fmt.Errorf("instance %q: missing access-token or access-token-cmd", instance.Name)
@@ -86,27 +99,6 @@ func loadConfigFile(filename string) (*Config, error) {
		if instance.AccessToken != "" && len(instance.AccessTokenCmd) > 0 {
			return nil, fmt.Errorf("instance %q: access-token and access-token-cmd can't be both specified", instance.Name)
		}

		for _, service := range []string{"builds", "git", "hg", "lists", "meta", "pages", "paste", "todo"} {
			serviceDir := instanceDir.Children.Get(service)
			if serviceDir == nil {
				continue
			}

			originDir := serviceDir.Children.Get("origin")
			if originDir == nil {
				continue
			}

			var origin string
			if err := originDir.ParseParams(&origin); err != nil {
				return nil, err
			}

			instance.Origins[service] = origin
		}

		cfg.Instances = append(cfg.Instances, instance)
	}

	return cfg, nil
diff --git a/go.mod b/go.mod
index 107bf7353a23..c3bdee2c350e 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,7 @@ module git.sr.ht/~emersion/hut
go 1.17

require (
	git.sr.ht/~emersion/go-scfg v0.0.0-20231004133111-9dce55c8d63b
	git.sr.ht/~emersion/go-scfg v0.0.0-20231208203353-7c6455e0239c
	git.sr.ht/~emersion/gqlclient v0.0.0-20230820050442-8873fe0204b9
	github.com/dustin/go-humanize v1.0.1
	github.com/juju/ansiterm v1.0.0
diff --git a/go.sum b/go.sum
index 9a39e01ebd2a..d17460e28082 100644
--- a/go.sum
+++ b/go.sum
@@ -1,5 +1,5 @@
git.sr.ht/~emersion/go-scfg v0.0.0-20231004133111-9dce55c8d63b h1:Lf4oYBOJVmbYzrfqWfXUvSpXQPNMgnbN0efn5A7bH3M=
git.sr.ht/~emersion/go-scfg v0.0.0-20231004133111-9dce55c8d63b/go.mod h1:ybgvEJTIx5XbaspSviB3KNa6OdPmAZqDoSud7z8fFlw=
git.sr.ht/~emersion/go-scfg v0.0.0-20231208203353-7c6455e0239c h1:xO+4dXkI2+BzXS7RRC6YPrMgD5ikfTOTyMRjcy17aXQ=
git.sr.ht/~emersion/go-scfg v0.0.0-20231208203353-7c6455e0239c/go.mod h1:ybgvEJTIx5XbaspSviB3KNa6OdPmAZqDoSud7z8fFlw=
git.sr.ht/~emersion/gqlclient v0.0.0-20230820050442-8873fe0204b9 h1:QNwHP6WknvS7X6MEFxCpefQb1QJMqgIIt+vn/PVoMMg=
git.sr.ht/~emersion/gqlclient v0.0.0-20230820050442-8873fe0204b9/go.mod h1:kvl/JK0Z3VRmtbBxdOJR4ydyXVouUIcFIXgv4H6rVAY=
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=

base-commit: 499ef88754326222b1567261ac6b39b9f2a586ed
-- 
2.43.0
This looks good to me besides the below comment.