mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 23:22:26 -05:00 
			
		
		
		
	- codeberg.org/gruf/go-ffmpreg: v0.6.10 -> v0.6.11 - github.com/spf13/cast: v1.9.2 -> v1.10.0 - github.com/spf13/viper: v1.20.1 -> v1.21.0 - golang.org/x/crypto: v0.41.0 -> v0.42.0 - golang.org/x/image: v0.30.0 -> v0.31.0 Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4423 Co-authored-by: kim <grufwub@gmail.com> Co-committed-by: kim <grufwub@gmail.com>
		
			
				
	
	
		
			211 lines
		
	
	
	
		
			4.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
	
		
			4.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright © 2014 Steve Francia <spf@spf13.com>.
 | |
| //
 | |
| // Use of this source code is governed by an MIT-style
 | |
| // license that can be found in the LICENSE file.
 | |
| 
 | |
| // Viper is a application configuration system.
 | |
| // It believes that applications can be configured a variety of ways
 | |
| // via flags, ENVIRONMENT variables, configuration files retrieved
 | |
| // from the file system, or a remote key/value store.
 | |
| 
 | |
| package viper
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"log/slog"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"runtime"
 | |
| 	"strings"
 | |
| 	"unicode"
 | |
| 
 | |
| 	"github.com/spf13/cast"
 | |
| )
 | |
| 
 | |
| // ConfigParseError denotes failing to parse configuration file.
 | |
| type ConfigParseError struct {
 | |
| 	err error
 | |
| }
 | |
| 
 | |
| // Error returns the formatted configuration error.
 | |
| func (pe ConfigParseError) Error() string {
 | |
| 	return fmt.Sprintf("While parsing config: %s", pe.err.Error())
 | |
| }
 | |
| 
 | |
| // Unwrap returns the wrapped error.
 | |
| func (pe ConfigParseError) Unwrap() error {
 | |
| 	return pe.err
 | |
| }
 | |
| 
 | |
| // toCaseInsensitiveValue checks if the value is a  map;
 | |
| // if so, create a copy and lower-case the keys recursively.
 | |
| func toCaseInsensitiveValue(value any) any {
 | |
| 	switch v := value.(type) {
 | |
| 	case map[any]any:
 | |
| 		value = copyAndInsensitiviseMap(cast.ToStringMap(v))
 | |
| 	case map[string]any:
 | |
| 		value = copyAndInsensitiviseMap(v)
 | |
| 	}
 | |
| 
 | |
| 	return value
 | |
| }
 | |
| 
 | |
| // copyAndInsensitiviseMap behaves like insensitiviseMap, but creates a copy of
 | |
| // any map it makes case insensitive.
 | |
