No description
Find a file
2026-05-15 14:02:28 +03:00
docs Добавление глобальной переменной окружения CONFIG_FILE 2026-03-20 11:21:19 +03:00
examples Примеры использования 2026-03-19 16:33:25 +03:00
.gitignore Покрытие кода тестами 95% 2026-03-20 10:49:55 +03:00
arg.go Добавление позиционных аргументов 2026-05-15 14:02:28 +03:00
config.go Заголовка 2026-03-19 12:52:11 +03:00
defaults.go Заголовка 2026-03-19 12:52:11 +03:00
defaults_test.go Заголовка 2026-03-19 12:52:11 +03:00
dotenv.go Заголовка 2026-03-19 12:52:11 +03:00
dotenv_test.go Заголовка 2026-03-19 12:52:11 +03:00
duplicate_test.go Заголовка 2026-03-19 12:52:11 +03:00
env.go Заголовка 2026-03-19 12:52:11 +03:00
env_test.go Заголовка 2026-03-19 12:52:11 +03:00
errors.go Заголовка 2026-03-19 12:52:11 +03:00
go.mod Нормализация модулей 2026-03-20 11:22:00 +03:00
go.sum Нормализация модулей 2026-03-20 11:22:00 +03:00
help.go Добавление позиционных аргументов 2026-05-15 14:02:28 +03:00
help_test.go Добавление позиционных аргументов 2026-05-15 14:02:28 +03:00
integration_test.go Реализация 2026-03-19 16:15:39 +03:00
json.go Заголовка 2026-03-19 12:52:11 +03:00
json_test.go Заголовка 2026-03-19 12:52:11 +03:00
LICENSE Заголовка 2026-03-19 12:52:11 +03:00
parse_test.go Заголовка 2026-03-19 12:52:11 +03:00
parse_value_test.go Добавление позиционных аргументов 2026-05-15 14:02:28 +03:00
parser.go Добавление позиционных аргументов 2026-05-15 14:02:28 +03:00
parser_impl.go Добавление позиционных аргументов 2026-05-15 14:02:28 +03:00
parser_test.go Добавление позиционных аргументов 2026-05-15 14:02:28 +03:00
pointer.go Заголовка 2026-03-19 12:52:11 +03:00
pointer_test.go Заголовка 2026-03-19 12:52:11 +03:00
README.md Добавление позиционных аргументов 2026-05-15 14:02:28 +03:00
reflect.go Добавление позиционных аргументов 2026-05-15 14:02:28 +03:00
reflect_test.go Добавление позиционных аргументов 2026-05-15 14:02:28 +03:00
validate_test.go Покрытие тестами примерно на 87% 2026-03-20 09:25:14 +03:00
version_test.go Покрытие тестами примерно на 87% 2026-03-20 09:25:14 +03:00
yaml.go Заголовка 2026-03-19 12:52:11 +03:00
yaml_test.go Покрытие кода тестами 95% 2026-03-20 10:49:55 +03:00

go-simple-args

Go Reference Go Report Card Tests

Библиотека для парсинга аргументов командной строки на Go на основе структур. Поддерживает аргументы командной строки, переменные окружения, .env файлы и конфигурационные файлы YAML/JSON с автоматическим приоритетом.

Особенности

  • Простой API — используйте теги для описания параметров
  • Множественные источники конфигурации — CLI args → Env vars → Config files → Defaults
  • Вложенные структуры — автоматическая поддержка с инициализацией nil указателей
  • Генерация справки — автоматически из тегов help
  • Валидация — поддержка required полей
  • Безопасность — обнаружение дубликатов параметров

Установка

go get git.ymnuktech.ru/ymnuk/go-simple-args

Быстрый старт

Базовое использование

package main

import (
    "fmt"
    "log"
    
    "git.ymnuktech.ru/ymnuk/go-simple-args"
)

