~/bend-docscommunity

src/lock/run.bend fails

raw source on the hub · import 0x74799d3f846634a3d7461d4336d7c9d4/src/lock/run.bend as Run

lock/run: the interpreter for ez lock. It reads the ledger and the committed sources into a World, then loops: it asks the planner (lock/plan.bend) what is still open, answers each question by IO, and adds the answers to the World, until nothing is left to ask. Then it runs the planner's plan. It decides nothing: which packages to read, whether their bytes are the ones the ledger names, where an upgrade moves a pin, and what is written are the planner's. That it reads and executes faithfully is EZ-TRUST-2. It answers a name's question by asking the hub once, and the lock's by reading ez.lock.toml. Under --upgrade it also answers the upgrade's questions (lock/up.bend): what git prints for refs, the default branch and tags, ancestry, checkouts at a rev, the hub's manifest for a moved hash, .gitignore, and the project's sources. A new checkout's package is walked from its entry here, by K.pkg_of, which is interpreter code under EZ-TRUST-2 until ez add is converted.

15 imports
import Base
import 0xabe575924687afad4cee1a2c1194d639/main.bend as R
import ../io/file.bend as F
import ../hub/hub.bend as Web
import ../hub/get.bend as Net
import ../git/git.bend as Git
import ../git/exec.bend as GX
import ../pkg/pkg.bend as K
import ../pkg/path.bend as P
import ../share/say.bend as Say
import ../share/spin.bend as Spin
import ./lock.bend as L
import ./world.bend as W
import ./up.bend as Up
import ./plan.bend as Plan

Definitions

def env.text source · line 35 · raw

@res:Result<&1, &1, Pair(U32, String), String> -> String

an environment variable's text; unset, ""

def lib.or source · line 43 · raw

@+dir:String -> String

where packages live, which is with the project rather than in ~/.bend/lib

def bend.lib source · line 47 · raw

IO(String)

the BEND_LIB this project pins

def nonempty source · line 53 · raw

@ss:List<&2, String> -> List<&2, String>

the non-empty lines

def read.ledger source · line 62 · raw

IO(Maybe<&2, String>)

the ledger's text, or None when there is no ez.toml

def read.all source · line 66 · raw

@ps:List<&2, String> -> IO(List<&2, 0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Source>)

every listed path, read

def listed source · line 77 · raw

@ok:Bool -> @+text:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Listing)

what git listed, or why it could not

def read.listing source · line 90 · raw

IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Listing)

every .bend file git tracks under the current directory, with its text. Untracked files are not a clone's, so they are not the lock's.

def gots source · line 100 · raw

@+how:0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.How -> @+manifest:String -> @gs:List<&2, 0x74799d3f846634a3d7461d4336d7c9d4/src/hub/hub.Got> -> @acc:List<&2, String> -> 0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Answer

every text a fetch answered, or the first miss

def hub.all source · line 112 · raw

@+hub:String -> @+hash:String -> @fs:List<&2, 0x74799d3f846634a3d7461d4336d7c9d4/src/pkg/pkg.Item> -> IO(List<&2, 0x74799d3f846634a3d7461d4336d7c9d4/src/hub/hub.Got>)

every file of a hub package, fetched and checked against its sum

def hub.got source · line 123 · raw

@got:0x74799d3f846634a3d7461d4336d7c9d4/src/hub/hub.Got -> @+hub:String -> @+hash:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Answer)

a hub package's files, once its manifest arrived

def answer.hub source · line 133 · raw

@+hub:String -> @+hash:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Answer)

a hub package: its manifest, then every file it names

def disk.all source · line 143 · raw

@+dir:String -> @fs:List<&2, 0x74799d3f846634a3d7461d4336d7c9d4/src/pkg/pkg.Item> -> IO(List<&2, String>)

every file a tree's manifest names, read from beside it. A file that is not there reads as "", which does not hash to its sum.

def answer.lib source · line 154 · raw

@+dir:String -> @+manifest:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Answer)

a tree under BEND_LIB, as it is

def clone.miss source · line 161 · raw

@+work:String -> @+why:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Answer)

a checkout that could not be made or read is removed, and the question is answered with why

def clone.ran source · line 168 · raw

@ok:Bool -> @+work:String -> @+why:String -> @go:(@_:Unit -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Answer)) -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Answer)

a command of a clone that worked goes on with the clone; one that failed ends it

def clone.run source · line 176 · raw

@+work:String -> @what:String -> @args:List<&2, String> -> @go:(@_:Unit -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Answer)) -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Answer)

one git command of a clone, and the rest of the clone when it worked

def clone.walk source · line 182 · raw

@+work:String -> @+entry:String -> @+nar:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Answer)

the checkout's package, walked from its entry the way ez add walked it

def clone.entry source · line 191 · raw

@ok:Bool -> @+work:String -> @+entry:String -> @+url:String -> @+rev:String -> @+nar:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Answer)

the entry has to be in the checkout for there to be a package to walk

def clone.weigh source · line 199 · raw

@+work:String -> @+url:String -> @+rev:String -> @+entry:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Answer)

