From 78cd653ceec31878a428853a67841728c5b1bb8c Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Mon, 9 Oct 2023 17:20:01 +0100 Subject: [PATCH] Opportunistic ZIP fetching --- src/nim_lk.nim | 135 +++++++++++++++++++++---------------------------- 1 file changed, 58 insertions(+), 77 deletions(-) diff --git a/src/nim_lk.nim b/src/nim_lk.nim index 18fc92f..2b7f65f 100644 --- a/src/nim_lk.nim +++ b/src/nim_lk.nim @@ -22,15 +22,11 @@ proc registryCachePath: string = result = home / ".cache" result.add "/packages.json" -func isGitUrl(uri: Uri): bool = - uri.path.endsWith(".git") or - uri.scheme == "git" or - uri.scheme.startsWith("git+") - -proc isWebGitForgeUrl(uri: Uri): bool = - case uri.hostname - of "github.com", "git.sr.ht", "codeberg.org": true - else: false +proc isGitUrl(uri: Uri): bool = + uri.scheme == "git" or + uri.scheme.startsWith("git+") or + uri.path.endsWith(".git") or + uri.hostname.contains("git") proc startProcess(cmd: string; cmdArgs: varargs[string]): Process = # stderr.writeLine(cmd, " ", join(cmdArgs, " ")) @@ -107,64 +103,54 @@ proc prefetchGit(uri: Uri; version: VersionRange): JsonNode = if uri.query.startsWith("subdir="): subdir = uri.query[7 .. ^1] uri.query = "" - let url = $uri - let (tag, rev) = matchRev(url, version) - var args = @["--quiet", "--fetch-submodules", "--url", url, "--rev", rev] - stderr.writeLine "prefetch ", url - let dump = execProcess( - "nix-prefetch-git", - args = args, - options = {poUsePath}) - try: result = parseJson dump - except JsonParsingError: - stderr.writeLine "failed to parse output of nix-prefetch-git ", join(args, " ") - quit(dump) - if subdir != "": - result["subdir"] = %* subdir - result["method"] = %"git" - if tag != "": - result["ref"] = %tag - collectMetadata(result) - -proc prefetchGitForge(uri: Uri; version: VersionRange): JsonNode = - result = newJObject() - var - uri = uri - subdir = "" - uri.scheme.removePrefix("git+") - if uri.query != "": - if uri.query.startsWith("subdir="): - subdir = uri.query[7 .. ^1] - uri.query = "" - var url = $uri - let (tag, rev) = matchRev(url, version) - - uri.scheme = "https" - uri.path.removeSuffix(".git") - uri.path.add("/archive/") - uri.path.add(rev) - uri.path.add(".tar.gz") - url = $uri - - stderr.writeLine "prefetch ", url - var lines = execProcess( - "nix-prefetch-url", - args = @[url, "--type", "sha256", "--print-path", "--unpack", "--name", "source"], - options = {poUsePath}) - var - hash, storePath: string - off: int - off.inc parseUntil(lines, hash, {'\n'}, off).succ - off.inc parseUntil(lines, storePath, {'\n'}, off).succ - doAssert off == lines.len, "unrecognized nix-prefetch-url output:\n" & lines - - result["method"] = %"fetchzip" - result["path"] = %storePath - result["rev"] = %rev - result["sha256"] = %hash - result["url"] = %url - if subdir != "": - result["subdir"] = %* subdir + let cloneUrl = $uri + let (tag, rev) = matchRev(cloneUrl, version) + var archiveUri = uri + archiveUri.scheme = "https" + archiveUri.path.removeSuffix ".git" + archiveUri.path.add "/archive/" + archiveUri.path.add rev + archiveUri.path.add ".tar.gz" + let client = newHttpClient() + defer: close(client) + let + archiveUrl = $archiveUri + resp = head(client, archiveUrl) + if resp.code in {Http200, Http302}: + stderr.writeLine "prefetch ", archiveUrl + var lines = execProcess( + "nix-prefetch-url", + args = @[archiveUrl, "--type", "sha256", "--print-path", "--unpack", "--name", "source"], + options = {poUsePath}) + var + hash, storePath: string + off: int + off.inc parseUntil(lines, hash, {'\n'}, off).succ + off.inc parseUntil(lines, storePath, {'\n'}, off).succ + doAssert off == lines.len, "unrecognized nix-prefetch-url output:\n" & lines + result = newJObject() + result["method"] = %"fetchzip" + result["path"] = %storePath + result["rev"] = %rev + result["sha256"] = %hash + result["url"] = %archiveUrl + if subdir != "": + result["subdir"] = %* subdir + else: + stderr.writeLine "fetch of ", archiveUrl, " returned ", resp.code + var args = @["--quiet", "--fetch-submodules", "--url", cloneUrl, "--rev", rev] + stderr.writeLine "prefetch ", cloneUrl + let dump = execProcess( + "nix-prefetch-git", + args = args, + options = {poUsePath}) + try: result = parseJson dump + except JsonParsingError: + stderr.writeLine "failed to parse output of nix-prefetch-git ", join(args, " ") + quit(dump) + if subdir != "": + result["subdir"] = %* subdir + result["method"] = %"git" if tag != "": result["ref"] = %tag collectMetadata(result) @@ -237,9 +223,7 @@ proc generateLockfile(): JsonNode = if not deps.containsPackage(pkg.name): pending.addLast(pkg) elif not deps.containsPackageUri(pkg.name): - if uri.isWebGitForgeUrl: - pkgData = prefetchGitForge(uri, pkg.ver) - elif uri.isGitUrl: + if uri.isGitUrl: pkgData = prefetchGit(uri, pkg.ver) else: quit("unhandled URI " & $uri) @@ -252,14 +236,11 @@ proc generateLockfile(): JsonNode = pkg = pending.popFirst() info = getPackgeUri(pkg.name) uri = parseUri info.uri - if uri.isWebGitForgeUrl: - pkgData = prefetchGitForge(uri, pkg.ver) + case info.meth + of "git": + pkgData = prefetchGit(uri, pkg.ver) else: - case info.meth - of "git": - pkgData = prefetchGit(uri, pkg.ver) - else: - quit("unhandled fetch method " & $info.meth & " for " & info.uri) + quit("unhandled fetch method " & $info.meth & " for " & info.uri) collectRequires(pending, pkgData["path"].getStr) deps.add pkgData sort(deps.elems)