added search by id, tree slice and filter

This commit is contained in:
Arnas Udovicius 2022-08-01 17:02:25 +03:00
parent d252680e45
commit 8ea36234a9
5 changed files with 160 additions and 69 deletions

View file

@ -41,6 +41,8 @@ Meta data separated by lines and in format `* name: value`. By default library s
During populating tree it adds missing `id` in `abcex` format and empty meta data lines and saves in `source` directory then copy During populating tree it adds missing `id` in `abcex` format and empty meta data lines and saves in `source` directory then copy
to `destination` directory. to `destination` directory.
There is possibility to add custom default value. That is passed with custom function what returns string.
### File structure ### File structure
``` ```
@ -54,10 +56,10 @@ Hear goes content. It can be written in html, markdown or whatever what can be p
``` ```
## Notes ## Usage
### Future plans There are two main commands: `PopulateTree` to prepare source (format, add metadata and add Id) and copy from source to destination and `BuildTree` to get object of tree.
`Tree` object has methods: `FileById` to get `File` by Id, `Slice` to get sub-tree of given path and `Filter` to filter tree by filter.
Filter contains array of meta key and searching value. `tag` key is searched as equal and other meta values of keys can contain part.
* add meta as function, ex. today date
* add meta with default value that should be used if other value is not set, ex. license
* add search on Tree

2
go.mod
View file