the checkout, weighed and walked

def answer.clone source · line 212 · raw

@+lib:String -> @+hash:String -> @+url:String -> @+rev:String -> @+entry:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Answer)

a git package whose tree is not under BEND_LIB: a shallow clone at the rev the ledger pins, the way ez add and ez fetch clone, from the source the question names, which the planner anchored at the project root. Nothing is laid here; the plan lays the tree once it has checked it.

def git.seen source · line 226 · raw

@got:Maybe<&2, String> -> @+lib:String -> @+hash:String -> @+url:String -> @+rev:String -> @+entry:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Answer)

a tree already under BEND_LIB is read; a missing one is cloned

def answer.git source · line 241 · raw

@+lib:String -> @+hash:String -> @+url:String -> @+rev:String -> @+entry:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Answer)

a git package

def answer.pkg source · line 247 · raw

@+lib:String -> @+hash:String -> @src:0x74799d3f846634a3d7461d4336d7c9d4/src/lock/lock.Src -> @+hub:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Answer)

a package, from where its source says

def said source · line 256 · raw

@got:0x74799d3f846634a3d7461d4336d7c9d4/src/hub/hub.Got -> 0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Answer

what the hub says a name names, as it said it; the planner reads the hash out of it

def answer.name source · line 264 · raw

@+hub:String -> @+nv:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Answer)

a name, asked of the hub once: GET <hub>/name/<nv>

def answer.lock source · line 272 · raw

IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Answer)

the lock being rewritten, "" when there is none

def answer source · line 278 · raw

@+lib:String -> @ask:0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Ask -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Answer)

one question, answered

def answer.all source · line 288 · raw

@+lib:String -> @asks:List<&2, 0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Ask> -> IO(List<&2, 0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Reply>)

every question, answered

def git.said source · line 302 · raw

@+what:String -> @args:List<&2, String> -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer)

what git printed, and whether it succeeded, kept as it was

def answer.refs source · line 315 · raw

@+url:String -> @+ref:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer)

the refs a ref could name: a tag, its peeled form, and a branch, all at once, because which of them exists is the question

def answer.head source · line 320 · raw

@+url:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer)

HEAD on the remote, with the branch it is a symref to

def answer.tags source · line 324 · raw

@+url:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer)

every tag on the remote

def answer.above source · line 328 · raw

@+lib:String -> @+url:String -> @+pin:String -> @+tip:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer)

whether tip descends from pin, asked of a blobless bare clone

def tree.walk source · line 335 · raw

@+work:String -> @+at:String -> @+nar:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer)

the checkout's package, walked from its entry the way ez add walks it, with the directory its paths are written from, against the repo

def tree.entry source · line 345 · raw

@ok:Bool -> @+work:String -> @+at:String -> @+url:String -> @+rev:String -> @+nar:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer)

the entry has to be in the checkout for there to be a package to walk

def answer.tree source · line 358 · raw

@+lib:String -> @+url:String -> @+rev:String -> @+entry:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer)

a checkout at a rev: cloned, its .git removed, weighed, and walked. An entry that was not recorded is read from the checkout. Nothing is laid and nothing is noted: a tree the upgrade moves to is laid by the plan, once the upgrade and the lock both succeed.

def answer.weigh source · line 373 · raw

@+url:String -> @+rev:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer)

a commit's NAR hash, for a tool

def answer.hubhas source · line 379 · raw

@+hub:String -> @+hash:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer)

the hub's manifest for a hash a dependency moved to

def answer.ignore source · line 385 · raw

IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer)

the ignore file, "" when it is missing

def found.put source · line 391 · raw

@got:Maybe<&2, String> -> @+at:String -> @rest:0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer -> 0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer

one source in front of the rest, or the first that could not be read

def found.all source · line 403 · raw

@ps:List<&2, String> -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer)

every listed source, read

def found.listed source · line 413 · raw

@ok:Bool -> @+text:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer)

def answer.sources source · line 422 · raw

IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer)

every Bend source of the project. Vendored trees and the gate's shadow live under .ez, and a checkout's .git is not source, so neither is rewritten.

def whole.miss source · line 430 · raw

@+work:String -> @+why:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer)

a checkout ez add walks, which could not be made or read: removed, and the question answered with why

def whole.ran source · line 437 · raw

@ok:Bool -> @+work:String -> @+why:String -> @go:(@_:Unit -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer)) -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer)

a command of the checkout that worked goes on with it; one that failed ends it

def whole.run source · line 445 · raw

@+work:String -> @what:String -> @args:List<&2, String> -> @go:(@_:Unit -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer)) -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer)

one git command of the checkout, and the rest of it when it worked

def whole.put source · line 451 · raw

@got:Maybe<&2, String> -> @+at:String -> @rest:List<&2, 0x74799d3f846634a3d7461d4336d7c9d4/src/pkg/pkg.Source> -> List<&2, 0x74799d3f846634a3d7461d4336d7c9d4/src/pkg/pkg.Source>

a file read, in front of the rest

