Ctrl K
ComunidadGuías…

iclient/config_file.go

Rama develop · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package iclient

import (
	"fmt"
	"os"
	"os/user"
	"path/filepath"

	"github.com/lxc/incus/v7/shared/api"
	"github.com/lxc/incus/v7/shared/util"
	"go.yaml.in/yaml/v4"
)

// configDir returns the directory holding the Incus CLI configuration.
func configDir() (string, error) {
	if os.Getenv("INCUS_CONF") != "" {
		return os.Getenv("INCUS_CONF"), nil
	}

	base, err := os.UserConfigDir()
	if err != nil || base == "" {
		usr, err := user.Current()
		if err != nil {
			return "", err
		}

		if usr.HomeDir == "" {
			return "", nil
		}

		base = filepath.Join(usr.HomeDir, ".config")
	}

	return filepath.Join(base, "incus"), nil
}

// configPaths returns the configuration file and the directory holding it.
func configPaths() (string, string, error) {
	dir, err := configDir()
	if err != nil {
		return "", "", err
	}

	if dir == "" {
		return "", "", nil
	}

	path := os.ExpandEnv(filepath.Join(dir, "config.yml"))

	return path, filepath.Dir(path), nil
}

// ReadConfig reads the CLI configuration at path, falling back to the default
// location when path is empty and to the built-in defaults when no file exists.
func ReadConfig(path string) (*Config, error) {
	dir := filepath.Dir(path)

	if path == "" {
		var err error

		path, dir, err = configPaths()
		if err != nil {
			return nil, err
		}
	}

	if path == "" || !util.PathExists(path) {
		c := ConfigDefaultConfig()
		c.ConfigDir = dir

		return c, nil
	}

	content, err := os.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("reading the configuration file: %w", err)
	}

	c := &Config{ConfigDir: dir}

	err = yaml.Load(content, c)
	if err != nil {
		return nil, fmt.Errorf("decoding the configuration: %w", err)
	}

	if c.Remotes == nil {
		c.Remotes = map[string]ConfigRemote{}
	}

	for k, r := range c.Remotes {
		if !r.Public && r.AuthType == "" {
			r.AuthType = api.AuthenticationMethodTLS
			c.Remotes[k] = r
		}
	}

	err = c.addGlobalRemotes()
	if err != nil {
		return nil, err
	}

	for k, r := range c.Remotes {
		if r.Protocol == "" {
			r.Protocol = "incus"
			c.Remotes[k] = r
		}
	}

	c.Remotes["local"] = ConfigLocalRemote

	if c.DefaultRemote == "" {
		c.DefaultRemote = ConfigDefaultConfig().DefaultRemote
	}

	c.prefillCreds()

	return c, nil
}

// addGlobalRemotes merges the system-wide remotes that the user's own
// configuration does not already name.
func (c *Config) addGlobalRemotes() error {
	path := configGlobalPath("config.yml")
	if !util.PathExists(path) {
		return nil
	}

	content, err := os.ReadFile(path)
	if err != nil {
		return fmt.Errorf("reading the global configuration: %w", err)
	}

	global := &Config{}

	err = yaml.Load(content, global)
	if err != nil {
		return fmt.Errorf("decoding the global configuration: %w", err)
	}

	for k, r := range global.Remotes {
		_, ok := c.Remotes[k]
		if ok {
			continue
		}

		r.Global = true
		c.Remotes[k] = r
	}

	return nil
}