| func copyAndInsensitiviseMap(m map[string]any) map[string]any {
 | |
| 	nm := make(map[string]any)
 | |
| 
 | |
| 	for key, val := range m {
 | |
| 		lkey := strings.ToLower(key)
 | |
| 		switch v := val.(type) {
 | |
| 		case map[any]any:
 | |
| 			nm[lkey] = copyAndInsensitiviseMap(cast.ToStringMap(v))
 | |
| 		case map[string]any:
 | |
| 			nm[lkey] = copyAndInsensitiviseMap(v)
 | |
| 		default:
 | |
| 			nm[lkey] = v
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return nm
 | |
| }
 | |
| 
 | |
| func insensitiviseVal(val any) any {
 | |
| 	switch v := val.(type) {
 | |
| 	case map[any]any:
 | |
| 		// nested map: cast and recursively insensitivise
 | |
| 		val = cast.ToStringMap(val)
 | |
| 		insensitiviseMap(val.(map[string]any))
 | |
| 	case map[string]any:
 | |
| 		// nested map: recursively insensitivise
 | |
| 		insensitiviseMap(v)
 | |
| 	case []any:
 | |
| 		// nested array: recursively insensitivise
 | |
| 		insensitiveArray(v)
 | |
| 	}
 | |
| 	return val
 | |
| }
 | |
| 
 | |
| func insensitiviseMap(m map[string]any) {
 | |
| 	for key, val := range m {
 | |
| 		val = insensitiviseVal(val)
 | |
| 		lower := strings.ToLower(key)
 | |
| 		if key != lower {
 | |
| 			// remove old key (not lower-cased)
 | |
| 			delete(m, key)
 | |
| 		}
 | |
| 		// update map
 | |
| 		m[lower] = val
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func insensitiveArray(a []any) {
 | |
| 	for i, val := range a {
 | |
| 		a[i] = insensitiviseVal(val)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func absPathify(logger *slog.Logger, inPath string) string {
 | |
| 	logger.Info("trying to resolve absolute path", "path", inPath)
 | |
| 
 | |
| 	if inPath == "$HOME" || strings.HasPrefix(inPath, "$HOME"+string(os.PathSeparator)) {
 | |
| 		inPath = userHomeDir() + inPath[5:]
 | |
| 	}
 | |
| 
 | |
| 	inPath = os.ExpandEnv(inPath)
 | |
| 
 | |
| 	if filepath.IsAbs(inPath) {
 | |
| 		return filepath.Clean(inPath)
 | |
| 	}
 | |
| 
 | |
| 	p, err := filepath.Abs(inPath)
 | |
| 	if err == nil {
 | |
| 		return filepath.Clean(p)
 | |
| 	}
 | |
| 
 | |
| 	logger.Error(fmt.Errorf("could not discover absolute path: %w", err).Error())
 | |
| 
 | |
| 	return ""
 | |
| }
 | |
| 
 | |
| func userHomeDir() string {
 | |
| 	if runtime.GOOS == "windows" {
 | |
| 		home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
 | |
| 		if home == "" {
 | |
| 			home = os.Getenv("USERPROFILE")
 | |
| 		}
 | |
| 		return home
 | |
| 	}
 | |
| 	return os.Getenv("HOME")
 | |
| }
 | |
| 
 | |
| func safeMul(a, b uint) uint {
 | |
| 	c := a * b
 | |
| 	if a > 1 && b > 1 && c/b != a {
 | |
| 		return 0
 | |
| 	}
 | |
| 	return c
 | |
| }
 | |
| 
 | |
| // parseSizeInBytes converts strings like 1GB or 12 mb into an unsigned integer number of bytes.
 | |
| func parseSizeInBytes(sizeStr string) uint {
 | |
| 	sizeStr = strings.TrimSpace(sizeStr)
 | |
| 	lastChar := len(sizeStr) - 1
 | |
| 	multiplier := uint(1)
 | |
| 
 | |
| 	if lastChar > 0 {
 | |
| 		if sizeStr[lastChar] == 'b' || sizeStr[lastChar] == 'B' {
 | |
| 			if lastChar > 1 {
 | |
| 				switch unicode.ToLower(rune(sizeStr[lastChar-1])) {
 | |
| 				case 'k':
 | |
| 					multiplier = 1 << 10
 | |
| 					sizeStr = strings.TrimSpace(sizeStr[:lastChar-1])
 | |
| 				case 'm':
 | |
| 					multiplier = 1 << 20
 | |
| 					sizeStr = strings.TrimSpace(sizeStr[:lastChar-1])
 | |
| 				case 'g':
 | |
| 					multiplier = 1 << 30
 | |
| 					sizeStr = strings.TrimSpace(sizeStr[:lastChar-1])
 | |
| 				default:
 | |
| 					multiplier = 1
 | |
| 					sizeStr = strings.TrimSpace(sizeStr[:lastChar])
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	size := max(cast.ToInt(sizeStr), 0)
 | |
| 
 | |
| 	return safeMul(uint(size), multiplier)
 | |
| }
 | |
| 
 | |
| // deepSearch scans deep maps, following the key indexes listed in the
 | |
| // sequence "path".
 | |
| // The last value is expected to be another map, and is returned.
 | |
| //
 | |
| // In case intermediate keys do not exist, or map to a non-map value,
 | |
| // a new map is created and inserted, and the search continues from there:
 | |
| // the initial map "m" may be modified!
 | |
| func deepSearch(m map[string]any, path []string) map[string]any {
 | |
| 	for _, k := range path {
 | |
| 		m2, ok := m[k]
 | |
| 		if !ok {
 | |
| 			// intermediate key does not exist
 | |
| 			// => create it and continue from there
 | |
| 			m3 := make(map[string]any)
 | |
| 			m[k] = m3
 | |
| 			m = m3
 | |
| 			continue
 | |
| 		}
 | |
| 		m3, ok := m2.(map[string]any)
 | |
| 		if !ok {
 | |
| 			// intermediate key is a value
 | |
| 			// => replace with a new map
 | |
| 			m3 = make(map[string]any)
 | |
| 			m[k] = m3
 | |
| 		}
 | |
| 		// continue search from here
 | |
| 		m = m3
 | |
| 	}
 | |
| 	return m
 | |
| }
 |