feat: add directory-scoped host defaults (match_dirs) and repo list --limit
Add match_dirs field to host config entries for directory-based host resolution. When no --hostname flag, FGJ_HOST env var, or git remote is detected, the longest matching directory prefix determines the host. Symlinks are resolved on both sides for macOS compatibility (/tmp → /private/tmp). Also adds --limit/-L flag to repo list.
This commit is contained in:
parent
113505de95
commit
c293e233d2
17 changed files with 252 additions and 79 deletions
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
|
@ -14,10 +15,11 @@ type Config struct {
|
|||
}
|
||||
|
||||
type HostConfig struct {
|
||||
Hostname string `yaml:"hostname"`
|
||||
Token string `yaml:"token"`
|
||||
User string `yaml:"user,omitempty"`
|
||||
GitProtocol string `yaml:"git_protocol,omitempty"`
|
||||
Hostname string `yaml:"hostname"`
|
||||
Token string `yaml:"token"`
|
||||
User string `yaml:"user,omitempty"`
|
||||
GitProtocol string `yaml:"git_protocol,omitempty"`
|
||||
MatchDirs []string `yaml:"match_dirs,omitempty"`
|
||||
}
|
||||
|
||||
func GetConfigDir() (string, error) {
|
||||
|
|
@ -96,8 +98,9 @@ func (c *Config) SaveToPath(path string) error {
|
|||
// 2. CLI flag (--hostname)
|
||||
// 3. Environment variable (FGJ_HOST)
|
||||
// 4. Auto-detected hostname from git remote
|
||||
// 5. Default to codeberg.org
|
||||
func (c *Config) GetHost(hostname string, detectedHost string) (HostConfig, error) {
|
||||
// 5. match_dirs lookup (longest prefix match)
|
||||
// 6. Default to codeberg.org
|
||||
func (c *Config) GetHost(hostname string, detectedHost string, cwd string) (HostConfig, error) {
|
||||
if hostname == "" {
|
||||
hostname = viper.GetString("hostname")
|
||||
}
|
||||
|
|
@ -110,6 +113,10 @@ func (c *Config) GetHost(hostname string, detectedHost string) (HostConfig, erro
|
|||
hostname = detectedHost
|
||||
}
|
||||
|
||||
if hostname == "" {
|
||||
hostname = c.ResolveHostByPath(cwd)
|
||||
}
|
||||
|
||||
if hostname == "" {
|
||||
hostname = "codeberg.org"
|
||||
}
|
||||
|
|
@ -122,6 +129,50 @@ func (c *Config) GetHost(hostname string, detectedHost string) (HostConfig, erro
|
|||
return host, nil
|
||||
}
|
||||
|
||||
// ResolveHostByPath finds the host whose match_dirs entry is the longest
|
||||
// prefix of cwd. Returns "" if no match is found.
|
||||
// Both cwd and match_dirs entries are resolved through filepath.EvalSymlinks
|
||||
// to handle symlinks (e.g. macOS /tmp → /private/tmp).
|
||||
func (c *Config) ResolveHostByPath(cwd string) string {
|
||||
if cwd == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Resolve symlinks in cwd so /tmp becomes /private/tmp on macOS, etc.
|
||||
if resolved, err := filepath.EvalSymlinks(cwd); err == nil {
|
||||
cwd = resolved
|
||||
}
|
||||
|
||||
bestHost := ""
|
||||
bestLen := 0
|
||||
|
||||
for hostname, host := range c.Hosts {
|
||||
for _, dir := range host.MatchDirs {
|
||||
if dir == "" {
|
||||
continue
|
||||
}
|
||||
// Resolve symlinks in the configured dir as well
|
||||
if resolved, err := filepath.EvalSymlinks(dir); err == nil {
|
||||
dir = resolved
|
||||
}
|
||||
// Normalize: ensure trailing slash for prefix matching
|
||||
prefix := dir
|
||||
if !strings.HasSuffix(prefix, "/") {
|
||||
prefix += "/"
|
||||
}
|
||||
// Match if cwd equals dir exactly or is under it
|
||||
if cwd == dir || strings.HasPrefix(cwd, prefix) {
|
||||
if len(dir) > bestLen {
|
||||
bestLen = len(dir)
|
||||
bestHost = hostname
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bestHost
|
||||
}
|
||||
|
||||
func (c *Config) SetHost(hostname string, host HostConfig) {
|
||||
if c.Hosts == nil {
|
||||
c.Hosts = make(map[string]HostConfig)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue