Compare commits
2
Commits
main
..
8b77537f44
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b77537f44 | ||
|
|
fcd37feb2a |
No files matched your search
@@ -1 +0,0 @@
|
|||||||
((nil . ((cider-clojure-cli-aliases . ":dev:test"))))
|
|
||||||
@@ -9,3 +9,5 @@ jobs:
|
|||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: build doerg
|
- name: build doerg
|
||||||
run: nix build -L .#doerg
|
run: nix build -L .#doerg
|
||||||
|
- name: build publisher
|
||||||
|
run: nix build -L .#publisher
|
||||||
@@ -9,6 +9,7 @@ result-*
|
|||||||
.lsp
|
.lsp
|
||||||
.nrepl
|
.nrepl
|
||||||
.direnv/
|
.direnv/
|
||||||
|
resources/vendor/*
|
||||||
node_modules
|
node_modules
|
||||||
.cljs_node_repl
|
.cljs_node_repl
|
||||||
build/
|
build/
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
lock
|
lock
|
||||||
{:doc "Update the clj-nix lockfile"
|
{:doc "Update the clj-nix lockfile"
|
||||||
:task (-> (p/sh {:out :inherit :err :inherit}
|
:task (-> (p/sh {:out :inherit :err :inherit}
|
||||||
"nix run github:jlesquembre/clj-nix#deps-lock")
|
"nix run github:jlesquembre/clj-nix#deps-lock")
|
||||||
:exit
|
:exit
|
||||||
System/exit)}}}
|
System/exit)}}}
|
||||||
+52
-9
@@ -1,6 +1,14 @@
|
|||||||
{
|
{
|
||||||
"lock-version": 4,
|
"lock-version": 4,
|
||||||
"git-deps": [],
|
"git-deps": [
|
||||||
|
{
|
||||||
|
"lib": "io.github.msyds/spec-dict",
|
||||||
|
"url": "https://github.com/msyds/spec-dict.git",
|
||||||
|
"rev": "531d629b7f05f37232261cf9e8927a4b5915714f",
|
||||||
|
"git-dir": "https/github.com/msyds/spec-dict",
|
||||||
|
"hash": "sha256-5hMdPsB8OhOCtByPZS+CHXzVLq0H+OBKKnXec21xwmg="
|
||||||
|
}
|
||||||
|
],
|
||||||
"mvn-deps": [
|
"mvn-deps": [
|
||||||
{
|
{
|
||||||
"mvn-path": "aero/aero/1.1.6/aero-1.1.6.jar",
|
"mvn-path": "aero/aero/1.1.6/aero-1.1.6.jar",
|
||||||
@@ -137,6 +145,11 @@
|
|||||||
"mvn-repo": "https://repo1.maven.org/maven2/",
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
"hash": "sha256-ccrFOSFR4qUozJoJF58KM0F58FxS+OWWz1jd8Suyfys="
|
"hash": "sha256-ccrFOSFR4qUozJoJF58KM0F58FxS+OWWz1jd8Suyfys="
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "com/fasterxml/jackson/core/jackson-core/2.20.0/jackson-core-2.20.0.jar",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-vAz0YHWHcgH4QG7n3idBrn32wGb18EV72AYypxjAbnI="
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"mvn-path": "com/fasterxml/jackson/core/jackson-core/2.20.0/jackson-core-2.20.0.pom",
|
"mvn-path": "com/fasterxml/jackson/core/jackson-core/2.20.0/jackson-core-2.20.0.pom",
|
||||||
"mvn-repo": "https://repo1.maven.org/maven2/",
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
@@ -358,9 +371,14 @@
|
|||||||
"hash": "sha256-OaawIvv0GgkuZwK6MAFtmuyw3zNcYiZVd66K/IipB2A="
|
"hash": "sha256-OaawIvv0GgkuZwK6MAFtmuyw3zNcYiZVd66K/IipB2A="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"mvn-path": "fipp/fipp/0.6.26/fipp-0.6.26.pom",
|
"mvn-path": "fipp/fipp/0.6.27/fipp-0.6.27.jar",
|
||||||
"mvn-repo": "https://repo.clojars.org/",
|
"mvn-repo": "https://repo.clojars.org/",
|
||||||
"hash": "sha256-p+xjV7gTIRMv0HwvV+/rAhFEFVlDY9g6FDE6GU9fVTU="
|
"hash": "sha256-qK1dAlan2r+90UOm6QvnZXURhA/is4MMp9tnK20RDPc="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "fipp/fipp/0.6.27/fipp-0.6.27.pom",
|
||||||
|
"mvn-repo": "https://repo.clojars.org/",
|
||||||
|
"hash": "sha256-ugagpDW5XBNQMTr+1z3s6r5TXwbF/pw6Ffrcc4Tzlvk="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"mvn-path": "fipp/fipp/0.6.29/fipp-0.6.29.jar",
|
"mvn-path": "fipp/fipp/0.6.29/fipp-0.6.29.jar",
|
||||||
@@ -468,14 +486,14 @@
|
|||||||
"hash": "sha256-1PXzUUHstr5hI/+oPIQUGogO744bynAw2Zoo5HSjTbE="
|
"hash": "sha256-1PXzUUHstr5hI/+oPIQUGogO744bynAw2Zoo5HSjTbE="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"mvn-path": "lambdaisland/deep-diff2/2.11.216/deep-diff2-2.11.216.jar",
|
"mvn-path": "lambdaisland/deep-diff2/2.12.219/deep-diff2-2.12.219.jar",
|
||||||
"mvn-repo": "https://repo.clojars.org/",
|
"mvn-repo": "https://repo.clojars.org/",
|
||||||
"hash": "sha256-U2zJZmPIO66EtkgwwfyY41uRyu2DRmXH0ogNfluw5Rg="
|
"hash": "sha256-BkOq5C/7omo09wyTTg7nkBi6GWBmlayVsPa9mrDvCyU="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"mvn-path": "lambdaisland/deep-diff2/2.11.216/deep-diff2-2.11.216.pom",
|
"mvn-path": "lambdaisland/deep-diff2/2.12.219/deep-diff2-2.12.219.pom",
|
||||||
"mvn-repo": "https://repo.clojars.org/",
|
"mvn-repo": "https://repo.clojars.org/",
|
||||||
"hash": "sha256-ok3nYS+8XCcCTPJIkqaO1SQH6v2ENwK2GZJdH0c4D20="
|
"hash": "sha256-rW/85js2hSWVc36e2BcTRmkahJHc2TjGIEfvForuToY="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"mvn-path": "lambdaisland/kaocha/1.91.1392/kaocha-1.91.1392.jar",
|
"mvn-path": "lambdaisland/kaocha/1.91.1392/kaocha-1.91.1392.jar",
|
||||||
@@ -953,9 +971,14 @@
|
|||||||
"hash": "sha256-NnHYN2UlIwq6Ah8fYmx54g86ELYrXfgXIiWJDsSv4EU="
|
"hash": "sha256-NnHYN2UlIwq6Ah8fYmx54g86ELYrXfgXIiWJDsSv4EU="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"mvn-path": "org/clojure/core.rrb-vector/0.1.2/core.rrb-vector-0.1.2.pom",
|
"mvn-path": "org/clojure/core.rrb-vector/0.2.0/core.rrb-vector-0.2.0.jar",
|
||||||
"mvn-repo": "https://repo1.maven.org/maven2/",
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
"hash": "sha256-juK6yvw4QzWMznZRDXMyQhK7NRn61XgE7Oq9w3rFCR8="
|
"hash": "sha256-ftqNXGlaxVNp3NTHN4YUMhdXuBAoG//KMMss02PRZZQ="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/core.rrb-vector/0.2.0/core.rrb-vector-0.2.0.pom",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-t+0/8ZfxrdZOHvJS2zRY8wlhPcZXdejY4OkTlx4CRY4="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"mvn-path": "org/clojure/core.rrb-vector/0.2.1/core.rrb-vector-0.2.1.jar",
|
"mvn-path": "org/clojure/core.rrb-vector/0.2.1/core.rrb-vector-0.2.1.jar",
|
||||||
@@ -1037,6 +1060,11 @@
|
|||||||
"mvn-repo": "https://repo1.maven.org/maven2/",
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
"hash": "sha256-CRbXpBVYuVAKQnyIb6KYJ6zlJZIGvjrTPmTilvwaYRE="
|
"hash": "sha256-CRbXpBVYuVAKQnyIb6KYJ6zlJZIGvjrTPmTilvwaYRE="
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/pom.contrib/1.3.0/pom.contrib-1.3.0.pom",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-g5qUXfrO6lvVB5+CSPM0bdIULesJFGyj9dG/riYxCWc="
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"mvn-path": "org/clojure/pom.contrib/1.4.0/pom.contrib-1.4.0.pom",
|
"mvn-path": "org/clojure/pom.contrib/1.4.0/pom.contrib-1.4.0.pom",
|
||||||
"mvn-repo": "https://repo1.maven.org/maven2/",
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
@@ -1072,6 +1100,16 @@
|
|||||||
"mvn-repo": "https://repo1.maven.org/maven2/",
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
"hash": "sha256-PLp+DcwIXEzpLd3/6iJhJP+sF4vnm9A3m1suMKlpy+o="
|
"hash": "sha256-PLp+DcwIXEzpLd3/6iJhJP+sF4vnm9A3m1suMKlpy+o="
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/test.check/1.1.2/test.check-1.1.2.jar",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-93r5qZJ67LZqNoa282s1Al8kvOZr8/AF3UTcQEvIdgE="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/test.check/1.1.2/test.check-1.1.2.pom",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-UZ45jnJMYvCsnWsZ15+P8QAdqYWD/eAb1wUrB+Ga1ow="
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"mvn-path": "org/clojure/test.check/1.1.3/test.check-1.1.3.jar",
|
"mvn-path": "org/clojure/test.check/1.1.3/test.check-1.1.3.jar",
|
||||||
"mvn-repo": "https://repo1.maven.org/maven2/",
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
@@ -1102,6 +1140,11 @@
|
|||||||
"mvn-repo": "https://repo1.maven.org/maven2/",
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
"hash": "sha256-E15H98p5wKoYG2kJPML50aYyKt1qgli2aXxQCNIwv00="
|
"hash": "sha256-E15H98p5wKoYG2kJPML50aYyKt1qgli2aXxQCNIwv00="
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/tools.reader/1.3.6/tools.reader-1.3.6.jar",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-EdGzHyxlwzVbKSu5tEuPyv2lS0TaY+NKuXt5qKs7uOA="
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"mvn-path": "org/clojure/tools.reader/1.3.6/tools.reader-1.3.6.pom",
|
"mvn-path": "org/clojure/tools.reader/1.3.6/tools.reader-1.3.6.pom",
|
||||||
"mvn-repo": "https://repo1.maven.org/maven2/",
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
{:deps {aero/aero #:mvn{:version "1.1.6"}
|
|
||||||
babashka/fs #:mvn{:version "0.5.24"}
|
|
||||||
babashka/process #:mvn{:version "0.6.25"}
|
|
||||||
ch.qos.logback/logback-classic #:mvn{:version "1.1.3"}
|
|
||||||
cheshire/cheshire #:mvn{:version "6.1.0"}
|
|
||||||
com.github.seancorfield/next.jdbc #:mvn{:version "1.3.1070"}
|
|
||||||
com.rpl/specter #:mvn{:version "1.1.6"}
|
|
||||||
hiccup/hiccup #:mvn{:version "2.0.0-RC4"}
|
|
||||||
http-kit/http-kit #:mvn{:version "2.8.0"}
|
|
||||||
instaparse/instaparse #:mvn{:version "1.5.0"}
|
|
||||||
metosin/reitit #:mvn{:version "0.10.1"}
|
|
||||||
mvxcvi/clj-cbor #:mvn{:version "1.1.1"}
|
|
||||||
org.clojars.pntblnk/clj-ldap #:mvn{:version "0.0.17"}
|
|
||||||
org.clojure/clojure #:mvn{:version "1.12.0"}
|
|
||||||
org.clojure/core.match #:mvn{:version "1.1.0"}
|
|
||||||
org.clojure/test.check #:mvn{:version "1.1.3"}
|
|
||||||
org.clojure/tools.logging #:mvn{:version "1.3.0"}
|
|
||||||
org.xerial/sqlite-jdbc #:mvn{:version "3.47.1.0"}}
|
|
||||||
:paths ["src" "resources"]
|
|
||||||
:aliases
|
|
||||||
{:test {:extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}}
|
|
||||||
:extra-paths ["test"]
|
|
||||||
:main-opts ["-m" "kaocha.runner"]}
|
|
||||||
:dev {:extra-paths ["dev"]}}}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
(ns user
|
|
||||||
(:require [net.deertopia.doerg.server :as server]
|
|
||||||
[net.deertopia.doerg.config :as cfg]
|
|
||||||
[net.deertopia.doerg.cached-file :as cached-file]
|
|
||||||
[babashka.fs :as fs]))
|
|
||||||
|
|
||||||
(cfg/load-config! :profile :dev)
|
|
||||||
|
|
||||||
(when (not= :running (server/status))
|
|
||||||
(server/start!))
|
|
||||||
|
|
||||||
(defn invalidate-html-cache! []
|
|
||||||
(fs/delete-tree (server/html-dir))
|
|
||||||
nil)
|
|
||||||
|
|
||||||
(defn toggle-html-cache! []
|
|
||||||
(alter-var-root #'cached-file/*use-cache?* not))
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#+title: Doerg specification
|
||||||
|
#+author: Guppy
|
||||||
|
|
||||||
|
* Footnotes
|
||||||
|
|
||||||
|
- A bunch of metadata should be read into a node of type =doerg-data=
|
||||||
@@ -4,11 +4,9 @@
|
|||||||
, doerg-parser
|
, doerg-parser
|
||||||
, doerg-temml-worker
|
, doerg-temml-worker
|
||||||
, ibm-plex-web
|
, ibm-plex-web
|
||||||
, test-emacs ? callPackage ./test-emacs.nix {}
|
|
||||||
, fake-git
|
, fake-git
|
||||||
, our-tex
|
, our-tex ? callPackage ./our-tex.nix {}
|
||||||
, makeWrapper
|
, makeWrapper
|
||||||
, writeText
|
|
||||||
}:
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
@@ -25,39 +23,23 @@ let
|
|||||||
plex = ibm-plex-web.override {
|
plex = ibm-plex-web.override {
|
||||||
families = [ "math" "serif" "sans" "sans-kr" ];
|
families = [ "math" "serif" "sans" "sans-kr" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
bin-path = lib.makeBinPath [
|
bin-path = lib.makeBinPath [
|
||||||
doerg-parser
|
doerg-parser
|
||||||
our-tex
|
our-tex
|
||||||
doerg-temml-worker
|
doerg-temml-worker
|
||||||
];
|
];
|
||||||
|
|
||||||
doerg-config = writeText "doerg-extra-config.edn" ''
|
|
||||||
#:net.deertopia.doerg.config
|
|
||||||
{:ibm-plex-web "${ibm-plex-web}/share/ibm-plex-web"
|
|
||||||
:latex "${lib.getExe' our-tex "xelatex"}"
|
|
||||||
:dvisvgm "${lib.getExe' our-tex "dvisvgm"}"
|
|
||||||
:doerg-temml-worker "${lib.getExe doerg-temml-worker}"
|
|
||||||
:doerg-parser "${lib.getExe doerg-parser}"}
|
|
||||||
'';
|
|
||||||
in mkCljBin' {
|
in mkCljBin' {
|
||||||
name = "net.deertopia/doerg";
|
name = "net.deertopia/doerg";
|
||||||
version = "0.1.0";
|
version = "0.1.0";
|
||||||
projectSrc = lib.cleanSourceWith {
|
projectSrc = lib.cleanSource ./.;
|
||||||
filter = path: type:
|
lockfile = ../deps-lock.json;
|
||||||
lib.sources.cleanSourceFilter path type
|
|
||||||
|| lib.hasSuffix ".nix" path;
|
|
||||||
src = ./.;
|
|
||||||
};
|
|
||||||
lockfile = ./deps-lock.json;
|
|
||||||
main-ns = "net.deertopia.doerg.main";
|
main-ns = "net.deertopia.doerg.main";
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
plex
|
plex
|
||||||
makeWrapper
|
makeWrapper
|
||||||
];
|
];
|
||||||
propagatedBuildInputs = [
|
buildInputs = [
|
||||||
doerg-parser
|
doerg-parser
|
||||||
ibm-plex-web
|
|
||||||
doerg-temml-worker
|
doerg-temml-worker
|
||||||
plex
|
plex
|
||||||
our-tex
|
our-tex
|
||||||
@@ -65,20 +47,15 @@ in mkCljBin' {
|
|||||||
nativeCheckInputs = [
|
nativeCheckInputs = [
|
||||||
doerg-parser
|
doerg-parser
|
||||||
doerg-temml-worker
|
doerg-temml-worker
|
||||||
test-emacs
|
|
||||||
plex
|
plex
|
||||||
our-tex
|
our-tex
|
||||||
];
|
];
|
||||||
preBuild = ''
|
|
||||||
cp ${doerg-config} resources/net/deertopia/doerg/extra-config.edn
|
|
||||||
'';
|
|
||||||
doCheck = true;
|
doCheck = true;
|
||||||
checkPhase = ''
|
checkPhase = ''
|
||||||
export \
|
|
||||||
EMACS=test-emacs \
|
|
||||||
XDG_STATE_HOME=$(mktemp -d "state-home-XXXXXX")
|
|
||||||
clojure -M:test
|
clojure -M:test
|
||||||
'';
|
'';
|
||||||
passthru = { inherit plex our-tex test-emacs doerg-config; };
|
postInstall = ''
|
||||||
meta.mainProgram = "doerg";
|
wrapProgram $out/bin/doerg \
|
||||||
|
--prefix PATH : ${bin-path}
|
||||||
|
'';
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,271 @@
|
|||||||
|
{
|
||||||
|
"lock-version": 4,
|
||||||
|
"git-deps": [],
|
||||||
|
"mvn-deps": [
|
||||||
|
{
|
||||||
|
"mvn-path": "babashka/fs/0.5.24/fs-0.5.24.jar",
|
||||||
|
"mvn-repo": "https://repo.clojars.org/",
|
||||||
|
"hash": "sha256-owunNIWFqt6xNGhNV6vFs7GyYEz8z8wHRT7TSw1MDlU="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "babashka/fs/0.5.24/fs-0.5.24.pom",
|
||||||
|
"mvn-repo": "https://repo.clojars.org/",
|
||||||
|
"hash": "sha256-E1jX6M3DeoTXVU6Vzd6xIpE0s9QAZpZALJl4nSKU8E8="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "babashka/process/0.6.25/process-0.6.25.jar",
|
||||||
|
"mvn-repo": "https://repo.clojars.org/",
|
||||||
|
"hash": "sha256-XWTJ6kUgLD3/UJGe++Lf0+/Ja9SPViS50v33v3JOf4s="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "babashka/process/0.6.25/process-0.6.25.pom",
|
||||||
|
"mvn-repo": "https://repo.clojars.org/",
|
||||||
|
"hash": "sha256-4bSR/Z0g4rXVwv2u6e9rkoL8d1nV5b9iNIs/U2o8l8Y="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "cheshire/cheshire/6.1.0/cheshire-6.1.0.jar",
|
||||||
|
"mvn-repo": "https://repo.clojars.org/",
|
||||||
|
"hash": "sha256-ruCrbkSBlaoJXyLEKOINK8YQWRxUwQ7D4YPdOwgWOcI="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "cheshire/cheshire/6.1.0/cheshire-6.1.0.pom",
|
||||||
|
"mvn-repo": "https://repo.clojars.org/",
|
||||||
|
"hash": "sha256-KKpi9U7eZ2YjAyQI14sMgqv91IiMfFagshIrg+Pad+M="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "com/fasterxml/jackson/core/jackson-core/2.20.0/jackson-core-2.20.0.jar",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-vAz0YHWHcgH4QG7n3idBrn32wGb18EV72AYypxjAbnI="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "com/fasterxml/jackson/core/jackson-core/2.20.0/jackson-core-2.20.0.pom",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-XxZVisIjBzpvJHRA8wX1nwXv9QqvHurguq1BKAABb2g="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "com/fasterxml/jackson/dataformat/jackson-dataformat-cbor/2.20.0/jackson-dataformat-cbor-2.20.0.jar",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-qwdWFsvWf1Z2+Jgl7JyLx7VMhNvpNLFiFFs0FyNwtdY="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "com/fasterxml/jackson/dataformat/jackson-dataformat-cbor/2.20.0/jackson-dataformat-cbor-2.20.0.pom",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-SYvwMYvqLnY2Wf0r/k8W8pHt8JNaMMnysKKP7jrXz8c="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "com/fasterxml/jackson/dataformat/jackson-dataformat-smile/2.20.0/jackson-dataformat-smile-2.20.0.jar",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-NFwALLesnlQ0Go8ExWoR3CGUVCbqg5n/VuAvuOkSpm4="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "com/fasterxml/jackson/dataformat/jackson-dataformat-smile/2.20.0/jackson-dataformat-smile-2.20.0.pom",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-IM1JgnnQUcaQMkt6R1+Ee/wQoAcQS6uc371ga1sFhDk="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "com/fasterxml/jackson/dataformat/jackson-dataformats-binary/2.20.0/jackson-dataformats-binary-2.20.0.pom",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-ZJ/OQKV9Qhx82erCP919XPbzwdG5NAbuJ3xFw1Mm5Yg="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "com/fasterxml/jackson/jackson-base/2.20.0/jackson-base-2.20.0.pom",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-/IgCjRnuqjftpZbmuY03SfIs/IrdGeoZdFq+g2iDzmY="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "com/fasterxml/jackson/jackson-bom/2.20.0/jackson-bom-2.20.0.pom",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-9ig2R+cB/aHNMS3MIcsTKkD3mPGejkL6/D/jR8WlG7s="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "com/fasterxml/jackson/jackson-parent/2.20/jackson-parent-2.20.pom",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-tDt/XGLoaxZPrnCuF9aRHF22B5mvAQVzYK/aguSEW+U="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "com/fasterxml/oss-parent/70/oss-parent-70.pom",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-JsqO1vgsnS7XzTIpgQW7ZcD52JnbYXV6CXQVhvqTpjk="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/clojure/1.10.3/clojure-1.10.3.jar",
|
||||||
|
"mvn-repo": "https://repo.maven.apache.org/maven2/",
|
||||||
|
"hash": "sha256-fxJHLa7Y9rUXSYqqKrE6ViR1w+31FHjkWBzHYemJeaM="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/clojure/1.10.3/clojure-1.10.3.pom",
|
||||||
|
"mvn-repo": "https://repo.maven.apache.org/maven2/",
|
||||||
|
"hash": "sha256-GJwAxDNAdJai+7DsyzeQjJSVXZHq0b5IFWdE7MGBbZQ="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/clojure/1.11.0/clojure-1.11.0.jar",
|
||||||
|
"mvn-repo": "https://repo.maven.apache.org/maven2/",
|
||||||
|
"hash": "sha256-PiH6daB+yd278bK1A1bPGAcQ0DmN6qT0TpHNYwRVWUc="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/clojure/1.11.0/clojure-1.11.0.pom",
|
||||||
|
"mvn-repo": "https://repo.maven.apache.org/maven2/",
|
||||||
|
"hash": "sha256-SQjMS0yeYsmoFJb5PLWsb2lBd8xkXc87jOXkkavOHro="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/clojure/1.11.1/clojure-1.11.1.jar",
|
||||||
|
"mvn-repo": "https://repo.maven.apache.org/maven2/",
|
||||||
|
"hash": "sha256-I4G26UI6tGUVFFWUSQPROlYkPWAGuRlK/Bv0+HEMtN4="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/clojure/1.11.1/clojure-1.11.1.pom",
|
||||||
|
"mvn-repo": "https://repo.maven.apache.org/maven2/",
|
||||||
|
"hash": "sha256-IMRaGr7b2L4grvk2BQrjGgjBZ0CzL4dAuIOM3pb/y4o="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/clojure/1.11.2/clojure-1.11.2.jar",
|
||||||
|
"mvn-repo": "https://repo.maven.apache.org/maven2/",
|
||||||
|
"hash": "sha256-iPqZkT1pIs+39kn1xGdQOHfLb8yMwW02948mSAhLqZc="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/clojure/1.11.2/clojure-1.11.2.pom",
|
||||||
|
"mvn-repo": "https://repo.maven.apache.org/maven2/",
|
||||||
|
"hash": "sha256-FzbP/xCV4dT+/raogrut9ttB7+MV8pbw/aMtt//EExE="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/clojure/1.11.3/clojure-1.11.3.jar",
|
||||||
|
"mvn-repo": "https://repo.maven.apache.org/maven2/",
|
||||||
|
"hash": "sha256-nDBUCTKOK5boXdK160t1gQxnt2unCuTQ9t3pvPtVsbc="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/clojure/1.11.3/clojure-1.11.3.pom",
|
||||||
|
"mvn-repo": "https://repo.maven.apache.org/maven2/",
|
||||||
|
"hash": "sha256-DA2+Ge4NKpxXMQzr3dNWRD8NFlFMQmBHsGLjpXwNuK0="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/clojure/1.11.4/clojure-1.11.4.jar",
|
||||||
|
"mvn-repo": "https://repo.maven.apache.org/maven2/",
|
||||||
|
"hash": "sha256-/H/xtmENDjSUp1zBHvgYEL2kAqwVcBL+TjuJlYbPQTM="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/clojure/1.11.4/clojure-1.11.4.pom",
|
||||||
|
"mvn-repo": "https://repo.maven.apache.org/maven2/",
|
||||||
|
"hash": "sha256-a6YADmhI+Cw5y5tJqyqmo6Vi9MJNUrMeUZCuZJXwwwk="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/clojure/1.12.0/clojure-1.12.0.jar",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-xFMzAGRBoFnqn9sTQfxsH0C5IaENzNgmZTEeSKA4R2M="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/clojure/1.12.0/clojure-1.12.0.pom",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-KfRiqonLl2RXWEGKXwjUwagrc1yW569JgX0WqpuQgVA="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/core.match/1.1.0/core.match-1.1.0.jar",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-10V6tjEIWae9cTmEM4IEX6PN7A0T97qSEpfy8/uZj1M="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/core.match/1.1.0/core.match-1.1.0.pom",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-NnHYN2UlIwq6Ah8fYmx54g86ELYrXfgXIiWJDsSv4EU="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/core.specs.alpha/0.2.56/core.specs.alpha-0.2.56.jar",
|
||||||
|
"mvn-repo": "https://repo.maven.apache.org/maven2/",
|
||||||
|
"hash": "sha256-/PRCveArBKhj8vzFjuaiowxM8Mlw99q4VjTwq3ERZrY="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/core.specs.alpha/0.2.56/core.specs.alpha-0.2.56.pom",
|
||||||
|
"mvn-repo": "https://repo.maven.apache.org/maven2/",
|
||||||
|
"hash": "sha256-AarxdIP/HHSCySoHKV1+e8bjszIt9EsptXONAg/wB0A="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/core.specs.alpha/0.2.62/core.specs.alpha-0.2.62.jar",
|
||||||
|
"mvn-repo": "https://repo.maven.apache.org/maven2/",
|
||||||
|
"hash": "sha256-Bu6owHC75FwVhWfkQ0OWgbyMRukSNBT4G/oyukLWy8g="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/core.specs.alpha/0.2.62/core.specs.alpha-0.2.62.pom",
|
||||||
|
"mvn-repo": "https://repo.maven.apache.org/maven2/",
|
||||||
|
"hash": "sha256-F3i70Ti9GFkLgFS+nZGdG+toCfhbduXGKFtn1Ad9MA4="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/core.specs.alpha/0.4.74/core.specs.alpha-0.4.74.jar",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-63OsCM9JuoQMiLpnvu8RM2ylVDM9lAiAjXiUbg/rnds="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/core.specs.alpha/0.4.74/core.specs.alpha-0.4.74.pom",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-M0EOuKpz1S2Vez3G4KZfOZisBiPL2BPZDDPm5onEJCk="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/pom.contrib/0.3.0/pom.contrib-0.3.0.pom",
|
||||||
|
"mvn-repo": "https://repo.maven.apache.org/maven2/",
|
||||||
|
"hash": "sha256-fxgrOypUPgV0YL+T/8XpzvasUn3xoTdqfZki6+ee8Rk="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/pom.contrib/1.1.0/pom.contrib-1.1.0.pom",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-EOzku1+YKQENwWVh9C67g7ry9HYFtR+RBbkvPKoIlxU="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/pom.contrib/1.2.0/pom.contrib-1.2.0.pom",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-CRbXpBVYuVAKQnyIb6KYJ6zlJZIGvjrTPmTilvwaYRE="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/spec.alpha/0.2.194/spec.alpha-0.2.194.jar",
|
||||||
|
"mvn-repo": "https://repo.maven.apache.org/maven2/",
|
||||||
|
"hash": "sha256-z2iZ+YUpjGSxPqEplGrZAo3uja3w6rmuGORVAn04JJw="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/spec.alpha/0.2.194/spec.alpha-0.2.194.pom",
|
||||||
|
"mvn-repo": "https://repo.maven.apache.org/maven2/",
|
||||||
|
"hash": "sha256-WhHw4eizwFLmUcSYxpRbRNs1Nb8sGHGf3PZd8fiLE+Y="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/spec.alpha/0.3.218/spec.alpha-0.3.218.jar",
|
||||||
|
"mvn-repo": "https://repo.maven.apache.org/maven2/",
|
||||||
|
"hash": "sha256-Z+yJjrVcZqlXpVJ53YXRN2u5lL2HZosrDeHrO5foquA="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/spec.alpha/0.3.218/spec.alpha-0.3.218.pom",
|
||||||
|
"mvn-repo": "https://repo.maven.apache.org/maven2/",
|
||||||
|
"hash": "sha256-bY3hTDrIdXYMX/kJVi/5hzB3AxxquTnxyxOeFp/pB1g="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/spec.alpha/0.5.238/spec.alpha-0.5.238.jar",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-lM2ZtupjlkHzevSGCmQ7btOZ7lqL5dcXz/C2Y8jXUHc="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/spec.alpha/0.5.238/spec.alpha-0.5.238.pom",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-PLp+DcwIXEzpLd3/6iJhJP+sF4vnm9A3m1suMKlpy+o="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/tools.logging/1.3.0/tools.logging-1.3.0.jar",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-gmlpt42a2jJ95rfaDxdkV9lWFPo4woAyZhDzGmtRXJE="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/clojure/tools.logging/1.3.0/tools.logging-1.3.0.pom",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-E15H98p5wKoYG2kJPML50aYyKt1qgli2aXxQCNIwv00="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "org/junit/junit-bom/5.13.4/junit-bom-5.13.4.pom",
|
||||||
|
"mvn-repo": "https://repo1.maven.org/maven2/",
|
||||||
|
"hash": "sha256-16CKmbJQLwu2jNTh+YTwv2kySqogi9D3M2bAP8NUikI="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "tigris/tigris/0.1.2/tigris-0.1.2.jar",
|
||||||
|
"mvn-repo": "https://repo.clojars.org/",
|
||||||
|
"hash": "sha256-SapkjttsFOVwlaEbOR6u5gZXgyP7eXVfkjMaxjAPl6A="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mvn-path": "tigris/tigris/0.1.2/tigris-0.1.2.pom",
|
||||||
|
"mvn-repo": "https://repo.clojars.org/",
|
||||||
|
"hash": "sha256-H9VZA1l1INzUrnbmoz7/XjWmFUIrutKo7ZrDMqr75KA="
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{:deps {org.clojure/tools.logging {:mvn/version "1.3.0"}
|
||||||
|
babashka/fs {:mvn/version "0.5.24"}
|
||||||
|
org.clojure/core.match {:mvn/version "1.1.0"}
|
||||||
|
cheshire/cheshire {:mvn/version "6.1.0"}
|
||||||
|
babashka/process {:mvn/version "0.6.25"}
|
||||||
|
io.github.msyds/spec-dict
|
||||||
|
{:git/sha "531d629b7f05f37232261cf9e8927a4b5915714f"}
|
||||||
|
hiccup/hiccup {:mvn/version "2.0.0-RC4"}
|
||||||
|
com.rpl/specter {:mvn/version "1.1.6"}
|
||||||
|
lambdaisland/deep-diff2 {:mvn/version "2.12.219"}
|
||||||
|
mvxcvi/clj-cbor {:mvn/version "1.1.1"}
|
||||||
|
ch.qos.logback/logback-classic {:mvn/version "1.1.3"}
|
||||||
|
org.clojure/test.check {:mvn/version "1.1.3"}}
|
||||||
|
:paths ["src" "resources" "test"]
|
||||||
|
:aliases
|
||||||
|
{:test {:extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}}
|
||||||
|
:main-opts ["-m" "kaocha.runner"]}}}
|
||||||
File renamed without changes.
@@ -10,5 +10,4 @@ buildNpmPackage {
|
|||||||
npmDeps = importNpmLock { npmRoot = ./.; };
|
npmDeps = importNpmLock { npmRoot = ./.; };
|
||||||
npmConfigHook = importNpmLock.npmConfigHook;
|
npmConfigHook = importNpmLock.npmConfigHook;
|
||||||
dontNpmBuild = true;
|
dontNpmBuild = true;
|
||||||
meta.mainProgram = "doerg-parser";
|
|
||||||
}
|
}
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -18,5 +18,4 @@ buildNpmPackage {
|
|||||||
npmDeps = importNpmLock { npmRoot = ./.; };
|
npmDeps = importNpmLock { npmRoot = ./.; };
|
||||||
npmConfigHook = importNpmLock.npmConfigHook;
|
npmConfigHook = importNpmLock.npmConfigHook;
|
||||||
dontNpmBuild = true;
|
dontNpmBuild = true;
|
||||||
meta.mainProgram = "doerg-temml-worker";
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{:deps {babashka/fs {:mvn/version "0.5.24"}
|
||||||
|
cheshire/cheshire {:mvn/version "6.1.0"}
|
||||||
|
com.rpl/specter {:mvn/version "1.1.6"}
|
||||||
|
mvxcvi/clj-cbor {:mvn/version "1.1.1"}
|
||||||
|
babashka/process {:mvn/version "0.6.25"}}
|
||||||
|
:paths ["."]}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
(ns deserialise
|
||||||
|
"A toy script for conveniently interfacing with doerg-temml-worker
|
||||||
|
during development."
|
||||||
|
(:require [clj-cbor.core :as cbor]
|
||||||
|
[clojure.string :as str]))
|
||||||
|
|
||||||
|
(prn (cbor/decode cbor/default-codec System/in :eof))
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,13 @@
|
|||||||
|
(ns serialise
|
||||||
|
"A toy script for conveniently interfacing with doerg-temml-worker
|
||||||
|
during development."
|
||||||
|
(:require [clj-cbor.core :as cbor]
|
||||||
|
[clojure.string :as str]))
|
||||||
|
|
||||||
|
(defn w [x]
|
||||||
|
(cbor/encode cbor/default-codec System/out x))
|
||||||
|
|
||||||
|
(defn c [x]
|
||||||
|
(->> x cbor/encode (map #(format "%02x" %)) (str/join " ")))
|
||||||
|
|
||||||
|
(w "\\ifxetex blah \\fi")
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+3
-3
@@ -438,7 +438,7 @@ label.margin-toggle:not(.sidenote-number) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.org-link.external::after
|
.link.external::after
|
||||||
{ content: "↗"
|
{ content: "↗"
|
||||||
; vertical-align: super
|
; vertical-align: super
|
||||||
; font-size: 1rem
|
; font-size: 1rem
|
||||||
@@ -446,8 +446,8 @@ label.margin-toggle:not(.sidenote-number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.center
|
.center
|
||||||
{ align-items: center
|
{ align-items: "center"
|
||||||
; justify-content: center
|
; justify-content: "center"
|
||||||
; display: flex
|
; display: flex
|
||||||
; max-width: 55%
|
; max-width: 55%
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
(ns scratch
|
||||||
|
(:require [clojure.spec.alpha :as s]
|
||||||
|
[spec-dict.main :refer [dict]]
|
||||||
|
[clojure.test.check.generators :as gen]))
|
||||||
|
|
||||||
|
|
||||||
|
(defmulti node-spec :type)
|
||||||
|
|
||||||
|
(s/def ::node
|
||||||
|
(s/multi-spec node-spec :type))
|
||||||
|
|
||||||
|
(s/def ::children (s/coll-of ::node :kind vector?))
|
||||||
|
|
||||||
|
(s/def ::value nat-int?)
|
||||||
|
|
||||||
|
(defmethod node-spec :branch [_]
|
||||||
|
(dict {:children ::children})
|
||||||
|
#_(s/keys :req-un [::children]))
|
||||||
|
|
||||||
|
(defmethod node-spec :leaf [_]
|
||||||
|
(dict {:value ::value})
|
||||||
|
#_
|
||||||
|
(s/keys :req-un [::value]))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(binding [s/*recursion-limit* 1]
|
||||||
|
(gen/generate (s/gen ::node))))
|
||||||
File renamed without changes.
@@ -0,0 +1,43 @@
|
|||||||
|
(ns net.deertopia.doerg.config
|
||||||
|
(:require [clojure.spec.alpha :as s]
|
||||||
|
[babashka.fs :as fs]
|
||||||
|
[spec-dict.main :refer [dict]]))
|
||||||
|
|
||||||
|
(s/def ::config
|
||||||
|
(s/keys :req [::ibm-plex-web
|
||||||
|
::latex
|
||||||
|
::dvisvgm
|
||||||
|
::doerg-temml-worker
|
||||||
|
::doerg-parser]))
|
||||||
|
|
||||||
|
(s/def ::file
|
||||||
|
#(or (instance? java.io.File %)
|
||||||
|
(string? %)))
|
||||||
|
|
||||||
|
(s/def ::executable #(or (fs/executable? %)
|
||||||
|
(and (fs/relative? %)
|
||||||
|
(fs/which %))))
|
||||||
|
|
||||||
|
(def default
|
||||||
|
{::ibm-plex-web
|
||||||
|
(fs/file (some #(let [x (fs/path % "ibm-plex-web")]
|
||||||
|
(and (fs/exists? x) x))
|
||||||
|
(fs/split-paths (System/getenv "XDG_DATA_DIRS"))))
|
||||||
|
::latex "xelatex"
|
||||||
|
::dvisvgm "dvisvgm"
|
||||||
|
;; TODO: Can we automatically set this to "./doerg-temml-worker/index.js" in
|
||||||
|
;; a development environment?
|
||||||
|
::doerg-temml-worker "doerg-temml-worker"
|
||||||
|
::doerg-parser "doerg-parser"})
|
||||||
|
|
||||||
|
(def ^:dynamic *cfg* default)
|
||||||
|
|
||||||
|
(s/def ::ibm-plex-web ::file)
|
||||||
|
|
||||||
|
(s/def ::latex ::executable)
|
||||||
|
|
||||||
|
(s/def ::dvisvgm ::executable)
|
||||||
|
|
||||||
|
(s/def ::doerg-temml-worker ::executable)
|
||||||
|
|
||||||
|
(s/def ::doerg-parser ::executable)
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
[clojure.core.match :refer [match]]
|
[clojure.core.match :refer [match]]
|
||||||
[clojure.java.io :as io]
|
[clojure.java.io :as io]
|
||||||
[clojure.set :as set]
|
[clojure.set :as set]
|
||||||
|
[clojure.spec.alpha :as s]
|
||||||
[clojure.string :as str]
|
[clojure.string :as str]
|
||||||
[clojure.test.check.generators :as gen]
|
[clojure.test.check.generators :as gen]
|
||||||
[clojure.tools.logging.readable :as lr]
|
[clojure.tools.logging.readable :as lr]
|
||||||
@@ -14,6 +15,7 @@
|
|||||||
[com.rpl.specter.zipper :as sz]
|
[com.rpl.specter.zipper :as sz]
|
||||||
[net.deertopia.doerg.common :as common]
|
[net.deertopia.doerg.common :as common]
|
||||||
[net.deertopia.doerg.config :as cfg]
|
[net.deertopia.doerg.config :as cfg]
|
||||||
|
[spec-dict.main :refer [dict]]
|
||||||
[clojure.tools.logging :as l])
|
[clojure.tools.logging :as l])
|
||||||
(:import
|
(:import
|
||||||
(java.util UUID)))
|
(java.util UUID)))
|
||||||
@@ -34,7 +36,7 @@
|
|||||||
:or {in *in*}}]
|
:or {in *in*}}]
|
||||||
(let [r (-> (p/process
|
(let [r (-> (p/process
|
||||||
{:in in :out :string}
|
{:in in :out :string}
|
||||||
(-> cfg/*cfg* ::cfg/doerg-parser str))
|
(::cfg/doerg-parser cfg/*cfg*))
|
||||||
(common/deref-with-timeout *uniorg-timeout-duration*))]
|
(common/deref-with-timeout *uniorg-timeout-duration*))]
|
||||||
(when (zero? (:exit r))
|
(when (zero? (:exit r))
|
||||||
(-> r :out (json/parse-string (comp keyword camel->kebab))))))
|
(-> r :out (json/parse-string (comp keyword camel->kebab))))))
|
||||||
@@ -62,6 +64,8 @@
|
|||||||
(and (map? e) (contains? e :children)))
|
(and (map? e) (contains? e :children)))
|
||||||
|
|
||||||
(defn org-element? [element]
|
(defn org-element? [element]
|
||||||
|
#_
|
||||||
|
(s/valid? ::org-element element)
|
||||||
(and (map? element)
|
(and (map? element)
|
||||||
(contains? element :type)))
|
(contains? element :type)))
|
||||||
|
|
||||||
@@ -94,6 +98,16 @@
|
|||||||
(and (of-type? element "latex-fragment")
|
(and (of-type? element "latex-fragment")
|
||||||
(-> element :contents (str/starts-with? "\\[")))))
|
(-> element :contents (str/starts-with? "\\[")))))
|
||||||
|
|
||||||
|
|
||||||
|
;;; Spec
|
||||||
|
|
||||||
|
(s/def ::org-element
|
||||||
|
(dict {:type string?}
|
||||||
|
^:opt {:contents-begin nat-int?
|
||||||
|
:contents-end nat-int?
|
||||||
|
:children (s/coll-of ::org-element
|
||||||
|
:kind seq?)}))
|
||||||
|
|
||||||
|
|
||||||
;;; Zipper
|
;;; Zipper
|
||||||
|
|
||||||
@@ -300,3 +314,149 @@
|
|||||||
(recur (conj acc c) rest)
|
(recur (conj acc c) rest)
|
||||||
[] acc))))))
|
[] acc))))))
|
||||||
|
|
||||||
|
|
||||||
|
;;; Specs (top-level)
|
||||||
|
|
||||||
|
;; Data taken from uniorg/index.d.ts
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(defn- typescript-enum->set [s]
|
||||||
|
(as-> s
|
||||||
|
it
|
||||||
|
(str/split it #" \| ")
|
||||||
|
(map camel->kebab it)
|
||||||
|
(into #{} it))))
|
||||||
|
|
||||||
|
(def greater-element-types
|
||||||
|
#{"org-data" "section" "property-drawer" "drawer" "plain-list"
|
||||||
|
"list-item" "quote-block" "verse-block" "center-block"
|
||||||
|
"special-block" "footnote-definition" "table"})
|
||||||
|
|
||||||
|
(def element-types
|
||||||
|
#{"list-item-tag" "src-block" "comment-block" "latex-environment"
|
||||||
|
"keyword" "paragraph" "node-property" "example-block" "clock"
|
||||||
|
"planning" "diary-sexp" "fixed-width" "export-block"
|
||||||
|
"horizontal-rule" "comment" "table-row" "headline"})
|
||||||
|
|
||||||
|
(def recursive-object-types
|
||||||
|
#{"citation" "footnote-reference" "superscript" "table-cell" "link"
|
||||||
|
"italic" "citation-common-prefix" "subscript" "citation-prefix"
|
||||||
|
"citation-common-suffix" "strike-through" "citation-reference"
|
||||||
|
"bold" "underline"})
|
||||||
|
|
||||||
|
(def object-types
|
||||||
|
#{"line-break" "citation-suffix" "statistics-cookie" "timestamp"
|
||||||
|
"text" "verbatim" "citation-key" "export-snippet" "latex-fragment"
|
||||||
|
"entity" "code"})
|
||||||
|
|
||||||
|
(s/def ::greater-element-type greater-element-types)
|
||||||
|
(s/def ::element-type element-types)
|
||||||
|
(s/def ::object-type (set/union recursive-object-types object-types))
|
||||||
|
(s/def ::recursive-object-type recursive-object-types)
|
||||||
|
|
||||||
|
(s/def ::contents-begin nat-int?)
|
||||||
|
(s/def ::contents-end nat-int?)
|
||||||
|
|
||||||
|
(defmulti node-spec :type)
|
||||||
|
|
||||||
|
(defn- unimplemented-spec [x]
|
||||||
|
(lr/warnf "unimplemented method for %s" x)
|
||||||
|
(s/with-gen any?
|
||||||
|
(constantly (gen/return {}))))
|
||||||
|
|
||||||
|
(defmethod node-spec :default [x] (unimplemented-spec x))
|
||||||
|
|
||||||
|
(def ^:private nfe
|
||||||
|
"NFE — “no further expectations.” Used in sub-specs of `::element`
|
||||||
|
et al. for elements with no additional structure beyond that
|
||||||
|
provided by their parents."
|
||||||
|
(s/with-gen any?
|
||||||
|
(constantly (gen/return {}))))
|
||||||
|
|
||||||
|
(s/def ::node
|
||||||
|
(s/multi-spec node-spec :type))
|
||||||
|
|
||||||
|
(s/def :object/type ::object-type)
|
||||||
|
|
||||||
|
(s/def ::object
|
||||||
|
(s/keys :req-un [:object/type]))
|
||||||
|
|
||||||
|
(s/def :element/children (s/coll-of ::object :kind vector?))
|
||||||
|
(s/def :element/type ::element-type)
|
||||||
|
|
||||||
|
(s/def ::element
|
||||||
|
(s/keys :opt-un [::contents-begin ::contents-end]
|
||||||
|
:req-un [:element/children :element/type]))
|
||||||
|
|
||||||
|
(s/def :greater-element/children
|
||||||
|
(s/coll-of (s/merge
|
||||||
|
(dict {:type (set/union greater-element-types
|
||||||
|
element-types)})
|
||||||
|
::node)
|
||||||
|
:kind vector?))
|
||||||
|
|
||||||
|
(s/def :greater-element/type ::greater-element-type)
|
||||||
|
|
||||||
|
(s/def ::greater-element
|
||||||
|
(s/keys :req-un [::contents-begin ::contents-end
|
||||||
|
:greater-element/children
|
||||||
|
:greater-element/type]))
|
||||||
|
|
||||||
|
(s/def :recursive-object/children
|
||||||
|
(s/coll-of
|
||||||
|
(s/merge
|
||||||
|
(dict {:type ::object-type})
|
||||||
|
::node)
|
||||||
|
:kind vector?))
|
||||||
|
|
||||||
|
(s/def :recursive-object/type ::object-type)
|
||||||
|
|
||||||
|
(s/def ::recursive-object
|
||||||
|
(s/keys :opt-un [::contents-begin ::contents-end]
|
||||||
|
:req-un [:recursive-object/children
|
||||||
|
:recursive-object/type]))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(use 'net.deertopia.doerg.repl)
|
||||||
|
(def doc (-> "test/net/deertopia/doerg/element_test/paragraph-with-multiple-latex.org"
|
||||||
|
slurp
|
||||||
|
(read-string :post-processors
|
||||||
|
[gather-first-section])))
|
||||||
|
(s/explain ::node doc)
|
||||||
|
(binding [s/*recursion-limit* 1]
|
||||||
|
(gen/generate (s/gen ::node)))
|
||||||
|
(sp/select [postorder-walker (sp/must :children)
|
||||||
|
(sp/continuous-subseqs)]
|
||||||
|
doc))
|
||||||
|
|
||||||
|
(s/def ::todo-keyword string?)
|
||||||
|
(s/def ::priority string?)
|
||||||
|
(s/def ::commented boolean?)
|
||||||
|
(s/def ::level nat-int?)
|
||||||
|
(s/def ::tags (s/coll-of string? :kind vector?))
|
||||||
|
|
||||||
|
|
||||||
|
;;; Specs (specific elements)
|
||||||
|
|
||||||
|
(def ^:private string-value (dict {:value string?}))
|
||||||
|
|
||||||
|
(defmethod node-spec "text" [_] (s/merge ::object string-value))
|
||||||
|
(defmethod node-spec "verbatim" [_] (s/merge ::object string-value))
|
||||||
|
(defmethod node-spec "code" [_] (s/merge ::object string-value))
|
||||||
|
(defmethod node-spec "bold" [_] ::recursive-object)
|
||||||
|
(defmethod node-spec "italic" [_] ::recursive-object)
|
||||||
|
|
||||||
|
(defmethod node-spec "headline" [_]
|
||||||
|
(s/merge ::element
|
||||||
|
(dict {:todo-keyword (s/nilable ::todo-keyword)
|
||||||
|
:priority (s/nilable ::priority)
|
||||||
|
:level ::level
|
||||||
|
:commented ::commented
|
||||||
|
:raw-value string?
|
||||||
|
:tags ::tags})))
|
||||||
|
|
||||||
|
(defmethod node-spec "org-data" [_]
|
||||||
|
::greater-element)
|
||||||
|
|
||||||
|
(defmethod node-spec "section" [_]
|
||||||
|
::greater-element)
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
(ns net.deertopia.doerg.html
|
(ns net.deertopia.doerg.html
|
||||||
"Common HTML elements and utilities"
|
"Common HTML elements and utilities"
|
||||||
(:require [clojure.java.io :as io]
|
(:require [clojure.java.io :as io]
|
||||||
|
[net.deertopia.doerg.config :as cfg]
|
||||||
[babashka.fs :as fs]))
|
[babashka.fs :as fs]))
|
||||||
|
|
||||||
#_
|
#_
|
||||||
@@ -27,7 +28,7 @@
|
|||||||
[:meta {:charset "utf-8"}])
|
[:meta {:charset "utf-8"}])
|
||||||
|
|
||||||
(defn external-stylesheet [href]
|
(defn external-stylesheet [href]
|
||||||
[:link {:rel "stylesheet" :type "text/css" :href (str "/resource/" href)}])
|
[:link {:rel "stylesheet" :type "text/css" :href href}])
|
||||||
|
|
||||||
(def ibm-plex
|
(def ibm-plex
|
||||||
(concat
|
(concat
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
(ns net.deertopia.doerg.main
|
||||||
|
(:gen-class))
|
||||||
|
|
||||||
|
(defn -main []
|
||||||
|
(println "hello from doerg"))
|
||||||
@@ -12,8 +12,7 @@
|
|||||||
[net.deertopia.doerg.tex :as tex]
|
[net.deertopia.doerg.tex :as tex]
|
||||||
[net.deertopia.doerg.tex.temml :as tex-temml]
|
[net.deertopia.doerg.tex.temml :as tex-temml]
|
||||||
[clojure.zip :as z]
|
[clojure.zip :as z]
|
||||||
[babashka.fs :as fs]
|
[babashka.fs :as fs]))
|
||||||
[clojure.edn :as edn]))
|
|
||||||
|
|
||||||
;;; Top-level API
|
;;; Top-level API
|
||||||
|
|
||||||
@@ -40,7 +39,7 @@
|
|||||||
#(do (assert (element/of-type? % "keyword"))
|
#(do (assert (element/of-type? % "keyword"))
|
||||||
(:key %)))
|
(:key %)))
|
||||||
|
|
||||||
(def ^:dynamic ^:private *opts*)
|
(def ^:dynamic ^:private *document-info*)
|
||||||
|
|
||||||
(declare ^:private gather-footnotes render-renderer-error
|
(declare ^:private gather-footnotes render-renderer-error
|
||||||
view-children-as-seq render-tex-snippets)
|
view-children-as-seq render-tex-snippets)
|
||||||
@@ -63,31 +62,23 @@
|
|||||||
|
|
||||||
(defn org-document
|
(defn org-document
|
||||||
"Recursively render an Org-mode document to Hiccup."
|
"Recursively render an Org-mode document to Hiccup."
|
||||||
[doc & {:as opts :keys [postamble header title]}]
|
[doc]
|
||||||
(binding [*opts* opts]
|
(tex-temml/binding-worker
|
||||||
(tex-temml/binding-worker
|
(let [rendered (-> doc gather-footnotes render-tex-snippets
|
||||||
(let [rendered (-> doc gather-footnotes render-tex-snippets
|
org-element-recursive)]
|
||||||
org-element-recursive)]
|
[:html
|
||||||
[:html
|
[:head
|
||||||
[:head
|
[:title "org document"]
|
||||||
(when title
|
doerg-html/head]
|
||||||
[:title title])
|
[:body {:lang default-language}
|
||||||
doerg-html/head]
|
[:article
|
||||||
[:body {:lang default-language}
|
rendered]]])))
|
||||||
(when header
|
|
||||||
[:header header])
|
|
||||||
[:article
|
|
||||||
rendered
|
|
||||||
(when postamble
|
|
||||||
[:footer
|
|
||||||
[:hr]
|
|
||||||
postamble])]]]))))
|
|
||||||
|
|
||||||
(defn to-html
|
(defn to-html
|
||||||
"Read `f` with `slurp` as an Org document and return a string of
|
"Read `f` with `slurp` as an Org document and return a string of
|
||||||
rendered HTML. See `org-document` for opts."
|
rendered HTML."
|
||||||
[f & {:as opts}]
|
[f]
|
||||||
(str (hiccup/html {} (-> f slurp element/read-string (org-document opts)))))
|
(str (hiccup/html {} (-> f slurp element/read-string org-document))))
|
||||||
|
|
||||||
|
|
||||||
;;; Further dispatching on `org-element`
|
;;; Further dispatching on `org-element`
|
||||||
@@ -111,19 +102,6 @@
|
|||||||
(sp/view #(update % :children seq))
|
(sp/view #(update % :children seq))
|
||||||
sp/STAY))
|
sp/STAY))
|
||||||
|
|
||||||
(defn center [& es]
|
|
||||||
[:div.center es])
|
|
||||||
|
|
||||||
(defn doerg-attrs [e]
|
|
||||||
(->> e :affiliated :attr_doerg (str/join " ")
|
|
||||||
(format "{%s}") edn/read-string))
|
|
||||||
|
|
||||||
(defn em [x]
|
|
||||||
(format "%.4fem" x))
|
|
||||||
|
|
||||||
(defn wrap-if [x c f]
|
|
||||||
(if c (f x) x))
|
|
||||||
|
|
||||||
(defn- contains-footnote-refs? [node]
|
(defn- contains-footnote-refs? [node]
|
||||||
(some #(element/of-type? % "footnote-reference")
|
(some #(element/of-type? % "footnote-reference")
|
||||||
(:children node)))
|
(:children node)))
|
||||||
@@ -201,7 +179,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defn render-pprint
|
(defn- render-pprint
|
||||||
"Render the argument inline as `clojure.pprint/pprint` output."
|
"Render the argument inline as `clojure.pprint/pprint` output."
|
||||||
[x & {:keys [text]
|
[x & {:keys [text]
|
||||||
:or {text "debug!"}}]
|
:or {text "debug!"}}]
|
||||||
@@ -276,14 +254,11 @@
|
|||||||
(defmethod org-element "bold" [{:keys [children]}]
|
(defmethod org-element "bold" [{:keys [children]}]
|
||||||
[:b children])
|
[:b children])
|
||||||
|
|
||||||
(defmethod org-element "strike-through" [{:keys [children]}]
|
|
||||||
[:s children])
|
|
||||||
|
|
||||||
(defmethod org-element "subscript" [{:keys [children]}]
|
(defmethod org-element "subscript" [{:keys [children]}]
|
||||||
[:sub children])
|
[:sub children])
|
||||||
|
|
||||||
(defmethod org-element "superscript" [{:keys [children]}]
|
(defmethod org-element "superscript" [{:keys [children]}]
|
||||||
[:sup children])
|
[:super children])
|
||||||
|
|
||||||
(defmethod org-element "italic" [{:keys [children]}]
|
(defmethod org-element "italic" [{:keys [children]}]
|
||||||
[:em children])
|
[:em children])
|
||||||
@@ -354,52 +329,23 @@
|
|||||||
[:span.latex-fragment.display-math
|
[:span.latex-fragment.display-math
|
||||||
(-> e ::rendered deref)])
|
(-> e ::rendered deref)])
|
||||||
|
|
||||||
(defmethod org-element "example-block" [{:keys [value] :as e}]
|
(defmethod org-element "example-block" [{:keys [value]}]
|
||||||
(let [{:keys [center? alt scale img?]} (doerg-attrs e)]
|
[:pre value])
|
||||||
(-> [:pre (merge (and img? {:role "img"
|
|
||||||
:aria-label alt
|
|
||||||
:title alt})
|
|
||||||
(and scale {:style {:font-size (em scale)}}))
|
|
||||||
value]
|
|
||||||
(wrap-if center? center))))
|
|
||||||
|
|
||||||
(defmethod org-element "src-block" [{:keys [value]}]
|
(defmethod org-element "src-block" [{:keys [value]}]
|
||||||
[:pre [:code value]])
|
[:pre [:code value]])
|
||||||
|
|
||||||
(defn- split-quote-block-children [children]
|
(defmethod org-element "quote-block" [{:keys [children]}]
|
||||||
(match (split-with #(not= % [:hr]) children)
|
[:blockquote children])
|
||||||
[x ([[:hr] & ys] :seq)] [x (strip-paragraphs ys)]
|
|
||||||
x x))
|
|
||||||
|
|
||||||
(defmethod org-element "quote-block" [{:keys [children] :as e}]
|
|
||||||
(let [{:keys [epigraph?]} (doerg-attrs e)
|
|
||||||
[content footer] (split-quote-block-children children)]
|
|
||||||
(-> [:blockquote
|
|
||||||
content
|
|
||||||
(when footer
|
|
||||||
[:footer footer])]
|
|
||||||
(wrap-if epigraph? (fn [c] [:div.epigraph c])))))
|
|
||||||
|
|
||||||
(defmethod org-element "horizontal-rule" [_]
|
|
||||||
[:hr])
|
|
||||||
|
|
||||||
(defmethod org-element "comment" [_] nil)
|
(defmethod org-element "comment" [_] nil)
|
||||||
|
|
||||||
(defmethod org-keyword "TITLE" [{:keys [value]}]
|
(defmethod org-keyword "TITLE" [{:keys [value]}]
|
||||||
[:h1 value])
|
[:h1 value])
|
||||||
|
|
||||||
(defmethod org-keyword "SUBTITLE" [{:keys [value]}]
|
|
||||||
[:p.subtitle value])
|
|
||||||
|
|
||||||
(defmethod org-keyword "LATEX_COMPILER" [_] nil)
|
(defmethod org-keyword "LATEX_COMPILER" [_] nil)
|
||||||
(defmethod org-keyword "LATEX_HEADER" [_] nil)
|
(defmethod org-keyword "LATEX_HEADER" [_] nil)
|
||||||
|
|
||||||
;; TODO: A bunch of things I'd rather hide for now, but should be
|
|
||||||
;; implemented eventually.
|
|
||||||
(defmethod org-keyword "FILETAGS" [_] nil)
|
|
||||||
(defmethod org-element "planning" [_] nil)
|
|
||||||
(defmethod org-element "timestamp" [_] nil)
|
|
||||||
|
|
||||||
;; Not sure how to deal with this one yet.
|
;; Not sure how to deal with this one yet.
|
||||||
(defmethod org-keyword "AUTHOR" [_] nil)
|
(defmethod org-keyword "AUTHOR" [_] nil)
|
||||||
|
|
||||||
@@ -5,8 +5,7 @@
|
|||||||
[clojure.java.io :as io]
|
[clojure.java.io :as io]
|
||||||
[hiccup2.core :as h]
|
[hiccup2.core :as h]
|
||||||
[clojure.pprint]
|
[clojure.pprint]
|
||||||
[babashka.fs :as fs]
|
[babashka.fs :as fs]))
|
||||||
[net.deertopia.doerg :as-alias doerg]))
|
|
||||||
|
|
||||||
(def some-org-file
|
(def some-org-file
|
||||||
#_
|
#_
|
||||||
@@ -28,20 +27,27 @@
|
|||||||
(fs/delete-if-exists path)
|
(fs/delete-if-exists path)
|
||||||
(fs/create-sym-link path target))
|
(fs/create-sym-link path target))
|
||||||
|
|
||||||
|
(defn reconfigure-doerg! []
|
||||||
|
(alter-var-root
|
||||||
|
#'cfg/*cfg*
|
||||||
|
#(assoc %
|
||||||
|
::cfg/doerg-temml-worker "./doerg-temml-worker/index.js"
|
||||||
|
::cfg/doerg-parser "./doerg-parser/index.js")))
|
||||||
|
|
||||||
(defn render-html [& {:keys [src dest]
|
(defn render-html [& {:keys [src dest]
|
||||||
:or {src some-org-file
|
:or {src some-org-file
|
||||||
dest "/tmp/doerg-test"}}]
|
dest "/tmp/doerg-test"}}]
|
||||||
(let [resource-dir (fs/file dest "resource")]
|
(fs/create-dirs dest)
|
||||||
(fs/create-dirs dest)
|
(force-create-sym-link (fs/file dest "ibm-plex-web")
|
||||||
(fs/create-dirs resource-dir)
|
(-> cfg/*cfg* ::cfg/ibm-plex-web))
|
||||||
(force-create-sym-link (fs/file resource-dir "ibm-plex-web")
|
(force-create-sym-link (fs/file dest "deerstar.css")
|
||||||
(-> cfg/*cfg* ::cfg/ibm-plex-web))
|
(io/resource "net/deertopia/doerg/deerstar.css"))
|
||||||
(doseq [x #{"Temml-Plex.css" "tuftesque.css" "deerstar.css"}]
|
(force-create-sym-link (fs/file dest "tuftesque.css")
|
||||||
(force-create-sym-link
|
(io/resource "net/deertopia/doerg/tuftesque.css"))
|
||||||
(fs/file resource-dir x)
|
(force-create-sym-link (fs/file dest "Temml-Plex.css")
|
||||||
(io/resource (str "net/deertopia/doerg/" x))))
|
(io/resource "net/deertopia/doerg/Temml-Plex.css"))
|
||||||
(fs/delete-if-exists (fs/file dest "index.html"))
|
(fs/delete-if-exists (fs/file dest "index.html"))
|
||||||
(->> src render/to-html str (spit (fs/file dest "index.html")))))
|
(->> src render/to-html str (spit (fs/file dest "index.html"))))
|
||||||
|
|
||||||
(defn render-edn [& {:keys [src dest]
|
(defn render-edn [& {:keys [src dest]
|
||||||
:or {src some-org-file
|
:or {src some-org-file
|
||||||
File renamed without changes.
+3
-4
@@ -7,8 +7,7 @@
|
|||||||
[clojure.string :as str]
|
[clojure.string :as str]
|
||||||
[clojure.tools.logging :as l]
|
[clojure.tools.logging :as l]
|
||||||
[babashka.fs :as fs]
|
[babashka.fs :as fs]
|
||||||
[net.deertopia.doerg.config :as cfg]
|
[net.deertopia.doerg.config :as cfg])
|
||||||
[net.deertopia.doerg :as-alias doerg])
|
|
||||||
(:import (java.io ByteArrayOutputStream)))
|
(:import (java.io ByteArrayOutputStream)))
|
||||||
|
|
||||||
(def ^:private scale-divisor 66873.46948423679)
|
(def ^:private scale-divisor 66873.46948423679)
|
||||||
@@ -83,14 +82,14 @@
|
|||||||
acc))))
|
acc))))
|
||||||
|
|
||||||
(defn- invoke-latex [& {:keys [file output-dir]}]
|
(defn- invoke-latex [& {:keys [file output-dir]}]
|
||||||
(let [latex (-> cfg/*cfg* ::cfg/latex)]
|
(let [latex (::cfg/latex cfg/*cfg*)]
|
||||||
(invoke
|
(invoke
|
||||||
{:dir output-dir}
|
{:dir output-dir}
|
||||||
latex "-no-pdf" "-interaction" "nonstopmode"
|
latex "-no-pdf" "-interaction" "nonstopmode"
|
||||||
"-output-directory" output-dir file)))
|
"-output-directory" output-dir file)))
|
||||||
|
|
||||||
(defn- invoke-dvisvgm [& {:keys [file output-dir]}]
|
(defn- invoke-dvisvgm [& {:keys [file output-dir]}]
|
||||||
(let [dvisvgm (-> cfg/*cfg* ::cfg/dvisvgm)]
|
(let [dvisvgm (::cfg/dvisvgm cfg/*cfg*)]
|
||||||
(invoke
|
(invoke
|
||||||
{:dir output-dir}
|
{:dir output-dir}
|
||||||
dvisvgm "--page=1-" "--optimize" "--clipjoin"
|
dvisvgm "--page=1-" "--optimize" "--clipjoin"
|
||||||
+6
-23
@@ -6,8 +6,7 @@
|
|||||||
[clojure.java.io :as io]
|
[clojure.java.io :as io]
|
||||||
[clojure.string :as str]
|
[clojure.string :as str]
|
||||||
[clojure.tools.logging :as l]
|
[clojure.tools.logging :as l]
|
||||||
[babashka.fs :as fs]
|
[babashka.fs :as fs])
|
||||||
[net.deertopia.doerg :as-alias doerg])
|
|
||||||
(:import (java.io ByteArrayOutputStream)))
|
(:import (java.io ByteArrayOutputStream)))
|
||||||
|
|
||||||
(def ^:dynamic *worker-timeout-duration*
|
(def ^:dynamic *worker-timeout-duration*
|
||||||
@@ -17,26 +16,14 @@
|
|||||||
|
|
||||||
(def ^:dynamic *worker*)
|
(def ^:dynamic *worker*)
|
||||||
|
|
||||||
;; 외부의 브로그램이 JVM resource를 사용 위해서 파일 시스템에서 써야
|
(defn worker [& {:keys [preamble]}]
|
||||||
;; 합니다.
|
(let [doerg-temml-worker (::cfg/doerg-temml-worker cfg/*cfg*)]
|
||||||
(defonce ^:private prelude-file
|
|
||||||
(-> (fs/create-temp-file {:prefix "doerg-prelude-"
|
|
||||||
:suffix ".tex"})
|
|
||||||
fs/file))
|
|
||||||
|
|
||||||
(defn worker []
|
|
||||||
(let [doerg-temml-worker (-> cfg/*cfg* ::cfg/doerg-temml-worker)]
|
|
||||||
(when (or (not (fs/exists? prelude-file))
|
|
||||||
(zero? (fs/size prelude-file)))
|
|
||||||
(-> "net/deertopia/doerg/prelude.tex"
|
|
||||||
io/resource
|
|
||||||
io/input-stream
|
|
||||||
(io/copy prelude-file)))
|
|
||||||
(p/process
|
(p/process
|
||||||
{:shutdown p/destroy-tree
|
{:shutdown p/destroy-tree
|
||||||
:err (l/log-stream :info "temml/err")}
|
:err (l/log-stream :info "temml/err")}
|
||||||
doerg-temml-worker
|
doerg-temml-worker
|
||||||
"--preamble" prelude-file)))
|
"--preamble"
|
||||||
|
"resources/net/deertopia/doerg/prelude.tex")))
|
||||||
|
|
||||||
(defn close-worker [tw]
|
(defn close-worker [tw]
|
||||||
(.close (:in tw)))
|
(.close (:in tw)))
|
||||||
@@ -59,11 +46,7 @@
|
|||||||
(defn command-worker [x]
|
(defn command-worker [x]
|
||||||
(cbor/encode cbor/default-codec (:in *worker*) x)
|
(cbor/encode cbor/default-codec (:in *worker*) x)
|
||||||
(.flush (:in *worker*))
|
(.flush (:in *worker*))
|
||||||
(let [r (cbor/decode cbor/default-codec (:out *worker*))]
|
(cbor/decode cbor/default-codec (:out *worker*)))
|
||||||
(if (string? r)
|
|
||||||
r
|
|
||||||
(throw (ex-info "bad data from temml worker"
|
|
||||||
{:data r})))))
|
|
||||||
|
|
||||||
(defn render-inline [s]
|
(defn render-inline [s]
|
||||||
(command-worker s))
|
(command-worker s))
|
||||||
File renamed without changes.
@@ -0,0 +1,8 @@
|
|||||||
|
(ns net.deertopia.doerg.config-test
|
||||||
|
(:require [net.deertopia.doerg.config :as sut]
|
||||||
|
[clojure.test :as t]
|
||||||
|
[clojure.spec.alpha :as s]))
|
||||||
|
|
||||||
|
(t/deftest default-config-is-config
|
||||||
|
(t/testing "default config is valid"
|
||||||
|
(t/is (s/valid? ::sut/config sut/default))))
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Generated
+37
-3
@@ -59,6 +59,24 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nix-fetcher-data": {
|
"nix-fetcher-data": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-parts": "flake-parts",
|
"flake-parts": "flake-parts",
|
||||||
@@ -111,11 +129,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1774386573,
|
"lastModified": 1760038930,
|
||||||
"narHash": "sha256-4hAV26quOxdC6iyG7kYaZcM3VOskcPUrdCQd/nx8obc=",
|
"narHash": "sha256-Oncbh0UmHjSlxO7ErQDM3KM0A5/Znfofj2BSzlHLeVw=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "46db2e09e1d3f113a13c0d7b81e2f221c63b8ce9",
|
"rev": "0b4defa2584313f3b781240b29d61f6f9f7e0df3",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -144,6 +162,7 @@
|
|||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"clj-nix": "clj-nix",
|
"clj-nix": "clj-nix",
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
"nixpkgs": "nixpkgs_2",
|
"nixpkgs": "nixpkgs_2",
|
||||||
"sydpkgs": "sydpkgs"
|
"sydpkgs": "sydpkgs"
|
||||||
}
|
}
|
||||||
@@ -165,6 +184,21 @@
|
|||||||
"repo": "sydpkgs",
|
"repo": "sydpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"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",
|
"root": "root",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
clj-nix.url = "github:jlesquembre/clj-nix";
|
clj-nix.url = "github:jlesquembre/clj-nix";
|
||||||
sydpkgs.url = "github:msyds/sydpkgs";
|
sydpkgs.url = "github:msyds/sydpkgs";
|
||||||
};
|
};
|
||||||
@@ -14,19 +15,16 @@
|
|||||||
"x86_64-linux"
|
"x86_64-linux"
|
||||||
];
|
];
|
||||||
|
|
||||||
overlays = [
|
|
||||||
inputs.sydpkgs.overlays.default
|
|
||||||
clj-nix.overlays.default
|
|
||||||
];
|
|
||||||
|
|
||||||
each-system = f: nixpkgs.lib.genAttrs supportedSystems (system: f rec {
|
each-system = f: nixpkgs.lib.genAttrs supportedSystems (system: f rec {
|
||||||
pkgs = import nixpkgs {
|
pkgs = import nixpkgs {
|
||||||
inherit system;
|
inherit system;
|
||||||
overlays = overlays ++ [
|
overlays = [
|
||||||
self.overlays.default
|
inputs.sydpkgs.overlays.default
|
||||||
];
|
clj-nix.overlays.default
|
||||||
};
|
self.overlays.default
|
||||||
inherit (pkgs) lib;
|
];
|
||||||
|
};
|
||||||
|
inherit (pkgs) lib;
|
||||||
inherit system;
|
inherit system;
|
||||||
});
|
});
|
||||||
in {
|
in {
|
||||||
@@ -34,51 +32,45 @@
|
|||||||
_pkgs = each-system ({ pkgs, ... }: pkgs);
|
_pkgs = each-system ({ pkgs, ... }: pkgs);
|
||||||
|
|
||||||
packages = each-system ({ pkgs, ... }: {
|
packages = each-system ({ pkgs, ... }: {
|
||||||
inherit (pkgs) doerg doerg-parser doerg-temml-worker;
|
inherit (pkgs) publisher doerg doerg-parser doerg-temml-worker;
|
||||||
default = pkgs.doerg;
|
default = pkgs.publisher;
|
||||||
});
|
});
|
||||||
|
|
||||||
overlays.default = final: prev:
|
overlays.default = final: prev:
|
||||||
let
|
let graal = x: final.mkGraalBin { cljDrv = x; };
|
||||||
# is this really the correct way to satisfy our
|
vendored = final.callPackage ./vendor {};
|
||||||
# dependencies? lmfao
|
in {
|
||||||
final' = final.appendOverlays overlays;
|
inherit (vendored) ibm-plex-web;
|
||||||
graal = x: final'.mkGraalBin { cljDrv = x; };
|
publisher = final.callPackage ./publisher {};
|
||||||
in {
|
doerg = final.callPackage ./doerg {};
|
||||||
ibm-plex-web = final'.callPackage ./ibm-plex-web.nix {};
|
doerg-parser = final.callPackage ./doerg/doerg-parser {};
|
||||||
doerg = final'.callPackage ./. {};
|
doerg-temml-worker = final.callPackage ./doerg/doerg-temml-worker {};
|
||||||
doerg-parser = final'.callPackage ./doerg-parser {};
|
};
|
||||||
doerg-temml-worker = final'.callPackage ./doerg-temml-worker {};
|
|
||||||
our-tex = final'.callPackage ./our-tex.nix {};
|
|
||||||
};
|
|
||||||
|
|
||||||
checks = each-system ({ pkgs, system, ... }: {
|
checks = each-system ({ pkgs, system, ... }: {
|
||||||
build-all =
|
build-all =
|
||||||
pkgs.linkFarmFromDrvs
|
pkgs.linkFarmFromDrvs
|
||||||
"all"
|
"all"
|
||||||
(pkgs.lib.attrValues self.packages.${system});
|
(pkgs.lib.attrValues self.packages.${system});
|
||||||
});
|
});
|
||||||
|
|
||||||
nixosModules.default = import ./module.nix { inherit self; };
|
|
||||||
|
|
||||||
devShells = each-system ({ pkgs, system, ... }: {
|
devShells = each-system ({ pkgs, system, ... }: {
|
||||||
default = pkgs.mkShell {
|
default = pkgs.mkShell {
|
||||||
inputsFrom = [
|
inputsFrom = [
|
||||||
pkgs.doerg
|
pkgs.doerg
|
||||||
pkgs.doerg-parser
|
pkgs.doerg-parser
|
||||||
pkgs.doerg-temml-worker
|
pkgs.doerg-temml-worker
|
||||||
];
|
];
|
||||||
packages = with pkgs; [
|
packages = with pkgs; [
|
||||||
clojure-lsp
|
clojure-lsp
|
||||||
doerg-parser
|
doerg-parser
|
||||||
doerg-temml-worker
|
doerg-temml-worker
|
||||||
zprint
|
zprint
|
||||||
clojure
|
clojure
|
||||||
babashka
|
babashka
|
||||||
sqlite-web
|
sqlite-web
|
||||||
pkgs.doerg.test-emacs
|
];
|
||||||
];
|
};
|
||||||
};
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
-107
@@ -1,107 +0,0 @@
|
|||||||
{ self, ... }:
|
|
||||||
{ config, lib, pkgs, ... }:
|
|
||||||
|
|
||||||
let
|
|
||||||
cfg = config.services.doerg;
|
|
||||||
doerg-config = pkgs.writeText "doerg-config.edn" ''
|
|
||||||
#:net.deertopia.doerg.config
|
|
||||||
{:org-roam-db-path "${cfg.databasePath}"
|
|
||||||
:state-directory "${cfg.stateDir}"
|
|
||||||
:port ${builtins.toString cfg.port}}
|
|
||||||
'';
|
|
||||||
|
|
||||||
inherit (lib) types;
|
|
||||||
|
|
||||||
org-roam-db-sync = pkgs.writeText "org-roam-db-sync.el" ''
|
|
||||||
#!/usr/bin/env -S emacs -Q -x
|
|
||||||
|
|
||||||
(require 'org-roam)
|
|
||||||
|
|
||||||
(setq org-roam-directory (expand-file-name (car command-line-args-left)))
|
|
||||||
(setq org-roam-db-location (expand-file-name (cadr command-line-args-left)))
|
|
||||||
|
|
||||||
(org-roam-db-sync)
|
|
||||||
'';
|
|
||||||
in {
|
|
||||||
options.services.doerg = {
|
|
||||||
enable = lib.mkEnableOption "Doerg";
|
|
||||||
org-roam-db-sync.enable = lib.mkEnableOption "Org-roam db sync";
|
|
||||||
port = lib.mkOption {
|
|
||||||
default = 21984;
|
|
||||||
type = lib.types.port;
|
|
||||||
description = ''
|
|
||||||
The port on which Doerg will listen.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
stateDir = lib.mkOption {
|
|
||||||
type = types.path;
|
|
||||||
default = "/var/lib/private/doerg";
|
|
||||||
description = "Daemon's state directory.";
|
|
||||||
};
|
|
||||||
orgDir = lib.mkOption {
|
|
||||||
type = types.path;
|
|
||||||
description = "Org roam directory.";
|
|
||||||
};
|
|
||||||
package = lib.mkPackageOption pkgs "doerg" {};
|
|
||||||
databasePath = lib.mkOption {
|
|
||||||
type = types.path;
|
|
||||||
description = "Org roam database path";
|
|
||||||
default = cfg.orgDir + "org-roam.db";
|
|
||||||
};
|
|
||||||
openFirewall = lib.mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
description = "Open doerg ports?";
|
|
||||||
default = false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
nixpkgs.overlays = [ self.overlays.default ];
|
|
||||||
|
|
||||||
systemd.services.org-roam-db-sync = lib.mkIf cfg.org-roam-db-sync.enable {
|
|
||||||
script = lib.escapeShellArgs [
|
|
||||||
(lib.getExe cfg.package.test-emacs)
|
|
||||||
"-Q" "-x" org-roam-db-sync cfg.orgDir cfg.databasePath
|
|
||||||
];
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
ReadOnlyBindPaths = [
|
|
||||||
cfg.orgDir
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.timers.org-roam-db-sync = lib.mkIf cfg.org-roam-db-sync.enable {
|
|
||||||
unitConfig.StopWhenUnneeded = true;
|
|
||||||
timerConfig = {
|
|
||||||
OnActiveSec = "1h";
|
|
||||||
RandomizedDelaySec = "30m";
|
|
||||||
Persistent = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [
|
|
||||||
cfg.port
|
|
||||||
];
|
|
||||||
|
|
||||||
systemd.services.doerg = {
|
|
||||||
after = [ "network-online.target" ];
|
|
||||||
wants = [ "network-online.target" "org-roam-db-sync.timer" ];
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
environment.DOERG_CONFIG = doerg-config;
|
|
||||||
serviceConfig = {
|
|
||||||
# WorkingDirectory = cfg.stateDir;
|
|
||||||
StateDirectory = "doerg";
|
|
||||||
ExecStart = lib.getExe cfg.package;
|
|
||||||
DynamicUser = true;
|
|
||||||
ProtectSystem = "strict";
|
|
||||||
PrivateTmp = true;
|
|
||||||
BindReadOnlyPaths = [
|
|
||||||
cfg.orgDir
|
|
||||||
# cfg.databasePath
|
|
||||||
"/nix"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
((nil
|
||||||
|
. ((cider-clojure-cli-aliases . ":dev")
|
||||||
|
(eval
|
||||||
|
. (progn
|
||||||
|
(defun start-deertopia-server ()
|
||||||
|
(let ((n (cider-format-connection-params "%j" cider-launch-params)))
|
||||||
|
(when (equal n "net-deertopia")
|
||||||
|
(cider-interactive-eval
|
||||||
|
"(do (require '[net.deertopia.publisher.server :as server])
|
||||||
|
(server/start!))"))))
|
||||||
|
(add-hook 'cider-connected-hook #'start-deertopia-server))))))
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{ mkCljBin
|
||||||
|
, doerg
|
||||||
|
, babashka
|
||||||
|
}:
|
||||||
|
|
||||||
|
mkCljBin {
|
||||||
|
name = "net.deertopia/publisher";
|
||||||
|
version = "0.1.0";
|
||||||
|
projectSrc = ./.;
|
||||||
|
lockfile = ../deps-lock.json;
|
||||||
|
main-ns = "net.deertopia.publisher.main";
|
||||||
|
buildInputs = [];
|
||||||
|
nativeBuildInputs = [
|
||||||
|
babashka
|
||||||
|
];
|
||||||
|
postPatch = ''
|
||||||
|
mv deps.edn deps.edn.old
|
||||||
|
bb -cp . -m override-deps < deps.edn.old > deps.edn \
|
||||||
|
net.deertopia/doerg '{:local/root "${doerg.lib}/${doerg.name}.jar"}'
|
||||||
|
'';
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{:deps {org.clojure/clojure {:mvn/version "1.12.0"}
|
||||||
|
org.clojure/tools.logging {:mvn/version "1.3.0"}
|
||||||
|
hiccup/hiccup {:mvn/version "2.0.0-RC4"}
|
||||||
|
org.clojars.pntblnk/clj-ldap {:mvn/version "0.0.17"}
|
||||||
|
babashka/fs {:mvn/version "0.5.24"}
|
||||||
|
org.clojure/core.match {:mvn/version "1.1.0"}
|
||||||
|
com.github.seancorfield/next.jdbc {:mvn/version "1.3.1070"}
|
||||||
|
org.xerial/sqlite-jdbc {:mvn/version "3.47.1.0"}
|
||||||
|
cheshire/cheshire {:mvn/version "6.1.0"}
|
||||||
|
instaparse/instaparse {:mvn/version "1.5.0"}
|
||||||
|
org.clojure/test.check {:mvn/version "1.1.2"}
|
||||||
|
net.deertopia/doerg {:local/root "../doerg"}
|
||||||
|
metosin/reitit {:mvn/version "0.10.1"}
|
||||||
|
http-kit/http-kit {:mvn/version "2.8.0"}}
|
||||||
|
:paths ["src" "resources" "test"]}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
;;; -*- mode:clojure -*-
|
||||||
|
;;;
|
||||||
|
;;; USAGE:
|
||||||
|
;;;
|
||||||
|
;;; bb -cp . -m override-deps -- [DEP-NAME INFO]…
|
||||||
|
;;;
|
||||||
|
;;; This script takes a series of deps substitutions on the command
|
||||||
|
;;; line, applies them to a deps.edn file (read on stdin), and spits
|
||||||
|
;;; the result to stdout.
|
||||||
|
;;;
|
||||||
|
;;; It is used to build the Doerg server with Nix, since Clj-nix does
|
||||||
|
;;; not resolve the local deps itself.
|
||||||
|
|
||||||
|
(ns override-deps
|
||||||
|
(:require [rewrite-clj.zip :as z]
|
||||||
|
[babashka.fs :as fs]
|
||||||
|
[clojure.edn :as edn]))
|
||||||
|
|
||||||
|
(defn apply-overrides [zloc overrides]
|
||||||
|
(loop [os (seq overrides)
|
||||||
|
loc zloc]
|
||||||
|
(if-some [[[k v] & xs] os]
|
||||||
|
(recur xs (z/assoc loc k v))
|
||||||
|
loc)))
|
||||||
|
|
||||||
|
(defn args->overrides [args]
|
||||||
|
(assert (even? (count args)))
|
||||||
|
(->> args (map edn/read-string) (apply hash-map)))
|
||||||
|
|
||||||
|
(defn -main [& args]
|
||||||
|
(let [zloc (-> (slurp *in*) z/of-string)
|
||||||
|
overrides (args->overrides args)]
|
||||||
|
(-> zloc
|
||||||
|
z/down
|
||||||
|
(z/find-value :deps) z/right
|
||||||
|
(apply-overrides overrides)
|
||||||
|
z/root-string
|
||||||
|
print)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(comment
|
||||||
|
"Example overrides"
|
||||||
|
(def overrides '{net.deertopia/doerg "blah!!!!"
|
||||||
|
ring/ring-defaults {:mvn/version "xxxxx"}}))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
"Behaviour of `args->overrides`."
|
||||||
|
(= (args->overrides ["net.deertopia/doerg" "{:mvn/version \"abc\"}"
|
||||||
|
"ring/ring-defaults" "{:local/root \"/path/to/jar\"}"])
|
||||||
|
'{ring/ring-defaults {:local/root "/path/to/jar"}
|
||||||
|
net.deertopia/doerg {:mvn/version "abc"}}))
|
||||||
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
(ns net.deertopia.publisher.main
|
||||||
|
(:require [net.deertopia.doerg.main :as doerg]
|
||||||
|
[net.deertopia.publisher.server :as server])
|
||||||
|
(:gen-class))
|
||||||
|
|
||||||
|
(defn -main []
|
||||||
|
(server/start!))
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
(ns net.deertopia.publisher.server
|
||||||
|
(:require [clojure.pprint :refer [pprint]]
|
||||||
|
[clojure.tools.logging :as l]
|
||||||
|
[hiccup2.core :as hiccup]
|
||||||
|
[net.deertopia.doerg.html :as doerg-html]
|
||||||
|
[net.deertopia.publisher.slug :as slug]
|
||||||
|
[org.httpkit.server :as http]
|
||||||
|
[reitit.coercion]
|
||||||
|
[reitit.coercion.spec]
|
||||||
|
[reitit.ring]
|
||||||
|
[ring.util.response :as response]))
|
||||||
|
|
||||||
|
|
||||||
|
;;; Routes
|
||||||
|
|
||||||
|
(defn hello [req]
|
||||||
|
(-> (hiccup/html {}
|
||||||
|
[:html
|
||||||
|
[:head
|
||||||
|
[:title "hello"]
|
||||||
|
doerg-html/charset
|
||||||
|
doerg-html/viewport]
|
||||||
|
[:body
|
||||||
|
[:pre
|
||||||
|
(with-out-str
|
||||||
|
(pprint req))]]])
|
||||||
|
str
|
||||||
|
response/response
|
||||||
|
(response/content-type "text/html")))
|
||||||
|
|
||||||
|
(defn node-by-slug [req]
|
||||||
|
(hello req))
|
||||||
|
|
||||||
|
(defn node-by-id [req]
|
||||||
|
(hello req))
|
||||||
|
|
||||||
|
(def router
|
||||||
|
(reitit.ring/router
|
||||||
|
#{["/" {:get hello}]
|
||||||
|
["/n/:slug" {:get node-by-slug
|
||||||
|
#_#_#_#_:coercion reitit.coercion.spec/coercion
|
||||||
|
:parameters {:path {:slug ::slug/slug}}}]
|
||||||
|
["/id/:id" {:get node-by-id}]}
|
||||||
|
#_{:compile reitit.coercion/compile-request-coercers}))
|
||||||
|
|
||||||
|
(defn match-by-path-and-coerce! [path]
|
||||||
|
(if-let [match (r/match-by-path router path)]
|
||||||
|
(assoc match :parameters (reitit.coercion/coerce! match))))
|
||||||
|
|
||||||
|
|
||||||
|
;;; Server API
|
||||||
|
|
||||||
|
(def app (reitit.ring/ring-handler router))
|
||||||
|
|
||||||
|
(defonce server (atom nil))
|
||||||
|
|
||||||
|
(defn stop! []
|
||||||
|
(when @server
|
||||||
|
(http/server-stop! @server {:timeout 100})
|
||||||
|
(reset! server nil)
|
||||||
|
(l/info "Stopped server")))
|
||||||
|
|
||||||
|
;; For some reason, the log messages from `stop!` are not flushed
|
||||||
|
;; before the JVM shuts dowm. Nevertheless, the server /does/ come to
|
||||||
|
;; a graceful halt.
|
||||||
|
(def ^:private shutdown-hook (Thread. stop!))
|
||||||
|
|
||||||
|
(defn start! []
|
||||||
|
(if @server
|
||||||
|
(let [msg "Server already started"]
|
||||||
|
(throw (ex-info msg {})))
|
||||||
|
(do (reset! server
|
||||||
|
(http/run-server (bound-fn* #'app)
|
||||||
|
{:port 8080
|
||||||
|
:legacy-return-value? false}))
|
||||||
|
;; For some reason, the log messages are not flushed before
|
||||||
|
;; the JVM shuts dowm. Nevertheless, the server /does/ come
|
||||||
|
;; to a graceful halt.
|
||||||
|
(.addShutdownHook (Runtime/getRuntime) shutdown-hook)
|
||||||
|
(l/info "Server started on port 8080"))))
|
||||||
|
|
||||||
|
(defn status []
|
||||||
|
(if @server
|
||||||
|
(http/server-status @server)
|
||||||
|
:stopped))
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
(ns net.deertopia.doerg.slug
|
(ns net.deertopia.publisher.slug
|
||||||
(:require [clojure.spec.alpha :as s]
|
(:require [clojure.spec.alpha :as s])
|
||||||
[spec-tools.core :as st])
|
|
||||||
(:import (java.nio ByteBuffer)
|
(:import (java.nio ByteBuffer)
|
||||||
(java.util Base64 UUID)))
|
(java.util Base64 UUID)))
|
||||||
|
|
||||||
@@ -13,9 +12,11 @@
|
|||||||
(try (let [decoder (Base64/getUrlDecoder)]
|
(try (let [decoder (Base64/getUrlDecoder)]
|
||||||
(when (= 16 (count (.decode decoder s)))
|
(when (= 16 (count (.decode decoder s)))
|
||||||
(Slug. s)))
|
(Slug. s)))
|
||||||
;; really stupid
|
(catch IllegalArgumentException e
|
||||||
(catch IllegalArgumentException _
|
(when (not= (ex-message e)
|
||||||
nil)))
|
(str "Input byte[] should at least "
|
||||||
|
"have 2 bytes for base64 bytes"))
|
||||||
|
(throw e)))))
|
||||||
|
|
||||||
(defn to-string [s]
|
(defn to-string [s]
|
||||||
(str s))
|
(str s))
|
||||||
@@ -46,11 +47,11 @@
|
|||||||
(let [decoder (Base64/getUrlDecoder)]
|
(let [decoder (Base64/getUrlDecoder)]
|
||||||
(bytes->uuid (.decode decoder (str slug)))))
|
(bytes->uuid (.decode decoder (str slug)))))
|
||||||
|
|
||||||
(comment
|
#_
|
||||||
(let [uuid #uuid "f9eab66e-7773-4b87-b854-0bfc8f563809"
|
(let [uuid #uuid "f9eab66e-7773-4b87-b854-0bfc8f563809"
|
||||||
slug (from-uuid uuid)
|
slug (from-uuid uuid)
|
||||||
round-tripped (to-uuid slug)]
|
round-tripped (to-uuid slug)]
|
||||||
{:uuid uuid, :slug slug, :round-tripped round-tripped}))
|
{:uuid uuid, :slug slug, :round-tripped round-tripped})
|
||||||
|
|
||||||
(defn make-slug [string]
|
(defn make-slug [string]
|
||||||
(assert (try (to-uuid string)
|
(assert (try (to-uuid string)
|
||||||
@@ -59,6 +60,7 @@
|
|||||||
"invalid slug")
|
"invalid slug")
|
||||||
(->Slug string))
|
(->Slug string))
|
||||||
|
|
||||||
(s/def ::slug
|
(defn slug? [s]
|
||||||
(s/conformer #(or (some-> % from-string)
|
(some? (from-string s)))
|
||||||
::s/invalid)))
|
|
||||||
|
(s/def ::slug slug?)
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{ fetchzip
|
||||||
|
, fetchurl
|
||||||
|
}:
|
||||||
|
|
||||||
|
{
|
||||||
|
ibm-plex-serif = fetchzip {
|
||||||
|
url = "https://github.com/IBM/plex/releases/download/%40ibm%2Fplex-serif%401.1.0/ibm-plex-serif.zip";
|
||||||
|
hash = "sha256-8ygaAeMKygYS4GCub4YUQmkh87pYHfi3s0PQ6AbaeGw=";
|
||||||
|
};
|
||||||
|
|
||||||
|
ibm-plex-math = fetchzip {
|
||||||
|
url = "https://github.com/IBM/plex/releases/download/%40ibm%2Fplex-math%401.1.0/ibm-plex-math.zip";
|
||||||
|
hash = "sha256-dJA6uqxa/yb3eLY4l39NeP0yIl2NfrbaRpf6h0/F7Xc=";
|
||||||
|
};
|
||||||
|
|
||||||
|
ibm-plex-sans-kr = fetchzip {
|
||||||
|
url = "https://github.com/IBM/plex/releases/download/%40ibm%2Fplex-sans-kr%401.1.0/ibm-plex-sans-kr.zip";
|
||||||
|
hash = "sha256-FsHxMvLlI4yylgG96DOZIdW2DYpk7I+c5QgkVIkNZIE=";
|
||||||
|
};
|
||||||
|
|
||||||
|
"d3.v7.min.js" = fetchurl {
|
||||||
|
url = "https://d3js.org/d3.v7.min.js";
|
||||||
|
hash = "sha256-8glLv2FBs1lyLE/kVOtsSw8OQswQzHr5IfwVj864ZTk=";
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
#:net.deertopia.doerg.config
|
|
||||||
{:ibm-plex-web #or [#env IBM_PLEX_WEB
|
|
||||||
#xdg-data-dir "ibm-plex-web"]
|
|
||||||
:latex "xelatex"
|
|
||||||
:dvisvgm "dvisvgm"
|
|
||||||
:doerg-temml-worker
|
|
||||||
#profile {:dev #file "../../../../doerg-temml-worker/index.js"
|
|
||||||
:default "doerg-temml-worker"}
|
|
||||||
:doerg-parser
|
|
||||||
#profile {:dev #file "../../../../doerg-parser/index.js"
|
|
||||||
:default "doerg-parser"}
|
|
||||||
:state-directory #join [#or [#env XDG_STATE_HOME
|
|
||||||
#envf ["%s/.local/share" HOME]]
|
|
||||||
"/doerg-server"]
|
|
||||||
:org-roam-db-path
|
|
||||||
#profile {:default #join [#env HOME "/.cache/emacs/org-roam.db"]
|
|
||||||
:test #join [#or [#env TMP "/tmp"] "/doerg-org-roam-test.db"]}
|
|
||||||
:port #profile {:default 8080}}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
<file> ::= elements
|
|
||||||
|
|
||||||
<elements> ::= ws? element ws? elements
|
|
||||||
| ws? ε
|
|
||||||
|
|
||||||
<element> ::= string
|
|
||||||
| list
|
|
||||||
| symbol
|
|
||||||
| integer
|
|
||||||
| property-string
|
|
||||||
|
|
||||||
string ::= <'"'> #'([^"\\]|\\.|\\\n)*' <'"'>
|
|
||||||
|
|
||||||
property-string
|
|
||||||
::= <'#('> ws? string text-property* ws? <')'>
|
|
||||||
|
|
||||||
text-property ::= ws? element ws? element ws? element
|
|
||||||
|
|
||||||
list ::= <'('> elements dot-cdr? <')'>
|
|
||||||
|
|
||||||
symbol ::= #'([^?#0-9 \n\s\f()\[\]"\'\\.]|\\.)([^ \n\s\f()\[\]"\'\\]|\\.)*'
|
|
||||||
| #'\.([^ \n\s\f()\[\]"\'\\]|\\.)+'
|
|
||||||
|
|
||||||
integer ::= #'[-+]?[0-9]+' <#'.'>?
|
|
||||||
|
|
||||||
dot-cdr ::= <'.'> ws? element
|
|
||||||
|
|
||||||
<text> ::= ws? (string | property-string) ws?
|
|
||||||
|
|
||||||
<ws> ::= <#'(\s||\n)'>+
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 66 KiB |
@@ -1 +0,0 @@
|
|||||||
../Temml-Plex.css
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../deerstar.css
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../tuftesque.css
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
(ns net.deertopia.doerg.cached-file
|
|
||||||
(:require [babashka.fs :as fs]))
|
|
||||||
|
|
||||||
(defn newer-than?
|
|
||||||
"Return `true` if fs `file₁` was last modified sooner or at the same
|
|
||||||
time as `file₂`, or if `file₂` does not exist."
|
|
||||||
[file₁ file₂]
|
|
||||||
(or (not (fs/exists? file₂))
|
|
||||||
(<= 0 (compare (fs/last-modified-time file₁)
|
|
||||||
(fs/last-modified-time file₂)))))
|
|
||||||
|
|
||||||
(def ^:dynamic *use-cache?*
|
|
||||||
"Bind to `false` to disable caching for debugging purposes."
|
|
||||||
true)
|
|
||||||
|
|
||||||
(defn cached-file
|
|
||||||
"Return a file path after potentially regenerating the file by
|
|
||||||
calling `compute` with no arguments only if stale? is logical true."
|
|
||||||
[& {:keys [file stale? compute]}]
|
|
||||||
(when (or (not *use-cache?*) stale?)
|
|
||||||
(let [r (compute)
|
|
||||||
dir (fs/parent file)]
|
|
||||||
(assert (string? r))
|
|
||||||
(when-not (fs/exists? dir)
|
|
||||||
(fs/create-dirs dir))
|
|
||||||
(spit file r)))
|
|
||||||
file)
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
(ns net.deertopia.doerg.config
|
|
||||||
(:require [clojure.spec.alpha :as s]
|
|
||||||
[babashka.fs :as fs]
|
|
||||||
[aero.core :as aero]
|
|
||||||
[clojure.java.io :as io]))
|
|
||||||
|
|
||||||
(s/def ::config
|
|
||||||
(s/keys :req [::ibm-plex-web
|
|
||||||
::latex
|
|
||||||
::dvisvgm
|
|
||||||
::doerg-temml-worker
|
|
||||||
::doerg-parser
|
|
||||||
::state-directory
|
|
||||||
::org-roam-db-path]))
|
|
||||||
|
|
||||||
(s/def ::directory
|
|
||||||
(s/conformer #(fs/file %)))
|
|
||||||
|
|
||||||
(s/def ::file
|
|
||||||
(s/conformer #(-> % fs/expand-home fs/file)))
|
|
||||||
|
|
||||||
(s/def ::executable
|
|
||||||
(s/conformer
|
|
||||||
;; I'd love to use `fs/which` here, but it's fairly problematic to
|
|
||||||
;; check `fs/executable?` at… build time (which `fs/which` does)?
|
|
||||||
;; Wait… what? Do I know how Clojure compilation works?
|
|
||||||
#(or #_(some-> % fs/expand-home fs/which fs/file)
|
|
||||||
(some-> % fs/expand-home fs/file)
|
|
||||||
::s/invalid)))
|
|
||||||
|
|
||||||
(s/def ::ibm-plex-web ::directory)
|
|
||||||
|
|
||||||
(s/def ::latex ::executable)
|
|
||||||
|
|
||||||
(s/def ::dvisvgm ::executable)
|
|
||||||
|
|
||||||
(s/def ::doerg-temml-worker ::executable)
|
|
||||||
|
|
||||||
(s/def ::doerg-parser ::executable)
|
|
||||||
|
|
||||||
(s/def ::state-directory ::file)
|
|
||||||
(s/def ::org-roam-db-path ::file)
|
|
||||||
|
|
||||||
(defmethod aero/reader 'xdg-data-dir
|
|
||||||
[_opts tag value]
|
|
||||||
"Aero tag to search for a directory on $XDG_DATA_DIRS."
|
|
||||||
(some #(let [x (fs/path % value)]
|
|
||||||
(and (fs/exists? x) x))
|
|
||||||
(some-> (System/getenv "XDG_DATA_DIRS")
|
|
||||||
fs/split-paths)))
|
|
||||||
|
|
||||||
(defmethod aero/reader 'file
|
|
||||||
[{:keys [source]} tag value]
|
|
||||||
"Aero tag to reference a `java.io.File` relative to the config
|
|
||||||
file."
|
|
||||||
(-> (aero/relative-resolver source value)
|
|
||||||
fs/file))
|
|
||||||
|
|
||||||
(defn read-config [files & {:as opts}]
|
|
||||||
(let [r (->> files
|
|
||||||
(filter identity)
|
|
||||||
(map #(aero/read-config % opts))
|
|
||||||
(apply merge))
|
|
||||||
conformed (s/conform ::config r)]
|
|
||||||
(if-not (s/invalid? conformed)
|
|
||||||
conformed
|
|
||||||
(throw (ex-info "Failed to conform config"
|
|
||||||
(s/explain-data ::config r))))))
|
|
||||||
|
|
||||||
(def sources
|
|
||||||
[;; Default config.
|
|
||||||
(io/resource "net/deertopia/doerg/default-config.edn")
|
|
||||||
;; Defaults set at build time, if any.
|
|
||||||
(io/resource "net/deertopia/doerg/extra-config.edn")
|
|
||||||
;; Config set at runtime.
|
|
||||||
(System/getenv "DOERG_CONFIG")])
|
|
||||||
|
|
||||||
(def default (read-config sources))
|
|
||||||
|
|
||||||
(def ^:dynamic *cfg* default)
|
|
||||||
|
|
||||||
(defn load-config!
|
|
||||||
([& {:as opts :keys [files]
|
|
||||||
:or {files sources}}]
|
|
||||||
(let [passthru-opts (-> opts (dissoc :files))]
|
|
||||||
(alter-var-root
|
|
||||||
#'*cfg* (constantly (read-config files passthru-opts))))))
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
(ns net.deertopia.doerg.elisp
|
|
||||||
(:require [clojure.core.match :refer [match]]
|
|
||||||
[clojure.java.io :as io]
|
|
||||||
[clojure.spec.alpha :as s]
|
|
||||||
[instaparse.core :as ip])
|
|
||||||
(:refer-clojure :exclude [print read read-string]))
|
|
||||||
|
|
||||||
(ip/defparser read*
|
|
||||||
(io/resource "net/deertopia/doerg/elisp/grammar"))
|
|
||||||
|
|
||||||
(defn- transform-string [s]
|
|
||||||
(let [s* (loop [s (seq s)
|
|
||||||
acc ""]
|
|
||||||
(match s
|
|
||||||
([\\ c & cs] :seq)
|
|
||||||
(recur
|
|
||||||
cs
|
|
||||||
(str acc
|
|
||||||
(condp = c
|
|
||||||
\n \newline
|
|
||||||
\f \formfeed
|
|
||||||
\\ \\
|
|
||||||
\" \"
|
|
||||||
\newline nil
|
|
||||||
(throw (ex-info "IDK!" {:char c})))))
|
|
||||||
([c & cs] :seq) (recur cs (str acc c))
|
|
||||||
([] :seq) acc))]
|
|
||||||
[:string (apply str s*)]))
|
|
||||||
|
|
||||||
(defn- transform-integer [s]
|
|
||||||
[:integer (parse-long s)])
|
|
||||||
|
|
||||||
(defn- transform-property-string
|
|
||||||
([[_ text]]
|
|
||||||
[:string text])
|
|
||||||
([[_ text] & props]
|
|
||||||
[:string text (->> (for [[_ [_ beg] [_ end] prop] props]
|
|
||||||
{[beg end] prop})
|
|
||||||
(apply merge))]))
|
|
||||||
|
|
||||||
(defn- transform-list [& xs]
|
|
||||||
(match (last xs)
|
|
||||||
[:dot-cdr x] [:cons* (butlast xs) x]
|
|
||||||
_ [:cons* xs]))
|
|
||||||
|
|
||||||
(def transforms {:string transform-string
|
|
||||||
:list transform-list
|
|
||||||
:integer transform-integer
|
|
||||||
:property-string transform-property-string})
|
|
||||||
|
|
||||||
(defn read [s & args]
|
|
||||||
(->> (apply read* s args)
|
|
||||||
(ip/transform transforms)))
|
|
||||||
|
|
||||||
(defn read-string [s]
|
|
||||||
(read s :start :text))
|
|
||||||
|
|
||||||
(defn cons? [x]
|
|
||||||
(= (first x) :cons*))
|
|
||||||
|
|
||||||
(s/def ::alist
|
|
||||||
(s/tuple #{:list}
|
|
||||||
(s/and ::list
|
|
||||||
cons?)))
|
|
||||||
|
|
||||||
(defn car [x]
|
|
||||||
(match x
|
|
||||||
[:cons* xs y] (first xs)
|
|
||||||
[:cons* xs] (first xs)
|
|
||||||
[:symbol "nil"] nil
|
|
||||||
_ nil))
|
|
||||||
|
|
||||||
(defn cdr [x]
|
|
||||||
(match x
|
|
||||||
[:cons* xs y] (if (<= (count xs) 1)
|
|
||||||
y
|
|
||||||
[:cons* (rest xs) y])
|
|
||||||
[:cons* xs] [:cons* (rest xs)]
|
|
||||||
[:symbol "nil"] nil
|
|
||||||
_ nil))
|
|
||||||
|
|
||||||
(defn emacs-list? [x]
|
|
||||||
(match x
|
|
||||||
[:cons* xs] true
|
|
||||||
_ false))
|
|
||||||
|
|
||||||
(defn read-alist [s]
|
|
||||||
(let [r (->> s read*
|
|
||||||
(ip/transform
|
|
||||||
(merge transforms
|
|
||||||
{:symbol (fn [s] (symbol s))
|
|
||||||
:string (fn [s] s)}))
|
|
||||||
first)]
|
|
||||||
(match r
|
|
||||||
[:cons* pairs] (->> (for [pair pairs]
|
|
||||||
(let [x (car pair)
|
|
||||||
y (cdr pair)]
|
|
||||||
{x y}))
|
|
||||||
(apply merge))
|
|
||||||
_ nil)))
|
|
||||||
|
|
||||||
(defn read-string [s]
|
|
||||||
(match (-> s read first)
|
|
||||||
[:string x & props] x
|
|
||||||
:else nil))
|
|
||||||
|
|
||||||
(defn print [x]
|
|
||||||
;; TODO: this is really not how it should be done lol. at the
|
|
||||||
;; moment, `print` is only used in `net.deertopia.doerg.roam`
|
|
||||||
;; and only to serialise uuids, so it's not a /massive/ priority.
|
|
||||||
(cond (or (string? x) (uuid? x)) (str \" x \")
|
|
||||||
:else (throw (ex-info "`print` is unimplemented lol"
|
|
||||||
{:x x}))))
|
|
||||||
|
|
||||||
(comment
|
|
||||||
(do (ip/defparser parse* (io/resource "elisp-grammar"))
|
|
||||||
(read "#(\"blah\" 0 1 (doge))")
|
|
||||||
(read "\"bla\\nh\"")
|
|
||||||
(read-alist "((x . y))")))
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
(ns net.deertopia.doerg.main
|
|
||||||
(:require [net.deertopia.doerg.server :as server]
|
|
||||||
[net.deertopia.doerg.config :as cfg])
|
|
||||||
(:gen-class))
|
|
||||||
|
|
||||||
(defn -main [& _]
|
|
||||||
(binding [cfg/*cfg* (cfg/read-config cfg/sources)]
|
|
||||||
(server/start!)))
|
|
||||||
@@ -1,188 +0,0 @@
|
|||||||
(ns net.deertopia.doerg.roam
|
|
||||||
(:require [babashka.fs :as fs]
|
|
||||||
[net.deertopia.doerg.config :as cfg]
|
|
||||||
[net.deertopia.doerg.elisp :as elisp]
|
|
||||||
[net.deertopia.doerg.slug :as slug]
|
|
||||||
[next.jdbc :as sql])
|
|
||||||
(:import (java.util UUID)))
|
|
||||||
|
|
||||||
|
|
||||||
;;; Global database
|
|
||||||
|
|
||||||
(defonce ^:dynamic *use-db-cache?* true)
|
|
||||||
|
|
||||||
(defn ds []
|
|
||||||
(sql/get-datasource
|
|
||||||
{:dbtype "sqlite"
|
|
||||||
:dbname (-> cfg/*cfg* ::cfg/org-roam-db-path str)}))
|
|
||||||
|
|
||||||
|
|
||||||
;;; Elisp sexp (de)serialisation
|
|
||||||
|
|
||||||
(defn id [node]
|
|
||||||
(-> node :id))
|
|
||||||
|
|
||||||
(defn slug [node]
|
|
||||||
(-> node :id slug/from-uuid))
|
|
||||||
|
|
||||||
(defn- print-id [node]
|
|
||||||
(-> node id elisp/print))
|
|
||||||
|
|
||||||
|
|
||||||
;;; Node
|
|
||||||
|
|
||||||
(defrecord Node [id cache])
|
|
||||||
|
|
||||||
(defn uuid-exists? [uuid]
|
|
||||||
(sql/execute-one! (ds)
|
|
||||||
["select 1 from nodes where id = ? limit 1"
|
|
||||||
(-> uuid str elisp/print)]))
|
|
||||||
|
|
||||||
(defn make-node
|
|
||||||
([uuid] (make-node uuid {}))
|
|
||||||
([uuid props]
|
|
||||||
(and (uuid-exists? uuid)
|
|
||||||
(->Node uuid (atom props)))))
|
|
||||||
|
|
||||||
(defn- fetch-with-cache [node field fetch]
|
|
||||||
(if *use-db-cache?*
|
|
||||||
(-> (:cache node)
|
|
||||||
(swap! (fn [cache]
|
|
||||||
(update cache field #(or % (fetch node)))))
|
|
||||||
(get field))
|
|
||||||
(fetch node)))
|
|
||||||
|
|
||||||
(defn org-file [node]
|
|
||||||
(fetch-with-cache
|
|
||||||
node :org-file
|
|
||||||
(fn [node]
|
|
||||||
(when-some [r (sql/execute-one!
|
|
||||||
(ds)
|
|
||||||
["select file from nodes where id = ?"
|
|
||||||
(-> node :id str elisp/print)])]
|
|
||||||
(-> r :nodes/file elisp/read-string)))))
|
|
||||||
|
|
||||||
(defn title [node]
|
|
||||||
(fetch-with-cache
|
|
||||||
node :title
|
|
||||||
#(when-some [r (sql/execute-one!
|
|
||||||
(ds)
|
|
||||||
["select title from nodes where id = ?"
|
|
||||||
(print-id %)])]
|
|
||||||
(-> r :nodes/title elisp/read-string))))
|
|
||||||
|
|
||||||
(defprotocol GetNode
|
|
||||||
(get-node [this]
|
|
||||||
"Return the node associated with `this` or nil."))
|
|
||||||
|
|
||||||
(extend-protocol GetNode
|
|
||||||
String
|
|
||||||
(get-node [this]
|
|
||||||
(or (some-> this slug/from-string get-node)
|
|
||||||
(some-> this parse-uuid get-node)
|
|
||||||
(throw (IllegalArgumentException.
|
|
||||||
"Give `get-node` a UUID or slug string plz. }:)"))))
|
|
||||||
java.util.UUID
|
|
||||||
(get-node [this]
|
|
||||||
(make-node this))
|
|
||||||
net.deertopia.doerg.slug.Slug
|
|
||||||
(get-node [this]
|
|
||||||
(-> this slug/to-uuid make-node))
|
|
||||||
Node
|
|
||||||
(get-node [this]
|
|
||||||
this))
|
|
||||||
|
|
||||||
(comment
|
|
||||||
(def node (get-node "68XqhHerTWCbE--RYLEdHw"))
|
|
||||||
(fetch-with-cache
|
|
||||||
node :title
|
|
||||||
#(do (println "fetch")
|
|
||||||
(sql/execute-one! (ds) ["select title from nodes where id = ?"
|
|
||||||
(elisp/print (:id %))]))))
|
|
||||||
|
|
||||||
|
|
||||||
;;; Node operations
|
|
||||||
|
|
||||||
(defn level [node]
|
|
||||||
(fetch-with-cache
|
|
||||||
node :level
|
|
||||||
#(-> (sql/execute-one!
|
|
||||||
(ds) ["select level from nodes where id = ?"
|
|
||||||
(print-id %)])
|
|
||||||
:nodes/level)))
|
|
||||||
|
|
||||||
(defn top-level? [node]
|
|
||||||
(zero? (level node)))
|
|
||||||
|
|
||||||
(defn file [node]
|
|
||||||
(fetch-with-cache
|
|
||||||
node :file
|
|
||||||
#(-> (sql/execute-one!
|
|
||||||
(ds) ["select file from nodes where id = ?"
|
|
||||||
(print-id %)])
|
|
||||||
:nodes/file
|
|
||||||
elisp/read-string)))
|
|
||||||
|
|
||||||
(defn properties [node]
|
|
||||||
(fetch-with-cache
|
|
||||||
node :properties
|
|
||||||
#(-> (sql/execute-one!
|
|
||||||
(ds) ["select properties from nodes where id = ?"
|
|
||||||
(print-id %)])
|
|
||||||
:nodes/properties
|
|
||||||
elisp/read-alist)))
|
|
||||||
|
|
||||||
(defn public? [node]
|
|
||||||
(some-> (properties node) (get "DEERTOPIAVISIBILITY") (= "public")))
|
|
||||||
|
|
||||||
(defn get-public-node [node]
|
|
||||||
(when-let [n (get-node node)]
|
|
||||||
(when (public? n) n)))
|
|
||||||
|
|
||||||
(defn graph-visible? [node]
|
|
||||||
(#{"public" "graphonly"}
|
|
||||||
(some-> (properties node) (get "DEERTOPIAVISIBILITY"))))
|
|
||||||
|
|
||||||
(defn backlinks
|
|
||||||
"Returns a collection of nodes linking to `node`."
|
|
||||||
[node]
|
|
||||||
(for [{id :nodes/id title :nodes/title}
|
|
||||||
(sql/execute! (ds) ["select distinct nodes.id, nodes.title from links
|
|
||||||
inner join nodes
|
|
||||||
on nodes.id = links.source
|
|
||||||
where links.dest = ?"
|
|
||||||
(elisp/print (str (:id node)))])
|
|
||||||
:let [id' (elisp/read-string id)]
|
|
||||||
:when (some-> (-> id' parse-uuid get-node)
|
|
||||||
public?)]
|
|
||||||
(make-node id' {:title (elisp/read-string title)})))
|
|
||||||
|
|
||||||
|
|
||||||
;;; Graph support
|
|
||||||
|
|
||||||
(defn- read-string-field [n field]
|
|
||||||
(-> n (get field) elisp/read-string))
|
|
||||||
|
|
||||||
(defn- uuid-graph-visible? [uuid]
|
|
||||||
(-> uuid parse-uuid get-node graph-visible?))
|
|
||||||
|
|
||||||
(defn get-graph []
|
|
||||||
(let [nodes (sql/execute! (ds) ["select id, title from nodes"])
|
|
||||||
links (sql/execute!
|
|
||||||
(ds)
|
|
||||||
["select n1.id as source, nodes.id as target from
|
|
||||||
((nodes as n1) join links on n1.id = links.source)
|
|
||||||
join (nodes as n2) on links.dest = nodes.id
|
|
||||||
where links.type = '\"id\"'"])]
|
|
||||||
{:nodes (for [n nodes
|
|
||||||
:let [id (read-string-field n :nodes/id)]
|
|
||||||
:when (uuid-graph-visible? id)]
|
|
||||||
{:id id
|
|
||||||
:title (read-string-field n :nodes/title)})
|
|
||||||
:links (for [l links
|
|
||||||
:let [source (read-string-field l :nodes/source)
|
|
||||||
target (read-string-field l :nodes/target)]
|
|
||||||
:when (and (uuid-graph-visible? source)
|
|
||||||
(uuid-graph-visible? target))]
|
|
||||||
{:source source
|
|
||||||
:target target})}))
|
|
||||||
@@ -1,210 +0,0 @@
|
|||||||
(ns net.deertopia.doerg.server
|
|
||||||
(:require [clojure.pprint :refer [pprint]]
|
|
||||||
[clojure.tools.logging :as l]
|
|
||||||
[hiccup2.core :as hiccup]
|
|
||||||
[net.deertopia.doerg.html :as doerg-html]
|
|
||||||
[net.deertopia.doerg.config :as-alias cfg]
|
|
||||||
[net.deertopia.doerg.slug :as slug]
|
|
||||||
[net.deertopia.doerg.config :as cfg]
|
|
||||||
[net.deertopia.doerg.roam :as roam]
|
|
||||||
[org.httpkit.server :as http]
|
|
||||||
[reitit.coercion]
|
|
||||||
[reitit.coercion.spec]
|
|
||||||
[reitit.ring.coercion]
|
|
||||||
[reitit.core :as r]
|
|
||||||
[reitit.ring]
|
|
||||||
[reitit.ring.middleware.exception :as reitit-exception]
|
|
||||||
[ring.util.response :as response]
|
|
||||||
[spec-tools.spell]
|
|
||||||
[reitit.spec]
|
|
||||||
[reitit.dev.pretty]
|
|
||||||
[clojure.spec.alpha :as s]
|
|
||||||
[net.deertopia.doerg.render :as doerg-render]
|
|
||||||
[net.deertopia.doerg.cached-file :as cached-file]
|
|
||||||
[babashka.fs :as fs]
|
|
||||||
[aero.core :as aero]
|
|
||||||
[clojure.string :as str]))
|
|
||||||
|
|
||||||
|
|
||||||
;;; Routes
|
|
||||||
|
|
||||||
(def homepage-slug "68XqhHerTWCbE--RYLEdHw")
|
|
||||||
(def not-found-slug "PGDHTvUzQ62Js1Y5db-A8g")
|
|
||||||
|
|
||||||
(defn hello [req]
|
|
||||||
(-> (hiccup/html {}
|
|
||||||
[:html
|
|
||||||
[:head
|
|
||||||
[:title "hello"]
|
|
||||||
doerg-html/charset
|
|
||||||
doerg-html/viewport]
|
|
||||||
[:body
|
|
||||||
[:pre
|
|
||||||
(with-out-str
|
|
||||||
(pprint req))]]])
|
|
||||||
str
|
|
||||||
response/response
|
|
||||||
(response/content-type "text/html")))
|
|
||||||
|
|
||||||
(defn html-dir []
|
|
||||||
(-> cfg/*cfg* ::cfg/state-directory (fs/file "html")))
|
|
||||||
|
|
||||||
(declare node-by-slug)
|
|
||||||
|
|
||||||
;; This could infinitely loop if the 404 page can't be found. lmfao.
|
|
||||||
(defn not-found [_req]
|
|
||||||
(-> (node-by-slug {:path-params {:slug not-found-slug}})
|
|
||||||
(assoc :status 404))
|
|
||||||
#_(response/not-found "not found"))
|
|
||||||
|
|
||||||
(defn org-file->html-file [org-file]
|
|
||||||
(fs/file (html-dir)
|
|
||||||
(-> org-file
|
|
||||||
fs/file-name
|
|
||||||
(fs/strip-ext {:ext "org"})
|
|
||||||
(str ".html"))))
|
|
||||||
|
|
||||||
(defn slug-link [slug & contents]
|
|
||||||
[:a {:href (str "/n/" slug)}
|
|
||||||
contents])
|
|
||||||
|
|
||||||
(defmethod doerg-render/org-link "id"
|
|
||||||
[{:keys [path raw-link children]}]
|
|
||||||
[:span.org-link
|
|
||||||
(slug-link (slug/from-uuid path)
|
|
||||||
(or (seq children) raw-link))
|
|
||||||
#_[:a {:href (str "/n/" (slug/from-uuid path))}
|
|
||||||
(or (seq children) raw-link)]])
|
|
||||||
|
|
||||||
(def navbar
|
|
||||||
"Hiccup element for Deertopia.net's navbar."
|
|
||||||
[:nav.navbar
|
|
||||||
[:ol.navbar-list
|
|
||||||
[:li
|
|
||||||
[:a.home-link {:href "/"}
|
|
||||||
"🦌 deertopia.net"]]
|
|
||||||
#_[:li
|
|
||||||
[:a.home-link {:href "/graph"}
|
|
||||||
"graph"]]
|
|
||||||
#_
|
|
||||||
[:li
|
|
||||||
[:a.home-link {:onclick "alert('unimplemented }:(')"}
|
|
||||||
"search"]]]])
|
|
||||||
|
|
||||||
(defn backlinks-postamble [node]
|
|
||||||
(let [backlinks (roam/backlinks node)]
|
|
||||||
(when-not (empty? backlinks)
|
|
||||||
[:section#backlinks
|
|
||||||
[:h2 "Backlinks"]
|
|
||||||
[:ul
|
|
||||||
(for [n (->> backlinks
|
|
||||||
(sort-by (comp str/lower-case roam/title)))]
|
|
||||||
[:li (slug-link (roam/slug n)
|
|
||||||
(roam/title n))])]])))
|
|
||||||
|
|
||||||
(defn node-by-slug [{{:keys [slug]} :path-params :as req}]
|
|
||||||
(if-some [node (some-> slug slug/from-string roam/get-public-node)]
|
|
||||||
(let [org-file (roam/org-file node)
|
|
||||||
html-file (org-file->html-file org-file)]
|
|
||||||
(cached-file/cached-file
|
|
||||||
:file html-file
|
|
||||||
:stale? (cached-file/newer-than? org-file html-file)
|
|
||||||
:compute #(doerg-render/to-html
|
|
||||||
org-file
|
|
||||||
:postamble (backlinks-postamble node)
|
|
||||||
:header navbar
|
|
||||||
:title (roam/title node)))
|
|
||||||
(-> (str html-file)
|
|
||||||
response/file-response
|
|
||||||
(response/content-type "text/html")))
|
|
||||||
(not-found req)))
|
|
||||||
|
|
||||||
(defn node-by-id [req]
|
|
||||||
(hello req))
|
|
||||||
|
|
||||||
(def exception-middleware
|
|
||||||
(reitit-exception/create-exception-middleware
|
|
||||||
(merge
|
|
||||||
reitit-exception/default-handlers
|
|
||||||
{::reitit-exception/wrap
|
|
||||||
(fn [handler e request]
|
|
||||||
(l/error e "error in fucking somwhere dude")
|
|
||||||
(handler e request))})))
|
|
||||||
|
|
||||||
(defn handle-homepage [req]
|
|
||||||
(-> req
|
|
||||||
(assoc-in [:path-params :slug] homepage-slug)
|
|
||||||
node-by-slug))
|
|
||||||
|
|
||||||
(defn handle-resource [{:keys [uri]}]
|
|
||||||
(if-some [[_ resource] (re-matches #"^/resource/ibm-plex-web/(.*)" uri)]
|
|
||||||
(-> resource
|
|
||||||
(response/file-response
|
|
||||||
{:root (-> cfg/*cfg* ::cfg/ibm-plex-web str)}))
|
|
||||||
(-> uri
|
|
||||||
(str/replace-first #"^/resource/" "")
|
|
||||||
(response/resource-response
|
|
||||||
{:root "net/deertopia/doerg/public"
|
|
||||||
:allow-symlinks? true}))))
|
|
||||||
|
|
||||||
(defn handle-favicon [_]
|
|
||||||
(response/resource-response "net/deertopia/doerg/favicon.ico"))
|
|
||||||
|
|
||||||
(def router
|
|
||||||
(reitit.ring/router
|
|
||||||
#{["/" #'handle-homepage]
|
|
||||||
["/n/:slug" #'node-by-slug]
|
|
||||||
["/id/:id" #'node-by-id]
|
|
||||||
["/resource/*" #'handle-resource]
|
|
||||||
["/myreq" #'hello]
|
|
||||||
["/favicon.ico" #'handle-favicon]}
|
|
||||||
{:validate reitit.spec/validate
|
|
||||||
:exception reitit.dev.pretty/exception
|
|
||||||
:spec :reitit.spec/default-data
|
|
||||||
:data
|
|
||||||
{:coercion reitit.coercion.spec/coercion
|
|
||||||
:middleware [exception-middleware
|
|
||||||
reitit.ring.coercion/coerce-request-middleware
|
|
||||||
reitit.ring.coercion/coerce-response-middleware
|
|
||||||
#_reitit.ring.coercion/coerce-exceptions-middleware]}}))
|
|
||||||
|
|
||||||
|
|
||||||
;;; Server API
|
|
||||||
|
|
||||||
(def app (reitit.ring/ring-handler router))
|
|
||||||
|
|
||||||
(defonce server (atom nil))
|
|
||||||
|
|
||||||
(defn stop! []
|
|
||||||
(when @server
|
|
||||||
(http/server-stop! @server {:timeout 100})
|
|
||||||
(reset! server nil)
|
|
||||||
(l/info "Stopped server")))
|
|
||||||
|
|
||||||
;; For some reason, the log messages from `stop!` are not flushed
|
|
||||||
;; before the JVM shuts dowm. Nevertheless, the server /does/ come to
|
|
||||||
;; a graceful halt.
|
|
||||||
(def ^:private shutdown-hook (Thread. stop!))
|
|
||||||
|
|
||||||
(defn start! []
|
|
||||||
(if @server
|
|
||||||
(throw (IllegalStateException. "Server already started"))
|
|
||||||
(do (reset! server
|
|
||||||
(http/run-server (bound-fn* #'app)
|
|
||||||
{:port (-> cfg/*cfg* ::cfg/port)
|
|
||||||
:legacy-return-value? false}))
|
|
||||||
;; For some reason, the log messages are not flushed before
|
|
||||||
;; the JVM shuts dowm. Nevertheless, the server /does/ come
|
|
||||||
;; to a graceful halt.
|
|
||||||
(try (.addShutdownHook (Runtime/getRuntime) shutdown-hook)
|
|
||||||
(catch IllegalArgumentException e
|
|
||||||
(when (not= "Hook previously registered"
|
|
||||||
(ex-message e))
|
|
||||||
(throw e))))
|
|
||||||
(l/infof "Server started on port %d"
|
|
||||||
(-> cfg/*cfg* ::cfg/port)))))
|
|
||||||
|
|
||||||
(defn status []
|
|
||||||
(if @server
|
|
||||||
(http/server-status @server)
|
|
||||||
:stopped))
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
{ emacsPackages
|
|
||||||
, symlinkJoin
|
|
||||||
, writeScriptBin
|
|
||||||
, lib
|
|
||||||
}:
|
|
||||||
|
|
||||||
let emacs = emacsPackages.emacsWithPackages (epkgs: [ epkgs.org-roam ]);
|
|
||||||
in writeScriptBin "test-emacs" ''
|
|
||||||
exec ${lib.getExe emacs} "$@"
|
|
||||||
''
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
(ns net.deertopia.doerg.config-test
|
|
||||||
(:require [clojure.test :as t]
|
|
||||||
[net.deertopia.doerg.config :as cfg]))
|
|
||||||
|
|
||||||
(defn test-config-fixture
|
|
||||||
"`clojure.test` fixture to run tests with the :test configuration."
|
|
||||||
[f]
|
|
||||||
(binding [cfg/*cfg* (cfg/read-config cfg/sources :profile :test)]
|
|
||||||
(f)))
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#!/usr/bin/env -S emacs -Q -x
|
|
||||||
|
|
||||||
(require 'org-roam)
|
|
||||||
|
|
||||||
(setq org-roam-directory (expand-file-name (car command-line-args-left)))
|
|
||||||
(setq org-roam-db-location (expand-file-name (cadr command-line-args-left)))
|
|
||||||
|
|
||||||
(org-roam-db-sync)
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
:PROPERTIES:
|
|
||||||
:ID: 23ee464d-b13e-4649-826f-622d0edef24e
|
|
||||||
:DeertopiaVisibility: public
|
|
||||||
:END:
|
|
||||||
#+title: awesome file
|
|
||||||
|
|
||||||
wow!
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
:PROPERTIES:
|
|
||||||
:ID: 3c60c74e-f533-43ad-89b3-563975bf80f2
|
|
||||||
:DeertopiaVisibility: public
|
|
||||||
:END:
|
|
||||||
#+title: page not found
|
|
||||||
|
|
||||||
the page you're looking for doesn't exist, or you lack the permissions necessary to view it........
|
|
||||||
|
|
||||||
#+attr_doerg: :center? true :alt "A doe sitting and sobbing" :scale 1.4
|
|
||||||
#+begin_example
|
|
||||||
\{ / \ }/
|
|
||||||
\/ . . \/
|
|
||||||
.. \Y` `Y/ ..
|
|
||||||
\ `\|~==~|/' /
|
|
||||||
'". T T ."`
|
|
||||||
{`^' }
|
|
||||||
| |
|
|
||||||
/</3 \
|
|
||||||
|| ||
|
|
||||||
_| || |_
|
|
||||||
.,_) ) || ( (_,.
|
|
||||||
|__ /_||_\ __|
|
|
||||||
#+end_example
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
:PROPERTIES:
|
|
||||||
:ID: 90f23e03-f746-42cb-862f-1af2d4bde3cc
|
|
||||||
:DeertopiaVisibility: public
|
|
||||||
:END:
|
|
||||||
#+title: Category theory
|
|
||||||
|
|
||||||
*Category theory* is the mathematical study of categories and functors between them.
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
:PROPERTIES:
|
|
||||||
:ID: ebc5ea84-77ab-4d60-9b13-ef9160b11d1f
|
|
||||||
:DeertopiaVisibility: public
|
|
||||||
:END:
|
|
||||||
#+title: deertopia.net!!!!!!!!
|
|
||||||
|
|
||||||
homeee
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
:PROPERTIES:
|
|
||||||
:ID: 897bfc9d-94ce-4c58-8d21-93f13372b17b
|
|
||||||
:END:
|
|
||||||
#+title: Monomorphisms and epimorphisms
|
|
||||||
|
|
||||||
In [[id:90f23e03-f746-42cb-862f-1af2d4bde3cc][category theory]], *monomorphisms* and *epimorphisms* are types of cancellative morphisms generalising injective and surjective functions, respectively.[fn:1]
|
|
||||||
|
|
||||||
\begin{tikzcd}
|
|
||||||
% https://q.uiver.app/#q=WzAsNixbMCwwLCJYIl0sWzEsMCwiWSJdLFsyLDAsIloiXSxbMSwxLCJZIl0sWzIsMSwiWiJdLFswLDEsIlgiXSxbMCwxLCJnXzEiLDAseyJvZmZzZXQiOi0yfV0sWzAsMSwiZ18yIiwyLHsib2Zmc2V0IjoyfV0sWzEsMiwiZiIsMl0sWzMsNCwiZ18xIiwwLHsib2Zmc2V0IjotMn1dLFszLDQsImdfMiIsMix7Im9mZnNldCI6Mn1dLFs1LDMsImYiLDJdXQ==
|
|
||||||
X & Y & Z \\
|
|
||||||
X & Y & Z
|
|
||||||
\arrow["{g_1}", shift left=2, from=1-1, to=1-2]
|
|
||||||
\arrow["{g_2}"', shift right=2, from=1-1, to=1-2]
|
|
||||||
\arrow["f"', from=1-2, to=1-3]
|
|
||||||
\arrow["f"', from=2-1, to=2-2]
|
|
||||||
\arrow["{g_1}", shift left=2, from=2-2, to=2-3]
|
|
||||||
\arrow["{g_2}"', shift right=2, from=2-2, to=2-3]
|
|
||||||
\end{tikzcd}
|
|
||||||
|
|
||||||
* Footnotes
|
|
||||||
|
|
||||||
[fn:1] blahahahahah blah blah
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
(ns net.deertopia.doerg.roam-test
|
|
||||||
(:require [net.deertopia.doerg.roam :as sut]
|
|
||||||
[clojure.test :as t]
|
|
||||||
[clojure.java.io :as io]
|
|
||||||
[net.deertopia.doerg.config :as cfg]
|
|
||||||
[babashka.fs :as fs]
|
|
||||||
[babashka.process :as p]
|
|
||||||
[net.deertopia.doerg.config-test :refer [test-config-fixture]]
|
|
||||||
[next.jdbc :as sql]
|
|
||||||
[clojure.string :as str]
|
|
||||||
[net.deertopia.doerg.elisp :as elisp]
|
|
||||||
[com.rpl.specter :as sp]))
|
|
||||||
|
|
||||||
(def org-roam-directory
|
|
||||||
(fs/file "test/net/deertopia/doerg/roam-test"))
|
|
||||||
|
|
||||||
(defn org-roam-db-sync [db-file]
|
|
||||||
(let [script-file (fs/create-temp-file {:prefix "org-roam-db-sync-"
|
|
||||||
:suffix ".el"})
|
|
||||||
emacs (->> [(System/getenv "EMACS") "test-emacs" "emacs"]
|
|
||||||
(some #(some-> % fs/which)))]
|
|
||||||
(io/copy (-> "net/deertopia/doerg/org-roam-db-sync.el"
|
|
||||||
io/resource io/reader)
|
|
||||||
(fs/file script-file))
|
|
||||||
(p/shell {:out :string :err :string}
|
|
||||||
emacs "-Q" "-x" script-file org-roam-directory db-file)
|
|
||||||
(fs/delete script-file)))
|
|
||||||
|
|
||||||
(defn test-db-fixture [f]
|
|
||||||
(let [db-file (-> cfg/*cfg* ::cfg/org-roam-db-path)]
|
|
||||||
(assert (->> db-file fs/canonicalize str
|
|
||||||
(re-matches #"^/(build|tmp)/.*"))
|
|
||||||
(format "i'm scared to delete a non-test database... %s"
|
|
||||||
(str db-file)))
|
|
||||||
(fs/delete-if-exists db-file)
|
|
||||||
(org-roam-db-sync db-file)
|
|
||||||
(f)
|
|
||||||
(fs/delete db-file)))
|
|
||||||
|
|
||||||
(t/use-fixtures
|
|
||||||
:once (t/join-fixtures [test-config-fixture test-db-fixture]))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(t/deftest all-nodes-exist
|
|
||||||
(let [known-node-files (->> (fs/list-dir org-roam-directory)
|
|
||||||
(map (comp str fs/canonicalize))
|
|
||||||
(into #{}))
|
|
||||||
database-nodes
|
|
||||||
(->> (sql/execute!
|
|
||||||
(sut/ds) ["select file, id from nodes"])
|
|
||||||
(map (fn [x]
|
|
||||||
{:file (-> x :nodes/file elisp/read-string)
|
|
||||||
:id (-> x :nodes/id elisp/read-string parse-uuid)}))
|
|
||||||
(into #{}))]
|
|
||||||
(t/testing "database has a node for each file?"
|
|
||||||
(t/is (= known-node-files (sp/transform
|
|
||||||
[sp/ALL]
|
|
||||||
#(:file %)
|
|
||||||
database-nodes))))
|
|
||||||
(t/testing "each uuid exists?"
|
|
||||||
(t/is (every? (comp sut/uuid-exists? :id)
|
|
||||||
database-nodes)))))
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
(ns net.deertopia.doerg.server-test
|
|
||||||
(:require [net.deertopia.doerg.server :as sut]
|
|
||||||
[reitit.ring]
|
|
||||||
[clojure.test :as t]
|
|
||||||
[net.deertopia.doerg.config :as cfg]
|
|
||||||
[net.deertopia.doerg.roam :as roam]
|
|
||||||
[babashka.fs :as fs]
|
|
||||||
[clojure.java.io :as io]
|
|
||||||
[net.deertopia.doerg.roam-test :refer [test-db-fixture]]
|
|
||||||
[net.deertopia.doerg.config-test :refer [test-config-fixture]]))
|
|
||||||
|
|
||||||
(t/use-fixtures
|
|
||||||
:once (t/join-fixtures [test-config-fixture test-db-fixture]))
|
|
||||||
|
|
||||||
(defn with-server [f]
|
|
||||||
(let [was-already-running? (= :running (sut/status))]
|
|
||||||
(when-not was-already-running?
|
|
||||||
(sut/start!))
|
|
||||||
(f)
|
|
||||||
(when-not was-already-running?
|
|
||||||
(sut/stop!))))
|
|
||||||
|
|
||||||
(defn get-sut [uri]
|
|
||||||
(sut/app {:request-method :get
|
|
||||||
:uri uri}))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(t/deftest server-is-running
|
|
||||||
;; 서버는 벌써 시작한 다음에 이 테스트 하면 잘못됩니다.
|
|
||||||
;; (assert (not= :running (sut/status)))
|
|
||||||
(with-server
|
|
||||||
(fn []
|
|
||||||
(t/is (= :running (sut/status)))
|
|
||||||
(t/is (->> (format "http://localhost:%d"
|
|
||||||
(::cfg/port cfg/*cfg*))
|
|
||||||
slurp
|
|
||||||
string?)))))
|
|
||||||
|
|
||||||
(t/deftest get-nonexistent-node
|
|
||||||
(let [slug "3Lxvxnb0QrivoU3DX-l_5w"]
|
|
||||||
(assert (nil? (roam/make-node slug)))
|
|
||||||
(t/is (= 404
|
|
||||||
(-> (str "/n/" slug)
|
|
||||||
get-sut :status)))))
|
|
||||||
|
|
||||||
(t/deftest get-homepage
|
|
||||||
(let [resp (-> (str "/n/" sut/homepage-slug)
|
|
||||||
get-sut)]
|
|
||||||
(t/is (= 200 (:status resp)))
|
|
||||||
(t/is (= (-> "/" get-sut :body)
|
|
||||||
(-> resp :body)))))
|
|
||||||
Vendored
+8
@@ -0,0 +1,8 @@
|
|||||||
|
{ fetchzip
|
||||||
|
, fetchurl
|
||||||
|
, callPackage
|
||||||
|
}:
|
||||||
|
|
||||||
|
{
|
||||||
|
ibm-plex-web = callPackage ./ibm-plex-web.nix {};
|
||||||
|
}
|
||||||
File renamed without changes.
Reference in new issue
Block a user