Establish connections using bookmark ID only (#619)
* Establish connections using bookmark ID only * Refactor specs * Extra tests * Fix homedir assertion for bookmarks path * Fix newline in the warning message * Check for bookmark file existence before reading * Connect code restructure
This commit is contained in:
152
pkg/bookmarks/manager.go
Normal file
152
pkg/bookmarks/manager.go
Normal file
@@ -0,0 +1,152 @@
|
||||
package bookmarks
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
)
|
||||
|
||||
type Manager struct {
|
||||
dir string
|
||||
}
|
||||
|
||||
func NewManager(dir string) Manager {
|
||||
return Manager{
|
||||
dir: dir,
|
||||
}
|
||||
}
|
||||
|
||||
func (m Manager) Get(id string) (*Bookmark, error) {
|
||||
bookmarks, err := m.list()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, b := range bookmarks {
|
||||
if b.ID == id {
|
||||
return &b, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("bookmark %v not found", id)
|
||||
}
|
||||
|
||||
func (m Manager) List() ([]Bookmark, error) {
|
||||
return m.list()
|
||||
}
|
||||
|
||||
func (m Manager) ListIDs() ([]string, error) {
|
||||
bookmarks, err := m.list()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ids := make([]string, len(bookmarks))
|
||||
for i, bookmark := range bookmarks {
|
||||
ids[i] = bookmark.ID
|
||||
}
|
||||
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
func (m Manager) list() ([]Bookmark, error) {
|
||||
result := []Bookmark{}
|
||||
|
||||
if m.dir == "" {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
info, err := os.Stat(m.dir)
|
||||
if err != nil {
|
||||
// Do not fail if base dir does not exists: it's not created by default
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
fmt.Fprintf(os.Stderr, "[WARN] bookmarks dir %s does not exist\n", m.dir)
|
||||
return result, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if !info.IsDir() {
|
||||
return nil, fmt.Errorf("path %s is not a directory", m.dir)
|
||||
}
|
||||
|
||||
dirEntries, err := os.ReadDir(m.dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, entry := range dirEntries {
|
||||
name := entry.Name()
|
||||
if filepath.Ext(name) != ".toml" {
|
||||
continue
|
||||
}
|
||||
|
||||
bookmark, err := readBookmark(filepath.Join(m.dir, name))
|
||||
if err != nil {
|
||||
// Do not fail if one of the bookmarks is invalid
|
||||
fmt.Fprintf(os.Stderr, "[WARN] bookmark file %s is invalid: %s\n", name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
result = append(result, bookmark)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func readBookmark(path string) (Bookmark, error) {
|
||||
bookmark := Bookmark{
|
||||
ID: fileBasename(path),
|
||||
}
|
||||
|
||||
_, err := os.Stat(path)
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
err = fmt.Errorf("bookmark file %s does not exist", path)
|
||||
}
|
||||
return bookmark, err
|
||||
}
|
||||
|
||||
buff, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return bookmark, err
|
||||
}
|
||||
|
||||
_, err = toml.Decode(string(buff), &bookmark)
|
||||
|
||||
if bookmark.Port == 0 {
|
||||
bookmark.Port = 5432
|
||||
}
|
||||
|
||||
// List of all supported postgres modes
|
||||
modes := []string{"disable", "allow", "prefer", "require", "verify-ca", "verify-full"}
|
||||
valid := false
|
||||
|
||||
for _, mode := range modes {
|
||||
if bookmark.SSLMode == mode {
|
||||
valid = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to a default mode if mode is not set or invalid
|
||||
// Typical typo: ssl mode set to "disabled"
|
||||
if bookmark.SSLMode == "" || !valid {
|
||||
bookmark.SSLMode = "disable"
|
||||
}
|
||||
|
||||
// Set default SSH port if it's not provided by user
|
||||
if bookmark.SSH != nil && bookmark.SSH.Port == "" {
|
||||
bookmark.SSH.Port = "22"
|
||||
}
|
||||
|
||||
return bookmark, err
|
||||
}
|
||||
|
||||
func fileBasename(path string) string {
|
||||
filename := filepath.Base(path)
|
||||
return strings.Replace(filename, filepath.Ext(path), "", 1)
|
||||
}
|
||||
Reference in New Issue
Block a user