mirror of
https://github.com/logos-messaging/logos-delivery.git
synced 2026-07-21 04:00:27 +00:00
176 lines
5.4 KiB
Nim
176 lines
5.4 KiB
Nim
## Install nimble.lock packages into nimbledeps/pkgs2 and write nimble.paths.
|
|
##
|
|
## Used when `nimble setup --localdeps` fails (e.g. SAT cannot resolve libp2p
|
|
## git pins). Reproducible: clones exact vcsRevision from the lockfile.
|
|
##
|
|
## Usage (from repo root):
|
|
## nim c -r --hints:off tools/install_from_lock.nim
|
|
##
|
|
## Optional env:
|
|
## INSTALL_FROM_LOCK_FORCE=1 re-clone packages even if present
|
|
|
|
import std/[json, os, osproc, strutils, algorithm]
|
|
|
|
const
|
|
PkgsRel = "nimbledeps" / "pkgs2"
|
|
LockRel = "nimble.lock"
|
|
PathsRel = "nimble.paths"
|
|
|
|
proc run(cmd: string): int =
|
|
execCmd(cmd)
|
|
|
|
proc runOut(cmd: string): tuple[output: string, exitCode: int] =
|
|
execCmdEx(cmd)
|
|
|
|
proc gitClone(url, dest, rev: string): bool =
|
|
if dirExists(dest):
|
|
removeDir(dest)
|
|
# Shallow clone of a specific commit is awkward; full clone then checkout.
|
|
var c = run("git clone --quiet " & quoteShell(url) & " " & quoteShell(dest))
|
|
if c != 0:
|
|
let url2 = url.replace(".git", "")
|
|
c = run("git clone --quiet " & quoteShell(url2) & " " & quoteShell(dest))
|
|
if c != 0:
|
|
return false
|
|
if run("git -C " & quoteShell(dest) & " checkout -q " & quoteShell(rev)) != 0:
|
|
discard run("git -C " & quoteShell(dest) & " fetch --quiet origin " & quoteShell(rev))
|
|
if run("git -C " & quoteShell(dest) & " checkout -q " & quoteShell(rev)) != 0:
|
|
return false
|
|
# Submodules (bearssl, boringssl, secp256k1, lsquic, zlib, ...)
|
|
discard run(
|
|
"git -C " & quoteShell(dest) & " submodule update --init --recursive --quiet"
|
|
)
|
|
true
|
|
|
|
proc packageVersion(pkgDir: string, fallback: string): string =
|
|
result = fallback
|
|
for f in walkFiles(pkgDir / "*.nimble"):
|
|
for line in readFile(f).splitLines:
|
|
let t = line.strip
|
|
if t.startsWith("version"):
|
|
let parts = t.split('=')
|
|
if parts.len >= 2:
|
|
return parts[1].strip().strip(chars = {'"', '\''})
|
|
break
|
|
|
|
proc writeMeta(pkgDir, url, rev, sha1, ver: string) =
|
|
let meta = %*{
|
|
"url": url,
|
|
"vcsRevision": rev,
|
|
"downloadMethod": "git",
|
|
"versions": [ver],
|
|
"checksums": {"sha1": sha1}
|
|
}
|
|
writeFile(pkgDir / "nimblemeta.json", meta.pretty)
|
|
|
|
proc installPkg(root, name: string, entry: JsonNode, force: bool): string =
|
|
## Returns final package directory path.
|
|
let version = entry["version"].getStr
|
|
let rev = entry["vcsRevision"].getStr
|
|
let url = entry["url"].getStr
|
|
let sha1 = entry["checksums"]["sha1"].getStr
|
|
let pkgsDir = root / PkgsRel
|
|
createDir(pkgsDir)
|
|
|
|
# Prefer existing dir matching name-*-sha1
|
|
var existing = ""
|
|
for kind, path in walkDir(pkgsDir):
|
|
if kind != pcDir:
|
|
continue
|
|
let base = path.extractFilename
|
|
if base.startsWith(name & "-") and base.endsWith("-" & sha1):
|
|
existing = path
|
|
break
|
|
|
|
if existing.len > 0 and not force and fileExists(existing / "nimblemeta.json"):
|
|
# Ensure submodules present (best-effort)
|
|
if dirExists(existing / ".git"):
|
|
discard run(
|
|
"git -C " & quoteShell(existing) &
|
|
" submodule update --init --recursive --quiet"
|
|
)
|
|
echo " skip ", existing.extractFilename
|
|
return existing
|
|
|
|
echo " install ", name, " @ ", version, " (", rev[0 .. min(11, rev.high)], ")"
|
|
let tmpName = name & "-tmp-" & sha1
|
|
let tmpDest = pkgsDir / tmpName
|
|
if not gitClone(url, tmpDest, rev):
|
|
echo " FAILED ", name
|
|
quit(1)
|
|
|
|
var pkgVer = packageVersion(tmpDest, version.replace("#", ""))
|
|
if pkgVer.len == 0:
|
|
pkgVer = version.replace("#", "")
|
|
let finalName = name & "-" & pkgVer & "-" & sha1
|
|
let finalDest = pkgsDir / finalName
|
|
if finalDest != tmpDest:
|
|
if dirExists(finalDest):
|
|
removeDir(finalDest)
|
|
moveDir(tmpDest, finalDest)
|
|
writeMeta(finalDest, url, rev, sha1, pkgVer)
|
|
echo " -> ", finalName
|
|
finalDest
|
|
|
|
proc writePaths(root: string, dirs: seq[string]) =
|
|
var lines = @["--noNimblePath"]
|
|
var sorted = dirs
|
|
sorted.sort()
|
|
for d in sorted:
|
|
lines.add("--path:\"" & d & "\"")
|
|
if dirExists(d / "src"):
|
|
lines.add("--path:\"" & d / "src" & "\"")
|
|
writeFile(root / PathsRel, lines.join("\n") & "\n")
|
|
echo "Wrote ", root / PathsRel, " (", sorted.len, " packages)"
|
|
|
|
proc applyLibp2pShims(root: string) =
|
|
## libp2p_mix still imports removed libp2p modules; restore as thin shims.
|
|
var lp = ""
|
|
let pkgs = root / PkgsRel
|
|
for kind, path in walkDir(pkgs):
|
|
if kind != pcDir:
|
|
continue
|
|
let base = path.extractFilename
|
|
if base.startsWith("libp2p-2.2") and dirExists(path / "libp2p"):
|
|
lp = path
|
|
break
|
|
if lp.len == 0:
|
|
echo " (no libp2p 2.2 package; skip shims)"
|
|
return
|
|
writeFile(
|
|
lp / "libp2p" / "utility.nim",
|
|
"""
|
|
# Shim: libp2p/utility removed in nim-libp2p 2.x; needed by current libp2p_mix pin.
|
|
import ./utils/[opt, shortlog, collections]
|
|
export opt, shortlog, collections
|
|
""",
|
|
)
|
|
createDir(lp / "libp2p" / "utils")
|
|
writeFile(
|
|
lp / "libp2p" / "utils" / "sequninit.nim",
|
|
"""
|
|
# Shim: libp2p/utils/sequninit removed; newSeqUninit lives in system.
|
|
export system
|
|
""",
|
|
)
|
|
echo " applied libp2p 2.2 shims in ", lp.extractFilename
|
|
|
|
proc main() =
|
|
let root = getCurrentDir()
|
|
let lockPath = root / LockRel
|
|
if not fileExists(lockPath):
|
|
echo "error: ", lockPath, " not found (run from repo root)"
|
|
quit(1)
|
|
|
|
let force = getEnv("INSTALL_FROM_LOCK_FORCE") == "1"
|
|
let lock = parseFile(lockPath)
|
|
echo "Installing packages from ", LockRel, " ..."
|
|
var dirs: seq[string]
|
|
for name, entry in lock["packages"].pairs:
|
|
dirs.add(installPkg(root, name, entry, force))
|
|
writePaths(root, dirs)
|
|
applyLibp2pShims(root)
|
|
echo "Done."
|
|
|
|
main()
|