From 71b329e2e98c453a1e35fd569a4eb58e4ed28aa9 Mon Sep 17 00:00:00 2001 From: yeti Date: Sat, 28 Mar 2026 03:11:49 +0000 Subject: [PATCH 1/2] refactor: consolidate duplicate directory scanning into collectConfigFiles Extract shared directory scanning logic from LoadFeatures and LoadTransfers into a single collectConfigFiles helper that returns a name -> filepath map. Both functions had nearly identical loops for iterating search paths, reading directories, filtering by suffix, and deduplicating by name. This ensures any future bug fixes to the scanning logic only need to be made once. Co-Authored-By: Claude Opus 4.6 (1M context) --- config/config.go | 41 +++++++++++++++++++++++++++++++++++++++++ config/feature.go | 30 +++++------------------------- config/transfer.go | 29 +++-------------------------- 3 files changed, 49 insertions(+), 51 deletions(-) create mode 100644 config/config.go diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..c025f0b --- /dev/null +++ b/config/config.go @@ -0,0 +1,41 @@ +package config + +import ( + "fmt" + "os" + "path/filepath" + "strings" +) + +// collectConfigFiles scans searchPaths for files ending in suffix and returns +// a name -> filepath map. Earlier paths take priority (first occurrence wins). +// The name is derived by trimming the suffix from the filename. +func collectConfigFiles(searchPaths []string, suffix string) (map[string]string, error) { + files := make(map[string]string) + + for _, dir := range searchPaths { + entries, err := os.ReadDir(dir) + if err != nil { + if os.IsNotExist(err) { + continue + } + return nil, fmt.Errorf("failed to read directory %s: %w", dir, err) + } + + for _, entry := range entries { + if entry.IsDir() { + continue + } + if !strings.HasSuffix(entry.Name(), suffix) { + continue + } + + name := strings.TrimSuffix(entry.Name(), suffix) + if _, exists := files[name]; !exists { + files[name] = filepath.Join(dir, entry.Name()) + } + } + } + + return files, nil +} diff --git a/config/feature.go b/config/feature.go index defc640..736588e 100644 --- a/config/feature.go +++ b/config/feature.go @@ -12,6 +12,8 @@ import ( "gopkg.in/ini.v1" ) +const featureSuffix = ".feature" + // Feature represents a parsed .feature configuration file type Feature struct { Name string // Derived from filename (e.g., "devel" from "devel.feature") @@ -35,31 +37,9 @@ func LoadFeatures(customPath string) ([]*Feature, error) { } // Collect all .feature files, with earlier paths taking priority - featureFiles := make(map[string]string) // feature name -> file path - - for _, dir := range searchPaths { - entries, err := os.ReadDir(dir) - if err != nil { - if os.IsNotExist(err) { - continue - } - return nil, fmt.Errorf("failed to read directory %s: %w", dir, err) - } - - for _, entry := range entries { - if entry.IsDir() { - continue - } - if !strings.HasSuffix(entry.Name(), ".feature") { - continue - } - - featureName := strings.TrimSuffix(entry.Name(), ".feature") - if _, exists := featureFiles[featureName]; !exists { - // Earlier paths take priority - featureFiles[featureName] = filepath.Join(dir, entry.Name()) - } - } + featureFiles, err := collectConfigFiles(searchPaths, featureSuffix) + if err != nil { + return nil, err } if len(featureFiles) == 0 { diff --git a/config/transfer.go b/config/transfer.go index a7af533..675bf8d 100644 --- a/config/transfer.go +++ b/config/transfer.go @@ -4,7 +4,6 @@ import ( "cmp" "fmt" "os" - "path/filepath" "runtime" "slices" "strings" @@ -93,31 +92,9 @@ func LoadTransfers(customPath string) ([]*Transfer, error) { } // Collect all .transfer files, with earlier paths taking priority - transferFiles := make(map[string]string) // component name -> file path - - for _, dir := range searchPaths { - entries, err := os.ReadDir(dir) - if err != nil { - if os.IsNotExist(err) { - continue - } - return nil, fmt.Errorf("failed to read directory %s: %w", dir, err) - } - - for _, entry := range entries { - if entry.IsDir() { - continue - } - if !strings.HasSuffix(entry.Name(), ".transfer") { - continue - } - - component := strings.TrimSuffix(entry.Name(), ".transfer") - if _, exists := transferFiles[component]; !exists { - // Earlier paths take priority - transferFiles[component] = filepath.Join(dir, entry.Name()) - } - } + transferFiles, err := collectConfigFiles(searchPaths, ".transfer") + if err != nil { + return nil, err } if len(transferFiles) == 0 { From 935e675f2b9867db02fd17f3b16c65288287bc72 Mon Sep 17 00:00:00 2001 From: yeti Date: Mon, 30 Mar 2026 23:40:13 +0000 Subject: [PATCH 2/2] refactor: use transferSuffix constant to match featureSuffix pattern Addresses PR review feedback to use a named constant instead of a string literal for the ".transfer" suffix, consistent with how featureSuffix is defined in feature.go. Co-Authored-By: Claude Opus 4.6 (1M context) --- config/transfer.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/config/transfer.go b/config/transfer.go index 675bf8d..7947b22 100644 --- a/config/transfer.go +++ b/config/transfer.go @@ -11,6 +11,8 @@ import ( "gopkg.in/ini.v1" ) +const transferSuffix = ".transfer" + // Transfer represents a parsed .transfer configuration file type Transfer struct { Component string // Derived from filename @@ -92,7 +94,7 @@ func LoadTransfers(customPath string) ([]*Transfer, error) { } // Collect all .transfer files, with earlier paths taking priority - transferFiles, err := collectConfigFiles(searchPaths, ".transfer") + transferFiles, err := collectConfigFiles(searchPaths, transferSuffix) if err != nil { return nil, err }