cl-micropm

A very minimalist, decentralized "package manager" for Common Lisp (<200 LOC)
Log | Files | Refs | Submodules | README | LICENSE

commit 3835e76dbdfc9fb1c39a1416bbbc64412e432f77
parent 28b75f8e64f9f951240b4f7fea98f4b3b29c79f6
Author: Risto Stevcev <me@risto.codes>
Date:   Sun, 10 Sep 2023 18:21:09 +0200

Fixed get-depdenencies and updated README

Diffstat:
MREADME.md | 139+++++++++++++------------------------------------------------------------------
Mcl-micropm.lisp | 48++++--------------------------------------------
2 files changed, 26 insertions(+), 161 deletions(-)

diff --git a/README.md b/README.md @@ -1,81 +1,40 @@ # cl-micropm -A very minimalist "package manager" for Common Lisp. +A very minimalist "package manager" for Common Lisp in under 200 LOC. -## Install - -Make sure that you have docker installed on your system and that your user has permissions (is in -the `docker` group) - -Fetch the single-file executable from git and add the permissions: - -``` sh -curl -LO https://github.com/Risto-Stevcev/cl-micropm/raw/main/micropm-get -chmod +x ./micropm-get -``` - -Then you can also move the file into a path that your system can find, ie: - -``` sh -sudo mv ./micropm-get /usr/local/bin/ -``` - - -## Usage - - -### Defining a system - -A system is how you set up your project to be used as a library to the rest of the world, similar to -NodeJS packages. An `asd` file (ie `monty-hall.asd`) is a system file, similar to NodeJS' -`package.json`. - -The library that's used to interact with systems is called the -[ASDF](https://common-lisp.net/project/asdf/asdf/) build system, and it's already included in most -Common Lisp compilers. If it's included with the Common Lisp compiler that you're using, but for -some reason you can't call asdf commands, then you may neet to also import it for it to be -available: `(require 'asdf)`. - -Here is an example of a system definition for a project called monty-hall in a file -`monty-hall.asd`: - -``` common-lisp -;; monty-hall.asd -(asdf:defsystem :monty-hall - :version "0.1.0" - :description "Monty hall problem simulator" - :author "Risto Stevcev <me@risto.codes>" - :serial t - :license "GNU GPL, version 3" - :components ((:file "monty-hall")) - :depends-on (#:alexandria #:arrow-macros)) -``` +## How it works -The first argument after the `defsystem` call is the name of the system (`:monty-hall`). It's then a -plist of various metadata about the project, as well as dependencies to foreign libraries, like -`#:alexandria` and ` #:arrow-macros`. You can view available libraries at -[quickref](https://quickref.common-lisp.net/index-per-library.html). +1. Load `cl-micropm.lisp`. Since it's a single file, you don't need to have ASDF + load the system definition, but it's there if you need it. -In this case, system with the name `monty-hall`, you can get the dependencies by passing in the -system name like this: +2. Run `(micropm:setup <your-system-name>)`. It doesn't directly use quicklisp, + but this will fetch the quicklisp system sources and build the quicklisp + dependency index, and then fetch the system dependencies using these data. By + default, it will create git submodules in the `lisp-systems` folder. -```sh -$ micropm-get monty-hall -``` +3. Tweak the `lisp-systems` to your needs, whether you need to freeze a + dependency on a particular branch or commit, etc. -They'll be saved in the project-local `lisp-systems` folder. +Once all your deps are setup in `lisp-systems`, you can just run the normal +flow with `(micropm:setup-asdf-registry)`. -Then just make sure to set `CL_SOURCE_REGISTRY` to point to that directory, like this -[.envrc](./envrc), which gets copied by default `.envrc` when installing deps. +You can also skip `(micropm:setup <your-system-name>)` and just manually add the +deps into `lisp-systems` if you want to do that, by reading the quicklisp +dependency index. -Or optionally, use [direnv](direnv.net/) and just copy the [.envrc](./envrc), and it will -load/unload the environment variable for all of your common lisp projects! +**Note**: The old version used an `.envrc` file and pulled the dependencies from +quicklisp in a Docker container. See the `old` branch if you want to use that +instead. ## Goals +- It should be loadable as a single file. +- The code should be easily auditable and readable, and therefore small in size + (< 200 LOCs). +- It should be decentralized. No quicklisp or ultralisp, just git, http(s), etc. - Dependendies should not be global, each project may have a local version that's different and may want to pin that version. - It should be easy to work on projects that use different versions of a package, maybe even at the @@ -86,60 +45,6 @@ load/unload the environment variable for all of your common lisp projects! -## How it works - -1. Fetch the entire dependency graph using quicklisp and copy it into the project-local - `lisp-systems` folder -2. Set the `CL_SOURCE_REGISTRY` env file to point to the project-local `lisp-systems` folder - - -This way it's easy to set up, it's easy to understand what it's doing, and it's possible to freeze -or update each package individually without too much hassle. It *is* using quicklisp, but not -really -- it's only using it to fetch the dependency graph into a local folder, the rest is just -managed by asdf. Note that quicklisp isn't installed, it's entirely run via an ephemeral docker -container that gets unloaded once the dependencies are fetched. Once it's known which deps are used, -it could be updated via other means like directly cloning dependencies from a git repo or using -ultralisp. - - -## Slimv - -Slimv doesn't seem to set env vars: - -```lisp -CL-USER> (uiop:getenv "CL_SOURCE_REGISTRY") -NIL -``` - -Which means that `asdf` won't be able to find your systems. - -A hacky workaround: - -```sh -$ echo $CL_SOURCE_REGISTRY -/home/risto/git/lisp/lqlite/:/home/risto/git/lisp/lqlite/lisp-systems// -``` - -```lisp -CL-USER> (setf (uiop:getenv "CL_SOURCE_REGISTRY") "/home/risto/git/lisp/lqlite/:/home/risto/git/lisp/lqlite/lisp-systems//") -"/home/risto/git/lisp/lqlite/:/home/risto/git/lisp/lqlite/lisp-systems//" -CL-USER> (uiop:getenv "CL_SOURCE_REGISTRY") -"/home/risto/git/lisp/lqlite/:/home/risto/git/lisp/lqlite/lisp-systems//" -CL-USER> (asdf:clear-source-registry) -; No value -CL-USER> (asdf:ensure-source-registry) -; No value -CL-USER> (asdf:load-system :alexandria) -T -``` - - -## Roadmap - -- Support Ultralisp -- Self-destruct/uninstall command - - ## License See [LICENSE](./LICENSE) diff --git a/cl-micropm.lisp b/cl-micropm.lisp @@ -30,8 +30,6 @@ (ignore-errors (clone-dependencies dependency-name *systems-alist*))) (clone-dependencies dependency-name *systems-alist*)))) -#+nil(init "micropm") - (defun setup-asdf-registry () "Initializes the ASDF registry with the existing dependencies in *lisp-systems-dir*" (setf asdf:*central-registry* (cons (uiop:getcwd) (list-lisp-systems-paths)))) @@ -56,24 +54,8 @@ (map 'list (lambda (source) (uiop:split-string source :separator " ")) (uiop:read-file-lines system-source)))) -#+nil(fetch-system-quicklisp-source "xmls") - (defvar *quicklisp-container-name* "quicklisp") -#+nil(define-condition progress (condition) - ((topic :initarg :topic) - (msg :initarg :msg))) - -#+nil(defmacro with-progress (&body body) - `(handler-bind - ((progress #'(lambda (condition) - (with-slots (topic msg) condition - (format t "~&* ~a: ~a" topic msg)) - (continue)))) - (progn ,@body))) - -#+nil(with-progress (build-quicklisp-image)) - (defconstant *dockerfile* "FROM debian:bullseye-slim RUN apt-get update && apt-get install -y sbcl curl gnupg @@ -134,8 +116,6 @@ RUN sbcl --non-interactive \\ when (and (eql (first x) (second x)) (eql (first x) (third x))) collect (cddr x)))) -#+nil(defvar *systems-alist* (generate-quicklisp-index)) - (defun micropm::get-deps (system alist) "Recursively finds all of the dependencies for the system" (let* ((system-name (intern (string-upcase system))) @@ -150,26 +130,10 @@ RUN sbcl --non-interactive \\ (defun get-dependencies (system systems-alist) (let ((system-name (intern (string-upcase system)))) (loop for x in (get-deps system-name systems-alist) - when (not (member x `(,system-name uiop asdf))) collect x))) - -#+nil(get-dependencies 'cffi *systems-alist*) - -#+nil(defconstant +source-types+ - '(branched-git - cvs - darcs - ediware-http - git - http - https - kmr-git - latest-github-release - latest-github-tag - latest-gitlab-release - mercurial - single-file - svn - tagged-git)) + when (not (member-if + (lambda (e) (equal (symbol-name x) e)) + `(,(string-upcase system) "UIOP" "ASDF"))) + collect x))) (defun get-source-type (source) (first source)) @@ -233,7 +197,3 @@ RUN sbcl --non-interactive \\ "Lists the paths of the dependencies in lisp-systems" (let ((dir (uiop:merge-pathnames* *lisp-systems-dir* (uiop:getcwd)))) (uiop:subdirectories dir))) - -#+nil(push - (uiop:strcat (uiop:native-namestring (uiop:getcwd)) "lisp-systems/babel/") - asdf:*central-registry*)