~/bend-docscommunity

src/git/git.bend checks

raw source on the hub · import 0x886223f5c47e4983fe57d887c034bc7f/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

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.

type Id source · line 32 · raw

Data

one prerelease identifier

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.

type Cut source · line 43 · raw

Data

a string split once, on the first time a char occurs

type Tip source · line 160 · raw

Data

that commit is the tip of

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, 0x886223f5c47e4983fe57d887c034bc7f/src/toml/toml.Sect> -> String

a document that did not parse has no entry to take

def entry.doc source · line 296 · raw

@toml:0x886223f5c47e4983fe57d887c034bc7f/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, 0x886223f5c47e4983fe57d887c034bc7f/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:0x886223f5c47e4983fe57d887c034bc7f/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