summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Kreutz <mail@skreutz.com>2025-08-24 22:21:37 +0200
committerStefan Kreutz <mail@skreutz.com>2025-08-24 22:26:04 +0200
commita19cc6497a788742ea25bba82d2fcc2e217b2c29 (patch)
tree5252dcea82c70adb3b7c2d71ec3c8d8c842f8a0c
parentc3a733cb0e2e937e39f809ba31f18c023738a313 (diff)
downloadblog-a19cc6497a788742ea25bba82d2fcc2e217b2c29.tar
Add experimental Nix flake
-rw-r--r--.gitignore1
-rw-r--r--flake.lock61
-rw-r--r--flake.nix55
-rw-r--r--site.hs167
-rw-r--r--site.nix13
5 files changed, 215 insertions, 82 deletions
diff --git a/.gitignore b/.gitignore
index af1c5f6..90c6795 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+/result
.stack-work
_cache
_site
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..94bba45
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,61 @@
+{
+ "nodes": {
+ "flake-utils": {
+ "inputs": {
+ "systems": "systems"
+ },
+ "locked": {
+ "lastModified": 1731533236,
+ "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1755829505,
+ "narHash": "sha256-4/Jd+LkQ2ssw8luQVkqVs9spDBVE6h/u/hC/tzngsPo=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "f937f8ecd1c70efd7e9f90ba13dfb400cf559de4",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixpkgs-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "flake-utils": "flake-utils",
+ "nixpkgs": "nixpkgs"
+ }
+ },
+ "systems": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..7d153a9
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,55 @@
+{
+ description = "Stefan Kreutz's personal website";
+
+ inputs = {
+ nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
+ flake-utils.url = "github:numtide/flake-utils";
+ };
+
+ outputs = inputs@{ self, nixpkgs, flake-utils, ... }:
+ flake-utils.lib.eachDefaultSystem (system:
+ let
+ pkgs = import nixpkgs {
+ inherit system;
+ config = { };
+ overlays = [ ];
+ };
+ src = builtins.path { path = ./.; name = "blog"; };
+ in rec {
+ # nix develop
+ devShells.default = pkgs.mkShell {
+ nativeBuildInputs = with pkgs; [ ghc cabal-install lychee ];
+ };
+
+ # nix build .
+ # open ./result/srv/www.skreutz.com/index.html
+ packages.default = packages.site;
+
+ # nix run .#generator -- --help
+ packages.generator = pkgs.haskell.lib.compose.justStaticExecutables (
+ pkgs.haskellPackages.callCabal2nix "blog" src { }
+ );
+
+ # nix build .#site
+ packages.site = pkgs.callPackage ./site.nix {
+ inherit self;
+ inherit (packages) generator;
+ };
+
+ checks.links = pkgs.stdenvNoCC.mkDerivation {
+ inherit src;
+ name = "offline-link-check";
+ dontBuild = true;
+ doCheck = true;
+ nativeBuildInputs = with pkgs; [ lychee ];
+ checkPhase = ''
+ "${packages.generator}/bin/site" rebuild
+ lychee --offline --no-progress --require-https --root-dir "$( realpath _site )" _site
+ '';
+ installPhase = ''
+ mkdir $out
+ '';
+ };
+ }
+ );
+}
diff --git a/site.hs b/site.hs
index c016f04..1833558 100644
--- a/site.hs
+++ b/site.hs
@@ -8,90 +8,93 @@ import System.FilePath.Posix ((</>), (<.>), splitExtension, splitFileName, takeD
import Text.Pandoc (Pandoc, Inline(Link, Space, Str), Block(Header))
import Text.Pandoc.Shared (stringify)
import Text.Pandoc.Walk (walk)
+import qualified GHC.IO.Encoding as Encoding
main :: IO ()
-main = hakyllWith hakyllConfig $ do
- match ("images/*" .||. "files/*" .||. "robots.txt" .||. "health") $ do
- route idRoute
- compile copyFileCompiler
-
- match "css/*" $ do
- route idRoute
- -- WORKAROUND: compressCssCompiler removes copyright notices
- compile copyFileCompiler
-
- match (fromList ["about.md", "contact.md", "privacy.md", "code.md"]) $ do
- route $ setExtension "html" `composeRoutes` appendIndex
- let context = dropIndexHtml "url" <> defaultContext
- compile $ customPandocCompiler
- >>= loadAndApplyTemplate "templates/direct.html" context
- >>= loadAndApplyTemplate "templates/default.html" context
-
- match "posts/*" $ do
- route $ setExtension "html" `composeRoutes` appendIndex
- compile $ customPandocCompiler
- >>= loadAndApplyTemplate "templates/post.html" postContext
- >>= saveSnapshot "content"
- >>= loadAndApplyTemplate "templates/default.html" postContext
-
- create ["posts.html"] $ do
- route appendIndex
- compile $ do
- posts <- recentFirst =<< loadAll "posts/*"
- let archiveContext =
- listField "posts" postContext (return posts) <>
- constField "title" "Blog" <>
- dropIndexHtml "url" <>
- defaultContext
-
- makeItem ""
- >>= loadAndApplyTemplate "templates/posts.html" archiveContext
- >>= loadAndApplyTemplate "templates/default.html" archiveContext
-
- create ["feeds/posts.rss"] $ do
- route idRoute
- compileFeed renderRss rfc822DateTimeFormat
-
- create ["feeds/posts.atom"] $ do
- route idRoute
- compileFeed renderAtom rfc3339DateTimeFormat
-
- create ["sitemap.xml"] $ do
- route idRoute
- compile $ do
- posts <- recentFirst =<< loadAll "posts/*"
- singles <- loadAll (fromList ["about.md", "contact.md", "privacy.md", "code.md", "posts.html"])
- let
- pages = posts <> singles
- sitemapContext =
- constField "root" root <>
- listField "pages" postContext (return pages)
- makeItem ""
- >>= loadAndApplyTemplate "templates/sitemap.xml" sitemapContext
-
- match "index.html" $ do
- route idRoute
- compile $ do
- posts <- recentFirst =<< loadAll "posts/*"
- let indexContext =
- listField "posts" postContext (return posts) <>
- defaultContext
-
- getResourceBody
- >>= applyAsTemplate indexContext
- >>= loadAndApplyTemplate "templates/default.html" indexContext
-
- match "err.html" $ do
- route idRoute
- compile $ customPandocCompiler
- >>= loadAndApplyTemplate "templates/default.html" defaultContext
-
- match "404.html" $ do
- route idRoute
- compile $ customPandocCompiler
- >>= loadAndApplyTemplate "templates/default.html" defaultContext
-
- match "templates/*" $ compile templateBodyCompiler
+main = do
+ Encoding.setLocaleEncoding Encoding.utf8
+ hakyllWith hakyllConfig $ do
+ match ("images/*" .||. "files/*" .||. "robots.txt" .||. "health") $ do
+ route idRoute
+ compile copyFileCompiler
+
+ match "css/*" $ do
+ route idRoute
+ -- WORKAROUND: compressCssCompiler removes copyright notices
+ compile copyFileCompiler
+
+ match (fromList ["about.md", "contact.md", "privacy.md", "code.md"]) $ do
+ route $ setExtension "html" `composeRoutes` appendIndex
+ let context = dropIndexHtml "url" <> defaultContext
+ compile $ customPandocCompiler
+ >>= loadAndApplyTemplate "templates/direct.html" context
+ >>= loadAndApplyTemplate "templates/default.html" context
+
+ match "posts/*" $ do
+ route $ setExtension "html" `composeRoutes` appendIndex
+ compile $ customPandocCompiler
+ >>= loadAndApplyTemplate "templates/post.html" postContext
+ >>= saveSnapshot "content"
+ >>= loadAndApplyTemplate "templates/default.html" postContext
+
+ create ["posts.html"] $ do
+ route appendIndex
+ compile $ do
+ posts <- recentFirst =<< loadAll "posts/*"
+ let archiveContext =
+ listField "posts" postContext (return posts) <>
+ constField "title" "Blog" <>
+ dropIndexHtml "url" <>
+ defaultContext
+
+ makeItem ""
+ >>= loadAndApplyTemplate "templates/posts.html" archiveContext
+ >>= loadAndApplyTemplate "templates/default.html" archiveContext
+
+ create ["feeds/posts.rss"] $ do
+ route idRoute
+ compileFeed renderRss rfc822DateTimeFormat
+
+ create ["feeds/posts.atom"] $ do
+ route idRoute
+ compileFeed renderAtom rfc3339DateTimeFormat
+
+ create ["sitemap.xml"] $ do
+ route idRoute
+ compile $ do
+ posts <- recentFirst =<< loadAll "posts/*"
+ singles <- loadAll (fromList ["about.md", "contact.md", "privacy.md", "code.md", "posts.html"])
+ let
+ pages = posts <> singles
+ sitemapContext =
+ constField "root" root <>
+ listField "pages" postContext (return pages)
+ makeItem ""
+ >>= loadAndApplyTemplate "templates/sitemap.xml" sitemapContext
+
+ match "index.html" $ do
+ route idRoute
+ compile $ do
+ posts <- recentFirst =<< loadAll "posts/*"
+ let indexContext =
+ listField "posts" postContext (return posts) <>
+ defaultContext
+
+ getResourceBody
+ >>= applyAsTemplate indexContext
+ >>= loadAndApplyTemplate "templates/default.html" indexContext
+
+ match "err.html" $ do
+ route idRoute
+ compile $ customPandocCompiler
+ >>= loadAndApplyTemplate "templates/default.html" defaultContext
+
+ match "404.html" $ do
+ route idRoute
+ compile $ customPandocCompiler
+ >>= loadAndApplyTemplate "templates/default.html" defaultContext
+
+ match "templates/*" $ compile templateBodyCompiler
hakyllConfig :: Configuration
hakyllConfig = defaultConfiguration
diff --git a/site.nix b/site.nix
new file mode 100644
index 0000000..6626ad6
--- /dev/null
+++ b/site.nix
@@ -0,0 +1,13 @@
+{ self, stdenv, generator }:
+
+stdenv.mkDerivation rec {
+ name = "www.skreutz.com";
+ src = self;
+ buildPhase = ''
+ ${generator}/bin/site rebuild
+ '';
+ installPhase = ''
+ mkdir -p $out
+ cp -a _site $out/srv/${name}
+ '';
+}
Generated by cgit. See skreutz.com for my tech blog and contact information.