Skip to content

Commit c1f529e

Browse files
authored
Merge pull request #79 from viktomas/core-split
Splitting the `core` package into `files` and `commands`
2 parents ad03d2a + f5017c1 commit c1f529e

23 files changed

+174
-161
lines changed

CONTRIBUTING.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ Why for nomral use it is ok to call `go get` without go modules, if you are goin
88
![godu architecture](godu_architecture.png)
99

1010
Main things to consider when implementing new functionality is packages, there are 3:
11-
* `core` - this is the true godu. Everything that does the main job is here. If godu wasn't CLI utility but GUI app, this package would ideally stay untouched
11+
* `files` - godu's file system representation and algorythms for making and changing the file tree structure
12+
* `commands` - application state representation and functions to change it, all based on the command design pattern
1213
* `interactive` - this is functionality connected to UI of the app
1314
* `main` - this contains main wiring + tcell.Screen related functionality, **this is the only package that is not expected to have 100% test coverage**
1415

15-
#### Before doing significant changes to core (specially changing the main structures like File and State, please consult the change in form of Github Issue
16+
#### Before doing significant changes to `files` and `commands` packages (specially changing the main structures like File and State, please consult the change in form of Github Issue
1617

1718
## Main ideas
1819
### State is immutable
@@ -22,12 +23,12 @@ Main things to consider when implementing new functionality is packages, there a
2223
### the root folder structure should only represent the file system
2324
You would notice that in `godu.go` we are walking through the whole folder using
2425
```
25-
rootFolder := core.WalkFolder(rootFolderName, ioutil.ReadDir, getIgnoredFolders())
26+
rootFolder := files.WalkFolder(rootFolderName, ioutil.ReadDir, getIgnoredFolders())
2627
```
27-
The expectation is that the `core.File` structure contains only representation of the file system and it is not going to change after calling `WalkFolder`
28+
The expectation is that the `files.File` structure contains only representation of the file system and it is not going to change after calling `WalkFolder`
2829

2930
### Everything that commands do should be represented in State
3031
When implementing new command please make sure that it's result is captured in a state and that the state is appropriately displayed using `InteractiveFolder` (e.g. highlighting selected line in file column)
3132

3233
## 100% test coverage
33-
Expectation is that `core` and `interactive` packages will have 100% test coverage. I'm not a testing nazi but I won't have time to checkout every PR and manually retest it and neither will you. We need to be confident that `godu` still works after merging your (and any subsequent) PR.
34+
Expectation is that `files`, `commands` and `interactive` packages will have 100% test coverage. I'm not a testing nazi but I won't have time to checkout every PR and manually retest it and neither will you. We need to be confident that `godu` still works after merging your (and any subsequent) PR.

core/command.go renamed to commands/command.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1-
package core
1+
package commands
22

3-
import "errors"
3+
import (
4+
"errors"
5+
6+
"github.com/viktomas/godu/files"
7+
)
48

59
// State represents system configuration after processing user input
610
type State struct {
7-
Folder *File
11+
Folder *files.File
812
Selected int
9-
history map[*File]int // last cursor location in each folder
10-
MarkedFiles map[*File]struct{}
13+
history map[*files.File]int // last cursor location in each folder
14+
MarkedFiles map[*files.File]struct{}
1115
}
1216

