Initial QSfera import

This commit is contained in:
Курнат Андрей
2026-06-07 10:20:04 +03:00
commit 2315f25754
16485 changed files with 4826827 additions and 0 deletions
+62
View File
@@ -0,0 +1,62 @@
# Env Util
Provide some commonly system or go ENV util functions.
## Install
```shell
go get github.com/gookit/goutil/envutil
```
## Go docs
- [Go docs](https://pkg.go.dev/github.com/gookit/goutil/envutil)
## Functions API
> **Note**: doc by run `go doc ./envutil`
```go
func Environ() map[string]string
func GetBool(name string, def ...bool) bool
func GetInt(name string, def ...int) int
func Getenv(name string, def ...string) string
func HasShellEnv(shell string) bool
func IsConsole(out io.Writer) bool
func IsGithubActions() bool
func IsLinux() bool
func IsMSys() bool
func IsMac() bool
func IsSupport256Color() bool
func IsSupportColor() bool
func IsSupportTrueColor() bool
func IsTerminal(fd uintptr) bool
func IsWSL() bool
func IsWin() bool
func IsWindows() bool
func ParseEnvValue(val string) string
func ParseValue(val string) (newVal string)
func SetEnvs(mp map[string]string)
func StdIsTerminal() bool
func VarParse(val string) string
func VarReplace(s string) string
```
## Code Check & Testing
```bash
gofmt -w -l ./
golint ./...
```
**Testing**:
```shell
go test -v ./envutil/...
```
**Test limit by regexp**:
```shell
go test -v -run ^TestSetByKeys ./envutil/...
```
+198
View File
@@ -0,0 +1,198 @@
package envutil
import (
"os"
"path/filepath"
"strings"
"github.com/gookit/goutil/internal/comfunc"
)
// DefaultEnvFile default file name
const DefaultEnvFile = ".env"
// Dotenv load and parse dotenv files
type Dotenv struct {
// Files dot env file paths, allow multi files.
// - filename support simple glob pattern. eg: ".env.*"
//
// default: [".env"]
Files []string
// BaseDir base dir for join files path
//
// default is workdir
BaseDir string
// UpperKey change key to upper on set ENV. default: true
UpperKey bool
// IgnoreNotExist only load exists.
//
// - default: false - will return error if not exists
IgnoreNotExist bool
// LoadFirstExist only load first exists env file on Files
LoadFirstExist bool
loadFiles []string
loadData map[string]string
}
// NewDotenv create a new dotenv config
func NewDotenv() *Dotenv {
return &Dotenv{
UpperKey: true,
Files: []string{DefaultEnvFile},
// init fields
loadData: make(map[string]string),
}
}
// LoadAndInit load dotenv files and parse to os.Environ
func (c *Dotenv) LoadAndInit() error {
return c.doLoadFiles(c.Files)
}
// LoadFiles append load dotenv files
// - filename support simple glob pattern. eg: ".env.*"
func (c *Dotenv) LoadFiles(files ...string) error {
return c.doLoadFiles(files)
}
// LoadText load dotenv contents and parse to os Env
func (c *Dotenv) LoadText(contents string) error {
return c.parseAndSetEnv(contents)
}
// do load dotenv files
func (c *Dotenv) doLoadFiles(files []string) error {
var filePath string
for _, file := range files {
filePath = strings.TrimSpace(file)
if c.BaseDir != "" && !filepath.IsAbs(file) {
filePath = filepath.Join(c.BaseDir, file)
}
// load and parse to ENV
if err := c.loadFile(filePath); err != nil {
return err
}
if c.LoadFirstExist && len(c.loadFiles) > 0 {
break
}
}
return nil
}
func (c *Dotenv) loadFile(filePath string) error {
// filename support simple glob pattern.
if strings.ContainsRune(filePath, '*') {
matches, err := filepath.Glob(filePath)
if err != nil {
return err
}
for _, matchFile := range matches {
if err = c.parseFile(matchFile); err != nil {
return err
}
}
return err
}
// Load single file
return c.parseFile(filePath)
}
// parseFile load single file and parse to ENV
func (c *Dotenv) parseFile(filePath string) error {
contents, err := os.ReadFile(filePath)
if err != nil {
// IgnoreNotExist: skip non-existent files
if c.IgnoreNotExist && os.IsNotExist(err) {
return nil
}
return err
}
err = c.parseAndSetEnv(string(contents))
if err == nil {
c.loadFiles = append(c.loadFiles, filePath)
}
return err
}
func (c *Dotenv) parseAndSetEnv(contents string) error {
// Parse ENV lines
envMp, err := comfunc.ParseEnvLines(contents, comfunc.ParseEnvLineOption{
SkipOnErrorLine: true,
})
// Set to ENV
for key, val := range envMp {
key = strings.ToUpper(key)
c.loadData[key] = val
_ = os.Setenv(key, val)
}
return err
}
// UnloadEnv remove loaded dotenv data from os.Environ
func (c *Dotenv) UnloadEnv() bool {
if len(c.loadData) == 0 {
return false
}
for key := range c.loadData {
_ = os.Unsetenv(key)
}
return true
}
// LoadedData get loaded dotenv data map
func (c *Dotenv) LoadedData() map[string]string {
return c.loadData
}
// LoadedFiles get loaded dotenv files
func (c *Dotenv) LoadedFiles() []string {
return c.loadFiles
}
// Reset unload all loaded ENV and reset data
func (c *Dotenv) Reset() {
c.UnloadEnv()
c.loadFiles = nil
c.loadData = make(map[string]string)
}
//
// region standard dotenv instance
//
var stdEnv = NewDotenv()
// StdDotenv get standard dotenv instance
func StdDotenv() *Dotenv { return stdEnv }
// DotenvLoad load dotenv file and parse to ENV
func DotenvLoad(fns ...func(cfg *Dotenv)) error {
for _, fn := range fns {
fn(stdEnv)
}
return stdEnv.LoadAndInit()
}
// LoadEnvFiles load dotenv files and parse to ENV
func LoadEnvFiles(baseDir string, files ...string) error {
return DotenvLoad(func(cfg *Dotenv) {
cfg.BaseDir = baseDir
if len(files) > 0 {
cfg.Files = files
}
})
}
// LoadedEnvFiles get loaded dotenv files
func LoadedEnvFiles() []string {
return stdEnv.LoadedFiles()
}
+66
View File
@@ -0,0 +1,66 @@
// Package envutil provide some commonly ENV util functions.
package envutil
import (
"os"
"strings"
"github.com/gookit/goutil/internal/comfunc"
"github.com/gookit/goutil/internal/varexpr"
)
// ValueGetter Env value provider func.
//
// TIPS: you can custom provide data.
var ValueGetter = os.Getenv
// VarReplace replaces ${var} or $var in the string according to the values.
//
// is alias of the os.ExpandEnv()
func VarReplace(s string) string { return os.ExpandEnv(s) }
// ParseOrErr parse ENV var value from input string, support default value.
//
// Diff with the ParseValue, this support return error.
//
// With error format: ${VAR_NAME | ?error}
func ParseOrErr(val string) (string, error) {
return varexpr.Parse(val)
}
// ParseValue parse ENV var value from input string, support default value.
//
// Format:
//
// ${var_name} Only var name
// ${var_name | default} With default value
//
// Usage:
//
// envutil.ParseValue("${ APP_NAME }")
// envutil.ParseValue("${ APP_ENV | dev }")
func ParseValue(val string) string {
return varexpr.SafeParse(val)
}
// VarParse alias of the ParseValue
func VarParse(val string) string { return varexpr.SafeParse(val) }
// ParseEnvValue alias of the ParseValue
func ParseEnvValue(val string) string { return varexpr.SafeParse(val) }
// SplitText2map parse ENV text to map. Can use to parse .env file contents.
func SplitText2map(text string) map[string]string {
envMp, _ := comfunc.ParseEnvLines(text, comfunc.ParseEnvLineOption{
SkipOnErrorLine: true,
})
return envMp
}
// SplitLineToKv parse ENV line to k-v. eg: 'DEBUG=true' => ['DEBUG', 'true']
func SplitLineToKv(line string) (string, string) {
if line = strings.TrimSpace(line); line == "" {
return "", ""
}
return comfunc.SplitLineToKv(line, "=")
}
+115
View File
@@ -0,0 +1,115 @@
package envutil
import (
"os"
"path/filepath"
"github.com/gookit/goutil/internal/comfunc"
"github.com/gookit/goutil/strutil"
"github.com/gookit/goutil/x/basefn"
)
// HasEnv check ENV key exists
func HasEnv(name string) bool {
_, ok := os.LookupEnv(name)
return ok
}
// Getenv get ENV value by key name, can with default value
func Getenv(name string, def ...string) string {
val := os.Getenv(name)
if val == "" && len(def) > 0 {
val = def[0]
}
return val
}
// MustGet get ENV value by key name, if not exists or empty, will panic
func MustGet(name string) string {
if val := os.Getenv(name); val != "" {
return val
}
panic("ENV key '" + name + "' not exists")
}
// GetInt get int ENV value by key name, can with default value
func GetInt(name string, def ...int) int {
if val := os.Getenv(name); val != "" {
return strutil.QuietInt(val)
}
return basefn.FirstOr(def, 0)
}
// GetBool get bool ENV value by key name, can with default value
func GetBool(name string, def ...bool) bool {
if val := os.Getenv(name); val != "" {
return strutil.QuietBool(val)
}
return basefn.FirstOr(def, false)
}
// GetOne get one not empty ENV value by input names.
func GetOne(names []string, defVal ...string) string {
for _, name := range names {
if val := os.Getenv(name); val != "" {
return val
}
}
if len(defVal) > 0 {
return defVal[0]
}
return ""
}
// GetMulti ENV values by input names.
func GetMulti(names ...string) map[string]string {
valMap := make(map[string]string, len(names))
for _, name := range names {
if val := os.Getenv(name); val != "" {
valMap[name] = val
}
}
return valMap
}
// OnExist check ENV value by key name, will call fn on value exists(not-empty)
func OnExist(name string, fn func(val string)) bool {
if val := os.Getenv(name); val != "" {
fn(val)
return true
}
return false
}
// EnvPaths get and split $PATH to []string
func EnvPaths() []string {
return filepath.SplitList(os.Getenv("PATH"))
}
// EnvMap like os.Environ, but will returns key-value map[string]string data.
func EnvMap() map[string]string { return comfunc.Environ() }
// Environ like os.Environ, but will returns key-value map[string]string data.
func Environ() map[string]string { return comfunc.Environ() }
// SearchEnvKeys values by given keywords
func SearchEnvKeys(keywords string) map[string]string {
return SearchEnv(keywords, false)
}
// SearchEnv values by given keywords
func SearchEnv(keywords string, matchValue bool) map[string]string {
founded := make(map[string]string)
for name, val := range comfunc.Environ() {
if strutil.IContains(name, keywords) {
founded[name] = val
} else if matchValue && strutil.IContains(val, keywords) {
founded[name] = val
}
}
return founded
}
+143
View File
@@ -0,0 +1,143 @@
package envutil
import (
"io"
"os"
"runtime"
"strings"
"github.com/gookit/goutil/internal/comfunc"
"github.com/gookit/goutil/sysutil"
"golang.org/x/term"
)
// IsWin system. linux windows darwin
func IsWin() bool {
return runtime.GOOS == "windows"
}
// IsWindows system. alias of IsWin
func IsWindows() bool {
return runtime.GOOS == "windows"
}
// IsMac system
func IsMac() bool {
return runtime.GOOS == "darwin"
}
// IsLinux system
func IsLinux() bool {
return runtime.GOOS == "linux"
}
// IsMSys msys(MINGW64) env. alias of the sysutil.IsMSys()
func IsMSys() bool {
return sysutil.IsMSys()
}
// IsTerminal isatty check
//
// Usage:
//
// envutil.IsTerminal(os.Stdout.Fd())
func IsTerminal(fd uintptr) bool {
// return isatty.IsTerminal(fd) // "github.com/mattn/go-isatty"
return term.IsTerminal(int(fd))
}
// StdIsTerminal os.Stdout is terminal
func StdIsTerminal() bool {
return IsTerminal(os.Stdout.Fd())
}
// IsConsole check out is console env. alias of the sysutil.IsConsole()
func IsConsole(out io.Writer) bool {
return sysutil.IsConsole(out)
}
// HasShellEnv has shell env check.
//
// Usage:
//
// HasShellEnv("sh")
// HasShellEnv("bash")
func HasShellEnv(shell string) bool {
return comfunc.HasShellEnv(shell)
}
// Support color:
//
// "TERM=xterm"
// "TERM=xterm-vt220"
// "TERM=xterm-256color"
// "TERM=screen-256color"
// "TERM=tmux-256color"
// "TERM=rxvt-unicode-256color"
//
// Don't support color:
//
// "TERM=cygwin"
var specialColorTerms = map[string]bool{
"alacritty": true,
}
// IsSupportColor check current console is support color.
//
// Supported:
//
// linux, mac, or Windows's ConEmu, Cmder, putty, git-bash.exe
//
// Not support:
//
// windows cmd.exe, powerShell.exe
func IsSupportColor() bool {
envTerm := os.Getenv("TERM")
if strings.Contains(envTerm, "xterm") {
return true
}
// it's special color term
if _, ok := specialColorTerms[envTerm]; ok {
return true
}
// like on ConEmu software, e.g "ConEmuANSI=ON"
if os.Getenv("ConEmuANSI") == "ON" {
return true
}
// like on ConEmu software, e.g "ANSICON=189x2000 (189x43)"
if os.Getenv("ANSICON") != "" {
return true
}
// up: if support 256-color, can also support basic color.
return IsSupport256Color()
}
// IsSupport256Color render
func IsSupport256Color() bool {
// "TERM=xterm-256color"
// "TERM=screen-256color"
// "TERM=tmux-256color"
// "TERM=rxvt-unicode-256color"
supported := strings.Contains(os.Getenv("TERM"), "256color")
if !supported {
// up: if support true-color, can also support 256-color.
supported = IsSupportTrueColor()
}
return supported
}
// IsSupportTrueColor render. IsSupportRGBColor
func IsSupportTrueColor() bool {
// "COLORTERM=truecolor"
return strings.Contains(os.Getenv("COLORTERM"), "truecolor")
}
// IsGithubActions env
func IsGithubActions() bool {
return os.Getenv("GITHUB_ACTIONS") == "true"
}
+53
View File
@@ -0,0 +1,53 @@
package envutil
import (
"os"
"github.com/gookit/goutil/internal/comfunc"
)
// SetEnvMap set multi ENV(string-map) to os
func SetEnvMap(mp map[string]string) {
for key, value := range mp {
_ = os.Setenv(key, value)
}
}
// SetEnvs set multi k-v ENV pairs to os
func SetEnvs(kvPairs ...string) {
if len(kvPairs)%2 == 1 {
panic("envutil.SetEnvs: odd argument count")
}
for i := 0; i < len(kvPairs); i += 2 {
_ = os.Setenv(kvPairs[i], kvPairs[i+1])
}
}
// UnsetEnvs from os
func UnsetEnvs(keys ...string) {
for _, key := range keys {
_ = os.Unsetenv(key)
}
}
// LoadText parse multiline text to ENV. Can use to load .env file contents.
//
// Usage:
//
// envutil.LoadText(fsutil.ReadFile(".env"))
func LoadText(text string) {
envMp := SplitText2map(text)
for key, value := range envMp {
_ = os.Setenv(key, value)
}
}
// LoadString set line to ENV. e.g.: "KEY=VALUE"
func LoadString(line string) bool {
k, v := comfunc.SplitLineToKv(line, "=")
if len(k) > 0 {
return os.Setenv(k, v) == nil
}
return false
}