feat(repos): migrate filesystem operations to io.Local abstraction

Replace direct os package calls with io.Local methods:
- os.ReadFile → io.Local.Read
- os.Stat → io.Local.IsFile/IsDir
- os.ReadDir → io.Local.List

Part of #101 (io.Medium migration tracking issue).

Closes #111

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Snider 2026-02-02 04:38:38 +00:00
parent 68f2f658f4
commit d6fb905dba

View file

@ -9,6 +9,7 @@ import (
"path/filepath"
"strings"
"github.com/host-uk/core/pkg/io"
"gopkg.in/yaml.v3"
)
@ -60,13 +61,13 @@ type Repo struct {
// LoadRegistry reads and parses a repos.yaml file.
func LoadRegistry(path string) (*Registry, error) {
data, err := os.ReadFile(path)
dataStr, err := io.Local.Read(path)
if err != nil {
return nil, fmt.Errorf("failed to read registry file: %w", err)
}
var reg Registry
if err := yaml.Unmarshal(data, &reg); err != nil {
if err := yaml.Unmarshal([]byte(dataStr), &reg); err != nil {
return nil, fmt.Errorf("failed to parse registry file: %w", err)
}
@ -98,7 +99,7 @@ func FindRegistry() (string, error) {
for {
candidate := filepath.Join(dir, "repos.yaml")
if _, err := os.Stat(candidate); err == nil {
if io.Local.IsFile(candidate) {
return candidate, nil
}
@ -121,7 +122,7 @@ func FindRegistry() (string, error) {
}
for _, p := range commonPaths {
if _, err := os.Stat(p); err == nil {
if io.Local.IsFile(p) {
return p, nil
}
}
@ -132,7 +133,7 @@ func FindRegistry() (string, error) {
// ScanDirectory creates a Registry by scanning a directory for git repos.
// This is used as a fallback when no repos.yaml is found.
func ScanDirectory(dir string) (*Registry, error) {
entries, err := os.ReadDir(dir)
entries, err := io.Local.List(dir)
if err != nil {
return nil, fmt.Errorf("failed to read directory: %w", err)
}
@ -152,7 +153,7 @@ func ScanDirectory(dir string) (*Registry, error) {
repoPath := filepath.Join(dir, entry.Name())
gitPath := filepath.Join(repoPath, ".git")
if _, err := os.Stat(gitPath); err != nil {
if !io.Local.IsDir(gitPath) {
continue // Not a git repo
}
@ -176,14 +177,13 @@ func ScanDirectory(dir string) (*Registry, error) {
// detectOrg tries to extract the GitHub org from a repo's origin remote.
func detectOrg(repoPath string) string {
// Try to read git remote
cmd := filepath.Join(repoPath, ".git", "config")
data, err := os.ReadFile(cmd)
configPath := filepath.Join(repoPath, ".git", "config")
content, err := io.Local.Read(configPath)
if err != nil {
return ""
}
// Simple parse for github.com URLs
content := string(data)
// Look for patterns like github.com:org/repo or github.com/org/repo
for _, line := range strings.Split(content, "\n") {
line = strings.TrimSpace(line)
@ -292,15 +292,13 @@ func (r *Registry) TopologicalOrder() ([]*Repo, error) {
// Exists checks if the repo directory exists on disk.
func (repo *Repo) Exists() bool {
info, err := os.Stat(repo.Path)
return err == nil && info.IsDir()
return io.Local.IsDir(repo.Path)
}
// IsGitRepo checks if the repo directory contains a .git folder.
func (repo *Repo) IsGitRepo() bool {
gitPath := filepath.Join(repo.Path, ".git")
info, err := os.Stat(gitPath)
return err == nil && info.IsDir()
return io.Local.IsDir(gitPath)
}
// expandPath expands ~ to home directory.