Since cl/2910 depot has no lib attribute anymore. Import it from the depot fix point via depot.third_party.nixpkgs.lib to avoid passing another argument and enlargening the shebang further. Change-Id: I3c719eba38a5ceb36689ebf0409bd19d4f46a609 Reviewed-on: https://cl.tvl.fyi/c/depot/+/3050 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org>
		
			
				
	
	
		
			134 lines
		
	
	
	
		
			2.9 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			134 lines
		
	
	
	
		
			2.9 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
| { depot, ... }:
 | |
| 
 | |
| let
 | |
|   inherit (depot.third_party.nixpkgs)
 | |
|     lib
 | |
|     ;
 | |
| 
 | |
|   inherit (depot.users.sterni.nix)
 | |
|     url
 | |
|     fun
 | |
|     string
 | |
|     ;
 | |
| 
 | |
|   inherit (depot.web.bubblegum)
 | |
|     pathInfo
 | |
|     scriptName
 | |
|     respond
 | |
|     absolutePath
 | |
|     ;
 | |
| 
 | |
|   # substituted using substituteAll in default.nix
 | |
|   blogdir = "@blogdir@";
 | |
|   # blogdir = toString ./posts; # for local testing
 | |
| 
 | |
|   parseDate = post:
 | |
|     let
 | |
|       matched = builtins.match "/?([0-9]+)-([0-9]+)-([0-9]+)-.+" post;
 | |
|     in
 | |
|       if matched == null
 | |
|       then [ 0 0 0 ]
 | |
|       else builtins.map builtins.fromJSON matched;
 | |
| 
 | |
|   parseTitle = post:
 | |
|     let
 | |
|       matched = builtins.match "/?[0-9]+-[0-9]+-[0-9]+-(.+).html" post;
 | |
|     in
 | |
|       if matched == null
 | |
|       then "no title"
 | |
|       else builtins.head matched;
 | |
| 
 | |
|   dateAtLeast = a: b:
 | |
|     builtins.all fun.id
 | |
|       (lib.zipListsWith (partA: partB: partA >= partB) a b);
 | |
| 
 | |
|   byPostDate = a: b:
 | |
|     dateAtLeast (parseDate a) (parseDate b);
 | |
| 
 | |
|   posts = builtins.sort byPostDate
 | |
|     (builtins.attrNames
 | |
|       (lib.filterAttrs (_: v: v == "regular")
 | |
|         (builtins.readDir blogdir)));
 | |
| 
 | |
|   generic = { title, inner, ... }: ''
 | |
|     <!doctype html>
 | |
|     <html>
 | |
|       <head>
 | |
|         <meta charset="utf-8">
 | |
|         <title>${title}</title>
 | |
|         <style>a:link, a:visited { color: blue; }</style>
 | |
|       </head>
 | |
|       <body>
 | |
|       ${inner}
 | |
|       </body>
 | |
|     </html>
 | |
|   '';
 | |
| 
 | |
|   index = posts: ''
 | |
|     <main>
 | |
|       <h1>blog posts</h1>
 | |
|       <ul>
 | |
|   '' + lib.concatMapStrings (post: ''
 | |
|       <li>
 | |
|         <a href="${absolutePath (url.encode {} post)}">${parseTitle post}</a>
 | |
|       </li>
 | |
|   '') posts + ''
 | |
|       </ul>
 | |
|     </main>
 | |
|   '';
 | |
| 
 | |
|   formatDate =
 | |
|     let
 | |
|       # Assume we never deal with years < 1000
 | |
|       formatDigit = d: string.fit {
 | |
|         char = "0"; width = 2;
 | |
|       } (toString d);
 | |
|     in lib.concatMapStringsSep "-" formatDigit;
 | |
| 
 | |
|   post = title: post: ''
 | |
|     <main>
 | |
|       <h1>${title}</h1>
 | |
|       <div id="content">
 | |
|         ${builtins.readFile (blogdir + "/" + post)}
 | |
|       </div>
 | |
|     </main>
 | |
|     <footer>
 | |
|       <p>Posted on ${formatDate (parseDate post)}</p>
 | |
|       <nav><a href="${scriptName}">index</a></nav>
 | |
|     </footer>
 | |
|   '';
 | |
| 
 | |
|   validatePathInfo = pathInfo:
 | |
|     let
 | |
|       chars = string.toChars pathInfo;
 | |
|     in builtins.length chars > 1
 | |
|       && !(builtins.elem "/" (builtins.tail chars));
 | |
| 
 | |
|   response =
 | |
|     if pathInfo == "/"
 | |
|     then {
 | |
|       title = "blog";
 | |
|       status = 200;
 | |
|       inner = index posts;
 | |
|     }
 | |
|     else if !(validatePathInfo pathInfo)
 | |
|     then {
 | |
|       title = "Bad Request";
 | |
|       status = 400;
 | |
|       inner = "No slashes in post names 😡";
 | |
|     }
 | |
|     # CGI should already url.decode for us
 | |
|     else if builtins.pathExists (blogdir + "/" + pathInfo)
 | |
|     then rec {
 | |
|       title = parseTitle pathInfo;
 | |
|       status = 200;
 | |
|       inner = post title pathInfo;
 | |
|     } else {
 | |
|       title = "Not Found";
 | |
|       status = 404;
 | |
|       inner = "<h1>404 — not found</h1>";
 | |
|     };
 | |
| in
 | |
|   respond response.status {
 | |
|     "Content-type" = "text/html";
 | |
|   } (generic response)
 |