ncdu: refactor accumulated attributes into a struct

This commit is contained in:
albertony 2022-04-11 17:06:01 +02:00
parent a15885dd74
commit 97606bbdef
2 changed files with 68 additions and 47 deletions

View File

@ -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

View File

@ -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