diff --git a/.github/actions/build-docs/action.yml b/.github/actions/build-docs/action.yml new file mode 100644 index 0000000..7c03453 --- /dev/null +++ b/.github/actions/build-docs/action.yml @@ -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 }} diff --git a/.github/actions/build-docs/upload.ros b/.github/actions/build-docs/upload.ros new file mode 100755 index 0000000..0b51454 --- /dev/null +++ b/.github/actions/build-docs/upload.ros @@ -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: diff --git a/.github/actions/run-tests/action.yml b/.github/actions/run-tests/action.yml new file mode 100644 index 0000000..31ecb96 --- /dev/null +++ b/.github/actions/run-tests/action.yml @@ -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 }} <> $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:: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..6dce146 --- /dev/null +++ b/.github/workflows/ci.yml @@ -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: + # # # 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:: diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..e1729ee --- /dev/null +++ b/.github/workflows/docs.yml @@ -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 + diff --git a/.github/workflows/install.yml b/.github/workflows/install.yml deleted file mode 100644 index 26b3df2..0000000 --- a/.github/workflows/install.yml +++ /dev/null @@ -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: - # # 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 diff --git a/.gitignore b/.gitignore index ea23d3b..8abc0d0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /docs/build/ -/env/ \ No newline at end of file +/env/ +/.qlot diff --git a/docs/source/_static/.keep b/README.md similarity index 100% rename from docs/source/_static/.keep rename to README.md diff --git a/TEST.md b/TEST.md deleted file mode 100644 index 8544ec4..0000000 --- a/TEST.md +++ /dev/null @@ -1,8 +0,0 @@ -Before iframe - - - -AFTER diff --git a/cl-info-docs.asd b/cl-info-docs.asd new file mode 100644 index 0000000..57befb9 --- /dev/null +++ b/cl-info-docs.asd @@ -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")) diff --git a/cl-info-test.asd b/cl-info-test.asd index 828f35b..12037fe 100644 --- a/cl-info-test.asd +++ b/cl-info-test.asd @@ -1,12 +1,12 @@ (defsystem cl-info-test - :author "" - :license "" - :class :package-inferred-system - :pathname "t" - :depends-on (:cl-info - "cl-info-test/core") - :description "Test system for cl-info" + :author "" + :license "" + :class :package-inferred-system + :pathname "t" + :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")))) diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index 332cc8b..0000000 --- a/docs/Makefile +++ /dev/null @@ -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 ' where 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." diff --git a/docs/requirements.in b/docs/requirements.in deleted file mode 100644 index ebbb6a1..0000000 --- a/docs/requirements.in +++ /dev/null @@ -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 diff --git a/docs/requirements.txt b/docs/requirements.txt deleted file mode 100644 index 06f074b..0000000 --- a/docs/requirements.txt +++ /dev/null @@ -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 diff --git a/docs/scripts/build.ros b/docs/scripts/build.ros new file mode 100755 index 0000000..fb1df80 --- /dev/null +++ b/docs/scripts/build.ros @@ -0,0 +1,163 @@ +#!/bin/sh +#|-*- mode:lisp -*-|# +#| +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))) diff --git a/docs/source/api.rst b/docs/source/api.rst deleted file mode 100644 index ceeb5a2..0000000 --- a/docs/source/api.rst +++ /dev/null @@ -1,30 +0,0 @@ -===== - API -===== - -Here you can describe an API. - -Use `cldomain's `_ 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 `_ and -write your own beautiful docs! diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst deleted file mode 100644 index 705b295..0000000 --- a/docs/source/changelog.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../ChangeLog.rst diff --git a/docs/source/conf.py b/docs/source/conf.py deleted file mode 100644 index e94b28f..0000000 --- a/docs/source/conf.py +++ /dev/null @@ -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
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 -# " v 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 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' diff --git a/docs/source/docs.lisp b/docs/source/docs.lisp new file mode 100644 index 0000000..907f889 --- /dev/null +++ b/docs/source/docs.lisp @@ -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 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: + + + +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"))))) diff --git a/docs/source/index.rst b/docs/source/index.rst deleted file mode 100644 index e7865df..0000000 --- a/docs/source/index.rst +++ /dev/null @@ -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` - - diff --git a/qlfile b/qlfile new file mode 100644 index 0000000..b91f000 --- /dev/null +++ b/qlfile @@ -0,0 +1 @@ +dist ultralisp http://dist.ultralisp.org diff --git a/qlfile.lock b/qlfile.lock new file mode 100644 index 0000000..5321340 --- /dev/null +++ b/qlfile.lock @@ -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")) diff --git a/src/core.lisp b/src/core.lisp index 1dc254c..6cf43e0 100644 --- a/src/core.lisp +++ b/src/core.lisp @@ -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 - #:get-cl-info - #:system-info - #:get-name - #:get-version - #:get-path - #:absent-p - #:get-system-info)) + (:import-from #:mgl-pax-minimal + #:defsection + #:reader) + (:export #:cl-info + #:get-cl-info + #: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) diff --git a/t/core.lisp b/t/core.lisp index 557a9bb..58e4450 100644 --- a/t/core.lisp +++ b/t/core.lisp @@ -1,12 +1,20 @@ (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) - (contains 1 2)))) + (testing "Replace this test with real staff." + (assert-that (foo 1 2) + (contains 1 2)))) diff --git a/tasks.py b/tasks.py deleted file mode 100644 index 7ddd766..0000000 --- a/tasks.py +++ /dev/null @@ -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)