summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd/gdu/app/app.go4
-rw-r--r--internal/common/analyze.go21
-rw-r--r--internal/common/ignore.go4
-rw-r--r--internal/common/ui.go4
-rw-r--r--internal/testanalyze/analyze.go12
-rw-r--r--pkg/analyze/dir.go48
-rw-r--r--pkg/analyze/dir_test.go23
-rw-r--r--pkg/analyze/encode_test.go5
-rw-r--r--pkg/analyze/file.go177
-rw-r--r--pkg/analyze/file_test.go29
-rw-r--r--pkg/analyze/sort_test.go25
-rw-r--r--pkg/fs/file.go104
-rw-r--r--report/export.go11
-rw-r--r--report/import.go4
-rw-r--r--stdout/stdout.go21
-rw-r--r--tui/actions.go25
-rw-r--r--tui/actions_test.go29
-rw-r--r--tui/format.go4
-rw-r--r--tui/keys.go6
-rw-r--r--tui/keys_test.go47
-rw-r--r--tui/progress.go3
-rw-r--r--tui/show.go6
-rw-r--r--tui/sort.go22
-rw-r--r--tui/tui.go23
-rw-r--r--tui/tui_test.go11
25 files changed, 363 insertions, 305 deletions
diff --git a/cmd/gdu/app/app.go b/cmd/gdu/app/app.go
index f5a747b..7e67732 100644
--- a/cmd/gdu/app/app.go
+++ b/cmd/gdu/app/app.go
@@ -16,8 +16,8 @@ import (
"github.com/dundee/gdu/v5/build"
"github.com/dundee/gdu/v5/internal/common"
- "github.com/dundee/gdu/v5/pkg/analyze"
"github.com/dundee/gdu/v5/pkg/device"
+ gfs "github.com/dundee/gdu/v5/pkg/fs"
"github.com/dundee/gdu/v5/report"
"github.com/dundee/gdu/v5/stdout"
"github.com/dundee/gdu/v5/tui"
@@ -28,7 +28,7 @@ import (
// UI is common interface for both terminal UI and text output
type UI interface {
ListDevices(getter device.DevicesInfoGetter) error
- AnalyzePath(path string, parentDir *analyze.Dir) error
+ AnalyzePath(path string, parentDir gfs.Item) error
ReadAnalysis(input io.Reader) error
SetIgnoreDirPaths(paths []string)
SetIgnoreDirPatterns(paths []string) error
diff --git a/internal/common/analyze.go b/internal/common/analyze.go
new file mode 100644
index 0000000..0894c46
--- /dev/null
+++ b/internal/common/analyze.go
@@ -0,0 +1,21 @@
+package common
+
+import "github.com/dundee/gdu/v5/pkg/fs"
+
+// CurrentProgress struct
+type CurrentProgress struct {
+ CurrentItemName string
+ ItemCount int
+ TotalSize int64
+}
+
+// ShouldDirBeIgnored whether path should be ignored
+type ShouldDirBeIgnored func(name, path string) bool
+
+// Analyzer is type for dir analyzing function
+type Analyzer interface {
+ AnalyzeDir(path string, ignore ShouldDirBeIgnored) fs.Item
+ GetProgressChan() chan CurrentProgress
+ GetDoneChan() chan struct{}
+ ResetProgress()
+}
diff --git a/internal/common/ignore.go b/internal/common/ignore.go
index f09d1a5..2ae1458 100644
--- a/internal/common/ignore.go
+++ b/internal/common/ignore.go
@@ -7,8 +7,6 @@ import (
"strings"
log "github.com/sirupsen/logrus"
-
- "github.com/dundee/gdu/v5/pkg/analyze"
)
// CreateIgnorePattern creates one pattern from all path patterns
@@ -103,7 +101,7 @@ func (ui *UI) IsHiddenDir(name, path string) bool {
}
// CreateIgnoreFunc returns function for detecting if dir should be ignored
-func (ui *UI) CreateIgnoreFunc() analyze.ShouldDirBeIgnored {
+func (ui *UI) CreateIgnoreFunc() ShouldDirBeIgnored {
switch {
case len(ui.IgnoreDirPaths) > 0 && ui.IgnoreDirPathPatterns == nil && !ui.IgnoreHidden:
return ui.ShouldDirBeIgnored
diff --git a/internal/common/ui.go b/internal/common/ui.go
index 18b7113..9f19596 100644
--- a/internal/common/ui.go
+++ b/internal/common/ui.go
@@ -3,13 +3,11 @@ package common
import (
"regexp"
"strconv"
-
- "github.com/dundee/gdu/v5/pkg/analyze"
)
// UI struct
type UI struct {
- Analyzer analyze.Analyzer
+ Analyzer Analyzer
IgnoreDirPaths map[string]struct{}
IgnoreDirPathPatterns *regexp.Regexp
IgnoreHidden bool
diff --git a/internal/testanalyze/analyze.go b/internal/testanalyze/analyze.go
index 76e01df..b0429c1 100644
--- a/internal/testanalyze/analyze.go
+++ b/internal/testanalyze/analyze.go
@@ -4,14 +4,16 @@ import (
"errors"
"time"
+ "github.com/dundee/gdu/v5/internal/common"
"github.com/dundee/gdu/v5/pkg/analyze"
+ "github.com/dundee/gdu/v5/pkg/fs"
)
// MockedAnalyzer returns dir with files with different size exponents
type MockedAnalyzer struct{}
// AnalyzeDir returns dir with files with different size exponents
-func (a *MockedAnalyzer) AnalyzeDir(path string, ignore analyze.ShouldDirBeIgnored) *analyze.Dir {
+func (a *MockedAnalyzer) AnalyzeDir(path string, ignore common.ShouldDirBeIgnored) fs.Item {
dir := &analyze.Dir{
File: &analyze.File{
Name: "test_dir",
@@ -56,14 +58,14 @@ func (a *MockedAnalyzer) AnalyzeDir(path string, ignore analyze.ShouldDirBeIgnor
Mtime: time.Date(2021, 8, 27, 22, 23, 24, 0, time.UTC),
Parent: dir,
}
- dir.Files = analyze.Files{dir2, dir3, dir4, file}
+ dir.Files = fs.Files{dir2, dir3, dir4, file}
return dir
}
// GetProgressChan returns always Done
-func (a *MockedAnalyzer) GetProgressChan() chan analyze.CurrentProgress {
- return make(chan analyze.CurrentProgress)
+func (a *MockedAnalyzer) GetProgressChan() chan common.CurrentProgress {
+ return make(chan common.CurrentProgress)
}
// GetDoneChan returns always Done
@@ -77,6 +79,6 @@ func (a *MockedAnalyzer) GetDoneChan() chan struct{} {
func (a *MockedAnalyzer) ResetProgress() {}
// RemoveItemFromDirWithErr returns error
-func RemoveItemFromDirWithErr(dir *analyze.Dir, file analyze.Item) error {
+func RemoveItemFromDirWithErr(dir fs.Item, file fs.Item) error {
return errors.New("Failed")
}
diff --git a/pkg/analyze/dir.go b/pkg/analyze/dir.go
index f91ddda..e6c9467 100644
--- a/pkg/analyze/dir.go
+++ b/pkg/analyze/dir.go
@@ -5,55 +5,39 @@ import (
"path/filepath"
"runtime"
+ "github.com/dundee/gdu/v5/internal/common"
+ "github.com/dundee/gdu/v5/pkg/fs"
log "github.com/sirupsen/logrus"
)
-// CurrentProgress struct
-type CurrentProgress struct {
- CurrentItemName string
- ItemCount int
- TotalSize int64
-}
-
var concurrencyLimit = make(chan struct{}, 3*runtime.GOMAXPROCS(0))
-// ShouldDirBeIgnored whether path should be ignored
-type ShouldDirBeIgnored func(name, path string) bool
-
-// Analyzer is type for dir analyzing function
-type Analyzer interface {
- AnalyzeDir(path string, ignore ShouldDirBeIgnored) *Dir
- GetProgressChan() chan CurrentProgress
- GetDoneChan() chan struct{}
- ResetProgress()
-}
-
// ParallelAnalyzer implements Analyzer
type ParallelAnalyzer struct {
- progress *CurrentProgress
- progressChan chan CurrentProgress
- progressOutChan chan CurrentProgress
+ progress *common.CurrentProgress
+ progressChan chan common.CurrentProgress
+ progressOutChan chan common.CurrentProgress
doneChan chan struct{}
wait *WaitGroup
- ignoreDir ShouldDirBeIgnored
+ ignoreDir common.ShouldDirBeIgnored
}
// CreateAnalyzer returns Analyzer
-func CreateAnalyzer() Analyzer {
+func CreateAnalyzer() common.Analyzer {
return &ParallelAnalyzer{
- progress: &CurrentProgress{
+ progress: &common.CurrentProgress{
ItemCount: 0,
TotalSize: int64(0),
},
- progressChan: make(chan CurrentProgress, 1),
- progressOutChan: make(chan CurrentProgress, 1),
+ progressChan: make(chan common.CurrentProgress, 1),
+ progressOutChan: make(chan common.CurrentProgress, 1),
doneChan: make(chan struct{}, 1),
wait: (&WaitGroup{}).Init(),
}
}
// GetProgressChan returns channel for getting progress
-func (a *ParallelAnalyzer) GetProgressChan() chan CurrentProgress {
+func (a *ParallelAnalyzer) GetProgressChan() chan common.CurrentProgress {
return a.progressOutChan
}
@@ -70,7 +54,7 @@ func (a *ParallelAnalyzer) ResetProgress() {
}
// AnalyzeDir analyzes given path
-func (a *ParallelAnalyzer) AnalyzeDir(path string, ignore ShouldDirBeIgnored) *Dir {
+func (a *ParallelAnalyzer) AnalyzeDir(path string, ignore common.ShouldDirBeIgnored) fs.Item {
a.ignoreDir = ignore
go a.updateProgress()
@@ -108,7 +92,7 @@ func (a *ParallelAnalyzer) processDir(path string) *Dir {
Flag: getDirFlag(err, len(files)),
},
ItemCount: 1,
- Files: make([]Item, 0, len(files)),
+ Files: make(fs.Files, 0, len(files)),
}
setDirPlatformSpecificAttrs(dir, path)
@@ -145,7 +129,7 @@ func (a *ParallelAnalyzer) processDir(path string) *Dir {
totalSize += info.Size()
- dir.Files.Append(file)
+ dir.AddFile(file)
}
}
@@ -154,13 +138,13 @@ func (a *ParallelAnalyzer) processDir(path string) *Dir {
for i := 0; i < dirCount; i++ {
sub = <-subDirChan
- dir.Files.Append(sub)
+ dir.AddFile(sub)
}
a.wait.Done()
}()
- a.progressChan <- CurrentProgress{path, len(files), totalSize}
+ a.progressChan <- common.CurrentProgress{path, len(files), totalSize}
return dir
}
diff --git a/pkg/analyze/dir_test.go b/pkg/analyze/dir_test.go
index 874de8c..a4b15ca 100644
--- a/pkg/analyze/dir_test.go
+++ b/pkg/analyze/dir_test.go
@@ -8,6 +8,7 @@ import (
log "github.com/sirupsen/logrus"
"github.com/dundee/gdu/v5/internal/testdir"
+ "github.com/dundee/gdu/v5/pkg/fs"
"github.com/stretchr/testify/assert"
)
@@ -20,14 +21,14 @@ func TestAnalyzeDir(t *testing.T) {
defer fin()
analyzer := CreateAnalyzer()
- dir := analyzer.AnalyzeDir("test_dir", func(_, _ string) bool { return false })
+ dir := analyzer.AnalyzeDir("test_dir", func(_, _ string) bool { return false }).(*Dir)
progress := <-analyzer.GetProgressChan()
assert.GreaterOrEqual(t, progress.TotalSize, int64(0))
analyzer.ResetProgress()
<-analyzer.GetDoneChan()
- dir.UpdateStats(make(HardLinkedItems))
+ dir.UpdateStats(make(fs.HardLinkedItems))
// test dir info
assert.Equal(t, "test_dir", dir.Name)
@@ -47,14 +48,14 @@ func TestAnalyzeDir(t *testing.T) {
assert.Equal(t, int64(5), dir.Files[0].(*Dir).Files[1].(*Dir).Files[0].GetSize())
// test parent link
- assert.Equal(t, "test_dir", dir.Files[0].(*Dir).Files[1].(*Dir).Files[0].GetParent().GetParent().GetParent().Name)
+ assert.Equal(t, "test_dir", dir.Files[0].(*Dir).Files[1].(*Dir).Files[0].GetParent().GetParent().GetParent().GetName())
}
func TestIgnoreDir(t *testing.T) {
fin := testdir.CreateTestDir()
defer fin()
- dir := CreateAnalyzer().AnalyzeDir("test_dir", func(_, _ string) bool { return true })
+ dir := CreateAnalyzer().AnalyzeDir("test_dir", func(_, _ string) bool { return true }).(*Dir)
assert.Equal(t, "test_dir", dir.Name)
assert.Equal(t, 1, dir.ItemCount)
@@ -71,9 +72,9 @@ func TestFlags(t *testing.T) {
assert.Nil(t, err)
analyzer := CreateAnalyzer()
- dir := analyzer.AnalyzeDir("test_dir", func(_, _ string) bool { return false })
+ dir := analyzer.AnalyzeDir("test_dir", func(_, _ string) bool { return false }).(*Dir)
<-analyzer.GetDoneChan()
- dir.UpdateStats(make(HardLinkedItems))
+ dir.UpdateStats(make(fs.HardLinkedItems))
sort.Sort(dir.Files)
@@ -97,9 +98,9 @@ func TestHardlink(t *testing.T) {
assert.Nil(t, err)
analyzer := CreateAnalyzer()
- dir := analyzer.AnalyzeDir("test_dir", func(_, _ string) bool { return false })
+ dir := analyzer.AnalyzeDir("test_dir", func(_, _ string) bool { return false }).(*Dir)
<-analyzer.GetDoneChan()
- dir.UpdateStats(make(HardLinkedItems))
+ dir.UpdateStats(make(fs.HardLinkedItems))
assert.Equal(t, int64(7+4096*3), dir.Size) // file2 and file3 are counted just once for size
assert.Equal(t, 6, dir.ItemCount) // but twice for item count
@@ -122,9 +123,9 @@ func TestErr(t *testing.T) {
}()
analyzer := CreateAnalyzer()
- dir := analyzer.AnalyzeDir("test_dir", func(_, _ string) bool { return false })
+ dir := analyzer.AnalyzeDir("test_dir", func(_, _ string) bool { return false }).(*Dir)
<-analyzer.GetDoneChan()
- dir.UpdateStats(make(HardLinkedItems))
+ dir.UpdateStats(make(fs.HardLinkedItems))
assert.Equal(t, "test_dir", dir.GetName())
assert.Equal(t, 2, dir.ItemCount)
@@ -143,5 +144,5 @@ func BenchmarkAnalyzeDir(b *testing.B) {
analyzer := CreateAnalyzer()
dir := analyzer.AnalyzeDir("test_dir", func(_, _ string) bool { return false })
<-analyzer.GetDoneChan()
- dir.UpdateStats(make(HardLinkedItems))
+ dir.UpdateStats(make(fs.HardLinkedItems))
}
diff --git a/pkg/analyze/encode_test.go b/pkg/analyze/encode_test.go
index 6989bcd..819ccb4 100644
--- a/pkg/analyze/encode_test.go
+++ b/pkg/analyze/encode_test.go
@@ -5,6 +5,7 @@ import (
"testing"
"time"
+ "github.com/dundee/gdu/v5/pkg/fs"
log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
)
@@ -53,8 +54,8 @@ func TestEncode(t *testing.T) {
Mli: 1234,
Flag: 'H',
}
- dir.Files = Files{subdir}
- subdir.Files = Files{file, file2, file3}
+ dir.Files = fs.Files{subdir}
+ subdir.Files = fs.Files{file, file2, file3}
var buff bytes.Buffer
err := dir.EncodeJSON(&buff, true)
diff --git a/pkg/analyze/file.go b/pkg/analyze/file.go
index 209ce2c..a80a458 100644
--- a/pkg/analyze/file.go
+++ b/pkg/analyze/file.go
@@ -1,36 +1,17 @@
package analyze
import (
- "io"
"os"
"path/filepath"
"time"
-)
-// HardLinkedItems maps inode number to array of all hard linked items
-type HardLinkedItems map[uint64]Files
-
-// Item is fs item (file or dir)
-type Item interface {
- GetPath() string
- GetName() string
- GetFlag() rune
- IsDir() bool
- GetSize() int64
- GetType() string
- GetUsage() int64
- GetMtime() time.Time
- GetItemCount() int
- GetParent() *Dir
- GetMultiLinkedInode() uint64
- EncodeJSON(writer io.Writer, topLevel bool) error
- getItemStats(linkedItems HardLinkedItems) (int, int64, int64)
-}
+ "github.com/dundee/gdu/v5/pkg/fs"
+)
// File struct
type File struct {
Mtime time.Time
- Parent *Dir
+ Parent fs.Item
Name string
Size int64
Usage int64
@@ -49,10 +30,15 @@ func (f *File) IsDir() bool {
}
// GetParent retruns parent dir
-func (f *File) GetParent() *Dir {
+func (f *File) GetParent() fs.Item {
return f.Parent
}
+// SetParent sets parent dir
+func (f *File) SetParent(parent fs.Item) {
+ f.Parent = parent
+}
+
// GetPath retruns absolute Get of the file
func (f *File) GetPath() string {
return filepath.Join(f.Parent.GetPath(), f.Name)
@@ -97,7 +83,7 @@ func (f *File) GetMultiLinkedInode() uint64 {
return f.Mli
}
-func (f *File) alreadyCounted(linkedItems HardLinkedItems) bool {
+func (f *File) alreadyCounted(linkedItems fs.HardLinkedItems) bool {
mli := f.Mli
counted := false
if mli > 0 {
@@ -110,21 +96,55 @@ func (f *File) alreadyCounted(linkedItems HardLinkedItems) bool {
return counted
}
-func (f *File) getItemStats(linkedItems HardLinkedItems) (int, int64, int64) {
+// GetItemStats returns 1 as count of items, apparent usage and real usage of this file
+func (f *File) GetItemStats(linkedItems fs.HardLinkedItems) (int, int64, int64) {
if f.alreadyCounted(linkedItems) {
return 1, 0, 0
}
return 1, f.GetSize(), f.GetUsage()
}
+// UpdateStats does nothing on file
+func (f *File) UpdateStats(linkedItems fs.HardLinkedItems) {}
+
+// GetFiles returns all files in directory
+func (f *File) GetFiles() fs.Files {
+ return fs.Files{}
+}
+
+// SetFiles panics on file
+func (f *File) SetFiles(files fs.Files) {
+ panic("SetFiles should not be called on file")
+}
+
+// AddFile panics on file
+func (f *File) AddFile(item fs.Item) {
+ panic("AddFile should not be called on file")
+}
+
// Dir struct
type Dir struct {
*File
BasePath string
- Files Files
+ Files fs.Files
ItemCount int
}
+// AddFile add item fo files
+func (f *Dir) AddFile(item fs.Item) {
+ f.Files = append(f.Files, item)
+}
+
+// GetFiles returns all files in directory
+func (f *Dir) GetFiles() fs.Files {
+ return f.Files
+}
+
+// SetFiles sets files in directory
+func (f *Dir) SetFiles(files fs.Files) {
+ f.Files = files
+}
+
// GetType returns name type of item
func (f *Dir) GetType() string {
return "Directory"
@@ -148,18 +168,19 @@ func (f *Dir) GetPath() string {
return filepath.Join(f.Parent.GetPath(), f.Name)
}
-func (f *Dir) getItemStats(linkedItems HardLinkedItems) (int, int64, int64) {
+// GetItemStats returns item count, apparent usage and real usage of this dir
+func (f *Dir) GetItemStats(linkedItems fs.HardLinkedItems) (int, int64, int64) {
f.UpdateStats(linkedItems)
return f.ItemCount, f.GetSize(), f.GetUsage()
}
// UpdateStats recursively updates size and item count
-func (f *Dir) UpdateStats(linkedItems HardLinkedItems) {
+func (f *Dir) UpdateStats(linkedItems fs.HardLinkedItems) {
totalSize := int64(4096)
totalUsage := int64(4096)
var itemCount int
for _, entry := range f.Files {
- count, size, usage := entry.getItemStats(linkedItems)
+ count, size, usage := entry.GetItemStats(linkedItems)
totalSize += size
totalUsage += usage
itemCount += count
@@ -180,96 +201,16 @@ func (f *Dir) UpdateStats(linkedItems HardLinkedItems) {
f.Usage = totalUsage
}
-// Files - slice of pointers to File
-type Files []Item
-
-// Append addes one item to Files
-func (f *Files) Append(file Item) {
- slice := *f
- slice = append(slice, file)
- *f = slice
-}
-
-// IndexOf searches File in Files and returns its index
-func (f Files) IndexOf(file Item) (int, bool) {
- for i, item := range f {
- if item == file {
- return i, true
- }
- }
- return 0, false
-}
-
-// FindByName searches name in Files and returns its index
-func (f Files) FindByName(name string) (int, bool) {
- for i, item := range f {
- if item.GetName() == name {
- return i, true
- }
- }
- return 0, false
-}
-
-// Remove removes File from Files
-func (f Files) Remove(file Item) Files {
- index, ok := f.IndexOf(file)
- if !ok {
- return f
- }
- return append(f[:index], f[index+1:]...)
-}
-
-// RemoveByName removes File from Files
-func (f Files) RemoveByName(name string) Files {
- index, ok := f.FindByName(name)
- if !ok {
- return f
- }
- return append(f[:index], f[index+1:]...)
-}
-
-func (f Files) Len() int { return len(f) }
-func (f Files) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
-func (f Files) Less(i, j int) bool { return f[i].GetUsage() > f[j].GetUsage() }
-
-// ByApparentSize sorts files by apparent size
-type ByApparentSize Files
-
-func (f ByApparentSize) Len() int { return len(f) }
-func (f ByApparentSize) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
-func (f ByApparentSize) Less(i, j int) bool { return f[i].GetSize() > f[j].GetSize() }
-
-// ByItemCount sorts files by item count
-type ByItemCount Files
-
-func (f ByItemCount) Len() int { return len(f) }
-func (f ByItemCount) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
-func (f ByItemCount) Less(i, j int) bool { return f[i].GetItemCount() > f[j].GetItemCount() }
-
-// ByName sorts files by name
-type ByName Files
-
-func (f ByName) Len() int { return len(f) }
-func (f ByName) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
-func (f ByName) Less(i, j int) bool { return f[i].GetName() > f[j].GetName() }
-
-// ByMtime sorts files by name
-type ByMtime Files
-
-func (f ByMtime) Len() int { return len(f) }
-func (f ByMtime) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
-func (f ByMtime) Less(i, j int) bool { return f[i].GetMtime().After(f[j].GetMtime()) }
-
// RemoveItemFromDir removes item from dir
-func RemoveItemFromDir(dir *Dir, item Item) error {
+func RemoveItemFromDir(dir fs.Item, item fs.Item) error {
err := os.RemoveAll(item.GetPath())
if err != nil {
return err
}
- dir.Files = dir.Files.Remove(item)
+ dir.SetFiles(dir.GetFiles().Remove(item))
- cur := dir
+ cur := dir.(*Dir)
for {
cur.ItemCount -= item.GetItemCount()
cur.Size -= item.GetSize()
@@ -278,19 +219,19 @@ func RemoveItemFromDir(dir *Dir, item Item) error {
if cur.Parent == nil {
break
}
- cur = cur.Parent
+ cur = cur.Parent.(*Dir)
}
return nil
}
// EmptyFileFromDir empty file from dir
-func EmptyFileFromDir(dir *Dir, file Item) error {
+func EmptyFileFromDir(dir fs.Item, file fs.Item) error {
err := os.Truncate(file.GetPath(), 0)
if err != nil {
return err
}
- cur := dir
+ cur := dir.(*Dir)
for {
cur.Size -= file.GetSize()
cur.Usage -= file.GetUsage()
@@ -298,17 +239,17 @@ func EmptyFileFromDir(dir *Dir, file Item) error {
if cur.Parent == nil {
break
}
- cur = cur.Parent
+ cur = cur.Parent.(*Dir)
}
- dir.Files = dir.Files.Remove(file)
+ dir.SetFiles(dir.GetFiles().Remove(file))
newFile := &File{
Name: file.GetName(),
Flag: file.GetFlag(),
Size: 0,
Parent: dir,
}
- dir.Files.Append(newFile)
+ dir.AddFile(newFile)
return nil
}
diff --git a/pkg/analyze/file_test.go b/pkg/analyze/file_test.go
index 48cdc51..d07d841 100644
--- a/pkg/analyze/file_test.go
+++ b/pkg/analyze/file_test.go
@@ -6,6 +6,7 @@ import (
"time"
"github.com/dundee/gdu/v5/internal/testdir"
+ "github.com/dundee/gdu/v5/pkg/fs"
"github.com/stretchr/testify/assert"
)
@@ -22,7 +23,7 @@ func TestIsDir(t *testing.T) {
Size: 2,
Parent: &dir,
}
- dir.Files = Files{file}
+ dir.Files = fs.Files{file}
assert.True(t, dir.IsDir())
assert.False(t, file.IsDir())
@@ -48,7 +49,7 @@ func TestGetType(t *testing.T) {
Parent: &dir,
Flag: '@',
}
- dir.Files = Files{file, file2}
+ dir.Files = fs.Files{file, file2}
assert.Equal(t, "Directory", dir.GetType())
assert.Equal(t, "File", file.GetType())
@@ -74,7 +75,7 @@ func TestFind(t *testing.T) {
Size: 3,
Parent: &dir,
}
- dir.Files = Files{file, file2}
+ dir.Files = fs.Files{file, file2}
i, _ := dir.Files.IndexOf(file)
assert.Equal(t, 0, i)
@@ -101,7 +102,7 @@ func TestRemove(t *testing.T) {
Size: 3,
Parent: &dir,
}
- dir.Files = Files{file, file2}
+ dir.Files = fs.Files{file, file2}
dir.Files = dir.Files.Remove(file)
@@ -131,7 +132,7 @@ func TestRemoveByName(t *testing.T) {
Usage: 4,
Parent: &dir,
}
- dir.Files = Files{file, file2}
+ dir.Files = fs.Files{file, file2}
dir.Files = dir.Files.RemoveByName("yyy")
@@ -160,7 +161,7 @@ func TestRemoveNotInDir(t *testing.T) {
Size: 3,
Usage: 4,
}
- dir.Files = Files{file}
+ dir.Files = fs.Files{file}
_, ok := dir.Files.IndexOf(file2)
assert.Equal(t, false, ok)
@@ -191,7 +192,7 @@ func TestRemoveByNameNotInDir(t *testing.T) {
Size: 3,
Usage: 4,
}
- dir.Files = Files{file}
+ dir.Files = fs.Files{file}
_, ok := dir.Files.IndexOf(file2)
assert.Equal(t, false, ok)
@@ -227,8 +228,8 @@ func TestRemoveFile(t *testing.T) {
Usage: 4,
Parent: subdir,
}
- dir.Files = Files{subdir}
- subdir.Files = Files{file}
+ dir.Files = fs.Files{subdir}
+ subdir.Files = fs.Files{file}
err := RemoveItemFromDir(subdir, file)
assert.Nil(t, err)
@@ -300,8 +301,8 @@ func TestTruncateFile(t *testing.T) {
Usage: 4,
Parent: subdir,
}
- dir.Files = Files{subdir}
- subdir.Files = Files{file}
+ dir.Files = fs.Files{subdir}
+ subdir.Files = fs.Files{file}
err := EmptyFileFromDir(subdir, file)
@@ -341,8 +342,8 @@ func TestTruncateFileWithErr(t *testing.T) {
Usage: 4,
Parent: subdir,
}
- dir.Files = Files{subdir}
- subdir.Files = Files{file}
+ dir.Files = fs.Files{subdir}
+ subdir.Files = fs.Files{file}
err := EmptyFileFromDir(subdir, file)
@@ -371,7 +372,7 @@ func TestUpdateStats(t *testing.T) {
Mtime: time.Date(2021, 8, 19, 0, 42, 0, 0, time.UTC),
Parent: &dir,
}
- dir.Files = Files{file, file2}
+ dir.Files = fs.Files{file, file2}
dir.UpdateStats(nil)
diff --git a/pkg/analyze/sort_test.go b/pkg/analyze/sort_test.go
index e828628..a7d208f 100644
--- a/pkg/analyze/sort_test.go
+++ b/pkg/analyze/sort_test.go
@@ -5,11 +5,12 @@ import (
"testing"
"time"
+ "github.com/dundee/gdu/v5/pkg/fs"
"github.com/stretchr/testify/assert"
)
func TestSortByUsage(t *testing.T) {
- files := Files{
+ files := fs.Files{
&File{
Usage: 1,
},
@@ -29,7 +30,7 @@ func TestSortByUsage(t *testing.T) {
}
func TestSortByUsageAsc(t *testing.T) {
- files := Files{
+ files := fs.Files{
&File{
Size: 1,
},
@@ -49,7 +50,7 @@ func TestSortByUsageAsc(t *testing.T) {
}
func TestSortBySize(t *testing.T) {
- files := Files{
+ files := fs.Files{
&File{
Size: 1,
},
@@ -61,7 +62,7 @@ func TestSortBySize(t *testing.T) {
},
}
- sort.Sort(ByApparentSize(files))
+ sort.Sort(fs.ByApparentSize(files))
assert.Equal(t, int64(3), files[0].GetSize())
assert.Equal(t, int64(2), files[1].GetSize())
@@ -69,7 +70,7 @@ func TestSortBySize(t *testing.T) {
}
func TestSortBySizeAsc(t *testing.T) {
- files := Files{
+ files := fs.Files{
&File{
Size: 1,
},
@@ -81,7 +82,7 @@ func TestSortBySizeAsc(t *testing.T) {
},
}
- sort.Sort(sort.Reverse(ByApparentSize(files)))
+ sort.Sort(sort.Reverse(fs.ByApparentSize(files)))
assert.Equal(t, int64(1), files[0].GetSize())
assert.Equal(t, int64(2), files[1].GetSize())
@@ -89,7 +90,7 @@ func TestSortBySizeAsc(t *testing.T) {
}
func TestSortByItemCount(t *testing.T) {
- files := Files{
+ files := fs.Files{
&Dir{
ItemCount: 1,
},
@@ -101,7 +102,7 @@ func TestSortByItemCount(t *testing.T) {
},
}
- sort.Sort(ByItemCount(files))
+ sort.Sort(fs.ByItemCount(files))
assert.Equal(t, 3, files[0].GetItemCount())
assert.Equal(t, 2, files[1].GetItemCount())
@@ -109,7 +110,7 @@ func TestSortByItemCount(t *testing.T) {
}
func TestSortByName(t *testing.T) {
- files := Files{
+ files := fs.Files{
&File{
Name: "aa",
},
@@ -121,7 +122,7 @@ func TestSortByName(t *testing.T) {
},
}
- sort.Sort(ByName(files))
+ sort.Sort(fs.ByName(files))
assert.Equal(t, "cc", files[0].GetName())
assert.Equal(t, "bb", files[1].GetName())
@@ -129,7 +130,7 @@ func TestSortByName(t *testing.T) {
}
func TestSortByMtime(t *testing.T) {
- files := Files{
+ files := fs.Files{
&File{
Mtime: time.Date(2021, 8, 19, 0, 40, 0, 0, time.UTC),
},
@@ -141,7 +142,7 @@ func TestSortByMtime(t *testing.T) {
},
}
- sort.Sort(ByMtime(files))
+ sort.Sort(fs.ByMtime(files))
assert.Equal(t, 42, files[0].GetMtime().Minute())
assert.Equal(t, 41, files[1].GetMtime().Minute())
diff --git a/pkg/fs/file.go b/pkg/fs/file.go
new file mode 100644
index 0000000..71e85c2
--- /dev/null
+++ b/pkg/fs/file.go
@@ -0,0 +1,104 @@
+package fs
+
+import (
+ "io"
+ "time"
+)
+
+// Item is a FS item (file or dir)
+type Item interface {
+ GetPath() string
+ GetName() string
+ GetFlag() rune
+ IsDir() bool
+ GetSize() int64
+ GetType() string
+ GetUsage() int64
+ GetMtime() time.Time
+ GetItemCount() int
+ GetParent() Item
+ SetParent(Item)
+ GetMultiLinkedInode() uint64
+ EncodeJSON(writer io.Writer, topLevel bool) error
+ GetItemStats(linkedItems HardLinkedItems) (int, int64, int64)
+ UpdateStats(linkedItems HardLinkedItems)
+ AddFile(Item)
+ GetFiles() Files
+ SetFiles(Files)
+}
+
+// Files - slice of pointers to File
+type Files []Item
+
+// HardLinkedItems maps inode number to array of all hard linked items
+type HardLinkedItems map[uint64]Files
+
+// IndexOf searches File in Files and returns its index
+func (f Files) IndexOf(file Item) (int, bool) {
+ for i, item := range f {
+ if item == file {
+ return i, true
+ }
+ }
+ return 0, false
+}
+
+// FindByName searches name in Files and returns its index
+func (f Files) FindByName(name string) (int, bool) {
+ for i, item := range f {
+ if item.GetName() == name {
+ return i, true
+ }
+ }
+ return 0, false
+}
+
+// Remove removes File from Files
+func (f Files) Remove(file Item) Files {
+ index, ok := f.IndexOf(file)
+ if !ok {
+ return f
+ }
+ return append(f[:index], f[index+1:]...)
+}
+
+// RemoveByName