# This file is generated by gradle2nix. # # Example usage (e.g. in default.nix): # # with (import {}); # let # buildGradle = callPackage ./gradle-env.nix {}; # in # buildGradle { # envSpec = ./gradle-env.json; # # src = ./.; # # gradleFlags = [ "installDist" ]; # # installPhase = '' # mkdir -p $out # cp -r app/build/install/myproject $out # ''; # } { lib , stdenv , buildEnv , fetchs3 , fetchurl , gradleGen , maven , runCommandLocal , symlinkJoin , writeText , writeTextDir }: { # Path to the environment spec generated by gradle2nix (e.g. gradle-env.json). envSpec , pname ? "project" , version ? null , enableParallelBuilding ? true # Arguments to Gradle used to build the project in buildPhase. , gradleFlags ? [ "build" ] # Gradle package to use instead of the one generated by gradle2nix. , gradlePackage ? null # Enable debugging for the Gradle build; this will cause Gradle to run a debug server # and wait for a JVM debugging client to attach. , enableDebug ? false # Additional code to run in the Gradle init script (init.gradle). , extraInit ? "" # Override the default JDK used to run Gradle itself. , buildJdk ? 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, sha256 }` 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 ? { } , ... } @ args: let inherit (builtins) attrValues concatStringsSep elemAt filter fromJSON getAttr hasAttr head length match replaceStrings sort; inherit (lib) assertMsg concatMapStringsSep foldl' groupBy' hasSuffix hasPrefix last mapAttrs mapAttrsToList optionalAttrs optionalString readFile removeSuffix unique versionAtLeast versionOlder; inherit (lib.strings) sanitizeDerivationName; toCoordinates = id: let coords = builtins.split ":" id; in { group = elemAt coords 0; module = elemAt coords 2; }; parseVersion = version: let parts = builtins.split ":" version; base = elemAt parts 0; in { inherit base; exact = base; } // optionalAttrs (length parts >= 2) ( let snapshot = elemAt parts 2; exact = replaceStrings [ "-SNAPSHOT" ] [ "-${snapshot}" ] base; parts = builtins.split "-" timestamp; timestamp = findFirst (match "[0-9]{8}\.[0-9]{6}") parts; buildNumber = let lastPart = last parts; in if match "[0-9]+" lastPart then lastPart else null; in { inherit snapshot exact timestamp buildNumber; } ); snapshotVersion = { revision, snapshot ? null, ... }: if snapshot == null then revision else replaceStrings ["SNAPSHOT"] [snapshot] revision; fetchers' = { http = fetchurl; https = fetchurl; } // fetchers; # Fetch urls using the scheme for the first entry only; there isn't a # straightforward way to tell Nix to try multiple fetchers in turn # and short-circuit on the first successful fetch. fetch = _: { urls, hash }: let first = head urls; scheme = head (builtins.match "([a-z0-9+.-]+)://.*" first); fetch' = getAttr scheme fetchers'; urls' = filter (hasPrefix scheme) urls; in fetch' { urls = urls'; inherit hash; }; mkModuleMetadata = deps: let metadata = group: module: versions: let latest = foldl' (l: v: if l == null || versionOlder l v then v else l) null versions; release = foldl' (l: v: if !(hasSuffix "-SNAPSHOT" v) && (l == null || versionOlder l v) then v else l) null versions; path = "${replaceStrings ["."] ["/"] group}/${module}/maven-metadata.xml"; in writeTextDir path '' ${group} ${module} ${optionalString (latest != null) "${latest}"} ${optionalString (release != null) "${release}"} ${concatMapStringsSep "\n " (v: "${v}") versions} ''; groupedModules = groupBy ({ organisation, module, ... }: "${organisation}:${module}") (mapAttrsToList (_: dep: dep.attrs) deps); in map # mkSnapshotMetadata = { group, module }: version: artifacts: # let # versions' = filter (hasAttr "timestamp") versions; # in # map ({ base, exact, snapshot, timestamp, buildNumber }: # ) versions'; mkModule = { attrs, artifacts }: let modulePath = "${replaceStrings ["."] ["/"] attrs.orgPath}/${attrs.module}/${attrs.revision}"; in stdenv.mkDerivation { pname = "${attrs.group}-${attrs.module}"; version = snapshotVersion attrs.revision; 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; }; mkModules = deps: mapAttrsToList (_: m: mkModule m) deps; # mkSnapshotMetadata = deps: # let # snapshotDeps = filter (dep: dep ? build && dep ? timestamp) deps; # modules = groupBy' # (meta: dep: # let # id = dep.id; # isNewer = dep.build > meta.buildNumber; # # Timestamp values can be bogus, e.g. jitpack.io # updated = if (match "[0-9]{8}\.[0-9]{6}" dep.timestamp) != null # then replaceStrings ["."] [""] dep.timestamp # else ""; # in { # groupId = id.group; # artifactId = id.name; # version = id.version; # timestamp = if isNewer then dep.timestamp else meta.timestamp; # buildNumber = if isNewer then dep.build else meta.buildNumber; # lastUpdated = if isNewer then updated else meta.lastUpdated; # versions = meta.versions or [] ++ [{ # classifier = id.classifier or ""; # extension = id.extension; # value = "${removeSuffix "-SNAPSHOT" id.version}-${dep.timestamp}-${toString dep.build}"; # updated = updated; # }]; # } # ) # { # timestamp = ""; # buildNumber = -1; # lastUpdated = ""; # } # (dep: "${replaceStrings ["."] ["/"] dep.id.group}/${dep.id.name}/${dep.id.version}/maven-metadata.xml") # snapshotDeps; # mkSnapshotVersion = version: '' # # ${optionalString (version.classifier != "") "${version.classifier}"} # ${version.extension} # ${version.value} # ${optionalString (version.updated != "") "${version.updated}"} # # ''; # in # attrValues (mapAttrs (path: meta: # with meta; writeTextDir path '' # # # ${groupId} # ${artifactId} # ${version} # # # ${optionalString (timestamp != "") "${timestamp}"} # ${optionalString (buildNumber != -1) "${toString buildNumber}"} # # ${optionalString (lastUpdated != "") "${lastUpdated}"} # # ${concatMapStringsSep "\n " mkSnapshotVersion versions} # # # # '' # ) modules); mkRepo = name: deps: symlinkJoin { name = "${name}-gradle-repo"; paths = mkModules deps ++ mkModuleMetadata deps ++ mkSnapshotMetadata deps; }; mkInitScript = projectSpec: gradle: let repos = mapAttrs (mkRepo projectSpec.name) projectSpec.dependencies; hasDependencies = mapAttrs (type: deps: deps != []) projectSpec.dependencies; inSettings = pred: script: optionalString pred ( if versionAtLeast gradle.version "6.0" then '' gradle.beforeSettings { ${script} } '' else '' gradle.settingsEvaluated { ${script} } '' ); in assert (assertMsg (hasDependencies.settings -> versionAtLeast gradle.version "6.0") '' Project `${projectSpec.name}' has settings script dependencies, such as settings plugins, which are not supported by gradle2nix for Gradle versions prior to 6.0. Potential remedies: - Pass `--gradle-version=' to the gradle2nix command. - Patch the `settings.gradle[.kts]' file to remove script dependencies. ''); writeText "init.gradle" '' static def offlineRepo(RepositoryHandler repositories, String env, String path) { repositories.clear() repositories.maven { name "Nix''${env.capitalize()}Offline" url path metadataSources { it.gradleMetadata() it.mavenPom() it. } } repositories.ivy { name "Nix''${env.capitalize()}IvyOffline" url path layout "maven" metadataSources { it.gradleMetadata() it.ivyDescriptor() } } } ${inSettings (hasDependencies.settings && (versionAtLeast gradle.version "6.0")) '' offlineRepo(it.buildscript.repositories, "settings", "${repos.settings}") ''} ${inSettings (hasDependencies.plugin) '' offlineRepo(it.pluginManagement.repositories, "plugin", "${repos.plugin}") ''} ${optionalString (hasDependencies.buildscript) '' gradle.projectsLoaded { allprojects { buildscript { offlineRepo(repositories, "buildscript", "${repos.buildscript}") } } } ''} ${optionalString (hasDependencies.project) ( if versionAtLeast gradle.version "6.8" then '' gradle.beforeSettings { it.dependencyResolutionManagement { offlineRepo(repositories, "project", "${repos.project}") repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS) } } '' else '' gradle.projectsLoaded { allprojects { offlineRepo(repositories, "project", "${repos.project}") } } '' )} ${extraInit} ''; mkGradle = gradleSpec: gradleGen.gradleGen { inherit (gradleSpec) nativeVersion; name = "gradle-${gradleSpec.version}-${gradleSpec.type}"; src = fetchurl { inherit (gradleSpec) url sha256; }; } // { inherit (gradleSpec) version; }; mkProjectEnv = projectSpec: rec { inherit (projectSpec) name path version; gradle = args.gradlePackage or mkGradle projectSpec.gradle; initScript = mkInitScript projectSpec gradle; }; gradleEnv = mapAttrs (_: p: mkProjectEnv p) (fromJSON (readFile envSpec)); projectEnv = gradleEnv.""; pname = args.pname or projectEnv.name; version = args.version or projectEnv.version; buildProject = env: flags: '' cp ${env.initScript} "$GRADLE_USER_HOME/init.d" gradle --offline --no-daemon --no-build-cache \ --info --full-stacktrace --warning-mode=all \ ${optionalString enableParallelBuilding "--parallel"} \ ${optionalString enableDebug "-Dorg.gradle.debug=true"} \ ${optionalString (buildJdk != null) "-Dorg.gradle.java.home=${buildJdk.home}"} \ --init-script ${env.initScript} \ ${optionalString (env.path != "") ''-p "${env.path}"''} \ ${concatStringsSep " " flags} ''; buildIncludedProjects = concatStringsSep "\n" (mapAttrsToList (_: env: buildProject env [ "build" ]) (removeAttrs gradleEnv [ "" ])); buildRootProject = buildProject projectEnv gradleFlags; # in stdenv.mkDerivation (args // { # inherit pname version; # nativeBuildInputs = (args.nativeBuildInputs or []) ++ [ projectEnv.gradle ]; # buildPhase = args.buildPhase or '' # runHook preBuild # ( # set -eux # # Work around https://github.com/gradle/gradle/issues/1055 # TMPHOME="$(mktemp -d)" # mkdir -p "$TMPHOME/init.d" # export GRADLE_USER_HOME="$TMPHOME" # ${buildIncludedProjects} # ${buildRootProject} # ) # runHook postBuild # ''; # dontStrip = true; # }) in mkRepo pname (fromJSON (readFile envSpec))