src/git/git.bend checks
raw source on the hub · import 0x74799d3f846634a3d7461d4336d7c9d4/src/git/git.bend as Git
git/git: what ez asks of git, and how it reads the answers. The decisions are
pure functions over what git ls-remote printed and what a checkout's
ez.toml says: which tag ez add pins (choose), what a named ref names
(exact), the default branch (tip.*), whether a ref is already a commit
(is_rev), and a package's entry and name (entry.*, called.*). The
planners (add/plan.bend, lock/up.bend) make them; the commands that run git
are the interpreters', which clone, weigh and ask about ancestry, and they
live in git/exec.bend, since they reach foreign code a law may not import.
Nothing here reimplements git. Bend links no TLS and Base has no readdir, so the programs that already speak the protocol are run instead, through the one process effect the rest of ez uses: arguments execvp'd, no shell between.
6 imports
import Base import ../io/file.bend as F import ../toml/toml.bend as T import ../ledger/manifest.bend as M import ../pkg/pkg.bend as K import ../pkg/path.bend as P
Types
type Row source · line 21 · raw
Data
one <sha>\t<name> row of what git ls-remote printed
Row@rev:String -> @name:String -> Row
type Ord source · line 26 · raw
Data
how two versions compare. A release is greater than its prerelease, and a numeric identifier is less than a word, which is the semver order.
LtOrd
EqOrd
GtOrd
type Id source · line 32 · raw
Data
one prerelease identifier
IdNum@n:Nat -> Id
IdWord@s:String -> Id
type Ver source · line 38 · raw
Data
a semver-ish tag, or a name that is not one. Build metadata is not kept: it does not change which tag is newer.
NoVer
Yes@nums:List<&2, Nat> -> @pre:List<&2, Id> -> Ver
type Cut source · line 43 · raw
Data
a string split once, on the first time a char occurs
Cut@left:String -> @right:String -> Cut
type Tip source · line 160 · raw
Data
that commit is the tip of
Tip@rev:String -> @branch:String -> Tip
Definitions
def among.step source · line 51 · raw
@here:Bool -> @rest:(@_:Unit -> Bool) -> Bool
one step of a scan looking for one hit, with the head's answer in hand.
Bool.or is an ordinary function and reduces both of its sides, so the
alphabet was read to its end for every char of every ref. The rest of the
scan arrives as a thunk, which is a value, and only the arm that wants it
applies it.
def among source · line 61 · raw
@+ch:Char -> @cs:List<&2, Char> -> Bool
whether a char is one of these. Base has Char.is_digit and Char.is_alpha
and nothing between, and a commit name is written with neither alphabet but
with sixteen characters of its own, so the sixteen are named.
def hex.at source · line 69 · raw
@ch:Char -> Bool
a char a commit name may hold
def hex.all.step source · line 75 · raw
@here:Bool -> @rest:(@_:Unit -> Bool) -> Bool
one step of the walk, and among.step turned around: Bool.and reduces
both of its sides too, so the first char that is not hex still cost a walk
of the rest of the ref
def hex.all source · line 85 · raw
@cs:List<&2, Char> -> Bool
whether every char of a ref is one. Base's List.all applies an erased
function parameter, which falls outside the termination check; this walk is
structural.
def is_rev source · line 95 · raw
@+ref:String -> Bool
a ref that is already the commit it names, which is what git rev-parse
prints: forty hex characters and nothing else. Such a ref needs no remote
asked about it, and leaves no tag behind to re-resolve later.
def row.rev source · line 99 · raw
@line:Row -> String
a row's commit
def row.name source · line 104 · raw
@line:Row -> String
a row's ref name
def row_of source · line 109 · raw
@+text:String -> Row
one row taken apart. ls-remote separates the two fields with a tab.
def row.put source · line 113 · raw
@+text:String -> List<&2, Row>
a line that says nothing is no row
def rows source · line 117 · raw
@ls:List<&2, String> -> List<&2, Row>
every row of what ls-remote printed
def named.step source · line 128 · raw
@here:Bool -> @rev:String -> @rest:(@_:Unit -> String) -> String
one step of the search, with the head's answer in hand. A recursive call in
an arm of a Bool.pick is not an arm at all: it is built whatever the
condition says, so the first row that answered still cost a walk of every
row after it.
def named source · line 139 · raw
@rs:List<&2, Row> -> @+want:String -> String
the commit of the first row whose ref name is exactly want, or "" when no
row is. The whole name is compared: git ls-remote matches its patterns
against the tail of a ref, so it answers refs/heads/main with
refs/heads/feature/main as well, and only this comparison tells them apart.
def or_else source · line 147 · raw
@+primary:String -> @fallback:String -> String
the first of two answers that says anything
def exact source · line 155 · raw
@+rs:List<&2, Row> -> @+ref:String -> String
the commit a ref names, from the rows the remote answered with. A tag comes
first, through its peeled ^{} row when it is annotated, since that row is
the commit and the other is the tag object; then a branch of that name. No
other row is ever picked, so a tag and a branch that share a name resolve to
the tag, and main never resolves to feature/main.
def tip.step source · line 166 · raw
@empty:Bool -> @+got:String -> @rest:(@_:Unit -> String) -> String
the rest of the scan only when this row said nothing. A recursive call
written as an argument of Bool.pick would run for a row that already
answered.
def tip.rev.hex source · line 174 · raw
@hex:Bool -> @rev:String -> String
a HEAD row whose first field is already a commit
def tip.rev.pick source · line 182 · raw
@head:Bool -> @hex:Bool -> @rev:String -> String
a HEAD row's commit, or "" when the row is the symref or not HEAD
def tip.rev.at source · line 190 · raw
@line:Row -> String
this row's commit when it is HEAD's commit
def tip.rev source · line 195 · raw
@rs:List<&2, Row> -> String
the commit HEAD names, from the rows ls-remote --symref wrote
def tip.strip source · line 204 · raw
@+text:String -> @+pre:String -> String
the prefix taken off when it is there, and "" when it is not, so a commit line is not mistaken for a branch name
def tip.sym source · line 209 · raw
@+rev:String -> String
ref: refs/heads/main is main. Anything else is no branch.
def tip.branch.pick source · line 213 · raw
@head:Bool -> @rev:String -> String
the symref only, so the commit row that follows it contributes nothing
def tip.branch.at source · line 221 · raw
@line:Row -> String
this row's branch when it is the symref for HEAD
def tip.branch source · line 226 · raw
@rs:List<&2, Row> -> String
the branch HEAD is, or "" when the remote did not say
def depth source · line 234 · raw
@path:String -> Nat
how many components a path has, which is how far down it sits
def root.rel source · line 242 · raw
@+at:String -> @root:String -> @+entry:String -> String
the directory inside the repo a package's paths are written from. pkg/pkg
resolves that against the checkout it read; the lock records it against the
repo, so the same number of components is climbed back off the entry's own
directory here. It is "." until a module reached through .. re-roots the
package above the entry.
def title.go source · line 246 · raw
@cs:List<&2, Char> -> String
the first char of a name in upper case, which is how bend writes an alias
def title source · line 254 · raw
@text:String -> String
a name as an import alias, as ez add and ez publish print it
def import.line source · line 261 · raw
@+hash:String -> @+at:String -> String
the import line a consumer writes for a package: the hash, the entry's path
inside the package, which is where the hub serves it, and the entry's name
as the alias, the way bend prints it. ez add and ez publish both print
this line.
def entry.main source · line 266 · raw
@no:Bool -> @+binary:String -> String
main.bend when neither the entry nor the bin was named. That is the file
ez init writes when it is not told an entry.
def entry.bin source · line 275 · raw
@no:Bool -> @+file:String -> @+binary:String -> String
bin only when the package named no entry. The bin is the file a tool
builds; it is not the entry unless the entry is absent.
def entry.pick source · line 283 · raw
@+file:String -> @+binary:String -> String
the file a package is taken from: its entry, else its bin, else main.bend
def entry.sects source · line 287 · raw
@ok:Bool -> @ss:List<&2, 0x74799d3f846634a3d7461d4336d7c9d4/src/toml/toml.Sect> -> String
a document that did not parse has no entry to take
def entry.doc source · line 296 · raw
@toml:0x74799d3f846634a3d7461d4336d7c9d4/src/toml/toml.Toml -> String
the entry a parsed document names
def entry.text source · line 301 · raw
@+text:String -> String
the entry a parsed ez.toml names
def entry.maybe source · line 305 · raw
@got:Maybe<&2, String> -> String
a missing ez.toml names main.bend, the same stub ez init uses
def entry.at source · line 313 · raw
@+work:String -> IO(String)
the checkout's ez.toml, read for the entry it names
def called.sects source · line 319 · raw
@ok:Bool -> @ss:List<&2, 0x74799d3f846634a3d7461d4336d7c9d4/src/toml/toml.Sect> -> String
the package name a parsed document gives, or "" when it did not parse
def called.doc source · line 327 · raw
@toml:0x74799d3f846634a3d7461d4336d7c9d4/src/toml/toml.Toml -> String
the package name a parsed document gives
def called.maybe source · line 332 · raw
@got:Maybe<&2, String> -> String
a checkout with no ez.toml gives no package name
def entry.for source · line 340 · raw
@given:Bool -> @+entry:String -> @+work:String -> IO(String)
the entry a vendoring is taken from. One that was asked for is that one.
def ord.lt source · line 354 · raw
@lt:Bool -> Ord
def ord.nat source · line 361 · raw
@eq:Bool -> @lt:Bool -> Ord
def ord.str source · line 368 · raw
@eq:Bool -> @le:Bool -> Ord
def ord.flip source · line 375 · raw
@order:Ord -> Ord
def ord.pad.at source · line 384 · raw
@zero:Bool -> @rest:(@_:Unit -> Ord) -> Ord
def ord.pad source · line 391 · raw
@xs:List<&2, Nat> -> Ord
def ord.nums.at source · line 398 · raw
@order:Ord -> @rest:(@_:Unit -> Ord) -> Ord
def ord.nums source · line 407 · raw
@left:List<&2, Nat> -> @right:List<&2, Nat> -> Ord
def ord.id source · line 419 · raw
@left:Id -> @right:Id -> Ord
def ord.ids source · line 430 · raw
@left:List<&2, Id> -> @right:List<&2, Id> -> Ord
def ord.rel.at source · line 441 · raw
@ae:Bool -> @be:Bool -> @left:List<&2, Id> -> @right:List<&2, Id> -> Ord
def ord.rel source · line 452 · raw
@+left:List<&2, Id> -> @+right:List<&2, Id> -> Ord
def ord.ver.at source · line 455 · raw
@order:Ord -> @pa:List<&2, Id> -> @pb:List<&2, Id> -> Ord
def ord.ver source · line 458 · raw
@left:Ver -> @right:Ver -> Ord
def dig source · line 468 · raw
@ch:Char -> Nat
a decimal digit's value
def num.go source · line 471 · raw
@text:String -> @+acc:Nat -> Nat
def flag.step source · line 478 · raw
@ok:Bool -> @rest:(@_:Unit -> Bool) -> Bool
def digits.go source · line 485 · raw
@text:String -> Bool
def digits.at source · line 492 · raw
@empty:Bool -> @+text:String -> Bool
def digits source · line 500 · raw
@+text:String -> Bool
a non-empty run of decimal digits
def nums.cons source · line 503 · raw
@value:Nat -> @rest:Maybe<&2, List<&2, Nat>> -> Maybe<&2, List<&2, Nat>>
def nums.put source · line 510 · raw
@ok:Bool -> @+part:String -> @rest:Maybe<&2, List<&2, Nat>> -> Maybe<&2, List<&2, Nat>>
def nums.of source · line 517 · raw
@ps:List<&2, String> -> Maybe<&2, List<&2, Nat>>
def id.char source · line 524 · raw
@+ch:Char -> Bool
def id.chars source · line 527 · raw
@text:String -> Bool
def id.make source · line 534 · raw
@num:Bool -> @+text:String -> Id
def ids.cons source · line 541 · raw
@ident:Id -> @rest:Maybe<&2, List<&2, Id>> -> Maybe<&2, List<&2, Id>>
def ids.ok source · line 548 · raw
@ok:Bool -> @num:Bool -> @+part:String -> @rest:Maybe<&2, List<&2, Id>> -> Maybe<&2, List<&2, Id>>
def ids.put source · line 555 · raw
@empty:Bool -> @ok:Bool -> @num:Bool -> @+part:String -> @rest:Maybe<&2, List<&2, Id>> -> Maybe<&2, List<&2, Id>>
def ids.of source · line 562 · raw
@ps:List<&2, String> -> Maybe<&2, List<&2, Id>>
def pre.parts source · line 569 · raw
@empty:Bool -> @+raw:String -> Maybe<&2, List<&2, Id>>
def pre.of source · line 576 · raw
@had:Bool -> @+raw:String -> Maybe<&2, List<&2, Id>>
def split1.put source · line 583 · raw
@ch:Char -> @cut:Cut -> Cut
def split1.step source · line 587 · raw
@hit:Bool -> @ch:Char -> @+tail:String -> @rest:(@_:Unit -> Cut) -> Cut
def split1 source · line 596 · raw
@+sep:Char -> @text:String -> Cut
a string cut at the first of a character, the character dropped; no hit leaves the whole string on the left
def unv.step source · line 603 · raw
@drop:Bool -> @ch:Char -> @tail:String -> String
def unv source · line 611 · raw
@text:String -> String
a tag with one leading v or V dropped
def ver.yes source · line 618 · raw
@empty:Bool -> @xs:List<&2, Nat> -> @ys:List<&2, Id> -> Ver
def ver.pre source · line 625 · raw
@+xs:List<&2, Nat> -> @ps:Maybe<&2, List<&2, Id>> -> Ver
def ver.nums source · line 632 · raw
@had:Bool -> @ns:Maybe<&2, List<&2, Nat>> -> @+pre:String -> Ver
def ver.from source · line 639 · raw
@empty:Bool -> @had:Bool -> @+core:String -> @+pre:String -> Ver
def ver.cut source · line 646 · raw
@had:Bool -> @cut:Cut -> Ver
def ver.main source · line 650 · raw
@+main:String -> Ver
def ver.core source · line 653 · raw
@cut:Cut -> Ver
def ver.of source · line 658 · raw
@+tag:String -> Ver
a tag read as a version. A leading v is optional, and + metadata is dropped.
def newer source · line 662 · raw
@order:Ord -> Bool
whether the first version is strictly newer
def latest.cmp source · line 671 · raw
@take:Bool -> @+name:String -> @+rest:String -> String
def latest.have source · line 678 · raw
@empty:Bool -> @+name:String -> @+rest:String -> @version:Ver -> String
def latest.step source · line 685 · raw
@version:Ver -> @+name:String -> @+rest:String -> String
def latest source · line 693 · raw
@names:List<&2, String> -> String
the newest semver-ish name, or "" when none of them is one
def release.ver source · line 701 · raw
@version:Ver -> Bool
a version with no pre-release, which is a release
def release source · line 709 · raw
@+name:String -> Bool
a semver-ish tag that is a release: v1.9.0, not v2.0.0-rc1
def latest.rel.step source · line 714 · raw
@keep:Bool -> @+name:String -> @+rest:String -> String
a name that is a release, weighed against the greatest release after it the
way latest weighs any two versions; a name that is not is passed over
def latest.rel source · line 722 · raw
@names:List<&2, String> -> String
the greatest release, or "" when no name is one
def has.release.step source · line 730 · raw
@here:Bool -> @rest:(@_:Unit -> Bool) -> Bool
one name found to be a release, or the rest still to be asked about
def has.release source · line 738 · raw
@names:List<&2, String> -> Bool
whether any name is a release
def choose.go source · line 747 · raw
@none:Bool -> @+rel:String -> @+any:String -> String
the greatest release when there is one, and otherwise the greatest of what is left, every one of which is a pre-release
def choose source · line 758 · raw
@+names:List<&2, String> -> String
the tag ez add pins when no ref was asked for: a release beats every
pre-release, however much greater the pre-release's numbers are, and
within each class the greatest wins by ord.ver, the later of two equal
ones winning as latest has it. "" when no name is semver-ish.
def tag.put source · line 763 · raw
@hit:Bool -> @+name:String -> List<&2, String>
one row's tag name, or nothing when the row is peeled or not a tag
def tag.keep source · line 770 · raw
@peeled:Bool -> @+name:String -> List<&2, String>
def tag.one source · line 777 · raw
@line:Row -> List<&2, String>
def tag.names source · line 782 · raw
@rs:List<&2, Row> -> List<&2, String>
every tag name ls-remote --tags wrote, peeled rows left out