-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmain.go
219 lines (194 loc) · 4.54 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
package main
import (
"bufio"
"bytes"
"database/sql"
"flag"
"fmt"
"log"
"os"
"path"
"sort"
_ "modernc.org/sqlite"
)
// model
type Category struct {
PID uint64
UUID uint64
Name string
SubCategory []*Category
Article []*Article
}
type Article struct {
RID uint64
AID uint64
Name string
Media []string
}
func (a *Article) readDetail(dir string) {
file, err := os.Open(path.Join(dir, fmt.Sprintf("%d.md", a.AID)))
if err != nil {
log.Fatal(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
scanner.Scan()
a.Name = scanner.Text()[2:]
}
func (c *Category) sortArticleByName() {
sort.Slice(c.Article, func(i, j int) bool {
return c.Article[i].Name > c.Article[j].Name
})
}
// converter
func convertTreeToMarkdown(cat *Category, deep int, buff *bytes.Buffer) {
space := ""
for i := 0; i < deep; i++ {
space = space + " "
}
buff.WriteString(fmt.Sprintf("%s- %s\n", space, cat.Name))
for _, article := range cat.Article {
buff.WriteString(fmt.Sprintf("%s - [%s](./docs/%d.md)\n", space, article.Name, article.AID))
}
for _, category := range cat.SubCategory {
convertTreeToMarkdown(category, deep+1, buff)
}
}
func convertDataToTree(root *Category, input []*Category) []*Category {
var otherNode []*Category
for _, category := range input {
if category.PID == root.UUID {
root.SubCategory = append(root.SubCategory, category)
} else {
otherNode = append(otherNode, category)
}
}
for _, category := range root.SubCategory {
otherNode = convertDataToTree(category, otherNode)
}
return otherNode
}
func bindArticleToCategory(cat []*Category, art []*Article) *Category {
catMap := map[uint64]*Category{}
var root *Category
for _, category := range cat {
catMap[category.UUID] = category
if category.PID == 0 {
root = category
}
}
for _, article := range art {
article.readDetail(path.Join(lib, "docs"))
if c, ok := catMap[article.RID]; ok {
c.Article = append(c.Article, article)
}
}
for _, category := range cat {
category.sortArticleByName()
}
return root
}
// dao
func loadDatasource() (cat []*Category, art []*Article) {
if lib == "" {
log.Fatalf("path to MWebLibrary is empty")
}
sqlPath := path.Join(lib, "mainlib.db")
db, err := sql.Open("sqlite", sqlPath)
if err != nil {
log.Fatalf("open sqlite3 failed: %s", err)
}
defer db.Close()
cat, err = loadCategories(db)
if err != nil {
log.Fatalf("load categories failed: %s", err)
}
art, err = loadArticles(db)
if err != nil {
log.Fatalf("load articles failed: %s", err)
}
return cat, art
}
func loadCategories(db *sql.DB) ([]*Category, error) {
row, err := db.Query("select pid, uuid, name from cat order by sort")
if err != nil {
return nil, err
}
var temp []*Category
for row.Next() {
var (
pid uint64
uuid uint64
name string
)
if err := row.Scan(&pid, &uuid, &name); err == nil {
temp = append(temp, &Category{
PID: pid,
UUID: uuid,
Name: name,
})
}
}
return temp, nil
}
func loadArticles(db *sql.DB) ([]*Article, error) {
row, err := db.Query("select rid, aid from cat_article;")
// row, err := db.Query("select cat_article.rid, cat_article.aid from cat_article left join article on cat_article.aid = article.uuid order by article.sort ;")
if err != nil {
return nil, err
}
var temp []*Article
for row.Next() {
var (
rid uint64
aid uint64
)
if err := row.Scan(&rid, &aid); err == nil {
temp = append(temp, &Article{
RID: rid,
AID: aid,
})
}
}
return temp, nil
}
var (
lib string
target string
mode string
help bool
)
func init() {
home, _ := os.UserHomeDir()
pwd, _ := os.Getwd()
libDefaultPath := home + "/Library/Containers/com.coderforart.MWeb3/Data/Library/Application Support/MWebLibrary"
flag.StringVar(&lib, "path", libDefaultPath, "path to MWebLibrary")
flag.StringVar(&target, "target", pwd, "export README.md directory")
flag.StringVar(&mode, "mode", "debug", "'save': save file, 'debug': print only")
flag.BoolVar(&help, "help", false, "show usage")
flag.Parse()
}
func main() {
if help {
flag.Usage()
return
}
var buffer bytes.Buffer
cat, art := loadDatasource()
root := bindArticleToCategory(cat, art)
buffer.WriteString("# NoteBook\n\n")
convertDataToTree(root, cat)
convertTreeToMarkdown(root, 0, &buffer)
switch mode {
case "save":
err := os.WriteFile(path.Join(target, "README.md"), buffer.Bytes(), 0644)
if err != nil {
log.Fatalf("Write file fail: %v", err)
return
}
case "debug":
fmt.Printf("%s", buffer.String())
default:
log.Fatalf("Unknown mode: %s", mode)
}
}