Skip to content

Commit

Permalink
feat: show top largest files
Browse files Browse the repository at this point in the history
  • Loading branch information
dundee committed Nov 30, 2024
1 parent 8c2680b commit b8c9820
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 19 deletions.
2 changes: 2 additions & 0 deletions cmd/gdu/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ type Flags struct {
StoragePath string `yaml:"storage-path"`
ReadFromStorage bool `yaml:"read-from-storage"`
Summarize bool `yaml:"summarize"`
Top int `yaml:"top"`
UseSIPrefix bool `yaml:"use-si-prefix"`
NoPrefix bool `yaml:"no-prefix"`
WriteConfig bool `yaml:"-"`
Expand Down Expand Up @@ -242,6 +243,7 @@ func (a *App) createUI() (UI, error) {
a.Flags.ConstGC,
a.Flags.UseSIPrefix,
a.Flags.NoPrefix,
a.Flags.Top,
)
if a.Flags.NoUnicode {
stdoutUI.UseOldProgressRunes()
Expand Down
1 change: 1 addition & 0 deletions cmd/gdu/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ func init() {
flags.BoolVarP(&af.NoProgress, "no-progress", "p", false, "Do not show progress in non-interactive mode")
flags.BoolVarP(&af.NoUnicode, "no-unicode", "u", false, "Do not use Unicode symbols (for size bar)")
flags.BoolVarP(&af.Summarize, "summarize", "s", false, "Show only a total in non-interactive mode")
flags.IntVarP(&af.Top, "top", "t", 0, "Show only top X largest files in non-interactive mode")
flags.BoolVar(&af.UseSIPrefix, "si", false, "Show sizes with decimal SI prefixes (kB, MB, GB) instead of binary prefixes (KiB, MiB, GiB)")
flags.BoolVar(&af.NoPrefix, "no-prefix", false, "Show sizes as raw numbers without any prefixes (SI or binary) in non-interactive mode")
flags.BoolVar(&af.NoMouse, "no-mouse", false, "Do not use mouse")
Expand Down
55 changes: 55 additions & 0 deletions pkg/analyze/top.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package analyze

import (
"sort"

"github.com/dundee/gdu/v5/pkg/fs"
)

// TopList is a list of top largest files
type TopList struct {
Count int
Items fs.Files
MinSize int64
}

// NewTopList creates new TopList
func NewTopList(count int) *TopList {
return &TopList{Count: count}
}

// Add adds file to the list
func (tl *TopList) Add(file fs.Item) {
if len(tl.Items) < tl.Count {
tl.Items = append(tl.Items, file)
if file.GetSize() > tl.MinSize {
tl.MinSize = file.GetSize()
}
} else {

Check failure on line 28 in pkg/analyze/top.go

View workflow job for this annotation

GitHub Actions / lint

elseif: can replace 'else {if cond {}}' with 'else if cond {}' (gocritic)
if file.GetSize() > tl.MinSize {
tl.Items = append(tl.Items, file)
tl.MinSize = file.GetSize()
if len(tl.Items) > tl.Count {
sort.Sort(fs.ByApparentSize(tl.Items))
tl.Items = tl.Items[1:]
}
}
}
}

func CollectTopFiles(dir fs.Item, count int) fs.Files {
topList := NewTopList(count)
walkDir(dir, topList)
sort.Sort(sort.Reverse(fs.ByApparentSize(topList.Items)))
return topList.Items
}

func walkDir(dir fs.Item, topList *TopList) {
for _, item := range dir.GetFiles() {
if item.IsDir() {
walkDir(item, topList)
} else {
topList.Add(item)
}
}
}
38 changes: 38 additions & 0 deletions pkg/analyze/top_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package analyze

import (
"testing"

"github.com/dundee/gdu/v5/internal/testdir"
"github.com/stretchr/testify/assert"
)

func TestCollectTopFiles2(t *testing.T) {
fin := testdir.CreateTestDir()
defer fin()

dir := CreateAnalyzer().AnalyzeDir(
"test_dir", func(_, _ string) bool { return false }, false,
)

topFiles := CollectTopFiles(dir, 2)
assert.Equal(t, 2, len(topFiles))
assert.Equal(t, "file", topFiles[0].GetName())
assert.Equal(t, int64(5), topFiles[0].GetSize())
assert.Equal(t, "file2", topFiles[1].GetName())
assert.Equal(t, int64(2), topFiles[1].GetSize())
}

func TestCollectTopFiles1(t *testing.T) {
fin := testdir.CreateTestDir()
defer fin()

dir := CreateAnalyzer().AnalyzeDir(
"test_dir", func(_, _ string) bool { return false }, false,
)

topFiles := CollectTopFiles(dir, 1)
assert.Equal(t, 1, len(topFiles))
assert.Equal(t, "file", topFiles[0].GetName())
assert.Equal(t, int64(5), topFiles[0].GetSize())
}
39 changes: 37 additions & 2 deletions stdout/stdout.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type UI struct {
blue *color.Color
summarize bool
noPrefix bool
top int
}

var (
Expand All @@ -45,6 +46,7 @@ func CreateStdoutUI(
constGC bool,
useSIPrefix bool,
noPrefix bool,
top int,
) *UI {
ui := &UI{
UI: &common.UI{
Expand All @@ -59,6 +61,7 @@ func CreateStdoutUI(
output: output,
summarize: summarize,
noPrefix: noPrefix,
top: top,
}

ui.red = color.New(color.FgRed).Add(color.Bold)
Expand Down Expand Up @@ -167,7 +170,9 @@ func (ui *UI) AnalyzePath(path string, _ fs.Item) error {

wait.Wait()

if ui.summarize {
if ui.top > 0 {
ui.printTopFiles(dir)
} else if ui.summarize {
ui.printTotalItem(dir)
} else {
ui.showDir(dir)
Expand All @@ -187,7 +192,9 @@ func (ui *UI) ReadFromStorage(storagePath, path string) error {
return err
}

if ui.summarize {
if ui.top > 0 {
ui.printTopFiles(dir)
} else if ui.summarize {
ui.printTotalItem(dir)
} else {
ui.showDir(dir)
Expand All @@ -203,6 +210,13 @@ func (ui *UI) showDir(dir fs.Item) {
}
}

func (ui *UI) printTopFiles(file fs.Item) {
collected := analyze.CollectTopFiles(file, ui.top)
for _, file := range collected {
ui.printItemPath(file)
}
}

func (ui *UI) printTotalItem(file fs.Item) {
var lineFormat string
if ui.UseColors {
Expand Down Expand Up @@ -256,6 +270,27 @@ func (ui *UI) printItem(file fs.Item) {
}
}

func (ui *UI) printItemPath(file fs.Item) {
var lineFormat string
if ui.UseColors {
lineFormat = "%20s %s\n"
} else {
lineFormat = "%9s %s\n"
}

var size int64
if ui.ShowApparentSize {
size = file.GetSize()
} else {
size = file.GetUsage()
}

fmt.Fprintf(ui.output,
lineFormat,
ui.formatSize(size),
file.GetPath())
}

// ReadAnalysis reads analysis report from JSON file
func (ui *UI) ReadAnalysis(input io.Reader) error {
var (
Expand Down
Loading

0 comments on commit b8c9820

Please sign in to comment.