pub const LOCK: &str = "; Resolve `naj.deps` into `naj.lock`: the impure half of the module system, and\n; the only part of narju that reaches the network. It runs when asked and writes\n; a file; everything after reads that file and no more, which is what lets a\n; program be built with no network. The same split `nix flake lock` makes.\n\n; A field of a `naj.deps` entry, or `fallback` where it has none. The manifest\n; carries no version marker, being written by hand; the lock has one because a\n; program reads it and must be able to refuse a format it does not know.\n(define (dep-field entry name fallback)\n (let ((f (assq name entry)))\n (if (pair? f) (cadr f) fallback)))\n\n; The resolved revision is what gets written down, so naming a branch is a\n; request to pin what it points at now and not a request to track it.\n(define (resolve entry)\n (call \'(host modules)\n `(fetch ,(lock-field entry \'url) ,(dep-field entry \'ref \"HEAD\"))))\n\n(define (cat parts) (join \"\" parts))\n\n(define (quoted s) (cat (list \"\\\"\" s \"\\\"\")))\n\n(define (field name value) (cat (list \"(\" name \" \" (quoted value) \")\")))\n\n; Both `url` and `path` are written because they have different readers: nix\n; fetches with the first and lays out with the second, and `need` only joins the\n; second. Neither is derived from the other downstream.\n(define (entry-text name entry at where)\n (cat (list \" (\" (sym->str name) \"\\n\"\n \" \" (field \"url\" (lock-field entry \'url)) \"\\n\"\n \" \" (field \"rev\" at) \"\\n\"\n \" \" (field \"path\" where) \"\\n\"\n \" \" (field \"file\" (lock-field entry \'file)) \")\")))\n\n; Written rather than printed: `show` writes a symbol as `\'a`, which reads back\n; as a two-element list.\n(define (lock-text parts)\n (cat (list \"((narju-lock 1)\\n (modules\\n\" (join \"\\n\" parts) \"))\\n\")))\n\n; Answered as `(name entry rev path)`. Sequential because a fetch is an RPC and\n; the world runs whatever else it holds while this task is parked.\n(define (walk entries)\n (if (nil? entries)\n \'()\n (let (((name . entry) (car entries)))\n (let ((got (resolve entry)))\n (let ((at (car got)) (where (cadr got)))\n (begin\n (say (cat (list \" \" (sym->str name) \" \" at)))\n (cons (list name entry at where) (walk (cdr entries)))))))))\n\n(define root (call \'(host files) \'(root)))\n\n; A module carrying no lock has no dependencies, which is an ordinary thing to\n; be, so the missing file is the answer rather than a raise.\n(define (deps-of dir)\n (let ((got (attempt (lambda ()\n (call \'(host files)\n `(read ,(join \"/\" (list dir \"naj.lock\"))))))))\n (if (eq? (car got) \'ok)\n (cdr (assq \'modules (read-lock (cdr got))))\n \'())))\n\n; Everything reachable, fetched. Nothing is *merged*: each of these was already\n; locked by the repository that named it, so this fetches by exact revision and\n; cannot find a conflict - the closure is a graph walk rather than a solver.\n;\n; Keyed on `path/rev` rather than on a name, since a name means only what the\n; lock that used it meant.\n(define (close entries seen)\n (if (nil? entries)\n seen\n (let (((name . e) (car entries)))\n (let ((at (join \"/\" (list (lock-field e \'path) (lock-field e \'rev)))))\n (if (member? at seen)\n (close (cdr entries) seen)\n (begin\n (call \'(host modules)\n `(fetch ,(lock-field e \'url) ,(lock-field e \'rev)))\n (say (cat (list \" \" at)))\n (close (cdr entries)\n (close (deps-of (join \"/\" (list root at)))\n (cons at seen)))))))))\n\n(define (close-all got seen)\n (if (nil? got)\n seen\n (let (((name entry at where) (car got)))\n (close-all (cdr got)\n (close (deps-of (join \"/\" (list root where at))) seen)))))\n\n(define (texts got)\n (if (nil? got)\n \'()\n (let (((name entry at where) (car got)))\n (cons (entry-text name entry at where) (texts (cdr got))))))\n\n(define deps (car (read (call \'(host files) \'(read \"naj.deps\")))))\n\n(define resolved (walk deps))\n\n(define text (lock-text (texts resolved)))\n\n(begin\n (close-all resolved \'())\n (call \'(host disk) `(write \"naj.lock\" ,text))\n (say \"wrote naj.lock\"))\n";Expand description
Resolves naj.deps into naj.lock. An object program for the same reason
the prompt is one: everything it needed was already a capability.