config

package
v0.3.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 28, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package config reads and writes the ana CLI configuration file.

The on-disk shape holds one or more named profiles, each carrying an endpoint + token pair. API keys are org-scoped, so users targeting more than one TextQL org need one profile per org. A single "active" pointer selects which profile is used by default.

Index

Constants

View Source
const DefaultEndpoint = "https://app.textql.com"

DefaultEndpoint is used by Resolve when no endpoint is configured.

Variables

View Source
var ErrUnknownProfile = errors.New("config: unknown profile")

ErrUnknownProfile is returned by Resolve when the caller explicitly asked for a profile by name (via --profile) that does not exist in the loaded config AND no ANA_ENDPOINT/ANA_TOKEN env fallback was provided. Wrapped with %w so callers can detect it via errors.Is.

Functions

func DefaultPath

func DefaultPath(env func(string) string) (string, error)

DefaultPath returns the default path for the config file.

It prefers $XDG_CONFIG_HOME/ana/config.json; falling back to $HOME/.config/ana/config.json. If neither variable is set, an error is returned.

env is the environment lookup function (injected so tests do not touch the real process environment); callers typically pass os.Getenv.

func Save

func Save(path string, cfg Config) error

Save writes cfg to path atomically. The parent directory is created with mode 0700 if it does not exist; the file itself is written with mode 0600. Writes go through path+".tmp" followed by os.Rename.

Types

type Config

type Config struct {
	Profiles            map[string]Profile `json:"profiles"`
	Active              string             `json:"active"`
	UpdateCheckInterval *string            `json:"updateCheckInterval,omitempty"`
}

Config is the persisted CLI configuration. Profiles maps profile name to its Profile. Active names the profile selected by default.

UpdateCheckInterval controls the passive self-update nudge cadence (see internal/update.ParseInterval). A pointer + omitempty keeps the on-disk shape backward-compatible: existing files never acquire the field and a nil value means "use the built-in default".

func Load

func Load(path string) (Config, error)

Load reads a config file from path. A missing file yields a zero-value Config and a nil error (first-run case). Other IO or JSON errors are wrapped and returned.

If the file is a legacy {endpoint, token} document (no "profiles" key), it is migrated in-memory to a single "default" profile. The migration is not persisted automatically — the next Save overwrites in the new shape.

When the new shape is present with an empty Active and exactly one profile, Active is inferred from that profile's name. With two or more profiles Active stays empty and callers must pick one.

func (Config) ActiveProfile

func (c Config) ActiveProfile() (string, Profile, bool)

ActiveProfile returns the currently active profile. ok is false when Active is unset or points at a profile that is not in the map.

func (*Config) Remove

func (c *Config) Remove(name string) bool

Remove deletes a profile by name. When the removed profile was Active, a replacement is chosen deterministically (lexicographic first of whatever remains); if no profiles remain, Active is cleared. Returns whether anything was removed.

func (*Config) Upsert

func (c *Config) Upsert(name string, p Profile)

Upsert inserts or replaces a profile by name. When Active is empty it is set to name so the first profile written always becomes active. Callers must Save afterwards to persist.

type Profile

type Profile struct {
	Endpoint string    `json:"endpoint"`
	Token    cli.Token `json:"token"`
	OrgName  string    `json:"orgName,omitempty"`
}

Profile is a single named {endpoint, token} pair. OrgName is a human label captured at login time; it is purely informational and never affects resolution.

func Resolve

func Resolve(env func(string) string, loaded Config, profileName string) (Profile, string, error)

Resolve selects a profile and applies environment overrides.

Profile selection priority (first non-empty wins):

  1. profileName argument (from --profile)
  2. env("ANA_PROFILE")
  3. loaded.Active
  4. first key of loaded.Profiles, sorted for determinism
  5. "default"

A selected name that does not exist in loaded.Profiles yields an empty Profile{} — this is not an error because first-run/login writes into a named slot that doesn't exist yet. The one exception: when the caller passed an explicit profileName that is missing AND no ANA_ENDPOINT / ANA_TOKEN env override is present, that's a user mistake (e.g. `--profile prod` when `prod` is not configured) and ErrUnknownProfile is returned with the bad name in the message.

ANA_ENDPOINT and ANA_TOKEN override whatever was resolved from the profile. If the final Endpoint is still empty, DefaultEndpoint fills it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL