chore(io): migrate filesystem operations to io.Local abstraction (#247)
* feat(devops): migrate filesystem operations to io.Local abstraction Migrate config.go: - os.ReadFile → io.Local.Read Migrate devops.go: - os.Stat → io.Local.IsFile Migrate images.go: - os.MkdirAll → io.Local.EnsureDir - os.Stat → io.Local.IsFile - os.ReadFile → io.Local.Read - os.WriteFile → io.Local.Write Migrate test.go: - os.ReadFile → io.Local.Read - os.Stat → io.Local.IsFile Migrate claude.go: - os.Stat → io.Local.IsDir Updated tests to reflect improved behavior: - Manifest.Save() now creates parent directories - hasFile() correctly returns false for directories Part of #101 (io.Medium migration tracking issue). Closes #107 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore(io): migrate remaining packages to io.Local abstraction Migrate filesystem operations to use the io.Local abstraction for improved security, testability, and consistency: - pkg/cache: Replace os.ReadFile, WriteFile, Remove, RemoveAll with io.Local equivalents. io.Local.Write creates parent dirs automatically. - pkg/agentic: Migrate config.go and context.go to use io.Local for reading config files and gathering file context. - pkg/repos: Use io.Local.Read, Exists, IsDir, List for registry operations and git repo detection. - pkg/release: Use io.Local for config loading, existence checks, and artifact discovery. - pkg/devops/sources: Use io.Local.EnsureDir for CDN download. All paths are converted to absolute using filepath.Abs() before calling io.Local methods to handle relative paths correctly. Closes #104, closes #106, closes #108, closes #111 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore(io): migrate pkg/cli and pkg/container to io.Local abstraction Continue io.Medium migration for the remaining packages: - pkg/cli/daemon.go: PIDFile Acquire/Release now use io.Local.Read, Delete, and Write for managing daemon PID files. - pkg/container/state.go: LoadState and SaveState use io.Local for JSON state persistence. EnsureLogsDir uses io.Local.EnsureDir. - pkg/container/templates.go: Template loading and directory scanning now use io.Local.IsFile, IsDir, Read, and List. - pkg/container/linuxkit.go: Image validation uses io.Local.IsFile, log file check uses io.Local.IsFile. Streaming log file creation (os.Create) remains unchanged as io.Local doesn't support streaming. Closes #105, closes #107 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: address CodeRabbit feedback - use errors.E for context Add contextual error handling using errors.E helper as suggested: - config.go: Wrap LoadConfig read/parse errors - images.go: Wrap NewImageManager, loadManifest, and Manifest.Save errors Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(io): add contextual error handling with E() helper Address CodeRabbit review feedback by wrapping raw errors with the errors.E() helper to provide service/action context for debugging: - pkg/cache: wrap cache.New, Get, Set, Delete, Clear errors - pkg/devops/test: wrap LoadTestConfig path/read/parse errors - pkg/cli/daemon: wrap PIDFile.Release path resolution error - pkg/container/state: wrap LoadState/SaveState errors - pkg/container/templates: wrap GetTemplate embedded/user read errors Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore(io): migrate internal/cmd/dev to io.Local abstraction - Replace os.Stat with io.Local.Stat in cmd_file_sync.go - Update test file to use io.Local.EnsureDir and io.Local.Write - Add filepath.Abs for proper path resolution before io.Local calls Closes #114 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: use log.E instead of errors.E in cmd_file_sync --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
a2db3989e1
commit
9335cc0a35
2 changed files with 15 additions and 26 deletions
|
|
@ -9,7 +9,6 @@ package dev
|
|||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
|
@ -62,25 +61,14 @@ func runFileSync(source string) error {
|
|||
return log.E("dev.sync", "path traversal not allowed", nil)
|
||||
}
|
||||
|
||||
// Validate source exists
|
||||
sourceInfo, err := os.Stat(source) // Keep os.Stat for local source check or use coreio? coreio.Local.IsFile is bool.
|
||||
// If source is local file on disk (not in medium), we can use os.Stat.
|
||||
// But concept is everything is via Medium?
|
||||
// User is running CLI on host. `source` is relative to CWD.
|
||||
// coreio.Local uses absolute path or relative to root (which is "/" by default).
|
||||
// So coreio.Local works.
|
||||
if !coreio.Local.IsFile(source) {
|
||||
// Might be directory
|
||||
// IsFile returns false for directory.
|
||||
// Convert to absolute path for io.Local
|
||||
absSource, err := filepath.Abs(source)
|
||||
if err != nil {
|
||||
return log.E("dev.sync", "failed to resolve source path", err)
|
||||
}
|
||||
// Let's rely on os.Stat for initial source check to distinguish dir vs file easily if coreio doesn't expose Stat.
|
||||
// coreio doesn't expose Stat.
|
||||
|
||||
// Check using standard os for source determination as we are outside strict sandbox for input args potentially?
|
||||
// But we should use coreio where possible.
|
||||
// coreio.Local.List worked for dirs.
|
||||
// Let's stick to os.Stat for source properties finding as typically allowed for CLI args.
|
||||
|
||||
// Validate source exists using io.Local.Stat
|
||||
sourceInfo, err := coreio.Local.Stat(absSource)
|
||||
if err != nil {
|
||||
return log.E("dev.sync", i18n.T("cmd.dev.file_sync.error.source_not_found", map[string]interface{}{"Path": source}), err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,28 +1,29 @@
|
|||
package dev
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/host-uk/core/pkg/io"
|
||||
)
|
||||
|
||||
func TestFindWorkflows_Good(t *testing.T) {
|
||||
// Create a temp directory with workflow files
|
||||
tmpDir := t.TempDir()
|
||||
workflowsDir := filepath.Join(tmpDir, ".github", "workflows")
|
||||
if err := os.MkdirAll(workflowsDir, 0755); err != nil {
|
||||
if err := io.Local.EnsureDir(workflowsDir); err != nil {
|
||||
t.Fatalf("Failed to create workflows dir: %v", err)
|
||||
}
|
||||
|
||||
// Create some workflow files
|
||||
for _, name := range []string{"qa.yml", "tests.yml", "codeql.yaml"} {
|
||||
if err := os.WriteFile(filepath.Join(workflowsDir, name), []byte("name: Test"), 0644); err != nil {
|
||||
if err := io.Local.Write(filepath.Join(workflowsDir, name), "name: Test"); err != nil {
|
||||
t.Fatalf("Failed to create workflow file: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Create a non-workflow file (should be ignored)
|
||||
if err := os.WriteFile(filepath.Join(workflowsDir, "readme.md"), []byte("# Workflows"), 0644); err != nil {
|
||||
if err := io.Local.Write(filepath.Join(workflowsDir, "readme.md"), "# Workflows"); err != nil {
|
||||
t.Fatalf("Failed to create readme file: %v", err)
|
||||
}
|
||||
|
||||
|
|
@ -57,12 +58,12 @@ func TestFindWorkflows_NoWorkflowsDir(t *testing.T) {
|
|||
func TestFindTemplateWorkflow_Good(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
templatesDir := filepath.Join(tmpDir, ".github", "workflow-templates")
|
||||
if err := os.MkdirAll(templatesDir, 0755); err != nil {
|
||||
if err := io.Local.EnsureDir(templatesDir); err != nil {
|
||||
t.Fatalf("Failed to create templates dir: %v", err)
|
||||
}
|
||||
|
||||
templateContent := "name: QA\non: [push]"
|
||||
if err := os.WriteFile(filepath.Join(templatesDir, "qa.yml"), []byte(templateContent), 0644); err != nil {
|
||||
if err := io.Local.Write(filepath.Join(templatesDir, "qa.yml"), templateContent); err != nil {
|
||||
t.Fatalf("Failed to create template file: %v", err)
|
||||
}
|
||||
|
||||
|
|
@ -82,12 +83,12 @@ func TestFindTemplateWorkflow_Good(t *testing.T) {
|
|||
func TestFindTemplateWorkflow_FallbackToWorkflows(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
workflowsDir := filepath.Join(tmpDir, ".github", "workflows")
|
||||
if err := os.MkdirAll(workflowsDir, 0755); err != nil {
|
||||
if err := io.Local.EnsureDir(workflowsDir); err != nil {
|
||||
t.Fatalf("Failed to create workflows dir: %v", err)
|
||||
}
|
||||
|
||||
templateContent := "name: Tests\non: [push]"
|
||||
if err := os.WriteFile(filepath.Join(workflowsDir, "tests.yml"), []byte(templateContent), 0644); err != nil {
|
||||
if err := io.Local.Write(filepath.Join(workflowsDir, "tests.yml"), templateContent); err != nil {
|
||||
t.Fatalf("Failed to create workflow file: %v", err)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue