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. 6 import Base 7 import 0xead4c7939c9eaca8d47da53b4496b731/main.bend as R 8 import ../io/file.bend as F 9 import ./nar.bend as Nar 10 11 # a command's output as it printed it, or the walk stopped with why it failed 12 def 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 21 def 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 29 def 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 37 def under.top(+top: String, +at: String) -> String: 38 Bool.pick(String, String.is_empty(at), top, top ++ "/" ++ at) 39 40 def 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 48 def file.of(+path: String) -> IO(String): 49 do IO: 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 55 def 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 70 def 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: 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 89 def 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 94 def 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>: 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 105 def 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 113 def dump(+path: String) -> IO(String): 114 do IO: 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 121 def path(+work: String) -> IO(String): 122 do IO: 123 node : String <- dump(work) 124 return Nar.sri(Nar.archive(node))