type Config struct {
    Port    int    `arg:"--port" default:"8080" help:"Port to listen on"`
    Host    string `arg:"--host" default:"localhost" help:"Host to bind"`
    Verbose bool   `arg:"--verbose" help:"Enable verbose logging"`
}

func main() {
    var cfg Config
    err := arg.MustParse(&cfg)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("Starting server on %s:%d\n", cfg.Host, cfg.Port)
}

Использование с обработкой ошибок

var cfg Config
parser, err := arg.NewParser(arg.Config{}, &cfg)
if err != nil {
    log.Fatal(err)
}

err = parser.Parse(os.Args[1:])
if err == arg.ErrHelp {
    parser.WriteHelp(os.Stdout)
    os.Exit(0)
}
if err == arg.ErrRequired {
    parser.WriteHelp(os.Stdout)
    os.Exit(1)
}
if err != nil {
    log.Fatal(err)
}

Теги полей

arg: — Аргументы командной строки

type Config struct {
    // Короткий флаг: -p
    Port int `arg:"-p" default:"8080"`
    
    // Длинный флаг: --host
    Host string `arg:"--host" default:"localhost"`
    
    // Оба флага: -v или --verbose
    Verbose bool `arg:"-v,--verbose"`
    
    // Переменная окружения: APP_NAME
    Name string `arg:"--name,env:APP_NAME"`
    
    // Required поле
    Token string `arg:"--token,required"`
    
    // Позиционный аргумент
    Input string `arg:"position" help:"Input file"`
    
    // Позиционный аргумент с индексом
    Output string `arg:"position:1" default:"out.txt"`
    
    // Позиционный аргумент + required
    Mode string `arg:"position:2,required" help:"Mode: read or write"`

    // Игнорировать поле
    Internal string `arg:"-"`
}

default: — Значения по умолчанию

type Config struct {
    Port    int    `default:"8080"`
    Host    string `default:"localhost"`
    Enabled bool   `default:"true"`
    Timeout string `default:"30s"`  // time.Duration
}

help: — Описание для справки

type Config struct {
    Port int `arg:"--port" help:"Port to listen on" default:"8080"`
    Host string `arg:"--host" help:"Host to bind" default:"localhost"`
}

env: — Переменные окружения

type Config struct {
    // Явное имя переменной
    Name string `arg:"--name,env:MY_NAME"`
    
    // С префиксом из Config.EnvPrefix
    // При EnvPrefix: "APP_" → APP_DATABASE_URL
    DatabaseURL string `arg:"--db-url,env:DATABASE_URL"`
}

required — Обязательные поля

type Config struct {
	// Без значения будет ошибка
	APIKey string `arg:"--api-key,required" help:"API key for authentication"`
}

position — Позиционные аргументы

type Config struct {
	// Позиционный аргумент (порядковый индекс auto)
	Input string `arg:"position" help:"Input file"`
	
	// С явным индексом
	Output string `arg:"position:1" help:"Output file" default:"out.txt"`
	
	// Обязательный позиционный аргумент
	Mode string `arg:"position:2,required" help:"Mode: read or write"`
}

Позиционные аргументы заполняются из аргументов командной строки, не начинающихся с - или --. Порядок:

  • Аргументы без флагов собираются в порядке появления
  • Назначаются полям по возрастанию индекса (position:0, position:1, ...)
  • Если индекс не указан, он назначается автоматически
  • Опциональные поля (без required) показываются в usage как [ИМЯ]
# ./app in.txt --verbose out.txt
./app input.txt output.txt --verbose

Источники конфигурации

Приоритет (от высшего к низшему)

  1. Аргументы командной строки (наивысший приоритет)
  2. Переменные окружения
  3. Файлы конфигурации (YAML/JSON)
  4. Значения по умолчанию (низший приоритет)

Пример приоритета

type Config struct {
    Port int `arg:"--port" env:PORT default:"8080"`
}
# 1. CLI (приоритет 1)
./app --port 9000    # Port = 9000

# 2. Env (приоритет 2)
PORT=8500 ./app      # Port = 8500

