Add optional config file parser in addition to environment variables
This commit is contained in:
parent
bb720c87c1
commit
f7b7b63e3f
8 changed files with 599 additions and 251 deletions
25
cli/cli.go
25
cli/cli.go
|
@ -24,11 +24,14 @@ const (
|
||||||
flagResetPasswordHelp = "Reset user password"
|
flagResetPasswordHelp = "Reset user password"
|
||||||
flagResetFeedErrorsHelp = "Clear all feed errors for all users"
|
flagResetFeedErrorsHelp = "Clear all feed errors for all users"
|
||||||
flagDebugModeHelp = "Show debug logs"
|
flagDebugModeHelp = "Show debug logs"
|
||||||
|
flagConfigFileHelp = "Load configuration file"
|
||||||
|
flagConfigDumpHelp = "Print parsed configuration values"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Parse parses command line arguments.
|
// Parse parses command line arguments.
|
||||||
func Parse() {
|
func Parse() {
|
||||||
var (
|
var (
|
||||||
|
err error
|
||||||
flagInfo bool
|
flagInfo bool
|
||||||
flagVersion bool
|
flagVersion bool
|
||||||
flagMigrate bool
|
flagMigrate bool
|
||||||
|
@ -37,6 +40,8 @@ func Parse() {
|
||||||
flagResetPassword bool
|
flagResetPassword bool
|
||||||
flagResetFeedErrors bool
|
flagResetFeedErrors bool
|
||||||
flagDebugMode bool
|
flagDebugMode bool
|
||||||
|
flagConfigFile string
|
||||||
|
flagConfigDump bool
|
||||||
)
|
)
|
||||||
|
|
||||||
flag.BoolVar(&flagInfo, "info", false, flagInfoHelp)
|
flag.BoolVar(&flagInfo, "info", false, flagInfoHelp)
|
||||||
|
@ -49,12 +54,30 @@ func Parse() {
|
||||||
flag.BoolVar(&flagResetPassword, "reset-password", false, flagResetPasswordHelp)
|
flag.BoolVar(&flagResetPassword, "reset-password", false, flagResetPasswordHelp)
|
||||||
flag.BoolVar(&flagResetFeedErrors, "reset-feed-errors", false, flagResetFeedErrorsHelp)
|
flag.BoolVar(&flagResetFeedErrors, "reset-feed-errors", false, flagResetFeedErrorsHelp)
|
||||||
flag.BoolVar(&flagDebugMode, "debug", false, flagDebugModeHelp)
|
flag.BoolVar(&flagDebugMode, "debug", false, flagDebugModeHelp)
|
||||||
|
flag.StringVar(&flagConfigFile, "config-file", "", flagConfigFileHelp)
|
||||||
|
flag.StringVar(&flagConfigFile, "c", "", flagConfigFileHelp)
|
||||||
|
flag.BoolVar(&flagConfigDump, "config-dump", false, flagConfigDumpHelp)
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if err := config.ParseConfig(); err != nil {
|
cfg := config.NewParser()
|
||||||
|
|
||||||
|
if flagConfigFile != "" {
|
||||||
|
config.Opts, err = cfg.ParseFile(flagConfigFile)
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatal("%v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config.Opts, err = cfg.ParseEnvironmentVariables()
|
||||||
|
if err != nil {
|
||||||
logger.Fatal("%v", err)
|
logger.Fatal("%v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if flagConfigDump {
|
||||||
|
fmt.Print(config.Opts)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if flagDebugMode || config.Opts.HasDebugMode() {
|
if flagDebugMode || config.Opts.HasDebugMode() {
|
||||||
logger.EnableDebug()
|
logger.EnableDebug()
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,5 @@
|
||||||
|
|
||||||
package config // import "miniflux.app/config"
|
package config // import "miniflux.app/config"
|
||||||
|
|
||||||
// Opts contains configuration options after parsing.
|
// Opts holds parsed configuration options.
|
||||||
var Opts *Options
|
var Opts *Options
|
||||||
|
|
||||||
// ParseConfig parses configuration options.
|
|
||||||
func ParseConfig() (err error) {
|
|
||||||
Opts, err = parse()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
package config // import "miniflux.app/config"
|
package config // import "miniflux.app/config"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
@ -13,9 +14,10 @@ func TestDebugModeOn(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("DEBUG", "1")
|
os.Setenv("DEBUG", "1")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !opts.HasDebugMode() {
|
if !opts.HasDebugMode() {
|
||||||
|
@ -26,9 +28,10 @@ func TestDebugModeOn(t *testing.T) {
|
||||||
func TestDebugModeOff(t *testing.T) {
|
func TestDebugModeOff(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.HasDebugMode() {
|
if opts.HasDebugMode() {
|
||||||
|
@ -40,9 +43,10 @@ func TestCustomBaseURL(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("BASE_URL", "http://example.org")
|
os.Setenv("BASE_URL", "http://example.org")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.BaseURL() != "http://example.org" {
|
if opts.BaseURL() != "http://example.org" {
|
||||||
|
@ -62,9 +66,10 @@ func TestCustomBaseURLWithTrailingSlash(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("BASE_URL", "http://example.org/folder/")
|
os.Setenv("BASE_URL", "http://example.org/folder/")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.BaseURL() != "http://example.org/folder" {
|
if opts.BaseURL() != "http://example.org/folder" {
|
||||||
|
@ -84,7 +89,7 @@ func TestBaseURLWithoutScheme(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("BASE_URL", "example.org/folder/")
|
os.Setenv("BASE_URL", "example.org/folder/")
|
||||||
|
|
||||||
_, err := parse()
|
_, err := NewParser().ParseEnvironmentVariables()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf(`Parsing must fail`)
|
t.Fatalf(`Parsing must fail`)
|
||||||
}
|
}
|
||||||
|
@ -94,7 +99,7 @@ func TestBaseURLWithInvalidScheme(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("BASE_URL", "ftp://example.org/folder/")
|
os.Setenv("BASE_URL", "ftp://example.org/folder/")
|
||||||
|
|
||||||
_, err := parse()
|
_, err := NewParser().ParseEnvironmentVariables()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf(`Parsing must fail`)
|
t.Fatalf(`Parsing must fail`)
|
||||||
}
|
}
|
||||||
|
@ -104,7 +109,7 @@ func TestInvalidBaseURL(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("BASE_URL", "http://example|org")
|
os.Setenv("BASE_URL", "http://example|org")
|
||||||
|
|
||||||
_, err := parse()
|
_, err := NewParser().ParseEnvironmentVariables()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf(`Parsing must fail`)
|
t.Fatalf(`Parsing must fail`)
|
||||||
}
|
}
|
||||||
|
@ -113,9 +118,10 @@ func TestInvalidBaseURL(t *testing.T) {
|
||||||
func TestDefaultBaseURL(t *testing.T) {
|
func TestDefaultBaseURL(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.BaseURL() != defaultBaseURL {
|
if opts.BaseURL() != defaultBaseURL {
|
||||||
|
@ -135,41 +141,52 @@ func TestDatabaseURL(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("DATABASE_URL", "foobar")
|
os.Setenv("DATABASE_URL", "foobar")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "foobar"
|
expected := "foobar"
|
||||||
result := opts.DatabaseURL()
|
result := opts.DatabaseURL()
|
||||||
|
|
||||||
if result != expected {
|
if result != expected {
|
||||||
t.Fatalf(`Unexpected DATABASE_URL value, got %q instead of %q`, result, expected)
|
t.Errorf(`Unexpected DATABASE_URL value, got %q instead of %q`, result, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.IsDefaultDatabaseURL() {
|
||||||
|
t.Errorf(`This is not the default database URL and it should returns false`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDefaultDatabaseURLValue(t *testing.T) {
|
func TestDefaultDatabaseURLValue(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := defaultDatabaseURL
|
expected := defaultDatabaseURL
|
||||||
result := opts.DatabaseURL()
|
result := opts.DatabaseURL()
|
||||||
|
|
||||||
if result != expected {
|
if result != expected {
|
||||||
t.Fatalf(`Unexpected DATABASE_URL value, got %q instead of %q`, result, expected)
|
t.Errorf(`Unexpected DATABASE_URL value, got %q instead of %q`, result, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !opts.IsDefaultDatabaseURL() {
|
||||||
|
t.Errorf(`This is the default database URL and it should returns true`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDefaultDatabaseMaxConnsValue(t *testing.T) {
|
func TestDefaultDatabaseMaxConnsValue(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := defaultDatabaseMaxConns
|
expected := defaultDatabaseMaxConns
|
||||||
|
@ -184,9 +201,10 @@ func TestDatabaseMaxConns(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("DATABASE_MAX_CONNS", "42")
|
os.Setenv("DATABASE_MAX_CONNS", "42")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := 42
|
expected := 42
|
||||||
|
@ -200,9 +218,10 @@ func TestDatabaseMaxConns(t *testing.T) {
|
||||||
func TestDefaultDatabaseMinConnsValue(t *testing.T) {
|
func TestDefaultDatabaseMinConnsValue(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := defaultDatabaseMinConns
|
expected := defaultDatabaseMinConns
|
||||||
|
@ -217,9 +236,10 @@ func TestDatabaseMinConns(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("DATABASE_MIN_CONNS", "42")
|
os.Setenv("DATABASE_MIN_CONNS", "42")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := 42
|
expected := 42
|
||||||
|
@ -234,9 +254,10 @@ func TestListenAddr(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("LISTEN_ADDR", "foobar")
|
os.Setenv("LISTEN_ADDR", "foobar")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "foobar"
|
expected := "foobar"
|
||||||
|
@ -252,9 +273,10 @@ func TestListenAddrWithPortDefined(t *testing.T) {
|
||||||
os.Setenv("PORT", "3000")
|
os.Setenv("PORT", "3000")
|
||||||
os.Setenv("LISTEN_ADDR", "foobar")
|
os.Setenv("LISTEN_ADDR", "foobar")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := ":3000"
|
expected := ":3000"
|
||||||
|
@ -268,9 +290,10 @@ func TestListenAddrWithPortDefined(t *testing.T) {
|
||||||
func TestDefaultListenAddrValue(t *testing.T) {
|
func TestDefaultListenAddrValue(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := defaultListenAddr
|
expected := defaultListenAddr
|
||||||
|
@ -285,9 +308,10 @@ func TestCertFile(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("CERT_FILE", "foobar")
|
os.Setenv("CERT_FILE", "foobar")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "foobar"
|
expected := "foobar"
|
||||||
|
@ -301,9 +325,10 @@ func TestCertFile(t *testing.T) {
|
||||||
func TestDefaultCertFileValue(t *testing.T) {
|
func TestDefaultCertFileValue(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := defaultCertFile
|
expected := defaultCertFile
|
||||||
|
@ -318,9 +343,10 @@ func TestKeyFile(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("KEY_FILE", "foobar")
|
os.Setenv("KEY_FILE", "foobar")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "foobar"
|
expected := "foobar"
|
||||||
|
@ -334,9 +360,10 @@ func TestKeyFile(t *testing.T) {
|
||||||
func TestDefaultKeyFileValue(t *testing.T) {
|
func TestDefaultKeyFileValue(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := defaultKeyFile
|
expected := defaultKeyFile
|
||||||
|
@ -351,9 +378,10 @@ func TestCertDomain(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("CERT_DOMAIN", "example.org")
|
os.Setenv("CERT_DOMAIN", "example.org")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "example.org"
|
expected := "example.org"
|
||||||
|
@ -367,9 +395,10 @@ func TestCertDomain(t *testing.T) {
|
||||||
func TestDefaultCertDomainValue(t *testing.T) {
|
func TestDefaultCertDomainValue(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := defaultCertDomain
|
expected := defaultCertDomain
|
||||||
|
@ -384,9 +413,10 @@ func TestCertCache(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("CERT_CACHE", "foobar")
|
os.Setenv("CERT_CACHE", "foobar")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "foobar"
|
expected := "foobar"
|
||||||
|
@ -400,9 +430,10 @@ func TestCertCache(t *testing.T) {
|
||||||
func TestDefaultCertCacheValue(t *testing.T) {
|
func TestDefaultCertCacheValue(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := defaultCertCache
|
expected := defaultCertCache
|
||||||
|
@ -416,9 +447,10 @@ func TestDefaultCertCacheValue(t *testing.T) {
|
||||||
func TestDefaultCleanupFrequencyValue(t *testing.T) {
|
func TestDefaultCleanupFrequencyValue(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := defaultCleanupFrequency
|
expected := defaultCleanupFrequency
|
||||||
|
@ -433,9 +465,10 @@ func TestCleanupFrequency(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("CLEANUP_FREQUENCY", "42")
|
os.Setenv("CLEANUP_FREQUENCY", "42")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := 42
|
expected := 42
|
||||||
|
@ -449,9 +482,10 @@ func TestCleanupFrequency(t *testing.T) {
|
||||||
func TestDefaultWorkerPoolSizeValue(t *testing.T) {
|
func TestDefaultWorkerPoolSizeValue(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := defaultWorkerPoolSize
|
expected := defaultWorkerPoolSize
|
||||||
|
@ -466,9 +500,10 @@ func TestWorkerPoolSize(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("WORKER_POOL_SIZE", "42")
|
os.Setenv("WORKER_POOL_SIZE", "42")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := 42
|
expected := 42
|
||||||
|
@ -482,9 +517,10 @@ func TestWorkerPoolSize(t *testing.T) {
|
||||||
func TestDefautPollingFrequencyValue(t *testing.T) {
|
func TestDefautPollingFrequencyValue(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := defaultPollingFrequency
|
expected := defaultPollingFrequency
|
||||||
|
@ -499,9 +535,10 @@ func TestPollingFrequency(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("POLLING_FREQUENCY", "42")
|
os.Setenv("POLLING_FREQUENCY", "42")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := 42
|
expected := 42
|
||||||
|
@ -515,9 +552,10 @@ func TestPollingFrequency(t *testing.T) {
|
||||||
func TestDefaultBatchSizeValue(t *testing.T) {
|
func TestDefaultBatchSizeValue(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := defaultBatchSize
|
expected := defaultBatchSize
|
||||||
|
@ -532,9 +570,10 @@ func TestBatchSize(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("BATCH_SIZE", "42")
|
os.Setenv("BATCH_SIZE", "42")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := 42
|
expected := 42
|
||||||
|
@ -548,9 +587,10 @@ func TestBatchSize(t *testing.T) {
|
||||||
func TestOAuth2UserCreationWhenUnset(t *testing.T) {
|
func TestOAuth2UserCreationWhenUnset(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := false
|
expected := false
|
||||||
|
@ -565,9 +605,10 @@ func TestOAuth2UserCreationAdmin(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("OAUTH2_USER_CREATION", "1")
|
os.Setenv("OAUTH2_USER_CREATION", "1")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := true
|
expected := true
|
||||||
|
@ -582,9 +623,10 @@ func TestOAuth2ClientID(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("OAUTH2_CLIENT_ID", "foobar")
|
os.Setenv("OAUTH2_CLIENT_ID", "foobar")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "foobar"
|
expected := "foobar"
|
||||||
|
@ -598,9 +640,10 @@ func TestOAuth2ClientID(t *testing.T) {
|
||||||
func TestDefaultOAuth2ClientIDValue(t *testing.T) {
|
func TestDefaultOAuth2ClientIDValue(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := defaultOAuth2ClientID
|
expected := defaultOAuth2ClientID
|
||||||
|
@ -615,9 +658,10 @@ func TestOAuth2ClientSecret(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("OAUTH2_CLIENT_SECRET", "secret")
|
os.Setenv("OAUTH2_CLIENT_SECRET", "secret")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "secret"
|
expected := "secret"
|
||||||
|
@ -631,9 +675,10 @@ func TestOAuth2ClientSecret(t *testing.T) {
|
||||||
func TestDefaultOAuth2ClientSecretValue(t *testing.T) {
|
func TestDefaultOAuth2ClientSecretValue(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := defaultOAuth2ClientSecret
|
expected := defaultOAuth2ClientSecret
|
||||||
|
@ -648,9 +693,10 @@ func TestOAuth2RedirectURL(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("OAUTH2_REDIRECT_URL", "http://example.org")
|
os.Setenv("OAUTH2_REDIRECT_URL", "http://example.org")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "http://example.org"
|
expected := "http://example.org"
|
||||||
|
@ -664,9 +710,10 @@ func TestOAuth2RedirectURL(t *testing.T) {
|
||||||
func TestDefaultOAuth2RedirectURLValue(t *testing.T) {
|
func TestDefaultOAuth2RedirectURLValue(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := defaultOAuth2RedirectURL
|
expected := defaultOAuth2RedirectURL
|
||||||
|
@ -681,9 +728,10 @@ func TestOAuth2Provider(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("OAUTH2_PROVIDER", "google")
|
os.Setenv("OAUTH2_PROVIDER", "google")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "google"
|
expected := "google"
|
||||||
|
@ -697,9 +745,10 @@ func TestOAuth2Provider(t *testing.T) {
|
||||||
func TestDefaultOAuth2ProviderValue(t *testing.T) {
|
func TestDefaultOAuth2ProviderValue(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := defaultOAuth2Provider
|
expected := defaultOAuth2Provider
|
||||||
|
@ -713,9 +762,10 @@ func TestDefaultOAuth2ProviderValue(t *testing.T) {
|
||||||
func TestHSTSWhenUnset(t *testing.T) {
|
func TestHSTSWhenUnset(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := true
|
expected := true
|
||||||
|
@ -730,9 +780,10 @@ func TestHSTS(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("DISABLE_HSTS", "1")
|
os.Setenv("DISABLE_HSTS", "1")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := false
|
expected := false
|
||||||
|
@ -746,9 +797,10 @@ func TestHSTS(t *testing.T) {
|
||||||
func TestDisableHTTPServiceWhenUnset(t *testing.T) {
|
func TestDisableHTTPServiceWhenUnset(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := true
|
expected := true
|
||||||
|
@ -763,9 +815,10 @@ func TestDisableHTTPService(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("DISABLE_HTTP_SERVICE", "1")
|
os.Setenv("DISABLE_HTTP_SERVICE", "1")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := false
|
expected := false
|
||||||
|
@ -779,9 +832,10 @@ func TestDisableHTTPService(t *testing.T) {
|
||||||
func TestDisableSchedulerServiceWhenUnset(t *testing.T) {
|
func TestDisableSchedulerServiceWhenUnset(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := true
|
expected := true
|
||||||
|
@ -796,9 +850,10 @@ func TestDisableSchedulerService(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("DISABLE_SCHEDULER_SERVICE", "1")
|
os.Setenv("DISABLE_SCHEDULER_SERVICE", "1")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := false
|
expected := false
|
||||||
|
@ -813,9 +868,10 @@ func TestArchiveReadDays(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("ARCHIVE_READ_DAYS", "7")
|
os.Setenv("ARCHIVE_READ_DAYS", "7")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := 7
|
expected := 7
|
||||||
|
@ -829,9 +885,10 @@ func TestArchiveReadDays(t *testing.T) {
|
||||||
func TestRunMigrationsWhenUnset(t *testing.T) {
|
func TestRunMigrationsWhenUnset(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := false
|
expected := false
|
||||||
|
@ -846,9 +903,10 @@ func TestRunMigrations(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("RUN_MIGRATIONS", "yes")
|
os.Setenv("RUN_MIGRATIONS", "yes")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := true
|
expected := true
|
||||||
|
@ -862,9 +920,10 @@ func TestRunMigrations(t *testing.T) {
|
||||||
func TestCreateAdminWhenUnset(t *testing.T) {
|
func TestCreateAdminWhenUnset(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := false
|
expected := false
|
||||||
|
@ -879,9 +938,10 @@ func TestCreateAdmin(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("CREATE_ADMIN", "true")
|
os.Setenv("CREATE_ADMIN", "true")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := true
|
expected := true
|
||||||
|
@ -896,9 +956,10 @@ func TestPocketConsumerKeyFromEnvVariable(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("POCKET_CONSUMER_KEY", "something")
|
os.Setenv("POCKET_CONSUMER_KEY", "something")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "something"
|
expected := "something"
|
||||||
|
@ -912,9 +973,10 @@ func TestPocketConsumerKeyFromEnvVariable(t *testing.T) {
|
||||||
func TestPocketConsumerKeyFromUserPrefs(t *testing.T) {
|
func TestPocketConsumerKeyFromUserPrefs(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "default"
|
expected := "default"
|
||||||
|
@ -929,9 +991,10 @@ func TestProxyImages(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("PROXY_IMAGES", "all")
|
os.Setenv("PROXY_IMAGES", "all")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "all"
|
expected := "all"
|
||||||
|
@ -945,9 +1008,10 @@ func TestProxyImages(t *testing.T) {
|
||||||
func TestDefaultProxyImagesValue(t *testing.T) {
|
func TestDefaultProxyImagesValue(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := defaultProxyImages
|
expected := defaultProxyImages
|
||||||
|
@ -961,9 +1025,10 @@ func TestDefaultProxyImagesValue(t *testing.T) {
|
||||||
func TestHTTPSOff(t *testing.T) {
|
func TestHTTPSOff(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.HTTPS {
|
if opts.HTTPS {
|
||||||
|
@ -975,9 +1040,10 @@ func TestHTTPSOn(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("HTTPS", "on")
|
os.Setenv("HTTPS", "on")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !opts.HTTPS {
|
if !opts.HTTPS {
|
||||||
|
@ -989,9 +1055,10 @@ func TestHTTPClientTimeout(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("HTTP_CLIENT_TIMEOUT", "42")
|
os.Setenv("HTTP_CLIENT_TIMEOUT", "42")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := 42
|
expected := 42
|
||||||
|
@ -1005,9 +1072,10 @@ func TestHTTPClientTimeout(t *testing.T) {
|
||||||
func TestDefaultHTTPClientTimeoutValue(t *testing.T) {
|
func TestDefaultHTTPClientTimeoutValue(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := defaultHTTPClientTimeout
|
expected := defaultHTTPClientTimeout
|
||||||
|
@ -1022,9 +1090,10 @@ func TestHTTPClientMaxBodySize(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("HTTP_CLIENT_MAX_BODY_SIZE", "42")
|
os.Setenv("HTTP_CLIENT_MAX_BODY_SIZE", "42")
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := int64(42 * 1024 * 1024)
|
expected := int64(42 * 1024 * 1024)
|
||||||
|
@ -1038,9 +1107,10 @@ func TestHTTPClientMaxBodySize(t *testing.T) {
|
||||||
func TestDefaultHTTPClientMaxBodySizeValue(t *testing.T) {
|
func TestDefaultHTTPClientMaxBodySizeValue(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|
||||||
opts, err := parse()
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseEnvironmentVariables()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`Parsing failure: %q`, err)
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := int64(defaultHTTPClientMaxBodySize * 1024 * 1024)
|
expected := int64(defaultHTTPClientMaxBodySize * 1024 * 1024)
|
||||||
|
@ -1050,3 +1120,50 @@ func TestDefaultHTTPClientMaxBodySizeValue(t *testing.T) {
|
||||||
t.Fatalf(`Unexpected HTTP_CLIENT_MAX_BODY_SIZE value, got %d instead of %d`, result, expected)
|
t.Fatalf(`Unexpected HTTP_CLIENT_MAX_BODY_SIZE value, got %d instead of %d`, result, expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseConfigFile(t *testing.T) {
|
||||||
|
content := []byte(`
|
||||||
|
# This is a comment
|
||||||
|
|
||||||
|
DEBUG = yes
|
||||||
|
|
||||||
|
POCKET_CONSUMER_KEY= >#1234
|
||||||
|
|
||||||
|
Invalid text
|
||||||
|
`)
|
||||||
|
|
||||||
|
tmpfile, err := ioutil.TempFile(".", "miniflux.*.unit_test.conf")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := tmpfile.Write(content); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Clearenv()
|
||||||
|
|
||||||
|
parser := NewParser()
|
||||||
|
opts, err := parser.ParseFile(tmpfile.Name())
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf(`Parsing failure: %v`, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.HasDebugMode() != true {
|
||||||
|
t.Errorf(`Unexpected debug mode value, got "%v"`, opts.HasDebugMode())
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := ">#1234"
|
||||||
|
result := opts.PocketConsumerKey("default")
|
||||||
|
if result != expected {
|
||||||
|
t.Errorf(`Unexpected POCKET_CONSUMER_KEY value, got %q instead of %q`, result, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tmpfile.Close(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.Remove(tmpfile.Name()); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,11 +4,24 @@
|
||||||
|
|
||||||
package config // import "miniflux.app/config"
|
package config // import "miniflux.app/config"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
defaultHTTPS = false
|
||||||
|
defaultHSTS = true
|
||||||
|
defaultHTTPService = true
|
||||||
|
defaultSchedulerService = true
|
||||||
|
defaultDebug = false
|
||||||
defaultBaseURL = "http://localhost"
|
defaultBaseURL = "http://localhost"
|
||||||
|
defaultRootURL = "http://localhost"
|
||||||
|
defaultBasePath = ""
|
||||||
defaultWorkerPoolSize = 5
|
defaultWorkerPoolSize = 5
|
||||||
defaultPollingFrequency = 60
|
defaultPollingFrequency = 60
|
||||||
defaultBatchSize = 10
|
defaultBatchSize = 10
|
||||||
|
defaultRunMigrations = false
|
||||||
defaultDatabaseURL = "user=postgres password=postgres dbname=miniflux2 sslmode=disable"
|
defaultDatabaseURL = "user=postgres password=postgres dbname=miniflux2 sslmode=disable"
|
||||||
defaultDatabaseMaxConns = 20
|
defaultDatabaseMaxConns = 20
|
||||||
defaultDatabaseMinConns = 1
|
defaultDatabaseMinConns = 1
|
||||||
|
@ -20,10 +33,13 @@ const (
|
||||||
defaultCertCache = "/tmp/cert_cache"
|
defaultCertCache = "/tmp/cert_cache"
|
||||||
defaultCleanupFrequency = 24
|
defaultCleanupFrequency = 24
|
||||||
defaultProxyImages = "http-only"
|
defaultProxyImages = "http-only"
|
||||||
|
defaultCreateAdmin = false
|
||||||
|
defaultOAuth2UserCreation = false
|
||||||
defaultOAuth2ClientID = ""
|
defaultOAuth2ClientID = ""
|
||||||
defaultOAuth2ClientSecret = ""
|
defaultOAuth2ClientSecret = ""
|
||||||
defaultOAuth2RedirectURL = ""
|
defaultOAuth2RedirectURL = ""
|
||||||
defaultOAuth2Provider = ""
|
defaultOAuth2Provider = ""
|
||||||
|
defaultPocketConsumerKey = ""
|
||||||
defaultHTTPClientTimeout = 20
|
defaultHTTPClientTimeout = 20
|
||||||
defaultHTTPClientMaxBodySize = 15
|
defaultHTTPClientMaxBodySize = 15
|
||||||
)
|
)
|
||||||
|
@ -64,6 +80,44 @@ type Options struct {
|
||||||
httpClientMaxBodySize int64
|
httpClientMaxBodySize int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewOptions returns Options with default values.
|
||||||
|
func NewOptions() *Options {
|
||||||
|
return &Options{
|
||||||
|
HTTPS: defaultHTTPS,
|
||||||
|
hsts: defaultHSTS,
|
||||||
|
httpService: defaultHTTPService,
|
||||||
|
schedulerService: defaultSchedulerService,
|
||||||
|
debug: defaultDebug,
|
||||||
|
baseURL: defaultBaseURL,
|
||||||
|
rootURL: defaultRootURL,
|
||||||
|
basePath: defaultBasePath,
|
||||||
|
databaseURL: defaultDatabaseURL,
|
||||||
|
databaseMaxConns: defaultDatabaseMaxConns,
|
||||||
|
databaseMinConns: defaultDatabaseMinConns,
|
||||||
|
runMigrations: defaultRunMigrations,
|
||||||
|
listenAddr: defaultListenAddr,
|
||||||
|
certFile: defaultCertFile,
|
||||||
|
certDomain: defaultCertDomain,
|
||||||
|
certCache: defaultCertCache,
|
||||||
|
certKeyFile: defaultKeyFile,
|
||||||
|
cleanupFrequency: defaultCleanupFrequency,
|
||||||
|
archiveReadDays: defaultArchiveReadDays,
|
||||||
|
pollingFrequency: defaultPollingFrequency,
|
||||||
|
batchSize: defaultBatchSize,
|
||||||
|
workerPoolSize: defaultWorkerPoolSize,
|
||||||
|
createAdmin: defaultCreateAdmin,
|
||||||
|
proxyImages: defaultProxyImages,
|
||||||
|
oauth2UserCreationAllowed: defaultOAuth2UserCreation,
|
||||||
|
oauth2ClientID: defaultOAuth2ClientID,
|
||||||
|
oauth2ClientSecret: defaultOAuth2ClientSecret,
|
||||||
|
oauth2RedirectURL: defaultOAuth2RedirectURL,
|
||||||
|
oauth2Provider: defaultOAuth2Provider,
|
||||||
|
pocketConsumerKey: defaultPocketConsumerKey,
|
||||||
|
httpClientTimeout: defaultHTTPClientTimeout,
|
||||||
|
httpClientMaxBodySize: defaultHTTPClientMaxBodySize * 1024 * 1024,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// HasDebugMode returns true if debug mode is enabled.
|
// HasDebugMode returns true if debug mode is enabled.
|
||||||
func (o *Options) HasDebugMode() bool {
|
func (o *Options) HasDebugMode() bool {
|
||||||
return o.debug
|
return o.debug
|
||||||
|
@ -226,3 +280,40 @@ func (o *Options) HTTPClientTimeout() int {
|
||||||
func (o *Options) HTTPClientMaxBodySize() int64 {
|
func (o *Options) HTTPClientMaxBodySize() int64 {
|
||||||
return o.httpClientMaxBodySize
|
return o.httpClientMaxBodySize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *Options) String() string {
|
||||||
|
var builder strings.Builder
|
||||||
|
builder.WriteString(fmt.Sprintf("DEBUG: %v\n", o.debug))
|
||||||
|
builder.WriteString(fmt.Sprintf("HTTP_SERVICE: %v\n", o.httpService))
|
||||||
|
builder.WriteString(fmt.Sprintf("SCHEDULER_SERVICE: %v\n", o.schedulerService))
|
||||||
|
builder.WriteString(fmt.Sprintf("HTTPS: %v\n", o.HTTPS))
|
||||||
|
builder.WriteString(fmt.Sprintf("HSTS: %v\n", o.hsts))
|
||||||
|
builder.WriteString(fmt.Sprintf("BASE_URL: %v\n", o.baseURL))
|
||||||
|
builder.WriteString(fmt.Sprintf("ROOT_URL: %v\n", o.rootURL))
|
||||||
|
builder.WriteString(fmt.Sprintf("BASE_PATH: %v\n", o.basePath))
|
||||||
|
builder.WriteString(fmt.Sprintf("LISTEN_ADDR: %v\n", o.listenAddr))
|
||||||
|
builder.WriteString(fmt.Sprintf("DATABASE_URL: %v\n", o.databaseURL))
|
||||||
|
builder.WriteString(fmt.Sprintf("DATABASE_MAX_CONNS: %v\n", o.databaseMaxConns))
|
||||||
|
builder.WriteString(fmt.Sprintf("DATABASE_MIN_CONNS: %v\n", o.databaseMinConns))
|
||||||
|
builder.WriteString(fmt.Sprintf("RUN_MIGRATIONS: %v\n", o.runMigrations))
|
||||||
|
builder.WriteString(fmt.Sprintf("CERT_FILE: %v\n", o.certFile))
|
||||||
|
builder.WriteString(fmt.Sprintf("KEY_FILE: %v\n", o.certKeyFile))
|
||||||
|
builder.WriteString(fmt.Sprintf("CERT_DOMAIN: %v\n", o.certDomain))
|
||||||
|
builder.WriteString(fmt.Sprintf("CERT_CACHE: %v\n", o.certCache))
|
||||||
|
builder.WriteString(fmt.Sprintf("CLEANUP_FREQUENCY: %v\n", o.cleanupFrequency))
|
||||||
|
builder.WriteString(fmt.Sprintf("WORKER_POOL_SIZE: %v\n", o.workerPoolSize))
|
||||||
|
builder.WriteString(fmt.Sprintf("POLLING_FREQUENCY: %v\n", o.pollingFrequency))
|
||||||
|
builder.WriteString(fmt.Sprintf("BATCH_SIZE: %v\n", o.batchSize))
|
||||||
|
builder.WriteString(fmt.Sprintf("ARCHIVE_READ_DAYS: %v\n", o.archiveReadDays))
|
||||||
|
builder.WriteString(fmt.Sprintf("PROXY_IMAGES: %v\n", o.proxyImages))
|
||||||
|
builder.WriteString(fmt.Sprintf("CREATE_ADMIN: %v\n", o.createAdmin))
|
||||||
|
builder.WriteString(fmt.Sprintf("POCKET_CONSUMER_KEY: %v\n", o.pocketConsumerKey))
|
||||||
|
builder.WriteString(fmt.Sprintf("OAUTH2_USER_CREATION: %v\n", o.oauth2UserCreationAllowed))
|
||||||
|
builder.WriteString(fmt.Sprintf("OAUTH2_CLIENT_ID: %v\n", o.oauth2ClientID))
|
||||||
|
builder.WriteString(fmt.Sprintf("OAUTH2_CLIENT_SECRET: %v\n", o.oauth2ClientSecret))
|
||||||
|
builder.WriteString(fmt.Sprintf("OAUTH2_REDIRECT_URL: %v\n", o.oauth2RedirectURL))
|
||||||
|
builder.WriteString(fmt.Sprintf("OAUTH2_PROVIDER: %v\n", o.oauth2Provider))
|
||||||
|
builder.WriteString(fmt.Sprintf("HTTP_CLIENT_TIMEOUT: %v\n", o.httpClientTimeout))
|
||||||
|
builder.WriteString(fmt.Sprintf("HTTP_CLIENT_MAX_BODY_SIZE: %v\n", o.httpClientMaxBodySize))
|
||||||
|
return builder.String()
|
||||||
|
}
|
||||||
|
|
228
config/parser.go
228
config/parser.go
|
@ -5,113 +5,184 @@
|
||||||
package config // import "miniflux.app/config"
|
package config // import "miniflux.app/config"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"io"
|
||||||
|
url_parser "net/url"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func parse() (opts *Options, err error) {
|
// Parser handles configuration parsing.
|
||||||
opts = &Options{}
|
type Parser struct {
|
||||||
opts.baseURL, opts.rootURL, opts.basePath, err = parseBaseURL()
|
opts *Options
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewParser returns a new Parser.
|
||||||
|
func NewParser() *Parser {
|
||||||
|
return &Parser{
|
||||||
|
opts: NewOptions(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseEnvironmentVariables loads configuration values from environment variables.
|
||||||
|
func (p *Parser) ParseEnvironmentVariables() (*Options, error) {
|
||||||
|
err := p.parseLines(os.Environ())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return p.opts, nil
|
||||||
opts.debug = getBooleanValue("DEBUG")
|
|
||||||
opts.listenAddr = parseListenAddr()
|
|
||||||
|
|
||||||
opts.databaseURL = getStringValue("DATABASE_URL", defaultDatabaseURL)
|
|
||||||
opts.databaseMaxConns = getIntValue("DATABASE_MAX_CONNS", defaultDatabaseMaxConns)
|
|
||||||
opts.databaseMinConns = getIntValue("DATABASE_MIN_CONNS", defaultDatabaseMinConns)
|
|
||||||
opts.runMigrations = getBooleanValue("RUN_MIGRATIONS")
|
|
||||||
|
|
||||||
opts.hsts = !getBooleanValue("DISABLE_HSTS")
|
|
||||||
opts.HTTPS = getBooleanValue("HTTPS")
|
|
||||||
|
|
||||||
opts.schedulerService = !getBooleanValue("DISABLE_SCHEDULER_SERVICE")
|
|
||||||
opts.httpService = !getBooleanValue("DISABLE_HTTP_SERVICE")
|
|
||||||
|
|
||||||
opts.certFile = getStringValue("CERT_FILE", defaultCertFile)
|
|
||||||
opts.certKeyFile = getStringValue("KEY_FILE", defaultKeyFile)
|
|
||||||
opts.certDomain = getStringValue("CERT_DOMAIN", defaultCertDomain)
|
|
||||||
opts.certCache = getStringValue("CERT_CACHE", defaultCertCache)
|
|
||||||
|
|
||||||
opts.cleanupFrequency = getIntValue("CLEANUP_FREQUENCY", defaultCleanupFrequency)
|
|
||||||
opts.workerPoolSize = getIntValue("WORKER_POOL_SIZE", defaultWorkerPoolSize)
|
|
||||||
opts.pollingFrequency = getIntValue("POLLING_FREQUENCY", defaultPollingFrequency)
|
|
||||||
opts.batchSize = getIntValue("BATCH_SIZE", defaultBatchSize)
|
|
||||||
opts.archiveReadDays = getIntValue("ARCHIVE_READ_DAYS", defaultArchiveReadDays)
|
|
||||||
opts.proxyImages = getStringValue("PROXY_IMAGES", defaultProxyImages)
|
|
||||||
opts.createAdmin = getBooleanValue("CREATE_ADMIN")
|
|
||||||
opts.pocketConsumerKey = getStringValue("POCKET_CONSUMER_KEY", "")
|
|
||||||
|
|
||||||
opts.oauth2UserCreationAllowed = getBooleanValue("OAUTH2_USER_CREATION")
|
|
||||||
opts.oauth2ClientID = getStringValue("OAUTH2_CLIENT_ID", defaultOAuth2ClientID)
|
|
||||||
opts.oauth2ClientSecret = getStringValue("OAUTH2_CLIENT_SECRET", defaultOAuth2ClientSecret)
|
|
||||||
opts.oauth2RedirectURL = getStringValue("OAUTH2_REDIRECT_URL", defaultOAuth2RedirectURL)
|
|
||||||
opts.oauth2Provider = getStringValue("OAUTH2_PROVIDER", defaultOAuth2Provider)
|
|
||||||
|
|
||||||
opts.httpClientTimeout = getIntValue("HTTP_CLIENT_TIMEOUT", defaultHTTPClientTimeout)
|
|
||||||
opts.httpClientMaxBodySize = int64(getIntValue("HTTP_CLIENT_MAX_BODY_SIZE", defaultHTTPClientMaxBodySize) * 1024 * 1024)
|
|
||||||
|
|
||||||
return opts, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseBaseURL() (string, string, string, error) {
|
// ParseFile loads configuration values from a local file.
|
||||||
baseURL := os.Getenv("BASE_URL")
|
func (p *Parser) ParseFile(filename string) (*Options, error) {
|
||||||
if baseURL == "" {
|
fp, err := os.Open(filename)
|
||||||
return defaultBaseURL, defaultBaseURL, "", nil
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer fp.Close()
|
||||||
|
|
||||||
|
err = p.parseLines(p.parseFileContent(fp))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return p.opts, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) parseFileContent(r io.Reader) (lines []string) {
|
||||||
|
scanner := bufio.NewScanner(r)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := strings.TrimSpace(scanner.Text())
|
||||||
|
if len(line) > 0 && !strings.HasPrefix(line, "#") && strings.Index(line, "=") > 0 {
|
||||||
|
lines = append(lines, line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) parseLines(lines []string) (err error) {
|
||||||
|
var port string
|
||||||
|
|
||||||
|
for _, line := range lines {
|
||||||
|
fields := strings.SplitN(line, "=", 2)
|
||||||
|
key := strings.TrimSpace(fields[0])
|
||||||
|
value := strings.TrimSpace(fields[1])
|
||||||
|
|
||||||
|
switch key {
|
||||||
|
case "DEBUG":
|
||||||
|
p.opts.debug = parseBool(value, defaultDebug)
|
||||||
|
case "BASE_URL":
|
||||||
|
p.opts.baseURL, p.opts.rootURL, p.opts.basePath, err = parseBaseURL(value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case "PORT":
|
||||||
|
port = value
|
||||||
|
case "LISTEN_ADDR":
|
||||||
|
p.opts.listenAddr = parseString(value, defaultListenAddr)
|
||||||
|
case "DATABASE_URL":
|
||||||
|
p.opts.databaseURL = parseString(value, defaultDatabaseURL)
|
||||||
|
case "DATABASE_MAX_CONNS":
|
||||||
|
p.opts.databaseMaxConns = parseInt(value, defaultDatabaseMaxConns)
|
||||||
|
case "DATABASE_MIN_CONNS":
|
||||||
|
p.opts.databaseMinConns = parseInt(value, defaultDatabaseMinConns)
|
||||||
|
case "RUN_MIGRATIONS":
|
||||||
|
p.opts.runMigrations = parseBool(value, defaultRunMigrations)
|
||||||
|
case "DISABLE_HSTS":
|
||||||
|
p.opts.hsts = !parseBool(value, defaultHSTS)
|
||||||
|
case "HTTPS":
|
||||||
|
p.opts.HTTPS = parseBool(value, defaultHTTPS)
|
||||||
|
case "DISABLE_SCHEDULER_SERVICE":
|
||||||
|
p.opts.schedulerService = !parseBool(value, defaultSchedulerService)
|
||||||
|
case "DISABLE_HTTP_SERVICE":
|
||||||
|
p.opts.httpService = !parseBool(value, defaultHTTPService)
|
||||||
|
case "CERT_FILE":
|
||||||
|
p.opts.certFile = parseString(value, defaultCertFile)
|
||||||
|
case "KEY_FILE":
|
||||||
|
p.opts.certKeyFile = parseString(value, defaultKeyFile)
|
||||||
|
case "CERT_DOMAIN":
|
||||||
|
p.opts.certDomain = parseString(value, defaultCertDomain)
|
||||||
|
case "CERT_CACHE":
|
||||||
|
p.opts.certCache = parseString(value, defaultCertCache)
|
||||||
|
case "CLEANUP_FREQUENCY":
|
||||||
|
p.opts.cleanupFrequency = parseInt(value, defaultCleanupFrequency)
|
||||||
|
case "WORKER_POOL_SIZE":
|
||||||
|
p.opts.workerPoolSize = parseInt(value, defaultWorkerPoolSize)
|
||||||
|
case "POLLING_FREQUENCY":
|
||||||
|
p.opts.pollingFrequency = parseInt(value, defaultPollingFrequency)
|
||||||
|
case "BATCH_SIZE":
|
||||||
|
p.opts.batchSize = parseInt(value, defaultBatchSize)
|
||||||
|
case "ARCHIVE_READ_DAYS":
|
||||||
|
p.opts.archiveReadDays = parseInt(value, defaultArchiveReadDays)
|
||||||
|
case "PROXY_IMAGES":
|
||||||
|
p.opts.proxyImages = parseString(value, defaultProxyImages)
|
||||||
|
case "CREATE_ADMIN":
|
||||||
|
p.opts.createAdmin = parseBool(value, defaultCreateAdmin)
|
||||||
|
case "POCKET_CONSUMER_KEY":
|
||||||
|
p.opts.pocketConsumerKey = parseString(value, defaultPocketConsumerKey)
|
||||||
|
case "OAUTH2_USER_CREATION":
|
||||||
|
p.opts.oauth2UserCreationAllowed = parseBool(value, defaultOAuth2UserCreation)
|
||||||
|
case "OAUTH2_CLIENT_ID":
|
||||||
|
p.opts.oauth2ClientID = parseString(value, defaultOAuth2ClientID)
|
||||||
|
case "OAUTH2_CLIENT_SECRET":
|
||||||
|
p.opts.oauth2ClientSecret = parseString(value, defaultOAuth2ClientSecret)
|
||||||
|
case "OAUTH2_REDIRECT_URL":
|
||||||
|
p.opts.oauth2RedirectURL = parseString(value, defaultOAuth2RedirectURL)
|
||||||
|
case "OAUTH2_PROVIDER":
|
||||||
|
p.opts.oauth2Provider = parseString(value, defaultOAuth2Provider)
|
||||||
|
case "HTTP_CLIENT_TIMEOUT":
|
||||||
|
p.opts.httpClientTimeout = parseInt(value, defaultHTTPClientTimeout)
|
||||||
|
case "HTTP_CLIENT_MAX_BODY_SIZE":
|
||||||
|
p.opts.httpClientMaxBodySize = int64(parseInt(value, defaultHTTPClientMaxBodySize) * 1024 * 1024)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if baseURL[len(baseURL)-1:] == "/" {
|
if port != "" {
|
||||||
baseURL = baseURL[:len(baseURL)-1]
|
p.opts.listenAddr = ":" + port
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseBaseURL(value string) (string, string, string, error) {
|
||||||
|
if value == "" {
|
||||||
|
return defaultBaseURL, defaultRootURL, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
u, err := url.Parse(baseURL)
|
if value[len(value)-1:] == "/" {
|
||||||
|
value = value[:len(value)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
url, err := url_parser.Parse(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", "", fmt.Errorf("Invalid BASE_URL: %v", err)
|
return "", "", "", fmt.Errorf("Invalid BASE_URL: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
scheme := strings.ToLower(u.Scheme)
|
scheme := strings.ToLower(url.Scheme)
|
||||||
if scheme != "https" && scheme != "http" {
|
if scheme != "https" && scheme != "http" {
|
||||||
return "", "", "", errors.New("Invalid BASE_URL: scheme must be http or https")
|
return "", "", "", errors.New("Invalid BASE_URL: scheme must be http or https")
|
||||||
}
|
}
|
||||||
|
|
||||||
basePath := u.Path
|
basePath := url.Path
|
||||||
u.Path = ""
|
url.Path = ""
|
||||||
return baseURL, u.String(), basePath, nil
|
return value, url.String(), basePath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseListenAddr() string {
|
func parseBool(value string, fallback bool) bool {
|
||||||
if port := os.Getenv("PORT"); port != "" {
|
|
||||||
return ":" + port
|
|
||||||
}
|
|
||||||
|
|
||||||
return getStringValue("LISTEN_ADDR", defaultListenAddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getBooleanValue(key string) bool {
|
|
||||||
value := strings.ToLower(os.Getenv(key))
|
|
||||||
if value == "1" || value == "yes" || value == "true" || value == "on" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func getStringValue(key, fallback string) string {
|
|
||||||
value := os.Getenv(key)
|
|
||||||
if value == "" {
|
if value == "" {
|
||||||
return fallback
|
return fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
return value
|
value = strings.ToLower(value)
|
||||||
|
if value == "1" || value == "yes" || value == "true" || value == "on" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func getIntValue(key string, fallback int) int {
|
func parseInt(value string, fallback int) int {
|
||||||
value := os.Getenv(key)
|
|
||||||
if value == "" {
|
if value == "" {
|
||||||
return fallback
|
return fallback
|
||||||
}
|
}
|
||||||
|
@ -123,3 +194,10 @@ func getIntValue(key string, fallback int) int {
|
||||||
|
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseString(value string, fallback string) string {
|
||||||
|
if value == "" {
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
|
@ -5,20 +5,12 @@
|
||||||
package config // import "miniflux.app/config"
|
package config // import "miniflux.app/config"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetBooleanValueWithUnsetVariable(t *testing.T) {
|
func TestParseBoolValue(t *testing.T) {
|
||||||
os.Clearenv()
|
|
||||||
if getBooleanValue("MY_TEST_VARIABLE") {
|
|
||||||
t.Errorf(`Unset variables should returns false`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetBooleanValue(t *testing.T) {
|
|
||||||
scenarios := map[string]bool{
|
scenarios := map[string]bool{
|
||||||
"": false,
|
"": true,
|
||||||
"1": true,
|
"1": true,
|
||||||
"Yes": true,
|
"Yes": true,
|
||||||
"yes": true,
|
"yes": true,
|
||||||
|
@ -31,49 +23,39 @@ func TestGetBooleanValue(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for input, expected := range scenarios {
|
for input, expected := range scenarios {
|
||||||
os.Clearenv()
|
result := parseBool(input, true)
|
||||||
os.Setenv("MY_TEST_VARIABLE", input)
|
|
||||||
result := getBooleanValue("MY_TEST_VARIABLE")
|
|
||||||
if result != expected {
|
if result != expected {
|
||||||
t.Errorf(`Unexpected result for %q, got %v instead of %v`, input, result, expected)
|
t.Errorf(`Unexpected result for %q, got %v instead of %v`, input, result, expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetStringValueWithUnsetVariable(t *testing.T) {
|
func TestParseStringValueWithUnsetVariable(t *testing.T) {
|
||||||
os.Clearenv()
|
if parseString("", "defaultValue") != "defaultValue" {
|
||||||
if getStringValue("MY_TEST_VARIABLE", "defaultValue") != "defaultValue" {
|
|
||||||
t.Errorf(`Unset variables should returns the default value`)
|
t.Errorf(`Unset variables should returns the default value`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetStringValue(t *testing.T) {
|
func TestParseStringValue(t *testing.T) {
|
||||||
os.Clearenv()
|
if parseString("test", "defaultValue") != "test" {
|
||||||
os.Setenv("MY_TEST_VARIABLE", "test")
|
|
||||||
if getStringValue("MY_TEST_VARIABLE", "defaultValue") != "test" {
|
|
||||||
t.Errorf(`Defined variables should returns the specified value`)
|
t.Errorf(`Defined variables should returns the specified value`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetIntValueWithUnsetVariable(t *testing.T) {
|
func TestParseIntValueWithUnsetVariable(t *testing.T) {
|
||||||
os.Clearenv()
|
if parseInt("", 42) != 42 {
|
||||||
if getIntValue("MY_TEST_VARIABLE", 42) != 42 {
|
|
||||||
t.Errorf(`Unset variables should returns the default value`)
|
t.Errorf(`Unset variables should returns the default value`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetIntValueWithInvalidInput(t *testing.T) {
|
func TestParseIntValueWithInvalidInput(t *testing.T) {
|
||||||
os.Clearenv()
|
if parseInt("invalid integer", 42) != 42 {
|
||||||
os.Setenv("MY_TEST_VARIABLE", "invalid integer")
|
|
||||||
if getIntValue("MY_TEST_VARIABLE", 42) != 42 {
|
|
||||||
t.Errorf(`Invalid integer should returns the default value`)
|
t.Errorf(`Invalid integer should returns the default value`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetIntValue(t *testing.T) {
|
func TestParseIntValue(t *testing.T) {
|
||||||
os.Clearenv()
|
if parseInt("2018", 42) != 2018 {
|
||||||
os.Setenv("MY_TEST_VARIABLE", "2018")
|
|
||||||
if getIntValue("MY_TEST_VARIABLE", 42) != 2018 {
|
|
||||||
t.Errorf(`Defined variables should returns the specified value`)
|
t.Errorf(`Defined variables should returns the specified value`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
19
miniflux.1
19
miniflux.1
|
@ -5,14 +5,29 @@
|
||||||
miniflux \- Minimalist and opinionated feed reader
|
miniflux \- Minimalist and opinionated feed reader
|
||||||
|
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
\fBminiflux\fR [-vi] [-create-admin] [-debug] [-flush-sessions] [-info] [-migrate]
|
\fBminiflux\fR [-vic] [-create-admin] [-debug] [-flush-sessions] [-info] [-migrate]
|
||||||
[-reset-feed-errors] [-reset-password] [-version]
|
[-reset-feed-errors] [-reset-password] [-version] [-config-file] [-config-dump]
|
||||||
|
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
\fBminiflux\fR is a minimalist and opinionated feed reader.
|
\fBminiflux\fR is a minimalist and opinionated feed reader.
|
||||||
|
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.PP
|
.PP
|
||||||
|
.B \-c
|
||||||
|
.RS 4
|
||||||
|
Load configuration file\&.
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
.B \-config-file
|
||||||
|
.RS 4
|
||||||
|
Load configuration file\&.
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
.B \-config-dump
|
||||||
|
.RS 4
|
||||||
|
Print parsed configuration values\&.
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
.B \-create-admin
|
.B \-create-admin
|
||||||
.RS 4
|
.RS 4
|
||||||
Create admin user\&.
|
Create admin user\&.
|
||||||
|
|
|
@ -134,7 +134,13 @@ func TestElapsedTime(t *testing.T) {
|
||||||
func TestProxyFilterWithHttpDefault(t *testing.T) {
|
func TestProxyFilterWithHttpDefault(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("PROXY_IMAGES", "http-only")
|
os.Setenv("PROXY_IMAGES", "http-only")
|
||||||
config.ParseConfig()
|
|
||||||
|
var err error
|
||||||
|
parser := config.NewParser()
|
||||||
|
config.Opts, err = parser.ParseEnvironmentVariables()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
|
}
|
||||||
|
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
|
r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
|
||||||
|
@ -151,7 +157,13 @@ func TestProxyFilterWithHttpDefault(t *testing.T) {
|
||||||
func TestProxyFilterWithHttpsDefault(t *testing.T) {
|
func TestProxyFilterWithHttpsDefault(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("PROXY_IMAGES", "http-only")
|
os.Setenv("PROXY_IMAGES", "http-only")
|
||||||
config.ParseConfig()
|
|
||||||
|
var err error
|
||||||
|
parser := config.NewParser()
|
||||||
|
config.Opts, err = parser.ParseEnvironmentVariables()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
|
}
|
||||||
|
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
|
r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
|
||||||
|
@ -168,7 +180,13 @@ func TestProxyFilterWithHttpsDefault(t *testing.T) {
|
||||||
func TestProxyFilterWithHttpNever(t *testing.T) {
|
func TestProxyFilterWithHttpNever(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("PROXY_IMAGES", "none")
|
os.Setenv("PROXY_IMAGES", "none")
|
||||||
config.ParseConfig()
|
|
||||||
|
var err error
|
||||||
|
parser := config.NewParser()
|
||||||
|
config.Opts, err = parser.ParseEnvironmentVariables()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
|
}
|
||||||
|
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
|
r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
|
||||||
|
@ -185,7 +203,13 @@ func TestProxyFilterWithHttpNever(t *testing.T) {
|
||||||
func TestProxyFilterWithHttpsNever(t *testing.T) {
|
func TestProxyFilterWithHttpsNever(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("PROXY_IMAGES", "none")
|
os.Setenv("PROXY_IMAGES", "none")
|
||||||
config.ParseConfig()
|
|
||||||
|
var err error
|
||||||
|
parser := config.NewParser()
|
||||||
|
config.Opts, err = parser.ParseEnvironmentVariables()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
|
}
|
||||||
|
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
|
r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
|
||||||
|
@ -202,7 +226,13 @@ func TestProxyFilterWithHttpsNever(t *testing.T) {
|
||||||
func TestProxyFilterWithHttpAlways(t *testing.T) {
|
func TestProxyFilterWithHttpAlways(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("PROXY_IMAGES", "all")
|
os.Setenv("PROXY_IMAGES", "all")
|
||||||
config.ParseConfig()
|
|
||||||
|
var err error
|
||||||
|
parser := config.NewParser()
|
||||||
|
config.Opts, err = parser.ParseEnvironmentVariables()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
|
}
|
||||||
|
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
|
r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
|
||||||
|
@ -219,7 +249,13 @@ func TestProxyFilterWithHttpAlways(t *testing.T) {
|
||||||
func TestProxyFilterWithHttpsAlways(t *testing.T) {
|
func TestProxyFilterWithHttpsAlways(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("PROXY_IMAGES", "all")
|
os.Setenv("PROXY_IMAGES", "all")
|
||||||
config.ParseConfig()
|
|
||||||
|
var err error
|
||||||
|
parser := config.NewParser()
|
||||||
|
config.Opts, err = parser.ParseEnvironmentVariables()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
|
}
|
||||||
|
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
|
r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
|
||||||
|
@ -236,7 +272,13 @@ func TestProxyFilterWithHttpsAlways(t *testing.T) {
|
||||||
func TestProxyFilterWithHttpInvalid(t *testing.T) {
|
func TestProxyFilterWithHttpInvalid(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("PROXY_IMAGES", "invalid")
|
os.Setenv("PROXY_IMAGES", "invalid")
|
||||||
config.ParseConfig()
|
|
||||||
|
var err error
|
||||||
|
parser := config.NewParser()
|
||||||
|
config.Opts, err = parser.ParseEnvironmentVariables()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
|
}
|
||||||
|
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
|
r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
|
||||||
|
@ -253,7 +295,13 @@ func TestProxyFilterWithHttpInvalid(t *testing.T) {
|
||||||
func TestProxyFilterWithHttpsInvalid(t *testing.T) {
|
func TestProxyFilterWithHttpsInvalid(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("PROXY_IMAGES", "invalid")
|
os.Setenv("PROXY_IMAGES", "invalid")
|
||||||
config.ParseConfig()
|
|
||||||
|
var err error
|
||||||
|
parser := config.NewParser()
|
||||||
|
config.Opts, err = parser.ParseEnvironmentVariables()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf(`Parsing failure: %v`, err)
|
||||||
|
}
|
||||||
|
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
|
r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
|
||||||
|
|
Loading…
Reference in a new issue