1317
// Executer represents a user action triggered on a State
@@ -62,7 +66,7 @@ func (e Enter) Execute(oldState State) (State, error) {
6266
if len(newFolder.Files) == 0 {
6367
return oldState, errors.New("Trying to enter empty file")
6468
}
65-
newHistory := map[*File]int{}
69+
newHistory := map[*files.File]int{}
6670
for fp, selected := range oldState.history {
6771
newHistory[fp] = selected
6872
}
@@ -80,7 +84,7 @@ func (GoBack) Execute(oldState State) (State, error) {
8084
if parentFolder == nil {
8185
return oldState, errors.New("Trying to go back on root")
8286
}
83-
newHistory := map[*File]int{}
87+
newHistory := map[*files.File]int{}
8488
for fp, selected := range oldState.history {
8589
newHistory[fp] = selected
8690
}

core/command_test.go renamed to commands/command_test.go

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
package core
1+
package commands
22

33
import (
44
"testing"
55

66
"github.com/stretchr/testify/assert"
7+
"github.com/viktomas/godu/files"
78
)
89

910
func TestDownCommand(t *testing.T) {
10-
folder := NewTestFolder("a", NewTestFile("b", 50), NewTestFile("c", 50))
11+
folder := files.NewTestFolder("a", files.NewTestFile("b", 50), files.NewTestFile("c", 50))
1112
initialState := State{
1213
Folder: folder,
1314
}
@@ -17,7 +18,7 @@ func TestDownCommand(t *testing.T) {
1718
}
1819

1920
func TestDownCommandFails(t *testing.T) {
20-
folder := NewTestFolder("a", NewTestFile("b", 50), NewTestFile("c", 50))
21+
folder := files.NewTestFolder("a", files.NewTestFile("b", 50), files.NewTestFile("c", 50))
2122
initialState := State{
2223
Folder: folder,
2324
Selected: 1,
@@ -28,7 +29,7 @@ func TestDownCommandFails(t *testing.T) {
2829
}
2930

3031
func TestUpCommand(t *testing.T) {
31-
folder := NewTestFolder("a", NewTestFile("b", 50), NewTestFile("c", 50))
32+
folder := files.NewTestFolder("a", files.NewTestFile("b", 50), files.NewTestFile("c", 50))
3233
initialState := State{
3334
Folder: folder,
3435
Selected: 1,
@@ -38,7 +39,7 @@ func TestUpCommand(t *testing.T) {
3839
}
3940

4041
func TestUpCommandFails(t *testing.T) {
41-
folder := NewTestFolder("a", NewTestFile("b", 50), NewTestFile("c", 50))
42+
folder := files.NewTestFolder("a", files.NewTestFile("b", 50), files.NewTestFile("c", 50))
4243
initialState := State{
4344
Folder: folder,
4445
Selected: 0,
@@ -49,28 +50,28 @@ func TestUpCommandFails(t *testing.T) {
4950
}
5051

5152
func TestEnterCommand(t *testing.T) {
52-
folder := NewTestFolder("a", NewTestFile("b", 50), NewTestFolder("c", NewTestFile("d", 50), NewTestFile("e", 50)))
53+
folder := files.NewTestFolder("a", files.NewTestFile("b", 50), files.NewTestFolder("c", files.NewTestFile("d", 50), files.NewTestFile("e", 50)))
5354
subFolder := folder.Files[1]
54-
marked := make(map[*File]struct{})
55+
marked := make(map[*files.File]struct{})
5556
initialState := State{
5657
Folder: folder,
57-
history: map[*File]int{subFolder: 1},
58+
history: map[*files.File]int{subFolder: 1},
5859
Selected: 1,
5960
MarkedFiles: marked,
6061
}
6162
command := Enter{}
6263
newState, _ := command.Execute(initialState)
6364
expectedState := State{
6465
Folder: subFolder,
65-
history: map[*File]int{folder: 1, subFolder: 1},
66+
history: map[*files.File]int{folder: 1, subFolder: 1},
6667
Selected: 1,
6768
MarkedFiles: marked,
6869
}
6970
assert.Equal(t, expectedState, newState)
7071
}
7172

7273
func TestEnterCommandFails(t *testing.T) {
73-
folder := NewTestFolder("a", NewTestFile("b", 50))
74+
folder := files.NewTestFolder("a", files.NewTestFile("b", 50))
7475
initialState := State{
7576
Folder: folder,
7677
}
@@ -80,28 +81,28 @@ func TestEnterCommandFails(t *testing.T) {
8081
}
8182

8283
func TestGoBackCommand(t *testing.T) {
83-
folder := NewTestFolder("a", NewTestFile("b", 50), NewTestFolder("c", NewTestFile("d", 50), NewTestFile("e", 50)))
84+
folder := files.NewTestFolder("a", files.NewTestFile("b", 50), files.NewTestFolder("c", files.NewTestFile("d", 50), files.NewTestFile("e", 50)))
8485
subFolder := folder.Files[1]
85-
marked := make(map[*File]struct{})
86+
marked := make(map[*files.File]struct{})
8687
initialState := State{
8788
Folder: subFolder,
88-
history: map[*File]int{folder: 1},
89+
history: map[*files.File]int{folder: 1},
8990
Selected: 1,
9091
MarkedFiles: marked,
9192
}
9293
command := GoBack{}
9394
newState, _ := command.Execute(initialState)
9495
expectedState := State{
9596
Folder: folder,
96-
history: map[*File]int{folder: 1, subFolder: 1},
97+
history: map[*files.File]int{folder: 1, subFolder: 1},
9798
Selected: 1,
9899
MarkedFiles: marked,
99100
}
100101
assert.Equal(t, expectedState, newState)
101102
}
102103

103104
func TestGoBackOnRoot(t *testing.T) {
104-
folder := NewTestFolder("a", NewTestFile("b", 50))
105+
folder := files.NewTestFolder("a", files.NewTestFile("b", 50))
105106
initialState := State{
106107
Folder: folder,
107108
}
@@ -111,11 +112,11 @@ func TestGoBackOnRoot(t *testing.T) {
111112
}
112113

113114
func TestMarkFile(t *testing.T) {
114-
folder := NewTestFolder("a", NewTestFile("b", 50))
115+
folder := files.NewTestFolder("a", files.NewTestFile("b", 50))
115116
initialState := State{
116117
Folder: folder,
117118
Selected: 0,
118-
MarkedFiles: make(map[*File]struct{}),
119+
MarkedFiles: make(map[*files.File]struct{}),
119120
}
120121
command := Mark{}
121122
newState, _ := command.Execute(initialState)

core/processor.go renamed to commands/processor.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,25 @@
1-
package core
1+
package commands
22

33
import (
44
"fmt"
55
"sync"
6+
7+
"github.com/viktomas/godu/files"
68
)
79

810
// ProcessFolder removes small files and sorts folder content based on accumulated size
9-
func ProcessFolder(folder *File, limit int64) error {
10-
pruneFolder(folder, limit)
11+
func ProcessFolder(folder *files.File, limit int64) error {
12+
files.PruneSmallFiles(folder, limit)
1113
if len(folder.Files) == 0 {
12-
return fmt.Errorf("the folder '%s' doesn't contain any files bigger than %dMB", folder.Name, limit/MEGABYTE)
14+
return fmt.Errorf("the folder '%s' doesn't contain any files bigger than %dMB", folder.Name, limit/files.MEGABYTE)
1315
}
14-
SortDesc(folder)
16+
files.SortDesc(folder)
1517
return nil
1618
}
1719

1820
// StartProcessing reads user commands and applies them to state
1921
func StartProcessing(
20-
folder *File,
22+
folder *files.File,
2123
commands <-chan Executer,
2224
states chan<- State,
2325
lastStateChan chan<- *State,
@@ -26,7 +28,7 @@ func StartProcessing(
2628
defer wg.Done()
2729
state := State{
2830
Folder: folder,
29-
MarkedFiles: make(map[*File]struct{}),
31+
MarkedFiles: make(map[*files.File]struct{}),
3032
}
3133
states <- state
3234
for {

core/processor_test.go renamed to commands/processor_test.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
1-
package core
1+
package commands
22

33
import (
44
"sync"
55
"testing"
66

77
"github.com/stretchr/testify/assert"
8+
"github.com/viktomas/godu/files"
89
)
910

1011
func TestProcessFolder(t *testing.T) {
11-
folder := NewTestFolder("a", NewTestFile("b", 10), NewTestFile("c", 50), NewTestFile("d", 70))
12+
folder := files.NewTestFolder("a", files.NewTestFile("b", 10), files.NewTestFile("c", 50), files.NewTestFile("d", 70))
1213
ProcessFolder(folder, 30)
13-
c := &File{"c", nil, 50, false, []*File{}}
14-
d := &File{"d", nil, 70, false, []*File{}}
15-
a := &File{"a", nil, 130, true, []*File{d, c}}
14+
c := &files.File{"c", nil, 50, false, []*files.File{}}
15+
d := &files.File{"d", nil, 70, false, []*files.File{}}
16+
a := &files.File{"a", nil, 130, true, []*files.File{d, c}}
1617
d.Parent = a
1718
c.Parent = a
1819
assert.Equal(t, a, folder, "ProcessFoler didn't prune and sort folder")
1920
}
2021

2122
func TestProcessFolderShouldFailWithSmallFiles(t *testing.T) {
22-
folder := NewTestFolder("a", NewTestFile("b", 70))
23+
folder := files.NewTestFolder("a", files.NewTestFile("b", 70))
2324
err := ProcessFolder(folder, 80)
2425
assert.NotNil(t, err, "ProcessFolder didn't result in error when run on folder with too small files")
2526
}
@@ -28,7 +29,7 @@ func TestStartProcessing(t *testing.T) {
2829
commands := make(chan Executer)
2930
states := make(chan State, 2)
3031
lastStateChan := make(chan<- *State, 1)
31-
folder := NewTestFolder("a", NewTestFile("b", 10), NewTestFile("c", 50))
32+
folder := files.NewTestFolder("a", files.NewTestFile("b", 10), files.NewTestFile("c", 50))
3233
var wg sync.WaitGroup
3334
wg.Add(1)
3435
go StartProcessing(folder, commands, states, lastStateChan, &wg)
@@ -48,7 +49,7 @@ func TestDoesntProcessInvalidCommand(t *testing.T) {
4849
lastStateChan := make(chan<- *State, 1)
4950
var wg sync.WaitGroup
5051
wg.Add(1)
51-
folder := NewTestFolder("a", NewTestFile("b", 10), NewTestFile("c", 50))
52+
folder := files.NewTestFolder("a", files.NewTestFile("b", 10), files.NewTestFile("c", 50))
5253
go StartProcessing(folder, commands, states, lastStateChan, &wg)
5354
<-states
5455
commands <- Enter{}

core/const.go renamed to files/const.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
package core
1+
package files
22

33
const (
4-
_ = iota
4+
_ = iota
55
KILOBYTE = 1 << (10 * iota)
66
MEGABYTE
77
GIGABYTE

core/file_walker.go renamed to files/file_walker.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package core
1+
package files
22

33
import (
44
"log"

core/file_walker_test.go renamed to files/file_walker_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package core
1+
package files
22

33
import (
44
"errors"

core/test_utils.go renamed to files/test_utils.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package core
1+
package files
22

33
// NewTestFolder is providing easy interface to create folders for automated tests
44
// Never use in production code!

core/test_utils_test.go renamed to files/test_utils_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package core
1+
package files
22

33
import (
44
"testing"

0 commit comments

Comments
 (0)