From 268d8f822e7bc5dceeac73046a31e15c9c9b5934 Mon Sep 17 00:00:00 2001 From: Arun Isaac Date: Mon, 21 Feb 2022 13:01:26 +0530 Subject: doc: Add manual. * Makefile (GUILD, SKRIBILO, sources, doc_skribilo_config, doc_skribilo_config_go, doc_sources, doc_html): New variables. (%.go, html, $(doc_html), website/manual/dev/en, clean): New targets. (website): Depend on website/manual/dev/en. (.PHONY): Add html and clean targets. * doc/forge.skb, doc/skribilo.scm: New files. --- Makefile | 30 ++++++++++- doc/forge.skb | 54 ++++++++++++++++++++ doc/skribilo.scm | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 230 insertions(+), 2 deletions(-) create mode 100644 doc/forge.skb create mode 100644 doc/skribilo.scm diff --git a/Makefile b/Makefile index b4063c4..2fe0dd3 100644 --- a/Makefile +++ b/Makefile @@ -17,11 +17,37 @@ # along with guix-forge. If not, see . EMACS = emacs +GUILD = guild +SKRIBILO = skribilo -.PHONY: all +sources = $(wildcard forge/*.scm) $(wildcard forge/*/*.scm) +doc_skribilo_config = doc/skribilo.scm +doc_skribilo_config_go = $(doc_skribilo_config:.scm=.go) +doc_sources = doc/forge.skb +doc_html = $(doc_sources:.skb=.html) + +.PHONY: all html clean all: ; -website: website/index.html +%.go: %.scm + $(GUILD) compile -L . -o $@ $< + +html: $(doc_html) + +$(doc_html): $(doc_sources) $(sources) $(doc_skribilo_config_go) + rm -rf $@ + mkdir -p $@ + GUILE_LOAD_PATH=$(CURDIR):$(GUILE_LOAD_PATH) GUILE_LOAD_COMPILED_PATH=$(CURDIR):$(GUILE_LOAD_COMPILED_PATH) $(SKRIBILO) --target=html $< --output=$@/index.html + +website: website/index.html website/manual/dev/en website/index.html: README.org build-aux/build-home-page.el $(EMACS) -Q --batch --load build-aux/build-home-page.el --funcall build-website + +website/manual/dev/en: $(doc_html) + rm -rf $@ + mkdir -p $(dir $@) + cp -vr $^ $@ + +clean: + rm -f $(doc_skribilo_config_go) diff --git a/doc/forge.skb b/doc/forge.skb new file mode 100644 index 0000000..723d47f --- /dev/null +++ b/doc/forge.skb @@ -0,0 +1,54 @@ +;;; guix-forge --- Guix software forge meta-service +;;; Copyright © 2022 Arun Isaac +;;; +;;; This file is part of guix-forge. +;;; +;;; guix-forge is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published +;;; by the Free Software Foundation, either version 3 of the License, +;;; or (at your option) any later version. +;;; +;;; guix-forge is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;;; General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with guix-forge. If not, see +;;; . + +(use-modules (doc skribilo)) + +(document :title [guix-forge] + (chapter :title [Introduction] + (p [guix-forge is a Guix service that lets you run a complete +,(ref :url "https://en.wikipedia.org/wiki/Forge_(software)" +:text "software forge") in the manner of GitHub, GitLab, etc. Unlike +other free software forges such as GitLab, Gitea, etc., guix-forge is +not a monolith but is an assemblage of several pieces of server +software wired up to function as one. In this sense, it is a +,(emph "meta-service"). guix-forge does for software forges what ,(ref +:url "https://mailinabox.email/" :text "Mail-in-a-Box") does for +email.]) + (p [guix-forge is provided on a best effort basis. Its +design is unstable, and open to change. We will try our best to not +break your system configuration often, but it might happen.]) + (section :title [Philosophy] + (p [In order to empower ordinary users, software should not just +be free (as in freedom), but also be simple and easy to deploy, +especially for small-scale deployments. guix-forge is therefore +minimalistic, and does not require running large database servers such +as MariaDB and PostgreSQL.]) + (p [While some state is inevitable, server software should +strive to be as stateless as an old analog television set. You switch +it on, and it works all the time. There are no pesky software updates, +and complex hidden state. guix-forge tries to be as stateless as +possible. Almost all of guix-forge's state can be version controlled, +and the rest are simple files that can be backed up easily.]) + (p [,(ref +:url "https://drewdevault.com/2018/07/23/Git-is-already-distributed.html" +:text "Git is already federated and decentralized") with +email. guix-forge acknowledges this and prefers to support git's ,(ref +:url "https://drewdevault.com/2018/07/02/Email-driven-git.html" +:text "email driven workflow") with project discussion, bug reports +and patches all happening over email.])))) diff --git a/doc/skribilo.scm b/doc/skribilo.scm new file mode 100644 index 0000000..d97f485 --- /dev/null +++ b/doc/skribilo.scm @@ -0,0 +1,148 @@ +;;; guix-forge --- Guix software forge meta-service +;;; Copyright © 2022 Arun Isaac +;;; +;;; This file is part of guix-forge. +;;; +;;; guix-forge is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published +;;; by the Free Software Foundation, either version 3 of the License, +;;; or (at your option) any later version. +;;; +;;; guix-forge is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;;; General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with guix-forge. If not, see +;;; . + +(define-module (doc skribilo) + #:use-module (rnrs conditions) + #:use-module (rnrs io ports) + #:use-module (srfi srfi-28) + #:use-module (ice-9 match) + #:use-module (ice-9 regex) + #:use-module (skribilo ast) + #:use-module (skribilo engine) + #:use-module (skribilo lib) + #:use-module (skribilo writer) + #:use-module (skribilo package base) + #:use-module (skribilo parameters) + #:use-module (skribilo source lisp) + #:use-module (skribilo utils keywords) + #:export (file + command + scheme-source + scheme-source-form + source-ref)) + +;; Constants +(define %source-uri-base + "https://git.systemreboot.net/guix-forge/tree/") + +;; Aliases +(define file samp) +(define command code) + +;; Abbreviations +(define-markup (abbr #:rest opts + #:key (ident #f) (class "abbr") (short #f) (long #f)) + (new container + (markup 'abbr) + (ident (or ident (symbol->string (gensym "abbr")))) + (class class) + (loc &invocation-location) + (required-options '(#:short #:long)) + (options `((#:short ,short) + (#:long ,long) + ,@(the-options opts #:ident #:class #:short #:long))) + (body (the-body opts)))) + +;; S-exp source links +(define (source-uri file start-line end-line) + "Return a URI referring to source FILE from START-LINE to END-LINE." + (string-append %source-uri-base + file + "#n" + (number->string start-line))) + +(define (sexp-position str regexp) + "Return (START . END) where START is the start of the match to +REGEXP in STR and END is the end of the sexp beginning at START. START +and END are character positions indexed from 0. If multiple matches +are found, error out." + (cond + ((string-match regexp str) + => (lambda (match-struct) + (let ((start (match:start match-struct))) + (if (string-match regexp (substring str (1+ start))) + (raise-exception (condition (make-message-condition + (format "source-ref: regexp ~s found on multiple lines" + regexp)) + (make-irritants-condition regexp))) + (cons start + (1- (- (string-length str) + (string-length + (call-with-input-string (substring str start) + (lambda (port) + (read port) + (get-string-all port))))))))))) + (else + (raise-exception (condition (make-message-condition + (format "source-ref: regexp ~s not found" regexp)) + (make-irritants-condition regexp)))))) + +(define (position->line-number str position) + "Return the line number in STR corresponding to POSITION." + (string-fold (lambda (c result) + (if (char=? c #\newline) + (1+ result) + result)) + 1 + (substring str 0 position))) + +(define (sexp-file-lines file regexp) + "Return (START . END) where START is the start of the match to +REGEXP in STR and END is the end of the sexp beginning at START. START +and END are line numbers indexed from 1." + (let ((str (call-with-input-file file get-string-all))) + (match (sexp-position str regexp) + ((start . end) + (cons (position->line-number str start) + (position->line-number str end)))))) + +(define (source-ref file regexp text) + "Link to S-expression in FILE whose beginning matches REGEXP. TEXT +is the text of the link." + (ref #:url (match (sexp-file-lines (search-path (*source-path*) file) + regexp) + ((start-line . end-line) + (source-uri file start-line end-line))) + #:text text)) + +;; Extract forms from scheme source +(define (scheme-source-form file regexp) + "Extract form from scheme source FILE whose beginning matches +REGEXP. Return it enclosed in a prog form." + (prog (match (sexp-file-lines (search-path (*source-path*) file) + regexp) + ((start . stop) + (source #:language scheme + #:file file + #:start (1- start) + #:stop (1- stop)))) + #:line #f)) + +;; HTML engine customizations +(let ((html-engine (find-engine 'html))) + (engine-custom-set! html-engine 'css "/style.css") + (engine-custom-set! html-engine 'charset "UTF-8") + (markup-writer 'abbr html-engine + #:options '(#:short #:long) + #:action (lambda (markup engine) + (display (format "~a (~a)" + (markup-option markup #:long) + (markup-option markup #:short) + (markup-option markup #:long)) + (current-output-port))))) -- cgit v1.2.3