diff options
| author | Julian Hurst <ark@mansus.space> | 2025-09-29 18:50:00 +0200 |
|---|---|---|
| committer | Julian Hurst <ark@mansus.space> | 2025-09-29 18:50:00 +0200 |
| commit | e3552f592ba5bce3fa3243166679fed986b6b949 (patch) | |
| tree | a0eca31771a17dc955d769862d7bdd12d8100f0c | |
| download | ssg-e3552f592ba5bce3fa3243166679fed986b6b949.tar.gz | |
Initial commit
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | base.html | 9 | ||||
| -rwxr-xr-x | converter/md2html | 3 | ||||
| -rwxr-xr-x | converter/skipmetadata | bin | 0 -> 2288264 bytes | |||
| -rw-r--r-- | converter/skipmetadata.go | 30 | ||||
| -rw-r--r-- | go.mod | 3 | ||||
| -rw-r--r-- | head.html | 3 | ||||
| -rw-r--r-- | index.html | 15 | ||||
| -rw-r--r-- | posts/chickens.md | 8 | ||||
| -rw-r--r-- | posts/rabbits.md | 6 | ||||
| -rw-r--r-- | ssg.go | 261 |
11 files changed, 340 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b857cda --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +public +ssg diff --git a/base.html b/base.html new file mode 100644 index 0000000..280cb7c --- /dev/null +++ b/base.html @@ -0,0 +1,9 @@ +<!DOCTYPE html> +<html> +<head> + {{template "head"}} +</head> +<body> + {{template "body" .}} +</body> +</html> diff --git a/converter/md2html b/converter/md2html new file mode 100755 index 0000000..331f348 --- /dev/null +++ b/converter/md2html @@ -0,0 +1,3 @@ +#!/bin/sh + +md2html diff --git a/converter/skipmetadata b/converter/skipmetadata Binary files differnew file mode 100755 index 0000000..c683e66 --- /dev/null +++ b/converter/skipmetadata diff --git a/converter/skipmetadata.go b/converter/skipmetadata.go new file mode 100644 index 0000000..869604e --- /dev/null +++ b/converter/skipmetadata.go @@ -0,0 +1,30 @@ +package main + +import ( + "fmt" + "os" + "bufio" +) + +func main() { + if len(os.Args) != 2 { + fmt.Fprintf(os.Stderr, "USAGE: %s file\n", os.Args[0]) + } + f, err := os.Open(os.Args[1]) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + defer f.Close() + sc := bufio.NewScanner(f) + doPrint := false + for sc.Scan() { + line := sc.Text() + if doPrint { + fmt.Println(line) + } + if line == "----" { + doPrint = true + } + } +} @@ -0,0 +1,3 @@ +module ssg + +go 1.25.1 diff --git a/head.html b/head.html new file mode 100644 index 0000000..236eaf4 --- /dev/null +++ b/head.html @@ -0,0 +1,3 @@ +{{define "head"}} + <link rel="stylesheet" href="/static/style.css"> +{{end}} diff --git a/index.html b/index.html new file mode 100644 index 0000000..d353e18 --- /dev/null +++ b/index.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<head> + {{template "head"}} +</head> +<body> + {{define "body"}} + <h1>My blog</h1> + {{range .}} + <a href="{{.Path}}">{{.Metadata.Name}}</a> + <p>{{.Metadata.Description}}</p> + {{end}} + {{end}} +</body> +</html> diff --git a/posts/chickens.md b/posts/chickens.md new file mode 100644 index 0000000..f7f8d78 --- /dev/null +++ b/posts/chickens.md @@ -0,0 +1,8 @@ +name=cheese +description=chickens are amazing +---- +# Chickens are great + +We all like chickens here, aren't they great?!! + + diff --git a/posts/rabbits.md b/posts/rabbits.md new file mode 100644 index 0000000..9f44d18 --- /dev/null +++ b/posts/rabbits.md @@ -0,0 +1,6 @@ +name=Rabbits are incredible +description=I really like rabbits and think they're awesome. One of my best friends is a Rabbit although he's technically a hare... +---- +# Rabbits!!!! + + @@ -0,0 +1,261 @@ +package main + +import ( + "slices" + "bufio" + "fmt" + "io" + "os" + "os/exec" + "strings" + "path/filepath" + //"flag" + "html/template" + "time" +) + +type post struct { + InPath string + OutPath string + ModTime time.Time +} + +type ParsedPost struct { + Path string + Metadata PostMetadata +} + +type PostMetadata struct { + Name string + Description string +} + +func buildTemplate(f string, w io.Writer, data interface{}) error { + tmpl, err := template.ParseFiles("base.html", "head.html", f) + if err != nil { + return err + } + err = tmpl.Execute(w, data) + if err != nil { + return err + } + return nil +} + +func main() { + args := os.Args + if len(args) != 2 { + fmt.Fprintf(os.Stderr, "USAGE: %s [postsfolder]", args[0]) + os.Exit(1) + } + + + postsOutDir := "public/posts/" + + err := os.MkdirAll(postsOutDir, 0o777) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + f, err := os.Open(args[1]) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + defer f.Close() + + entries, err := f.ReadDir(0) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + var files []post = nil + for _, entry := range entries { + name := entry.Name() + outName := strings.TrimSuffix(name, filepath.Ext(name)) + ".html" + fi, err := entry.Info() + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + p := post { + InPath: filepath.Join(args[1], name), + OutPath: filepath.Join(postsOutDir, outName), + ModTime: fi.ModTime(), + } + files = append(files, p) + } + + slices.SortFunc(files, func(a, b post) int { + if a.ModTime.After(b.ModTime) { + return -1 + } else { + return 1 + } + }) + + pposts, err := parseMetadata(files) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + err = md2html(files) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + idx, err := os.Create("public/index.html") + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + //var data []string = nil + //for _, post := range files { + // data = append(data, filepath.Join("posts", filepath.Base(post.OutPath))) + //} + for _, ppost := range pposts { + fmt.Fprintf(os.Stderr, "name: %s, description: %s\n", ppost.Metadata.Name, ppost.Metadata.Description) + } + err = buildTemplate("index.html", idx, pposts) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + +} + +func parseMetadata(files []post) ([]ParsedPost, error) { + var pposts []ParsedPost = nil + for _, file := range files { + + f, err := os.Open(file.InPath) + if err != nil { + return pposts, err + } + defer f.Close() + + sc := bufio.NewScanner(f) + + lnb := 1 + var metadata PostMetadata = PostMetadata {} + for sc.Scan() { + line := sc.Text() + if line == "----" { + break + } + spl := strings.Split(line, "=") + if len(spl) != 2 { + return pposts, fmt.Errorf("Invalid Metadata: %s:%d", file.InPath, lnb) + } + switch spl[0] { + case "name": + metadata.Name = spl[1] + case "description": + metadata.Description = spl[1] + default: + fmt.Fprintf(os.Stderr, "Invalid key: %s (%s:%d)\n", spl[0], file.InPath, lnb) + } + lnb += 1 + } + pposts = append(pposts, ParsedPost { + Path: filepath.Join("posts", filepath.Base(file.OutPath)), + Metadata: metadata, + }) + } + return pposts, nil +} + +func md2html(files []post) error { + for _, file := range files { + //err = os.WriteFile(file.OutPath, out, 0600) + //if err != nil { + // return err + //} + out, err := execcmd(file) + if err != nil { + return err + } + fmt.Println(string(out)) + tmpl, err := template.New("base.html").ParseFiles("base.html", "head.html") + if err != nil { + return err + } + _, err = tmpl.New("body").Parse(string(out)) + if err != nil { + return err + } + f, err := os.Create(file.OutPath) + if err != nil { + return err + } + defer f.Close() + err = tmpl.Execute(f, nil) + if err != nil { + return err + } + } + return nil +} + +func execcmd(file post) ([]byte, error) { + cmd := exec.Command("converter/md2html", file.InPath) + + inPipe, err := cmd.StdinPipe() + if err != nil { + return nil, err + } + outPipe, err := cmd.StdoutPipe() + if err != nil { + return nil, err + } + errPipe, err := cmd.StderrPipe() + if err != nil { + return nil, err + } + + + go func() { + defer inPipe.Close() + f, _ := os.Open(file.InPath) + defer f.Close() + sc := bufio.NewScanner(f) + doPrint := false + for sc.Scan() { + line := sc.Text() + if doPrint { + io.WriteString(inPipe, line + "\n") + } + if line == "----" { + doPrint = true + } + } + io.Copy(inPipe, f) + }() + + fmt.Fprintln(os.Stderr, "stdout") + + var out []byte = nil + go func() { + out, _ = io.ReadAll(outPipe) + }() + + fmt.Fprintln(os.Stderr, "stderr") + + var cmdErr []byte = nil + go func() { + cmdErr, _ = io.ReadAll(errPipe) + }() + + if err := cmd.Start(); err != nil { + return nil, err + } + + if err := cmd.Wait(); err != nil { + return nil, fmt.Errorf("%s\nstderr: %s\n", err, string(cmdErr)) + } + return out, nil +} |
