mirror of
https://github.com/rclone/rclone.git
synced 2024-11-22 13:26:11 +08:00
cmd/ncdu: highlight read errors instead of aborting - fixes #4014
When a directory cannot be walk-ed because of a permissions error - or any error for that matter -, ncdu mode keeps track of the error and highlights directories that could not be read. Previously, the error would cause ncdu to abort. Now, directories with unreadable sub-directories are displayed in yellow and a message warns that the total may be underestimated. Unreadable directories themselves are displayed in red along with the error message
This commit is contained in:
parent
55aec19389
commit
f7fe1d766b
|
@ -281,7 +281,7 @@ func (u *UI) biggestEntry() (biggest int64) {
|
|||
return
|
||||
}
|
||||
for i := range u.entries {
|
||||
size, _, _, _ := u.d.AttrI(u.sortPerm[i])
|
||||
size, _, _, _, _, _ := u.d.AttrI(u.sortPerm[i])
|
||||
if size > biggest {
|
||||
biggest = size
|
||||
}
|
||||
|
@ -326,12 +326,18 @@ func (u *UI) Draw() error {
|
|||
if y >= h-1 {
|
||||
break
|
||||
}
|
||||
size, count, isDir, readable, entriesHaveErrors, err := u.d.AttrI(u.sortPerm[n])
|
||||
fg := termbox.ColorWhite
|
||||
if entriesHaveErrors {
|
||||
fg = termbox.ColorYellow
|
||||
}
|
||||
if err != nil {
|
||||
fg = termbox.ColorRed
|
||||
}
|
||||
bg := termbox.ColorBlack
|
||||
if n == dirPos.entry {
|
||||
fg, bg = bg, fg
|
||||
}
|
||||
size, count, isDir, readable := u.d.AttrI(u.sortPerm[n])
|
||||
mark := ' '
|
||||
if isDir {
|
||||
mark = '/'
|
||||
|
@ -340,6 +346,12 @@ func (u *UI) Draw() error {
|
|||
if !readable {
|
||||
message = " [not read yet]"
|
||||
}
|
||||
if entriesHaveErrors {
|
||||
message = " [some subdirectories could not be read, size may be underestimated]"
|
||||
}
|
||||
if err != nil {
|
||||
message = fmt.Sprintf(" [%s]", err)
|
||||
}
|
||||
extras := ""
|
||||
if u.showCounts {
|
||||
if count > 0 {
|
||||
|
@ -512,8 +524,8 @@ 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])
|
||||
isize, icount, _, _, _, _ := ds.d.AttrI(ds.sortPerm[i])
|
||||
jsize, jcount, _, _, _, _ := 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)
|
||||
|
|
|
@ -13,13 +13,15 @@ import (
|
|||
|
||||
// Dir represents a directory found in the remote
|
||||
type Dir struct {
|
||||
parent *Dir
|
||||
path string
|
||||
mu sync.Mutex
|
||||
count int64
|
||||
size int64
|
||||
entries fs.DirEntries
|
||||
dirs map[string]*Dir
|
||||
parent *Dir
|
||||
path string
|
||||
mu sync.Mutex
|
||||
count int64
|
||||
size int64
|
||||
entries fs.DirEntries
|
||||
dirs map[string]*Dir
|
||||
readError error
|
||||
entriesHaveErrors bool
|
||||
}
|
||||
|
||||
// Parent returns the directory above this one
|
||||
|
@ -35,12 +37,13 @@ func (d *Dir) Path() string {
|
|||
}
|
||||
|
||||
// make a new directory
|
||||
func newDir(parent *Dir, dirPath string, entries fs.DirEntries) *Dir {
|
||||
func newDir(parent *Dir, dirPath string, entries fs.DirEntries, err error) *Dir {
|
||||
d := &Dir{
|
||||
parent: parent,
|
||||
path: dirPath,
|
||||
entries: entries,
|
||||
dirs: make(map[string]*Dir),
|
||||
parent: parent,
|
||||
path: dirPath,
|
||||
entries: entries,
|
||||
dirs: make(map[string]*Dir),
|
||||
readError: err,
|
||||
}
|
||||
// Count size in this dir
|
||||
for _, entry := range entries {
|
||||
|
@ -61,6 +64,9 @@ func newDir(parent *Dir, dirPath string, entries fs.DirEntries) *Dir {
|
|||
parent.mu.Lock()
|
||||
parent.count += d.count
|
||||
parent.size += d.size
|
||||
if d.readError != nil {
|
||||
parent.entriesHaveErrors = true
|
||||
}
|
||||
parent.mu.Unlock()
|
||||
}
|
||||
return d
|
||||
|
@ -145,18 +151,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, isDir bool, readable bool) {
|
||||
func (d *Dir) AttrI(i int) (size int64, count int64, isDir bool, readable bool, entriesHaveErrors bool, err error) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
subDir, isDir := d.getDir(i)
|
||||
|
||||
if !isDir {
|
||||
return d.entries[i].Size(), 0, false, true
|
||||
return d.entries[i].Size(), 0, false, true, d.entriesHaveErrors, d.readError
|
||||
}
|
||||
if subDir == nil {
|
||||
return 0, 0, true, false
|
||||
return 0, 0, true, false, false, nil
|
||||
}
|
||||
size, count = subDir.Attr()
|
||||
return size, count, true, true
|
||||
return size, count, true, true, subDir.entriesHaveErrors, subDir.readError
|
||||
}
|
||||
|
||||
// Scan the Fs passed in, returning a root directory channel and an
|
||||
|
@ -169,9 +176,6 @@ func Scan(ctx context.Context, f fs.Fs) (chan *Dir, chan error, chan struct{}) {
|
|||
go func() {
|
||||
parents := map[string]*Dir{}
|
||||
err := walk.Walk(ctx, f, "", false, ci.MaxDepth, func(dirPath string, entries fs.DirEntries, err error) error {
|
||||
if err != nil {
|
||||
return err // FIXME mark directory as errored instead of aborting
|
||||
}
|
||||
var parent *Dir
|
||||
if dirPath != "" {
|
||||
parentPath := path.Dir(dirPath)
|
||||
|
@ -184,7 +188,7 @@ func Scan(ctx context.Context, f fs.Fs) (chan *Dir, chan error, chan struct{}) {
|
|||
errChan <- errors.Errorf("couldn't find parent for %q", dirPath)
|
||||
}
|
||||
}
|
||||
d := newDir(parent, dirPath, entries)
|
||||
d := newDir(parent, dirPath, entries, err)
|
||||
parents[dirPath] = d
|
||||
if dirPath == "" {
|
||||
root <- d
|
||||
|
|
Loading…
Reference in New Issue
Block a user