@ -1,6 +1,6 @@
module g.arns.lt/zordsdavini/zord-tree module g.arns.lt/zordsdavini/zord-tree
go 1.16 go 1.18
require ( require (
g.arns.lt/zordsdavini/abcex v1.0.0 g.arns.lt/zordsdavini/abcex v1.0.0

2
go.sum
View file

@ -1,7 +1,5 @@
g.arns.lt/zordsdavini/abcex v1.0.0 h1:qQqlZ4DMfethCGK4I6yGaLqMrTzKNIshqpINd1l3t0E= g.arns.lt/zordsdavini/abcex v1.0.0 h1:qQqlZ4DMfethCGK4I6yGaLqMrTzKNIshqpINd1l3t0E=
g.arns.lt/zordsdavini/abcex v1.0.0/go.mod h1:YRcJgts3XZwI+LEkngpfUab3DkUAW387Irpr43hIym8= g.arns.lt/zordsdavini/abcex v1.0.0/go.mod h1:YRcJgts3XZwI+LEkngpfUab3DkUAW387Irpr43hIym8=
github.com/otiai10/copy v1.5.1 h1:a/cs2E1/1V0az8K5nblbl+ymEa4E11AfaOLMar8V34w=
github.com/otiai10/copy v1.5.1/go.mod h1:XWfuS3CrI0R6IE0FbgHsEazaXO8G0LpMp9o8tos0x4E=
github.com/otiai10/copy v1.6.0 h1:IinKAryFFuPONZ7cm6T6E2QX/vcJwSnlaA5lfoaXIiQ= github.com/otiai10/copy v1.6.0 h1:IinKAryFFuPONZ7cm6T6E2QX/vcJwSnlaA5lfoaXIiQ=
github.com/otiai10/copy v1.6.0/go.mod h1:XWfuS3CrI0R6IE0FbgHsEazaXO8G0LpMp9o8tos0x4E= github.com/otiai10/copy v1.6.0/go.mod h1:XWfuS3CrI0R6IE0FbgHsEazaXO8G0LpMp9o8tos0x4E=
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=

83
tree.go
View file

@ -2,6 +2,7 @@ package zord_tree
import ( import (
"bufio" "bufio"
"errors"
"fmt" "fmt"
"g.arns.lt/zordsdavini/abcex" "g.arns.lt/zordsdavini/abcex"
cp "github.com/otiai10/copy" cp "github.com/otiai10/copy"
@ -28,11 +29,79 @@ type Tree struct {
Files []File Files []File
} }
func (t Tree) FileById(id string) (File, error) {
for _, f := range t.Files {
if f.Id == id {
return f, nil
}
}
for _, t2 := range t.Dirs {
f, err := t2.FileById(id)
if err == nil {
return f, nil
}
}
return File{}, errors.New("file was not found")
}
func (t Tree) Slice(path string) (Tree, error) {
if t.Path == path {
return t, nil
}
for _, t2 := range t.Dirs {
t3, err := t2.Slice(path)
if err == nil {
return t3, nil
}
}
return Tree{}, errors.New("tree was not found")
}
func (t Tree) Filter(filter map[string]string) (Tree, bool) {
filtered := Tree{}
filtered.Path = t.Path
found := false
for _, f := range t.Files {
addFile := false
for option, value := range filter {
if option == "tag" {
for _, tag := range f.Tags {
if tag == value {
addFile = true
}
}
continue
}
if strings.Contains(f.Meta[option], value) {
addFile = true
}
}
if addFile {
found = true
filtered.Files = append(filtered.Files, f)
}
}
for _, t2 := range t.Dirs {
filteredChild, foundChild := t2.Filter(filter)
if foundChild {
found = true
filtered.Dirs = append(filtered.Dirs, filteredChild)
}
}
return filtered, found
}
func BuildTree(dirPath string, meta []string) (Tree, error) { func BuildTree(dirPath string, meta []string) (Tree, error) {
return readPath(dirPath, []string{}, meta) return readPath(dirPath, []string{}, meta)
} }
func PopulateTree(sourcePath string, destPath string, meta []string) error { func PopulateTree(sourcePath string, destPath string, meta []string, customMeta map[string]func() string) error {
err := fixFormat(sourcePath) err := fixFormat(sourcePath)
if err != nil { if err != nil {
return err return err
@ -50,7 +119,7 @@ func PopulateTree(sourcePath string, destPath string, meta []string) error {
return err return err
} }
err = addMissingMeta(sourcePath, meta) err = addMissingMeta(sourcePath, meta, customMeta)
if err != nil { if err != nil {
return err return err
} }
@ -110,7 +179,7 @@ func fixFormat(dir string) error {
return err return err
} }
func addMissingMeta(dir string, meta []string) error { func addMissingMeta(dir string, meta []string, customMeta map[string]func() string) error {
err := filepath.Walk(dir, func(path string, info os.FileInfo, e error) error { err := filepath.Walk(dir, func(path string, info os.FileInfo, e error) error {
if e != nil { if e != nil {
return e return e
@ -138,7 +207,11 @@ func addMissingMeta(dir string, meta []string) error {
if line == "---" { if line == "---" {
for option, process := range check { for option, process := range check {
if !process { if !process {
err = addMeta(path, option, "") defaultValue := ""
if _, ok := customMeta[option]; ok {
defaultValue = customMeta[option]()
}
err = addMeta(path, option, defaultValue)
if err != nil { if err != nil {
return err return err
} }
@ -247,7 +320,7 @@ func getMaxId(dir string) (int64, error) {
func readPath(dirPath string, category []string, meta []string) (Tree, error) { func readPath(dirPath string, category []string, meta []string) (Tree, error) {
tree := Tree{} tree := Tree{}
tree.Path = dirPath tree.Path = strings.TrimPrefix(dirPath, "./")
files, err := ioutil.ReadDir(dirPath) files, err := ioutil.ReadDir(dirPath)
if err != nil { if err != nil {

View file

@ -8,6 +8,19 @@ import (
"testing" "testing"
) )
func prepare(t *testing.T) {
err := os.Remove("./testdata/sunny1")
if err != nil {
}
err = os.Remove("./testdata/sunny2")
if err != nil {
}
err = cp.Copy("./testdata/sunny", "./testdata/sunny1")
if err != nil {
t.Fatal("Couldn't prepare data for testing")
}
}
func TestFromNotExistingDirectory(t *testing.T) { func TestFromNotExistingDirectory(t *testing.T) {
_, err := BuildTree("./testing/i_dont_exist", []string{}) _, err := BuildTree("./testing/i_dont_exist", []string{})
if err == nil { if err == nil {
@ -16,13 +29,8 @@ func TestFromNotExistingDirectory(t *testing.T) {
} }
func TestSunny(t *testing.T) { func TestSunny(t *testing.T) {
err := os.Remove("./testdata/sunny1") prepare(t)
if err != nil {
}
err = cp.Copy("./testdata/sunny", "./testdata/sunny1")
if err != nil {
t.Fatal("Couldn't prepare data for testing")
}
tree, err := BuildTree("./testdata/sunny1", []string{}) tree, err := BuildTree("./testdata/sunny1", []string{})
if err != nil { if err != nil {
t.Errorf("Got error: %v", err) t.Errorf("Got error: %v", err)
@ -48,18 +56,9 @@ func TestSunny(t *testing.T) {
} }
func TestFixFormat(t *testing.T) { func TestFixFormat(t *testing.T) {
err := os.Remove("./testdata/sunny1") prepare(t)
if err != nil {
}
err = os.Remove("./testdata/sunny2")
if err != nil {
}
err = cp.Copy("./testdata/sunny", "./testdata/sunny1")
if err != nil {
t.Fatal("Couldn't prepare data for testing")
}
err = PopulateTree("./testdata/sunny1", "./testdata/sunny2", []string{}) err := PopulateTree("./testdata/sunny1", "./testdata/sunny2", []string{}, nil)
if err != nil { if err != nil {
t.Fatal("Population ended in err:", err) t.Fatal("Population ended in err:", err)
} }
@ -79,13 +78,8 @@ func TestFixFormat(t *testing.T) {
} }
func TestMeta(t *testing.T) { func TestMeta(t *testing.T) {
err := os.Remove("./testdata/sunny1") prepare(t)
if err != nil {
}
err = cp.Copy("./testdata/sunny", "./testdata/sunny1")
if err != nil {
t.Fatal("Couldn't prepare data for testing")
}
meta := []string{"option1", "option2"} meta := []string{"option1", "option2"}
tree, err := BuildTree("./testdata/sunny1", meta) tree, err := BuildTree("./testdata/sunny1", meta)
@ -103,18 +97,9 @@ func TestMeta(t *testing.T) {
} }
func TestId(t *testing.T) { func TestId(t *testing.T) {
err := os.Remove("./testdata/sunny1") prepare(t)
if err != nil {
}
err = os.Remove("./testdata/sunny2")
if err != nil {
}
err = cp.Copy("./testdata/sunny", "./testdata/sunny1")
if err != nil {
t.Fatal("Couldn't prepare data for testing")
}
err = PopulateTree("./testdata/sunny1", "./testdata/sunny2", []string{}) err := PopulateTree("./testdata/sunny1", "./testdata/sunny2", []string{}, nil)
if err != nil { if err != nil {
t.Fatal("Population ended in err:", err) t.Fatal("Population ended in err:", err)
} }
@ -139,18 +124,13 @@ func TestId(t *testing.T) {
} }
func TestMissingOptions(t *testing.T) { func TestMissingOptions(t *testing.T) {
err := os.Remove("./testdata/sunny1") prepare(t)
if err != nil {
}
err = os.Remove("./testdata/sunny2")
if err != nil {
}
err = cp.Copy("./testdata/sunny", "./testdata/sunny1")
if err != nil {
t.Fatal("Couldn't prepare data for testing")
}
err = PopulateTree("./testdata/sunny1", "./testdata/sunny2", []string{"option1", "option2"}) customMeta := make(map[string]func() string)
customMeta["option2"] = func() string {
return "customDefaultValue"
}
err := PopulateTree("./testdata/sunny1", "./testdata/sunny2", []string{"option1", "option2"}, customMeta)
if err != nil { if err != nil {
t.Fatal("Population ended in err:", err) t.Fatal("Population ended in err:", err)
} }
@ -163,7 +143,7 @@ func TestMissingOptions(t *testing.T) {
if !strings.Contains(str, "\n* option1: test option\n") { if !strings.Contains(str, "\n* option1: test option\n") {
t.Fatal("Changed old value for 'option1' in file 'file1.md'.") t.Fatal("Changed old value for 'option1' in file 'file1.md'.")
} }
if !strings.Contains(str, "\n* option2: \n") { if !strings.Contains(str, "\n* option2: customDefaultValue\n") {
t.Fatal("'option2' has not been added to file 'file1.md'.") t.Fatal("'option2' has not been added to file 'file1.md'.")
} }
@ -175,7 +155,7 @@ func TestMissingOptions(t *testing.T) {
if !strings.Contains(str, "\n* option1: \n") { if !strings.Contains(str, "\n* option1: \n") {
t.Fatal("'option1' has not been added to file 'file2.md'.") t.Fatal("'option1' has not been added to file 'file2.md'.")
} }
if !strings.Contains(str, "\n* option2: \n") { if !strings.Contains(str, "\n* option2: customDefaultValue\n") {
t.Fatal("'option2' has not been added to file 'file2.md'.") t.Fatal("'option2' has not been added to file 'file2.md'.")
} }
@ -193,13 +173,7 @@ func TestMissingOptions(t *testing.T) {
} }
func TestReadingFileContent(t *testing.T) { func TestReadingFileContent(t *testing.T) {
err := os.Remove("./testdata/sunny1") prepare(t)
if err != nil {
}
err = cp.Copy("./testdata/sunny", "./testdata/sunny1")
if err != nil {
t.Fatal("Couldn't prepare data for testing")
}
tree, err := BuildTree("./testdata/sunny1", []string{}) tree, err := BuildTree("./testdata/sunny1", []string{})
@ -216,3 +190,47 @@ func TestReadingFileContent(t *testing.T) {
t.Error("File content is wrong...") t.Error("File content is wrong...")
} }
} }
func TestGetSlice(t *testing.T) {
prepare(t)
err := PopulateTree("./testdata/sunny1", "./testdata/sunny2", []string{}, nil)
if err != nil {
t.Fatal("Population ended in err:", err)
}
tree, err := BuildTree("./testdata/sunny2", []string{})
if err != nil {
t.Errorf("Got error: %v", err)
}
tree2, err := tree.Slice("testdata/sunny2/subcategory")
if err != nil {
t.Errorf("Error during search the tree: %v", err)
}
if tree2.Files[0].Name != "file3.md" {
t.Errorf("Got frong tree")
}
}
func TestGetFileById(t *testing.T) {
prepare(t)
err := PopulateTree("./testdata/sunny1", "./testdata/sunny2", []string{}, nil)
if err != nil {
t.Fatal("Population ended in err:", err)
}
tree, err := BuildTree("./testdata/sunny2", []string{})
if err != nil {
t.Errorf("Got error: %v", err)
}
file, err := tree.FileById("3")
if err != nil {
t.Errorf("Error during search: %v", err)
}
if file.Name != "file3.md" {
t.Errorf("Got frong file: %s", file.Name)
}
}