167 lines
4.7 KiB
Go
167 lines
4.7 KiB
Go
package backer
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"regexp"
|
|
|
|
"backer/internal/log"
|
|
|
|
hjson "github.com/hjson/hjson-go"
|
|
)
|
|
|
|
// LoadConfig loads config file to global variable C.
|
|
func LoadConfig(path string) error {
|
|
var tmp map[string]any
|
|
|
|
buf, err := os.ReadFile(path)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to read config file: %w", err)
|
|
}
|
|
|
|
if err = hjson.Unmarshal(buf, &tmp); err != nil {
|
|
return fmt.Errorf("Unable to parse config: %w", err)
|
|
}
|
|
|
|
buf, err = json.Marshal(tmp)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Unable to convert config: %w", err)
|
|
}
|
|
|
|
if err = json.Unmarshal(buf, &C); err != nil {
|
|
return fmt.Errorf("Failed to decode config file: %w", err)
|
|
}
|
|
|
|
// Address: default and no range validation needed.
|
|
if C.Address == "" {
|
|
C.Address = defaultAddress
|
|
|
|
log.Warnf("Config option address is not set, fallback to %s", C.Address)
|
|
}
|
|
|
|
// Port: set default, then validate range.
|
|
if C.Port == 0 {
|
|
C.Port = defaultPort
|
|
|
|
log.Warnf("Config option port is not set, fallback to %d", C.Port)
|
|
}
|
|
|
|
if C.Port < portMin || C.Port > portMax {
|
|
return fmt.Errorf("Config option port must be between %d and %d, got %d", portMin, portMax, C.Port)
|
|
}
|
|
|
|
// Location: default and no range validation needed.
|
|
if C.Location == "" {
|
|
C.Location = defaultLocation
|
|
|
|
log.Warnf("Config option location is not set, fallback to %s", C.Location)
|
|
}
|
|
|
|
// Log: default only.
|
|
if C.Log == "" {
|
|
log.Warn("Config option log is not set, fallback to stderr")
|
|
}
|
|
|
|
// LogLevel: default and no range validation needed.
|
|
if C.LogLevel == "" {
|
|
C.LogLevel = defaultLogLevel
|
|
|
|
log.Warnf("Config option loglevel is not set, fallback to %s", C.LogLevel)
|
|
}
|
|
|
|
// Directories: required, then validate existence.
|
|
if len(C.Directories) == 0 {
|
|
return errors.New("You should configure at least one directory to backup!") //nolint: revive
|
|
}
|
|
|
|
for _, dir := range C.Directories {
|
|
if _, err := os.Stat(dir); err != nil {
|
|
return fmt.Errorf("Backup directory does not exist: %s", dir)
|
|
}
|
|
}
|
|
|
|
// BackupTimeout: set default, then validate range.
|
|
if C.BackupTimeout == 0 {
|
|
C.BackupTimeout = defaultBackupTimeout
|
|
|
|
log.Warnf("Config option backup_timeout is not set, fallback to %d minutes", C.BackupTimeout)
|
|
}
|
|
|
|
if C.BackupTimeout < backupTimeoutMin || C.BackupTimeout > backupTimeoutMax {
|
|
return fmt.Errorf("Config option backup_timeout must be between %d and %d minutes, got %d", backupTimeoutMin, backupTimeoutMax, C.BackupTimeout)
|
|
}
|
|
|
|
// CompressionLevel: set default, then validate range.
|
|
if C.CompressionLevel == 0 {
|
|
C.CompressionLevel = defaultCompressionLevel
|
|
|
|
log.Warnf("Config option compression_level is not set, fallback to %d", C.CompressionLevel)
|
|
}
|
|
|
|
if C.CompressionLevel < compressionLevelMin || C.CompressionLevel > compressionLevelMax {
|
|
return fmt.Errorf("Config option compression_level must be between %d and %d, got %d", compressionLevelMin, compressionLevelMax, C.CompressionLevel)
|
|
}
|
|
|
|
// HTTPS: validate cert/key when HTTPS enabled.
|
|
if !C.NoHTTPS {
|
|
switch {
|
|
case C.Cert == "" && C.Key == "":
|
|
return errors.New("Config option nohttps set to false, but neither cert nor key options set")
|
|
case C.Cert == "":
|
|
return errors.New("Config option nohttps set to false, but no cert option set")
|
|
case C.Key == "":
|
|
return errors.New("Config option nohttps set to false, but no key option set")
|
|
}
|
|
}
|
|
|
|
// User: required.
|
|
if C.User == "" {
|
|
return errors.New("Config option user is not set")
|
|
}
|
|
|
|
// Password: required.
|
|
if C.Password == "" {
|
|
return errors.New("Config option password is not set")
|
|
}
|
|
|
|
// FilenamePrefix: default.
|
|
if C.FilenamePrefix == "" {
|
|
C.FilenamePrefix = defaultFilenamePrefix
|
|
|
|
log.Warnf("Config option filename_prefix is not set, fallback to %s", C.FilenamePrefix)
|
|
}
|
|
|
|
// CompressionAlgorithm: default and validate.
|
|
if C.CompressionAlgorithm == "" {
|
|
C.CompressionAlgorithm = defaultCompressionAlgorithm
|
|
|
|
log.Warnf("Config option compression_algorithm is not set, fallback to %s", C.CompressionAlgorithm)
|
|
}
|
|
|
|
if C.CompressionAlgorithm != "gzip" && C.CompressionAlgorithm != "bzip2" && C.CompressionAlgorithm != "zstd" && C.CompressionAlgorithm != "lz4" && C.CompressionAlgorithm != "xz" && C.CompressionAlgorithm != "pgzip" {
|
|
return fmt.Errorf("Config option compression_algorithm must be gzip, bzip2, zstd, lz4, xz or pgzip, got %s", C.CompressionAlgorithm)
|
|
}
|
|
|
|
// Compile exclude patterns.
|
|
excludePatterns = make([]*regexp.Regexp, 0, len(C.ExcludePatterns))
|
|
|
|
for _, pattern := range C.ExcludePatterns {
|
|
re, err := regexp.Compile(pattern)
|
|
if err != nil {
|
|
log.Warnf("Invalid exclude pattern %q: %v", pattern, err)
|
|
|
|
continue
|
|
}
|
|
|
|
excludePatterns = append(excludePatterns, re)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
/* vim: setlocal ft=go noet ai ts=4 sw=4 sts=4: */
|