snix/users/sterni/blërg/blërg.bqn
sterni defd2a811b fix(sterni/blërg/git): correctly resolve relative repo paths
Change-Id: I2b3d5cf58494c29375eb406070d50fbe919a2097
Reviewed-on: https://cl.tvl.fyi/c/depot/+/13127
Reviewed-by: sterni <sternenseemann@systemli.org>
Autosubmit: sterni <sternenseemann@systemli.org>
Tested-by: BuildkiteCI
2025-02-09 21:26:52 +00:00

170 lines
5.3 KiB
BQN
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env BQN
# SPDX-FileCopyrightText: Copyright © 2024-2025 sterni
# SPDX-License-Identifier: GPL-3.0-only
#
# blërg is a reimplementation of mblog in BQN. BQN is used as a sort of bespoke
# scripting languages so we can rely on external tools for certain tasks (e.g.
# transforming HTML and parsing MIME messages). A list of dependencies is
# maintained in README.md.
# Utilities
MkDirP •file.CreateDir(¬•file.Exists)
AsciiDown - ('A'-'a')×('A''Z')
Slugify '-'(('A' 'z') ¬ "-_0123456789"(˜)<)¨ AsciiDown
DropPrefix {𝕩(/)𝕨˜𝕩}
StripLeft (¬ `=)/
StripRight StripLeft
_join {((𝕗))´𝕩;𝕨𝕗𝕩}
nl @+10
SplitChar (= (¯1˙)¨ +`=)
Lines nlSplitChar
ReadPosInt {(𝕨×+)´ '0'-˜𝕩} # ty leah2
ReadPosDec 10ReadPosInt
Chomp {nl¯1𝕩? ¯1𝕩; 𝕩}
Run {
𝕊 𝕩: 1 𝕊 𝕩;
doChomp 𝕊 cmd:
exitstdoutstderr •SH cmd
exitChompdoChomp¨ stdoutstderr
}
R {𝕊 exitstdoutstderr: stderr!0=exit stdout}Run
LR LinesR
GetEnv {R "importas""env"𝕩"printf""%s""$env"}
RelPath •wdpath•file.At
SplitExt ( (` + ¯2×) ='.')
# 3p dependencies
j {
# Update README.md if dependency discovery changes
Parse •Import (GetEnv "BQN_LIBS") •file.At "json.bqn"
ObjGet (() ˜1)<
ObjGetPath ObjGet˜´
_objGetDef {𝕨 (() ((𝕗))(˜1)) <𝕩}
}
# (Apple) Mail Notes Backend
# TODO(sterni): avoid argv limit by chunking
Hdrs {LR "mhdr""-dh"(':' _join 𝕨)𝕩}
Dates {ReadPosDec¨ LR "mhdr""-Dh""Date"𝕩}
headerNames "X-Uniform-Type-Identifier""X-Universally-Unique-Identifier""Subject"
MailNotesBackend {𝕊 config:
mailDir RelPath config j.ObjGet "maildir"
Entries {𝕊:
ms LR "mlist"mailDir
th ms,headerNamesheaderNames Hdrs ms
dh Dates ms
ah (("com.apple.mail-note")˘/) th˘dh˘ms
{𝕊 ·uuidtitletimepath:
title time
id Slugify uuid
Render {R "execline-cd"𝕩"mshow""-x"path R "mn2html"path}
}˘ ah
}
}
# Git Backend
converters >
# TODO(sterni): avoid cat
"html", "cat",
"md", "lowdown""-T""html""--html-no-skiphtml""--html-no-escapehtml""--html-callout-mdn",
# TODO(sterni): use emacs
"org", "pandoc""-f""org""-t""html5",
# TODO(sterni): don't assemble blocks in this ad hoc fashion
# TODO(sterni): pipefail
PipelineCmd {"pipeline"(' '¨𝕨)""𝕩}
GitBackend {𝕊 config:
repo RelPath config j.ObjGet "repository"
path '/' '/' StripRight config "." j._ObjGetDef "path"
# We use zero separated fields when dealing with paths, so quoting is unnecessary
GitCmd {"git""-c""core.quotePath=false""-C"repo𝕩}
rev R GitCmd "rev-parse""HEAD"
# Use the author date of the latest commit on the file to establish the date
# of the file. The author date is easier to arbitrarily change and survives
# history rewrites. It could be interesting to ignore commits that touch
# multiple files (especially treewide ones).
PathDate {ReadPosDec R GitCmd "log""--date=unix""--pretty=tformat:%ad""-1"rev"--"𝕩}
Entries {𝕤
blobs 2@ SplitChar R GitCmd "ls-tree""-zr""--format=%(path)%x00%(objectname)"revpath
{𝕊 pb:
extlesspext SplitExt p
id Slugify path DropPrefix extlessp
# TODO(sterni): extract from file if possible
title •file.Name extlessp
time PathDate p
Render {𝕤
conv converters j.ObjGet ext
R (GitCmd "cat-file""blob"b) PipelineCmd conv
}
}˘blobs
}
}
backends >"mail-notes"mailNotesBackend, "git"gitBackend
# Rendering
RenderPage {
"<!doctype html>
<html lang=""en"">
<head>
<meta charset=""utf-8"">
<title>"𝕨"</title>
<body>
<h1>"𝕨"</h1>"𝕩
}
WriteEntry {outDir 𝕊 entry:
entryDir MkDirP outDir •file.At entry.id
(entryDir •file.At "index.html") •file.Chars entry.title RenderPage entry.Render entryDir
# TODO(sterni): urlencode
"<li><a href="""entry.id""">"entry.title"</a></li>"
}
# Main
configFileoutDir {
# Usage: blërg <config file> <out dir>
! 2=•args
# TODO(sterni): expand ~/
RelPath¨ •args
}
config {
raw j.Parse •FChars configFile
[bns,bcs] raw j.ObjGet "backends"
bcs bcs ˘{21"name"𝕩}¨ bns
bts j.ObjGet"type"¨ bcs
backends bcs {𝕏 𝕨}¨ backendsj.ObjGet¨ bts
title raw j.ObjGet "title"
}
entries (( •ns.Get"time"¨)) {𝕩.Entries @}¨ config.backends
"All entry IDs must be unique"!(=) •ns.Get"id"¨ entries
MkDirP outDir
entryIndex outDirWriteEntry¨ entries
(outDir •file.At "index.html") •file.Chars config.title RenderPage "<ul>"entryIndex"</ul>"