diff options
author | Emery Hemingway <ehmry@posteo.net> | 2021-09-02 19:03:01 +0200 |
---|---|---|
committer | Emery Hemingway <ehmry@posteo.net> | 2021-09-05 11:20:00 +0200 |
commit | 45398d7b54d5910d026fa67c62be16d2444d6f4a (patch) | |
tree | 74883ee2cb22d6e0ef7ff8d5be3be0d547a98baa /pkgs/development/nim-packages | |
parent | 584ea304754b2893004428298905585aa531d99e (diff) |
Initial nimPackages utilities
Add a nimPackages attrset with "buildNimPackage" and "fetchNimble".
Diffstat (limited to 'pkgs/development/nim-packages')
5 files changed, 260 insertions, 0 deletions
diff --git a/pkgs/development/nim-packages/build-nim-package/default.nix b/pkgs/development/nim-packages/build-nim-package/default.nix new file mode 100644 index 0000000000000..6c7aafd22c81e --- /dev/null +++ b/pkgs/development/nim-packages/build-nim-package/default.nix @@ -0,0 +1,43 @@ +{ lib, stdenv, nim, nim_builder }: + +{ strictDeps ? true, nativeBuildInputs ? [ ], configurePhase ? null +, buildPhase ? null, checkPhase ? null, installPhase ? null, meta ? { }, ... +}@attrs: + +stdenv.mkDerivation (attrs // { + inherit strictDeps; + nativeBuildInputs = [ nim nim_builder ] ++ nativeBuildInputs; + + configurePhase = if isNull configurePhase then '' + runHook preConfigure + find $NIX_BUILD_TOP -name .attrs.json + nim_builder --phase:configure + runHook postConfigure + '' else + buildPhase; + + buildPhase = if isNull buildPhase then '' + runHook preBuild + nim_builder --phase:build + runHook postBuild + '' else + buildPhase; + + checkPhase = if isNull checkPhase then '' + runHook preCheck + nim_builder --phase:check + runHook postCheck + '' else + checkPhase; + + installPhase = if isNull installPhase then '' + runHook preInstall + nim_builder --phase:install + runHook postInstall + '' else + installPhase; + + meta = meta // { + maintainers = (meta.maintainers or [ ]) ++ [ lib.maintainers.ehmry ]; + }; +}) diff --git a/pkgs/development/nim-packages/fetch-nimble/builder.sh b/pkgs/development/nim-packages/fetch-nimble/builder.sh new file mode 100644 index 0000000000000..693ab339408ed --- /dev/null +++ b/pkgs/development/nim-packages/fetch-nimble/builder.sh @@ -0,0 +1,12 @@ +source $stdenv/setup +export HOME=$NIX_BUILD_TOP + +nimble --accept --noSSLCheck develop "${pkgname}@${version}" +# TODO: bring in the certificates for Nimble to verify the fetch of +# the package list. + +pkgdir=${NIX_BUILD_TOP}/${pkgname} + +find "$pkgdir" -name .git -print0 | xargs -0 rm -rf + +cp -a "$pkgdir" "$out" diff --git a/pkgs/development/nim-packages/fetch-nimble/default.nix b/pkgs/development/nim-packages/fetch-nimble/default.nix new file mode 100644 index 0000000000000..ccdacc8e27b9b --- /dev/null +++ b/pkgs/development/nim-packages/fetch-nimble/default.nix @@ -0,0 +1,20 @@ +{ lib, makeOverridable, stdenv, gitMinimal, nim, cacert }: + +makeOverridable ( + + { pname, version, hash ? lib.fakeHash, + + meta ? { }, passthru ? { }, preferLocalBuild ? true }: + stdenv.mkDerivation { + inherit version meta passthru preferLocalBuild; + pname = pname + "-src"; + pkgname = pname; + builder = ./builder.sh; + nativeBuildInputs = [ gitMinimal nim ]; + outputHash = hash; + outputHashAlgo = null; + outputHashMode = "recursive"; + impureEnvVars = lib.fetchers.proxyImpureEnvVars + ++ [ "GIT_PROXY_COMMAND" "SOCKS_SERVER" ]; + GIT_SSL_CAINFO = "${cacert}/etc/ssl/certs/ca-bundle.crt"; + }) diff --git a/pkgs/development/nim-packages/nim_builder/default.nix b/pkgs/development/nim-packages/nim_builder/default.nix new file mode 100644 index 0000000000000..34da4dfa61a07 --- /dev/null +++ b/pkgs/development/nim-packages/nim_builder/default.nix @@ -0,0 +1,19 @@ +{ lib, stdenv, nim }: + +stdenv.mkDerivation { + pname = "nim_builder"; + inherit (nim) version; + dontUnpack = true; + nativeBuildInputs = [ nim ]; + buildPhase = '' + cp ${./nim_builder.nim} nim_builder.nim + nim c --nimcache:$TMPDIR nim_builder + ''; + installPhase = '' + install -Dt $out/bin nim_builder + ''; + meta = { + description = "Internal Nixpkgs utility for buildNimPackage."; + maintainers = [ lib.maintainers.ehmry ]; + }; +} diff --git a/pkgs/development/nim-packages/nim_builder/nim_builder.nim b/pkgs/development/nim-packages/nim_builder/nim_builder.nim new file mode 100644 index 0000000000000..b8881b700047f --- /dev/null +++ b/pkgs/development/nim-packages/nim_builder/nim_builder.nim @@ -0,0 +1,166 @@ +# SPDX-FileCopyrightText: 2021 Nixpkgs/NixOS contributors +## Custom Nim builder for Nixpkgs. + +import std/[os, osproc, parseutils, sequtils, streams, strutils] + +proc findNimbleFile(): string = + ## Copied from Nimble. + ## Copyright (c) 2015, Dominik Picheta + ## BSD3 + let dir = getCurrentDir() + result = "" + var hits = 0 + for kind, path in walkDir(dir): + if kind in {pcFile, pcLinkToFile}: + let ext = path.splitFile.ext + if ext == ".nimble": + result = path + inc hits + if hits >= 2: + quit("Only one .nimble file should be present in " & dir) + elif hits == 0: + quit("Could not find a file with a .nimble extension in " & dir) + +proc getEnvBool(key: string; default = false): bool = + ## Parse a boolean environmental variable. + let val = getEnv(key) + if val == "": default + else: parseBool(val) + +proc getNimbleFilePath(): string = + ## Get the Nimble file for the current package. + if existsEnv"nimbleFile": + getEnv"nimbleFile" + else: + findNimbleFile() + +proc getNimbleValue(filePath, key: string; default = ""): string = + ## Extract a string value from the Nimble file at ``filePath``. + var + fs = newFileStream(filePath, fmRead) + line: string + if fs.isNil: + quit("could not open " & filePath) + while fs.readline(line): + if line.startsWith(key): + var i = key.len + i.inc skipWhile(line, Whitespace, i) + if line[i] == '=': + inc i + i.inc skipWhile(line, Whitespace, i) + discard parseUntil(line, result, Newlines, i) + if result.len > 0 and result[0] == '"': + result = result.unescape + return + default + +proc getNimbleValues(filePath, key: string): seq[string] = + ## Extract a string sequence from the Nimble file at ``filePath``. + var gunk = getNimbleValue(filePath, key) + result = gunk.strip(chars = {'@', '[', ']'}).split(',') + if result == @[""]: reset result + apply(result) do (s: var string): + s = s.strip() + if s.len > 0 and s[0] == '"': + s = s.unescape() + +proc configurePhase*() = + ## Generate "config.nims" which will be read by the Nim + ## compiler during later phases. + const configFilePath = "config.nims" + echo "generating ", configFilePath + let + nf = getNimbleFilePath() + mode = + if fileExists configFilePath: fmAppend + else: fmWrite + var cfg = newFileStream(configFilePath, mode) + proc switch(key, val: string) = + cfg.writeLine("switch(", key.escape, ",", val.escape, ")") + switch("backend", nf.getNimbleValue("backend", "c")) + switch("nimcache", getEnv("NIX_BUILD_TOP", ".") / "nimcache") + if getEnvBool("nimRelease", true): + switch("define", "release") + for def in getEnv("nimDefines").split: + if def != "": + switch("define", def) + for input in getEnv("buildInputs").split: + if input != "": + for nimbleFile in walkFiles(input / "*.nimble"): + let inputSrc = normalizedPath( + input / nimbleFile.getNimbleValue("srcDir", ".")) + echo "found nimble input ", inputSrc + switch("path", inputSrc) + close(cfg) + +proc buildPhase*() = + ## Build the programs listed in the Nimble file and + ## optionally some documentation. + var cmds: seq[string] + proc before(idx: int) = + echo "build job ", idx, ": ", cmds[idx] + let + nf = getNimbleFilePath() + bins = nf.getNimbleValues("bin") + srcDir = nf.getNimbleValue("srcDir", ".") + binDir = getenv("outputBin", getenv("out", "/dev/null")) / "bin" + if bins != @[]: + for bin in bins: + cmds.add("nim compile $# --outdir:$# $#" % + [getenv"nimFlags", binDir, normalizedPath(srcDir / bin)]) + if getEnvBool"nimDoc": + echo "generating documentation" + let docDir = getenv("outputDoc", (getenv("out", "/dev/null") / "doc")) + for path in walkFiles(srcDir / "*.nim"): + cmds.add("nim doc --outdir:$# $#" % [docDir, path]) + if cmds.len > 0: + let err = execProcesses( + cmds, n = 1, + beforeRunEvent = before) + if err != 0: quit("build phase failed", err) + +proc installPhase*() = + ## Install the Nim sources if ``nimBinOnly`` is not + ## set in the environment. + if not getEnvBool"nimBinOnly": + let + nf = getNimbleFilePath() + srcDir = nf.getNimbleValue("srcDir", ".") + devDir = getenv("outputDev", getenv("out", "/dev/null")) + echo "Install ", srcDir, " to ", devDir + copyDir(normalizedPath(srcDir), normalizedPath(devDir / srcDir)) + copyFile(nf, devDir / nf.extractFilename) + +proc checkPhase*() = + ## Build and run the tests in ``tests``. + var cmds: seq[string] + proc before(idx: int) = + echo "check job ", idx, ": ", cmds[idx] + for path in walkPattern("tests/t*.nim"): + cmds.add("nim r $#" % [path]) + let err = execProcesses( + cmds, n = 1, + beforeRunEvent = before) + if err != 0: quit("check phase failed", err) + +when isMainModule: + import std/parseopt + var phase: string + + for kind, key, val in getopt(): + case kind + of cmdLongOption: + case key.toLowerAscii + of "phase": + if phase != "": quit("only a single phase may be specified") + phase = val + else: quit("unhandled argument " & key) + of cmdEnd: discard + else: quit("unhandled argument " & key) + + case phase + of "configure": configurePhase() + of "build": buildPhase() + of "install": installPhase() + of "check": checkPhase() + else: quit("unhandled phase " & phase) |