From 5724bd127982289dd52e79933bbe60b98a5b639e Mon Sep 17 00:00:00 2001 From: Kevin Burke Date: Sun, 5 Jun 2022 12:44:00 -0700 Subject: [PATCH] config: add UserSettings.ConfigFinder Fixes #48. --- config.go | 41 +++++++++++++++++++++++++++++++++++++++-- config_test.go | 12 ++++++++++++ example_test.go | 10 ++++++++++ 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/config.go b/config.go index 00d815c..4816e67 100644 --- a/config.go +++ b/config.go @@ -53,6 +53,8 @@ type configFinder func() string // files are parsed and cached the first time Get() or GetStrict() is called. type UserSettings struct { IgnoreErrors bool + customConfig *Config + customConfigFinder configFinder systemConfig *Config systemConfigFinder configFinder userConfig *Config @@ -203,6 +205,13 @@ func (u *UserSettings) GetStrict(alias, key string) (string, error) { if u.onceErr != nil && u.IgnoreErrors == false { return "", u.onceErr } + // TODO this is getting repetitive + if u.customConfig != nil { + val, err := findVal(u.customConfig, alias, key) + if err != nil || val != "" { + return val, err + } + } val, err := findVal(u.userConfig, alias, key) if err != nil || val != "" { return val, err @@ -228,6 +237,12 @@ func (u *UserSettings) GetAllStrict(alias, key string) ([]string, error) { if u.onceErr != nil && u.IgnoreErrors == false { return nil, u.onceErr } + if u.customConfig != nil { + val, err := findAll(u.customConfig, alias, key) + if err != nil || val != nil { + return val, err + } + } val, err := findAll(u.userConfig, alias, key) if err != nil || val != nil { return val, err @@ -243,16 +258,38 @@ func (u *UserSettings) GetAllStrict(alias, key string) ([]string, error) { return []string{}, nil } +// ConfigFinder will invoke f to try to find a ssh config file in a custom +// location on disk, instead of in /etc/ssh or $HOME/.ssh. f should return the +// name of a file containing SSH configuration. +// +// ConfigFinder must be invoked before any calls to Get or GetStrict and panics +// if f is nil. Most users should not need to use this function. +func (u *UserSettings) ConfigFinder(f func() string) { + if f == nil { + panic("cannot call ConfigFinder with nil function") + } + u.customConfigFinder = f +} + func (u *UserSettings) doLoadConfigs() { u.loadConfigs.Do(func() { - // can't parse user file, that's ok. var filename string + var err error + if u.customConfigFinder != nil { + filename = u.customConfigFinder() + u.customConfig, err = parseFile(filename) + // IsNotExist should be returned because a user specified this + // function - not existing likely means they made an error + if err != nil { + u.onceErr = err + } + return + } if u.userConfigFinder == nil { filename = userConfigFinder() } else { filename = u.userConfigFinder() } - var err error u.userConfig, err = parseFile(filename) //lint:ignore S1002 I prefer it this way if err != nil && os.IsNotExist(err) == false { diff --git a/config_test.go b/config_test.go index 0bd350f..11b203d 100644 --- a/config_test.go +++ b/config_test.go @@ -455,3 +455,15 @@ func TestNoTrailingNewline(t *testing.T) { t.Errorf("wrong port: got %q want 4242", port) } } + +func TestCustomFinder(t *testing.T) { + us := &UserSettings{} + us.ConfigFinder(func() string { + return "testdata/config1" + }) + + val := us.Get("wap", "User") + if val != "root" { + t.Errorf("expected to find User root, got %q", val) + } +} diff --git a/example_test.go b/example_test.go index f2058c6..a7c16d6 100644 --- a/example_test.go +++ b/example_test.go @@ -2,6 +2,7 @@ package ssh_config_test import ( "fmt" + "path/filepath" "strings" "github.com/kevinburke/ssh_config" @@ -46,3 +47,12 @@ func ExampleDefault() { // 22 // } + +func ExampleUserSettings_ConfigFinder() { + // This can be used to test SSH config parsing. + u := ssh_config.UserSettings{} + u.ConfigFinder(func() string { + return filepath.Join("testdata", "test_config") + }) + u.Get("example.com", "Host") +}