Skip to content

Commit 9b179d7

Browse files
committed
Implemented the tree structure generator
1 parent 714b5af commit 9b179d7

File tree

4 files changed

+201
-1
lines changed

4 files changed

+201
-1
lines changed

cmd/root.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,11 @@ var rootCmd = &cobra.Command{
3737
return
3838
}
3939

40-
internal.Help()
40+
processed := internal.ProcessInput(args)
41+
42+
if !processed {
43+
internal.Help()
44+
}
4145
},
4246
}
4347

internal/filesystem.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package internal
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"os"
7+
)
8+
9+
func createDirectory(path string) {
10+
err := os.MkdirAll(path, 0755)
11+
12+
if err != nil {
13+
if Verbose && os.IsExist(err) {
14+
fmt.Println(err)
15+
} else {
16+
FatalError(err)
17+
}
18+
}
19+
}
20+
21+
func createFile(path string) {
22+
var modes int
23+
24+
if Force {
25+
modes = os.O_CREATE | os.O_TRUNC
26+
} else {
27+
modes = os.O_CREATE | os.O_EXCL
28+
}
29+
30+
file, err := os.OpenFile(path, modes, 0644)
31+
32+
if err != nil {
33+
if Verbose && errors.Is(err, os.ErrExist) {
34+
fmt.Println(err)
35+
} else {
36+
FatalError(err)
37+
}
38+
}
39+
40+
defer file.Close()
41+
}

internal/generate.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package internal
2+
3+
import (
4+
"path/filepath"
5+
"strings"
6+
)
7+
8+
const (
9+
gap = " "
10+
ascChild = "├── "
11+
ascSubChild = "│ "
12+
ascEndChild = "└── "
13+
txtChild = "|-- "
14+
txtSubChild = "| "
15+
txtEndChild = "+-- "
16+
)
17+
18+
func generate(lines []string) {
19+
level := 0
20+
dir := lines[0]
21+
22+
createDirectory(dir)
23+
24+
for i, line := range lines[1:] {
25+
currentLevel := nodeLevel(line)
26+
27+
if currentLevel > level {
28+
parentDir := nodeName(lines[i]) // name of previous line
29+
dir = dir + parentDir
30+
level++
31+
} else if currentLevel < level {
32+
dir = strings.TrimRight(dir, "/")
33+
dir = moveUpDirectories(dir, level-currentLevel)
34+
dir = dir + "/"
35+
level = currentLevel // could drop down multiple levels
36+
}
37+
38+
nodePath := dir + nodeName(line)
39+
40+
if strings.HasSuffix(nodePath, "/") {
41+
createDirectory(nodePath)
42+
} else {
43+
createFile(nodePath)
44+
}
45+
}
46+
}
47+
48+
func nodeLevel(line string) int {
49+
level := 0
50+
51+
for {
52+
if strings.HasPrefix(line, ascSubChild) {
53+
level++
54+
line = line[len(ascSubChild):]
55+
} else if strings.HasPrefix(line, txtSubChild) {
56+
level++
57+
line = line[len(txtSubChild):]
58+
} else if strings.HasPrefix(line, gap) {
59+
level++
60+
line = line[len(gap):]
61+
} else {
62+
break
63+
}
64+
}
65+
66+
return level
67+
}
68+
69+
func nodeName(line string) string {
70+
return strings.TrimLeft(line, "└├ ─│|+-")
71+
}
72+
73+
func moveUpDirectories(path string, n int) string {
74+
for i := 0; i < n; i++ {
75+
path = filepath.Dir(path)
76+
}
77+
78+
return path
79+
}

internal/input.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package internal
2+
3+
import (
4+
"bufio"
5+
"os"
6+
)
7+
8+
func ProcessInput(args []string) bool {
9+
processed := false
10+
11+
if len(args) > 0 {
12+
for _, path := range args {
13+
tree := readFromFile(path)
14+
15+
if len(tree) > 0 {
16+
generate(tree)
17+
processed = true
18+
}
19+
}
20+
}
21+
22+
tree := readFromStdIn()
23+
24+
if len(tree) > 0 {
25+
generate(tree)
26+
processed = true
27+
}
28+
29+
return processed
30+
}
31+
32+
func readFromFile(path string) []string {
33+
file, err := os.Open(path)
34+
35+
if err != nil {
36+
FatalError(err)
37+
}
38+
39+
defer file.Close()
40+
41+
scanner := bufio.NewScanner(file)
42+
43+
var lines []string
44+
45+
for scanner.Scan() {
46+
lines = append(lines, scanner.Text())
47+
}
48+
49+
if err := scanner.Err(); err != nil {
50+
FatalError(err)
51+
}
52+
53+
return lines
54+
}
55+
56+
func readFromStdIn() []string {
57+
stat, _ := os.Stdin.Stat()
58+
59+
if (stat.Mode() & os.ModeCharDevice) != 0 {
60+
return []string{}
61+
}
62+
63+
scanner := bufio.NewScanner(os.Stdin)
64+
65+
var lines []string
66+
67+
for scanner.Scan() {
68+
lines = append(lines, scanner.Text())
69+
}
70+
71+
if err := scanner.Err(); err != nil {
72+
FatalError(err)
73+
}
74+
75+
return lines
76+
}

0 commit comments

Comments
 (0)