The fastest, period.
Signed-off-by: Izuru Yakumo <yakumo.izuru@chaotic.ninja> git-svn-id: file:///srv/svn/repo/aya/trunk@56 cec141ff-132a-4243-88a5-ce187bd62f94
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -2,6 +2,6 @@
|
|||||||
*.bak
|
*.bak
|
||||||
**.pub
|
**.pub
|
||||||
|
|
||||||
/zs
|
/aya
|
||||||
/dist
|
/dist
|
||||||
/test.md
|
/test.md
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
---
|
|
||||||
builds:
|
|
||||||
-
|
|
||||||
id: zs
|
|
||||||
binary: zs
|
|
||||||
main: .
|
|
||||||
flags: -tags "static_build"
|
|
||||||
ldflags: -w -X main.Version={{.Version}} -X main.Commit={{.Commit}}
|
|
||||||
env:
|
|
||||||
- CGO_ENABLED=0
|
|
||||||
goos:
|
|
||||||
- darwin
|
|
||||||
- linux
|
|
||||||
goarch:
|
|
||||||
- amd64
|
|
||||||
- arm64
|
|
||||||
signs:
|
|
||||||
- artifacts: checksum
|
|
||||||
release:
|
|
||||||
gitea:
|
|
||||||
owner: prologic
|
|
||||||
name: zs
|
|
||||||
draft: true
|
|
||||||
gitea_urls:
|
|
||||||
api: https://git.mills.io/api/v1/
|
|
||||||
1
LICENSE
1
LICENSE
@@ -1,6 +1,7 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2014 zserge
|
Copyright (c) 2014 zserge
|
||||||
|
Copyright (c) 2023 Izuru Yakumo
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
16
Makefile
16
Makefile
@@ -1,13 +1,17 @@
|
|||||||
destdir ?=
|
destdir ?=
|
||||||
|
goflags ?= -v -ldflags "-w -X `go list`.Version=$(version) -X `go list`.Commit=$(commit)" -tags "static_build"
|
||||||
prefix ?= /usr/local
|
prefix ?= /usr/local
|
||||||
|
version ?= `git rev-list --count HEAD || echo "$version"`
|
||||||
|
commit ?= `git rev-parse --short HEAD || echo "$commit"`
|
||||||
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
go build -v
|
go build ${goflags} ./cmd/aya
|
||||||
clean:
|
clean:
|
||||||
rm -f zs
|
rm -f aya
|
||||||
install:
|
install:
|
||||||
install -m0755 zs ${destdir}${prefix}/bin/zs
|
install -Dm0755 aya ${destdir}${prefix}/bin/aya
|
||||||
install -m0644 zs.1 ${destdir}${prefix}/share/man/man1/zs.1
|
install -Dm0644 aya.1 ${destdir}${prefix}/share/man/man1/aya.1
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -f ${prefix}/bin/zs
|
rm -f ${prefix}/bin/aya
|
||||||
rm -f ${prefix}/share/man/man1/zs.1
|
rm -f ${prefix}/share/man/man1/aya.1
|
||||||
|
|||||||
52
README.md
52
README.md
@@ -1,10 +1,8 @@
|
|||||||
# zs
|
# aya
|
||||||
|
|
||||||
zs is an extremely minimal static site generator written in Go.
|
aya is an extremely minimal static site generator written in Go.
|
||||||
|
|
||||||
It's inspired by `zas` generator, but is even more minimal.
|
This crow tengu stands for 'the fastest one in Gensokyo' and yes this is also a Touhou Project reference.
|
||||||
|
|
||||||
The name stands for 'zen static' as well as it's my initials.
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
@@ -17,9 +15,9 @@ The name stands for 'zen static' as well as it's my initials.
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Download the binaries from Github or build it manually:
|
Build it manually assuming you have Go installed:
|
||||||
|
|
||||||
$ go get git.mills.io/prologic/zs
|
$ go install marisa.chaotic.ninja/aya@latest
|
||||||
|
|
||||||
## Ideology
|
## Ideology
|
||||||
|
|
||||||
@@ -27,7 +25,7 @@ Keep your texts in markdown, or HTML format right in the main directory
|
|||||||
of your blog/site.
|
of your blog/site.
|
||||||
|
|
||||||
Keep all service files (extensions, layout pages, deployment scripts etc)
|
Keep all service files (extensions, layout pages, deployment scripts etc)
|
||||||
in the `.zs` subdirectory.
|
in the `.aya` subdirectory.
|
||||||
|
|
||||||
Define variables in the header of the content files using [YAML]:
|
Define variables in the header of the content files using [YAML]:
|
||||||
|
|
||||||
@@ -40,18 +38,18 @@ Define variables in the header of the content files using [YAML]:
|
|||||||
Use placeholders for variables and plugins in your markdown or html
|
Use placeholders for variables and plugins in your markdown or html
|
||||||
files, e.g. `{{ title }}` or `{{ command arg1 arg2 }}.
|
files, e.g. `{{ title }}` or `{{ command arg1 arg2 }}.
|
||||||
|
|
||||||
Write extensions in any language you like and put them into the `.zs`
|
Write extensions in any language you like and put them into the `.aya`
|
||||||
subdiretory.
|
subdiretory.
|
||||||
|
|
||||||
Everything the extensions prints to stdout becomes the value of the
|
Everything the extensions prints to stdout becomes the value of the
|
||||||
placeholder.
|
placeholder.
|
||||||
|
|
||||||
Every variable from the content header will be passed via environment variables like `title` becomes `$ZS_TITLE` and so on. There are some special variables:
|
Every variable from the content header will be passed via environment variables like `title` becomes `$AYA_TITLE` and so on. There are some special variables:
|
||||||
|
|
||||||
* `$ZS` - a path to the `zs` executable
|
* `$AYA` - a path to the `aya` executable
|
||||||
* `$ZS_OUTDIR` - a path to the directory with generated files
|
* `$AYA_OUTDIR` - a path to the directory with generated files
|
||||||
* `$ZS_FILE` - a path to the currently processed markdown file
|
* `$AYA_FILE` - a path to the currently processed markdown file
|
||||||
* `$ZS_URL` - a URL for the currently generated page
|
* `$AYA_URL` - a URL for the currently generated page
|
||||||
|
|
||||||
## Example of RSS generation
|
## Example of RSS generation
|
||||||
|
|
||||||
@@ -59,19 +57,19 @@ Extensions can be written in any language you know (Bash, Python, Lua, JavaScrip
|
|||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
for f in ./blog/*.md ; do
|
for f in ./blog/*.md ; do
|
||||||
d=$($ZS var $f date)
|
d=$($AYA var $f date)
|
||||||
if [ ! -z $d ] ; then
|
if [ ! -z $d ] ; then
|
||||||
timestamp=`date --date "$d" +%s`
|
timestamp=`date --date "$d" +%s`
|
||||||
url=`$ZS var $f url`
|
url=`$AYA var $f url`
|
||||||
title=`$ZS var $f title | tr A-Z a-z`
|
title=`$AYA var $f title | tr A-Z a-z`
|
||||||
descr=`$ZS var $f description`
|
descr=`$AYA var $f description`
|
||||||
echo $timestamp \
|
echo $timestamp \
|
||||||
"<item>" \
|
"<item>" \
|
||||||
"<title>$title</title>" \
|
"<title>$title</title>" \
|
||||||
"<link>http://zserge.com/$url</link>" \
|
"<link>http://ayaerge.com/$url</link>" \
|
||||||
"<description>$descr</description>" \
|
"<description>$descr</description>" \
|
||||||
"<pubDate>$(date --date @$timestamp -R)</pubDate>" \
|
"<pubDate>$(date --date @$timestamp -R)</pubDate>" \
|
||||||
"<guid>http://zserge.com/$url</guid>" \
|
"<guid>http://ayaerge.com/$url</guid>" \
|
||||||
"</item>"
|
"</item>"
|
||||||
fi
|
fi
|
||||||
done | sort -r -n | cut -d' ' -f2-
|
done | sort -r -n | cut -d' ' -f2-
|
||||||
@@ -83,21 +81,21 @@ There are two special plugin names that are executed every time the build
|
|||||||
happens - `prehook` and `posthook`. You can define some global actions here like
|
happens - `prehook` and `posthook`. You can define some global actions here like
|
||||||
content generation, or additional commands, like LESS to CSS conversion:
|
content generation, or additional commands, like LESS to CSS conversion:
|
||||||
|
|
||||||
# .zs/post
|
# .aya/post
|
||||||
|
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
lessc < $ZS_OUTDIR/styles.less > $ZS_OUTDIR/styles.css
|
lessc < $AYA_OUTDIR/styles.less > $AYA_OUTDIR/styles.css
|
||||||
rm -f $ZS_OUTDIR/styles.css
|
rm -f $AYA_OUTDIR/styles.css
|
||||||
|
|
||||||
## Command line usage
|
## Command line usage
|
||||||
|
|
||||||
`zs build` re-builds your site.
|
`aya build` re-builds your site.
|
||||||
|
|
||||||
`zs build <file>` re-builds one file and prints resulting content to stdout.
|
`aya build <file>` re-builds one file and prints resulting content to stdout.
|
||||||
|
|
||||||
`zs watch` rebuilds your site every time you modify any file.
|
`aya watch` rebuilds your site every time you modify any file.
|
||||||
|
|
||||||
`zs var <filename> [var1 var2...]` prints a list of variables defined in the
|
`aya var <filename> [var1 var2...]` prints a list of variables defined in the
|
||||||
header of a given markdown file, or the values of certain variables (even if
|
header of a given markdown file, or the values of certain variables (even if
|
||||||
it's an empty string).
|
it's an empty string).
|
||||||
|
|
||||||
|
|||||||
37
aya.1
Normal file
37
aya.1
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
.Dd $Mdocdate$
|
||||||
|
.Dt AYA 1
|
||||||
|
.Os
|
||||||
|
.Sh NAME
|
||||||
|
.Nm aya
|
||||||
|
.Nd A really fast static site generator
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
Does it need one?
|
||||||
|
.Sh FEATURES
|
||||||
|
.Bl -tag -width 11n -compact
|
||||||
|
.It Zero configuration (no configuration file needed)
|
||||||
|
.It Cross-platform
|
||||||
|
.It Highly extensible
|
||||||
|
.It Works well for blogs and generic static websites (landing pages etc)
|
||||||
|
.It Easy to learn
|
||||||
|
.It Fast (of course)
|
||||||
|
.El
|
||||||
|
.Sh USAGE
|
||||||
|
.Ss (Re-)build your site.
|
||||||
|
.Nm
|
||||||
|
.Cm build
|
||||||
|
.Ss (Re-)build one file and prints resulting content to standard output.
|
||||||
|
.Nm
|
||||||
|
.Cm build
|
||||||
|
.Ar <file>
|
||||||
|
.Ss (Re-)build your site every time you modify any file.
|
||||||
|
.Nm
|
||||||
|
.Cm watch
|
||||||
|
.Ss Print a list of variables defined in the header of a given markdown file.
|
||||||
|
.Nm
|
||||||
|
.Cm var
|
||||||
|
.Ar <file>
|
||||||
|
.Ar <var1> <var2> ...
|
||||||
|
.Sh AUTHORS
|
||||||
|
.Nm
|
||||||
|
is maintained by Izuru Yakumo
|
||||||
|
.Aq Lk https://pub.chaotic.ninja/~yakumo_izuru/
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/md5"
|
|
||||||
"encoding/hex"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
const TESTDIR = ".test"
|
|
||||||
|
|
||||||
func TestBuild(t *testing.T) {
|
|
||||||
files, _ := ioutil.ReadDir("testdata")
|
|
||||||
for _, f := range files {
|
|
||||||
if f.IsDir() {
|
|
||||||
testBuild(filepath.Join("testdata", f.Name()), t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testBuild(path string, t *testing.T) {
|
|
||||||
wd, _ := os.Getwd()
|
|
||||||
os.Chdir(path)
|
|
||||||
args := os.Args[:]
|
|
||||||
os.Args = []string{"zs", "build"}
|
|
||||||
t.Log("--- BUILD", path)
|
|
||||||
main()
|
|
||||||
|
|
||||||
compare(PUBDIR, TESTDIR, t)
|
|
||||||
|
|
||||||
os.Chdir(wd)
|
|
||||||
os.Args = args
|
|
||||||
}
|
|
||||||
|
|
||||||
func compare(pub, test string, t *testing.T) {
|
|
||||||
a := md5dir(pub)
|
|
||||||
b := md5dir(test)
|
|
||||||
for k, v := range a {
|
|
||||||
if s, ok := b[k]; !ok {
|
|
||||||
t.Error("Unexpected file:", k, v)
|
|
||||||
} else if s != v {
|
|
||||||
t.Error("Different file:", k, v, s)
|
|
||||||
} else {
|
|
||||||
t.Log("Matching file", k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for k, v := range b {
|
|
||||||
if _, ok := a[k]; !ok {
|
|
||||||
t.Error("Missing file:", k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func md5dir(path string) map[string]string {
|
|
||||||
files := map[string]string{}
|
|
||||||
filepath.Walk(path, func(s string, info os.FileInfo, err error) error {
|
|
||||||
if err == nil && !info.IsDir() {
|
|
||||||
if f, err := os.Open(s); err == nil {
|
|
||||||
defer f.Close()
|
|
||||||
hash := md5.New()
|
|
||||||
io.Copy(hash, f)
|
|
||||||
files[strings.TrimPrefix(s, path)] = hex.EncodeToString(hash.Sum(nil))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return files
|
|
||||||
}
|
|
||||||
@@ -15,10 +15,11 @@ import (
|
|||||||
|
|
||||||
"github.com/russross/blackfriday/v2"
|
"github.com/russross/blackfriday/v2"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
|
"marisa.chaotic.ninja/aya"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ZSDIR = ".zs"
|
AYADIR = ".aya"
|
||||||
PUBDIR = ".pub"
|
PUBDIR = ".pub"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -38,12 +39,12 @@ func renameExt(path, oldext, newext string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// globals returns list of global OS environment variables that start
|
// globals returns list of global OS environment variables that start
|
||||||
// with ZS_ prefix as Vars, so the values can be used inside templates
|
// with AYA_ prefix as Vars, so the values can be used inside templates
|
||||||
func globals() Vars {
|
func globals() Vars {
|
||||||
vars := Vars{}
|
vars := Vars{}
|
||||||
for _, e := range os.Environ() {
|
for _, e := range os.Environ() {
|
||||||
pair := strings.Split(e, "=")
|
pair := strings.Split(e, "=")
|
||||||
if strings.HasPrefix(pair[0], "ZS_") {
|
if strings.HasPrefix(pair[0], "AYA_") {
|
||||||
vars[strings.ToLower(pair[0][3:])] = pair[1]
|
vars[strings.ToLower(pair[0][3:])] = pair[1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,21 +52,21 @@ func globals() Vars {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// run executes a command or a script. Vars define the command environment,
|
// run executes a command or a script. Vars define the command environment,
|
||||||
// each zs var is converted into OS environemnt variable with ZS_ prefix
|
// each aya var is converted into OS environemnt variable with AYA_ prefix
|
||||||
// prepended. Additional variable $ZS contains path to the zs binary. Command
|
// prepended. Additional variable $AYA contains path to the aya binary. Command
|
||||||
// stderr is printed to zs stderr, command output is returned as a string.
|
// stderr is printed to aya stderr, command output is returned as a string.
|
||||||
func run(vars Vars, cmd string, args ...string) (string, error) {
|
func run(vars Vars, cmd string, args ...string) (string, error) {
|
||||||
// First check if partial exists (.html)
|
// First check if partial exists (.html)
|
||||||
if b, err := ioutil.ReadFile(filepath.Join(ZSDIR, cmd+".html")); err == nil {
|
if b, err := ioutil.ReadFile(filepath.Join(AYADIR, cmd+".html")); err == nil {
|
||||||
return string(b), nil
|
return string(b), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var errbuf, outbuf bytes.Buffer
|
var errbuf, outbuf bytes.Buffer
|
||||||
c := exec.Command(cmd, args...)
|
c := exec.Command(cmd, args...)
|
||||||
env := []string{"ZS=" + os.Args[0], "ZS_OUTDIR=" + PUBDIR}
|
env := []string{"AYA=" + os.Args[0], "AYA_OUTDIR=" + PUBDIR}
|
||||||
env = append(env, os.Environ()...)
|
env = append(env, os.Environ()...)
|
||||||
for k, v := range vars {
|
for k, v := range vars {
|
||||||
env = append(env, "ZS_"+strings.ToUpper(k)+"="+v)
|
env = append(env, "AYA_"+strings.ToUpper(k)+"="+v)
|
||||||
}
|
}
|
||||||
c.Env = env
|
c.Env = env
|
||||||
c.Stdout = &outbuf
|
c.Stdout = &outbuf
|
||||||
@@ -136,7 +137,7 @@ func getVars(path string, globals Vars) (Vars, string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render expanding zs plugins and variables
|
// Render expanding aya plugins and variables
|
||||||
func render(s string, vars Vars) (string, error) {
|
func render(s string, vars Vars) (string, error) {
|
||||||
delim_open := "{{"
|
delim_open := "{{"
|
||||||
delim_close := "}}"
|
delim_close := "}}"
|
||||||
@@ -193,7 +194,7 @@ func buildMarkdown(path string, w io.Writer, vars Vars) error {
|
|||||||
defer out.Close()
|
defer out.Close()
|
||||||
w = out
|
w = out
|
||||||
}
|
}
|
||||||
return buildHTML(filepath.Join(ZSDIR, v["layout"]), w, v)
|
return buildHTML(filepath.Join(AYADIR, v["layout"]), w, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renders text file expanding all variable macros inside it
|
// Renders text file expanding all variable macros inside it
|
||||||
@@ -296,9 +297,9 @@ func buildAll(watch bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// prepend .zs to $PATH, so plugins will be found before OS commands
|
// prepend .aya to $PATH, so plugins will be found before OS commands
|
||||||
p := os.Getenv("PATH")
|
p := os.Getenv("PATH")
|
||||||
p = ZSDIR + ":" + p
|
p = AYADIR + ":" + p
|
||||||
os.Setenv("PATH", p)
|
os.Setenv("PATH", p)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,6 +343,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
fmt.Println(strings.TrimSpace(s))
|
fmt.Println(strings.TrimSpace(s))
|
||||||
}
|
}
|
||||||
|
case "version":
|
||||||
|
fmt.Printf("%v\n", aya.Version)
|
||||||
|
os.Exit(0)
|
||||||
default:
|
default:
|
||||||
if s, err := run(globals(), cmd, args...); err != nil {
|
if s, err := run(globals(), cmd, args...); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
2
go.mod
2
go.mod
@@ -1,4 +1,4 @@
|
|||||||
module git.mills.io/prologic/zs
|
module marisa.chaotic.ninja/aya
|
||||||
|
|
||||||
go 1.17
|
go 1.17
|
||||||
|
|
||||||
|
|||||||
108
main_test.go
108
main_test.go
@@ -1,108 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestRenameExt(t *testing.T) {
|
|
||||||
if s := renameExt("foo.amber", ".amber", ".html"); s != "foo.html" {
|
|
||||||
t.Error(s)
|
|
||||||
}
|
|
||||||
if s := renameExt("foo.amber", "", ".html"); s != "foo.html" {
|
|
||||||
t.Error(s)
|
|
||||||
}
|
|
||||||
if s := renameExt("foo.amber", ".md", ".html"); s != "foo.amber" {
|
|
||||||
t.Error(s)
|
|
||||||
}
|
|
||||||
if s := renameExt("foo", ".amber", ".html"); s != "foo" {
|
|
||||||
t.Error(s)
|
|
||||||
}
|
|
||||||
if s := renameExt("foo", "", ".html"); s != "foo.html" {
|
|
||||||
t.Error(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRun(t *testing.T) {
|
|
||||||
// external command
|
|
||||||
if s, err := run(Vars{}, "echo", "hello"); err != nil || s != "hello\n" {
|
|
||||||
t.Error(s, err)
|
|
||||||
}
|
|
||||||
// passing variables to plugins
|
|
||||||
if s, err := run(Vars{"foo": "bar"}, "sh", "-c", "echo $ZS_FOO"); err != nil || s != "bar\n" {
|
|
||||||
t.Error(s, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// custom plugin overriding external command
|
|
||||||
os.Mkdir(ZSDIR, 0755)
|
|
||||||
script := `#!/bin/sh
|
|
||||||
echo foo
|
|
||||||
`
|
|
||||||
ioutil.WriteFile(filepath.Join(ZSDIR, "echo"), []byte(script), 0755)
|
|
||||||
if s, err := run(Vars{}, "echo", "hello"); err != nil || s != "foo\n" {
|
|
||||||
t.Error(s, err)
|
|
||||||
}
|
|
||||||
os.Remove(filepath.Join(ZSDIR, "echo"))
|
|
||||||
os.Remove(ZSDIR)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVars(t *testing.T) {
|
|
||||||
tests := map[string]Vars{
|
|
||||||
`
|
|
||||||
foo: bar
|
|
||||||
title: Hello, world!
|
|
||||||
---
|
|
||||||
Some content in markdown
|
|
||||||
`: {
|
|
||||||
"foo": "bar",
|
|
||||||
"title": "Hello, world!",
|
|
||||||
"url": "test.html",
|
|
||||||
"file": "test.md",
|
|
||||||
"output": filepath.Join(PUBDIR, "test.html"),
|
|
||||||
"__content": "Some content in markdown\n",
|
|
||||||
},
|
|
||||||
`
|
|
||||||
url: "example.com/foo.html"
|
|
||||||
---
|
|
||||||
Hello
|
|
||||||
`: {
|
|
||||||
"url": "example.com/foo.html",
|
|
||||||
"__content": "Hello\n",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for script, vars := range tests {
|
|
||||||
ioutil.WriteFile("test.md", []byte(script), 0644)
|
|
||||||
if v, s, err := getVars("test.md", Vars{"baz": "123"}); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
} else if s != vars["__content"] {
|
|
||||||
t.Error(s, vars["__content"])
|
|
||||||
} else {
|
|
||||||
for key, value := range vars {
|
|
||||||
if key != "__content" && v[key] != value {
|
|
||||||
t.Error(key, v[key], value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRender(t *testing.T) {
|
|
||||||
vars := map[string]string{"foo": "bar"}
|
|
||||||
|
|
||||||
if s, _ := render("foo bar", vars); s != "foo bar" {
|
|
||||||
t.Error(s)
|
|
||||||
}
|
|
||||||
if s, _ := render("a {{printf short}} text", vars); s != "a short text" {
|
|
||||||
t.Error(s)
|
|
||||||
}
|
|
||||||
if s, _ := render("{{printf Hello}} x{{foo}}z", vars); s != "Hello xbarz" {
|
|
||||||
t.Error(s)
|
|
||||||
}
|
|
||||||
// Test error case
|
|
||||||
if _, err := render("a {{greet text ", vars); err == nil {
|
|
||||||
t.Error("error expected")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
10
testdata/blog/.test/about.html
vendored
10
testdata/blog/.test/about.html
vendored
@@ -1,10 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>About myself</title>
|
|
||||||
<link href="styles.css" rel="stylesheet" type="text/css" />
|
|
||||||
</head>
|
|
||||||
<body><h1>About myself</h1>
|
|
||||||
|
|
||||||
<p>Hi all. This is a brief description of who I am.</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
17
testdata/blog/.test/index.html
vendored
17
testdata/blog/.test/index.html
vendored
@@ -1,17 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>My blog</title>
|
|
||||||
<link href="styles.css" rel="stylesheet" type="text/css" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<p>Here goes list of posts</p>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<a href="/posts/hello.html">First post</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="/posts/update.html">Second post</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
10
testdata/blog/.test/posts/hello.html
vendored
10
testdata/blog/.test/posts/hello.html
vendored
@@ -1,10 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>First post</title>
|
|
||||||
<link href="styles.css" rel="stylesheet" type="text/css" />
|
|
||||||
</head>
|
|
||||||
<body><h1>First post</h1>
|
|
||||||
|
|
||||||
<p>This is my first post</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
10
testdata/blog/.test/posts/update.html
vendored
10
testdata/blog/.test/posts/update.html
vendored
@@ -1,10 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Second post</title>
|
|
||||||
<link href="styles.css" rel="stylesheet" type="text/css" />
|
|
||||||
</head>
|
|
||||||
<body><h1>Second post</h1>
|
|
||||||
|
|
||||||
<p>This is my second post</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
1
testdata/blog/.test/styles.css
vendored
1
testdata/blog/.test/styles.css
vendored
@@ -1 +0,0 @@
|
|||||||
html{margin:0;padding:0;box-sizing:border-box;}body{font-size:16pt;}
|
|
||||||
6
testdata/blog/.zs/layout.amber
vendored
6
testdata/blog/.zs/layout.amber
vendored
@@ -1,6 +0,0 @@
|
|||||||
html
|
|
||||||
head
|
|
||||||
title #{title}
|
|
||||||
link[href="styles.css"][rel="stylesheet"][type="text/css"]
|
|
||||||
body
|
|
||||||
#{unescaped(content)}
|
|
||||||
7
testdata/blog/about.md
vendored
7
testdata/blog/about.md
vendored
@@ -1,7 +0,0 @@
|
|||||||
title: About myself
|
|
||||||
date: 28-08-2015
|
|
||||||
---
|
|
||||||
|
|
||||||
# {{title}}
|
|
||||||
|
|
||||||
Hi all. This is a brief description of who I am.
|
|
||||||
12
testdata/blog/index.amber
vendored
12
testdata/blog/index.amber
vendored
@@ -1,12 +0,0 @@
|
|||||||
html
|
|
||||||
head
|
|
||||||
title My blog
|
|
||||||
link[href="styles.css"][rel="stylesheet"][type="text/css"]
|
|
||||||
body
|
|
||||||
p Here goes list of posts
|
|
||||||
ul
|
|
||||||
li
|
|
||||||
a[href="/posts/hello.html"] First post
|
|
||||||
li
|
|
||||||
a[href="/posts/update.html"] Second post
|
|
||||||
|
|
||||||
8
testdata/blog/posts/hello.md
vendored
8
testdata/blog/posts/hello.md
vendored
@@ -1,8 +0,0 @@
|
|||||||
title: First post
|
|
||||||
date: 28-08-2015
|
|
||||||
---
|
|
||||||
|
|
||||||
# {{title}}
|
|
||||||
|
|
||||||
This is my first post
|
|
||||||
|
|
||||||
8
testdata/blog/posts/update.md
vendored
8
testdata/blog/posts/update.md
vendored
@@ -1,8 +0,0 @@
|
|||||||
title: Second post
|
|
||||||
date: 29-08-2015
|
|
||||||
---
|
|
||||||
|
|
||||||
# {{title}}
|
|
||||||
|
|
||||||
This is my second post
|
|
||||||
|
|
||||||
7
testdata/blog/styles.gcss
vendored
7
testdata/blog/styles.gcss
vendored
@@ -1,7 +0,0 @@
|
|||||||
html
|
|
||||||
margin: 0
|
|
||||||
padding: 0
|
|
||||||
box-sizing: border-box
|
|
||||||
|
|
||||||
body
|
|
||||||
font-size: 16pt
|
|
||||||
0
testdata/empty/.empty
vendored
0
testdata/empty/.empty
vendored
5
testdata/page/.test/index.html
vendored
5
testdata/page/.test/index.html
vendored
@@ -1,5 +0,0 @@
|
|||||||
<html>
|
|
||||||
<body>
|
|
||||||
<h1>Hello</h1>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
5
testdata/page/index.html
vendored
5
testdata/page/index.html
vendored
@@ -1,5 +0,0 @@
|
|||||||
<html>
|
|
||||||
<body>
|
|
||||||
<h1>{{ printf Hello }}</h1>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
5
testdata/sugar/.test/index.html
vendored
5
testdata/sugar/.test/index.html
vendored
@@ -1,5 +0,0 @@
|
|||||||
<html>
|
|
||||||
<body>
|
|
||||||
<p>Hello world</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
1
testdata/sugar/.test/styles.css
vendored
1
testdata/sugar/.test/styles.css
vendored
@@ -1 +0,0 @@
|
|||||||
body{font:100% Helvetica, sans-serif;color:blue;}
|
|
||||||
3
testdata/sugar/index.amber
vendored
3
testdata/sugar/index.amber
vendored
@@ -1,3 +0,0 @@
|
|||||||
html
|
|
||||||
body
|
|
||||||
p Hello world
|
|
||||||
6
testdata/sugar/styles.gcss
vendored
6
testdata/sugar/styles.gcss
vendored
@@ -1,6 +0,0 @@
|
|||||||
$base-font: Helvetica, sans-serif
|
|
||||||
$main-color: blue
|
|
||||||
|
|
||||||
body
|
|
||||||
font: 100% $base-font
|
|
||||||
color: $main-color
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# Get the highest tag number
|
|
||||||
VERSION="$(git describe --abbrev=0 --tags)"
|
|
||||||
VERSION=${VERSION:-'0.0.0'}
|
|
||||||
|
|
||||||
# Get number parts
|
|
||||||
MAJOR="${VERSION%%.*}"; VERSION="${VERSION#*.}"
|
|
||||||
MINOR="${VERSION%%.*}"; VERSION="${VERSION#*.}"
|
|
||||||
PATCH="${VERSION%%.*}"; VERSION="${VERSION#*.}"
|
|
||||||
|
|
||||||
# Increase version
|
|
||||||
PATCH=$((PATCH+1))
|
|
||||||
|
|
||||||
TAG="${1}"
|
|
||||||
|
|
||||||
if [ "${TAG}" = "" ]; then
|
|
||||||
TAG="${MAJOR}.${MINOR}.${PATCH}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Releasing ${TAG} ..."
|
|
||||||
|
|
||||||
git tag -a -s -m "Release ${TAG}" "${TAG}"
|
|
||||||
git push --tags
|
|
||||||
goreleaser release --rm-dist
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package aya
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|||||||
50
zs.1
50
zs.1
@@ -1,50 +0,0 @@
|
|||||||
.Dd January 7, 2022
|
|
||||||
.Dt ZS 1
|
|
||||||
.Os
|
|
||||||
.Sh NAME
|
|
||||||
.Nm zs
|
|
||||||
.Nd Absolutely minimal static site generator written in Go.
|
|
||||||
.Sh DESCRIPTION
|
|
||||||
.Nm
|
|
||||||
is an extremely minimal static site generator written in Go.
|
|
||||||
.Pp
|
|
||||||
It's inspired by
|
|
||||||
.Em zas
|
|
||||||
generator, but is even more minimal.
|
|
||||||
.Pp
|
|
||||||
The name stands for 'zen static'
|
|
||||||
.Sh FEATURES
|
|
||||||
.Li Zero configuration (no configuration file needed)
|
|
||||||
.Pp
|
|
||||||
.Li Cross-platform
|
|
||||||
.Pp
|
|
||||||
.Li Highly extensible
|
|
||||||
.Pp
|
|
||||||
.Li Works well for blogs and generic static websites (landing pages etc)
|
|
||||||
.Pp
|
|
||||||
.Li Easy to learn
|
|
||||||
.Pp
|
|
||||||
.Li Fast
|
|
||||||
.Sh USAGE
|
|
||||||
.Ss (Re-)build your site.
|
|
||||||
.Nm
|
|
||||||
.Cm build
|
|
||||||
.Ss (Re-)build one file and prints resulting content to standard output.
|
|
||||||
.Nm
|
|
||||||
.Cm build
|
|
||||||
.Ar <file>
|
|
||||||
.Ss (Re-)build your site every time you modify any file.
|
|
||||||
.Nm
|
|
||||||
.Cm watch
|
|
||||||
.Ss Print a list of variables defined in the header of a given markdown file.
|
|
||||||
.Nm
|
|
||||||
.Cm var
|
|
||||||
.Ar <file>
|
|
||||||
.Ar <var1> <var2> ...
|
|
||||||
.Sh AUTHORS
|
|
||||||
.Nm
|
|
||||||
is maintained by James Mills
|
|
||||||
.Aq Lk https://prologic.shortcircuit.net.au/
|
|
||||||
.Pp
|
|
||||||
This manual page was written by Nova
|
|
||||||
.Aq Lk https://tilde.cafe/~novaburst
|
|
||||||
Reference in New Issue
Block a user