# 3. Config file (приоритет 3)
./app --config config.yaml  # Port из файла

# 4. Default (приоритет 4)
./app                  # Port = 8080

Вложенные структуры

type WebConfig struct {
    Port int    `arg:"--web-port" default:"8080"`
    Host string `arg:"--web-host" default:"localhost"`
}

type DBConfig struct {
    Host     string `arg:"--db-host" default:"localhost"`
    Port     int    `arg:"--db-port" default:"5432"`
    Database string `arg:"--db-name" default:"mydb"`
}

type Config struct {
    Web WebConfig `arg:"-"`
    DB  DBConfig  `arg:"-"`
}

func main() {
    var cfg Config
    arg.MustParse(&cfg)
    // cfg.Web.Port, cfg.DB.Host и т.д.
}

Указатели на структуры

type Config struct {
    Web *WebConfig `arg:"-"`  // Автоматически инициализируется
}

Библиотека автоматически создаст экземпляр WebConfig при парсинге.

Конфигурационные файлы

YAML

# config.yaml
name: myapp
port: 8080
enabled: true

database:
  host: localhost
  port: 5432
type Config struct {
    Name    string `yaml:"name" default:"app"`
    Port    int    `yaml:"port" default:"8080"`
    Enabled bool   `yaml:"enabled" default:"false"`
}

func main() {
    var cfg Config
    p, _ := arg.NewParser(arg.Config{
        ConfigFile: "config.yaml",  // Или используйте переменную окружения CONFIG_FILE
    }, &cfg)
    p.Parse(os.Args[1:])
}

Путь к файлу конфигурации можно указать тремя способами (по приоритету):

  1. Явно в коде: ConfigFile: "config.yaml"
  2. Переменная окружения: CONFIG_FILE=/path/to/config.yaml
  3. Флаг командной строки: --config /path/to/config.yaml

Для Docker: удобно использовать переменную окружения:

ENV CONFIG_FILE=/app/config.yaml

JSON

{
  "name": "myapp",
  "port": 8080,
  "enabled": true
}
type Config struct {
    Name    string `json:"name" default:"app"`
    Port    int    `json:"port" default:"8080"`
    Enabled bool   `json:"enabled" default:"false"`
}

.env файлы

Автоматически загружается файл .env из текущей директории:

# .env
APP_PORT=9000
APP_HOST=0.0.0.0
APP_DEBUG=true
type Config struct {
    Port  int    `arg:"--port,env:APP_PORT" default:"8080"`
    Host  string `arg:"--host,env:APP_HOST" default:"localhost"`
    Debug bool   `arg:"--debug,env:APP_DEBUG" default:"false"`
}

func main() {
    var cfg Config
    arg.MustParse(&cfg)  // .env загрузится автоматически
}

Пользовательский путь к .env

p, _ := arg.NewParser(arg.Config{
    EnvFile: ".env.production",
}, &cfg)
p.Parse(os.Args[1:])

Поддерживаемые типы

  • Целочисленные: int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64
  • С плавающей точкой: float32, float64
  • Строки: string
  • Булевы: bool
  • Время: time.Duration (формат: 1s, 1m, 1h)
  • Указатели на все вышеперечисленные типы
  • Вложенные структуры

Расширенные возможности

Префикс переменных окружения

type Config struct {
    Port int `arg:"--port,env:PORT"`
}

p, _ := arg.NewParser(arg.Config{
    EnvPrefix: "APP_",  // APP_PORT
}, &cfg)

Игнорирование источников

// Игнорировать переменные окружения
p, _ := arg.NewParser(arg.Config{
    IgnoreEnv: true,
}, &cfg)

// Игнорировать значения по умолчанию
p, _ := arg.NewParser(arg.Config{
    IgnoreDefault: true,
}, &cfg)

Версия приложения

p, _ := arg.NewParser(arg.Config{
    Version: "1.0.0",
    AppName: "MyApp",
}, &cfg)

// ./app --version
// MyApp version 1.0.0

