Mercurial > yakumo_izuru > aya
comparison zs.go @ 17:0214b1b5f5eb draft
added amber and gcss compilers
author | zaitsev.serge |
---|---|
date | Sat, 29 Aug 2015 15:47:16 +0000 |
parents | a9c42bd52f64 |
children | ae3116ea938b |
comparison
equal
deleted
inserted
replaced
16:be58ace6edae | 17:0214b1b5f5eb |
---|---|
11 "path" | 11 "path" |
12 "path/filepath" | 12 "path/filepath" |
13 "strings" | 13 "strings" |
14 "time" | 14 "time" |
15 | 15 |
16 "github.com/eknkc/amber" | |
16 "github.com/russross/blackfriday" | 17 "github.com/russross/blackfriday" |
18 "github.com/yosssi/gcss" | |
17 ) | 19 ) |
18 | 20 |
19 const ( | 21 const ( |
20 ZSDIR = ".zs" | 22 ZSDIR = ".zs" |
21 PUBDIR = ".pub" | 23 PUBDIR = ".pub" |
22 ) | 24 ) |
23 | 25 |
24 type EvalFn func(args []string, vars map[string]string) (string, error) | 26 type Vars map[string]string |
25 | 27 |
28 type EvalFn func(args []string, vars Vars) (string, error) | |
29 | |
30 // Splits a string in exactly two parts by delimiter | |
31 // If no delimiter is found - the second string is be empty | |
26 func split2(s, delim string) (string, string) { | 32 func split2(s, delim string) (string, string) { |
27 parts := strings.SplitN(s, delim, 2) | 33 parts := strings.SplitN(s, delim, 2) |
28 if len(parts) == 2 { | 34 if len(parts) == 2 { |
29 return parts[0], parts[1] | 35 return parts[0], parts[1] |
30 } else { | 36 } else { |
31 return parts[0], "" | 37 return parts[0], "" |
32 } | 38 } |
33 } | 39 } |
34 | 40 |
35 func md(path, s string) (map[string]string, string) { | 41 // Parses markdown content. Returns parsed header variables and content |
42 func md(path string) (Vars, string, error) { | |
43 b, err := ioutil.ReadFile(path) | |
44 if err != nil { | |
45 return nil, "", err | |
46 } | |
47 s := string(b) | |
36 url := path[:len(path)-len(filepath.Ext(path))] + ".html" | 48 url := path[:len(path)-len(filepath.Ext(path))] + ".html" |
37 v := map[string]string{ | 49 v := Vars{ |
38 "file": path, | 50 "file": path, |
39 "url": url, | 51 "url": url, |
40 "output": filepath.Join(PUBDIR, url), | 52 "output": filepath.Join(PUBDIR, url), |
41 "layout": "index.html", | 53 "layout": "index.html", |
42 } | 54 } |
43 if strings.Index(s, "\n\n") == -1 { | 55 if strings.Index(s, "\n\n") == -1 { |
44 return map[string]string{}, s | 56 return Vars{}, s, nil |
45 } | 57 } |
46 header, body := split2(s, "\n\n") | 58 header, body := split2(s, "\n\n") |
47 for _, line := range strings.Split(header, "\n") { | 59 for _, line := range strings.Split(header, "\n") { |
48 key, value := split2(line, ":") | 60 key, value := split2(line, ":") |
49 v[strings.ToLower(strings.TrimSpace(key))] = strings.TrimSpace(value) | 61 v[strings.ToLower(strings.TrimSpace(key))] = strings.TrimSpace(value) |
50 } | 62 } |
51 if strings.HasPrefix(v["url"], "./") { | 63 if strings.HasPrefix(v["url"], "./") { |
52 v["url"] = v["url"][2:] | 64 v["url"] = v["url"][2:] |
53 } | 65 } |
54 return v, body | 66 return v, body, nil |
55 } | 67 } |
56 | 68 |
57 func render(s string, vars map[string]string, eval EvalFn) (string, error) { | 69 func render(s string, vars Vars, eval EvalFn) (string, error) { |
58 delim_open := "{{" | 70 delim_open := "{{" |
59 delim_close := "}}" | 71 delim_close := "}}" |
60 | 72 |
61 out := bytes.NewBuffer(nil) | 73 out := bytes.NewBuffer(nil) |
62 for { | 74 for { |
85 } | 97 } |
86 } | 98 } |
87 } | 99 } |
88 } | 100 } |
89 | 101 |
90 func env(vars map[string]string) []string { | 102 // Converts zs markdown variables into environment variables |
103 func env(vars Vars) []string { | |
91 env := []string{"ZS=" + os.Args[0], "ZS_OUTDIR=" + PUBDIR} | 104 env := []string{"ZS=" + os.Args[0], "ZS_OUTDIR=" + PUBDIR} |
92 env = append(env, os.Environ()...) | 105 env = append(env, os.Environ()...) |
93 if vars != nil { | 106 if vars != nil { |
94 for k, v := range vars { | 107 for k, v := range vars { |
95 env = append(env, "ZS_"+strings.ToUpper(k)+"="+v) | 108 env = append(env, "ZS_"+strings.ToUpper(k)+"="+v) |
96 } | 109 } |
97 } | 110 } |
98 return env | 111 return env |
99 } | 112 } |
100 | 113 |
101 func run(cmd string, args []string, vars map[string]string, output io.Writer) error { | 114 // Runs command with given arguments and variables, intercepts stderr and |
115 // redirects stdout into the given writer | |
116 func run(cmd string, args []string, vars Vars, output io.Writer) error { | |
102 var errbuf bytes.Buffer | 117 var errbuf bytes.Buffer |
103 c := exec.Command(cmd, args...) | 118 c := exec.Command(cmd, args...) |
104 c.Env = env(vars) | 119 c.Env = env(vars) |
105 c.Stdout = output | 120 c.Stdout = output |
106 c.Stderr = &errbuf | 121 c.Stderr = &errbuf |
115 return err | 130 return err |
116 } | 131 } |
117 return nil | 132 return nil |
118 } | 133 } |
119 | 134 |
120 func eval(cmd []string, vars map[string]string) (string, error) { | 135 func eval(cmd []string, vars Vars) (string, error) { |
121 outbuf := bytes.NewBuffer(nil) | 136 outbuf := bytes.NewBuffer(nil) |
122 err := run(path.Join(ZSDIR, cmd[0]), cmd[1:], vars, outbuf) | 137 err := run(path.Join(ZSDIR, cmd[0]), cmd[1:], vars, outbuf) |
123 if err != nil { | 138 if err != nil { |
124 if _, ok := err.(*exec.ExitError); ok { | 139 if _, ok := err.(*exec.ExitError); ok { |
125 return "", err | 140 return "", err |
133 } | 148 } |
134 return outbuf.String(), nil | 149 return outbuf.String(), nil |
135 } | 150 } |
136 | 151 |
137 func buildMarkdown(path string) error { | 152 func buildMarkdown(path string) error { |
138 b, err := ioutil.ReadFile(path) | 153 v, body, err := md(path) |
139 if err != nil { | 154 if err != nil { |
140 return err | 155 return err |
141 } | 156 } |
142 v, body := md(path, string(b)) | |
143 content, err := render(body, v, eval) | 157 content, err := render(body, v, eval) |
144 if err != nil { | 158 if err != nil { |
145 return err | 159 return err |
146 } | 160 } |
147 v["content"] = string(blackfriday.MarkdownBasic([]byte(content))) | 161 v["content"] = string(blackfriday.MarkdownBasic([]byte(content))) |
148 return buildPlain(filepath.Join(ZSDIR, v["layout"]), v) | 162 return buildPlain(filepath.Join(ZSDIR, v["layout"]), v) |
149 } | 163 } |
150 | 164 |
151 func buildPlain(path string, vars map[string]string) error { | 165 func buildPlain(path string, vars Vars) error { |
152 b, err := ioutil.ReadFile(path) | 166 b, err := ioutil.ReadFile(path) |
153 if err != nil { | 167 if err != nil { |
154 return err | 168 return err |
155 } | 169 } |
156 content, err := render(string(b), vars, eval) | 170 content, err := render(string(b), vars, eval) |
164 err = ioutil.WriteFile(output, []byte(content), 0666) | 178 err = ioutil.WriteFile(output, []byte(content), 0666) |
165 if err != nil { | 179 if err != nil { |
166 return err | 180 return err |
167 } | 181 } |
168 return nil | 182 return nil |
183 } | |
184 | |
185 func buildGCSS(path string) error { | |
186 f, err := os.Open(path) | |
187 if err != nil { | |
188 return err | |
189 } | |
190 s := strings.TrimSuffix(path, ".gcss") + ".css" | |
191 log.Println(s) | |
192 css, err := os.Create(filepath.Join(PUBDIR, s)) | |
193 if err != nil { | |
194 return err | |
195 } | |
196 | |
197 defer f.Close() | |
198 defer css.Close() | |
199 | |
200 _, err = gcss.Compile(css, f) | |
201 return err | |
202 } | |
203 | |
204 func buildAmber(path string, vars Vars) error { | |
205 a := amber.New() | |
206 err := a.ParseFile(path) | |
207 if err != nil { | |
208 return err | |
209 } | |
210 t, err := a.Compile() | |
211 if err != nil { | |
212 return err | |
213 } | |
214 //amber.FuncMap = amber.FuncMap | |
215 s := strings.TrimSuffix(path, ".amber") + ".html" | |
216 f, err := os.Create(filepath.Join(PUBDIR, s)) | |
217 if err != nil { | |
218 return err | |
219 } | |
220 defer f.Close() | |
221 return t.Execute(f, vars) | |
169 } | 222 } |
170 | 223 |
171 func copyFile(path string) (err error) { | 224 func copyFile(path string) (err error) { |
172 var in, out *os.File | 225 var in, out *os.File |
173 if in, err = os.Open(path); err == nil { | 226 if in, err = os.Open(path); err == nil { |
200 run(filepath.Join(ZSDIR, "pre"), []string{}, nil, nil) | 253 run(filepath.Join(ZSDIR, "pre"), []string{}, nil, nil) |
201 modified = true | 254 modified = true |
202 } | 255 } |
203 ext := filepath.Ext(path) | 256 ext := filepath.Ext(path) |
204 if ext == ".md" || ext == ".mkd" { | 257 if ext == ".md" || ext == ".mkd" { |
205 log.Println("mkd: ", path) | 258 log.Println("md: ", path) |
206 return buildMarkdown(path) | 259 return buildMarkdown(path) |
207 } else if ext == ".html" || ext == ".xml" { | 260 } else if ext == ".html" || ext == ".xml" { |
208 return buildPlain(path, map[string]string{}) | 261 log.Println("html: ", path) |
262 return buildPlain(path, Vars{}) | |
263 } else if ext == ".amber" { | |
264 log.Println("html: ", path) | |
265 return buildAmber(path, Vars{}) | |
266 } else if ext == ".gcss" { | |
267 log.Println("css: ", path) | |
268 return buildGCSS(path) | |
209 } else { | 269 } else { |
210 log.Println("raw: ", path) | 270 log.Println("raw: ", path) |
211 return copyFile(path) | 271 return copyFile(path) |
212 } | 272 } |
213 } | 273 } |
244 case "var": | 304 case "var": |
245 if len(args) == 0 { | 305 if len(args) == 0 { |
246 log.Println("ERROR: filename expected") | 306 log.Println("ERROR: filename expected") |
247 return | 307 return |
248 } | 308 } |
249 if b, err := ioutil.ReadFile(args[0]); err == nil { | 309 if vars, _, err := md(args[0]); err == nil { |
250 vars, _ := md(args[0], string(b)) | |
251 if len(args) > 1 { | 310 if len(args) > 1 { |
252 for _, a := range args[1:] { | 311 for _, a := range args[1:] { |
253 fmt.Println(vars[a]) | 312 fmt.Println(vars[a]) |
254 } | 313 } |
255 } else { | 314 } else { |
259 } | 318 } |
260 } else { | 319 } else { |
261 log.Println(err) | 320 log.Println(err) |
262 } | 321 } |
263 default: | 322 default: |
264 err := run(path.Join(ZSDIR, cmd), args, map[string]string{}, os.Stdout) | 323 err := run(path.Join(ZSDIR, cmd), args, Vars{}, os.Stdout) |
265 if err != nil { | 324 if err != nil { |
266 log.Println(err) | 325 log.Println(err) |
267 } | 326 } |
268 } | 327 } |
269 } | 328 } |