Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 96 additions & 35 deletions cmd/clean.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bufio"
"context"
"fmt"
"io"
"os"
"os/exec"
"path"
Expand All @@ -14,11 +15,24 @@ import (
"github.com/bruin-data/bruin/pkg/git"
"github.com/bruin-data/bruin/pkg/telemetry"
"github.com/bruin-data/bruin/pkg/user"
"github.com/fatih/color"
"github.com/pkg/errors"
"github.com/spf13/afero"
"github.com/urfave/cli/v3"
)

type colorPrinter struct {
c *color.Color
}

func (p *colorPrinter) Printf(format string, args ...interface{}) {
p.c.Printf(format, args...) // ignore return values
}

func (p *colorPrinter) Println(args ...interface{}) {
p.c.Println(args...)
}

func CleanCmd() *cli.Command {
return &cli.Command{
Name: "clean",
Expand All @@ -37,71 +51,118 @@ func CleanCmd() *cli.Command {
inputPath = "."
}

r := CleanCommand{
infoPrinter: infoPrinter,
errorPrinter: errorPrinter,
r := NewCleanCommand(
user.NewConfigManager(afero.NewOsFs()), // cm
&git.RepoFinder{}, // gitFinder
afero.NewOsFs(), // fs
&colorPrinter{c: color.New(color.FgGreen)}, // infoPrinter
&colorPrinter{c: color.New(color.FgRed)}, // errorPrinter
)

err := r.Run(inputPath, c.Bool("uv-cache"))
if err != nil {
return cli.Exit("", 1)
}

return r.Run(inputPath, c.Bool("uv-cache"))
return nil
},
Before: telemetry.BeforeCommand,
After: telemetry.AfterCommand,
}
}

type ConfigManager interface {
EnsureAndGetBruinHomeDir() (string, error)
RecreateHomeDir() error
}

type GitFinder interface {
Repo(path string) (*git.Repo, error)
}

type Printer interface {
Printf(format string, a ...interface{})
Println(a ...interface{})
}

type CleanCommand struct {
infoPrinter printer
errorPrinter printer
cm ConfigManager
gitFinder GitFinder
fs afero.Fs
infoPrinter Printer
errorPrinter Printer
}

func NewCleanCommand(cm ConfigManager, gitFinder GitFinder, fs afero.Fs, info Printer, errPrinter Printer) *CleanCommand {
return &CleanCommand{
cm: cm,
gitFinder: gitFinder,
fs: fs,
infoPrinter: info,
errorPrinter: errPrinter,
}
}

func (r *CleanCommand) Run(inputPath string, cleanUvCache bool) error {
cm := user.NewConfigManager(afero.NewOsFs())
bruinHomeDirAbsPath, err := cm.EnsureAndGetBruinHomeDir()
bruinHomeDir, err := r.cm.EnsureAndGetBruinHomeDir()
if err != nil {
return errors.Wrap(err, "failed to get bruin home directory")
}

// Clean uv caches if requested
if cleanUvCache {
if err := r.cleanUvCache(bruinHomeDirAbsPath); err != nil {
if err := r.cleanUvCache(bruinHomeDir); err != nil {
return err
}
}

err = cm.RecreateHomeDir()
if err != nil {
if err := r.cm.RecreateHomeDir(); err != nil {
return errors.Wrap(err, "failed to recreate the home directory")
}

repoRoot, err := git.FindRepoFromPath(inputPath)
repoRoot, err := r.gitFinder.Repo(inputPath)
if err != nil {
errorPrinter.Printf("Failed to find the git repository root: %v\n", err)
return cli.Exit("", 1)
r.errorPrinter.Printf("Failed to find the git repository root: %v\n", err)
return errors.Wrap(err, "failed to find the git repository root")
}

logsFolder := path.Join(repoRoot.Path, LogsFolder)

contents, err := filepath.Glob(logsFolder + "/*.log")
// Check if logs folder exists
exists, err := afero.Exists(r.fs, logsFolder)
if err != nil {
return errors.Wrap(err, "failed to find the logs folder")
return errors.Wrap(err, "failed to check logs folder")
}

if len(contents) == 0 {
infoPrinter.Println("No log files found, nothing to clean up...")
if !exists {
r.infoPrinter.Println("No log files found, nothing to clean up...")
return nil
}

infoPrinter.Printf("Found %d log files, cleaning them up...\n", len(contents))
// Read directory contents
entries, err := afero.ReadDir(r.fs, logsFolder)
if err != nil {
return errors.Wrap(err, "failed to read logs folder")
}

for _, f := range contents {
err := os.Remove(f)
if err != nil {
return errors.Wrapf(err, "failed to remove file: %s", f)
// Filter for .log files
var logFiles []string
for _, entry := range entries {
if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".log") {
logFiles = append(logFiles, path.Join(logsFolder, entry.Name()))
}
}

infoPrinter.Printf("Successfully removed %d log files.\n", len(contents))
if len(logFiles) == 0 {
r.infoPrinter.Println("No log files found, nothing to clean up...")
return nil
}

r.infoPrinter.Printf("Found %d log files, cleaning them up...\n", len(logFiles))
for _, f := range logFiles {
if err := r.fs.Remove(f); err != nil {
return errors.Wrapf(err, "failed to remove file: %s", f)
}
}
r.infoPrinter.Printf("Successfully removed %d log files.\n", len(logFiles))
return nil
}

Expand All @@ -116,7 +177,7 @@ func (r *CleanCommand) cleanUvCache(bruinHomeDirAbsPath string) error {

// Check if uv binary exists
if _, err := os.Stat(uvBinaryPath); os.IsNotExist(err) {
infoPrinter.Println("UV is not installed yet. Nothing to clean.")
r.infoPrinter.Println("UV is not installed yet. Nothing to clean.")
return nil
}

Expand All @@ -127,30 +188,30 @@ func (r *CleanCommand) cleanUvCache(bruinHomeDirAbsPath string) error {
}

// Prompt user for confirmation
if !r.confirmUvCacheClean() {
infoPrinter.Println("UV cache cleaning cancelled by user.")
if !r.confirmUvCacheClean(os.Stdin) {
r.infoPrinter.Println("UV cache cleaning cancelled by user.")
return nil
}

infoPrinter.Println("Cleaning uv caches...")
r.infoPrinter.Println("Cleaning uv caches...")

cleanCmd := exec.Command(uvBinaryPath, "cache", "clean")
output, err := cleanCmd.CombinedOutput()
if err != nil {
return errors.Wrapf(err, "failed to clean uv cache: %s", string(output))
}

infoPrinter.Println("Successfully cleaned uv caches.")
r.infoPrinter.Println("Successfully cleaned uv caches.")
return nil
}

func (r *CleanCommand) confirmUvCacheClean() bool {
reader := bufio.NewReader(os.Stdin)
func (r *CleanCommand) confirmUvCacheClean(reader io.Reader) bool {
bufReader := bufio.NewReader(reader)
fmt.Print("Are you sure you want to clean uv cache? (y/N): ")

response, err := reader.ReadString('\n')
response, err := bufReader.ReadString('\n')
if err != nil {
errorPrinter.Printf("Error reading input: %v\n", err)
r.errorPrinter.Printf("Error reading input: %v\n", err)
return false
}

Expand Down
Loading
Loading