commit 8e20ab7bd726175354ef5cff078e937d792daa41 Author: Kyle Isom Date: Fri Apr 11 23:52:41 2025 -0700 Hacks and glory await. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..931c810 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.fasl +/docs/build/ diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..321e40a --- /dev/null +++ b/README.txt @@ -0,0 +1,2 @@ +;;;; metacircular-codex is the top-level build for my documentation +;;;; site. diff --git a/docs/manifest.lisp b/docs/manifest.lisp new file mode 100644 index 0000000..036f386 --- /dev/null +++ b/docs/manifest.lisp @@ -0,0 +1,7 @@ +(:docstring-markup-format :scriba + :systems (:mcodex) + :documents ((:title "mcodex" + :authors ("K. Isom") + :output-format (:type :multi-html + :template :minima) + :sources ("manual.scr")))) diff --git a/docs/manual.scr b/docs/manual.scr new file mode 100644 index 0000000..42ddd1f --- /dev/null +++ b/docs/manual.scr @@ -0,0 +1,27 @@ +@begin(section) +@title(Index) + +This is the top-level for my various lisp projects. + +@begin(list) +@item(@link[uri="/kutils/"](kutils) - my personal utility library.) +@end(list) + +@end(section) + +@begin(section) +@title(mcodex tools) + +mcodex also defines some tooling for building and maintaining codex +documentation. + +@cl:with-package[name="mcodex"]( +@cl:doc(function rsync) +@cl:doc(function build-site) +@cl:doc(function deploy-site) +@cl:doc(function publish-site) +@cl:doc(function mcodex-path) +@cl:doc(function build-and-publish) +) + +@end(section) \ No newline at end of file diff --git a/mcodex.asd b/mcodex.asd new file mode 100644 index 0000000..13e8455 --- /dev/null +++ b/mcodex.asd @@ -0,0 +1,10 @@ +;;;; metacircular-codex is the top-level build for my documentation +;;;; site. + +(asdf:defsystem #:mcodex + :description "top-level documentation index for my projects." + :author "K. Isom " + :license "MIT license" + :depends-on (#:codex) + :components ((:file "package") + (:file "mcodex"))) diff --git a/mcodex.lisp b/mcodex.lisp new file mode 100644 index 0000000..f39fc87 --- /dev/null +++ b/mcodex.lisp @@ -0,0 +1,226 @@ +;;;; mcodex.lisp + +(defpackage :mcodex + (:use :cl :uiop :codex) + (:export #:rsync + #:build-site + #:deploy-site + #:publish-site + #:mcodex-path + #:build-and-publish)) + +(in-package :mcodex) + +(defparameter *doc-path* "docs/build/mcodex/html/" + "Default local directory for Codex-generated documentation.") +(defparameter *top-level* "/srv/www/codex/" + "Default remote base directory for deployed documentation.") +(defparameter *ssh-host* (format nil "web.metacircular.net:~A" *top-level*) + "Default remote host and path for rsync deployment.") + +(defun rsync (path site) + "Synchronize a local PATH directory to a remote SITE using rsync. + +Parameters: + PATH (string): The local directory to synchronize, typically containing generated + documentation (e.g., `*doc-path*` = \"docs/build/mcodex/html/\"). + SITE (string): The remote destination in rsync-compatible format, including the host + and path (e.g., `*ssh-host*` = \"web.metacircular.net:/srv/www/codex/\"). + +Returns: + `nil` on successful synchronization (rsync exit code 0), or `nil` if an error occurs, + with error details printed to `*error-output*`. + +Description: + Executes `rsync` with options `--progress` (show transfer progress), `-a` (archive mode), + `-u` (update, skip newer files on receiver), `-v` (verbose), and `-z` (compress data) + to transfer files from PATH to SITE. Uses `uiop:run-program` to run the command, directing + output and errors to standard streams. Errors (e.g., network issues, invalid paths) are + caught and logged, making this function suitable for use in deployment workflows like + `deploy-site` and `publish-site`. + +Example: + (rsync *doc-path* *ssh-host*) + ; Syncs docs/build/mcodex/html/ to web.metacircular.net:/srv/www/codex/. + (rsync \"my/docs/\" \"otherserver:/var/www\") + ; Syncs a custom directory to a different server. + +Notes: + - Requires `rsync` to be installed and in the system’s PATH. + - Assumes SSH access to the remote host (e.g., key-based authentication). + - Does not validate PATH or SITE; ensure PATH exists and SITE is accessible. + - Verbose output (`--progress`, `-v`) aids monitoring but may clutter logs." + (handler-case + (uiop:run-program + `("rsync" "--progress" "-auvz" ,path ,site) + :output t + :error-output t) + (error (e) + (format *error-output* "Error during rsync: ~A~%" e) + nil))) + +(defun build-site (&optional (package (package-name *package*))) + "Generate documentation for a specified PACKAGE using the Codex documentation system. + +Parameters: + PACKAGE (string or symbol, optional): The name of the package or system to document. + Defaults to the name of the current package (via `package-name` and `*package*`). + Converted to a keyword (e.g., \"mcodex\" or 'mcodex becomes :mcodex). + +Returns: + The result of `codex:document`, typically a truthy value (e.g., `t`) on success, or + `nil` on failure, depending on Codex’s implementation. + +Description: + Invokes `codex:document` with a keyword derived from PACKAGE to generate documentation + (e.g., HTML files) for the specified system. Used in workflows like `publish-site` to + prepare files for deployment. Clients can override the default package to document + alternative systems. + +Example: + (build-site) ; Generates documentation for :mcodex. + (build-site \"test\") ; Generates documentation for :test. + +Notes: + - Assumes the `codex` package is loaded and configured. + - Output directory is set by Codex (typically `*doc-path*` = \"docs/build/mcodex/html/\"). + - Errors from `codex:document` are not caught; wrap with `handler-case` if needed." + (codex:document (intern (string package) :keyword))) + +(defun deploy-site (&optional (source *doc-path*) (destination *ssh-host*)) + "Deploy a local SOURCE directory to a remote DESTINATION using rsync. + +Parameters: + SOURCE (string, optional): The local directory to synchronize, typically where Codex + outputs documentation. Defaults to `*doc-path*` (\"docs/build/mcodex/html/\"). + DESTINATION (string, optional): The remote rsync destination (host:path format). + Defaults to `*ssh-host*` (\"web.metacircular.net:/srv/www/codex/\"). + +Returns: + `nil` on successful deployment (rsync exit code 0), or `nil` if an error occurs, + with error details printed to `*error-output*`. + +Description: + Calls `rsync` to transfer files from SOURCE to DESTINATION, providing a convenient + wrapper for deployment tasks. Suitable for standalone use or as part of `publish-site`. + Clients can override defaults to deploy to custom locations. + +Example: + (deploy-site) ; Deploys *doc-path* to *ssh-host*. + (deploy-site \"my/docs/\" \"otherserver:/var/www\") ; Custom source and destination. + +Notes: + - Inherits `rsync`’s requirements: rsync installed, SSH configured. + - Does not validate SOURCE or DESTINATION; ensure they are valid. + - Verbose rsync output is enabled for monitoring." + (rsync source destination)) + +(defun mcodex-path (&optional (package (package-name *package*))) + "Generate a remote path for storing a site’s files under *top-level*, based on PACKAGE. + +Parameters: + PACKAGE (string or symbol, optional): The package or system name used to determine + the path. Defaults to the current package’s name (via `package-name` and `*package*`). + +Returns: + A string representing the remote path: + - If PACKAGE is \"mcodex\" (case-insensitive), returns `*top-level*` (\"/srv/www/codex/\"). + - Otherwise, returns \"*top-level*//\", with in lowercase. + +Description: + Constructs a path for rsync destinations (e.g., in `build-and-publish`). Ensures the + `mcodex` package uses the root directory `*top-level*`, while other packages use a + subdirectory. Validates PACKAGE to prevent empty names, ensuring well-formed paths. + Clients can use this to customize deployment paths for different systems. + +Example: + (mcodex-path) ; Returns \"/srv/www/codex/\" in mcodex package. + (mcodex-path \"test\") ; Returns \"/srv/www/codex/test/\". + (mcodex-path 'my-proj) ; Returns \"/srv/www/codex/my-proj/\". + +Notes: + - Paths exclude the host prefix; combine with a host (e.g., \"web.metacircular.net:\"). + - Package names are lowercased for consistent URLs. + - Does not verify remote path existence; rsync creates directories as needed. + - Signals an error for invalid (empty) package names." + (let ((pkg-str (string-downcase (string package)))) + (unless (plusp (length pkg-str)) + (error "Package name must not be empty")) + (if (string-equal pkg-str "mcodex") + *top-level* + (format nil "~A~A/" *top-level* pkg-str)))) + +(defun publish-site (&key (path *doc-path*) + (site (format nil "web.metacircular.net:~A" (mcodex-path))) + (package (package-name *package*))) + "Build and publish a site by generating documentation and deploying it to a remote server. + +Parameters: + PATH (string, optional): The local directory containing documentation to synchronize. + Defaults to `*doc-path*` (\"docs/build/mcodex/html/\"). + SITE (string, optional): The remote rsync destination (host:path format). Defaults to + \"web.metacircular.net:\" combined with `(mcodex-path)`, yielding package-specific paths + (e.g., \"web.metacircular.net:/srv/www/codex/\" for mcodex). + PACKAGE (string or symbol, optional): The package or system to document. Defaults to + the current package’s name (via `package-name` and `*package*`). + +Returns: + `nil` if the build and deployment succeed, or `nil` if either fails, with errors printed + to `*error-output*`. + +Description: + Orchestrates site publishing by: + 1. Calling `build-site` with PACKAGE to generate documentation. + 2. If successful (non-nil result), calling `rsync` with PATH and SITE to deploy. + Prints progress messages to standard output and errors to `*error-output*`. Ensures + deployment only proceeds after a successful build, preventing partial uploads. Clients + can override parameters to customize the build and deployment process. + +Example: + (publish-site) ; Builds and deploys with defaults. + (publish-site :package \"test\") ; Builds for :test, deploys to .../codex/test/. + (publish-site :path \"my/docs/\" :site \"otherserver:/var/www\") ; Custom path and site. + +Notes: + - Assumes `build-site` and `rsync` are available. + - Relies on `build-site` returning a truthy value on success. + - Does not validate inputs; ensure PATH exists and SITE is accessible. + - Requires SSH configuration for rsync." + (format t "Building site for package ~A...~%" package) + (let ((build-result (build-site package))) + (if build-result + (progn + (format *error-output* "build-result: ~a~%" build-result) + (format *error-output* "Build failed, skipping rsync.~%") + nil) + (progn + (format t "Deploying site from ~A to ~A...~%" path site) + (rsync path site))))) + +(defun build-and-publish (&optional (package (package-name *package*))) + "Build and publish a site for PACKAGE with a package-specific remote path. + +Parameters: + PACKAGE (string or symbol, optional): The package or system to document and deploy. + Defaults to the current package’s name (via `package-name` and `*package*`). + +Returns: + `nil` if the build and deployment succeed, or `nil` if either fails, with errors printed + to `*error-output*`. + +Description: + A high-level wrapper around `publish-site` that uses `mcodex-path` to determine the + remote deployment path based on PACKAGE. Calls `publish-site` with default `*doc-path*` + and a SITE constructed from \"web.metacircular.net:\" and `(mcodex-path package)`. + Simplifies deployment for clients who want package-specific paths (e.g., /srv/www/codex/test/ + for :test) without specifying paths manually. + +Example: + (build-and-publish) ; Builds and deploys to .../codex/ for mcodex. + (build-and-publish \"test\") ; Builds and deploys to .../codex/test/. + +Notes: + - Assumes `publish-site` and `mcodex-path` are available. + - Inherits `publish-site`’s requirements (Codex, rsync, SSH). + - Does not validate `*doc-path*` or remote accessibility." + (publish-site :package package)) diff --git a/package.lisp b/package.lisp new file mode 100644 index 0000000..24ad060 --- /dev/null +++ b/package.lisp @@ -0,0 +1,45 @@ +;;;; package.lisp + +(defpackage #:mcodex + (:use #:cl) + (:export #:rsync + #:build-site + #:deploy-site + #:publish-site + #:mcodex-path + #:build-and-publish) + (:documentation + "The MCODEX package provides tools for building and deploying documentation using + the Codex documentation system and rsync for file synchronization. + + Overview: + This package facilitates generating documentation for Lisp systems (via `build-site`) + and deploying it to a remote server (via `rsync`, `deploy-site`, `publish-site`, or + `build-and-publish`). It supports package-specific deployment paths (via `mcodex-path`) + and allows clients to customize paths, hosts, and packages through function arguments. + The default configuration targets a remote server at web.metacircular.net, with + documentation stored under /srv/www/codex/. + + Key Functions: + - `build-site`: Generates documentation for a specified package using Codex. + - `rsync`: Synchronizes a local directory to a remote destination. + - `deploy-site`: Deploys a directory to a remote server, wrapping `rsync`. + - `publish-site`: Builds documentation and deploys it in one step. + - `mcodex-path`: Constructs package-specific remote paths (e.g., /srv/www/codex/test/). + - `build-and-publish`: High-level function to build and deploy with package-specific paths. + + Usage Example: + (ql:quickload :mcodex) + (mcodex:build-and-publish) ; Build and deploy for current package + (mcodex:publish-site :package \"test\" :path \"my/docs/\") ; Custom build and deploy + + Dependencies: + - Common Lisp (CL) + - UIOP (for running rsync) + - Codex (for generating documentation) + + Notes: + - Requires rsync installed and SSH access configured for the remote server. + - Assumes Codex is set up to output documentation to a directory like + docs/build/mcodex/html/. + - All functions allow parameter overrides for flexibility."))