diff --git a/default.nix b/default.nix index e851016..d7f00d0 100644 --- a/default.nix +++ b/default.nix @@ -33,8 +33,8 @@ let ]; doerg-config = writeText "doerg-extra-config.edn" '' - #:net.deertopia.doerg - {:ibm-plex-web "${ibm-plex-web}" + #: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}" @@ -43,15 +43,21 @@ let in mkCljBin' { name = "net.deertopia/doerg"; version = "0.1.0"; - projectSrc = lib.cleanSource ./.; + projectSrc = lib.cleanSourceWith { + filter = path: type: + lib.sources.cleanSourceFilter path type + || lib.hasSuffix ".nix" path; + src = ./.; + }; lockfile = ./deps-lock.json; main-ns = "net.deertopia.doerg.main"; nativeBuildInputs = [ plex makeWrapper ]; - buildInputs = [ + propagatedBuildInputs = [ doerg-parser + ibm-plex-web doerg-temml-worker plex our-tex @@ -73,5 +79,6 @@ in mkCljBin' { XDG_STATE_HOME=$(mktemp -d "state-home-XXXXXX") clojure -M:test ''; - passthru = { inherit plex our-tex test-emacs; }; + passthru = { inherit plex our-tex test-emacs doerg-config; }; + meta.mainProgram = "doerg"; } diff --git a/flake.nix b/flake.nix index 2df7f00..4d5a790 100644 --- a/flake.nix +++ b/flake.nix @@ -14,12 +14,15 @@ "x86_64-linux" ]; + overlays = [ + inputs.sydpkgs.overlays.default + clj-nix.overlays.default + ]; + each-system = f: nixpkgs.lib.genAttrs supportedSystems (system: f rec { pkgs = import nixpkgs { inherit system; - overlays = [ - inputs.sydpkgs.overlays.default - clj-nix.overlays.default + overlays = overlays ++ [ self.overlays.default ]; }; @@ -36,13 +39,17 @@ }); overlays.default = final: prev: - let graal = x: final.mkGraalBin { cljDrv = x; }; + let + # is this really the correct way to satisfy our + # dependencies? lmfao + final' = final.appendOverlays overlays; + graal = x: final'.mkGraalBin { cljDrv = x; }; in { - ibm-plex-web = final.callPackage ./ibm-plex-web.nix {}; - doerg = final.callPackage ./. {}; - doerg-parser = final.callPackage ./doerg-parser {}; - doerg-temml-worker = final.callPackage ./doerg-temml-worker {}; - our-tex = final.callPackage ./our-tex.nix {}; + ibm-plex-web = final'.callPackage ./ibm-plex-web.nix {}; + doerg = final'.callPackage ./. {}; + 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, ... }: { @@ -52,6 +59,8 @@ (pkgs.lib.attrValues self.packages.${system}); }); + nixosModules.default = import ./module.nix { inherit self; }; + devShells = each-system ({ pkgs, system, ... }: { default = pkgs.mkShell { inputsFrom = [ diff --git a/module.nix b/module.nix new file mode 100644 index 0000000..795c6be --- /dev/null +++ b/module.nix @@ -0,0 +1,107 @@ +{ 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" + ]; + }; + }; + }; +} diff --git a/resources/net/deertopia/doerg/default-config.edn b/resources/net/deertopia/doerg/default-config.edn index 782ac3b..4d7fad1 100644 --- a/resources/net/deertopia/doerg/default-config.edn +++ b/resources/net/deertopia/doerg/default-config.edn @@ -1,9 +1,8 @@ #:net.deertopia.doerg.config -{:ibm-plex-web #or [#xdg-data-dir "ibm-plex-web" - #env IBM_PLEX_WEB] +{:ibm-plex-web #or [#env IBM_PLEX_WEB + #xdg-data-dir "ibm-plex-web"] :latex "xelatex" :dvisvgm "dvisvgm" - :debug-unimplemented? #profile {:dev true :default false} :doerg-temml-worker #profile {:dev #file "../../../../doerg-temml-worker/index.js" :default "doerg-temml-worker"} diff --git a/src/net/deertopia/doerg/cached_file.clj b/src/net/deertopia/doerg/cached_file.clj index 8dbf9f3..9db42b0 100644 --- a/src/net/deertopia/doerg/cached_file.clj +++ b/src/net/deertopia/doerg/cached_file.clj @@ -18,8 +18,10 @@ calling `compute` with no arguments only if stale? is logical true." [& {:keys [file stale? compute]}] (when (or (not *use-cache?*) stale?) - (let [r (compute)] + (let [r (compute) + dir (fs/parent file)] (assert (string? r)) - (fs/create-dirs (fs/parent file)) + (when-not (fs/exists? dir) + (fs/create-dirs dir)) (spit file r))) file) diff --git a/src/net/deertopia/doerg/config.clj b/src/net/deertopia/doerg/config.clj index 54b9c8e..a17d7e9 100644 --- a/src/net/deertopia/doerg/config.clj +++ b/src/net/deertopia/doerg/config.clj @@ -46,7 +46,8 @@ "Aero tag to search for a directory on $XDG_DATA_DIRS." (some #(let [x (fs/path % value)] (and (fs/exists? x) x)) - (fs/split-paths (System/getenv "XDG_DATA_DIRS")))) + (some-> (System/getenv "XDG_DATA_DIRS") + fs/split-paths))) (defmethod aero/reader 'file [{:keys [source]} tag value] diff --git a/src/net/deertopia/doerg/roam.clj b/src/net/deertopia/doerg/roam.clj index f34c5eb..5290404 100644 --- a/src/net/deertopia/doerg/roam.clj +++ b/src/net/deertopia/doerg/roam.clj @@ -135,6 +135,10 @@ (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")))) diff --git a/src/net/deertopia/doerg/server.clj b/src/net/deertopia/doerg/server.clj index e88fd83..98a4787 100644 --- a/src/net/deertopia/doerg/server.clj +++ b/src/net/deertopia/doerg/server.clj @@ -23,9 +23,7 @@ [net.deertopia.doerg.cached-file :as cached-file] [babashka.fs :as fs] [aero.core :as aero] - [clojure.string :as str] - [net.deertopia.doerg :as-alias doerg] - [net.deertopia.doerg.config :as doerg-config])) + [clojure.string :as str])) ;;; Routes @@ -105,7 +103,7 @@ (roam/title n))])]]))) (defn node-by-slug [{{:keys [slug]} :path-params :as req}] - (if-some [node (some-> slug slug/from-string roam/get-node)] + (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 @@ -142,7 +140,7 @@ (if-some [[_ resource] (re-matches #"^/resource/ibm-plex-web/(.*)" uri)] (-> resource (response/file-response - {:root (-> doerg-config/*cfg* ::cfg/ibm-plex-web str)})) + {:root (-> cfg/*cfg* ::cfg/ibm-plex-web str)})) (-> uri (str/replace-first #"^/resource/" "") (response/resource-response