@@ 3,6 3,20 @@ import cbor, dhall/[render, terms], eris
const selfDescribedCbor = 55799
+type
+ Manifest = Table[string, ManifestEntry]
+ ManifestEntry = object
+ cap, path: string
+ closure: Table[string, string]
+
+proc parseManifestFile(path: string): Manifest =
+ let js = parseFile(path)
+ for key, val in js.pairs:
+ var entry: ManifestEntry
+ entry.cap = val["cap"].getStr
+ entry.path = val["path"].getStr
+ result[key] = entry
+
proc writeErisLinks(path: string; node: CborNode) =
# Inspired by "Package Metadata for Core Files"
# - https://systemd.io/COREDUMP_PACKAGE_METADATA/
@@ 25,16 39,33 @@ proc toCbor(cap: ErisCap): CborNode =
result = initCborBytes(cap.bytes)
result.tag = erisCborTag
-proc toDhall(js: JsonNode): Value =
- case js.kind
- of JString:
- result = newValue(js.str)
- of JObject:
- result = newRecordLiteral(js.fields.len)
- for key, val in js.fields.pairs:
- result.table[key] = val.toDhall
- else:
- raiseAssert "unhandled JSON value"
+proc toDhall(entry: ManifestEntry): Value =
+ var closure = newSeqOfCap[Value](entry.closure.len+1)
+ closure.add newRecordLiteral(
+ { "cap": newValue $entry.cap, "path": newValue entry.path})
+ for path, urn in entry.closure.pairs:
+ closure.add newRecordLiteral(
+ { "cap": newValue urn, "path": newValue path })
+ newRecordLiteral {
+ "cap": newValue entry.cap,
+ "closure": newValue closure,
+ }
+
+proc toDhall(manifest: Manifest): Value =
+ result = newRecordLiteral(manifest.len)
+ for name, entry in manifest.pairs:
+ result.table[name] = entry.toDhall
+
+proc toJson(entry: ManifestEntry): JsonNode =
+ var closure = newJObject()
+ for path, urn in entry.closure.pairs:
+ closure[path] = %urn
+ %*{ "cap": entry.cap, "closure": closure, "path": entry.path }
+
+proc toJson(manifest: Manifest): JsonNode =
+ result = newJObject()
+ for name, entry in manifest.pairs:
+ result[name] = entry.toJSON
proc isElf(path: string): bool =
var magic: array[4, char]
@@ 66,7 97,7 @@ proc main =
erisLinks: CborNode
var
- outputManifests = initTable[string, JsonNode]()
+ outputManifests = initTable[string, Manifest]()
pendingFiles = initDeque[PendingFile]()
failed = false
if getEnv("outputs") == "":
@@ 78,7 109,7 @@ proc main =
if fileExists(outputRoot / jsonManifestSubPath):
stderr.writeLine "Not running ERIS patch hook again"
quit 0
- outputManifests[outputRoot] = newJObject()
+ outputManifests[outputRoot] = Manifest()
let buildInputs = getEnv("buildInputs").splitWhitespace
@@ 149,10 180,10 @@ proc main =
let manifestPath = storePath / jsonManifestSubPath
if fileExists(manifestPath):
let
- manifest = parseFile(manifestPath)
+ manifest = parseManifestFile(manifestPath)
entry = manifest[filePath.extractFilename]
- for path, urn in entry["closure"].pairs:
- result[path] = parseErisUrn urn.getStr
+ for path, urn in entry.closure.pairs:
+ result[path] = parseErisUrn urn
let otherClosure = fileClosure(path)
for otherPath, otherCap in otherClosure.pairs:
# merge the closure of the dependency
@@ 196,7 227,7 @@ proc main =
pendingFiles.addLast(pendingFile)
break selfReferenceCheck
var
- closure = newJObject()
+ closure = initTable[string, string]()
replaceCmd = patchelf & " --set-rpath '' " & filePath
for need, replacementPath in pendingFile.replacements.pairs:
if replacementPath == "": continue
@@ 204,11 235,11 @@ proc main =
cap = fileCap(replacementPath)
urn = $cap
stderr.writeLine "replace reference to ", need, " with ", urn
- closure[replacementPath] = %urn
+ closure[replacementPath] = urn
pendingFile.erisLinks[ replacementPath.toCbor] = cap.toCbor
replaceCmd.add(" --replace-needed $# $#" % [need, urn])
for path, cap in fileClosure(replacementPath).pairs:
- closure[path] = %($cap)
+ closure[path] = $cap
pendingFile.erisLinks[path.toCbor] = cap.toCbor
if runPatchelf and pendingFile.replacements.len != 0:
@@ 238,11 269,12 @@ proc main =
quit("Adding note to $1 failed" % pendingFile.filePath)
moveFile(tmpFile, pendingFile.filePath)
- outputManifests[pendingFile.outputRoot][filePath.extractFilename] = %* {
- "cap": $fileCap(filePath),
- "closure": closure,
- "path": filePath
- }
+ outputManifests[pendingFile.outputRoot][filePath.extractFilename] =
+ ManifestEntry(
+ cap: $fileCap(filePath),
+ closure: closure,
+ path: filePath,
+ )
if pendingFiles.len == prevPrevLen:
failed = true
@@ 260,7 292,7 @@ proc main =
for outputRoot, manifest in outputManifests:
let supportDir = outputRoot / "nix-support"
createDir(supportDir)
- writeFile(outputRoot / jsonManifestSubPath, $manifest)
- writeFile(outputRoot / dhallManifestSubPath, $(manifest.toDhall))
+ writeFile(outputRoot / jsonManifestSubPath, $manifest.toJson)
+ writeFile(outputRoot / dhallManifestSubPath, $manifest.toDhall)
main()