Mercurial > yakumo_izuru > aya
annotate zs.go @ 3:53dea9841cd9 draft
moved eval func type to the top, added some error logs
author | zaitsev.serge |
---|---|
date | Fri, 05 Dec 2014 17:26:59 +0000 |
parents | fd79b3a90bef |
children | 05fc24caac37 |
rev | line source |
---|---|
0 | 1 package main |
2 | |
3 import ( | |
4 "bytes" | |
5 "fmt" | |
6 "io" | |
7 "io/ioutil" | |
8 "log" | |
9 "os" | |
10 "os/exec" | |
11 "path" | |
12 "path/filepath" | |
13 "strings" | |
14 "time" | |
15 | |
16 "github.com/russross/blackfriday" | |
17 ) | |
18 | |
19 const ( | |
20 ZSDIR = ".zs" | |
21 PUBDIR = ".pub" | |
22 ) | |
23 | |
3
53dea9841cd9
moved eval func type to the top, added some error logs
zaitsev.serge
parents:
2
diff
changeset
|
24 type EvalFn func(args []string, vars map[string]string) (string, error) |
53dea9841cd9
moved eval func type to the top, added some error logs
zaitsev.serge
parents:
2
diff
changeset
|
25 |
0 | 26 func split2(s, delim string) (string, string) { |
27 parts := strings.SplitN(s, delim, 2) | |
28 if len(parts) == 2 { | |
29 return parts[0], parts[1] | |
30 } else { | |
31 return parts[0], "" | |
32 } | |
33 } | |
34 | |
35 func md(s string) (map[string]string, string) { | |
36 v := map[string]string{} | |
2 | 37 if strings.Index(s, "\n\n") == -1 { |
38 return map[string]string{}, s | |
39 } | |
0 | 40 header, body := split2(s, "\n\n") |
41 for _, line := range strings.Split(header, "\n") { | |
42 key, value := split2(line, ":") | |
43 v[strings.ToLower(strings.TrimSpace(key))] = strings.TrimSpace(value) | |
44 } | |
45 return v, body | |
46 } | |
47 | |
48 func render(s string, vars map[string]string, eval EvalFn) (string, error) { | |
49 b := []byte(s) | |
50 delim_open := []byte("{{") | |
51 delim_close := []byte("}}") | |
52 | |
53 out := bytes.NewBuffer(nil) | |
54 for { | |
55 if from := bytes.Index(b, delim_open); from == -1 { | |
56 out.Write(b) | |
57 return out.String(), nil | |
58 } else { | |
59 to := bytes.Index(b, delim_close) | |
60 if to == -1 { | |
61 return "", fmt.Errorf("Close delim not found") | |
62 } else { | |
63 out.Write(b[:from]) | |
64 cmd := b[from+len(delim_open) : to] | |
65 b = b[to+len(delim_close):] | |
66 m := strings.Fields(string(cmd)) | |
67 if len(m) == 1 { | |
68 if v, ok := vars[m[0]]; ok { | |
69 out.Write([]byte(v)) | |
70 continue | |
71 } | |
72 } | |
73 if res, err := eval(m, vars); err == nil { | |
74 out.Write([]byte(res)) | |
75 } else { | |
76 log.Println(err) // silent | |
77 } | |
78 } | |
79 } | |
80 } | |
81 } | |
82 | |
83 func eval(cmd []string, vars map[string]string) (string, error) { | |
84 var outbuf, errbuf bytes.Buffer | |
85 c := exec.Command(path.Join(ZSDIR, cmd[0]), cmd[1:]...) | |
86 env := []string{"ZS=" + os.Args[0]} | |
87 for k, v := range vars { | |
88 env = append(env, "ZS_"+strings.ToUpper(k)+"="+v) | |
89 } | |
90 c.Env = append(c.Env, env...) | |
91 c.Stdout = &outbuf | |
92 c.Stderr = &errbuf | |
93 if err := c.Run(); err != nil { | |
94 log.Println(err) | |
95 c := exec.Command(path.Join(cmd[0]), cmd[1:]...) | |
96 c.Env = append(c.Env, env...) | |
97 c.Stdout = &outbuf | |
98 c.Stderr = &errbuf | |
99 if err := c.Run(); err != nil { | |
100 return "", err | |
101 } | |
102 } | |
103 if errbuf.Len() > 0 { | |
104 log.Println(errbuf.String()) | |
105 } | |
106 return outbuf.String(), nil | |
107 } | |
108 | |
109 func buildMarkdown(path string) error { | |
110 b, err := ioutil.ReadFile(path) | |
111 if err != nil { | |
112 return err | |
113 } | |
114 v, body := md(string(b)) | |
115 defaultVars(v, path) | |
116 content, err := render(body, v, eval) | |
117 if err != nil { | |
118 return err | |
119 } | |
120 v["content"] = string(blackfriday.MarkdownBasic([]byte(content))) | |
121 b, err = ioutil.ReadFile(filepath.Join(ZSDIR, v["layout"])) | |
122 if err != nil { | |
123 return err | |
124 } | |
125 content, err = render(string(b), v, eval) | |
126 if err != nil { | |
127 return err | |
128 } | |
129 err = ioutil.WriteFile(v["output"], []byte(content), 0666) | |
130 if err != nil { | |
131 return err | |
132 } | |
133 return nil | |
134 } | |
135 | |
136 func defaultVars(vars map[string]string, path string) { | |
137 if _, ok := vars["file"]; !ok { | |
138 vars["file"] = path | |
139 } | |
140 if _, ok := vars["url"]; !ok { | |
141 vars["url"] = path[:len(path)-len(filepath.Ext(path))] + ".html" | |
142 if strings.HasPrefix(vars["url"], "./") { | |
143 vars["url"] = vars["url"][2:] | |
144 } | |
145 } | |
146 if _, ok := vars["outdir"]; !ok { | |
147 vars["outdir"] = PUBDIR | |
148 } | |
149 if _, ok := vars["output"]; !ok { | |
150 vars["output"] = filepath.Join(PUBDIR, vars["url"]) | |
151 } | |
152 if _, ok := vars["layout"]; !ok { | |
153 vars["layout"] = "index.html" | |
154 } | |
155 } | |
156 | |
157 func copyFile(path string) error { | |
158 if in, err := os.Open(path); err != nil { | |
159 return err | |
160 } else { | |
161 defer in.Close() | |
162 if stat, err := in.Stat(); err != nil { | |
163 return err | |
164 } else { | |
165 // Directory? | |
166 if stat.Mode().IsDir() { | |
167 os.Mkdir(filepath.Join(PUBDIR, path), 0755) | |
168 return nil | |
169 } | |
170 if !stat.Mode().IsRegular() { | |
171 return nil | |
172 } | |
173 } | |
174 if out, err := os.Create(filepath.Join(PUBDIR, path)); err != nil { | |
175 return err | |
176 } else { | |
177 defer out.Close() | |
178 _, err = io.Copy(out, in) | |
179 return err | |
180 } | |
181 } | |
182 } | |
183 | |
184 func buildAll(once bool) { | |
185 lastModified := time.Unix(0, 0) | |
186 for { | |
187 os.Mkdir(PUBDIR, 0755) | |
188 err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error { | |
189 // ignore hidden files and directories | |
190 if filepath.Base(path)[0] == '.' || strings.HasPrefix(path, ".") { | |
191 return nil | |
192 } | |
193 | |
194 if info.ModTime().After(lastModified) { | |
195 ext := filepath.Ext(path) | |
196 if ext == ".md" || ext == "mkd" { | |
197 log.Println("mkd: ", path) | |
198 return buildMarkdown(path) | |
199 } else { | |
200 log.Println("raw: ", path) | |
201 return copyFile(path) | |
202 } | |
203 } | |
204 return nil | |
205 }) | |
206 if err != nil { | |
207 log.Println("ERROR:", err) | |
208 } | |
209 lastModified = time.Now() | |
210 if once { | |
211 break | |
212 } | |
213 time.Sleep(1 * time.Second) | |
214 } | |
215 } | |
216 | |
217 func main() { | |
218 if len(os.Args) == 1 { | |
219 fmt.Println(os.Args[0], "<command> [args]") | |
220 return | |
221 } | |
222 cmd := os.Args[1] | |
223 args := os.Args[2:] | |
224 switch cmd { | |
225 case "build": | |
226 buildAll(true) | |
227 case "watch": | |
228 buildAll(false) // pass duration | |
229 case "var": | |
230 if len(args) == 0 { | |
3
53dea9841cd9
moved eval func type to the top, added some error logs
zaitsev.serge
parents:
2
diff
changeset
|
231 log.Println("ERROR: filename expected") |
0 | 232 return |
233 } | |
234 if b, err := ioutil.ReadFile(args[0]); err == nil { | |
235 vars, _ := md(string(b)) | |
236 defaultVars(vars, args[0]) | |
237 if len(args) > 1 { | |
238 for _, a := range args[1:] { | |
239 fmt.Println(vars[a]) | |
240 } | |
241 } else { | |
242 for k, v := range vars { | |
243 fmt.Println(k + ":" + v) | |
244 } | |
245 } | |
246 } else { | |
3
53dea9841cd9
moved eval func type to the top, added some error logs
zaitsev.serge
parents:
2
diff
changeset
|
247 log.Println(err) |
0 | 248 } |
249 default: | |
250 cmd := exec.Command(path.Join(ZSDIR, cmd), args...) | |
251 cmd.Env = append(cmd.Env, "ZS="+os.Args[0]) | |
252 cmd.Stdout = os.Stdout | |
253 cmd.Stderr = os.Stderr | |
254 if err := cmd.Run(); err != nil { | |
255 log.Println(err) | |
256 } | |
257 } | |
258 } |