feat: implement configuration loading from file, env vars and flags

This commit is contained in:
garionion 2025-02-27 17:42:16 +01:00 committed by garionion (aider)
parent 0299e2891c
commit 46cecdc007

102
main.go
View file

@ -5,18 +5,21 @@ import (
"database/sql"
"embed"
"encoding/json"
"flag"
"fmt"
"github.com/num30/config"
"github.com/pressly/goose/v3"
"go.uber.org/zap"
"io"
"net/http"
"os"
"strconv"
"strings"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
_ "github.com/mattn/go-sqlite3"
"golang.org/x/oauth2"
"gopkg.in/yaml.v2"
)
//go:embed static/*
@ -30,7 +33,7 @@ type OAuthConfig struct {
ClientSecret string `config:"client_secret" yaml:"client_secret"`
AuthURL string `config:"auth_url" yaml:"auth_url"`
TokenURL string `config:"token_url" yaml:"token_url"`
UserInfoURL string `config:"userinfo_url" yaml:"userinfo_url"`
UserInfoURL string `config:"user_info_url" yaml:"user_info_url"`
}
type DBConfig struct {
@ -61,34 +64,95 @@ var (
var db *sql.DB
func main() {
// Use the global cfg variable instead of declaring a new one
cfgReader := config.NewConfReader("config").WithSearchDirs("./", ".", "../", "../../")
cfgErr := cfgReader.Read(&cfg)
// Load configuration from YAML file, environment variables, and flags
configFile := flag.String("config", "config.yaml", "Path to config file")
serverPort := flag.Int("port", 0, "Server port (overrides config file)")
oauthClientID := flag.String("oauth-client-id", "", "OAuth Client ID (overrides config file)")
oauthClientSecret := flag.String("oauth-client-secret", "", "OAuth Client Secret (overrides config file)")
oauthAuthURL := flag.String("oauth-auth-url", "", "OAuth Auth URL (overrides config file)")
oauthTokenURL := flag.String("oauth-token-url", "", "OAuth Token URL (overrides config file)")
oauthUserInfoURL := flag.String("oauth-user-info-url", "", "OAuth User Info URL (overrides config file)")
flag.Parse()
// Set default values
cfg = Config{
Env: "dev",
Server: struct {
Port int `config:"port"`
}{Port: 8088},
OAuth: OAuthConfig{},
DB: DBConfig{
Driver: "sqlite3",
DBName: "./inventor.sqlite",
},
}
yamlData, err := os.ReadFile(*configFile)
if err != nil {
fmt.Printf("Warning: Could not read config file: %v\n", err)
} else {
if err := yaml.Unmarshal(yamlData, &cfg); err != nil {
fmt.Printf("Warning: Could not parse config file: %v\n", err)
} else {
fmt.Println("Successfully loaded configuration from", *configFile)
}
}
if envPort := os.Getenv("INVENTOR_SERVER_PORT"); envPort != "" {
if port, err := strconv.Atoi(envPort); err == nil {
cfg.Server.Port = port
}
}
if envClientID := os.Getenv("INVENTOR_OAUTH_CLIENT_ID"); envClientID != "" {
cfg.OAuth.ClientID = envClientID
}
if envClientSecret := os.Getenv("INVENTOR_OAUTH_CLIENT_SECRET"); envClientSecret != "" {
cfg.OAuth.ClientSecret = envClientSecret
}
if envAuthURL := os.Getenv("INVENTOR_OAUTH_AUTH_URL"); envAuthURL != "" {
cfg.OAuth.AuthURL = envAuthURL
}
if envTokenURL := os.Getenv("INVENTOR_OAUTH_TOKEN_URL"); envTokenURL != "" {
cfg.OAuth.TokenURL = envTokenURL
}
if envUserInfoURL := os.Getenv("INVENTOR_OAUTH_USER_INFO_URL"); envUserInfoURL != "" {
cfg.OAuth.UserInfoURL = envUserInfoURL
}
// 3. Override with command line flags (highest priority)
if *serverPort != 0 {
cfg.Server.Port = *serverPort
}
if *oauthClientID != "" {
cfg.OAuth.ClientID = *oauthClientID
}
if *oauthClientSecret != "" {
cfg.OAuth.ClientSecret = *oauthClientSecret
}
if *oauthAuthURL != "" {
cfg.OAuth.AuthURL = *oauthAuthURL
}
if *oauthTokenURL != "" {
cfg.OAuth.TokenURL = *oauthTokenURL
}
if *oauthUserInfoURL != "" {
cfg.OAuth.UserInfoURL = *oauthUserInfoURL
}
zapcfg := zap.NewProductionConfig()
if cfg.Env == "dev" {
zapcfg = zap.NewDevelopmentConfig()
}
logger, err := zapcfg.Build()
logger, err = zapcfg.Build()
if err != nil {
panic(fmt.Sprintf("Failed to initialize logger: %v", err))
}
defer logger.Sync()
if cfgErr != nil {
logger.Fatal("Failed to load config", zap.Error(cfgErr))
}
// Configuration errors are now handled inline during loading
// Print the raw config to see what's actually loaded
logger.Info("Raw config loaded", zap.Any("config", cfg))
// Add detailed logging of the OAuth config
logger.Info("OAuth Configuration",
zap.String("ClientID", cfg.OAuth.ClientID),
zap.String("ClientSecret", cfg.OAuth.ClientSecret),
zap.String("AuthURL", cfg.OAuth.AuthURL),
zap.String("TokenURL", cfg.OAuth.TokenURL),
zap.String("UserInfoURL", cfg.OAuth.UserInfoURL))
logger.Debug("Raw config loaded", zap.Any("config", cfg))
// Initialize OAuth2
oauthConfig = &oauth2.Config{
@ -98,7 +162,7 @@ func main() {
AuthURL: cfg.OAuth.AuthURL,
TokenURL: cfg.OAuth.TokenURL,
},
RedirectURL: fmt.Sprintf("http://localhost:%d/oauth/callback", cfg.Server.Port),
RedirectURL: fmt.Sprintf("http://localhost:3000/oauth/callback"),
Scopes: []string{"profile", "email"},
}