From 7ccbbe2099e2edeb2d47a4a9a4bb9fa3e3b8c8cd Mon Sep 17 00:00:00 2001 From: Amy Gale Ruth Bowersox Date: Tue, 3 Mar 2026 23:12:38 -0700 Subject: [PATCH] added means of locating config files in standard places per operating system --- config/config.go | 48 ++++++++++++++++++++++++++++++++++------- config/fpath_mac.go | 21 ++++++++++++++++++ config/fpath_unix.go | 21 ++++++++++++++++++ config/fpath_windows.go | 23 ++++++++++++++++++++ 4 files changed, 105 insertions(+), 8 deletions(-) create mode 100644 config/fpath_mac.go create mode 100644 config/fpath_unix.go create mode 100644 config/fpath_windows.go diff --git a/config/config.go b/config/config.go index b8787f0..ae13c89 100644 --- a/config/config.go +++ b/config/config.go @@ -14,7 +14,9 @@ import ( _ "embed" "errors" "fmt" + "io" "os" + "path/filepath" "reflect" "regexp" "strconv" @@ -30,6 +32,9 @@ const AMSTERDAM_VERSION = "0.0.1" // AMSTERDAM_COPYRIGHT contains the copyright dates for Amsterdam. const AMSTERDAM_COPYRIGHT = "2025-2026" +// CONFIGFILE_NAME is the name of the standard configuration file. +const CONFIGFILE_NAME = "amsterdam.yaml" + // AmCLI is the command-line interface arguments structure. type AmCLI struct { ConfigFile string `arg:"-C,--config,env:AMSTERDAM_CONFIG" help:"Location of the configuration file."` @@ -126,9 +131,10 @@ type AmConfig struct { } `yaml:"tuning"` } +// AmConfigComputed is the configuration values which are "computed" based only on values in AmConfig. type AmConfigComputed struct { - UploadMaxSize int32 - UploadNoCompress map[string]bool + UploadMaxSize int32 // maximum upload size in bytes + UploadNoCompress map[string]bool // which upload types are not compressed? } //go:embed default.yaml @@ -150,6 +156,28 @@ func init() { } } +// locateConfigFile locates and opens the Amsterdam configuration file, if it exists. +func locateConfigFile() (string, *os.File) { + // first, check the one on the command line (or in the environment) + if CommandLine.ConfigFile != "" { + f, err := os.Open(CommandLine.ConfigFile) + if err == nil { + return CommandLine.ConfigFile, f + } + } + // now, check the OS-specific configuration file directories + dirs := configFileDirs() + for _, d := range dirs { + p := filepath.Join(d, CONFIGFILE_NAME) + f, err := os.Open(p) + if err == nil { + return p, f + } + } + // finally, punt and just use the defaults + return "", nil +} + // overlayStructValue overlays the "loaded" and "defaults" structure onto the "dest" structure. All parameters are AmConfig structures. func overlayStructValue(dest, loaded, defaults reflect.Value) { typ := dest.Type() @@ -211,7 +239,7 @@ func parseDataSize(s string) (int32, error) { } m := re.FindStringSubmatch(s) if m == nil { - return -1, errors.New("invalid value spacified") + return -1, errors.New("invalid value specified") } rc, err := strconv.Atoi(m[1]) if err != nil { @@ -236,18 +264,22 @@ func SetupConfig() { log.Warn("WARNING: --buggy-attachments flag set - NOT recommended for production usage") } - if CommandLine.ConfigFile != "" { - // load the data and use it to unmarshal the loaded configuration - data, err := os.ReadFile(CommandLine.ConfigFile) + // Locate and read the Amsterdam configuration file. + name, file := locateConfigFile() + if file != nil { + log.Infof("SetupConfig(): using config file %s", name) + data, err := io.ReadAll(file) + file.Close() if err != nil { - panic(fmt.Sprintf("unable to load configuration file %s: %v", CommandLine.ConfigFile, err)) + panic(fmt.Sprintf("unable to load configuration file %s: %v", name, err)) } var loadedConfig AmConfig if err = yaml.Unmarshal(data, &loadedConfig); err != nil { - panic(fmt.Sprintf("unable to load configuration file %s: %v", CommandLine.ConfigFile, err)) + panic(fmt.Sprintf("unable to load configuration file %s: %v", name, err)) } overlayStructValue(reflect.ValueOf(&GlobalConfig).Elem(), reflect.ValueOf(&loadedConfig).Elem(), reflect.ValueOf(&defaultConfig).Elem()) } else { + log.Info("SetupConfig(): using default configs only") GlobalConfig = defaultConfig // just copy over the defaults } diff --git a/config/fpath_mac.go b/config/fpath_mac.go new file mode 100644 index 0000000..f17c464 --- /dev/null +++ b/config/fpath_mac.go @@ -0,0 +1,21 @@ +//go:build darwin + +/* + * Amsterdam Web Communities System + * Copyright (c) 2025-2026 Erbosoft Metaverse Design Solutions, All Rights Reserved + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +// Package config contains support for Amsterdam site-wide configuration data. +package config + +// configFileDirs returns the directories where an Amsterdam config file may be located. +func configFileDirs() []string { + // this variant is for Apple macOS + rc := make([]string, 0, 2) + rc = append(rc, "/usr/local/etc/amsterdam", "/Library/Application Support/Amsterdam") + return rc +} diff --git a/config/fpath_unix.go b/config/fpath_unix.go new file mode 100644 index 0000000..1e8f4fa --- /dev/null +++ b/config/fpath_unix.go @@ -0,0 +1,21 @@ +//go:build unix && !darwin + +/* + * Amsterdam Web Communities System + * Copyright (c) 2025-2026 Erbosoft Metaverse Design Solutions, All Rights Reserved + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +// Package config contains support for Amsterdam site-wide configuration data. +package config + +// configFileDirs returns the directories where an Amsterdam config file may be located. +func configFileDirs() []string { + // this variant is for non-macOS Unix systems (Linux, *BSD, etc.) + rc := make([]string, 0, 3) + rc = append(rc, "/usr/local/etc/amsterdam", "/etc/amsterdam", "/etc/xdg/amsterdam") + return rc +} diff --git a/config/fpath_windows.go b/config/fpath_windows.go new file mode 100644 index 0000000..bd352b8 --- /dev/null +++ b/config/fpath_windows.go @@ -0,0 +1,23 @@ +//go:build windows + +/* + * Amsterdam Web Communities System + * Copyright (c) 2025-2026 Erbosoft Metaverse Design Solutions, All Rights Reserved + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +// Package config contains support for Amsterdam site-wide configuration data. +package config + +import "os" + +// configFileDirs returns the directories where an Amsterdam config file may be located. +func configFileDirs() []string { + // this variant is for Micro$oft Windows + rc := make([]string, 0, 1) + rc = append(rc, os.ExpandEnv("${PROGRAMDATA}\\\\amsterdam")) + return rc +}