mirror of
https://github.com/ivuorinen/gibidify.git
synced 2026-01-26 03:24:05 +00:00
Initial commit
This commit is contained in:
9
fileproc/collector.go
Normal file
9
fileproc/collector.go
Normal file
@@ -0,0 +1,9 @@
|
||||
// Package fileproc provides functions for collecting and processing files.
|
||||
package fileproc
|
||||
|
||||
// CollectFiles scans the given root directory using the default walker (ProdWalker)
|
||||
// and returns a slice of file paths.
|
||||
func CollectFiles(root string) ([]string, error) {
|
||||
var w Walker = ProdWalker{}
|
||||
return w.Walk(root)
|
||||
}
|
||||
47
fileproc/collector_test.go
Normal file
47
fileproc/collector_test.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package fileproc
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCollectFilesWithFakeWalker(t *testing.T) {
|
||||
// Instead of using the production walker, use FakeWalker.
|
||||
expectedFiles := []string{
|
||||
"/path/to/file1.txt",
|
||||
"/path/to/file2.go",
|
||||
}
|
||||
fake := FakeWalker{
|
||||
Files: expectedFiles,
|
||||
Err: nil,
|
||||
}
|
||||
|
||||
// Use fake.Walk directly.
|
||||
files, err := fake.Walk("dummyRoot")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %v", err)
|
||||
}
|
||||
|
||||
if len(files) != len(expectedFiles) {
|
||||
t.Fatalf("Expected %d files, got %d", len(expectedFiles), len(files))
|
||||
}
|
||||
|
||||
for i, f := range files {
|
||||
if f != expectedFiles[i] {
|
||||
t.Errorf("Expected file %s, got %s", expectedFiles[i], f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCollectFilesError(t *testing.T) {
|
||||
// Fake walker returns an error.
|
||||
fake := FakeWalker{
|
||||
Files: nil,
|
||||
Err: os.ErrNotExist,
|
||||
}
|
||||
|
||||
_, err := fake.Walk("dummyRoot")
|
||||
if err == nil {
|
||||
t.Fatal("Expected an error, got nil")
|
||||
}
|
||||
}
|
||||
16
fileproc/fake_walker.go
Normal file
16
fileproc/fake_walker.go
Normal file
@@ -0,0 +1,16 @@
|
||||
// Package fileproc provides functions for file processing.
|
||||
package fileproc
|
||||
|
||||
// FakeWalker implements Walker for testing purposes.
|
||||
type FakeWalker struct {
|
||||
Files []string
|
||||
Err error
|
||||
}
|
||||
|
||||
// Walk returns predetermined file paths or an error, depending on FakeWalker's configuration.
|
||||
func (fw FakeWalker) Walk(root string) ([]string, error) {
|
||||
if fw.Err != nil {
|
||||
return nil, fw.Err
|
||||
}
|
||||
return fw.Files, nil
|
||||
}
|
||||
27
fileproc/processor.go
Normal file
27
fileproc/processor.go
Normal file
@@ -0,0 +1,27 @@
|
||||
// Package fileproc provides functions for processing files.
|
||||
package fileproc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// WriteRequest represents the content to be written.
|
||||
type WriteRequest struct {
|
||||
Content string
|
||||
}
|
||||
|
||||
// ProcessFile reads the file at filePath and sends a formatted output to outCh.
|
||||
// The optional wg parameter is used when the caller wants to wait on file-level processing.
|
||||
func ProcessFile(filePath string, outCh chan<- WriteRequest, wg *interface{}) {
|
||||
content, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to read file %s: %v", filePath, err)
|
||||
return
|
||||
}
|
||||
// Format: separator, file path, then content.
|
||||
formatted := fmt.Sprintf("\n---\n%s\n%s\n", filePath, string(content))
|
||||
outCh <- WriteRequest{Content: formatted}
|
||||
}
|
||||
45
fileproc/processor_test.go
Normal file
45
fileproc/processor_test.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package fileproc
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestProcessFile(t *testing.T) {
|
||||
// Create a temporary file with known content.
|
||||
tmpFile, err := os.CreateTemp("", "testfile")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(tmpFile.Name())
|
||||
|
||||
content := "Test content"
|
||||
if _, err := tmpFile.WriteString(content); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tmpFile.Close()
|
||||
|
||||
ch := make(chan WriteRequest, 1)
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
ProcessFile(tmpFile.Name(), ch, nil)
|
||||
}()
|
||||
wg.Wait()
|
||||
close(ch)
|
||||
|
||||
var result string
|
||||
for req := range ch {
|
||||
result = req.Content
|
||||
}
|
||||
|
||||
if !strings.Contains(result, tmpFile.Name()) {
|
||||
t.Errorf("Output does not contain file path: %s", tmpFile.Name())
|
||||
}
|
||||
if !strings.Contains(result, content) {
|
||||
t.Errorf("Output does not contain file content: %s", content)
|
||||
}
|
||||
}
|
||||
40
fileproc/walker.go
Normal file
40
fileproc/walker.go
Normal file
@@ -0,0 +1,40 @@
|
||||
// Package fileproc provides functions for file processing.
|
||||
package fileproc
|
||||
|
||||
import (
|
||||
"github.com/boyter/gocodewalker"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Walker defines an interface for scanning directories.
|
||||
type Walker interface {
|
||||
Walk(root string) ([]string, error)
|
||||
}
|
||||
|
||||
// ProdWalker implements Walker using gocodewalker.
|
||||
type ProdWalker struct{}
|
||||
|
||||
// Walk scans the given root directory using gocodewalker and returns a slice of file paths.
|
||||
func (pw ProdWalker) Walk(root string) ([]string, error) {
|
||||
fileListQueue := make(chan *gocodewalker.File, 100)
|
||||
fileWalker := gocodewalker.NewFileWalker(root, fileListQueue)
|
||||
|
||||
errorHandler := func(err error) bool {
|
||||
logrus.Errorf("error walking directory: %s", err.Error())
|
||||
return true
|
||||
}
|
||||
fileWalker.SetErrorHandler(errorHandler)
|
||||
go func() {
|
||||
err := fileWalker.Start()
|
||||
if err != nil {
|
||||
logrus.Errorf("error walking directory: %s", err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
var files []string
|
||||
for f := range fileListQueue {
|
||||
files = append(files, f.Location)
|
||||
}
|
||||
|
||||
return files, nil
|
||||
}
|
||||
21
fileproc/writer.go
Normal file
21
fileproc/writer.go
Normal file
@@ -0,0 +1,21 @@
|
||||
// Package fileproc provides functions for writing file contents concurrently.
|
||||
package fileproc
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// StartWriter listens on the write channel and writes content to outFile.
|
||||
// When finished, it signals on the done channel.
|
||||
func StartWriter(outFile *os.File, writeCh <-chan WriteRequest, done chan<- struct{}) {
|
||||
writer := io.Writer(outFile)
|
||||
for req := range writeCh {
|
||||
if _, err := writer.Write([]byte(req.Content)); err != nil {
|
||||
logrus.Errorf("Error writing to file: %v", err)
|
||||
}
|
||||
}
|
||||
done <- struct{}{}
|
||||
}
|
||||
31
fileproc/writer_test.go
Normal file
31
fileproc/writer_test.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package fileproc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStartWriter(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
|
||||
writeCh := make(chan WriteRequest)
|
||||
done := make(chan struct{})
|
||||
|
||||
go StartWriter(&buf, writeCh, done)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
writeCh <- WriteRequest{Content: "Hello"}
|
||||
writeCh <- WriteRequest{Content: " World"}
|
||||
}()
|
||||
wg.Wait()
|
||||
close(writeCh)
|
||||
<-done
|
||||
|
||||
if buf.String() != "Hello World" {
|
||||
t.Errorf("Expected 'Hello World', got '%s'", buf.String())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user