summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--roseh.moe.go123
-rw-r--r--templates/blog/post.html.template4
-rw-r--r--templates/blog/posts/2024-10-22_nix_flakes.html.template82
-rw-r--r--templates/index.html.template34
-rw-r--r--templates/outline.html.template11
5 files changed, 225 insertions, 29 deletions
diff --git a/roseh.moe.go b/roseh.moe.go
index 5ce4258..ad09cb5 100644
--- a/roseh.moe.go
+++ b/roseh.moe.go
@@ -1,6 +1,7 @@
package main
import (
+ "bytes"
"embed"
"flag"
"fmt"
@@ -10,6 +11,7 @@ import (
"net/http"
"net/http/httputil"
"net/url"
+ "slices"
"strings"
"time"
)
@@ -36,26 +38,126 @@ func notFound(w http.ResponseWriter, r *http.Request) {
}
}
+//go:embed templates/outline.html.template
+var outlineString string
+
+var outlineTemplate = template.Must(template.New("outline").Parse(outlineString))
+
+var (
+ //go:embed templates/blog/post.html.template
+ postString string
+
+ //go:embed templates/blog/posts
+ blogPostFiles embed.FS
+)
+
+func preloadBlogPosts() map[string][]byte {
+ base, err := outlineTemplate.Clone()
+ if err != nil {
+ log.Fatalf("outlineTemplate.Clone: %s", err)
+ }
+ base, err = base.New("body").Parse(postString)
+ if err != nil {
+ log.Fatalf("post.html.template: invalid template: %s", err)
+ }
+ postTemplates, err := blogPostFiles.ReadDir("templates/blog/posts")
+ if err != nil {
+ log.Fatalf("blog posts: %s", err)
+ }
+ posts := make(map[string][]byte, len(postTemplates))
+ for _, post := range postTemplates {
+ base, err = base.Clone()
+ if err != nil {
+ log.Fatalf("base.Clone: %s", err)
+ }
+ postString, err := blogPostFiles.ReadFile("templates/blog/posts/" + post.Name())
+ if err != nil {
+ log.Fatalf("somehow I fucked the paths up: %s", err)
+ }
+ postTemplate, err := base.New("post").Parse(string(postString))
+ if err != nil {
+ log.Fatalf("%q: invalid template: %s", post.Name(), err)
+ }
+ buf := new(bytes.Buffer)
+ if err := postTemplate.ExecuteTemplate(buf, "outline", nil); err != nil {
+ log.Fatalf("%q: error: %s", post.Name(), err)
+ }
+ posts[strings.TrimSuffix(post.Name(), ".html.template")] = buf.Bytes()
+ }
+ return posts
+}
+
+var blogPostsHTML = preloadBlogPosts()
+
+func blog(w http.ResponseWriter, r *http.Request) {
+ post, ok := blogPostsHTML[strings.TrimPrefix(r.URL.Path, "/blog/")]
+ if !ok {
+ notFound(w, r)
+ return
+ }
+ http.ServeContent(w, r, "post.html", serverStartTime, bytes.NewReader(post))
+}
+
//go:embed templates/index.html.template
var indexString string
-var indexTemplate = template.Must(template.New("index").Parse(indexString))
-
-func index(w http.ResponseWriter, _ *http.Request) {
- if err := indexTemplate.Execute(w, nil); err != nil {
- log.Printf("Warning: index: %s", err)
+func preloadIndex() []byte {
+ base, err := outlineTemplate.Clone()
+ if err != nil {
+ log.Fatalf("outlineTemplate.Clone: %s", err)
+ }
+ base.Funcs(template.FuncMap{
+ "name": func(post string) string {
+ postBytes, err := blogPostFiles.ReadFile("templates/blog/posts/" + post + ".html.template")
+ if err != nil {
+ log.Fatalf("no such post %q: %s", post, err)
+ }
+ date := post[:strings.IndexByte(post, '_')]
+ firstLine := postBytes[:bytes.IndexByte(postBytes, '\n')]
+ return date + ": " + string(bytes.TrimSuffix(bytes.TrimPrefix(firstLine, []byte("<h1>")), []byte("</h1>")))
+ },
+ })
+ indexTemplate, err := base.New("body").Parse(indexString)
+ if err != nil {
+ log.Fatalf("index.html.template: invalid template: %s", err)
+ }
+ posts := make([]string, 0, len(blogPostsHTML))
+ for p := range blogPostsHTML {
+ posts = append(posts, p)
}
+ slices.Sort(posts)
+ buf := new(bytes.Buffer)
+ if err := indexTemplate.ExecuteTemplate(buf, "outline", posts); err != nil {
+ log.Fatalf("index.html.template: error: %s", err)
+ }
+ return buf.Bytes()
+}
+
+var indexHTML = preloadIndex()
+
+func index(w http.ResponseWriter, r *http.Request) {
+ http.ServeContent(w, r, "index.html", serverStartTime, bytes.NewReader(indexHTML))
}
//go:embed templates/pong.html.template
var pongString string
-var pongTemplate = template.Must(template.New("pong").Parse(pongString))
-
-func pong(w http.ResponseWriter, _ *http.Request) {
- if err := pongTemplate.Execute(w, nil); err != nil {
- log.Printf("Warning: pong: %s", err)
+func preloadPong() []byte {
+ pongTemplate, err := template.New("pong").Parse(pongString)
+ if err != nil {
+ log.Fatalf("pong.html.template: invalid template: %s", err)
+ }
+ buf := new(bytes.Buffer)
+ if err := pongTemplate.Execute(buf, nil); err != nil {
+ log.Fatalf("pong.html.template: error: %s", err)
}
+ return buf.Bytes()
+}
+
+var pongHTML = preloadPong()
+
+func pong(w http.ResponseWriter, r *http.Request) {
+ http.ServeContent(w, r, "pong.html", serverStartTime, bytes.NewReader(pongHTML))
}
//go:embed static
@@ -76,6 +178,7 @@ func main() {
flag.Parse()
mux := http.NewServeMux()
+ mux.HandleFunc("/blog/", blog)
mux.HandleFunc("/pong", pong)
jellyfinURL, err := url.Parse("http://localhost:8096")
if err != nil {
diff --git a/templates/blog/post.html.template b/templates/blog/post.html.template
new file mode 100644
index 0000000..ba5e81f
--- /dev/null
+++ b/templates/blog/post.html.template
@@ -0,0 +1,4 @@
+<article>
+ <a href="/">⬅️Home</a>
+{{template "post"}}
+</article>
diff --git a/templates/blog/posts/2024-10-22_nix_flakes.html.template b/templates/blog/posts/2024-10-22_nix_flakes.html.template
new file mode 100644
index 0000000..b9b2ca0
--- /dev/null
+++ b/templates/blog/posts/2024-10-22_nix_flakes.html.template
@@ -0,0 +1,82 @@
+<h1>nix flakes for busy people</h1>
+
+<h2>TL;DR</h2>
+
+<h4>To enable flakes on a NixOS system</h4>
+
+<p>Just put</p>
+
+<pre>
+ nix.settings.experimental-features = [
+ "nix-command"
+ "flakes"
+ ];
+</pre>
+
+<p>in your <code>configuration.nix</code>. IMO it's a shame that flakes
+have been locked behind experimental for so long, it's a large part of
+why they have a bad reputation. It's absolutely worth enabling them
+since they're so useful.</p>
+
+<h4>To use a flake from github</h4>
+
+<pre>
+nix shell github:ggerganov/llama.cpp
+</pre>
+
+<p>or to install a specific flake output:</p>
+
+<pre>
+nix shell github:ggerganov/llama.cpp#rocm
+</pre>
+
+<p>To list the outputs for a specific flake, you can usually type
+<code>nix shell github:ggerganov/llama.cpp#&lt;tab&gt;</code> and your
+shell may or may not list the outputs. If anyone has a better way to do this,
+please let me know.</p>
+
+<p>To install a flake in your system profile, use</p>
+
+<pre>
+nix profile install github:ggerganov/llama.cpp
+</pre>
+
+<p>Here is the greatest power of nix flakes: the ability to install and
+use them as first-class packages just like anything from nixpkgs. It
+feels a lot better integrated than something like the AUR.</p>
+
+<h4>To create a nix flake for your own project</h4>
+
+<pre>
+nix flake init -t templates#go-hello
+</pre>
+
+<p>Replace go-hello with whatever template you want that most closely
+matches your project configuration. Unfortunately many of these templates
+have the questionable behavior of also overwriting source files in the
+current directory, so I recommend only running nix flake init in an
+empty directory, and copying the flake.nix file over to your
+existing project.</p>
+
+<h2>A philosophical intro to nix flakes</h2>
+
+<p>Flakes are a way to replace the centralized nixpkgs repository with
+decentralized packages controlled directly by upstream. In many ways
+Linux packaging has been moving more and more towards upstream with
+things like appimages or flatpak, and being able to remove many of the
+distro-specific hacks needed to make things run on various systems. Nix
+flakes address this same issue, by allowing upstream to control their own
+flake.nix, and pull in the specific versions of any dependencies they
+might need. They also give an easy way to install any programs that
+might not be packaged yet for nixpkgs, as long as anyone has written a
+flake and published it online.</p>
+
+<h2>The bad parts</h2>
+
+<p>Nix flakes are still rough around the edges, and the worst part for
+a new Nix user is the lack of documentation. This is a large part of why
+I'm writing yet another nix flakes tutorial!
+<a href="https://xeiaso.net/blog/nix-flakes-1-2022-02-21/">https://xeiaso.net/blog/nix-flakes-1-2022-02-21</a>
+is really good, but reading this as a new user, I only wanted to know
+how to install an app packaged with flakes, and I didn't care so much
+about how to package my own stuff yet.</p>
diff --git a/templates/index.html.template b/templates/index.html.template
index 49316cc..0d83073 100644
--- a/templates/index.html.template
+++ b/templates/index.html.template
@@ -1,21 +1,17 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <title>rose.moe</title>
- <link rel="icon" href="/static/icon.png">
- <link rel="stylesheet" href="/static/styles.css">
- </head>
- <body>
- <div style="background-image:url(/static/index/stars.gif);background-repeat:repeat;height:500px;display:flex;justify-content:center;align-items:center">
- <h1>roseh.moe</h1>
- </div>
+<div style="background-image:url(/static/index/stars.gif);background-repeat:repeat;height:500px;display:flex;justify-content:center;align-items:center">
+ <h1>roseh.moe</h1>
+</div>
- <article>
- <center>
- <img src="/static/index/kanna.png" alt="A dragon loli" style="border-radius:50%;margin:-100px auto 20px">
- </center>
+<article>
+ <center>
+ <img src="/static/index/kanna.png" alt="A dragon loli" style="border-radius:50%;margin:-100px auto 20px">
+ </center>
- <p><a href="/pong">Games?</a></p>
- </article>
- </body>
-</html>
+ <p><a href="/pong">Games?</a> (Warning: loud)</p>
+</article>
+
+{{range .}}
+<article>
+ <a href="/blog/{{.}}"><h2>{{name .}}</h2></a>
+</article>
+{{end}}
diff --git a/templates/outline.html.template b/templates/outline.html.template
new file mode 100644
index 0000000..960a880
--- /dev/null
+++ b/templates/outline.html.template
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <title>rose.moe</title>
+ <link rel="icon" href="/static/icon.png">
+ <link rel="stylesheet" href="/static/styles.css">
+ </head>
+ <body>
+{{template "body" .}}
+ </body>
+</html>