{ lib, stdenv, fetchurl, symlinkJoin, }: { # Path to the lockfile generated by gradle2nix (e.g. gradle.lock). lockFile, pname ? "project", version ? null, # Override functions which fetch dependency artifacts. # Keys in this set are URL schemes such as "https" or "s3". # Values are functions which take a dependency in the form # `{ urls, hash }` and fetch into the Nix store. For example: # # { # s3 = { name, urls, hash }: fetchs3 { # s3url = builtins.head urls; # # TODO This doesn't work without patching fetchs3 to accept SRI hashes # inherit name hash; # region = "us-west-2"; # credentials = { # access_key_id = "foo"; # secret_access_key = "bar"; # }; # }; # } fetchers ? { }, # Overlays for dependencies in the offline Maven repository. # # Acceps an attrset of dependencies (usually parsed from 'lockFile'), and produces an attrset # containing dependencies to merge into the final set. # # The attrset is of the form: # # { # "${group}:${module}:${version}" = ; # # ... # } # # A dependency derivation unpacks multiple source files into a single Maven-style directory named # "${out}/${groupPath}/${module}/${version}/", where 'groupPath' is the dependency group ID with dot # characters ('.') replaced by the path separator ('/'). # # Examples: # # 1. Add or replace a dependency with a single JAR file: # # (_: { # "com.squareup.okio:okio:3.9.0" = fetchurl { # url = "https://repo.maven.apache.org/maven2/com/squareup/okio/okio/3.9.0/okio-3.9.0.jar"; # hash = "..."; # downloadToTemmp = true; # postFetch = "install -Dt $out/com/squareup/okio/okio/3.9.0/ $downloadedFile" # }; # }) # # 2. Remove a dependency entirely: # # # This works because the result is filtered for values that are derivations. # (_: { # "org.apache.log4j:core:2.23.1" = null; # }) overlays ? [ ], }: let inherit (builtins) attrValues elemAt filter fromJSON getAttr head length mapAttrs replaceStrings ; inherit (lib) mapAttrsToList readFile; inherit (lib.strings) sanitizeDerivationName; toCoordinates = id: let coords = builtins.split ":" id; parseVersion = version: let parts = builtins.split ":" version; base = elemAt parts 0; in if length parts >= 2 then let snapshot = elemAt parts 2; in replaceStrings [ "-SNAPSHOT" ] [ "-${snapshot}" ] base else base; in rec { group = elemAt coords 0; module = elemAt coords 2; version = elemAt coords 4; uniqueVersion = parseVersion version; }; fetchers' = { http = fetchurl; https = fetchurl; } // fetchers; fetch = name: { url, hash }: let scheme = head (builtins.match "([a-z0-9+.-]+)://.*" url); fetch' = getAttr scheme fetchers'; in fetch' { inherit url hash; }; mkModule = id: artifacts: let coords = toCoordinates id; modulePath = "${replaceStrings [ "." ] [ "/" ] coords.group}/${coords.module}/${coords.version}"; in stdenv.mkDerivation { pname = sanitizeDerivationName "${coords.group}-${coords.module}"; version = coords.uniqueVersion; srcs = mapAttrsToList fetch artifacts; dontPatch = true; dontConfigure = true; dontBuild = true; dontFixup = true; dontInstall = true; preUnpack = '' mkdir -p "$out/${modulePath}" ''; unpackCmd = '' cp "$curSrc" "$out/${modulePath}/$(stripHash "$curSrc")" ''; sourceRoot = "."; preferLocalBuild = true; allowSubstitutes = false; }; # Intermediate dependency spec. # # We want to allow overriding dependencies via the 'dependencies' function, # so we pass an intermediate set that maps each Maven coordinate to the # derivation created with 'mkModule'. This allows users extra flexibility # to do things like patching native libraries with patchelf or replacing # artifacts entirely. lockedDependencies = final: if lockFile == null then { } else let lockedDependencySpecs = fromJSON (readFile lockFile); in mapAttrs mkModule lockedDependencySpecs; finalDependencies = let composedExtension = lib.composeManyExtensions overlays; extended = lib.extends composedExtension lockedDependencies; fixed = lib.fix extended; in filter lib.isDerivation (attrValues fixed); offlineRepo = symlinkJoin { name = if version != null then "${pname}-${version}-gradle-repo" else "${pname}-gradle-repo"; paths = finalDependencies; }; in offlineRepo