From 92c8f64c5e0f98c5a721fb9188e71aa9c650514a Mon Sep 17 00:00:00 2001 From: TomaSajt <62384384+TomaSajt@users.noreply.github.com> Date: Sat, 30 Mar 2024 12:22:26 +0100 Subject: [PATCH] buildDubPackage, dub-to-nix: init --- pkgs/build-support/dlang/README.md | 7 + .../dlang/builddubpackage/default.nix | 124 ++++++++++++++++++ pkgs/build-support/dlang/dub-support.nix | 5 + .../dlang/dub-to-nix/default.nix | 19 +++ .../dlang/dub-to-nix/dub-to-nix.py | 39 ++++++ pkgs/build-support/fetchurl/mirrors.nix | 5 + pkgs/top-level/all-packages.nix | 3 + 7 files changed, 202 insertions(+) create mode 100644 pkgs/build-support/dlang/README.md create mode 100644 pkgs/build-support/dlang/builddubpackage/default.nix create mode 100644 pkgs/build-support/dlang/dub-support.nix create mode 100644 pkgs/build-support/dlang/dub-to-nix/default.nix create mode 100644 pkgs/build-support/dlang/dub-to-nix/dub-to-nix.py diff --git a/pkgs/build-support/dlang/README.md b/pkgs/build-support/dlang/README.md new file mode 100644 index 000000000000..bdd5fd2b6046 --- /dev/null +++ b/pkgs/build-support/dlang/README.md @@ -0,0 +1,7 @@ +# Build support for D + +Build utilities for the D language can be found in this directory. + +### Current maintainers +- @TomaSajt +- @jtbx diff --git a/pkgs/build-support/dlang/builddubpackage/default.nix b/pkgs/build-support/dlang/builddubpackage/default.nix new file mode 100644 index 000000000000..9295445b0f7c --- /dev/null +++ b/pkgs/build-support/dlang/builddubpackage/default.nix @@ -0,0 +1,124 @@ +{ + lib, + stdenv, + fetchurl, + linkFarm, + dub, + ldc, + removeReferencesTo, +}: + +# See https://nixos.org/manual/nixpkgs/unstable#dlang for more detailed usage information + +{ + # A lockfile generated by `dub-to-nix` from the source of the package. + # Can be either a path to the file, or an attrset already parsed with `lib.importJSON`. + dubLock, + # The build type to pass to `dub build` as a value for the `--build=` flag. + dubBuildType ? "release", + # The flags to pass to `dub build` and `dub test`. + dubFlags ? [ ], + # The flags to pass to `dub build`. + dubBuildFlags ? [ ], + # The flags to pass to `dub test`. + dubTestFlags ? [ ], + # The D compiler to be used by `dub`. + compiler ? ldc, + ... +}@args: + +let + makeDubDep = + { + pname, + version, + sha256, + }: + { + inherit pname version; + src = fetchurl { + name = "dub-${pname}-${version}.zip"; + url = "mirror://dub/${pname}/${version}.zip"; + inherit sha256; + }; + }; + + lockJson = if lib.isPath dubLock then lib.importJSON dubLock else dubLock; + + lockedDeps = lib.mapAttrsToList ( + pname: { version, sha256 }: makeDubDep { inherit pname version sha256; } + ) lockJson.dependencies; + + # a directory with multiple single element registries + # one big directory with all .zip files leads to version parsing errors + # when the name of a package is a prefix of the name of another package + dubRegistryBase = linkFarm "dub-registry-base" ( + map (dep: { + name = "${dep.pname}/${dep.pname}-${dep.version}.zip"; + path = dep.src; + }) lockedDeps + ); + + combinedFlags = "--skip-registry=all --compiler=${lib.getExe compiler} ${toString dubFlags}"; + combinedBuildFlags = "${combinedFlags} --build=${dubBuildType} ${toString dubBuildFlags}"; + combinedTestFlags = "${combinedFlags} ${toString dubTestFlags}"; +in +stdenv.mkDerivation ( + builtins.removeAttrs args [ "dubLock" ] + // { + strictDeps = args.strictDeps or true; + + nativeBuildInputs = args.nativeBuildInputs or [ ] ++ [ + dub + compiler + removeReferencesTo + ]; + + configurePhase = + args.configurePhase or '' + runHook preConfigure + + export DUB_HOME="$NIX_BUILD_TOP/.dub" + mkdir -p $DUB_HOME + + # register dependencies + ${lib.concatMapStringsSep "\n" (dep: '' + dub fetch ${dep.pname}@${dep.version} --cache=user --skip-registry=standard --registry=file://${dubRegistryBase}/${dep.pname} + '') lockedDeps} + + runHook postConfigure + ''; + + buildPhase = + args.buildPhase or '' + runHook preBuild + + dub build ${combinedBuildFlags} + + runHook postBuild + ''; + + doCheck = args.doCheck or false; + + checkPhase = + args.checkPhase or '' + runHook preCheck + + dub test ${combinedTestFlags} + + runHook postCheck + ''; + + preFixup = '' + ${args.preFixup or ""} + + find "$out" -type f -exec remove-references-to -t ${compiler} '{}' + + ''; + + disallowedReferences = [ compiler ]; + + meta = { + platforms = dub.meta.platforms; + } // args.meta or { }; + } +) diff --git a/pkgs/build-support/dlang/dub-support.nix b/pkgs/build-support/dlang/dub-support.nix new file mode 100644 index 000000000000..879d59357d11 --- /dev/null +++ b/pkgs/build-support/dlang/dub-support.nix @@ -0,0 +1,5 @@ +{ callPackage }: +{ + buildDubPackage = callPackage ./builddubpackage { }; + dub-to-nix = callPackage ./dub-to-nix { }; +} diff --git a/pkgs/build-support/dlang/dub-to-nix/default.nix b/pkgs/build-support/dlang/dub-to-nix/default.nix new file mode 100644 index 000000000000..53a2e99c18df --- /dev/null +++ b/pkgs/build-support/dlang/dub-to-nix/default.nix @@ -0,0 +1,19 @@ +{ + lib, + runCommand, + makeWrapper, + python3, + nix, +}: + +runCommand "dub-to-nix" + { + nativeBuildInputs = [ makeWrapper ]; + buildInputs = [ python3 ]; + } + '' + install -Dm755 ${./dub-to-nix.py} "$out/bin/dub-to-nix" + patchShebangs "$out/bin/dub-to-nix" + wrapProgram "$out/bin/dub-to-nix" \ + --prefix PATH : ${lib.makeBinPath [ nix ]} + '' diff --git a/pkgs/build-support/dlang/dub-to-nix/dub-to-nix.py b/pkgs/build-support/dlang/dub-to-nix/dub-to-nix.py new file mode 100644 index 000000000000..48a9f241348a --- /dev/null +++ b/pkgs/build-support/dlang/dub-to-nix/dub-to-nix.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 + +import sys +import json +import os +import subprocess + +def eprint(text: str): + print(text, file=sys.stderr) + +if not os.path.exists("dub.selections.json"): + eprint("The file `dub.selections.json` does not exist in the current working directory") + eprint("run `dub upgrade --annotate` to generate it") + sys.exit(1) + +with open("dub.selections.json") as f: + selectionsJson = json.load(f) + +versionDict: dict[str, str] = selectionsJson["versions"] + +for pname in versionDict: + version = versionDict[pname] + if version.startswith("~"): + eprint(f'Package "{pname}" has a branch-type version "{version}", which doesn\'t point to a fixed version') + eprint("You can resolve it by manually changing the required version to a fixed one inside `dub.selections.json`") + eprint("When packaging, you might need to create a patch for `dub.sdl` or `dub.json` to accept the changed version") + sys.exit(1) + +lockedDependenciesDict: dict[str, dict[str, str]] = {} + +for pname in versionDict: + version = versionDict[pname] + eprint(f"Fetching {pname}@{version}") + url = f"https://code.dlang.org/packages/{pname}/{version}.zip" + command = ["nix-prefetch-url", "--type", "sha256", url] + sha256 = subprocess.run(command, check=True, text=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout.rstrip() + lockedDependenciesDict[pname] = {"version": version, "sha256": sha256} + +print(json.dumps({"dependencies": lockedDependenciesDict}, indent=2)) diff --git a/pkgs/build-support/fetchurl/mirrors.nix b/pkgs/build-support/fetchurl/mirrors.nix index af0468b3e494..a7e697c55215 100644 --- a/pkgs/build-support/fetchurl/mirrors.nix +++ b/pkgs/build-support/fetchurl/mirrors.nix @@ -312,6 +312,11 @@ "https://backpan.perl.org/" # for old releases ]; + # D DUB + dub = [ + "https://code.dlang.org/packages/" + ]; + # Haskell Hackage hackage = [ "https://hackage.haskell.org/package/" diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index e88689aa7e50..d0d23a2f3c31 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -7577,6 +7577,9 @@ with pkgs; dub = callPackage ../development/tools/build-managers/dub { }; + inherit (import ../build-support/dlang/dub-support.nix { inherit callPackage; }) + buildDubPackage dub-to-nix; + duc = callPackage ../tools/misc/duc { }; duff = callPackage ../tools/filesystems/duff {