This commit is contained in:
Alexander Artemenko 2021-02-06 22:44:26 +00:00 committed by GitHub
commit 17a18186e2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 1091 additions and 784 deletions

46
.github/actions/build-docs/action.yml vendored Normal file
View file

@ -0,0 +1,46 @@
name: 'Build Docs'
inputs:
asdf-system:
description: 'ASDF system to build system for'
required: true
qlfile-template:
description: "Djula template for qlfile. All environment variables are available in it's context"
required: false
runs:
using: composite
steps:
- name: Install Documentation Builder
shell: bash
run: |
echo ::group::Install Documentation Builder
echo 'github docs-builder 40ants/docs-builder' >> qlfile
qlot update
qlot exec ros install docs-builder
echo ::endgroup::
- name: Build Docs
id: build-docs
shell: bash
run: |
set -Eeuo pipefail
echo ::group::Build Docs
build-docs ${{ inputs.asdf-system }} output.dir
echo ::endgroup::
- name: Upload Docs
shell: bash
run: |
set -Eeuo pipefail
echo ::group::Upload Docs
${{ github.action_path }}/upload.ros "$(cat output.dir)"
echo ::endgroup::
env:
GITHUB_TOKEN: ${{ github.token }}

203
.github/actions/build-docs/upload.ros vendored Executable file
View file

