mirror of
https://git.mills.io/prologic/zs
synced 2024-11-25 23:06:11 +03:00
added amber and gcss compilers
This commit is contained in:
parent
9803539c0f
commit
49a47d065d
5
testdata/sugar/.test/index.html
vendored
Normal file
5
testdata/sugar/.test/index.html
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<p>Hello world</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
1
testdata/sugar/.test/styles.css
vendored
Normal file
1
testdata/sugar/.test/styles.css
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
body{font:100% Helvetica, sans-serif;color:blue;}
|
3
testdata/sugar/index.amber
vendored
Normal file
3
testdata/sugar/index.amber
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
html
|
||||||
|
body
|
||||||
|
p Hello world
|
6
testdata/sugar/styles.gcss
vendored
Normal file
6
testdata/sugar/styles.gcss
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
$base-font: Helvetica, sans-serif
|
||||||
|
$main-color: blue
|
||||||
|
|
||||||
|
body
|
||||||
|
font: 100% $base-font
|
||||||
|
color: $main-color
|
93
zs.go
93
zs.go
@ -13,7 +13,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/eknkc/amber"
|
||||||
"github.com/russross/blackfriday"
|
"github.com/russross/blackfriday"
|
||||||
|
"github.com/yosssi/gcss"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -21,8 +23,12 @@ const (
|
|||||||
PUBDIR = ".pub"
|
PUBDIR = ".pub"
|
||||||
)
|
)
|
||||||
|
|
||||||
type EvalFn func(args []string, vars map[string]string) (string, error)
|
type Vars map[string]string
|
||||||
|
|
||||||
|
type EvalFn func(args []string, vars Vars) (string, error)
|
||||||
|
|
||||||
|
// Splits a string in exactly two parts by delimiter
|
||||||
|
// If no delimiter is found - the second string is be empty
|
||||||
func split2(s, delim string) (string, string) {
|
func split2(s, delim string) (string, string) {
|
||||||
parts := strings.SplitN(s, delim, 2)
|
parts := strings.SplitN(s, delim, 2)
|
||||||
if len(parts) == 2 {
|
if len(parts) == 2 {
|
||||||
@ -32,16 +38,22 @@ func split2(s, delim string) (string, string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func md(path, s string) (map[string]string, string) {
|
// Parses markdown content. Returns parsed header variables and content
|
||||||
|
func md(path string) (Vars, string, error) {
|
||||||
|
b, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
s := string(b)
|
||||||
url := path[:len(path)-len(filepath.Ext(path))] + ".html"
|
url := path[:len(path)-len(filepath.Ext(path))] + ".html"
|
||||||
v := map[string]string{
|
v := Vars{
|
||||||
"file": path,
|
"file": path,
|
||||||
"url": url,
|
"url": url,
|
||||||
"output": filepath.Join(PUBDIR, url),
|
"output": filepath.Join(PUBDIR, url),
|
||||||
"layout": "index.html",
|
"layout": "index.html",
|
||||||
}
|
}
|
||||||
if strings.Index(s, "\n\n") == -1 {
|
if strings.Index(s, "\n\n") == -1 {
|
||||||
return map[string]string{}, s
|
return Vars{}, s, nil
|
||||||
}
|
}
|
||||||
header, body := split2(s, "\n\n")
|
header, body := split2(s, "\n\n")
|
||||||
for _, line := range strings.Split(header, "\n") {
|
for _, line := range strings.Split(header, "\n") {
|
||||||
@ -51,10 +63,10 @@ func md(path, s string) (map[string]string, string) {
|
|||||||
if strings.HasPrefix(v["url"], "./") {
|
if strings.HasPrefix(v["url"], "./") {
|
||||||
v["url"] = v["url"][2:]
|
v["url"] = v["url"][2:]
|
||||||
}
|
}
|
||||||
return v, body
|
return v, body, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func render(s string, vars map[string]string, eval EvalFn) (string, error) {
|
func render(s string, vars Vars, eval EvalFn) (string, error) {
|
||||||
delim_open := "{{"
|
delim_open := "{{"
|
||||||
delim_close := "}}"
|
delim_close := "}}"
|
||||||
|
|
||||||
@ -87,7 +99,8 @@ func render(s string, vars map[string]string, eval EvalFn) (string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func env(vars map[string]string) []string {
|
// Converts zs markdown variables into environment variables
|
||||||
|
func env(vars Vars) []string {
|
||||||
env := []string{"ZS=" + os.Args[0], "ZS_OUTDIR=" + PUBDIR}
|
env := []string{"ZS=" + os.Args[0], "ZS_OUTDIR=" + PUBDIR}
|
||||||
env = append(env, os.Environ()...)
|
env = append(env, os.Environ()...)
|
||||||
if vars != nil {
|
if vars != nil {
|
||||||
@ -98,7 +111,9 @@ func env(vars map[string]string) []string {
|
|||||||
return env
|
return env
|
||||||
}
|
}
|
||||||
|
|
||||||
func run(cmd string, args []string, vars map[string]string, output io.Writer) error {
|
// Runs command with given arguments and variables, intercepts stderr and
|
||||||
|
// redirects stdout into the given writer
|
||||||
|
func run(cmd string, args []string, vars Vars, output io.Writer) error {
|
||||||
var errbuf bytes.Buffer
|
var errbuf bytes.Buffer
|
||||||
c := exec.Command(cmd, args...)
|
c := exec.Command(cmd, args...)
|
||||||
c.Env = env(vars)
|
c.Env = env(vars)
|
||||||
@ -117,7 +132,7 @@ func run(cmd string, args []string, vars map[string]string, output io.Writer) er
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func eval(cmd []string, vars map[string]string) (string, error) {
|
func eval(cmd []string, vars Vars) (string, error) {
|
||||||
outbuf := bytes.NewBuffer(nil)
|
outbuf := bytes.NewBuffer(nil)
|
||||||
err := run(path.Join(ZSDIR, cmd[0]), cmd[1:], vars, outbuf)
|
err := run(path.Join(ZSDIR, cmd[0]), cmd[1:], vars, outbuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -135,11 +150,10 @@ func eval(cmd []string, vars map[string]string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func buildMarkdown(path string) error {
|
func buildMarkdown(path string) error {
|
||||||
b, err := ioutil.ReadFile(path)
|
v, body, err := md(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
v, body := md(path, string(b))
|
|
||||||
content, err := render(body, v, eval)
|
content, err := render(body, v, eval)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -148,7 +162,7 @@ func buildMarkdown(path string) error {
|
|||||||
return buildPlain(filepath.Join(ZSDIR, v["layout"]), v)
|
return buildPlain(filepath.Join(ZSDIR, v["layout"]), v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildPlain(path string, vars map[string]string) error {
|
func buildPlain(path string, vars Vars) error {
|
||||||
b, err := ioutil.ReadFile(path)
|
b, err := ioutil.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -168,6 +182,45 @@ func buildPlain(path string, vars map[string]string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func buildGCSS(path string) error {
|
||||||
|
f, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s := strings.TrimSuffix(path, ".gcss") + ".css"
|
||||||
|
log.Println(s)
|
||||||
|
css, err := os.Create(filepath.Join(PUBDIR, s))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
defer css.Close()
|
||||||
|
|
||||||
|
_, err = gcss.Compile(css, f)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildAmber(path string, vars Vars) error {
|
||||||
|
a := amber.New()
|
||||||
|
err := a.ParseFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
t, err := a.Compile()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//amber.FuncMap = amber.FuncMap
|
||||||
|
s := strings.TrimSuffix(path, ".amber") + ".html"
|
||||||
|
f, err := os.Create(filepath.Join(PUBDIR, s))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
return t.Execute(f, vars)
|
||||||
|
}
|
||||||
|
|
||||||
func copyFile(path string) (err error) {
|
func copyFile(path string) (err error) {
|
||||||
var in, out *os.File
|
var in, out *os.File
|
||||||
if in, err = os.Open(path); err == nil {
|
if in, err = os.Open(path); err == nil {
|
||||||
@ -202,10 +255,17 @@ func buildAll(once bool) {
|
|||||||
}
|
}
|
||||||
ext := filepath.Ext(path)
|
ext := filepath.Ext(path)
|
||||||
if ext == ".md" || ext == ".mkd" {
|
if ext == ".md" || ext == ".mkd" {
|
||||||
log.Println("mkd: ", path)
|
log.Println("md: ", path)
|
||||||
return buildMarkdown(path)
|
return buildMarkdown(path)
|
||||||
} else if ext == ".html" || ext == ".xml" {
|
} else if ext == ".html" || ext == ".xml" {
|
||||||
return buildPlain(path, map[string]string{})
|
log.Println("html: ", path)
|
||||||
|
return buildPlain(path, Vars{})
|
||||||
|
} else if ext == ".amber" {
|
||||||
|
log.Println("html: ", path)
|
||||||
|
return buildAmber(path, Vars{})
|
||||||
|
} else if ext == ".gcss" {
|
||||||
|
log.Println("css: ", path)
|
||||||
|
return buildGCSS(path)
|
||||||
} else {
|
} else {
|
||||||
log.Println("raw: ", path)
|
log.Println("raw: ", path)
|
||||||
return copyFile(path)
|
return copyFile(path)
|
||||||
@ -246,8 +306,7 @@ func main() {
|
|||||||
log.Println("ERROR: filename expected")
|
log.Println("ERROR: filename expected")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if b, err := ioutil.ReadFile(args[0]); err == nil {
|
if vars, _, err := md(args[0]); err == nil {
|
||||||
vars, _ := md(args[0], string(b))
|
|
||||||
if len(args) > 1 {
|
if len(args) > 1 {
|
||||||
for _, a := range args[1:] {
|
for _, a := range args[1:] {
|
||||||
fmt.Println(vars[a])
|
fmt.Println(vars[a])
|
||||||
@ -261,7 +320,7 @@ func main() {
|
|||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
err := run(path.Join(ZSDIR, cmd), args, map[string]string{}, os.Stdout)
|
err := run(path.Join(ZSDIR, cmd), args, Vars{}, os.Stdout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
|
17
zs_test.go
17
zs_test.go
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@ -31,14 +32,20 @@ func TestSplit2(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func tmpfile(path, s string) string {
|
||||||
|
ioutil.WriteFile(path, []byte(s), 0644)
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
func TestMD(t *testing.T) {
|
func TestMD(t *testing.T) {
|
||||||
v, body := md("foo.md", `
|
defer os.Remove("foo.md")
|
||||||
|
v, body, _ := md(tmpfile("foo.md", `
|
||||||
title: Hello, world!
|
title: Hello, world!
|
||||||
keywords: foo, bar, baz
|
keywords: foo, bar, baz
|
||||||
empty:
|
empty:
|
||||||
bayan: [:|||:]
|
bayan: [:|||:]
|
||||||
|
|
||||||
this: is a content`)
|
this: is a content`))
|
||||||
if v["title"] != "Hello, world!" {
|
if v["title"] != "Hello, world!" {
|
||||||
t.Error()
|
t.Error()
|
||||||
}
|
}
|
||||||
@ -56,20 +63,20 @@ this: is a content`)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Test empty md
|
// Test empty md
|
||||||
v, body = md("foo.md", "")
|
v, body, _ = md(tmpfile("foo.md", ""))
|
||||||
if len(v) != 0 || len(body) != 0 {
|
if len(v) != 0 || len(body) != 0 {
|
||||||
t.Error(v, body)
|
t.Error(v, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test empty header
|
// Test empty header
|
||||||
v, body = md("foo.md", "Hello")
|
v, body, _ = md(tmpfile("foo.md", "Hello"))
|
||||||
if len(v) != 0 || body != "Hello" {
|
if len(v) != 0 || body != "Hello" {
|
||||||
t.Error(v, body)
|
t.Error(v, body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRender(t *testing.T) {
|
func TestRender(t *testing.T) {
|
||||||
eval := func(a []string, vars map[string]string) (string, error) {
|
eval := func(a []string, vars Vars) (string, error) {
|
||||||
return "hello", nil
|
return "hello", nil
|
||||||
}
|
}
|
||||||
vars := map[string]string{"foo": "bar"}
|
vars := map[string]string{"foo": "bar"}
|
||||||
|
Loading…
Reference in New Issue
Block a user