Resolve and apply settings buildscript dependencies

This commit is contained in:
Tad Fisher
2020-11-24 16:35:48 -08:00
parent a99b5f40e3
commit fd6a6f4693
20 changed files with 951 additions and 41 deletions

View File

@@ -32,12 +32,12 @@
let let
inherit (builtins) inherit (builtins)
filter sort replaceStrings attrValues match fromJSON attrValues concatStringsSep filter fromJSON match replaceStrings sort;
concatStringsSep;
inherit (stdenv.lib) inherit (stdenv.lib)
versionOlder unique mapAttrs mapAttrsToList last concatMapStringsSep assertMsg concatMapStringsSep groupBy' hasSuffix last mapAttrs
removeSuffix optionalString groupBy' readFile hasSuffix; mapAttrsToList optionalString readFile removeSuffix unique versionAtLeast
versionOlder;
mkDep = depSpec: stdenv.mkDerivation { mkDep = depSpec: stdenv.mkDerivation {
inherit (depSpec) name; inherit (depSpec) name;
@@ -176,10 +176,20 @@ let
paths = map mkDep deps ++ mkModuleMetadata deps ++ mkSnapshotMetadata deps; paths = map mkDep deps ++ mkModuleMetadata deps ++ mkSnapshotMetadata deps;
}; };
mkInitScript = projectSpec: mkInitScript = projectSpec: gradle:
let let
repos = mapAttrs (mkRepo projectSpec.name) projectSpec.dependencies; repos = mapAttrs (mkRepo projectSpec.name) projectSpec.dependencies;
hasDependencies = mapAttrs (type: deps: deps != []) projectSpec.dependencies;
in 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=<version>' to the gradle2nix command.
- Patch the `settings.gradle[.kts]' file to remove script dependencies.
'');
writeText "init.gradle" '' writeText "init.gradle" ''
static def offlineRepo(RepositoryHandler repositories, String env, String path) { static def offlineRepo(RepositoryHandler repositories, String env, String path) {
repositories.clear() repositories.clear()
@@ -204,18 +214,35 @@ let
} }
} }
gradle.settingsEvaluated { ${optionalString (hasDependencies.settings && (versionAtLeast gradle.version "6.0")) ''
offlineRepo(it.pluginManagement.repositories, "plugin", "${repos.plugin}") gradle.beforeSettings {
} offlineRepo(it.buildscript.repositories, "settings", "${repos.settings}")
}
''}
gradle.projectsLoaded { ${optionalString (hasDependencies.plugin) ''
allprojects { gradle.settingsEvaluated {
buildscript { offlineRepo(it.pluginManagement.repositories, "plugin", "${repos.plugin}")
offlineRepo(repositories, "buildscript", "${repos.buildscript}") }
} ''}
offlineRepo(repositories, "project", "${repos.project}")
} ${optionalString (hasDependencies.buildscript) ''
} gradle.projectsLoaded {
allprojects {
buildscript {
offlineRepo(repositories, "buildscript", "${repos.buildscript}")
}
}
}
''}
${optionalString (hasDependencies.project) ''
gradle.projectsLoaded {
allprojects {
offlineRepo(repositories, "project", "${repos.project}")
}
}
''}
''; '';
mkGradle = gradleSpec: mkGradle = gradleSpec:
@@ -227,12 +254,14 @@ let
src = fetchurl { src = fetchurl {
inherit (gradleSpec) url sha256; inherit (gradleSpec) url sha256;
}; };
} // {
inherit (gradleSpec) version;
}; };
mkProjectEnv = projectSpec: { mkProjectEnv = projectSpec: rec {
inherit (projectSpec) name path version; inherit (projectSpec) name path version;
initScript = mkInitScript projectSpec;
gradle = args.gradlePackage or mkGradle projectSpec.gradle; gradle = args.gradlePackage or mkGradle projectSpec.gradle;
initScript = mkInitScript projectSpec gradle;
}; };
gradleEnv = mapAttrs gradleEnv = mapAttrs

View File

@@ -19,6 +19,7 @@ fun buildEnv(builds: Map<String, DefaultBuild>): Map<String, NixGradleEnv> =
path = path, path = path,
gradle = build.gradle, gradle = build.gradle,
dependencies = mapOf( dependencies = mapOf(
"settings" to build.settingsDependencies,
"plugin" to build.pluginDependencies, "plugin" to build.pluginDependencies,
"buildscript" to build.rootProject.collectDependencies(DefaultProject::buildscriptDependencies), "buildscript" to build.rootProject.collectDependencies(DefaultProject::buildscriptDependencies),
"project" to build.rootProject.collectDependencies(DefaultProject::projectDependencies) "project" to build.rootProject.collectDependencies(DefaultProject::projectDependencies)

View File

@@ -0,0 +1 @@
version = '1.1.0'

View File

@@ -0,0 +1,9 @@
with (import <nixpkgs> {});
let
buildGradle = callPackage ./gradle-env.nix {};
in
buildGradle {
envSpec = ./gradle-env.json;
src = ./.;
gradleFlags = [ "tasks" ];
}

View File

@@ -0,0 +1,456 @@
{
"": {
"name": "settings-buildscript",
"version": "1.1.0",
"path": "",
"gradle": {
"version": "5.0",
"type": "bin",
"url": "https://services.gradle.org/distributions/gradle-5.0-bin.zip",
"sha256": "6157ac9f3410bc63644625b3b3e9e96c963afd7910ae0697792db57813ee79a6",
"nativeVersion": "0.14"
},
"dependencies": {
"settings": [
{
"id": {
"group": "com.googlecode.javaewah",
"name": "JavaEWAH",
"version": "1.1.6",
"type": "jar",
"extension": "jar"
},
"name": "JavaEWAH-1.1.6.jar",
"path": "com/googlecode/javaewah/JavaEWAH/1.1.6",
"urls": [
"https://plugins.gradle.org/m2/com/googlecode/javaewah/JavaEWAH/1.1.6/JavaEWAH-1.1.6.jar"
],
"sha256": "f78d44a1e3877f1ce748b4a85df5171e5e8e9a5c3c6f63bb9003db6f84cce952"
},
{
"id": {
"group": "com.googlecode.javaewah",
"name": "JavaEWAH",
"version": "1.1.6",
"type": "pom",
"extension": "pom"
},
"name": "JavaEWAH-1.1.6.pom",
"path": "com/googlecode/javaewah/JavaEWAH/1.1.6",
"urls": [
"https://plugins.gradle.org/m2/com/googlecode/javaewah/JavaEWAH/1.1.6/JavaEWAH-1.1.6.pom"
],
"sha256": "7f4ff919b1ee17bf3776e058a3f20e6173db23a5e44cf2d107ec7570c186abf0"
},
{
"id": {
"group": "com.jcraft",
"name": "jsch",
"version": "0.1.54",
"type": "jar",
"extension": "jar"
},
"name": "jsch-0.1.54.jar",
"path": "com/jcraft/jsch/0.1.54",
"urls": [
"https://plugins.gradle.org/m2/com/jcraft/jsch/0.1.54/jsch-0.1.54.jar"
],
"sha256": "92eb273a3316762478fdd4fe03a0ce1842c56f496c9c12fe1235db80450e1fdb"
},
{
"id": {
"group": "com.jcraft",
"name": "jsch",
"version": "0.1.54",
"type": "pom",
"extension": "pom"
},
"name": "jsch-0.1.54.pom",
"path": "com/jcraft/jsch/0.1.54",
"urls": [
"https://plugins.gradle.org/m2/com/jcraft/jsch/0.1.54/jsch-0.1.54.pom"
],
"sha256": "ab8f512039be7f6ae20e18e743b4a9d8a20958494431917da58ae5aaef8a3478"
},
{
"id": {
"group": "commons-codec",
"name": "commons-codec",
"version": "1.6",
"type": "jar",
"extension": "jar"
},
"name": "commons-codec-1.6.jar",
"path": "commons-codec/commons-codec/1.6",
"urls": [
"https://plugins.gradle.org/m2/commons-codec/commons-codec/1.6/commons-codec-1.6.jar"
],
"sha256": "54b34e941b8e1414bd3e40d736efd3481772dc26db3296f6aa45cec9f6203d86"
},
{
"id": {
"group": "commons-codec",
"name": "commons-codec",
"version": "1.6",
"type": "pom",
"extension": "pom"
},
"name": "commons-codec-1.6.pom",
"path": "commons-codec/commons-codec/1.6",
"urls": [
"https://plugins.gradle.org/m2/commons-codec/commons-codec/1.6/commons-codec-1.6.pom"
],
"sha256": "a06e35d3fff3a6b813d94894ebf3e498f9540c864c5b39ae783907e3a6c72889"
},
{
"id": {
"group": "commons-logging",
"name": "commons-logging",
"version": "1.1.3",
"type": "jar",
"extension": "jar"
},
"name": "commons-logging-1.1.3.jar",
"path": "commons-logging/commons-logging/1.1.3",
"urls": [
"https://plugins.gradle.org/m2/commons-logging/commons-logging/1.1.3/commons-logging-1.1.3.jar"
],
"sha256": "70903f6fc82e9908c8da9f20443f61d90f0870a312642991fe8462a0b9391784"
},
{
"id": {
"group": "commons-logging",
"name": "commons-logging",
"version": "1.1.3",
"type": "pom",
"extension": "pom"
},
"name": "commons-logging-1.1.3.pom",
"path": "commons-logging/commons-logging/1.1.3",
"urls": [
"https://plugins.gradle.org/m2/commons-logging/commons-logging/1.1.3/commons-logging-1.1.3.pom"
],
"sha256": "3250ac3ac6bd60ed0631f5cd0335032b2993d63e405a6ae0555d27a7e4865849"
},
{
"id": {
"group": "gradle.plugin.net.vivin",
"name": "gradle-semantic-build-versioning",
"version": "4.0.0",
"type": "jar",
"extension": "jar"
},
"name": "gradle-semantic-build-versioning-4.0.0.jar",
"path": "gradle/plugin/net/vivin/gradle-semantic-build-versioning/4.0.0",
"urls": [
"https://plugins.gradle.org/m2/gradle/plugin/net/vivin/gradle-semantic-build-versioning/4.0.0/gradle-semantic-build-versioning-4.0.0.jar"
],
"sha256": "5138e67ce8e019437800b93c9f6f9d0fcbebefadc96fbc4ebc0975c99a261ef8"
},
{
"id": {
"group": "gradle.plugin.net.vivin",
"name": "gradle-semantic-build-versioning",
"version": "4.0.0",
"type": "pom",
"extension": "pom"
},
"name": "gradle-semantic-build-versioning-4.0.0.pom",
"path": "gradle/plugin/net/vivin/gradle-semantic-build-versioning/4.0.0",
"urls": [
"https://plugins.gradle.org/m2/gradle/plugin/net/vivin/gradle-semantic-build-versioning/4.0.0/gradle-semantic-build-versioning-4.0.0.pom"
],
"sha256": "4f2828741607ed102d95eb5f189d496c7840ed463acea89f1e51a60567714ef7"
},
{
"id": {
"group": "org.apache",
"name": "apache",
"version": "9",
"type": "pom",
"extension": "pom"
},
"name": "apache-9.pom",
"path": "org/apache/apache/9",
"urls": [
"https://plugins.gradle.org/m2/org/apache/apache/9/apache-9.pom"
],
"sha256": "4946e60a547c8eda69f3bc23c5b6f0dadcf8469ea49b1d1da7de34aecfcf18dd"
},
{
"id": {
"group": "org.apache",
"name": "apache",
"version": "13",
"type": "pom",
"extension": "pom"
},
"name": "apache-13.pom",
"path": "org/apache/apache/13",
"urls": [
"https://plugins.gradle.org/m2/org/apache/apache/13/apache-13.pom"
],
"sha256": "ff513db0361fd41237bef4784968bc15aae478d4ec0a9496f811072ccaf3841d"
},
{
"id": {
"group": "org.apache.commons",
"name": "commons-parent",
"version": "22",
"type": "pom",
"extension": "pom"
},
"name": "commons-parent-22.pom",
"path": "org/apache/commons/commons-parent/22",
"urls": [
"https://plugins.gradle.org/m2/org/apache/commons/commons-parent/22/commons-parent-22.pom"
],
"sha256": "fb8c5e55e30a7addb4ff210858a0e8d2494ed6757bbe19012da99d51586c3cbb"
},
{
"id": {
"group": "org.apache.commons",
"name": "commons-parent",
"version": "28",
"type": "pom",
"extension": "pom"
},
"name": "commons-parent-28.pom",
"path": "org/apache/commons/commons-parent/28",
"urls": [
"https://plugins.gradle.org/m2/org/apache/commons/commons-parent/28/commons-parent-28.pom"
],
"sha256": "14733a68e8b120b69de60cd96d222146dcf32f03c1c6cc6a750b1269bafe86c7"
},
{
"id": {
"group": "org.apache.httpcomponents",
"name": "httpclient",
"version": "4.3.6",
"type": "jar",
"extension": "jar"
},
"name": "httpclient-4.3.6.jar",
"path": "org/apache/httpcomponents/httpclient/4.3.6",
"urls": [
"https://plugins.gradle.org/m2/org/apache/httpcomponents/httpclient/4.3.6/httpclient-4.3.6.jar"
],
"sha256": "79838d9eaef73d4f852c63a480830c3a2d4b590f0ab3ae815a489463e4714004"
},
{
"id": {
"group": "org.apache.httpcomponents",
"name": "httpclient",
"version": "4.3.6",
"type": "pom",
"extension": "pom"
},
"name": "httpclient-4.3.6.pom",
"path": "org/apache/httpcomponents/httpclient/4.3.6",
"urls": [
"https://plugins.gradle.org/m2/org/apache/httpcomponents/httpclient/4.3.6/httpclient-4.3.6.pom"
],
"sha256": "d02634f6131e914961c02aa836711ebac72704b27e26c5bd223bbad89b1b64c3"
},
{
"id": {
"group": "org.apache.httpcomponents",
"name": "httpcomponents-client",
"version": "4.3.6",
"type": "pom",
"extension": "pom"
},
"name": "httpcomponents-client-4.3.6.pom",
"path": "org/apache/httpcomponents/httpcomponents-client/4.3.6",
"urls": [
"https://plugins.gradle.org/m2/org/apache/httpcomponents/httpcomponents-client/4.3.6/httpcomponents-client-4.3.6.pom"
],
"sha256": "4ada2827b496339826891c7c81dceba647029de6fc1888b16b3cab5650abcc63"
},
{
"id": {
"group": "org.apache.httpcomponents",
"name": "httpcomponents-core",
"version": "4.3.3",
"type": "pom",
"extension": "pom"
},
"name": "httpcomponents-core-4.3.3.pom",
"path": "org/apache/httpcomponents/httpcomponents-core/4.3.3",
"urls": [
"https://plugins.gradle.org/m2/org/apache/httpcomponents/httpcomponents-core/4.3.3/httpcomponents-core-4.3.3.pom"
],
"sha256": "c16e2fc0d49ba7a02cef5b5e2600585a9f673553328a6f9e58f24296df1dd031"
},
{
"id": {
"group": "org.apache.httpcomponents",
"name": "httpcore",
"version": "4.3.3",
"type": "jar",
"extension": "jar"
},
"name": "httpcore-4.3.3.jar",
"path": "org/apache/httpcomponents/httpcore/4.3.3",
"urls": [
"https://plugins.gradle.org/m2/org/apache/httpcomponents/httpcore/4.3.3/httpcore-4.3.3.jar"
],
"sha256": "5285de80af1651c489313b91a9f40c65a4cdcb6b3bde716fcc028d16869a5a93"
},
{
"id": {
"group": "org.apache.httpcomponents",
"name": "httpcore",
"version": "4.3.3",
"type": "pom",
"extension": "pom"
},
"name": "httpcore-4.3.3.pom",
"path": "org/apache/httpcomponents/httpcore/4.3.3",
"urls": [
"https://plugins.gradle.org/m2/org/apache/httpcomponents/httpcore/4.3.3/httpcore-4.3.3.pom"
],
"sha256": "b427f7cf67c75a4e3f9e2108d35bf45303573c145ec778fcadcffacef17a1264"
},
{
"id": {
"group": "org.apache.httpcomponents",
"name": "project",
"version": "7",
"type": "pom",
"extension": "pom"
},
"name": "project-7.pom",
"path": "org/apache/httpcomponents/project/7",
"urls": [
"https://plugins.gradle.org/m2/org/apache/httpcomponents/project/7/project-7.pom"
],
"sha256": "3d6eba428555a558de046b5d76eacc1f5a54b4f5f20b84d636ed7aff18aa48c3"
},
{
"id": {
"group": "org.eclipse.jgit",
"name": "org.eclipse.jgit",
"version": "4.8.0.201706111038-r",
"type": "jar",
"extension": "jar"
},
"name": "org.eclipse.jgit-4.8.0.201706111038-r.jar",
"path": "org/eclipse/jgit/org.eclipse.jgit/4.8.0.201706111038-r",
"urls": [
"https://plugins.gradle.org/m2/org/eclipse/jgit/org.eclipse.jgit/4.8.0.201706111038-r/org.eclipse.jgit-4.8.0.201706111038-r.jar"
],
"sha256": "49d912e8d5cce0dd08dca3d390189db8692a8f7e3363cdbbe182581462000aba"
},
{
"id": {
"group": "org.eclipse.jgit",
"name": "org.eclipse.jgit",
"version": "4.8.0.201706111038-r",
"type": "pom",
"extension": "pom"
},
"name": "org.eclipse.jgit-4.8.0.201706111038-r.pom",
"path": "org/eclipse/jgit/org.eclipse.jgit/4.8.0.201706111038-r",
"urls": [
"https://plugins.gradle.org/m2/org/eclipse/jgit/org.eclipse.jgit/4.8.0.201706111038-r/org.eclipse.jgit-4.8.0.201706111038-r.pom"
],
"sha256": "a556a9f5adfc6af49b2a12e72dc3cd7e43db8fdc216c0f35885972a2f5ada27d"
},
{
"id": {
"group": "org.eclipse.jgit",
"name": "org.eclipse.jgit-parent",
"version": "4.8.0.201706111038-r",
"type": "pom",
"extension": "pom"
},
"name": "org.eclipse.jgit-parent-4.8.0.201706111038-r.pom",
"path": "org/eclipse/jgit/org.eclipse.jgit-parent/4.8.0.201706111038-r",
"urls": [
"https://plugins.gradle.org/m2/org/eclipse/jgit/org.eclipse.jgit-parent/4.8.0.201706111038-r/org.eclipse.jgit-parent-4.8.0.201706111038-r.pom"
],
"sha256": "396a4cc894206873ff107d066a996252b0b47f585b88cf57fc3b31e93d492878"
},
{
"id": {
"group": "org.slf4j",
"name": "slf4j-api",
"version": "1.7.2",
"type": "jar",
"extension": "jar"
},
"name": "slf4j-api-1.7.2.jar",
"path": "org/slf4j/slf4j-api/1.7.2",
"urls": [
"https://plugins.gradle.org/m2/org/slf4j/slf4j-api/1.7.2/slf4j-api-1.7.2.jar"
],
"sha256": "3bae789b401333b2a1d1603b7fa573e19908628191707203f6eb708cdee2c052"
},
{
"id": {
"group": "org.slf4j",
"name": "slf4j-api",
"version": "1.7.2",
"type": "pom",
"extension": "pom"
},
"name": "slf4j-api-1.7.2.pom",
"path": "org/slf4j/slf4j-api/1.7.2",
"urls": [
"https://plugins.gradle.org/m2/org/slf4j/slf4j-api/1.7.2/slf4j-api-1.7.2.pom"
],
"sha256": "2eaca71afe0a1516f4abd8e9ff907838d268f38c81c3a542cce8d7f3b87c5d4c"
},
{
"id": {
"group": "org.slf4j",
"name": "slf4j-parent",
"version": "1.7.2",
"type": "pom",
"extension": "pom"
},
"name": "slf4j-parent-1.7.2.pom",
"path": "org/slf4j/slf4j-parent/1.7.2",
"urls": [
"https://plugins.gradle.org/m2/org/slf4j/slf4j-parent/1.7.2/slf4j-parent-1.7.2.pom"
],
"sha256": "1d8e084a6f2384ade42685332b52a0ece090478641dc14c0fa8c52e1e2984425"
},
{
"id": {
"group": "org.sonatype.oss",
"name": "oss-parent",
"version": "5",
"type": "pom",
"extension": "pom"
},
"name": "oss-parent-5.pom",
"path": "org/sonatype/oss/oss-parent/5",
"urls": [
"https://plugins.gradle.org/m2/org/sonatype/oss/oss-parent/5/oss-parent-5.pom"
],
"sha256": "1678d4120a585d8a630131aeec4c524d928398583b7eab616ee7d5a87f520d3d"
},
{
"id": {
"group": "org.sonatype.oss",
"name": "oss-parent",
"version": "6",
"type": "pom",
"extension": "pom"
},
"name": "oss-parent-6.pom",
"path": "org/sonatype/oss/oss-parent/6",
"urls": [
"https://plugins.gradle.org/m2/org/sonatype/oss/oss-parent/6/oss-parent-6.pom"
],
"sha256": "b4306d13e8f5392458a1b30866f1cff161b3d2e6999a88d059eea3932c8a8499"
}
],
"plugin": [],
"buildscript": [],
"project": []
}
}
}

View File

@@ -0,0 +1,318 @@
# This file is generated by gradle2nix.
#
# Example usage (e.g. in default.nix):
#
# with (import <nixpkgs> {});
# 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
# '';
# }
{ stdenv, buildEnv, fetchurl, gradleGen, writeText, writeTextDir }:
{ envSpec
, pname ? null
, version ? null
, enableParallelBuilding ? true
, gradleFlags ? [ "build" ]
, gradlePackage ? null
, enableDebug ? false
, ... } @ args:
let
inherit (builtins)
attrValues concatStringsSep filter fromJSON match replaceStrings sort;
inherit (stdenv.lib)
assertMsg concatMapStringsSep groupBy' hasSuffix last mapAttrs
mapAttrsToList optionalString readFile removeSuffix unique versionAtLeast
versionOlder;
mkDep = depSpec: stdenv.mkDerivation {
inherit (depSpec) name;
src = fetchurl {
inherit (depSpec) urls sha256;
};
phases = "installPhase";
installPhase = ''
mkdir -p $out/${depSpec.path}
ln -s $src $out/${depSpec.path}/${depSpec.name}
'';
};
mkModuleMetadata = deps:
let
ids = filter
(id: id.type == "pom")
(map (dep: dep.id) deps);
modules = groupBy'
(meta: id:
let
isNewer = versionOlder meta.latest id.version;
isNewerRelease =
!(hasSuffix "-SNAPSHOT" id.version) &&
versionOlder meta.release id.version;
in {
groupId = id.group;
artifactId = id.name;
latest = if isNewer then id.version else meta.latest;
release = if isNewerRelease then id.version else meta.release;
versions = meta.versions ++ [id.version];
}
)
{
latest = "";
release = "";
versions = [];
}
(id: "${replaceStrings ["."] ["/"] id.group}/${id.name}/maven-metadata.xml")
ids;
in
attrValues (mapAttrs (path: meta:
let
versions' = sort versionOlder (unique meta.versions);
in
with meta; writeTextDir path ''
<?xml version="1.0" encoding="UTF-8"?>
<metadata modelVersion="1.1">
<groupId>${groupId}</groupId>
<artifactId>${artifactId}</artifactId>
<versioning>
${optionalString (latest != "") "<latest>${latest}</latest>"}
${optionalString (release != "") "<release>${release}</release>"}
<versions>
${concatMapStringsSep "\n " (v: "<version>${v}</version>") versions'}
</versions>
</versioning>
</metadata>
''
) modules);
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: ''
<snapshotVersion>
${optionalString (version.classifier != "") "<classifier>${version.classifier}</classifier>"}
<extension>${version.extension}</extension>
<value>${version.value}</value>
${optionalString (version.updated != "") "<updated>${version.updated}</updated>"}
</snapshotVersion>
'';
in
attrValues (mapAttrs (path: meta:
with meta; writeTextDir path ''
<?xml version="1.0" encoding="UTF-8"?>
<metadata modelVersion="1.1">
<groupId>${groupId}</groupId>
<artifactId>${artifactId}</artifactId>
<version>${version}</version>
<versioning>
<snapshot>
${optionalString (timestamp != "") "<timestamp>${timestamp}</timestamp>"}
${optionalString (buildNumber != -1) "<buildNumber>${toString buildNumber}</buildNumber>"}
</snapshot>
${optionalString (lastUpdated != "") "<lastUpdated>${lastUpdated}</lastUpdated>"}
<snapshotVersions>
${concatMapStringsSep "\n " mkSnapshotVersion versions}
</snapshotVersions>
</versioning>
</metadata>
''
) modules);
mkRepo = project: type: deps: buildEnv {
name = "${project}-gradle-${type}-env";
paths = map mkDep deps ++ mkModuleMetadata deps ++ mkSnapshotMetadata deps;
};
mkInitScript = projectSpec: gradle:
let
repos = mapAttrs (mkRepo projectSpec.name) projectSpec.dependencies;
hasDependencies = mapAttrs (type: deps: deps != []) projectSpec.dependencies;
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=<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()}MavenOffline"
url path
metadataSources {
it.gradleMetadata()
it.mavenPom()
it.artifact()
}
}
repositories.ivy {
name "Nix''${env.capitalize()}IvyOffline"
url path
layout "maven"
metadataSources {
it.gradleMetadata()
it.ivyDescriptor()
it.artifact()
}
}
}
${optionalString (hasDependencies.settings && (versionAtLeast gradle.version "6.0")) ''
gradle.beforeSettings {
offlineRepo(it.buildscript.repositories, "settings", "${repos.settings}")
}
''}
${optionalString (hasDependencies.plugin) ''
gradle.settingsEvaluated {
offlineRepo(it.pluginManagement.repositories, "plugin", "${repos.plugin}")
}
''}
${optionalString (hasDependencies.buildscript) ''
gradle.projectsLoaded {
allprojects {
buildscript {
offlineRepo(repositories, "buildscript", "${repos.buildscript}")
}
}
}
''}
${optionalString (hasDependencies.project) ''
gradle.projectsLoaded {
allprojects {
offlineRepo(repositories, "project", "${repos.project}")
}
}
''}
'';
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: ''
gradle --offline --no-daemon --no-build-cache \
--info --full-stacktrace --warning-mode=all \
${optionalString enableParallelBuilding "--parallel"} \
${optionalString enableDebug "-Dorg.gradle.debug=true"} \
--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 -x
# use the init script here
TMPHOME=$(mktemp -d)
mkdir -p $TMPHOME/init.d
cp ${projectEnv.initScript} $TMPHOME/init.d
export "GRADLE_USER_HOME=$TMPHOME"
${buildIncludedProjects}
${buildRootProject}
)
runHook postBuild
'';
dontStrip = true;
})

View File

@@ -0,0 +1 @@
startingVersion = '1.0.0'

View File

@@ -0,0 +1,14 @@
buildscript {
repositories {
maven {
url 'https://plugins.gradle.org/m2/'
}
}
dependencies {
classpath 'gradle.plugin.net.vivin:gradle-semantic-build-versioning:4.0.0'
}
}
rootProject.name = "settings-buildscript"
//apply plugin: 'net.vivin.gradle-semantic-build-versioning'

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache</groupId>
<artifactId>test</artifactId>
<version>1.0.0</version>
<name>test</name>
<description>
test
</description>
</project>

View File

@@ -1 +0,0 @@
6eb7552156e0d517ae80cc2247be1427c8d90452

View File

@@ -1 +0,0 @@
9797702ee3e52e4be6bfbbc9fd20ac5447e7a541

View File

@@ -0,0 +1,10 @@
buildscript {
repositories {
maven {
url 'http://localhost:9999/'
}
}
dependencies {
classpath 'org.apache:test:1.0.0'
}
}

View File

@@ -8,12 +8,14 @@ import java.lang.IllegalArgumentException
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
data class DefaultBuild( data class DefaultBuild(
override val gradle: DefaultGradle, override val gradle: DefaultGradle,
override val settingsDependencies: List<DefaultArtifact>,
override val pluginDependencies: List<DefaultArtifact>, override val pluginDependencies: List<DefaultArtifact>,
override val rootProject: DefaultProject, override val rootProject: DefaultProject,
override val includedBuilds: List<DefaultIncludedBuild> override val includedBuilds: List<DefaultIncludedBuild>
) : Build, Serializable { ) : Build, Serializable {
constructor(model: Build) : this( constructor(model: Build) : this(
DefaultGradle(model.gradle), DefaultGradle(model.gradle),
model.settingsDependencies.map(::DefaultArtifact),
model.pluginDependencies.map(::DefaultArtifact), model.pluginDependencies.map(::DefaultArtifact),
DefaultProject(model.rootProject), DefaultProject(model.rootProject),
model.includedBuilds.map(::DefaultIncludedBuild) model.includedBuilds.map(::DefaultIncludedBuild)

View File

@@ -2,6 +2,7 @@ package org.nixos.gradle2nix
interface Build { interface Build {
val gradle: Gradle val gradle: Gradle
val settingsDependencies: List<Artifact>
val pluginDependencies: List<Artifact> val pluginDependencies: List<Artifact>
val rootProject: Project val rootProject: Project
val includedBuilds: List<IncludedBuild> val includedBuilds: List<IncludedBuild>

View File

@@ -1,10 +1,13 @@
package org.nixos.gradle2nix package org.nixos.gradle2nix
import dev.minutest.Tests import dev.minutest.Tests
import dev.minutest.experimental.FOCUS
import dev.minutest.experimental.minus
import dev.minutest.junit.JUnit5Minutests import dev.minutest.junit.JUnit5Minutests
import dev.minutest.rootContext import dev.minutest.rootContext
import strikt.api.expectThat import strikt.api.expectThat
import strikt.assertions.contains import strikt.assertions.contains
import strikt.assertions.containsExactly
class PluginTest : JUnit5Minutests { class PluginTest : JUnit5Minutests {
@Tests @Tests

View File

@@ -0,0 +1,26 @@
package org.nixos.gradle2nix
import dev.minutest.Tests
import dev.minutest.junit.JUnit5Minutests
import dev.minutest.rootContext
import strikt.api.expectThat
import strikt.assertions.containsExactly
class SettingsTest : JUnit5Minutests {
@Tests
fun tests() = rootContext("settings tests") {
withRepository("m2") {
withFixture("settings/buildscript") {
test("resolves settings plugin in buildscript classpath") {
expectThat(build()) {
get("settings dependencies") { settingsDependencies }.ids
.containsExactly(
"org.apache:test:1.0.0@jar",
"org.apache:test:1.0.0@pom"
)
}
}
}
}
}
}

View File

@@ -168,29 +168,27 @@ fun ContextBuilder<*>.withRepository(
fun ContextBuilder<*>.withFixture( fun ContextBuilder<*>.withFixture(
name: String, name: String,
block: TestContextBuilder<*, ProjectFixture>.() -> Unit block: TestContextBuilder<*, ProjectFixture>.() -> Unit
) { ) = derivedContext<TestFixture>(name) {
derivedContext<TestFixture>(name) { val url = checkNotNull(Thread.currentThread().contextClassLoader.getResource(name)?.toURI()) {
val url = checkNotNull(Thread.currentThread().contextClassLoader.getResource(name)?.toURI()) { "$name: No test fixture found"
"$name: No test fixture found" }
} val fixtureRoot = Paths.get(url).toFile().absoluteFile
val fixtureRoot = Paths.get(url).toFile().absoluteFile
deriveFixture { deriveFixture {
TestFixture(name, fixtureRoot) TestFixture(name, fixtureRoot)
} }
val testRoots = fixtureRoot.listFiles()!! val testRoots = fixtureRoot.listFiles()!!
.filter { it.isDirectory } .filter { it.isDirectory }
.map { it.absoluteFile } .map { it.absoluteFile }
.toList() .toList()
testRoots.forEach { testRoot -> testRoots.forEach { testRoot ->
derivedContext<ProjectFixture>(testRoot.name) { derivedContext<ProjectFixture>(testRoot.name) {
deriveFixture { ProjectFixture(this, testRoot) } deriveFixture { ProjectFixture(this, testRoot) }
before { copy() } before { copy() }
after { close() } after { close() }
block() block()
}
} }
} }
} }

View File

@@ -28,7 +28,8 @@ import org.gradle.util.GradleVersion
enum class ConfigurationScope { enum class ConfigurationScope {
BUILDSCRIPT, BUILDSCRIPT,
PLUGIN, PLUGIN,
PROJECT PROJECT,
SETTINGS
} }
internal class ConfigurationResolverFactory( internal class ConfigurationResolverFactory(

View File

@@ -6,6 +6,7 @@ import org.gradle.api.Project
import org.gradle.api.Task import org.gradle.api.Task
import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.ProjectDependency import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.internal.GradleInternal
import org.gradle.api.invocation.Gradle import org.gradle.api.invocation.Gradle
import org.gradle.api.tasks.TaskContainer import org.gradle.api.tasks.TaskContainer
import org.gradle.api.tasks.wrapper.Wrapper import org.gradle.api.tasks.wrapper.Wrapper
@@ -85,6 +86,7 @@ private fun Project.buildModel(
modelProperties: ModelProperties, modelProperties: ModelProperties,
pluginRequests: List<PluginRequest> pluginRequests: List<PluginRequest>
): DefaultBuild { ): DefaultBuild {
val settingsDependencies = settingsDependencies()
val plugins = buildPlugins(pluginRequests) val plugins = buildPlugins(pluginRequests)
val subprojects = if (modelProperties.subprojects.isEmpty()) { val subprojects = if (modelProperties.subprojects.isEmpty()) {
@@ -99,6 +101,7 @@ private fun Project.buildModel(
return DefaultBuild( return DefaultBuild(
gradle = buildGradle(), gradle = buildGradle(),
settingsDependencies = settingsDependencies,
pluginDependencies = plugins, pluginDependencies = plugins,
rootProject = buildProject(modelProperties.configurations, subprojects, plugins), rootProject = buildProject(modelProperties.configurations, subprojects, plugins),
includedBuilds = includedBuilds() includedBuilds = includedBuilds()
@@ -126,6 +129,31 @@ private fun Project.buildGradle(): DefaultGradle =
) )
} }
private fun Project.settingsDependencies(): List<DefaultArtifact> {
val buildscript = (gradle as GradleInternal).settings.buildscript
val resolverFactory = ConfigurationResolverFactory(this, ConfigurationScope.SETTINGS, buildscript.repositories)
val resolver = resolverFactory.create(buildscript.dependencies)
logger.lifecycle(" Settings script")
val dependencies = buildscript.configurations
.flatMap(resolver::resolve)
.distinct()
.sorted()
if (resolver.unresolved.isNotEmpty()) {
logger.warn(buildString {
append(" Failed to resolve settings script dependencies:\n")
for (id in resolver.unresolved) {
append(" - $id\n")
}
})
}
return dependencies
}
private fun Project.buildPlugins(pluginRequests: List<PluginRequest>): List<DefaultArtifact> { private fun Project.buildPlugins(pluginRequests: List<PluginRequest>): List<DefaultArtifact> {
return objects.newInstance<PluginResolver>(this).resolve(pluginRequests).distinct().sorted() return objects.newInstance<PluginResolver>(this).resolve(pluginRequests).distinct().sorted()
} }