Флаг --version и -v (если задана Version) показывают версию. MustParse выводит версию и завершает работу автоматически.

Колбэки OnHelp / OnVersion

Позволяют перехватить --help/-h и --version/-v, выполнив свою логику (например, выход из программы):

p, _ := arg.NewParser(arg.Config{
    Version: "1.0.0",
    OnHelp: func(p *arg.Parser) {
        p.WriteHelp(os.Stdout)
        os.Exit(0)
    },
    OnVersion: func(p *arg.Parser) {
        p.WriteVersion(os.Stdout)
        os.Exit(0)
    },
}, &cfg)

err := p.Parse(os.Args[1:])
// err == nil — колбэк уже обработал флаг

Если колбэк не задан, Parse() возвращает ErrHelp/ErrVersion как и раньше.

Обработка ошибок

var cfg Config
p, err := arg.NewParser(arg.Config{}, &cfg)
if err != nil {
    log.Fatal(err)
}

err = p.Parse(os.Args[1:])
switch err {
case nil:
    // Успех
case arg.ErrHelp:
    p.WriteHelp(os.Stdout)
    os.Exit(0)
case arg.ErrRequired:
    fmt.Fprintln(os.Stderr, "Error: required argument missing")
    p.WriteHelp(os.Stderr)
    os.Exit(1)
case arg.ErrDuplicate:
    fmt.Fprintln(os.Stderr, "Error: duplicate argument")
    os.Exit(1)
default:
    fmt.Fprintf(os.Stderr, "Error: %v\n", err)
    os.Exit(1)
}

Примеры

Полное приложение

package main

import (
    "fmt"
    "log"
    "os"
    
    "git.ymnuktech.ru/ymnuk/go-simple-args"
)

type DatabaseConfig struct {
    Host     string `arg:"--db-host" env:DB_HOST default:"localhost"`
    Port     int    `arg:"--db-port" env:DB_PORT default:"5432"`
    Database string `arg:"--db-name" env:DB_NAME default:"mydb"`
    User     string `arg:"--db-user" env:DB_USER,required`
    Password string `arg:"--db-pass" env:DB_PASSWORD,required`
}

type ServerConfig struct {
    Host string `arg:"--host" env:SERVER_HOST default:"0.0.0.0"`
    Port int    `arg:"--port" env:SERVER_PORT default:"8080"`
}

type Config struct {
    Debug    bool           `arg:"--debug" env:DEBUG default:"false"`
    Database DatabaseConfig `arg:"-"`
    Server   ServerConfig   `arg:"-"`
}

func main() {
    var cfg Config
    
    p, err := arg.NewParser(arg.Config{
        EnvPrefix: "APP_",
        EnvFile:   ".env",
    }, &cfg)
    if err != nil {
        log.Fatal(err)
    }
    
    err = p.Parse(os.Args[1:])
    if err == arg.ErrHelp {
        p.WriteHelp(os.Stdout)
        os.Exit(0)
    }
    if err == arg.ErrRequired {
        fmt.Fprintln(os.Stderr, "Error: required argument missing")
        p.WriteHelp(os.Stderr)
        os.Exit(1)
    }
    if err != nil {
        fmt.Fprintf(os.Stderr, "Error: %v\n", err)
        os.Exit(1)
    }
    
    fmt.Printf("Starting server on %s:%d\n", cfg.Server.Host, cfg.Server.Port)
    fmt.Printf("Database: %s@%s:%d/%s\n", 
        cfg.Database.User, cfg.Database.Host, 
        cfg.Database.Port, cfg.Database.Database)
}

Запуск:

# С значениями по умолчанию
./app

# С аргументами командной строки
./app --port 9000 --debug

# С переменными окружения
APP_PORT=9000 APP_DEBUG=true ./app

# С конфигурационным файлом
./app --config config.yaml

# С .env файлом
# .env: APP_PORT=9000, APP_DEBUG=true
./app

Лицензия

MIT License — см. файл LICENSE