@ -0,0 +1,203 @@
#!/bin/sh
#|-*- mode:lisp -*-|#
#|
exec ros -Q -- $0 "$@"
|#
(progn ;;init forms
(ros:ensure-asdf)
#+quicklisp
(ql:quickload '(log4cl)
:silent t))
(defpackage :ros.script.upload
(:use :cl))
(in-package :ros.script.upload)
(defvar *current-dir*)
(define-condition unable-to-proceed (simple-error)
((message :initarg :message
:reader get-message))
(:report (lambda (condition stream)
(format stream (get-message condition)))))
(define-condition subprocess-error-with-output (uiop::subprocess-error)
((stdout :initarg :stdout :reader subprocess-error-stdout)
(stderr :initarg :stderr :reader subprocess-error-stderr))
(:report (lambda (condition stream)
(format stream "Subprocess ~@[~S~% ~]~@[with command ~S~% ~]exited with error~@[ code ~D ~]~@[ and this text at stderr:~% ~S~]"
(uiop:subprocess-error-process condition)
(uiop:subprocess-error-command condition)
(uiop:subprocess-error-code condition)
(subprocess-error-stderr condition)))))
(defun run (command &key (raise t))
"Runs command and returns it's stdout stderr and code.
If there was an error, raises subprocess-error-with-output, but this
behaviour could be overriden by keyword argument ``:raise t``."
(multiple-value-bind (stdout stderr code)
(uiop:run-program command
:output '(:string :stripped t)
:error-output '(:string :stripped t)
:ignore-error-status t)
(when (and raise
(not (eql code 0)))
(error 'subprocess-error-with-output
:stdout stdout
:stderr stderr
:code code
:command command))
(values stdout stderr code)))
(defun gh-pages-repository-initialized-p (docs-dir)
"Checks if repository for documentation already initialized"
(uiop:directory-exists-p (uiop:merge-pathnames* #P".git/"
docs-dir)))
(defun git (&rest commands)
"Calls git command in gh-pages repository."
(uiop:with-current-directory (*current-dir*)
(let ((command (apply #'concatenate 'string
"git "
commands)))
(log:info "Running" command "in" *current-dir*)
(run command))))
(defun git-repository-was-changed-p ()
;; if git status returns something, then repository have uncommitted changes
(> (length (git "status --porcelain"))
0))
(defun get-git-upstream ()
;; taken from http://stackoverflow.com/a/9753364/70293
(let ((upstream (run "git rev-parse --abbrev-ref --symbolic-full-name @{u}" :raise nil)))
(when (> (length upstream)
0)
(subseq upstream
0
(search "/" upstream)))))
(defun get-origin-to-push ()
(let ((upstream (get-git-upstream)))
(cond
(upstream
;; If there is already some remote upstream, then use it
(run (concatenate 'string "git remote get-url " upstream)))
;; If we are running inside github actions
((uiop:getenv "GITHUB_ACTIONS")
(unless (uiop:getenv "GITHUB_TOKEN")
(error 'unable-to-proceed
:message "Please, provide GITHUB_TOKEN environment variable."))
(format nil "https://~A:~A@github.com/~A"
(uiop:getenv "GITHUB_ACTOR")
(uiop:getenv "GITHUB_TOKEN")
(uiop:getenv "GITHUB_REPOSITORY")))
;; otherwise make it from travis secret token and repo slug
(t
(let ((repo-slug (uiop:getenv "TRAVIS_REPO_SLUG"))
(repo-token (uiop:getenv "GH_REPO_TOKEN")))
(unless (and repo-slug repo-token)
(error 'unable-to-proceed
:message "Current branch does not track any upstream and there is no TRAVIS_REPO_SLUG and GH_REPO_TOKEN env variables. Where to push gh-pages branch?"))
(format nil "https://~A@github.com/~A"
repo-token
repo-slug))))))
(defun push-gh-pages (docs-dir)
(log:info "Pushing changes to gh-pages branch")
(let ((*current-dir* docs-dir))
(unless (gh-pages-repository-initialized-p docs-dir)
(git "init")
(git "remote add origin "
(get-origin-to-push)))
(git "add .")
(cond
((git-repository-was-changed-p)
(when (uiop:getenv "GITHUB_ACTIONS")
(git "config --global user.name \"github-actions[bot]\"")
(git "config --global user.email \"actions@github.com\""))
(git "commit -m 'Update docs'")
(git "push --force origin master:gh-pages"))
;; or
(t (log:info "Everything is up to date.")))))
(defun push-local-changes ()
"Some documentation builders, like MGL-PAX,
can update README file as well. In this case, we need
to push the file into the current branch of the repository."
(let ((*current-dir* (probe-file #P"")))
(cond
((git-repository-was-changed-p)
(git "add -u")
(when (uiop:getenv "GITHUB_ACTIONS")
(log:info "Pushing changes to gh-pages branch")
(git "config --global user.name \"github-actions[bot]\"")
(git "config --global user.email \"actions@github.com\""))
(git "commit -m 'Update docs'")
(cond
((uiop:getenv "GITHUB_HEAD_REF")
(git "remote add upstream "
(get-origin-to-push))
(git "push upstream HEAD:"
(uiop:getenv "GITHUB_HEAD_REF")))
(t
(git "push"))))
;; or
(t (log:info "There is no local changes.")))))
(defun main (&rest argv)
(log:info "Uploading documentation")
(unless argv
(log:error "Please, specify a directory with HTML docs.")
(uiop:quit 1))
(let ((docs-dir (uiop:parse-unix-namestring (first argv)
:ensure-directory t)))
(handler-bind ((error (lambda (condition)
(uiop:print-condition-backtrace condition :stream *error-output*)
(uiop:quit 1))))
(unless (probe-file docs-dir)
(log:error "Directory \"~A not found"
docs-dir)
(uiop:quit 1))
(uiop:with-output-file (s (uiop:merge-pathnames* #P".nojekyll"
docs-dir)
:if-exists :overwrite)
(declare (ignorable s)))
(push-gh-pages docs-dir)
(push-local-changes))))
;;; vim: set ft=lisp lisp:

19
.github/actions/run-tests/action.yml vendored Normal file
View file

@ -0,0 +1,19 @@
name: 'Test Common Lisp System'
inputs:
asdf-system:
description: 'ASDF system to install and test'
required: true
run-tests:
description: A command to run tests
required: false
runs:
using: composite
steps:
- name: Run Tests
shell: bash
run: |
${{ github.action_path }}/run-tests.ros ${{ inputs.asdf-system }} <<EOF
${{ inputs.run-tests }}
EOF

89
.github/actions/run-tests/run-tests.ros vendored Executable file
View file

@ -0,0 +1,89 @@
#!/bin/sh
#|-*- mode:lisp -*-|#
#|
exec ros -Q -L sbcl-bin -- $0 "$@"
|#
(progn ;;init forms
(ros:ensure-asdf)
#+quicklisp(ql:quickload '(trivial-backtrace)
:silent t))
(declaim (optimize (debug 3) (safety 3)
(speed 0) (space 0)))
(defpackage :ros.script.run-tests
(:use :cl))
(in-package :ros.script.run-tests)
(defparameter *test-system-name-templates*
'("~A-test"
"~A-tests"
"~A/test"
"~A/tests"
"~A"))
(defun guess-test-system-name (primary-system-name)
(check-type primary-system-name string)
(loop for template in *test-system-name-templates*
for system-name = (format nil template
primary-system-name)
for asd-file = (format nil "~A.asd"
system-name)
when (probe-file asd-file)
do (return system-name)))
(defun run-tests (primary-system-name)
"Default tests runner searches appropriate system's name and calls ASDF:TEST-SYSTEM.
If ASDF:TEST-SYSTEM does not signal error condition, test run considered successful.
Before call to the ASDF:TEST-SYSTEM we do QL:QUICKLOAD, to be sure that all dependencies
are downloaded."
(check-type primary-system-name string)
(let ((test-system-name
(guess-test-system-name primary-system-name)))
(ql:quickload test-system-name
:silent t)
;; ASDF:TEST-SYSTEM always returns T
(asdf:test-system test-system-name)))
(defun main (&rest args)
(let ((system (first args)))
(format t "::group::Running tests for ASDF system ~S~%"
(or system
""))
(unwind-protect
(handler-bind
((error (lambda (condition)
(trivial-backtrace:print-backtrace condition)
(uiop:quit 3))))
(when (or (null system)
(string= system ""))
(format *error-output*
"Please specify ASDF system as a first argument.~%")
(uiop:quit 1))
(let* ((user-script (uiop:slurp-stream-forms *standard-input*))
(result
(cond
(user-script
(loop with form-results
for form in user-script
do (setf form-results
(eval form))
finally (return form-results)))
;; default tests runner
(t
(run-tests system)))))
(unless result
(uiop:quit 2))))
(format t "::endgroup::~%"))))
;;; vim: set ft=lisp lisp:

52
.github/actions/scripts/templater.ros vendored Executable file
View file

@ -0,0 +1,52 @@
#!/bin/sh
#|-*- mode:lisp -*-|#
#|
exec ros -Q -L sbcl-bin -- $0 "$@"
|#
(progn
(ros:ensure-asdf)
#+quicklisp
(ql:quickload '(djula)
:silent t))
(defpackage :ros.script.templater
(:use :cl))
(in-package :ros.script.templater)
(defun collect-arguments ()
(let* ((env-output (with-output-to-string (s)
(uiop:run-program "env" :output s)))
(lines (uiop:with-input (env-output)
(uiop:slurp-stream-lines env-output))))
(loop for line in lines
for (key value) = (cl-ppcre:split "=" line
:limit 2)
appending (list (alexandria:make-keyword key)
value))))
(defun interpose (separator list)
"Returns a sequence of the elements of SEQUENCE separated by SEPARATOR."
(labels ((rec (s acc)
(if s
(rec (cdr s) (nconc acc
(list separator (car s))))
acc)))
(cdr (rec list nil))))
(defun main (&rest argv)
(declare (ignore argv))
(let* ((lines (uiop:slurp-stream-lines *standard-input*))
(template-text (apply #'concatenate 'string
(interpose (string #\Newline)
lines)))
(template (djula::compile-string template-text))
(arguments (collect-arguments)))
(apply #'djula:render-template*
template
*standard-output*
arguments)))
;;; vim: set ft=lisp lisp:

86
.github/actions/setup-lisp/action.yml vendored Normal file
View file

@ -0,0 +1,86 @@
name: 'Setup Common Lisp'
inputs:
asdf-system:
description: 'ASDF system to install'
required: false
qlfile-template:
description: "Djula template for qlfile. All environment variables are available in it's context"
required: false
runs:
using: composite
steps:
- name: Current Env
shell: bash
run: |
echo ::group::Environment
echo "Current dir:"
pwd
echo "Environment Variables:"
env | sort -u
echo ::endgroup::
- name: Install Roswell
shell: bash
run: |
echo ::group::Install Roswell
if [[ "$RUNNER_OS" == "Linux" ]]; then
sudo apt-get -y install git build-essential automake libcurl4-openssl-dev
fi
if [[ "$RUNNER_OS" == "macOS" ]]; then
brew install automake autoconf curl
fi
curl -L https://raw.githubusercontent.com/svetlyak40wt/roswell/patches/scripts/install-for-ci.sh | sh
echo $HOME/.roswell/bin >> $GITHUB_PATH
echo ::endgroup::
- name: Upgrade ASDF to the Latest Version
shell: bash
run: |
echo ::group::Upgrade ASDF
ros install asdf
echo ::endgroup::
- name: Install Qlot
shell: bash
run: |
echo ::group::Install Qlot
ros install qlot
echo .qlot/bin >> $GITHUB_PATH
echo ::endgroup::
- name: Create Qlot Environment
shell: bash
run: |
echo ::group::Create Qlot Environment
if [[ -n "${QLFILE_TEMPLATE}" ]]; then
echo "${QLFILE_TEMPLATE}" | ${{ github.action_path }}/../scripts/templater.ros > qlfile
rm -f qlfile.lock
fi
echo 'Here is content of qlfile:'
echo '==============='
cat qlfile
echo '==============='
echo ''
qlot install
echo ::endgroup::
env:
QLFILE_TEMPLATE: ${{ inputs.qlfile-template }}
# This step will install system and
# all possible roswell scripts, if the system
# has them in the roswell/ subdirectory:
- name: Install ASDF System
shell: bash
run: |
echo ::group::Install ASDF System
if [[ -n "${{ inputs.asdf-system }}" ]]; then
qlot exec ros install ${{ inputs.asdf-system }}
else
echo "ASDF system wasn't provided."
fi
echo ::endgroup::

94
.github/workflows/ci.yml vendored Normal file
View file

@ -0,0 +1,94 @@
name: 'CI'
on:
# This will run tests on pushes
# to master branch or on pull merges:
push:
branches:
- 'main'
- 'master'
# This will run tests for every pull request:
pull_request:
# Rerun tests at 10 AM every Monday
# to check if they still work with latest dependencies.
schedule:
- cron: '0 10 * * 1'
jobs:
run-tests:
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.can-fail || false }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
# - macos-latest
quicklisp-dist:
- quicklisp
- ultralisp
lisp:
- sbcl-bin
# - ccl-bin
# - ecl
# - abcl
# - allegro
# - clisp
# - cmucl
# include:
# # Seems allegro is does not support 64bit OSX.
# # Unable to install it using Roswell:
# # alisp is not executable. Missing 32bit glibc?
# - lisp: allegro
# os: macos-latest
# can-fail: true
# # CLisp on Ubuntu can't be installed because of the error:
# # #<FOREIGN-VARIABLE "rl_readline_state" #x00007FA93E698850> does not have
# # the required size or alignment
# - lisp: clisp
# os: ubuntu-latest
# can-fail: true
# # CMUCL is 32bit and cant' work on 64bit OSX:
# # .roswell/impls/x86-64/darwin/cmu-bin/21d/bin/lisp is not executable. Missing 32bit glibc?
# - lisp: cmucl
# os: macos-latest
# can-fail: true
env:
LISP: ${{ matrix.lisp }}
OS: ${{ matrix.os }}
QUICKLISP_DIST: ${{ matrix.quicklisp-dist }}
steps:
- uses: actions/checkout@v1
- uses: 40ants/cl-info/.github/actions/setup-lisp@custom-action
with:
asdf-system: cl-info
qlfile-template: |
{% ifequal quicklisp_dist "ultralisp" %}
dist ultralisp http://dist.ultralisp.org
{% endifequal %}
github mgl-pax svetlyak40wt/mgl-pax :branch mgl-pax-minimal
- uses: 40ants/cl-info/.github/actions/run-tests@custom-action
with:
asdf-system: cl-info
# This is additional step to check
# a command line script
- name: Run Command Line Version
run: |
echo ::group::Help Argument
qlot exec cl-info --help
echo ::endgroup::
echo ::group::Version Argument
qlot exec cl-info --version
echo ::endgroup::
echo ::group::Lisp Systems Info
qlot exec cl-info cl-info defmain
echo ::endgroup::

35
.github/workflows/docs.yml vendored Normal file
View file

@ -0,0 +1,35 @@
name: 'Docs'
on:
# This will run tests on pushes
# to master branch or on pull merges:
push:
branches:
- 'main'
- 'master'
# This will run tests for every pull request:
pull_request:
# Rerun tests at 10 AM every Monday
# to check if they still work with latest dependencies.
schedule:
- cron: '0 10 * * 1'
jobs:
build-docs:
runs-on: ubuntu-latest
env:
LISP: sbcl-bin
steps:
- uses: actions/checkout@v1
- uses: 40ants/cl-info/.github/actions/setup-lisp@custom-action
with:
asdf-system: cl-info
qlfile-template: |
github mgl-pax svetlyak40wt/mgl-pax :branch mgl-pax-minimal
- uses: 40ants/cl-info/.github/actions/build-docs@custom-action
with:
asdf-system: cl-info

View file

@ -1,110 +0,0 @@
name: 'Check Installation'
on:
# This will run tests on pushes
# to master branch or on pull merges:
push:
branches:
- 'main'
- 'master'
# This will run tests for every pull request:
pull_request:
# Rerun tests at 10 AM every Monday
# to check if they still work with latest dependencies.
schedule:
- cron: '0 10 * * 1'
jobs:
run_tests:
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- macos-latest
quicklisp-dist:
- quicklisp
- ultralisp
lisp:
- sbcl-bin
- ccl-bin
- ecl
- abcl
- allegro
- clisp
- cmucl
include:
# Seems allegro is does not support 64bit OSX.
# Unable to install it using Roswell:
# alisp is not executable. Missing 32bit glibc?
- lisp: allegro
os: macos-latest
can-fail: true
# CLisp on Ubuntu can't be installed because of the error:
# #<FOREIGN-VARIABLE "rl_readline_state" #x00007FA93E698850> does not have
# the required size or alignment
- lisp: clisp
os: ubuntu-latest
can-fail: true
# CMUCL is 32bit and cant' work on 64bit OSX:
# .roswell/impls/x86-64/darwin/cmu-bin/21d/bin/lisp is not executable. Missing 32bit glibc?
- lisp: cmucl
os: macos-latest
can-fail: true
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.can-fail || false }}
env:
LISP: ${{ matrix.lisp }}
OS: ${{ matrix.os }}
QUICKLISP_DIST: ${{ matrix.quicklisp-dist }}
steps:
- uses: actions/checkout@v1
- name: Show ENV
run: |
env | sort -u
- name: Install Roswell
run: |
if [[ "$OS" == "ubuntu-latest" ]]; then
sudo apt-get -y install git build-essential automake libcurl4-openssl-dev
fi
if [[ "$OS" == "macos-latest" ]]; then
brew install automake autoconf curl
fi
curl -L https://raw.githubusercontent.com/svetlyak40wt/roswell/patches/scripts/install-for-ci.sh | sh
echo $HOME/.roswell/bin >> $GITHUB_PATH
- name: Upgrade ASDF to the Latest Version
run: |
ros install asdf
- name: Install Qlot
run: |
ros install qlot
echo .qlot/bin >> $GITHUB_PATH
- name: Install Dependencies
run: |
rm -fr qlfile
touch qlfile
if [[ "${QUICKLISP_DIST}" == 'ultralisp' ]]; then
echo dist ultralisp http://dist.ultralisp.org/ >> qlfile
fi
qlot install
- name: Install System
run: |
if [[ "${QUICKLISP_DIST}" == 'quicklisp' ]]; then
qlot exec ros install 40ants/defmain
fi
qlot exec ros install cl-info
- name: Run Tests
run: |
set -x
qlot exec cl-info --help
qlot exec cl-info --version
qlot exec cl-info cl-info

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
/docs/build/
/env/
/.qlot

View file

@ -1,8 +0,0 @@
Before iframe
<iframe src="https://com-40ants-github-actions.herokuapp.com/40ants/cl-info/matrix.svg?v=2"
frameborder="0"
width="600"
height="500"></iframe>
AFTER

6
cl-info-docs.asd Normal file
View file

@ -0,0 +1,6 @@
(defsystem example-docs
:build-operation build-docs-op
:build-pathname "docs/build/"
:class :package-inferred-system
:pathname "docs/source/"
:depends-on ("example-docs/docs"))

View file

@ -3,10 +3,10 @@
:license ""
:class :package-inferred-system
:pathname "t"
:depends-on (:cl-info
:depends-on ("hamcrest"
"cl-info-test/core")
:description "Test system for cl-info"
:perform (test-op :after (op c)
(symbol-call :rove :run c)
(clear-system c)))
:perform (test-op (op c)
(unless (symbol-call :rove :run c)
(error "Tests failed"))))

View file

@ -1,153 +0,0 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/cl-info.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/cl-info.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/cl-info"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/cl-info"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

View file

@ -1,10 +0,0 @@
# to build documentation
sphinx
pygments-cl-repl
sphinx-bootstrap-theme
# to support docstring extraction and cross-referencing
-e git+git@github.com:russell/sphinxcontrib-cldomain.git#egg=sphinxcontrib-cldomain
# to run commands from tasks.py
invoke

View file

@ -1,30 +0,0 @@
#
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile --output-file requirements.txt requirements.in
#
-e git+git@github.com:russell/sphinxcontrib-cldomain.git#egg=sphinxcontrib-cldomain
alabaster==0.7.10 # via sphinx
appdirs==1.4.3 # via setuptools
babel==2.4.0 # via sphinx
docutils==0.13.1 # via sphinx
imagesize==0.7.1 # via sphinx
invoke==0.15.0
Jinja2==2.9.6 # via sphinx
MarkupSafe==1.0 # via jinja2
packaging==16.8 # via setuptools
pygments-cl-repl==0.1
pygments==2.2.0 # via pygments-cl-repl, sphinx
pyparsing==2.2.0 # via packaging
pytz==2017.2 # via babel
requests==2.13.0 # via sphinx
six==1.10.0 # via packaging, setuptools, sphinx
snowballstemmer==1.2.1 # via sphinx
sphinx-bootstrap-theme==0.4.14
sphinx==1.5.5
# The following packages are commented out because they are
# considered to be unsafe in a requirements file:
# setuptools # via sphinx-bootstrap-theme

163
docs/scripts/build.ros Executable file
View file

@ -0,0 +1,163 @@
#!/bin/sh
#|-*- mode:lisp -*-|#
#| <Put a one-line description here>
exec ros -Q -- $0 "$@"
|#
(progn ;;init forms
(ros:ensure-asdf)
#+quicklisp
(ql:quickload '(log4cl
example-docs)
:silent t))
(defpackage :script.build-docs
(:use :cl))
(in-package :script.build-docs)
(define-condition unable-to-proceed (simple-error)
((message :initarg :message
:reader get-message))
(:report (lambda (condition stream)
(format stream (get-message condition)))))
(define-condition subprocess-error-with-output (uiop::subprocess-error)
((stdout :initarg :stdout :reader subprocess-error-stdout)
(stderr :initarg :stderr :reader subprocess-error-stderr))
(:report (lambda (condition stream)
(format stream "Subprocess ~@[~S~% ~]~@[with command ~S~% ~]exited with error~@[ code ~D ~]~@[ and this text at stderr:~% ~S~]"
(uiop:subprocess-error-process condition)
(uiop:subprocess-error-command condition)
(uiop:subprocess-error-code condition)
(subprocess-error-stderr condition))
)))
(defun run (command &key (raise t))
"Runs command and returns it's stdout stderr and code.
If there was an error, raises subprocess-error-with-output, but this
behaviour could be overriden by keyword argument ``:raise t``."
(multiple-value-bind (stdout stderr code)
(uiop:run-program command
:output '(:string :stripped t)
:error-output '(:string :stripped t)
:ignore-error-status t)
(when (and raise
(not (eql code 0)))
(error 'subprocess-error-with-output
:stdout stdout
:stderr stderr
:code code
:command command))
(values stdout stderr code)))
(defun build-docs ()
(log:info "Building documentation in ./docs/")
(example-docs:build-docs)
(uiop:with-output-file (s "docs/build/.nojekyll" :if-exists :overwrite)
(declare (ignorable s))))
(defun gh-pages-repository-initialized-p ()
"Checks if repository for documentation already initialized"
(uiop:directory-exists-p "docs/build/.git"))
(defun git (&rest commands)
"Calls git command in gh-pages repository."
(let ((directory "docs/build/"))
(uiop:with-current-directory (directory)
(let ((command (apply #'concatenate 'string
"git "
commands)))
(log:info "Running" command "in" directory)
(run command)))))
(defun git-repository-was-changed-p ()
;; if git status returns something, then repository have uncommitted changes
(> (length (git "status --porcelain"))
0))
(defun get-git-upstream ()
;; taken from http://stackoverflow.com/a/9753364/70293
(let ((upstream (run "git rev-parse --abbrev-ref --symbolic-full-name @{u}" :raise nil)))
(when (> (length upstream)
0)
(subseq upstream
0
(search "/" upstream)))))
(defun get-origin-to-push ()
(let ((upstream (get-git-upstream)))
(cond
(upstream
;; If there is already some remote upstream, then use it
(run (concatenate 'string "git remote get-url " upstream)))
;; If we are running inside github actions
((uiop:getenv "GITHUB_ACTIONS")
(unless (uiop:getenv "GITHUB_TOKEN")
(error 'unable-to-proceed
:message "Please, provide GITHUB_TOKEN environment variable."))
(format nil "https://~A:~A@github.com/~A"
(uiop:getenv "GITHUB_ACTOR")
(uiop:getenv "GITHUB_TOKEN")
(uiop:getenv "GITHUB_REPOSITORY")))
;; otherwise make it from travis secret token and repo slug
(t
(let ((repo-slug (uiop:getenv "TRAVIS_REPO_SLUG"))
(repo-token (uiop:getenv "GH_REPO_TOKEN")))
(unless (and repo-slug repo-token)
(error 'unable-to-proceed
:message "Current branch does not track any upstream and there is no TRAVIS_REPO_SLUG and GH_REPO_TOKEN env variables. Where to push gh-pages branch?"))
(format nil "https://~A@github.com/~A"
repo-token
repo-slug))))))
(defun push-gh-pages ()
(log:info "Pushing changes to gh-pages branch")
(unless (gh-pages-repository-initialized-p)
(git "init")
(git "remote add origin "
(get-origin-to-push)))
(git "add .")
(cond
((git-repository-was-changed-p)
(when (uiop:getenv "GITHUB_ACTIONS")
(git "config --global user.name \"github-actions[bot]\"")
(git "config --global user.email \"actions@github.com\""))
(git "commit -m 'Update docs'")
(git "push --force origin master:gh-pages"))
;; or
(t (log:info "Everything is up to date."))))
(defun main (&rest argv)
(declare (ignorable argv))
(log:config :debug)
(log:info "Building documentation")
(handler-bind ((error (lambda (condition)
(uiop:print-condition-backtrace condition :stream *error-output*)
(uiop:quit 1))))
(build-docs)
(push-gh-pages)))

View file

@ -1,30 +0,0 @@
=====
API
=====
Here you can describe an API.
Use `cldomain's <http://cldomain.russellsim.org>`_ directives, to insert
functions or macroses descriptions, like that:
.. cl:package:: cl-info
.. cl:function:: foo
.. cl:macro:: bar
Also you can specify additional examples for some blocks:
.. code-block:: common-lisp-repl
TEST> (bar 1 2 3)
(1 2 3)
NIL
And because this is Sphinx, you can use it's great cross-referencing
features to link to functions. Here is the link to
:cl:function:`cl-info:foo`.
Read the documentation on `cldomain <http://cldomain.russellsim.org>`_ and
write your own beautiful docs!

View file

@ -1 +0,0 @@
.. include:: ../../ChangeLog.rst

View file

@ -1,324 +0,0 @@
# -*- coding: utf-8 -*-
#
# cl-info documentation build configuration file, created by
# sphinx-quickstart on Sat Apr 8 20:18:20 2017.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
# 'sphinx.ext.autodoc',
# 'sphinx.ext.doctest',
# 'sphinx.ext.viewcode',
# 'sphinx.ext.intersphinx',
# creates .nojekyll file on generated HTML directory
'sphinx.ext.githubpages',
# Allow reference sections using its title
# http://www.sphinx-doc.org/en/stable/ext/autosectionlabel.html
'sphinx.ext.autosectionlabel',
'sphinxcontrib.cldomain',
'sphinxcontrib.hyperspec',
]
from os.path import join, dirname, realpath, expandvars
cl_systems = [
{
'name': 'cl-info-test',
'path': join(dirname(realpath(__file__)), '../../'),
'packages': [
'cl-info',
]
},
]
cl_quicklisp = expandvars('$HOME/quicklisp/')
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'cl-info'
copyright = u'2017, '
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The full version, including alpha/beta/rc tags.
release = open(join(dirname(__file__), "../..",
"version.lisp-expr")).read().strip().strip('"')
# The short X.Y version.
version = '.'.join(release.split('.')[:2])
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = []
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
highlight_language = 'common-lisp'
pygments_style = 'emacs'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
import sphinx_bootstrap_theme
html_theme = 'bootstrap'
# почему-то в модуле его нет
#html_translator_class = 'sphinx_bootstrap_theme.BootstrapTranslator'
html_theme_path = sphinx_bootstrap_theme.get_html_theme_path()
html_theme_options = {
# Navigation bar title. (Default: ``project`` value)
# 'navbar_title': "Demo",
'navbar_sidebarrel': False,
'navbar_pagenav': False,
# Tab name for entire site. (Default: "Site")
"navbar_site_name": "Contents",
# Global TOC depth for "site" navbar tab. (Default: 1)
# Switching to -1 shows all levels.
# 'globaltoc_depth': 2,
# Include hidden TOCs in Site navbar?
#
# Note: If this is "false", you cannot have mixed ``:hidden:`` and
# non-hidden ``toctree`` directives in the same page, or else the build
# will break.
#
# Values: "true" (default) or "false"
# 'globaltoc_includehidden': "true",
# HTML navbar class (Default: "navbar") to attach to <div> element.
# For black navbar, do "navbar navbar-inverse"
# 'navbar_class': "navbar navbar-inverse",
'navbar_site_name': "Documentation",
'navbar_links': [("Changelog", "changelog")],
# Fix navigation bar to top of page?
# Values: "true" (default) or "false"
# 'navbar_fixed_top': "true",
# Location of link to source.
# Options are "nav" (default), "footer" or anything else to exclude.
'source_link_position': "footer",
# Bootswatch (http://bootswatch.com/) theme.
#
# Options are nothing with "" (default) or the name of a valid theme
# such as "amelia" or "cosmo".
#
# Note that this is served off CDN, so won't be available offline.
'bootswatch_theme': "yeti",
}
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
# Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = ["_themes/"]
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
html_sidebars = {'**': ['localtoc.html'],
'search': None,
'glossary': None}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'cl-infodoc'
# -- Options for LaTeX output --------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'cl-info.tex', u'cl-info Documentation',
u'', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'cl-info', u'cl-info Documentation',
[u''], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'cl-info', u'cl-info Documentation',
u'', 'cl-info', '',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'

168
docs/source/docs.lisp Normal file
View file

@ -0,0 +1,168 @@
(defpackage #:example-docs/docs
(:nicknames #:example-docs)
(:use #:cl)
(:import-from #:mgl-pax
#:section
#:defsection)
(:import-from #:example/app
#:@app)
(:import-from #:example/utils
#:@utils)
(:export
#:build-docs))
(in-package example-docs/docs)
(defsection @index (:title "Example of MGL-PAX Common Lisp Documentation Builder")
"
This is small library includes a few functions with docstrings and a documentation
for the system and all included packages.
The purpose is to demonstrate core features of the
[MGL-PAX](http://melisgl.github.io/mgl-pax/) documentation builder.
This repository is part of the <https://github.com/cl-doc-systems> organization,
created to compare different Common Lisp documentation systems.
The goal is make it easier for CL software developers to choose proper
documentation system and to improve docs in their software!
Resulting documentation can be viewed here:
<https://cl-doc-systems.github.io/mgl-pax/>
The repository can be used as a template for new libraries if you've choosen `MGL-PAX`
for documenting your library.
Let's review features, provided by `MGL-PAX`.
"
(@pros-n-cons section)
(@how-to-build section)
(@handwritten section)
(@autogenerated section)
(@packages section))
(defsection @pros-n-cons (:title "Pros & Cons of PAX")
(@pros section)
(@cons section))
(defsection @pros (:title "Pros")
"
* Markdown is widely used markup format and PAX uses it everywhere.
* Cross-referencing works like a charm and you can reference different
types of objects using [Locatives](http://melisgl.github.io/mgl-pax/#x-28MGL-PAX-3A-40MGL-PAX-LOCATIVES-AND-REFERENCES-20MGL-PAX-3ASECTION-29).
* New types of documentation objects can be defined in Common Lisp using CLOS.
Here is [an example](http://melisgl.github.io/mgl-pax/#x-28MGL-PAX-3AREFERENCE-LOCATIVE-20-28MGL-PAX-3AREADER-20MGL-PAX-3AREFERENCE-29-29).
* Emacs/SLIME integration and ability to jump to a xref objects using M-.
* Ability to generate Markdown README files as well as HTML.
* It is possible to link documentation and sources on the GitHub.
* Docstrings deindentation allows to format code nicely.
* You can generation docs for a multiple ASDF systems with cross-referencing.
* Autoexports all documented symbols. No need to enumerate them in `defpackage` form.
* There is a nice default HTML theme.
* No external tools like Sphinx. Everything is in Common Lisp.
")
(defsection @cons (:title "Cons")
"
* Markdown format may be somewhat limited and probably it can be non-trivial or not possible
to extend it in some rare cases.
* The recommended way to mix documentation section with code leads to
the runtime dependency from PAX and all it's dependencies. But you
might define documentation as a separate ASDF system.
* PAX does not notifies you if some references are missing or there are unused sections.
These mistakes can be catched automatically.
* It is inconvenient to write Markdown in docstrings. Is there any way
to teach Emacs to use markdown minor mode for documentation strings?
* There is no magically autogenerated reference API. See @AUTOGENERATED.
But if you prefer another way, it should be easy to write a function which
will collect external symbols and generate a MGL-PAX:SECTION object for them.
")
(defsection @how-to-build (:title "How to build the documentation")
"
MGL-PAX has a number of ways for generation of the docs. But most probably,
you'll need only toplevel helpers described in it's section
[Generating Documentation](http://melisgl.github.io/mgl-pax/#toc-7-generating-documentation).
These helpers is able to generate README and HTML docs for an ASDF system.
This example defines it's own wrapper EXAMPLE-DOCS:BUILD-DOCS:
"
(build-docs function)
"
It is as simple, as:
```
(defun build-docs ()
(mgl-pax:update-asdf-system-readmes @index :example)
(mgl-pax:update-asdf-system-html-docs @index :example
:target-dir \"docs/build/\"))
```
This function is used by docs/scripts/build.ros file to generate documentation from GitHub Actions.
Or can be called from the REPL.
")
(defsection @handwritten (:title "Handwritten Documentation")
"
I think the ability to write a large pieces of documentation which aren't bound to
a function, class or module is an important feature. This way you can tell the user
about some toplevel abstractions and give a bird eye view on the library or system.
For example, handwritten parts of the documentation can provide some code snippets
to demonstrate the ways, how to use the library:
```
(loop repeat 42
collect (foo \"bar\" 100500))
```
And when you are talking about some function or class, you can reference it.
For example, if I'm talking about the FOO function, I can reference it like this
`[example/app:foo][function]` and it will appear in the code as
the link [example/app:foo]. In most cases you can omit square brakets and just
capitalize symbol name.
Comparing MGL-PAX to Coo (here is it's [example project](https://cl-doc-systems.github.io/coo/),
I'd prefer the PAX, because it's ability to mix handwriten sections with documentation extracted
from docstrings.
")
(defsection @autogenerated (:title "Autogenerated API Reference")
"
There is no magically autogenerated reference API. Idea of PAX is that you
write docs manually and reference documented symbols. They are automatically
exported and this way you library's external API should be documented.
But if you prefer another way, it should be easy to write a function which
will collect external symbols and generate a MGL-PAX:SECTION object for them.
")
(defsection @packages (:title "Packages")
(@app section)
(@utils section))
(defun build-docs ()
(mgl-pax:update-asdf-system-readmes @index :example)
(mgl-pax:update-asdf-system-html-docs
@index :example
:target-dir "docs/build/"
:pages `((:objects (,example-docs:@index)
:source-uri-fn ,(pax:make-github-source-uri-fn
:example
"https://github.com/cl-doc-systems/mgl-pax")))))

View file

@ -1,40 +0,0 @@
=========================================
Welcome to cl-info's documentation!
=========================================
This is an implementation of Hamcrest for Common Lisp.
Here are some examples
----------------------
.. code-block:: common-lisp-repl
GIT> (assert-that
log-item
(has-plist-entries :|@message| "Some"
:|@timestamp| _)
(hasnt-plist-keys :|@fields|))
.. include:: ../../README.rst
:start-after: include-from
:end-before: include-to
Contents
========
.. toctree::
:maxdepth: 2
api
changelog
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

1
qlfile Normal file
View file

@ -0,0 +1 @@
dist ultralisp http://dist.ultralisp.org

8
qlfile.lock Normal file
View file

@ -0,0 +1,8 @@
("quicklisp" .
(:class qlot/source/dist:source-dist
:initargs (:distribution "http://beta.quicklisp.org/dist/quicklisp.txt" :%version :latest)
:version "2021-01-24"))
("ultralisp" .
(:class qlot/source/dist:source-dist
:initargs (:distribution "http://dist.ultralisp.org" :%version :latest)
:version "20210202153000"))

View file

@ -1,27 +1,103 @@
(defpackage #:cl-info/core
(:nicknames #:cl-info)
(defpackage #:cl-info
(:nicknames #:cl-info/core)
(:use #:cl)
(:export
#:cl-info
#:get-asdf-version
#:get-lisp-type
#:get-lisp-version
#:get-software-type
#:get-software-version
#:get-ql-dists
(:import-from #:mgl-pax-minimal
#:defsection
#:reader)
(:export #:cl-info
#:get-cl-info
#:system-info
#:get-name
#:get-version
#:get-path
#:absent-p
#:get-system-info))
(in-package cl-info/core)
(defsection @index (:title "CL-INFO - Common Lisp Environment Reporter")
"
[![](https://github-actions.40ants.com/40ants/cl-info/matrix.svg)](https://github.com/40ants/cl-info/actions)
This is a small utility, useful to display information about you Common
Lisp environment. You might want to call it in the CI pipeline or
to use it when rendering a crash report in some client applications.
Usage from Common Lisp
======================
It's main entry point is CL-INFO:GET-CL-INFO function. It returns an object with
customized PRINT-OBJECT method. You can use it to output debug
information in your programs.
CL-INFO collects inforrmation about OS, Lisp Implementation, ASDF, installed
Quicklisp distributions:
CL-USER> (cl-info:get-cl-info)
OS: Darwin 15.6.0
Lisp: SBCL 1.4.8
ASDF: 3.3.1.1
QL: ceramic github-e0d905187946f8f2358f7b05e1ce87b302e34312
cl-prevalence github-c163c227ed85d430b82cb1e3502f72d4f88e3cfa
log4cl-json github-c4f786e252d89a45372186aaf32fb8e8736b444b
log4cl github-6a857b0b41c030a8a3b04096205e221baaa1755f
quicklisp 2018-04-30
slynk github-3314cf8c3021cb758e0e30fe3ece54accf1dcf3d
weblocks-lass github-1b043afbf2f3e84e495dfeae5e63fe67a435019f
weblocks-parenscript github-8ef4ca2f837403a05c4e9b92dcf1c41771d16f17
weblocks-ui github-5afdf238534d70edc2447d0bc8bc63da8e35999f
weblocks-websocket github-b098db7f179dce3bfb045afd4e35e7cc868893f0
weblocks github-282483f97d6ca351265ebfebb017867c295d01ad
websocket-driver github-a3046b11dfb9803ac3bff7734dd017390c2b54bb
CL-USER>
Also, you can gather information about separate systems using CL-INFO:GET-SYSTEM-INFO
function:
CL-USER> (cl-info:get-system-info :hamcrest)
System: HAMCREST 0.4.2
/Users/art/common-lisp/cl-hamcrest/src/
Usage From Command-line
=======================
Also, you can use CL-INFO as a command-line utility. It is useful to
output information about common lisp environment running on CI server.
Here is how to do it:
```shell
# Here we use a Roswell, to install utility
[art@art-osx:~]% ros install 40ants/cl-info
# And now request information about lisp and some systems
[art@art-osx:~]% cl-info weblocks clack jonathan some-other-system
OS: Darwin 15.6.0
Lisp: Clozure Common Lisp Version 1.11.5/v1.11.5 (DarwinX8664)
ASDF: 3.3.1.1
QL: org.borodust.bodge 20180214223017
quicklisp 2017-10-23
System: weblocks 0.31.1
/Users/art/common-lisp/weblocks/src/
System: clack 2.0.0
/Users/art/common-lisp/clack/
System: jonathan 0.1
/Users/art/.roswell/lisp/quicklisp/dists/quicklisp/software/jonathan-20170630-git/
System: some-other-system is not available
```
API Reference
=============
"
(get-cl-info function)
(get-system-info function)
(cl-info class)
(get-asdf-version (reader cl-info))
(system-info class))
(defclass cl-info ()
((asdf-version :initform (asdf:asdf-version)
:reader get-asdf-version)
:reader get-asdf-version
:documentation "Returns ASDF version.")
(lisp-type :initform (lisp-implementation-type)
:reader get-lisp-type)
(lisp-version :initform (lisp-implementation-version)

View file

@ -1,11 +1,19 @@
(defpackage #:cl-info-test/core
(:use #:cl
#:cl-info/core
#:rove
#:hamcrest/rove))
(:use #:cl)
(:import-from #:cl-info)
(:import-from #:hamcrest/rove
#:contains
#:assert-that)
(:import-from #:rove
#:testing
#:deftest))
(in-package cl-info-test/core)
(defun foo (a b)
(list a b))
(deftest test-some-staff
(testing "Replace this test with real staff."
(assert-that (foo 1 2)

View file

@ -1,42 +0,0 @@
import os
import sys
from invoke import task, run
@task
def build_docs(ctx):
"""Builds html documentation and updates gh-pages branch.
"""
def git(cmd):
return run('cd docs/build/html && git {0}'.format(cmd))
# build docs
run('cd docs && make html')
# If project's directory is git repository
if os.path.exists('.git'):
# if no git repository in docs/build/html,
# then init one
if not os.path.exists('docs/build/html/.git'):
result = run("git remote -v | grep '^origin.*(push)$'", warn=True)
if result.failed:
print('There is no "origin" remote in this git repository.')
print('Please, add remote and push it to the Github.')
sys.exit(1)
else:
origin = result.stdout.strip().split()[1]
git('init')
git('remote add origin {0}'.format(origin))
git('add .')
git('commit -m "Update docs"')
git('push --force origin master:gh-pages')
else:
# If project's directory is not a repository
# then we don't know where to push the docs.
print('This project is not a git repository.')
print('Please, push it to the GitHub and run this command')
print('again. Then we\'ll be able to update gh-pages branch.')
sys.exit(1)