From 97606bbdef90bebe240d9d4603cbbacf17e06e36 Mon Sep 17 00:00:00 2001 From: albertony <12441419+albertony@users.noreply.github.com> Date: Mon, 11 Apr 2022 17:06:01 +0200 Subject: [PATCH] ncdu: refactor accumulated attributes into a struct --- cmd/ncdu/ncdu.go | 78 ++++++++++++++++++++----------------------- cmd/ncdu/scan/scan.go | 37 +++++++++++++++++--- 2 files changed, 68 insertions(+), 47 deletions(-) diff --git a/cmd/ncdu/ncdu.go b/cmd/ncdu/ncdu.go index 6dfafa5ef..6359184b5 100644 --- a/cmd/ncdu/ncdu.go +++ b/cmd/ncdu/ncdu.go @@ -299,9 +299,9 @@ func (u *UI) biggestEntry() (biggest int64) { return } for i := range u.entries { - size, _, _, _, _, _, _ := u.d.AttrI(u.sortPerm[i]) - if size > biggest { - biggest = size + attrs, _ := u.d.AttrI(u.sortPerm[i]) + if attrs.Size > biggest { + biggest = attrs.Size } } return @@ -313,8 +313,8 @@ func (u *UI) hasEmptyDir() bool { return false } for i := range u.entries { - _, count, _, isDir, _, _, _ := u.d.AttrI(u.sortPerm[i]) - if isDir && count == 0 { + attrs, _ := u.d.AttrI(u.sortPerm[i]) + if attrs.IsDir && attrs.Count == 0 { return true } } @@ -359,9 +359,9 @@ func (u *UI) Draw() error { if y >= h-1 { break } - size, count, countUnknownSize, isDir, readable, entriesHaveErrors, err := u.d.AttrI(u.sortPerm[n]) + attrs, err := u.d.AttrI(u.sortPerm[n]) fg := termbox.ColorWhite - if entriesHaveErrors { + if attrs.EntriesHaveErrors { fg = termbox.ColorYellow } if err != nil { @@ -372,19 +372,19 @@ func (u *UI) Draw() error { fg, bg = bg, fg } mark := ' ' - if isDir { + if attrs.IsDir { mark = '/' } fileFlag := ' ' message := "" - if !readable { + if !attrs.Readable { message = " [not read yet]" } - if countUnknownSize > 0 { - message = fmt.Sprintf(" [%d of %d files have unknown size, size may be underestimated]", countUnknownSize, count) + if attrs.CountUnknownSize > 0 { + message = fmt.Sprintf(" [%d of %d files have unknown size, size may be underestimated]", attrs.CountUnknownSize, attrs.Count) fileFlag = '~' } - if entriesHaveErrors { + if attrs.EntriesHaveErrors { message = " [some subdirectories could not be read, size may be underestimated]" fileFlag = '.' } @@ -394,35 +394,29 @@ func (u *UI) Draw() error { } extras := "" if u.showCounts { - ss := operations.CountStringField(count, u.humanReadable, 9) + " " - if count > 0 { + ss := operations.CountStringField(attrs.Count, u.humanReadable, 9) + " " + if attrs.Count > 0 { extras += ss } else { extras += strings.Repeat(" ", len(ss)) } } - var averageSize float64 - if count > 0 { - countForAverage := count - countUnknownSize - if countForAverage > 0 { - averageSize = float64(size) / float64(countForAverage) - } - } if u.showDirAverageSize { - ss := operations.SizeStringField(int64(averageSize), u.humanReadable, 9) + " " - if averageSize > 0 { + avg := attrs.AverageSize() + ss := operations.SizeStringField(int64(avg), u.humanReadable, 9) + " " + if avg > 0 { extras += ss } else { extras += strings.Repeat(" ", len(ss)) } } if showEmptyDir { - if isDir && count == 0 && fileFlag == ' ' { + if attrs.IsDir && attrs.Count == 0 && fileFlag == ' ' { fileFlag = 'e' } } if u.showGraph { - bars := (size + perBar/2 - 1) / perBar + bars := (attrs.Size + perBar/2 - 1) / perBar // clip if necessary - only happens during startup if bars > 10 { bars = 10 @@ -431,7 +425,7 @@ func (u *UI) Draw() error { } extras += "[" + graph[graphBars-bars:2*graphBars-bars] + "] " } - Linef(0, y, w, fg, bg, ' ', "%c %s %s%c%s%s", fileFlag, operations.SizeStringField(size, u.humanReadable, 12), extras, mark, path.Base(entry.Remote()), message) + Linef(0, y, w, fg, bg, ' ', "%c %s %s%c%s%s", fileFlag, operations.SizeStringField(attrs.Size, u.humanReadable, 12), extras, mark, path.Base(entry.Remote()), message) y++ } } @@ -582,14 +576,14 @@ type ncduSort struct { // Less is part of sort.Interface. func (ds *ncduSort) Less(i, j int) bool { var iAvgSize, jAvgSize float64 - isize, icount, _, _, _, _, _ := ds.d.AttrI(ds.sortPerm[i]) - jsize, jcount, _, _, _, _, _ := ds.d.AttrI(ds.sortPerm[j]) + iattrs, _ := ds.d.AttrI(ds.sortPerm[i]) + jattrs, _ := ds.d.AttrI(ds.sortPerm[j]) iname, jname := ds.entries[ds.sortPerm[i]].Remote(), ds.entries[ds.sortPerm[j]].Remote() - if icount > 0 { - iAvgSize = float64(isize / icount) + if iattrs.Count > 0 { + iAvgSize = iattrs.AverageSize() } - if jcount > 0 { - jAvgSize = float64(jsize / jcount) + if jattrs.Count > 0 { + jAvgSize = jattrs.AverageSize() } switch { @@ -598,33 +592,33 @@ func (ds *ncduSort) Less(i, j int) bool { case ds.u.sortByName > 0: break case ds.u.sortBySize < 0: - if isize != jsize { - return isize < jsize + if iattrs.Size != jattrs.Size { + return iattrs.Size < jattrs.Size } case ds.u.sortBySize > 0: - if isize != jsize { - return isize > jsize + if iattrs.Size != jattrs.Size { + return iattrs.Size > jattrs.Size } case ds.u.sortByCount < 0: - if icount != jcount { - return icount < jcount + if iattrs.Count != jattrs.Count { + return iattrs.Count < jattrs.Count } case ds.u.sortByCount > 0: - if icount != jcount { - return icount > jcount + if iattrs.Count != jattrs.Count { + return iattrs.Count > jattrs.Count } case ds.u.sortByAverageSize < 0: if iAvgSize != jAvgSize { return iAvgSize < jAvgSize } // if avgSize is equal, sort by size - return isize < jsize + return iattrs.Size < jattrs.Size case ds.u.sortByAverageSize > 0: if iAvgSize != jAvgSize { return iAvgSize > jAvgSize } // if avgSize is equal, sort by size - return isize > jsize + return iattrs.Size > jattrs.Size } // if everything equal, sort by name return iname < jname diff --git a/cmd/ncdu/scan/scan.go b/cmd/ncdu/scan/scan.go index 70f65d405..3b391ff53 100644 --- a/cmd/ncdu/scan/scan.go +++ b/cmd/ncdu/scan/scan.go @@ -25,6 +25,33 @@ type Dir struct { entriesHaveErrors bool } +// Attrs contains accumulated properties for a directory entry +// +// Files with unknown size are counted separately but also included +// in the total count. They are not included in the size, i.e. treated +// as empty files, which means the size may be underestimated. +type Attrs struct { + Size int64 + Count int64 + CountUnknownSize int64 + IsDir bool + Readable bool + EntriesHaveErrors bool +} + +// AverageSize calculates average size of files in directory +// +// If there are files with unknown size, this returns the average over +// files with known sizes, which means it may be under- or +// overestimated. +func (a *Attrs) AverageSize() float64 { + countKnownSize := a.Count - a.CountUnknownSize + if countKnownSize > 0 { + return float64(a.Size) / float64(countKnownSize) + } + return 0 +} + // Parent returns the directory above this one func (d *Dir) Parent() *Dir { // no locking needed since these are write once in newDir() @@ -167,19 +194,19 @@ func (d *Dir) Attr() (size int64, count int64) { } // AttrI returns the size, count and flags for the i-th directory entry -func (d *Dir) AttrI(i int) (size int64, count int64, countUnknownSize int64, isDir bool, readable bool, entriesHaveErrors bool, err error) { +func (d *Dir) AttrI(i int) (attrs Attrs, err error) { d.mu.Lock() defer d.mu.Unlock() subDir, isDir := d.getDir(i) if !isDir { - return d.entries[i].Size(), 0, 0, false, true, d.entriesHaveErrors, d.readError + return Attrs{d.entries[i].Size(), 0, 0, false, true, d.entriesHaveErrors}, d.readError } if subDir == nil { - return 0, 0, 0, true, false, false, nil + return Attrs{0, 0, 0, true, false, false}, nil } - size, count = subDir.Attr() - return size, count, subDir.countUnknownSize, true, true, subDir.entriesHaveErrors, subDir.readError + size, count := subDir.Attr() + return Attrs{size, count, subDir.countUnknownSize, true, true, subDir.entriesHaveErrors}, subDir.readError } // Scan the Fs passed in, returning a root directory channel and an