Compare commits

..

4 commits

Author SHA1 Message Date
Arnas Udovicius
2d1ac09ba1 code fix 2022-05-08 23:19:55 +03:00
Arnas Udovicius
fdbbc02d0a Updated README 2022-05-08 12:40:09 +03:00
Arnas Udovicius
057f6c1b1b Updated README; added fixFormat, ReadFileContent 2022-05-08 12:33:40 +03:00
Arnas Udovicius
76ba9ea0c5 upgraded dependences 2021-05-12 08:21:03 +03:00
6 changed files with 199 additions and 13 deletions

View file

@ -1,6 +1,67 @@
# zord-tree # zord-tree
Library for golang to build articles tree from file system. Library for golang to build articles tree from file system. The file should be in specific format to hold meta data, id and
content.
Process should go in two steps:
* populate existing `source` directory with formatting files, add missing `id` and meta data
* build `Tree` to operate on object for your app
* read file content without meta data by path
## File and tree format
### Category
During building `Tree` directory path is converted into array of categories. So, file in path `linux/command/video` will get
categories: `linux`, `command`, `video`.
### Split line
File meta should be split by `---` line. If there is markdown formating to mark header, first such case (`---`) will be formatted
to contain empty line. Example:
```
Text
---
```
will become
```
Text
---
```
### Meta data
Meta data separated by lines and in format `name: value`. By default library supports `tags` as comma separated array.
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.
### File structure
```
tags: linux,command,video
meta1: example
meta2: some long description
---
Hear goes content. It can be written in html, markdown or whatever what can be processed later
```
## Notes ## Notes
### Future plans
* 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
### TODO
* test to read file content

2
go.mod
View file

@ -4,5 +4,5 @@ go 1.16
require ( require (
g.arns.lt/zordsdavini/abcex v1.0.0 g.arns.lt/zordsdavini/abcex v1.0.0
github.com/otiai10/copy v1.5.1 github.com/otiai10/copy v1.6.0
) )

2
go.sum
View file

@ -2,6 +2,8 @@ g.arns.lt/zordsdavini/abcex v1.0.0 h1:qQqlZ4DMfethCGK4I6yGaLqMrTzKNIshqpINd1l3t0
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 h1:a/cs2E1/1V0az8K5nblbl+ymEa4E11AfaOLMar8V34w=
github.com/otiai10/copy v1.5.1/go.mod h1:XWfuS3CrI0R6IE0FbgHsEazaXO8G0LpMp9o8tos0x4E= 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/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=
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=

View file

@ -1,7 +1,7 @@
tags: t1,t2 tags: t1,t2
description: Če test file __va__ description: Če test file __va__
option1: test option option1: test option
--- ---
# Če kažkas torietom būtė # Če kažkas torietom būtė

105
tree.go
View file

@ -33,7 +33,13 @@ func BuildTree(dirPath string, meta []string) (Tree, error) {
} }
func PopulateTree(sourcePath string, destPath string, meta []string) error { func PopulateTree(sourcePath string, destPath string, meta []string) error {
id, err := getMaxId(sourcePath) err := fixFormat(sourcePath)
if err != nil {
return err
}
var id int64 = 0
id, err = getMaxId(sourcePath)
if err != nil { if err != nil {
return err return err
} }
@ -54,6 +60,56 @@ func PopulateTree(sourcePath string, destPath string, meta []string) error {
return err return err
} }
func fixFormat(dir string) error {
err := filepath.Walk(dir, func(path string, info os.FileInfo, e error) error {
if e != nil {
return e
}
if info.Mode().IsRegular() {
b, err := ioutil.ReadFile(path) // just pass the file name
if err != nil {
return err
}
osf, err := os.Open(path)
if err != nil {
return err
}
// remove all empty lines and separate split line
content := ""
format := true
scanner := bufio.NewScanner(osf)
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
line := scanner.Text()
if line == "---" {
format = false
}
if format {
line = strings.Trim(line, " ")
if line != "" {
content = content + "\n" + line
}
} else {
content = content + "\n" + line
}
}
err = ioutil.WriteFile(path, []byte(content), 0644)
// format split line
str := string(b)
str = strings.Replace(str, "\n---\n", "\n\n---\n", 1)
err = ioutil.WriteFile(path, []byte(str), 0644)
}
return nil
})
return err
}
func addMissingMeta(dir string, meta []string) error { func addMissingMeta(dir string, meta []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 {
@ -95,11 +151,8 @@ func addMissingMeta(dir string, meta []string) error {
} }
return nil return nil
}) })
if err != nil {
return err
}
return nil return err
} }
func addMissingId(dir string, id int64) error { func addMissingId(dir string, id int64) error {
@ -262,12 +315,50 @@ func readFile(file fs.FileInfo, fullPath string, category []string, meta []strin
} }
for _, option := range meta { for _, option := range meta {
if strings.HasPrefix(line, option) { if strings.HasPrefix(line, option) {
line = strings.TrimPrefix(line, option + ":") line = strings.TrimPrefix(line, option+":")
f.Meta[option] = strings.Trim(line, " ") f.Meta[option] = strings.Trim(line, " ")
} }
} }
} }
osf.Close() _ = osf.Close()
return f, nil return f, nil
} }
func ReadFileContent(file File) (string, error) {
osf, err := os.Open(file.FullPath)
if err != nil {
return "", err
}
content := ""
removeEmptyLine := true
isMetaPart := true
scanner := bufio.NewScanner(osf)
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
line := scanner.Text()
if line == "---" {
isMetaPart = false
continue
}
if isMetaPart {
continue
}
if removeEmptyLine {
line = strings.Trim(line, " ")
if line == "" {
continue
} else {
removeEmptyLine = false
}
}
content = content + "\n" + line
}
_ = osf.Close()
return content, nil
}

View file

@ -47,6 +47,38 @@ func TestSunny(t *testing.T) {
t.Log(tree) t.Log(tree)
} }
func TestFixFormat(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")
}
err = PopulateTree("./testdata/sunny1", "./testdata/sunny2", []string{})
if err != nil {
t.Fatal("Population ended in err:", err)
}
b, err := ioutil.ReadFile("./testdata/sunny2/file1.md")
if err != nil {
t.Fatal("No destination file 'file1.md'.")
}
str := string(b)
if !strings.Contains(str, "tags: t1,t2\ndescription: Če test file __va__\n") {
t.Fatal("Empty lines has not been removed in file 'file1.md'.")
}
if !strings.Contains(str, "\n\n---\n") {
t.Fatal("Split line has not been formatted in file 'file1.md'.")
}
t.Log(tree)
}
func TestMeta(t *testing.T) { func TestMeta(t *testing.T) {
err := os.Remove("./testdata/sunny1") err := os.Remove("./testdata/sunny1")
if err != nil { if err != nil {