From baa80069893cdcdbc68145d275853a5eab58ebac Mon Sep 17 00:00:00 2001 From: Alexander Artemenko Date: Wed, 19 Jul 2023 22:38:50 +0300 Subject: [PATCH 1/4] Output error information when asdf:load-system signals an error. --- qlfile.lock | 2 +- src/deploy/formula.lisp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/qlfile.lock b/qlfile.lock index 0ffa27b..b678ff7 100644 --- a/qlfile.lock +++ b/qlfile.lock @@ -5,7 +5,7 @@ ("ultralisp" . (:class qlot/source/dist:source-dist :initargs (:distribution "http://dist.ultralisp.org" :%version :latest) - :version "20230714091000")) + :version "20230719154500")) ("quicklisp-quicklisp-client" . (:class qlot/source/ultralisp:source-ultralisp :initargs (:%version "20210216013000") diff --git a/src/deploy/formula.lisp b/src/deploy/formula.lisp index bddc8d0..5b73419 100644 --- a/src/deploy/formula.lisp +++ b/src/deploy/formula.lisp @@ -64,7 +64,8 @@ system \"sbcl\"") (dolist (item (alexandria:ensure-list preload)) - (push (format nil "(handler-case (asdf:load-system :~A) (error () (uiop:quit 1)))" item) + (push (format nil "(handler-case (asdf:load-system :~A) (error () (format *error-output* \"~~A~~%\" e) (uiop:quit 1)))" + item) evals)) (push (format nil "(handler-case (asdf:make :~A) (error () (uiop:quit 1)))" From b17265752ef9471adbd737c54fe9eb9ee731f4c8 Mon Sep 17 00:00:00 2001 From: Alexander Artemenko Date: Sun, 23 Jul 2023 08:52:20 +0300 Subject: [PATCH 2/4] Refactored into separate packages and added documentation. --- .gitignore | 12 +- Changelog.md | 110 ++++++++---- README.md | 354 ++++++++++++++++++++++++++++++++++---- cl-brewer-ci.asd | 11 ++ cl-brewer-docs.asd | 11 ++ cl-brewer-test.asd | 23 --- cl-brewer-tests.asd | 13 ++ cl-brewer.asd | 71 ++------ cl-brewer.rb | 6 +- clpmfile | 24 +++ docs/changelog.lisp | 73 ++++++++ docs/index.lisp | 228 ++++++++++++++++++++++++ qlfile | 3 + qlfile.lock | 6 +- src/buildapp/formula.lisp | 49 ++++++ src/ci.lisp | 42 +++++ src/core.lisp | 19 ++ src/deploy/formula.lisp | 31 +++- src/formula-impl.lisp | 268 +++++++++++++++++++++++++++++ src/formula.lisp | 298 +++++++------------------------- src/hash.lisp | 7 + src/main.lisp | 25 +-- src/package.lisp | 27 --- src/utils.lisp | 21 ++- t/cl-brewer.lisp | 12 -- t/core.lisp | 11 ++ 26 files changed, 1304 insertions(+), 451 deletions(-) create mode 100644 cl-brewer-ci.asd create mode 100644 cl-brewer-docs.asd delete mode 100644 cl-brewer-test.asd create mode 100644 cl-brewer-tests.asd create mode 100644 clpmfile create mode 100644 docs/changelog.lisp create mode 100644 docs/index.lisp create mode 100644 src/buildapp/formula.lisp create mode 100644 src/ci.lisp create mode 100644 src/core.lisp create mode 100644 src/formula-impl.lisp create mode 100644 src/hash.lisp delete mode 100644 t/cl-brewer.lisp create mode 100644 t/core.lisp diff --git a/.gitignore b/.gitignore index cf0c43d..56661ca 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,6 @@ -*.fasl -/bundle-libs/ -/quicklisp/ -/.qlot/ -/sly/ -/cl-brewer-buildapp -/cl-brewer-asdf +.qlot/ +/docs/build/ +*~ +.#* +.*.~undo-tree~ .DS_Store diff --git a/Changelog.md b/Changelog.md index 060fab8..b249eee 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,8 +1,14 @@ -# Changelog + + +# ChangeLog + + ## 0.9.1 (2023-07-14) -Fixed an error happened in case if program does not have any dynamic libs to install into the Cellar. +* Fixed an error happened in case if program does not have any dynamic libs to install into the Cellar. + + ## 0.9.0 (2023-07-14) @@ -13,75 +19,117 @@ Also, dynamic libraries provided by other Homebrew formulas are not copied into the Cellar, instead these formulas are listed as a dependency of the formula, created by cl-homebrew. + + ## 0.8.0 (2019-09-12) * Now cl-brewer suppress debug output of the Deploy's startup process. + * Added a `--version` command line option. + * Fixed creation of dist, local-projects and tmp in the current directory. + + ## 0.7.0 (2019-09-11) -* Added a generic `get-implicit-dependencies` which can be used to specify additional dependencies for systems - when asdf is not possible to figure them out. It can be used like that: - - ``` - (defmethod cl-brewer:get-implicit-dependencies ((system-name (eql :cl-unicode))) - :flexi-streams) - ``` +* Added a generic-function [`cl-brewer:get-implicit-dependencies`][dda5] which can be used to +specify additional dependencies for systems when asdf is not possible to figure them out. + +It can be used like that: - It can return a single keyword or a list of keywords. +``` +(defmethod cl-brewer:get-implicit-dependencies ((system-name (eql :cl-unicode))) + :flexi-streams) +``` +It can return a single keyword or a list of keywords. -## 0.6.0 + + +## 0.6.0 (2019-07-30) * Now cl-brewer can be installed from the Homebrew tap as a binary. -## 0.5.6 + + +## 0.5.6 (2019-07-22) * Fixed arguments list in buildapp's entrypoint. -## 0.5.5 + + +## 0.5.5 (2019-07-22) * Fixed a bug in preloading code on buildapp. -## 0.5.4 + + +## 0.5.4 (2019-07-22) -* Added support for ``--preload`` option. - It allows to embedd Quicklisp client when building a binary for a homebrew. +* Added support for `--preload` option. +It allows to embedd Quicklisp client when building a binary for a homebrew. -## 0.5.3 + + +## 0.5.3 (2019-07-22) * More diagnostics to understand why does not work a binary built by homebrew. -## 0.5.2 + + +## 0.5.2 (2019-07-22) * Added an entry point for buildapp. -## 0.5.1 + + +## 0.5.1 (2019-07-21) -* Kickstarting quicklisp cliend when building cl-brewer. +* Kickstarting quicklisp client when building cl-brewer. -## 0.5.0 + + +## 0.5.0 (2019-07-21) * Now cl-brewer can work with package-inferred asdf systems. + * Previously, some archives were included more than once because they contains multiple systems. Now this is fixed. + * Added option `--compress-core`. It reduces size of a simple - "hello world" from 52M to 13M. + "hello world" from `52M` to `13M`. + * Function `cl-brewer::create-formula` was made external and now can accept system name as a symbol. + * Function `cl-brewer::save-formula` was made external. -* ASDF option `defsystem-depends-on` was supported. -## 0.4.0 +* `ASDF` option `defsystem-depends-on` was supported. + + + +## 0.4.0 (2016-12-17) + +* Provide a way to skip some systems if not found by quicklisp. Right now it's only sb-introspect + + + +## 0.3.0 (2016-11-10) + +* A bit of doc strings. + +* Cli interface. + +* Code was split into multiple files. + + -* 2016-12-17 Provide a way to skip some systems if not found by quicklisp. Right now it's only sb-introspect +## 0.2.0 (2016-11-04) -## 0.3.0 +Initial working functionality. -* 2016-11-10 A bit of doc strings -* 2016-11-08 Cli interface -* 2016-11-08 Code was split into multiple files -## 0.2.0 +[dda5]: https://40ants.com/cl-brewer/#x-28CL-BREWER-3AGET-IMPLICIT-DEPENDENCIES-20GENERIC-FUNCTION-29 -* 2016-11-04 Initial working functionality +* * * +###### [generated by [40ANTS-DOC](https://40ants.com/doc/)] diff --git a/README.md b/README.md index 6ddfdda..277261c 100644 --- a/README.md +++ b/README.md @@ -1,110 +1,388 @@ -# Homebrew formula builder for (command line) common lisp applications + + +# cl-brewer - Homebrew formula builder for Common Lisp applications. + + + +## CL-BREWER ASDF System Details + +* Version: 0.9.1 + +* Description: Homebrew formula builder for Common Lisp applications. + +* Licence: Public Domain + +* Author: Dmitry Petrov + +* Maintainer: Alexander Artemenko + +* Homepage: [https://40ants.com/cl-brewer/][1887] + +* Bug tracker: [https://github.com/40ants/cl-brewer/issues][557c] + +* Source control: [GIT][df7d] + +* Depends on: [alexandria][8236], [cl-plus-ssl-osx-fix][0ce0], [command-line-arguments][bdb0], [ironclad][90b9], [quicklisp][9c78], [trivial-download][923b] + +[![](https://github-actions.40ants.com/40ants/cl-brewer/matrix.svg?only=ci.run-tests)][a54e] + +![](http://quickdocs.org/badge/cl-brewer.svg) + + + +## About Currently there is now easy way to distribute common lisp applications. -One promising way is to use [roswell](https://github.com/roswell/roswell) project +One promising way is to use [roswell][795a] project however it might be to complicated for the users how just want to install an application and are not really interested in having one more package manager for that. -In Mac OS X world the most popular solution is to use brew package manager and all +In Mac `OS` X world the most popular solution is to use brew package manager and all we need is to be able to generate formula that will handle installation proccess. Since homebrew guidelines are not really fond of using third-party managers to get dependencies, we need to generate list manually and feed it to brew. -cl-brewer uses sbcl (default for buildapp) and targets command line applications -written in common lisp. GUI applications haven't been tested and might require additional -changes. +cl-brewer uses `SBCL` and targets command line applications written in Common Lisp. +`GUI` applications haven't been tested and might require additional changes. -This application is based on the awesome [quicklisp-homebrew-roundup](https://github.com/benesch/quicklisp-homebrew-roundup) +This application is based on the awesome [quicklisp-homebrew-roundup][f9c6] but has a purpose to make a process simplier by: * Allowing to generate file for any system available not just quicklisp package (dependencies should be on quicklisp though) + * Allowing to generate a complete formula, not just dependencies -* Having a cli interface that can be used in CI services to generate formulas automatically. + +* Having a cli interface that can be used in `CI` services to generate formulas automatically. At the moment several assumptions were made: -* We can use `buildapp to make executable` -* Formula is generated for the system available for asdf -* All dependencies should be available via quicklisp -* System source code should live on github all releases should be tagged with vX.Y.Z scheme +* We can use [Buildapp][ebe7] or [Deploy][eaea] make executable. + +* Formula is generated for the system available for `ASDF`. + +* All dependencies should be available via quicklisp. + +* System source code should live on github all releases should be tagged with vX.Y.Z scheme. + * System should have description, version, homepage fields defined. Project at GitHub should have a tag corresponding to the current system version. GitHub build a tar.gz archive with sources of the tagged revision and this way a formula, created by cl-brewer, will be able to fetch sources, corresponding to the version. -* Buildapp calls main function. By default namespace is default to system name but can be overridden with option -Here is an [example formula](https://github.com/can3p/homebrew-cl-journal/blob/master/cl-journal.rb) +* [Buildapp][ebe7] calls `main` function. By default `main` function is searched in the + package with the same name as system name but can be overridden with option. -## Install +* When using [Deploy][eaea], you don't have to define an entry point. Also, Deploy is able to + create formulas for applications which build some dynamic libraries. + +Here is an [example formula][cccc] + + + +## Installation ``` brew tap 40ants/soft brew install cl-brewer ``` - Or you can install it using Roswell: ``` # install roswell and sbcl before $ ros install 40ants/cl-brewer ``` +If you want to install it to use from the `REPL`, then you can install this library from Quicklisp, +but you want to receive updates quickly, then install it from Ultralisp.org: +``` +(ql-dist:install-dist "http://dist.ultralisp.org/" + :prompt nil) +(ql:quickload :cl-brewer) +``` + -## Use +## Usage + +Just run: ``` -$ cl-brewer # will emit .rb file in current folder +cl-brewer ``` +This will emit `.rb` file in current folder. + + ## Building a formula for cl-brewer -To kickstart a cl-brewer and to create a formula for itself, load it in the REPL and do like that: +To kickstart a cl-brewer and to create a formula for itself, load it in the `REPL` and do like that: ``` CL-USER> (cl-brewer:create-formula :cl-brewer) # CL-USER> (cl-brewer:save-formula * "cl-brewer" - :entry-point "cl-brewer::buildapp-main" - :preload (list "quicklisp-starter")) - -CL-USER> (cl-brewer:save-formula * "cl-brewer" - :entry-point "cl-brewer::buildapp-main" :preload (list "quicklisp-starter")) Downloading "https://github.com/40ants/cl-brewer/archive/v0.5.5.tar.gz" (Unknown size) NIL ``` - However, in most cases you can just install cl-brewer from the Homebrew. In this case, you can update `cl-brewer's` formula with this command: - qlot exec cl-brewer \ - --preload quicklisp-starter \ - --main cl-brewer::buildapp-main \ - cl-brewer +``` +qlot exec cl-brewer + --preload quicklisp-starter + cl-brewer +``` + -## How to install cl-brewer (or any other project) from a local formula +## Installing From Local Formula -Replace url line in a formula: +How to install cl-brewer (or any other project) from a local formula? - url "https://github.com/40ants/cl-brewer/archive/v0.5.6.tar.gz" +Replace url line in a formula: +``` +url "https://github.com/40ants/cl-brewer/archive/v0.5.6.tar.gz" +``` with two lines like this: - url File.dirname(__FILE__), :using => :git - version "0.5.6-rc1" - +``` +url File.dirname(__FILE__), :using => :git +version "0.5.6-rc1" +``` Next, do this in the shell: - HOMEBREW_NO_AUTO_UPDATE=1 brew install --debug --verbose ./*.rb - +``` +HOMEBREW_NO_AUTO_UPDATE=1 brew install --debug --verbose ./*.rb +``` it should build and install `cl-brewer`. + + ## Contribute If you are interested in using this project but your application has different requirements, please open an issue or make a pull request. Contributions are welcome! + + ## License -All code is public domain except parts that were taken from quicklisp-homebrew-roundup which is under MIT License +All code is public domain except parts that were taken from [quicklisp-homebrew-roundup][f9c6] which is under `MIT` License. + + + +## API + + + +### CL-BREWER + + + +#### [package](1c6a) `cl-brewer` + + + +#### Classes + + + +##### FORMULA + + + +###### [class](c8b9) `cl-brewer:formula` () + +Base class for Homebrew formula definition. + +**Readers** + + + +###### [reader](832f) `cl-brewer/formula:included-systems` (formula) (:included-systems) + + + +###### [reader](6691) `cl-brewer/formula:missing-systems` (formula) (:missing-systems) + + + +###### [reader](a2e1) `cl-brewer/formula:root-system` (formula) (:root-system) + +**Accessors** + + + +###### [accessor](832f) `cl-brewer/formula:included-systems` (formula) (:included-systems) + + + +###### [accessor](6691) `cl-brewer/formula:missing-systems` (formula) (:missing-systems) + + + +###### [accessor](a2e1) `cl-brewer/formula:root-system` (formula) (:root-system) + + + +#### Generics + + + +##### [generic-function](d29c) `cl-brewer:create-formula` system + +Create object based on asdf:system with a list of all dependencies + + + +##### [generic-function](72a2) `cl-brewer:get-implicit-dependencies` system-name + +Some systems, like cl-unicode have implicit dependencies in their asdf methods: +[https://github.com/edicl/cl-unicode/blob/8073fc5634c9d4802888ac03abf11dfe383e16fa/cl-unicode.asd#L67-L70][44a6] +use this method to provide information about such dependencies. + +System name is a keyword and method should return a one keyword or a list of keywords with names of systems. +Each returned system should be possible to find with ql-dist:find-system. + + + +#### Functions + + + +##### [function](7a21) `cl-brewer:save-formula` formula name &key entry-point preload + +Saves Homebrew formula definition into the file with given `NAME`. + +If `ENTRY-POINT` argument was given, then it might be used as entry-point, +but some formula classes like [`cl-brewer/deploy/formula:deploy-formula`][de5a] +might ignore this argument. + +`PRELOAD` argument if given, should be a list of strings with +`ASDF` system names to be preloaded before cl-brewer will build a binary. + + + +### CL-BREWER/BUILDAPP/FORMULA + + + +#### [package](0f5f) `cl-brewer/buildapp/formula` + + + +#### Classes + + + +##### BUILDAPP-FORMULA + + + +###### [class](0e6e) `cl-brewer/buildapp/formula:buildapp-formula` (formula) + +This formula class uses [Buildapp][ebe7] to build a binary. + + + +### CL-BREWER/DEPLOY/FORMULA + + + +#### [package](a5e9) `cl-brewer/deploy/formula` + + + +#### Classes + + + +##### DEPLOY-FORMULA + + + +###### [class](ef84) `cl-brewer/deploy/formula:deploy-formula` (formula) + +This formula class uses [Deploy][eaea] to build a binary. + +The core difference from [`cl-brewer/buildapp/formula:buildapp-formula`][854c] is that +this type of formula also builds and distributes all necessary dynamic libraries. + + + +### CL-BREWER/FORMULA + + + +#### [package](0534) `cl-brewer/formula` + + + +#### Generics + + + +##### [generic-function] `cl-brewer/formula:included-systems` object + + + +##### [generic-function] `cl-brewer/formula:missing-systems` object + + + +##### [generic-function] `cl-brewer/formula:root-system` object + + + +#### Macros + + + +##### [macro](bf6b) `cl-brewer/formula:define-quesser` name (asdf-system) &body body + +Use this macro to define a function to guess a formula class. + +The function should accept a one argument - an `ASDF` system and +return a symbol denoting a class derived from [`formula`][4e9e] class. + +If guesser does not know how to create a formula for the system, +then it should return a `NIL` value. + + +[1887]: https://40ants.com/cl-brewer/ +[854c]: https://40ants.com/cl-brewer/#x-28CL-BREWER-2FBUILDAPP-2FFORMULA-3ABUILDAPP-FORMULA-20CLASS-29 +[de5a]: https://40ants.com/cl-brewer/#x-28CL-BREWER-2FDEPLOY-2FFORMULA-3ADEPLOY-FORMULA-20CLASS-29 +[4e9e]: https://40ants.com/cl-brewer/#x-28CL-BREWER-3AFORMULA-20CLASS-29 +[df7d]: https://github.com/40ants/cl-brewer +[a54e]: https://github.com/40ants/cl-brewer/actions +[0f5f]: https://github.com/40ants/cl-brewer/blob/baa80069893cdcdbc68145d275853a5eab58ebac/src/buildapp/formula.lisp#L1 +[0e6e]: https://github.com/40ants/cl-brewer/blob/baa80069893cdcdbc68145d275853a5eab58ebac/src/buildapp/formula.lisp#L13 +[1c6a]: https://github.com/40ants/cl-brewer/blob/baa80069893cdcdbc68145d275853a5eab58ebac/src/core.lisp#L1 +[a5e9]: https://github.com/40ants/cl-brewer/blob/baa80069893cdcdbc68145d275853a5eab58ebac/src/deploy/formula.lisp#L1 +[ef84]: https://github.com/40ants/cl-brewer/blob/baa80069893cdcdbc68145d275853a5eab58ebac/src/deploy/formula.lisp#L14 +[7a21]: https://github.com/40ants/cl-brewer/blob/baa80069893cdcdbc68145d275853a5eab58ebac/src/formula-impl.lisp#L127 +[0534]: https://github.com/40ants/cl-brewer/blob/baa80069893cdcdbc68145d275853a5eab58ebac/src/formula.lisp#L1 +[bf6b]: https://github.com/40ants/cl-brewer/blob/baa80069893cdcdbc68145d275853a5eab58ebac/src/formula.lisp#L147 +[c8b9]: https://github.com/40ants/cl-brewer/blob/baa80069893cdcdbc68145d275853a5eab58ebac/src/formula.lisp#L21 +[a2e1]: https://github.com/40ants/cl-brewer/blob/baa80069893cdcdbc68145d275853a5eab58ebac/src/formula.lisp#L22 +[6691]: https://github.com/40ants/cl-brewer/blob/baa80069893cdcdbc68145d275853a5eab58ebac/src/formula.lisp#L25 +[832f]: https://github.com/40ants/cl-brewer/blob/baa80069893cdcdbc68145d275853a5eab58ebac/src/formula.lisp#L28 +[d29c]: https://github.com/40ants/cl-brewer/blob/baa80069893cdcdbc68145d275853a5eab58ebac/src/formula.lisp#L34 +[72a2]: https://github.com/40ants/cl-brewer/blob/baa80069893cdcdbc68145d275853a5eab58ebac/src/formula.lisp#L38 +[557c]: https://github.com/40ants/cl-brewer/issues +[f9c6]: https://github.com/benesch/quicklisp-homebrew-roundup +[cccc]: https://github.com/can3p/homebrew-cl-journal/blob/master/cl-journal.rb +[44a6]: https://github.com/edicl/cl-unicode/blob/8073fc5634c9d4802888ac03abf11dfe383e16fa/cl-unicode.asd#L67-L70 +[795a]: https://github.com/roswell/roswell +[8236]: https://quickdocs.org/alexandria +[0ce0]: https://quickdocs.org/cl-plus-ssl-osx-fix +[bdb0]: https://quickdocs.org/command-line-arguments +[90b9]: https://quickdocs.org/ironclad +[9c78]: https://quickdocs.org/quicklisp +[923b]: https://quickdocs.org/trivial-download +[eaea]: https://shinmera.github.io/deploy/ +[ebe7]: https://xach.com/lisp/buildapp/ + +* * * +###### [generated by [40ANTS-DOC](https://40ants.com/doc/)] diff --git a/cl-brewer-ci.asd b/cl-brewer-ci.asd new file mode 100644 index 0000000..4a2a677 --- /dev/null +++ b/cl-brewer-ci.asd @@ -0,0 +1,11 @@ +(defsystem "cl-brewer-ci" + :author "Alexander Artemenko " + :license "Unlicense" + :homepage "https://40ants.com/cl-brewer/" + :class :package-inferred-system + :description "Provides CI settings for cl-brewer." + :source-control (:git "https://github.com/40ants/cl-brewer") + :bug-tracker "https://github.com/40ants/cl-brewer/issues" + :pathname "src" + :depends-on ("40ants-ci" + "cl-brewer-ci/ci")) diff --git a/cl-brewer-docs.asd b/cl-brewer-docs.asd new file mode 100644 index 0000000..b84abbf --- /dev/null +++ b/cl-brewer-docs.asd @@ -0,0 +1,11 @@ +(defsystem "cl-brewer-docs" + :author "Alexander Artemenko " + :license "Unlicense" + :homepage "https://40ants.com/cl-brewer/" + :class :package-inferred-system + :description "Provides documentation for cl-brewer." + :source-control (:git "https://github.com/40ants/cl-brewer") + :bug-tracker "https://github.com/40ants/cl-brewer/issues" + :pathname "docs" + :depends-on ("cl-brewer" + "cl-brewer-docs/index")) diff --git a/cl-brewer-test.asd b/cl-brewer-test.asd deleted file mode 100644 index fbb5131..0000000 --- a/cl-brewer-test.asd +++ /dev/null @@ -1,23 +0,0 @@ -#| -This file is a part of cl-brewer project. -|# - -(in-package :cl-user) -(defpackage cl-brewer-test-asd - (:use :cl :asdf)) -(in-package :cl-brewer-test-asd) - -(defsystem cl-brewer-test - :author "" - :license "" - :depends-on (:cl-brewer - :prove) - :components ((:module "t" - :components - ((:test-file "cl-brewer")))) - :description "Test system for cl-brewer" - - :defsystem-depends-on (:prove-asdf) - :perform (test-op :after (op c) - (funcall (intern #.(string :run-test-system) :prove-asdf) c) - (asdf:clear-system c))) diff --git a/cl-brewer-tests.asd b/cl-brewer-tests.asd new file mode 100644 index 0000000..c4fbd39 --- /dev/null +++ b/cl-brewer-tests.asd @@ -0,0 +1,13 @@ +(defsystem "cl-brewer-tests" + :author "Alexander Artemenko " + :license "Unlicense" + :homepage "https://40ants.com/cl-brewer/" + :class :package-inferred-system + :description "Provides tests for cl-brewer." + :source-control (:git "https://github.com/40ants/cl-brewer") + :bug-tracker "https://github.com/40ants/cl-brewer/issues" + :pathname "t" + :depends-on ("cl-brewer-tests/core") + :perform (test-op (op c) + (unless (symbol-call :rove :run c) + (error "Tests failed")))) diff --git a/cl-brewer.asd b/cl-brewer.asd index bc0bc4c..1d1e133 100644 --- a/cl-brewer.asd +++ b/cl-brewer.asd @@ -1,59 +1,26 @@ -(defsystem cl-brewer - :description "Homebrew formula builder for common lisp applications" +#-asdf3.1 (error "cl-brewer requires ASDF 3.1 because for lower versions pathname does not work for package-inferred systems.") +(defsystem "cl-brewer" + :description "Homebrew formula builder for Common Lisp applications." :author "Dmitry Petrov " - :version "0.9.1" + :maintainer "Alexander Artemenko " :license "Public Domain" - :homepage "https://github.com/40ants/cl-brewer" + :homepage "https://40ants.com/cl-brewer/" :source-control (:git "https://github.com/40ants/cl-brewer") - - :defsystem-depends-on ("deploy") - :build-operation "deploy-op" - :build-pathname "cl-brewer" - :entry-point "cl-brewer::asdf-main" - + :bug-tracker "https://github.com/40ants/cl-brewer/issues" + :class :40ants-asdf-system + :defsystem-depends-on ("40ants-asdf-system" + "deploy") + :pathname "src" :depends-on ("cl-plus-ssl-osx-fix" "quicklisp" - "alexandria" - "ironclad" - "command-line-arguments" - "trivial-download") - :components ((:module "src" - :components - ((:file "package") - (:file "utils") - (:file "formula") - (:file "main") - (:module "deploy" - :components - ((:file "formula")))))) - :long-description - #.(with-open-file (stream (merge-pathnames - #p"README.md" - (or *load-pathname* *compile-file-pathname*)) - :if-does-not-exist nil - :direction :input) - (when stream - (let ((seq (make-array (file-length stream) - :element-type 'character - :fill-pointer t))) - (setf (fill-pointer seq) (read-sequence seq stream)) - seq))) - :in-order-to ((test-op (test-op cl-brewer-test)))) - + "cl-brewer/core" + "cl-brewer/buildapp/formula" + "cl-brewer/deploy/formula" + "cl-brewer/deploy/hooks" + "cl-brewer/main") + :build-operation "deploy-op" + :build-pathname "cl-brewer" + :entry-point "cl-brewer/main::main" -(defsystem "cl-brewer/deploy/hooks" - :description "Hooks for making Shinmera's Deploy work with Homebrew." - :author "Alexander Artemenko " - :version "0.8.2" - :license "Public Domain" - :homepage "https://github.com/40ants/cl-brewer" - :source-control (:git "https://github.com/40ants/cl-brewer") - - :depends-on ("deploy" - "cffi") - :components ((:module "src" - :components - ((:module "deploy" - :components - ((:file "hooks"))))))) + :in-order-to ((test-op (test-op "cl-brewer-tests")))) diff --git a/cl-brewer.rb b/cl-brewer.rb index 9ac06a3..d490024 100644 --- a/cl-brewer.rb +++ b/cl-brewer.rb @@ -1,6 +1,6 @@ class ClBrewer < Formula - desc "Homebrew formula builder for common lisp applications" - homepage "https://github.com/40ants/cl-brewer" + desc "Homebrew formula builder for Common Lisp applications." + homepage "https://40ants.com/cl-brewer/" url "https://github.com/40ants/cl-brewer/archive/v0.9.1.tar.gz" sha256 "38ee7640bca7b015a103b61d8303ed665217bc55ff24fffb5594f8f9e25041a8" head "https://github.com/40ants/cl-brewer" @@ -160,7 +160,7 @@ def install ENV["CL_SOURCE_REGISTRY"] = "#{buildpath}/lib//:#{buildpath}//" ENV["ASDF_OUTPUT_TRANSLATIONS"] = "/:/" - system "sbcl", "--eval", "(require :asdf)", "--eval", "(push :deploy-console *features*)", "--eval", "(asdf:load-system :cl-brewer/deploy/hooks)", "--eval", "(handler-case (asdf:load-system :quicklisp-starter) (error () (uiop:quit 1)))", "--eval", "(handler-case (asdf:make :cl-brewer) (error () (uiop:quit 1)))" + system "sbcl", "--eval", "(require :asdf)", "--eval", "(push :deploy-console *features*)", "--eval", "(asdf:load-system :cl-brewer/deploy/hooks)", "--eval", "(handler-case (asdf:load-system :quicklisp-starter) (error () (format *error-output* "~A~%" e) (uiop:quit 1)))", "--eval", "(handler-case (asdf:load-system :cl-plus-ssl-osx-fix) (error () (format *error-output* "~A~%" e) (uiop:quit 1)))", "--eval", "(handler-case (asdf:make :cl-brewer) (error () (uiop:quit 1)))" system "bash", "-c", "mkdir dyn-libs && find bin/ -name '*.dylib' -exec mv '{}' dyn-libs/ \\;" diff --git a/clpmfile b/clpmfile new file mode 100644 index 0000000..48c25e5 --- /dev/null +++ b/clpmfile @@ -0,0 +1,24 @@ +;;; -*- Mode: common-lisp; -*- +(:api-version "0.4") + +(:source "quicklisp" + :url "https://beta.quicklisp.org/dist/quicklisp.txt" + :type :quicklisp) + +;; Don't move abover quicklisp before this issue +;; will be resolved: +;; https://github.com/ultralisp/ultralisp/issues/197 +(:source "ultralisp" + :url "https://clpi.ultralisp.org/" + :type :clpi) + +;; Does not work because https://dist.ultralisp.org/ultralisp-versions.txt is missing +;; (:source "ultralisp" +;; :url "https://dist.ultralisp.org/ultralisp.txt" +;; :type :quicklisp) + +(:asd "cl-brewer.asd") +(:asd "cl-brewer-tests.asd") +(:asd "cl-brewer-ci.asd") +(:asd "cl-brewer-docs.asd") + diff --git a/docs/changelog.lisp b/docs/changelog.lisp new file mode 100644 index 0000000..7d42678 --- /dev/null +++ b/docs/changelog.lisp @@ -0,0 +1,73 @@ +(uiop:define-package #:cl-brewer-docs/changelog + (:use #:cl) + (:import-from #:40ants-doc/changelog + #:defchangelog)) +(in-package #:cl-brewer-docs/changelog) + + +(defchangelog (:ignore-words ("SLY" + "ASDF" + "REPL" + "52M" + "13M" + "HTTP")) + (0.9.1 2023-07-14 + "* Fixed an error happened in case if program does not have any dynamic libs to install into the Cellar.") + (0.9.0 2023-07-14 + "Now when using Deploy, dynamic libraries copied into the libexec + folder inside Cellar and not symlinked into the /ope/homebrew/bin folder. + + Also, dynamic libraries provided by other Homebrew formulas are not + copied into the Cellar, instead these formulas are listed as a dependency + of the formula, created by cl-homebrew. + ") + (0.8.0 2019-09-12 + "* Now cl-brewer suppress debug output of the Deploy's startup process. + * Added a `--version` command line option. + * Fixed creation of dist, local-projects and tmp in the current directory. +") + (0.7.0 2019-09-11 + "* Added a generic-function CL-BREWER:GET-IMPLICIT-DEPENDENCIES which can be used to + specify additional dependencies for systems when asdf is not possible to figure them out. + + It can be used like that: + + ``` + (defmethod cl-brewer:get-implicit-dependencies ((system-name (eql :cl-unicode))) + :flexi-streams) + ``` + + It can return a single keyword or a list of keywords.") + (0.6.0 2019-07-30 + "* Now cl-brewer can be installed from the Homebrew tap as a binary.") + (0.5.6 2019-07-22 + "* Fixed arguments list in buildapp's entrypoint.") + (0.5.5 2019-07-22 + "* Fixed a bug in preloading code on buildapp.") + (0.5.4 2019-07-22 + "* Added support for `--preload` option. + It allows to embedd Quicklisp client when building a binary for a homebrew.") + (0.5.3 2019-07-22 + "* More diagnostics to understand why does not work a binary built by homebrew.") + (0.5.2 2019-07-22 + "* Added an entry point for buildapp.") + (0.5.1 2019-07-21 + "* Kickstarting quicklisp client when building cl-brewer.") + (0.5.0 2019-07-21 + "* Now cl-brewer can work with package-inferred asdf systems. + * Previously, some archives were included more than once because + they contains multiple systems. Now this is fixed. + * Added option `--compress-core`. It reduces size of a simple + \"hello world\" from 52M to 13M. + * Function `cl-brewer::create-formula` was made external and now + can accept system name as a symbol. + * Function `cl-brewer::save-formula` was made external. + * ASDF option `defsystem-depends-on` was supported.") + (0.4.0 2016-12-17 + "* Provide a way to skip some systems if not found by quicklisp. Right now it's only sb-introspect") + (0.3.0 2016-11-10 + "* A bit of doc strings. + * Cli interface. + * Code was split into multiple files.") + (0.2.0 2016-11-04 + "Initial working functionality.")) diff --git a/docs/index.lisp b/docs/index.lisp new file mode 100644 index 0000000..046844e --- /dev/null +++ b/docs/index.lisp @@ -0,0 +1,228 @@ +(uiop:define-package #:cl-brewer-docs/index + (:use #:cl) + (:import-from #:pythonic-string-reader + #:pythonic-string-syntax) + #+quicklisp + (:import-from #:quicklisp) + (:import-from #:named-readtables + #:in-readtable) + (:import-from #:40ants-doc + #:defsection + #:defsection-copy) + (:import-from #:cl-brewer-docs/changelog + #:@changelog) + (:import-from #:docs-config + #:docs-config) + (:import-from #:40ants-doc/autodoc + #:defautodoc) + (:export #:@index + #:@readme + #:@changelog)) +(in-package #:cl-brewer-docs/index) + +(in-readtable pythonic-string-syntax) + + +(defmethod docs-config ((system (eql (asdf:find-system "cl-brewer-docs")))) + ;; 40ANTS-DOC-THEME-40ANTS system will bring + ;; as dependency a full 40ANTS-DOC but we don't want + ;; unnecessary dependencies here: + #+quicklisp + (ql:quickload "40ants-doc-theme-40ants") + #-quicklisp + (asdf:load-system "40ants-doc-theme-40ants") + + (list :theme + (find-symbol "40ANTS-THEME" + (find-package "40ANTS-DOC-THEME-40ANTS"))) + ) + + +(defsection @index (:title "cl-brewer - Homebrew formula builder for Common Lisp applications." + :ignore-words ("JSON" + "HTTP" + "TODO" + "Unlicense" + "REPL" + "ASDF:PACKAGE-INFERRED-SYSTEM" + "ASDF" + "40A" + "API" + "MIT" + "CI" + "Buildapp" + "GUI" + "SBCL" + "OS" + "URL" + "URI" + "RPC" + "L67-L70" + "GIT")) + (cl-brewer system) + " +[![](https://github-actions.40ants.com/40ants/cl-brewer/matrix.svg?only=ci.run-tests)](https://github.com/40ants/cl-brewer/actions) + +![Quicklisp](http://quickdocs.org/badge/cl-brewer.svg) +" + (@about section) + (@installation section) + (@usage section) + (@building-cl-brewer section) + (@local-install section) + (@contribute section) + (@license section) + (@api section)) + + +(defsection-copy @readme @index) + + +(defsection @about (:title "About" + :external-links (("buildapp" . "https://xach.com/lisp/buildapp/") + ("deploy" . "https://shinmera.github.io/deploy/"))) + " +Currently there is now easy way to distribute common lisp applications. +One promising way is to use [roswell](https://github.com/roswell/roswell) project +however it might be to complicated for the users how just want to install +an application and are not really interested in having one more package manager +for that. + +In Mac OS X world the most popular solution is to use brew package manager and all +we need is to be able to generate formula that will handle installation proccess. +Since homebrew guidelines are not really fond of using third-party managers to +get dependencies, we need to generate list manually and feed it to brew. + +cl-brewer uses SBCL and targets command line applications written in Common Lisp. +GUI applications haven't been tested and might require additional changes. + +This application is based on the awesome [quicklisp-homebrew-roundup](https://github.com/benesch/quicklisp-homebrew-roundup) +but has a purpose to make a process simplier by: + +* Allowing to generate file for any system available not just quicklisp package (dependencies should be on quicklisp though) +* Allowing to generate a complete formula, not just dependencies +* Having a cli interface that can be used in CI services to generate formulas automatically. + +At the moment several assumptions were made: + +* We can use [Buildapp][Buildapp] or [Deploy][deploy] make executable. +* Formula is generated for the system available for ASDF. +* All dependencies should be available via quicklisp. +* System source code should live on github all releases should be tagged with vX.Y.Z scheme. +* System should have description, version, homepage fields defined. Project at GitHub should have a tag corresponding to the + current system version. GitHub build a tar.gz archive with sources of the tagged revision and this way a formula, + created by cl-brewer, will be able to fetch sources, corresponding to the version. +* [Buildapp][buildapp] calls `main` function. By default `main` function is searched in the + package with the same name as system name but can be overridden with option. +* When using [Deploy][deploy], you don't have to define an entry point. Also, Deploy is able to + create formulas for applications which build some dynamic libraries. + +Here is an [example formula](https://github.com/can3p/homebrew-cl-journal/blob/master/cl-journal.rb) +") + + +(defsection @installation (:title "Installation") + """ +``` +brew tap 40ants/soft +brew install cl-brewer +``` + +Or you can install it using Roswell: + +``` +# install roswell and sbcl before +$ ros install 40ants/cl-brewer +``` + +If you want to install it to use from the REPL, then you can install this library from Quicklisp, +but you want to receive updates quickly, then install it from Ultralisp.org: + +``` +(ql-dist:install-dist "http://dist.ultralisp.org/" + :prompt nil) +(ql:quickload :cl-brewer) +``` +""") + + +(defsection @usage (:title "Usage") + " +Just run: + +``` +cl-brewer +``` + +This will emit `.rb` file in current folder. +") + + +(defsection @building-cl-brewer (:title "Building a formula for cl-brewer") + " +To kickstart a cl-brewer and to create a formula for itself, load it in the REPL and do like that: + +``` +CL-USER> (cl-brewer:create-formula :cl-brewer) +# + +CL-USER> (cl-brewer:save-formula * \"cl-brewer\" + :preload (list \"quicklisp-starter\")) +Downloading \"https://github.com/40ants/cl-brewer/archive/v0.5.5.tar.gz\" (Unknown size) +NIL +``` + +However, in most cases you can just install cl-brewer from the Homebrew. In this case, +you can update `cl-brewer's` formula with this command: + +``` +qlot exec cl-brewer \ + --preload quicklisp-starter \ + cl-brewer +``` +") + + +(defsection @local-install (:title "Installing From Local Formula") + " +How to install cl-brewer (or any other project) from a local formula? + +Replace url line in a formula: + +``` +url \"https://github.com/40ants/cl-brewer/archive/v0.5.6.tar.gz\" +``` + +with two lines like this: + +``` +url File.dirname(__FILE__), :using => :git +version \"0.5.6-rc1\" +``` + +Next, do this in the shell: + +``` +HOMEBREW_NO_AUTO_UPDATE=1 brew install --debug --verbose ./*.rb +``` + +it should build and install `cl-brewer`. +") + + +(defsection @contribute (:title "Contribute") + " +If you are interested in using this project but your application has different requirements, +please open an issue or make a pull request. Contributions are welcome! +") + + +(defsection @license (:title "License") + " +All code is public domain except parts that were taken from [quicklisp-homebrew-roundup](https://github.com/benesch/quicklisp-homebrew-roundup) which is under MIT License. +") + + + + +(defautodoc @api (:system "cl-brewer")) diff --git a/qlfile b/qlfile index 9b2f223..19ce199 100644 --- a/qlfile +++ b/qlfile @@ -1,3 +1,6 @@ dist ultralisp http://dist.ultralisp.org ultralisp quicklisp-quicklisp-client 20210216013000 + +# This branch is what I use in my Emacs. +github slynk svetlyak40wt/sly :branch patches diff --git a/qlfile.lock b/qlfile.lock index b678ff7..95de12a 100644 --- a/qlfile.lock +++ b/qlfile.lock @@ -5,8 +5,12 @@ ("ultralisp" . (:class qlot/source/dist:source-dist :initargs (:distribution "http://dist.ultralisp.org" :%version :latest) - :version "20230719154500")) + :version "20230721140501")) ("quicklisp-quicklisp-client" . (:class qlot/source/ultralisp:source-ultralisp :initargs (:%version "20210216013000") :version "ultralisp-20210216013000")) +("slynk" . + (:class qlot/source/github:source-github + :initargs (:repos "svetlyak40wt/sly" :ref nil :branch "patches" :tag nil) + :version "github-030a8441f57f7e0bb401570935e741dfd9edfb83")) diff --git a/src/buildapp/formula.lisp b/src/buildapp/formula.lisp new file mode 100644 index 0000000..3e5d9bd --- /dev/null +++ b/src/buildapp/formula.lisp @@ -0,0 +1,49 @@ +(uiop:define-package #:cl-brewer/buildapp/formula + (:use #:cl) + (:import-from #:cl-brewer/formula + #:name + #:print-dependencies + #:print-build-commands + #:define-quesser) + (:export + #:buildapp-formula)) +(in-package #:cl-brewer/buildapp/formula) + + +(defclass buildapp-formula (formula) + () + (:documentation "This formula class uses [Buildapp](https://xach.com/lisp/buildapp/) to build a binary.")) + + +(define-quesser guess-buildapp-formula (system) + (let* ((build-operation (asdf/component:component-build-operation system))) + (unless (string-equal build-operation + "deploy-op") + 'deploy-formula))) + + +(defmethod print-build-commands ((formula buildapp-formula) + &key (stream t) entry-point preload + &allow-other-keys) + (format stream + " + system \"buildapp\", \"--compress-core\", ") + + (dolist (item (alexandria:ensure-list preload)) + (format stream "\"--load-system\", \"~A\", " item)) + + (format stream + "\"--load-system\", \"~A\", \"--output\", \"~A\", \"--entry\", \"~A\" + + bin.install ~S +" + (name formula) + (name formula) + (if (null entry-point) + (format nil "~a.main" (name formula)) + entry-point) + (name formula))) + + +(defmethod print-dependencies :after ((formula buildapp-formula) &key (stream t)) + (format stream " depends_on \"buildapp\" => :build~%")) diff --git a/src/ci.lisp b/src/ci.lisp new file mode 100644 index 0000000..28af436 --- /dev/null +++ b/src/ci.lisp @@ -0,0 +1,42 @@ +(uiop:define-package #:cl-brewer-ci/ci + (:use #:cl) + (:import-from #:40ants-ci/jobs/linter) + (:import-from #:40ants-ci/jobs/run-tests + #:run-tests) + (:import-from #:40ants-ci/jobs/docs + #:build-docs) + (:import-from #:40ants-ci/workflow + #:defworkflow)) +(in-package #:cl-brewer-ci/ci) + + +(defworkflow linter + :on-push-to "master" + :by-cron "0 10 * * 1" + :on-pull-request t + :cache t + :jobs ((40ants-ci/jobs/linter:linter + :asdf-systems ("cl-brewer" + "cl-brewer-docs" + "cl-brewer-tests")))) + +(defworkflow docs + :on-push-to "master" + :by-cron "0 10 * * 1" + :on-pull-request t + :cache t + :jobs ((build-docs :asdf-system "cl-brewer-docs"))) + + +(defworkflow ci + :on-push-to "master" + :by-cron "0 10 * * 1" + :on-pull-request t + :cache t + :jobs ((run-tests + :asdf-system "cl-brewer" + :lisp ("sbcl-bin" + ;; Issue https://github.com/roswell/roswell/issues/534 + ;; is still reproduces on 2023-02-06: + "ccl-bin/1.12.0") + :coverage t))) diff --git a/src/core.lisp b/src/core.lisp new file mode 100644 index 0000000..0f18943 --- /dev/null +++ b/src/core.lisp @@ -0,0 +1,19 @@ +(uiop:define-package #:cl-brewer + (:use #:cl) + (:nicknames #:cl-brewer/core) + + ;; We need these dependencies to make + ;; sure these packages will be loaded + ;; before we'll try to recycle symbols + ;; from them: + (:import-from #:cl-brewer/formula) + (:import-from #:cl-brewer/formula-impl) + + (:export #:create-formula + #:save-formula + #:get-implicit-dependencies + #:formula) + (:recycle #:cl-brewer + #:cl-brewer/formula + #:cl-brewer/formula-impl)) +(in-package #:cl-brewer) diff --git a/src/deploy/formula.lisp b/src/deploy/formula.lisp index 5b73419..45cb300 100644 --- a/src/deploy/formula.lisp +++ b/src/deploy/formula.lisp @@ -1,4 +1,33 @@ -(in-package #:cl-brewer) +(uiop:define-package #:cl-brewer/deploy/formula + (:use #:cl) + (:import-from #:cl-brewer/formula + #:formula + #:name + #:print-build-commands + #:env-vars + #:print-dependencies + #:define-quesser) + (:export #:deploy-formula)) +(in-package #:cl-brewer/deploy/formula) + + +(defclass deploy-formula (formula) + () + (:documentation "This formula class uses [Deploy](https://shinmera.github.io/deploy/) to build a binary. + + The core difference from CL-BREWER/BUILDAPP/FORMULA:BUILDAPP-FORMULA is that + this type of formula also builds and distributes all necessary dynamic libraries.")) + + +(define-quesser guess-deploy-formula (system) + ;; We support Buildapp or Shinmera's Deploy as a build systems. + ;; + ;; TODO: Probably we also should search and build any Roswell scripts, + ;; found in the ./roswell/ subdirectory. + (let* ((build-operation (asdf/component:component-build-operation system))) + (when (string-equal build-operation + "deploy-op") + 'deploy-formula))) (defun extract-formula-name-from (path) diff --git a/src/formula-impl.lisp b/src/formula-impl.lisp new file mode 100644 index 0000000..39ef907 --- /dev/null +++ b/src/formula-impl.lisp @@ -0,0 +1,268 @@ +(uiop:define-package #:cl-brewer/formula-impl + (:use #:cl) + (:import-from #:trivial-download + #:download) + (:import-from #:ironclad + #:digest-file + #:byte-array-to-hex-string) + (:import-from #:cl-brewer/formula + #:env-vars + #:print-dependencies + #:root-system + #:print-footer + #:print-env-vars + #:print-build-commands + #:missing-systems + #:included-systems + #:repo-head + #:url + #:home-page + #:description + #:name + #:*formula-class-guessers* + #:get-implicit-dependencies + #:create-formula + #:print-header + #:formula) + (:import-from #:cl-brewer/hash + #:sha256) + (:import-from #:cl-brewer/utils + #:rubyize-name)) +(in-package #:cl-brewer/formula-impl) + + +(defparameter +formula-header+ "~: +class ~a < Formula + desc ~S + homepage ~S + url ~S + sha256 ~S + head ~S +") + +(defparameter +formula-footer+ "~: +end +") + + +(defparameter +dependency-body+ "~: + resource ~S do + url ~S + sha256 ~S + end~%~%") + + +;; we skip systems that we know for sure are available +(defparameter +whitelisted-systems+ '("asdf" "sb-introspect")) + + +(defun guess-formula-class (system) + (loop for guesser in *formula-class-guessers* + thereis (funcall guesser system))) + + +(defmethod create-formula ((system string)) + (create-formula (asdf::find-system system))) + +(defmethod create-formula ((system symbol)) + (create-formula (asdf::find-system system))) + +(defmethod create-formula ((system asdf:system)) + (let* ((class (or (guess-formula-class system) + (error "Unable to guess FORMULA class for system ~A." + system))) + (deps (append (asdf:system-depends-on system) + ;; We also need to include build dependencies + ;; into the system. + (asdf:system-defsystem-depends-on system) + (when (eql class 'deploy-formula) + ;; We need this system because these hooks + ;; restore path to dynamic libs: + (list "cl-brewer/deploy/hooks")))) + (root-primary-name (asdf:primary-system-name system)) + (existing-systems) + (missing-systems)) + (labels ((expand-deps (deps) + (dolist (subname deps) + (expand-dep subname))) + (expand-dep (name) + (check-type name string) + + (let* ((primary-name (asdf:primary-system-name name)) + (package-inferred-subsystem-p + (string-equal primary-name + root-primary-name)) + (ql-system (unless package-inferred-subsystem-p + (ql-dist:find-system name))) + (asdf-system (when package-inferred-subsystem-p + (asdf:find-system name)))) + (cond (ql-system + (pushnew ql-system existing-systems + ;; This fixes a problem of duplicate + ;; dependencies. + :test #'string-equal + :key #'ql-dist:name) + (expand-deps (ql-dist:required-systems ql-system)) + (expand-deps (get-implicit-dependencies (ql-dist:name ql-system)))) + ;; If this is asdf package inferred subsystem, + ;; then we don't need to add it as a dependency itself, + ;; but still need to process it's dependencies. + (asdf-system + (expand-deps (asdf:system-depends-on asdf-system)) + (expand-deps (get-implicit-dependencies + (asdf:component-name asdf-system)))) + ;; ignore if whitelisted + ((find name +whitelisted-systems+ :test #'string=) nil) + ;; store as missing if it is not available in Quicklisp + (t + (pushnew name missing-systems + :test #'string-equal)))))) + (dolist (subname deps) (expand-dep subname)) + (make-instance class + :root-system system + :missing-systems (remove-duplicates missing-systems :test #'string=) + :included-systems (remove-duplicates existing-systems))))) + + +(defun save-formula (formula name &key entry-point preload) + "Saves Homebrew formula definition into the file with given NAME. + + If ENTRY-POINT argument was given, then it might be used as entry-point, + but some formula classes like CL-BREWER/DEPLOY/FORMULA:DEPLOY-FORMULA + might ignore this argument. + + PRELOAD argument if given, should be a list of strings with + ASDF system names to be preloaded before cl-brewer will build a binary." + (let* ((output-file (make-pathname :name name :type "rb"))) + (with-open-file (stream output-file + :direction :output + :if-exists :supersede + :if-does-not-exist :create) + (print-formula formula + :stream stream + :entry-point entry-point + :preload preload)))) + + +(defmethod print-object ((obj formula) stream) + (print-unreadable-object (obj stream :type t) + (let ((missing (length (missing-systems obj)))) + (format stream + "~S depends on ~A system~:p~@[ but ~A of them are missing in known dists~]" + (asdf:component-name (root-system obj)) + (length (included-systems obj)) + (when (> missing 0) + missing))))) + + +(defun print-release (release &key (stream t)) + (check-type release ql-dist:release) + (format stream +dependency-body+ + (ql-dist:name release) + (ql-dist::archive-url release) + (sha256 release))) + + +(defun print-formula (formula &key (stream t) entry-point preload) + (check-type formula formula) + (print-header formula :stream stream) + (print-dependencies formula :stream stream) + (print-releases formula :stream stream) + (print-install formula + :stream stream + :entry-point entry-point + :preload preload) + (print-footer formula :stream stream)) + + +(defmethod print-releases ((formula formula) &key stream) + (let* ((systems (included-systems formula)) + ;; We want to print only releases, not systems. + ;; Because one release can contain multiple systems in it's archive. + (releases (loop with result = nil + for system in systems + for release = (ql-dist:release system) + do (pushnew release result + :key #'ql-dist:archive-url + :test #'string-equal) + ;; Also, we want all releases to be sorted. + ;; This way diffs in formula will be minimal. + finally (return (sort result + #'string< + :key (alexandria:compose + #'string-downcase + #'ql-dist:name)))))) + (loop for release in releases + do (print-release release :stream stream)))) + + +(defmethod print-install ((formula formula) &key stream entry-point preload) + (format stream + " def install + resources.each do |resource| + resource.stage buildpath/\"lib\"/resource.name + end +") + (print-env-vars formula :stream stream) + (print-build-commands formula + :stream stream + :entry-point entry-point + :preload preload) + (format stream " end~%")) + + +(defmethod env-vars ((formula formula)) + (list + (cons "CL_SOURCE_REGISTRY" + "#{buildpath}/lib//:#{buildpath}//") + (cons "ASDF_OUTPUT_TRANSLATIONS" + "/:/"))) + + +(defmethod cl-brewer/formula::print-env-vars :before ((formula formula) &key stream) + (terpri stream)) + + +(defmethod cl-brewer/formula::print-env-vars ((formula formula) &key stream) + (loop for (key . value) in (env-vars formula) + do (format stream + " ENV[\"~A\"] = \"~A\"~%" + key value))) + + +(defmethod cl-brewer/formula::print-build-commands ((formula formula) &key stream entry-point preload + &allow-other-keys) + (declare (ignorable formula stream entry-point preload))) + + +(defmethod cl-brewer/formula::print-header ((formula formula) &key stream) + (format stream +formula-header+ + (rubyize-name (name formula)) + (description formula) + (home-page formula) + (url formula) + (sha256 formula) + (repo-head formula))) + + +(defmethod print-footer ((formula formula) &key stream) + (declare (ignorable formula)) + (format stream +formula-footer+)) + + +(defmethod cl-brewer/formula::print-dependencies :around ((formula formula) &key stream) + (format stream "~2&") + (call-next-method) + (format stream "~%")) + + +(defmethod cl-brewer/formula::print-dependencies (formula &key stream) + (format stream " depends_on \"sbcl\" => :build~%")) + + +(defmethod sha256 ((formula formula)) + (let ((fname (make-pathname :directory '(:absolute "tmp") + :name (substitute #\- #\/ (name formula)))) + (url (url formula))) + (download url fname) + (sha256 fname))) diff --git a/src/formula.lisp b/src/formula.lisp index d12dfe9..596848e 100644 --- a/src/formula.lisp +++ b/src/formula.lisp @@ -1,55 +1,43 @@ -(in-package #:cl-brewer) +(uiop:define-package #:cl-brewer/formula + (:use #:cl) + (:import-from #:alexandria + #:ensure-list + #:make-keyword) + (:import-from #:cl-brewer/utils + #:startswith) + (:export #:define-quesser + #:included-systems + #:missing-systems + #:root-system)) +(in-package #:cl-brewer/formula) + + +(defvar *formula-class-guessers* nil + "A list of functions accepting one argument - ASDF system and returning NIL or symbol denoting a class-name of a formula to be created. + + Use DEFINE-GUESSER macro to add items to this list.") + + +(defclass formula () + ((root-system + :initarg :root-system + :accessor root-system) + (missing-systems + :initarg :missing-systems + :accessor missing-systems) + (included-systems + :initarg :included-systems + :accessor included-systems)) + (:documentation "Base class for Homebrew formula definition.")) -(defparameter +formula-header+ "~: -class ~a < Formula - desc ~S - homepage ~S - url ~S - sha256 ~S - head ~S -") - -(defparameter +formula-footer+ "~: -end -") - - -(defparameter +dependency-body+ "~: - resource ~S do - url ~S - sha256 ~S - end~%~%") - - -;; we skip systems that we know for sure are available -(defparameter +whitelisted-systems+ '("asdf" "sb-introspect")) - - -(defun save-formula (formula name &key entry-point preload) - (let* ((output-file (make-pathname :name name :type "rb"))) - (with-open-file (stream output-file - :direction :output - :if-exists :supersede - :if-does-not-exist :create) - (print-formula formula - :stream stream - :entry-point entry-point - :preload preload)))) - (defgeneric create-formula (system) (:documentation "Create object based on asdf:system with a list of all dependencies")) -(defmethod create-formula ((system string)) - (create-formula (asdf::find-system system))) - -(defmethod create-formula ((system symbol)) - (create-formula (asdf::find-system system))) - (defgeneric get-implicit-dependencies (system-name) (:documentation "Some systems, like cl-unicode have implicit dependencies in their asdf methods: -https://github.com/edicl/cl-unicode/blob/8073fc5634c9d4802888ac03abf11dfe383e16fa/cl-unicode.asd#L67-L70 + use this method to provide information about such dependencies. System name is a keyword and method should return a one keyword or a list of keywords with names of systems. @@ -63,216 +51,40 @@ Each returned system should be possible to find with ql-dist:find-system.") (keyword (symbol-name value)) (string value))))) (mapcar #'to-system-name - (alexandria:ensure-list (call-next-method))))) + (ensure-list (call-next-method))))) (:method ((system-name string)) (get-implicit-dependencies (make-keyword (string-upcase system-name)))) (:method ((system-name (eql :cl-unicode))) :flexi-streams)) -(defmethod create-formula (system) - (let* ((build-operation (asdf/component:component-build-operation system)) - ;; We support Buildapp or Shinmera's Deploy as a build systems. - ;; - ;; TODO: Probably we also should search and build any Roswell scripts, - ;; found in the ./roswell/ subdirectory. - (class (cond - ((string-equal build-operation - "deploy-op") - 'deploy-formula) - (t - 'buildapp-formula))) - (deps (append (asdf:system-depends-on system) - ;; We also need to include build dependencies - ;; into the system. - (asdf:system-defsystem-depends-on system) - (when (eql class 'deploy-formula) - ;; We need this system because these hooks - ;; restore path to dynamic libs: - (list "cl-brewer/deploy/hooks")))) - (root-primary-name (asdf:primary-system-name system)) - (existing-systems) - (missing-systems)) - (labels ((expand-deps (deps) - (dolist (subname deps) - (expand-dep subname))) - (expand-dep (name) - (check-type name string) - - (let* ((primary-name (asdf:primary-system-name name)) - (package-inferred-subsystem-p - (string-equal primary-name - root-primary-name)) - (ql-system (unless package-inferred-subsystem-p - (ql-dist:find-system name))) - (asdf-system (when package-inferred-subsystem-p - (asdf:find-system name)))) - (cond (ql-system - (pushnew ql-system existing-systems - ;; This fixes a problem of duplicate - ;; dependencies. - :test #'string-equal - :key #'ql-dist:name) - (expand-deps (ql-dist:required-systems ql-system)) - (expand-deps (get-implicit-dependencies (ql-dist:name ql-system)))) - ;; If this is asdf package inferred subsystem, - ;; then we don't need to add it as a dependency itself, - ;; but still need to process it's dependencies. - (asdf-system - (expand-deps (asdf:system-depends-on asdf-system)) - (expand-deps (get-implicit-dependencies - (asdf:component-name asdf-system)))) - ;; ignore if whitelisted - ((find name +whitelisted-systems+ :test #'string=) nil) - ;; store as missing if it is not available in Quicklisp - (t - (pushnew name missing-systems - :test #'string-equal)))))) - (dolist (subname deps) (expand-dep subname)) - (make-instance class - :root-system system - :missing-systems (remove-duplicates missing-systems :test #'string=) - :included-systems (remove-duplicates existing-systems))))) - - -(defun print-release (release &key (stream t)) - (check-type release ql-dist:release) - (format stream +dependency-body+ - (ql-dist:name release) - (ql-dist::archive-url release) - (sha256 release))) - - -(defun print-formula (formula &key (stream t) entry-point preload) - (check-type formula formula) - (print-header formula :stream stream) - (print-dependencies formula :stream stream) - (print-releases formula :stream stream) - (print-install formula - :stream stream - :entry-point entry-point - :preload preload) - (print-footer formula :stream stream)) - - -(defgeneric print-releases (formula &key stream) - (:method ((formula formula) &key (stream t)) - (let* ((systems (included-systems formula)) - ;; We want to print only releases, not systems. - ;; Because one release can contain multiple systems in it's archive. - (releases (loop with result = nil - for system in systems - for release = (ql-dist:release system) - do (pushnew release result - :key #'ql-dist:archive-url - :test #'string-equal) - ;; Also, we want all releases to be sorted. - ;; This way diffs in formula will be minimal. - finally (return (sort result - #'string< - :key (alexandria:compose - #'string-downcase - #'ql-dist:name)))))) - (loop for release in releases - do (print-release release :stream stream))))) +(defgeneric print-releases (formula &key stream)) (defgeneric print-install (formula &key stream entry-point preload) - (:documentation "Outputs \"install\" method for the formula.") - (:method ((formula formula) &key (stream t) entry-point preload) - (format stream - " def install - resources.each do |resource| - resource.stage buildpath/\"lib\"/resource.name - end -") - (print-env-vars formula :stream stream) - (print-build-commands formula - :stream stream - :entry-point entry-point - :preload preload) - (format stream " end~%"))) + (:documentation "Outputs \"install\" method for the formula.")) (defgeneric env-vars (formula) - (:documentation "Should return an alist with environment variables for \"install\" method of the formula.") - (:method ((formula formula)) - (list - (cons "CL_SOURCE_REGISTRY" - "#{buildpath}/lib//:#{buildpath}//") - (cons "ASDF_OUTPUT_TRANSLATIONS" - "/:/")))) + (:documentation "Should return an alist with environment variables for \"install\" method of the formula.")) (defgeneric print-env-vars (formula &key stream) - (:documentation "Outputs environment variables for \"install\" method of the formula.") - (:method :before ((formula formula) &key (stream t)) - (terpri stream)) - (:method ((formula formula) &key (stream t)) - (loop for (key . value) in (env-vars formula) - do (format stream - " ENV[\"~A\"] = \"~A\"~%" - key value)))) + (:documentation "Outputs environment variables for \"install\" method of the formula.")) (defgeneric print-build-commands (formula &key stream entry-point preload &allow-other-keys) - (:documentation "Outputs build commands for \"install\" method of the formula.") - (:method ((formula formula) &key (stream t) entry-point) - (declare (ignorable formula stream entry-point)))) - - -(defmethod print-build-commands ((formula buildapp-formula) - &key (stream t) entry-point preload - &allow-other-keys) - (format stream - " - system \"buildapp\", \"--compress-core\", ") - - (dolist (item (alexandria:ensure-list preload)) - (format stream "\"--load-system\", \"~A\", " item)) - - (format stream - "\"--load-system\", \"~A\", \"--output\", \"~A\", \"--entry\", \"~A\" - - bin.install ~S -" - (name formula) - (name formula) - (if (null entry-point) - (format nil "~a.main" (name formula)) - entry-point) - (name formula))) - - -(defgeneric print-header (formula &key stream) - (:method ((formula formula) &key (stream t)) - (format stream +formula-header+ - (rubyize-name (name formula)) - (description formula) - (home-page formula) - (url formula) - (sha256 formula) - (repo-head formula)))) - - -(defgeneric print-footer (formula &key stream) - (:method ((formula formula) &key (stream t)) - (declare (ignorable formula)) - (format stream +formula-footer+))) - - -(defgeneric print-dependencies (formula &key stream) - (:method :around ((formula formula) &key (stream t)) - (format stream "~2&") - (call-next-method) - (format stream "~%")) - (:method ((formula formula) &key (stream t)) - (format stream " depends_on \"sbcl\" => :build~%"))) - - -(defmethod print-dependencies :after ((formula buildapp-formula) &key (stream t)) - (format stream " depends_on \"buildapp\" => :build~%")) + (:documentation "Outputs build commands for \"install\" method of the formula.")) + + +(defgeneric print-header (formula &key stream)) + + +(defgeneric print-footer (formula &key stream)) + + +(defgeneric print-dependencies (formula &key stream)) (defun name (formula) @@ -321,6 +133,7 @@ Each returned system should be possible to find with ql-dist:find-system.") version ".tar.gz"))) + (defun repo-head (formula) (let ((source (asdf:system-source-control (root-system formula)))) (typecase source @@ -329,3 +142,18 @@ Each returned system should be possible to find with ql-dist:find-system.") ;; Feel free to add and make a PR: (list (or (getf source :git) ""))))) + + +(defmacro define-quesser (name (asdf-system) &body body) + "Use this macro to define a function to guess a formula class. + + The function should accept a one argument - an ASDF system and + return a symbol denoting a class derived from FORMULA class. + + If guesser does not know how to create a formula for the system, + then it should return a NIL value." + `(progn + (defun ,name (,asdf-system) + ,@body) + (pushnew ',name + *formula-class-guessers*))) diff --git a/src/hash.lisp b/src/hash.lisp new file mode 100644 index 0000000..a35cb27 --- /dev/null +++ b/src/hash.lisp @@ -0,0 +1,7 @@ +(uiop:define-package #:cl-brewer/hash + (:use #:cl)) +(in-package #:cl-brewer/hash) + + +(defgeneric sha256 (obj)) + diff --git a/src/main.lisp b/src/main.lisp index 9855a61..c2bd788 100644 --- a/src/main.lisp +++ b/src/main.lisp @@ -1,4 +1,17 @@ -(in-package :cl-brewer) +(uiop:define-package #:cl-brewer/main + (:use #:cl) + (:import-from #:cl-brewer/formula + #:missing-systems + #:create-formula) + (:import-from #:command-line-arguments + #:show-option-help + #:handle-command-line) + (:import-from #:cl-brewer/formula-impl + #:save-formula) + (:import-from #:cl-brewer/utils + #:split-string)) +(in-package #:cl-brewer/main) + (defparameter +command-line-spec+ '( @@ -10,7 +23,7 @@ :documentation "A comma-separated list of system names to preload before starting a build.") (("help" #\h) :type boolean :optional t - :documentation "Show help message") + :documentation "Show help message") (("version" #\v) :type boolean :optional t :documentation "Show program version"))) @@ -50,14 +63,6 @@ Usage: cl-brewer [options] ~%~%" (get-version)) (setf (symbol-value (intern "*USE-DEDICATED-OUTPUT-STREAM*" (find-package :slynk))) nil) - ;; (setf (symbol-value (intern "*LOG-EVENTS*" - ;; (find-package :slynk))) - ;; t) - (format t "USING COMMUNICATION STYLE: ~A~%" - (symbol-value (intern "*COMMUNICATION-STYLE*" - (find-package :slynk))) - nil) - (uiop:symbol-call :slynk :create-server :port port :interface interface diff --git a/src/package.lisp b/src/package.lisp index 68a7d95..ca3b59d 100644 --- a/src/package.lisp +++ b/src/package.lisp @@ -11,32 +11,5 @@ (in-package #:cl-brewer) -(defclass formula () - ((root-system - :initarg :root-system - :accessor root-system) - (missing-systems - :initarg :missing-systems - :accessor missing-systems) - (included-systems - :initarg :included-systems - :accessor included-systems))) -(defclass buildapp-formula (formula) - ()) - - -(defclass deploy-formula (formula) - ()) - - -(defmethod print-object ((obj formula) stream) - (print-unreadable-object (obj stream :type t) - (let ((missing (length (missing-systems obj)))) - (format stream - "~S depends on ~A system~:p~@[ but ~A of them are missing in known dists~]" - (asdf:component-name (root-system obj)) - (length (included-systems obj)) - (when (> missing 0) - missing))))) diff --git a/src/utils.lisp b/src/utils.lisp index 3214de5..eff1346 100644 --- a/src/utils.lisp +++ b/src/utils.lisp @@ -1,17 +1,16 @@ -(in-package :cl-brewer) +(uiop:define-package #:cl-brewer/utils + (:use #:cl) + (:import-from #:cl-brewer/hash + #:sha256) + (:import-from #:ironclad + #:byte-array-to-hex-string + #:digest-file)) +(in-package #:cl-brewer/utils) -(defgeneric sha256 (formula)) - -(defmethod sha256 ((formula formula)) - (let ((fname (make-pathname :directory '(:absolute "tmp") - :name (substitute #\- #\/ (name formula)))) - (url (url formula))) - (trivial-download:download url fname) - (sha256 fname))) (defmethod sha256 ((path pathname)) - (ironclad:byte-array-to-hex-string - (ironclad:digest-file :sha256 path))) + (byte-array-to-hex-string + (digest-file :sha256 path))) (defmethod sha256 ((release ql-dist:release)) (sha256 (ql-dist:ensure-local-archive-file release))) diff --git a/t/cl-brewer.lisp b/t/cl-brewer.lisp deleted file mode 100644 index a47dfc3..0000000 --- a/t/cl-brewer.lisp +++ /dev/null @@ -1,12 +0,0 @@ -(in-package :cl-user) -(defpackage cl-brewer-test - (:use :cl - :cl-brewer - :prove)) -(in-package :cl-brewer-test) - -;; NOTE: To run this test file, execute `(asdf:test-system :cl-brewer)' in your Lisp. - -(plan nil) - -(finalize) diff --git a/t/core.lisp b/t/core.lisp new file mode 100644 index 0000000..bfd121f --- /dev/null +++ b/t/core.lisp @@ -0,0 +1,11 @@ +(uiop:define-package #:cl-brewer-tests/core + (:use #:cl) + (:import-from #:rove + #:deftest + #:ok + #:testing)) +(in-package #:cl-brewer-tests/core) + + +(deftest test-example () + (ok t "Replace this test with something useful.")) From c52bd003b62f7e6fe6f8ab7fbbae79f049123be6 Mon Sep 17 00:00:00 2001 From: Alexander Artemenko Date: Sun, 23 Jul 2023 08:54:40 +0300 Subject: [PATCH 3/4] Add github actions. --- .github/workflows/ci.yml | 83 ++++++++++++++++++++++++++++++++++ .github/workflows/docs.yml | 74 +++++++++++++++++++++++++++++++ .github/workflows/linter.yml | 86 ++++++++++++++++++++++++++++++++++++ 3 files changed, 243 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/docs.yml create mode 100644 .github/workflows/linter.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..4d06902 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,83 @@ +{ + "name": "CI", + "on": { + "push": { + "branches": [ + "master" + ] + }, + "pull_request": null, + "schedule": [ + { + "cron": "0 10 * * 1" + } + ] + }, + "jobs": { + "run-tests": { + "strategy": { + "fail-fast": false, + "matrix": { + "lisp": [ + "sbcl-bin", + "ccl-bin/1.12.0" + ] + } + }, + "runs-on": "ubuntu-latest", + "env": { + "OS": "ubuntu-latest", + "QUICKLISP_DIST": "quicklisp", + "LISP": "${{ matrix.lisp }}" + }, + "steps": [ + { + "name": "Checkout Code", + "uses": "actions/checkout@v3" + }, + { + "name": "Grant All Perms to Make Cache Restoring Possible", + "run": "sudo mkdir -p /usr/local/etc/roswell\n sudo chown \"${USER}\" /usr/local/etc/roswell\n # Here the ros binary will be restored:\n sudo chown \"${USER}\" /usr/local/bin", + "shell": "bash" + }, + { + "name": "Get Current Month", + "id": "current-month", + "run": "echo \"value=$(date -u \"+%Y-%m\")\" >> $GITHUB_OUTPUT", + "shell": "bash" + }, + { + "name": "Cache Roswell Setup", + "id": "cache", + "uses": "actions/cache@v3", + "with": { + "path": "qlfile\nqlfile.lock\n~/.cache/common-lisp/\n~/.roswell\n/usr/local/etc/roswell\n/usr/local/bin/ros\n/usr/local/Cellar/roswell\n.qlot", + "key": "a-${{ steps.current-month.outputs.value }}-${{ env.cache-name }}-ubuntu-latest-quicklisp-${{ matrix.lisp }}-${{ hashFiles('qlfile.lock', '*.asd') }}" + } + }, + { + "name": "Restore Path To Cached Files", + "run": "echo $HOME/.roswell/bin >> $GITHUB_PATH\n echo .qlot/bin >> $GITHUB_PATH", + "shell": "bash", + "if": "steps.cache.outputs.cache-hit == 'true'" + }, + { + "name": "Setup Common Lisp Environment", + "uses": "40ants/setup-lisp@v2", + "with": { + "asdf-system": "cl-brewer" + }, + "if": "steps.cache.outputs.cache-hit != 'true'" + }, + { + "name": "Run Tests", + "uses": "40ants/run-tests@v2", + "with": { + "asdf-system": "cl-brewer", + "coveralls-token": "\n${{ matrix.lisp == 'sbcl-bin' &&\n matrix.os == 'ubuntu-latest' &&\n matrix.quicklisp == 'ultralisp' &&\n secrets.github_token }}" + } + } + ] + } + } +} \ No newline at end of file diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..7e9b935 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,74 @@ +{ + "name": "DOCS", + "on": { + "push": { + "branches": [ + "master" + ] + }, + "pull_request": null, + "schedule": [ + { + "cron": "0 10 * * 1" + } + ] + }, + "jobs": { + "build-docs": { + "runs-on": "ubuntu-latest", + "env": { + "OS": "ubuntu-latest", + "QUICKLISP_DIST": "quicklisp", + "LISP": "sbcl-bin" + }, + "steps": [ + { + "name": "Checkout Code", + "uses": "actions/checkout@v3" + }, + { + "name": "Grant All Perms to Make Cache Restoring Possible", + "run": "sudo mkdir -p /usr/local/etc/roswell\n sudo chown \"${USER}\" /usr/local/etc/roswell\n # Here the ros binary will be restored:\n sudo chown \"${USER}\" /usr/local/bin", + "shell": "bash" + }, + { + "name": "Get Current Month", + "id": "current-month", + "run": "echo \"value=$(date -u \"+%Y-%m\")\" >> $GITHUB_OUTPUT", + "shell": "bash" + }, + { + "name": "Cache Roswell Setup", + "id": "cache", + "uses": "actions/cache@v3", + "with": { + "path": "qlfile\nqlfile.lock\n~/.cache/common-lisp/\n~/.roswell\n/usr/local/etc/roswell\n/usr/local/bin/ros\n/usr/local/Cellar/roswell\n.qlot", + "key": "a-${{ steps.current-month.outputs.value }}-${{ env.cache-name }}-ubuntu-latest-quicklisp-sbcl-bin-${{ hashFiles('qlfile.lock', '*.asd') }}" + } + }, + { + "name": "Restore Path To Cached Files", + "run": "echo $HOME/.roswell/bin >> $GITHUB_PATH\n echo .qlot/bin >> $GITHUB_PATH", + "shell": "bash", + "if": "steps.cache.outputs.cache-hit == 'true'" + }, + { + "name": "Setup Common Lisp Environment", + "uses": "40ants/setup-lisp@v2", + "with": { + "asdf-system": "cl-brewer-docs" + }, + "if": "steps.cache.outputs.cache-hit != 'true'" + }, + { + "name": "Build Docs", + "uses": "40ants/build-docs@v1", + "with": { + "asdf-system": "cl-brewer-docs", + "error-on-warnings": true + } + } + ] + } + } +} \ No newline at end of file diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml new file mode 100644 index 0000000..37b5dc9 --- /dev/null +++ b/.github/workflows/linter.yml @@ -0,0 +1,86 @@ +{ + "name": "LINTER", + "on": { + "push": { + "branches": [ + "master" + ] + }, + "pull_request": null, + "schedule": [ + { + "cron": "0 10 * * 1" + } + ] + }, + "jobs": { + "linter": { + "runs-on": "ubuntu-latest", + "env": { + "OS": "ubuntu-latest", + "QUICKLISP_DIST": "quicklisp", + "LISP": "sbcl-bin" + }, + "steps": [ + { + "name": "Checkout Code", + "uses": "actions/checkout@v3" + }, + { + "name": "Grant All Perms to Make Cache Restoring Possible", + "run": "sudo mkdir -p /usr/local/etc/roswell\n sudo chown \"${USER}\" /usr/local/etc/roswell\n # Here the ros binary will be restored:\n sudo chown \"${USER}\" /usr/local/bin", + "shell": "bash" + }, + { + "name": "Get Current Month", + "id": "current-month", + "run": "echo \"value=$(date -u \"+%Y-%m\")\" >> $GITHUB_OUTPUT", + "shell": "bash" + }, + { + "name": "Cache Roswell Setup", + "id": "cache", + "uses": "actions/cache@v3", + "with": { + "path": "qlfile\nqlfile.lock\n~/.cache/common-lisp/\n~/.roswell\n/usr/local/etc/roswell\n/usr/local/bin/ros\n/usr/local/Cellar/roswell\n.qlot", + "key": "a-${{ steps.current-month.outputs.value }}-${{ env.cache-name }}-ubuntu-latest-quicklisp-sbcl-bin-${{ hashFiles('qlfile.lock', '*.asd') }}" + } + }, + { + "name": "Restore Path To Cached Files", + "run": "echo $HOME/.roswell/bin >> $GITHUB_PATH\n echo .qlot/bin >> $GITHUB_PATH", + "shell": "bash", + "if": "steps.cache.outputs.cache-hit == 'true'" + }, + { + "name": "Setup Common Lisp Environment", + "uses": "40ants/setup-lisp@v2", + "with": { + "asdf-system": "cl-brewer" + }, + "if": "steps.cache.outputs.cache-hit != 'true'" + }, + { + "name": "Change dist to Ultralisp if qlfile does not exist", + "run": "if [[ ! -e qlfile ]]; then echo 'dist ultralisp http://dist.ultralisp.org' > qlfile; fi", + "shell": "bash" + }, + { + "name": "Update Qlot", + "run": "qlot update --no-deps", + "shell": "bash" + }, + { + "name": "Install SBLint wrapper", + "run": "qlot exec ros install 40ants-asdf-system 40ants-linter", + "shell": "bash" + }, + { + "name": "Run Linter", + "run": "qlot exec 40ants-linter --system \"cl-brewer, cl-brewer-docs, cl-brewer-tests\"", + "shell": "bash" + } + ] + } + } +} \ No newline at end of file From 40d67a2f305b4602b4969c8e1021fdb9592985ca Mon Sep 17 00:00:00 2001 From: Alexander Artemenko Date: Sun, 23 Jul 2023 19:59:59 +0300 Subject: [PATCH 4/4] Ignore a few symbols. --- docs/index.lisp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/index.lisp b/docs/index.lisp index 046844e..6dc1584 100644 --- a/docs/index.lisp +++ b/docs/index.lisp @@ -226,3 +226,11 @@ All code is public domain except parts that were taken from [quicklisp-homebrew- (defautodoc @api (:system "cl-brewer")) + + +(eval-when (:compile-toplevel :load-toplevel :execute) + (loop for symbol in '(cl-brewer/formula:included-systems + cl-brewer/formula:missing-systems + cl-brewer/formula:root-system) + do (pushnew symbol + 40ants-doc:*symbols-with-ignored-missing-locations*)))