def whole.read source · line 461 · raw

@+work:String -> @ps:List<&2, String> -> IO(List<&2, 0x74799d3f846634a3d7461d4336d7c9d4/src/pkg/pkg.Source>)

every listed file of the checkout, read, with its path from the checkout's top. One that cannot be read as text, such as a link to a directory, is left out, as the walk would find it missing.

def whole.listed source · line 477 · raw

@ok:Bool -> @+work:String -> @+nar:String -> @+text:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer)

the checkout, its .git removed, weighed, and every file of it read; then removed. Nothing is laid: ez add lays the tree from its plan. the files of a checkout, read, once find has listed them. A listing that failed is refused rather than read: find writes what it could not reach to stderr, which snap answers beside the paths (SNAP-ANS-4), and such a line is no path of the package.

def whole.weigh source · line 489 · raw

@+work:String -> @+rev:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer)

def whole.dir source · line 499 · raw

@ok:Bool -> @+work:String -> @+url:String -> @+rev:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer)

a scratch directory made, or why it could not be

def answer.whole source · line 517 · raw

@+url:String -> @+rev:String -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer)

a checkout at a rev for ez add: a shallow clone into a scratch directory outside the project and BEND_LIB, weighed, and every file's text read, so the planner walks the package itself. The scratch directory is removed whether or not the clone worked, so a refused add leaves no trace.

def answer.up source · line 523 · raw

@+lib:String -> @ask:0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Ask -> IO(0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Answer)

one of the upgrade's questions, answered

def answer.ups source · line 547 · raw

@+lib:String -> @asks:List<&2, 0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Ask> -> IO(List<&2, 0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Reply>)

every one of them, answered

def answer.queries source · line 560 · raw

@+lib:String -> @qs:List<&2, 0x74799d3f846634a3d7461d4336d7c9d4/src/lock/plan.Query> -> IO(List<&2, 0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Reply>)

every query of the lock's upgrade: git is asked the question as the planner anchored it, and the answer is recorded under the question the upgrade looks it up by

def more source · line 571 · raw

@world:0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.World -> @rs:List<&2, 0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Reply> -> @us:List<&2, 0x74799d3f846634a3d7461d4336d7c9d4/src/lock/up.Reply> -> 0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.World

the World with more answers in it

def wrote source · line 580 · raw

@ok:Bool -> @+at:String -> IO(Unit)

a write that did not happen stops the command

def write source · line 588 · raw

@+at:String -> @text:String -> IO(Unit)

one file written, with the directory it goes in made first

def lay.all source · line 595 · raw

@+dir:String -> @fs:List<&2, 0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.Source> -> IO(Unit)

every file of a tree, in order

def place source · line 605 · raw

@+lib:String -> @pl:0x74799d3f846634a3d7461d4336d7c9d4/src/lock/plan.Place -> String

where a place is

def exec source · line 613 · raw

@+lib:String -> @effect:0x74799d3f846634a3d7461d4336d7c9d4/src/lock/plan.Effect -> IO(Unit)

one effect

def exec.all source · line 632 · raw

@+lib:String -> @es:List<&2, 0x74799d3f846634a3d7461d4336d7c9d4/src/lock/plan.Effect> -> IO(Unit)

every effect, in order

def end.at source · line 643 · raw

@zero:Bool -> @+code:U32 -> @+why:String -> IO(Unit)

a status that is 0 ends nothing, so the program runs out and exits 0; any other exits with that status and the reason

def end source · line 652 · raw

@+outcome:0x74799d3f846634a3d7461d4336d7c9d4/src/lock/plan.Outcome -> IO(Unit)

how the command ends: with the status the planner gave its outcome (Plan.status, EZ-OUT-1), and the reason when it refused

def exec.plan source · line 657 · raw

@+lib:String -> @pl:0x74799d3f846634a3d7461d4336d7c9d4/src/lock/plan.Plan -> IO(Unit)

a plan, executed

def loop.step source · line 668 · raw

@st:0x74799d3f846634a3d7461d4336d7c9d4/src/lock/plan.Step -> @+lib:String -> @world:0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.World -> @go:(@_:0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.World -> IO(Unit)) -> IO(Unit)

the planner's step: its questions answered and the loop gone round again, or its plan run

def rounds source · line 685 · raw

Nat

the rounds the loop may take. Each round's questions come from the last round's answers (a package's imports are known once git has answered for it), so how many there will be is not known up front. This is a guard against a planner that keeps asking, not a limit on a lock: running out of it dies loudly. The walk inside each round takes its fuel from its inputs (Plan.walk.fuel).

def loop source · line 690 · raw

@fuel:Nat -> @+lib:String -> @+world:0x74799d3f846634a3d7461d4336d7c9d4/src/lock/world.World -> IO(Unit)

the loop, under fuel. Every round adds at least one answer, since the planner never asks what the World answers already.

def run source · line 700 · raw

@up:Bool -> @+only:String -> IO(Unit)

ez lock and ez lock --upgrade [--package only]: the directory it runs in, the ledger and the listing read, every question answered, and the plan run