Skip to content

Commit

Permalink
Show cleanable size on dry run (#4)
Browse files Browse the repository at this point in the history
* Enhance dry-run functionality: Calculate and display total cleanable size and paths

* Add test for calculating cleanable size in dry-run mode

* Refactor setup_test_env.sh: Replace echo with dd for file creation

* Update test script to support dry-run and actual execution modes
  • Loading branch information
itSubeDibesh authored Nov 12, 2024
1 parent 8402c1e commit 8639905
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 44 deletions.
92 changes: 89 additions & 3 deletions cleaner_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package main

import (
"os"
"path/filepath"
"runtime"
"sync"
"testing"
)

Expand Down Expand Up @@ -31,12 +35,9 @@ func TestShouldRemoveFile(t *testing.T) {
matchRegex bool
want bool
}{
// Non-regex cases
{"program.exe", []string{".exe", ".dll", ".tmp"}, false, true},
{"tempfile.tmp", []string{".exe", ".dll", ".tmp"}, false, true},
{"document.txt", []string{".exe", ".dll", ".tmp"}, false, false},

// Regex cases
{"tempfile.log", []string{`temp.*\.log`}, true, true},
{"logfile.log", []string{`temp.*\.log`}, true, false},
{"debug_info.txt", []string{`debug_.*\.txt`}, true, true},
Expand Down Expand Up @@ -81,3 +82,88 @@ func TestLoadConfig(t *testing.T) {
t.Error("Expected default FileExtensionsToRemove to be non-empty")
}
}

func TestCalculateCleanableSizeDryRun(t *testing.T) {
rootDir := "test_dir"

// Remove existing test directory if it exists to ensure a clean setup
if _, err := os.Stat(rootDir); err == nil {
err := os.RemoveAll(rootDir)
if err != nil {
t.Fatalf("Failed to remove existing test directory: %v", err)
}
}

// Create a fresh test directory
err := os.Mkdir(rootDir, 0755)
if err != nil {
t.Fatalf("Failed to create test root directory: %v", err)
}
defer os.RemoveAll(rootDir) // Clean up after the test

// List of paths to create and check for size
filesToRemove := []string{
filepath.Join(rootDir, "node_modules", "module.js"),
filepath.Join(rootDir, "dist", "bundle.js"),
filepath.Join(rootDir, "build", "output.o"),
filepath.Join(rootDir, "tempfile.log"),
}

// Create files and directories for the test
for _, path := range filesToRemove {
err := os.MkdirAll(filepath.Dir(path), 0755)
if err != nil {
t.Fatalf("Failed to create directory for %s: %v", path, err)
}
err = os.WriteFile(path, []byte("sample data"), 0644)
if err != nil {
t.Fatalf("Failed to create file %s: %v", path, err)
}
}

config := &Config{
DirectoriesToRemove: []string{"node_modules", "dist", "build"},
FileExtensionsToRemove: []string{".log"},
ExcludeDirectories: []string{".git"},
ExcludeFiles: []string{},
MatchRegex: true,
}

var wg sync.WaitGroup
var paths []string
var totalSize int64
var totalSizeMutex sync.Mutex
logMutex := &sync.Mutex{}
consoleMutex := &sync.Mutex{}
semaphore := make(chan struct{}, runtime.NumCPU())

wg.Add(1)
go walkDir(rootDir, config, true, true, "text", &wg, semaphore, nil, logMutex, consoleMutex, &totalSize, &totalSizeMutex, &paths)
wg.Wait()

// Expected paths to delete
expectedPaths := []string{
filepath.Join(rootDir, "node_modules"),
filepath.Join(rootDir, "dist"),
filepath.Join(rootDir, "build"),
filepath.Join(rootDir, "tempfile.log"),
}

// Compare actual paths with expected paths
if len(paths) != len(expectedPaths) {
t.Fatalf("Expected %d paths, but got %d paths", len(expectedPaths), len(paths))
}

for _, expectedPath := range expectedPaths {
found := false
for _, path := range paths {
if path == expectedPath {
found = true
break
}
}
if !found {
t.Errorf("Expected path %s was not found in the paths to delete", expectedPath)
}
}
}
87 changes: 67 additions & 20 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,21 @@ func main() {
var logMutex sync.Mutex
var consoleMutex sync.Mutex

var totalSize int64
var totalSizeMutex sync.Mutex
var paths []string

wg.Add(1)
go walkDir(*rootDir, config, *verbose, *dryRun, *logFormat, &wg, semaphore, logger, &logMutex, &consoleMutex)
go walkDir(*rootDir, config, *verbose, *dryRun, *logFormat, &wg, semaphore, logger, &logMutex, &consoleMutex, &totalSize, &totalSizeMutex, &paths)

wg.Wait()
fmt.Println("Cleaning process completed.")

if *dryRun {
fmt.Printf("Total cleanable size: %.2f MB\n", float64(totalSize)/(1024*1024))
fmt.Println("Paths that would be removed:", paths)
} else {
fmt.Println("Cleaning process completed.")
}
}

func getDefaultConfig() *Config {
Expand Down Expand Up @@ -102,7 +112,19 @@ func loadConfig(configPath string) (*Config, error) {
return &config, nil
}

func walkDir(dir string, config *Config, verbose, dryRun bool, logFormat string, wg *sync.WaitGroup, semaphore chan struct{}, logger *log.Logger, logMutex, consoleMutex *sync.Mutex) {
func walkDir(
dir string,
config *Config,
verbose, dryRun bool,
logFormat string,
wg *sync.WaitGroup,
semaphore chan struct{},
logger *log.Logger,
logMutex, consoleMutex *sync.Mutex,
totalSize *int64,
totalSizeMutex *sync.Mutex,
paths *[]string, // New parameter to collect paths during dry-run
) {
defer wg.Done()

semaphore <- struct{}{}
Expand All @@ -126,13 +148,22 @@ func walkDir(dir string, config *Config, verbose, dryRun bool, logFormat string,
}

if shouldRemoveDir(entryName, config.DirectoriesToRemove) {
if verbose {
consoleMutex.Lock()
fmt.Printf("Detected directory to remove: %s\n", entryPath)
consoleMutex.Unlock()
}
dirSize := calculateSize(entryPath)
totalSizeMutex.Lock()
*totalSize += dirSize
totalSizeMutex.Unlock()

if !dryRun {
if dryRun {
if verbose {
consoleMutex.Lock()
fmt.Printf("[Dry Run] Would remove directory: %s (Size: %.2f MB)\n", entryPath, float64(dirSize)/(1024*1024))
consoleMutex.Unlock()
}
*paths = append(*paths, entryPath)
if logger != nil {
logEntry(logger, logMutex, logFormat, "[Dry Run] Would remove directory", entryPath)
}
} else {
err := os.RemoveAll(entryPath)
if err != nil {
consoleMutex.Lock()
Expand All @@ -141,26 +172,33 @@ func walkDir(dir string, config *Config, verbose, dryRun bool, logFormat string,
} else if logger != nil {
logEntry(logger, logMutex, logFormat, "Removed directory", entryPath)
}
} else if logger != nil {
logEntry(logger, logMutex, logFormat, "[Dry Run] Would remove directory", entryPath)
}
} else {
wg.Add(1)
go walkDir(entryPath, config, verbose, dryRun, logFormat, wg, semaphore, logger, logMutex, consoleMutex)
go walkDir(entryPath, config, verbose, dryRun, logFormat, wg, semaphore, logger, logMutex, consoleMutex, totalSize, totalSizeMutex, paths)
}
} else {
if isExcluded(entryName, config.ExcludeFiles) {
continue
}

if shouldRemoveFile(entryName, config.FileExtensionsToRemove, config.MatchRegex) {
if verbose {
consoleMutex.Lock()
fmt.Printf("Detected file to remove: %s\n", entryPath)
consoleMutex.Unlock()
}
fileSize := calculateSize(entryPath)
totalSizeMutex.Lock()
*totalSize += fileSize
totalSizeMutex.Unlock()

if !dryRun {
if dryRun {
if verbose {
consoleMutex.Lock()
fmt.Printf("[Dry Run] Would remove file: %s (Size: %.2f KB)\n", entryPath, float64(fileSize)/1024)
consoleMutex.Unlock()
}
*paths = append(*paths, entryPath)
if logger != nil {
logEntry(logger, logMutex, logFormat, "[Dry Run] Would remove file", entryPath)
}
} else {
err := os.Remove(entryPath)
if err != nil {
consoleMutex.Lock()
Expand All @@ -169,14 +207,23 @@ func walkDir(dir string, config *Config, verbose, dryRun bool, logFormat string,
} else if logger != nil {
logEntry(logger, logMutex, logFormat, "Removed file", entryPath)
}
} else if logger != nil {
logEntry(logger, logMutex, logFormat, "[Dry Run] Would remove file", entryPath)
}
}
}
}
}

func calculateSize(path string) int64 {
var size int64
filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {
if err == nil && info != nil {
size += info.Size()
}
return nil
})
return size
}

func shouldRemoveDir(dirName string, dirsToRemove []string) bool {
for _, name := range dirsToRemove {
if dirName == name {
Expand Down
34 changes: 17 additions & 17 deletions setup_test_env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,34 @@ mkdir -p .git bin build dist node_modules/module src
echo "git config" > .git/config

# Create files in bin (should be removed with regex and non-regex patterns)
echo "binary data" > bin/program.exe
echo "library data" > bin/helper.dll
echo "temporary data" > bin/temp_file.log # Should be removed if matched by regex `temp.*\.log`
echo "debug info" > bin/debug_info.txt # Should be removed if matched by regex `debug_.*\.txt`
dd if=/dev/zero of=bin/program.exe bs=1K count=5 # 5 KB
dd if=/dev/zero of=bin/helper.dll bs=1K count=3 # 3 KB
dd if=/dev/zero of=bin/temp_file.log bs=1K count=1 # 1 KB (matches regex `temp.*\.log`)
dd if=/dev/zero of=bin/debug_info.txt bs=1K count=2 # 2 KB (matches regex `debug_.*\.txt`)

# Create files in build (should be removed)
echo "object file data" > build/output.o
dd if=/dev/zero of=build/output.o bs=1K count=4 # 4 KB

# Create files in dist (should be removed)
echo "app js data" > dist/app.js
dd if=/dev/zero of=dist/app.js bs=1K count=6 # 6 KB

# Create files in node_modules (should be removed)
echo "module code" > node_modules/module/index.js
dd if=/dev/zero of=node_modules/module/index.js bs=1K count=2 # 2 KB

# Create source files (should not be removed)
echo "package main" > src/main.go
echo "package main" > src/utils.go
touch src/.DS_Store # Should be removed
dd if=/dev/zero of=src/.DS_Store bs=1K count=1 # 1 KB (should be removed)

# Create root-level files
echo "ENV variables" > .env # Should not be removed
echo "Project documentation" > README.md # Should not be removed
touch .DS_Store # Should be removed
touch __debug_bin # Should be removed
touch ___debug_bin_1100 # Should be removed
touch app__debug_bin # Should be removed
touch tempfile.log # Should be removed if matched by regex `temp.*\.log`
touch debug_output.txt # Should be removed if matched by regex `debug_.*\.txt`
echo "ENV variables" > .env # Should not be removed
echo "Project documentation" > README.md # Should not be removed
dd if=/dev/zero of=.DS_Store bs=1K count=1 # 1 KB (should be removed)
dd if=/dev/zero of=__debug_bin bs=1K count=1 # 1 KB (should be removed)
dd if=/dev/zero of=___debug_bin_1100 bs=1K count=1 # 1 KB (should be removed)
dd if=/dev/zero of=app__debug_bin bs=1K count=1 # 1 KB (should be removed)
dd if=/dev/zero of=tempfile.log bs=1K count=2 # 2 KB (matches regex `temp.*\.log`)
dd if=/dev/zero of=debug_output.txt bs=1K count=3 # 3 KB (matches regex `debug_.*\.txt`)

# Navigate back to the parent directory
cd ..
cd ..
12 changes: 8 additions & 4 deletions test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@
echo "Setting up Test Environment"
./setup_test_env.sh

# Run the main script
echo "Running Test Script"
go run main.go test_project
# Run the main script in dry-run mode
echo "Running Test Script in Dry-Run Mode"
go run main.go -root=test_project -dry-run -verbose=true

# Run the main script in actual mode (optional if you want to test real deletion)
echo "Running Test Script in Actual Mode"
go run main.go -root=test_project -verbose=true

# Clean up the test environment
echo "Cleaning up Test Environment"
rm -rf test_project
rm cleaned_source.txt
rm -f cleaned_source.txt

# Done
echo "Test Completed"

0 comments on commit 8639905

Please sign in to comment.