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 }