Archive for May, 2018

esthlos-V Genesis, Or: Who Presses the Pressor?

Wednesday, May 30th, 2018
Edit on 2018-06-07: Modified the below vpatch to include a manifest, per the spec.


This item fulfills the request for a new V implementation.


If you're new here and don't know what V is, I suggest you glance at the canonical introduction by Benjamin Vulpes, and possibly glance my (now outdated by this post) older, flawed vtron.

Credit is due to

  • trinque for overall guidance,
  • phf for providing a mkdtemp interface for ccl,
  • asciilifeform for providing the original V,
  • Diana Coman for helping me get my shit together,

and others for general advice on vtronics and other matters.

Setup and Use

Per-System Configuration

As a user, you must take care to correctly set the global tuning parameters for your system. I've tried to set sensible defaults, but if something doesn't work, you should make sure that these parameters are set correctly. Here are the defaults:

(defparameter *default-vpatch-dir* "./patches/")
(defparameter *default-wot-dir* "./wot/")
(defparameter *default-seal-dir* "./seals/")
(defparameter *default-keyring-dir-location* "./")
(defparameter *default-keyring-dir-template* "gpgXXXXXX")
(defparameter *gpg-location* "/usr/bin/gpg")
(defparameter *patch-location* "/usr/bin/patch")
(defparameter *rm-location* "/bin/rm")


  • default-vpatch-dir is the directory where vpatches are looked for;
  • default-wot-dir is the directory where public keys are looked for;
  • default-seal-dir is the directory where seals are looked for;
  • default-keyring-dir-location is the location where gpg temporary keyring directory generation is attempted;
  • default-keyring-dir-template is the template used to name the temporary keyring directory. It must end with "XXXXXX" (six capital X's);
  • gpg-location is the location of your gpg executable;
  • patch-location is the location of your patch executable; and
  • rm-location is the location of your rm executable.

Note well: strings pointing to directories should end in a forward slash to ensure correct interpretation.

Setup Guide

Setting the thing up is simple:

  1. (n00b step): Ensure the following:
    1. You're on a decent Linux distribution (e.g. Gentoo).
    2. You have gpg 1.4.X installed. (2.x is banned.)
  2. Ensure at least one of the following is installed:
    1. sbcl (tested on version 1.4.4 x86_64).
    2. ccl (tested on version 1.11.5 x86_64).
  3. Press the thing with your current vtron.
  4. Move the files to a convenient location.
  5. Create (and possibly populate) the wot, seals, and vpatch directories.
  6. If you want to run interactively:
    1. In the directory with the files, run sbcl or ccl.
    2. In the REPL, run (load "v.lisp").
    3. Either:
      1. run (in-package "V"); or
      2. preface the main vtron commands with v:, and the internal vtron commands with v::. E.g., (v:flow) or (v::load-vpatches)
  7. If you want run as a portable executable:
    1. Either:
      1. run make sbcl to build with sbcl; or
      2. run make ccl to build with ccl.
    2. Invoke ./v to see your options


Of course, the user of this program is expected to read and understood before use, but you might want to test it, too. I've designed the program so that each piece can be tested independently. Here's something to get you started.

Open up your preferred (any color you like, as long it's sbcl or ccl) REPL, and load in the vtron with (load "v.lisp"). We're going to test the topological sorting capability by creating all directed 6-graphs, and trying to press each one. Exactly one of the graphs has a cycle, and should throw an error.

To make things easier, we will first redefine the vpatch class so that subpatches (patches for individual files) can be added post-instantiation:

(defclass vpatch ()
  ((name :initarg :name :reader name)
   (subpatches :initform '() :initarg :subpatches :accessor subpatches)
   (path :initarg :path :reader path)
   (seals :initarg :seals :reader seals))
  (:documentation "A representation of a vpatch."))

Next, we define a command to spit out three distinct vpatches, and another generally useful routine for establishing the parenthood relation between vpatches:

(defun new-vertex-set ()
  (list (make-instance 'vpatch :name "a")
        (make-instance 'vpatch :name "b")
        (make-instance 'vpatch :name "c")))

(defun set-parent (vpatch-list child parent)
  (let ((filename (symbol-name (gensym)))
        (pre-hash (symbol-name (gensym)))
        (post-hash (symbol-name (gensym)))
        (parent (find-if #'(lambda (vp) (string= parent (name vp)))
        (child (find-if #'(lambda (vp) (string= child (name vp)))
    (cl:setf (subpatches parent)
             (append (subpatches parent)
                     (list (make-instance 'subpatch
                                          :path filename
                                          :pre-hash "false"
                                          :post-hash pre-hash))))
    (cl:setf (subpatches child)
             (append (subpatches child)
                     (list (make-instance 'subpatch
                                          :path filename
                                          :pre-hash pre-hash
                                          :post-hash post-hash))))))

Now the following procedure should, upon evaluation, simply print "Cycle caught correctly.":

(defun make-and-test-3-graphs ()
  (let ((g1) (g2) (g3) (g4) (g5) (g6))
    ;; {}
    (setq g1 (new-vertex-set))

    ;; {(b,a)}
    (setq g2 (new-vertex-set))
    (set-parent g2 "b" "a")

    ;; {(b,a), (c,a)}
    (setq g3 (new-vertex-set))
    (set-parent g3 "b" "a")
    (set-parent g3 "c" "a")

    ;; {(b,a), (a,c)}
    (setq g4 (new-vertex-set))
    (set-parent g4 "b" "a")
    (set-parent g4 "a" "c")

    ;; {(b,a), (c,a), (c,b)}
    (setq g5 (new-vertex-set))
    (set-parent g5 "b" "a")
    (set-parent g5 "c" "a")
    (set-parent g5 "c" "b")

    ;; {(b,a), (a,c), (c,b)}
    (setq g6 (new-vertex-set))
    (set-parent g6 "b" "a")
    (set-parent g6 "a" "c")
    (set-parent g6 "c" "b")

    ;; this should execute without a problem
    (mapcar #'(lambda (vpatch-list)
                (toposort (generate-depgraph vpatch-list)))
            (list g1 g2 g3 g4 g5))

    ;; the error should be caught here
        (toposort (generate-depgraph g6))
      (cyclic () (format t "Cycle caught correctly.")))))

I encourage you to further play with the thing, especially if you believe it's broken in some way.

Concluding Remarks

I'm sure something is broken, so please: read and test!

Regardless, I hope it serves you well.

esthlos-v Prerelease

Thursday, May 17th, 2018

Having made the required changes, this iteration of V is near finished. The program has no problem pressing:

Additional tests have been conducted to ensure that appropriate error conditions are raised when a press should fail.

As far as I'm aware, the only thing left to add is makefile support for Closure Common Lisp, which trinque has agreed to supply.

Get the source, the signature, and the optional makefile. Tests and comments are appreciated.

esthlos-v Version 2

Wednesday, May 9th, 2018

The current intention of the Republic is for my vtron to become the standard for the time being. This post is intended to keep track of the proposed changes to my item, my progress on those changes, and pertinent discussion of the matter.

The latest source will be maintained here,the latest signature here, and the makefile for a executable build here.

ChangeReferencesImplemented On
return vpatch objects12018-05-06
remove dependency on cl-ppcre1 22017-05-13
select run-program by cl implementation1 22018-05-11
take a head to press, not entire patch directory12018-05-06
use a tempdir for gpg keyring (stateless)12018-05-13
complain loudly (eggog) and clearly on bad sig1 2018-05-13
fail on bad public key2018-05-13
error on bad public key2018-05-13
deal with console args12018-05-14
build script to produce binary12018-05-14
remove form feeds1 2 3 2018-05-09
remove tabs12018-05-09