src/sha/dump.bend

ezx@1.4.0.0 · 124 lines · 0 definitions

1# sha/dump: a directory read off the disk and handed to sha/nar, which builds
2# its NAR and names it. The listing is one `find`, run through snap's foreign
3# effect, and every regular file is then read. This half lives apart from
4# sha/nar because bend 2.0.32 fails a proof whose imports reach foreign code,
5# so a law may import sha/nar but never this.
6import Base
7import snap@1.1.0.0/main.bend as R
8import ezx@1.4.0.0/src/io/file.bend as F
9import ezx@1.4.0.0/src/sha/nar.bend as Nar
10
11# a command's output as it printed it, or the walk stopped with why it failed
12def said(ok: Bool, +why: String, +text: String) -> IO(String):
13  match ok:
14    case False{}:
15      IO.die(String, 1, "ez: nar hash: " ++ why ++ text)
16    case True{}:
17      IO.pure(String, text)
18
19# what a program printed, with the status line in front of it taken off and
20# nothing else touched
21def printed.at(ends: Bool, tail: String, rest: Unit -> String) -> String:
22  match ends:
23    case True{}:
24      tail
25    case False{}:
26      rest(Unit{})
27
28# the output after its first newline
29def printed(out: String) -> String:
30  match out:
31    case SNil{}:
32      ""
33    case SCon{c, +t}:
34      printed.at(Char.is_eq(c, '\n'), t, _u => printed(t))
35
36# a path of the tree, as the file effect is to open it
37def under.top(+top: String, +at: String) -> String:
38  Bool.pick(String, String.is_empty(at), top, top ++ "/" ++ at)
39
40def file.got(got: Maybe<&2, String>, +path: String) -> IO(String):
41  match got:
42    case None{}:
43      IO.die(String, 1, "ez: nar hash: " ++ path ++ ": unreadable")
44    case Some{s}:
45      IO.pure(String, s)
46
47# a regular file's text, by its path from the top
48def file.of(+path: String) -> IO(String):
49  do IO<String>:
50    m : Maybe<&2, String> <- F.read(path)
51    file.got(m, path)
52
53# a path of the listing with what the NAR needs of it: a file's text read, a
54# symlink's target as the listing printed it
55def ent.other(
56  known: Bool,
57  +kind: String,
58  +name: String,
59  +at: String,
60  +target: String,
61  +path: String
62) -> IO(Nar.Ent):
63  match known:
64    case True{}:
65      IO.pure(Nar.Ent, Nar.Ent{kind, False{}, name, at, target})
66    case False{}:
67      IO.die(Nar.Ent, 1, "ez: nar hash: " ++ path ++ ": not a file, directory, or symlink")
68
69# a regular file's text read, or anything else as the listing gave it
70def ent.read(
71  file: Bool,
72  +kind: String,
73  +mode: String,
74  +name: String,
75  +at: String,
76  +target: String,
77  +path: String
78) -> IO(Nar.Ent):
79  match file:
80    case True{}:
81      do IO<Nar.Ent>:
82        body : String <- file.of(path)
83        return Nar.Ent{kind, Nar.owner.exec(mode), name, at, body}
84    case False{}:
85      ent.other(Bool.or(String.eq(kind, "d"), String.eq(kind, "l")), kind, name, at,
86        target, path)
87
88# one path of the listing, read
89def ent.of(+top: String, row: Nar.Row) -> IO(Nar.Ent):
90  Nar.Row{+kind, +mode, +name, +at, +target} = row
91  ent.read(String.eq(kind, "f"), kind, mode, name, at, target, under.top(top, at))
92
93# every path of the listing, read
94def ents(+top: String, rs: List<&2, Nar.Row>) -> IO(List<&2, Nar.Ent>):
95  match rs:
96    case []:
97      IO.pure(List<&2, Nar.Ent>, [])
98    case +h <> t:
99      do IO<List<&2, Nar.Ent>>:
100        e : Nar.Ent <- ent.of(top, h)
101        rest : List<&2, Nar.Ent> <- ents(top, t)
102        return e <> rest
103
104# the tree's node, or the walk stopped when the listing made none
105def built(got: Maybe<&2, String>, +path: String) -> IO(String):
106  match got:
107    case None{}:
108      IO.die(String, 1, "ez: nar hash: " ++ path ++ ": the listing does not make a tree")
109    case Some{node}:
110      IO.pure(String, node)
111
112# the NAR serial of one path
113def dump(+path: String) -> IO(String):
114  do IO<String>:
115    +out : String <- R.exec(Nar.listing.argv(path))
116    text : String <- said(R.ok(out), path ++ ": ", printed(out))
117    es : List<&2, Nar.Ent> <- ents(path, Nar.rows(Nar.cut(text)))
118    built(Nar.tree(es), path)
119
120# the SRI narHash of a path, the same string `nix hash path --sri` prints
121def path(+work: String) -> IO(String):
122  do IO<String>:
123    node : String <- dump(work)
124    return Nar.sri(Nar.archive(node))