[Jython-checkins] jython: Rework Gradle build to obtain distributable JAR and POM, both correct.
jeff.allen
jython-checkins at python.org
Mon Jul 30 01:23:12 EDT 2018
https://hg.python.org/jython/rev/121e7ca91b4a
changeset: 8177:121e7ca91b4a
user: Jeff Allen <ja.py at farowl.co.uk>
date: Sun Jul 29 23:11:43 2018 +0100
summary:
Rework Gradle build to obtain distributable JAR and POM, both correct.
Command "./gradlew publishToMavenLocal" will post a JAR and POM locally that may
be used experimentally in Maven-based projects.
files:
build.gradle | 253 ++++++++++++++++----------------------
1 files changed, 104 insertions(+), 149 deletions(-)
diff --git a/build.gradle b/build.gradle
--- a/build.gradle
+++ b/build.gradle
@@ -52,16 +52,26 @@
// ---------------- Miscellaneous configuration --------------------------------
+// Support Java 7 onwards
+sourceCompatibility = '1.7'
+targetCompatibility = '1.7'
// Separate the Gradle build from that of Ant
buildDir = file('build2')
ext {
buildDate = new Date()
+ /*
+ * The directory structure supporting the build has separate locations for
+ * several intermediate stages.
+ */
// Java source generated by ANTLR
antlrGenDir = "$buildDir/gensrc/org/python/antlr"
- // This is where we assemble the standard library pre-JAR
+ // Intermediate locations for compiled classes
+ unexposedDir = "$buildDir/unexposed"
+ exposedDir = "$buildDir/exposed"
+ // The standard library may safely be assembled in-place as a resource
buildLibDir = "$buildDir/resources/main/Lib/"
- compiledLibDir = "$buildDir/classes/main/Lib/"
+ compiledLibDir = "$buildDir/resources/main/Lib/"
}
@@ -87,11 +97,8 @@
exclude 'com/**' // for now
}
- // output.resourcesDir = project.ext.assemblyDir
-
resources {
- // Resources in project root, but this invites an explosion:
- // srcDirs = ['']
+ // Resources in project root, but this invites an explosion.
// ... so claim no sources:
srcDirs = []
// and fix it in task processResources
@@ -131,7 +138,7 @@
implementation group: 'org.ow2.asm', name: 'asm-commons', version: '5.2'
implementation group: 'org.ow2.asm', name: 'asm-util', version: '5.2'
- implementation group: 'com.google.guava', name: 'guava', version: '22.0-android'
+ api group: 'com.google.guava', name: 'guava', version: '22.0-android'
implementation group: 'com.ibm.icu', name: 'icu4j', version: '59.1'
implementation group: 'com.carrotsearch', name: 'java-sizeof', version: '0.0.5'
@@ -164,6 +171,11 @@
* Jython brings several files we could treat as resources, but they do not sit
* in the Gradle-conventional 'main/resources' directory, rather are in the
* project root or rub shoulders with the java source. Pick them individually.
+ *
+ * Several tasks defined below declare that processResources depends on them,
+ * with the objective that at the end of processResources all generated
+ * resources and the stdlib (but not the compiled stdlib) should be in place
+ * in $buildDir/resources/main.
*/
processResources {
from(file('.')) {
@@ -182,24 +194,29 @@
outputDirectory = file(project.ext.antlrGenDir)
}
+// ---------------- compleJava Task -------------------------------------------------
+
+compileJava {
+ // Divert compiled classes to intermediate location pre-exposure.
+ destinationDir = file(project.ext.unexposedDir)
+ println "compileJava.destinationDir = $destinationDir}"
+}
+
// ---------------- Expose Task ------------------------------------------------
/*
- * The exposer operates between two (somewhat fixed) directories. We follow
- * the Gradle-conventional directory structure (not the legacy one).
+ * The exposer operates between the output of compileJava (unexposed directory)
+ * and a second intermediate location (exposed directory). These two the
+ * mergeExposed task will finally combine in the Gradle-standard classes
+ * directory used as input by the jar task.
*/
-ext {
- compileDir = "$buildDir/classes/java/main/"
- exposedDir = "$buildDir/classes/exposed/main/"
-}
-
configurations {
expose.extendsFrom(implementation)
}
dependencies {
- // Put our compiled classes on the path of the expose (Ant) task
- expose files("$buildDir/classes/java/main")
+ // The expose (Ant) task depends on classes compiled to here:
+ expose files(project.ext.unexposedDir)
}
// A (Gradle) task to run the Ant task 'expose'.
@@ -208,7 +225,7 @@
description = 'Expose Java types to Python using their annotations.'
// Allow Gradle to infer the need to regenreate the outputs
- inputs.files(fileTree("${project.ext.compileDir}/org/python"))
+ inputs.files(fileTree("${project.ext.unexposedDir}/org/python"))
outputs.dir(project.ext.exposedDir)
doLast {
@@ -224,13 +241,27 @@
// Use the Gradle-conventional directory structure (not the legacy one).
ant.expose(
- srcdir: file(project.ext.compileDir),
+ srcdir: file(project.ext.unexposedDir),
destdir: mkdir(file(project.ext.exposedDir)),
includesfile: file('CoreExposed.includes')
)
}
}
+// Task to merge the exposed and unexposed classes
+task mergeExposed(group: 'Custom', type:Copy, dependsOn: expose) {
+ description = 'Copy exposed Java types to classes.'
+ // Exposed version will take precedence
+ duplicatesStrategy = DuplicatesStrategy.EXCLUDE
+ from file(exposedDir)
+ from file(unexposedDir)
+ into sourceSets.main.output.classesDirs.singleFile
+}
+
+// Attach to the classes task the placing of all compiled and exposed classes.
+classes.dependsOn(mergeExposed)
+
+
// ---------------- Version-related file generation ----------------------------
/*
@@ -375,11 +406,12 @@
libJython = 'Lib'
}
-
/*
* Copy the Python standard library. We take this from a distribution of
- * CPython, but take only the files specified in CPythonLib.includes in the
- * project root.
+ * CPython, but take only the files specified in CPythonLib.includes.
+ * The Jython version of the standard library will be copied to the same place.
+ * Files from the Jython library having the same name (relative path) as one
+ * in CPythonLib.includes thereby take precedence.
*/
task copyLib(
type: Copy,
@@ -411,28 +443,17 @@
}
// Copy the subset as specified by the list
project.copy {
+ into project.ext.buildLibDir
from file(project.ext.libPython)
include cPythonLibIncludes
exclude '**/*.pyc', '**/*.pyd'
- into project.ext.buildLibDir
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
}
-
- /*
- <target name="copy-cpythonlib">
- <copy todir="${dist.dir}/Lib">
- <fileset dir="${python.lib}" excludes="** /*.pyc, ** /*.pyo"
- includesfile="${jython.base.dir}/CPythonLib.includes">
- <!-- The include file gets all of lib-python/2.7's test directory, but we only want the ones from Jython's Lib. -->
- <present present="srconly" targetdir="${jython.base.dir}/Lib"/>
- </fileset>
- </copy>
- </target>
- */
}
-
+// Attach this task to processResources
+processResources.dependsOn(copyLib)
// ---------------- Jython-Compile Python --------------------------------------
@@ -450,7 +471,6 @@
dependencies {
// Jython as built so far should be on the path of the jycompile (Ant) task
- pycompile files("$buildDir/classes/exposed/main")
pycompile files("$buildDir/classes/java/main")
pycompile files("$buildDir/resources/main")
}
@@ -460,9 +480,9 @@
group: 'Custom',
description: 'Compile the Python modules to .class files for the JAR') {
- dependsOn compileJava
- dependsOn expose
- dependsOn copyLib
+ // Compiler depends on rest of Jython being fully assembled in 'classes'
+ dependsOn classes
+ // Note that classes depends on processResources (Java plug-in).
// Allow Gradle to infer the need to regenerate the outputs
inputs.dir project.ext.buildLibDir
@@ -516,39 +536,32 @@
/*
* The default behaviour of the Java plug-in is to make a JAR of the classes in
- * the "main" source set. We need a more complex operation that provides users
- * with exposed classes instead of their plain counterparts, and also various
- * configuration files and the Python library.
- *
- * Much of the assembly has taken place already in selective copying to the
- * build directory by tasks processResources and copyLib.
+ * the "main" source set and its resources. Having carefully substituted/added
+ * exposed classes in the assembled classes directory, and having prepared the
+ * (compiled) stdlib as a resource, this is close to what we need, with a few
+ * adjustments as noted.
*/
-task jar(type: Jar, overwrite: true) {
+jar {
+ // Ensure that compiled stdlib is part of the resources to JAR.
dependsOn pycompile
- /*
- * This is a custom replacement Jar task so that we may control the
- * order of adding classes. Exposed versions of identically-named classes
- * supersede (by arriving first) those directly from compilation.
- */
- exclude 'org/python/expose/generate/**' // The expose tool itself
-
- duplicatesStrategy = DuplicatesStrategy.EXCLUDE
+ // It is important for import that X$py.class be newer than X.py
preserveFileTimestamps = true
- // Add the exposed classes to the JAR
- from expose
-
- // Add other compiled classes
- from compileJava
+ // We don't JAR the expose tool itself
+ exclude 'org/python/expose/generate/**'
- // Add the resources (includes merged Python library)
- from processResources
+ // Exclude tests and test material from the main JAR
+ exclude 'Lib/distutils/tests/'
+ exclude 'Lib/email/test/'
+ exclude 'Lib/json/tests/'
+ exclude 'Lib/lib2to3/tests/'
+ exclude 'Lib/unittest/tests/'
+ exclude 'Lib/test/'
+ // XXX is this not more naturally done by having separate test resources?
- // Add compiled Python library
- from file(project.ext.compiledLibDir).parent
-
+ // Build a custom manifest
manifest {
// These attribute values are based on inspecting the ant build
attributes ([
@@ -559,11 +572,15 @@
attributes( [ // Build-Info section
'version': project.version,
'build-compiler': 'modern',
- 'jdk-target-version': '1.7',
+ 'jdk-target-version': project.targetCompatibility,
'debug': true,
], 'Build-Info' )
}
-
+
+ doFirst {
+ println "jar: for ${archiveName}"
+ }
+
}
@@ -607,17 +624,13 @@
publications {
// The production JAR we expect to be cited as a dependency by users
main(MavenPublication) {
-
- // Correctly-constructed jar but a .pom without dependencies:
- artifact jar
- // Nice .pom but the jar is the default built by the Java plugin:
- //from components.java
+ from components.java
// Also provide the source.
artifact sourcesJar
- // Also provide the docs. (Some javadoc errors currntly.)
- artifact javadocJar
+ // Also provide the docs. (Some javadoc errors currently.)
+ //artifact javadocJar
}
}
@@ -663,7 +676,6 @@
failFast = true
// Properties as defined in Ant target javatest-basepath
- //systemProperty 'python.home', project.ext.distDir
// XXX Not sure of all that python.home is used for in tests.
systemProperty 'python.home', file(copyLib.destinationDir).parent
systemProperty 'python.test.source.dir', project.ext.testSourceDir
@@ -766,81 +778,24 @@
}
}
-task dumpCompo {
+task dumpSS {
doLast {
- println('components:')
- components.each { println it }
- println('components.java:')
- components.java.each { println it }
- }
-}
-
-task dumpArt {
- doLast {
- println('artifacts:')
- artifacts.each { println it }
- }
-}
-
-task dumpArch {
- doLast {
- println('archives:')
- configurations.archives.each { println it }
+ println '*** source sets ***'
+ for (ss in sourceSets) {
+ String name = ss.name
+ println ss
+ println " ${name}.compileConfigurationName = ${ss.compileConfigurationName}"
+ println " ${name}.implementationConfigurationName = ${ss.implementationConfigurationName}"
+ println " ${name}.runtimeConfigurationName = ${ss.runtimeConfigurationName}"
+ println " ${name}.java.srcDirs = ${ss.java.srcDirs}"
+ println " ${name}.antlr.srcDirs = ${ss.antlr.srcDirs}"
+ println " ${name}.resources.srcDirs = ${ss.resources.srcDirs}"
+ println " ${name}.output.dirs = ${ss.output.dirs.files}"
+ println " ${name}.output.classesDirs = ${ss.output.classesDirs.files}"
+ println " ${name}.output.resourcesDir = ${ss.output.resourcesDir}"
+ println " ${name}.classesTaskName = ${ss.classesTaskName}"
+ println " ${name}.compileJavaTaskName = ${ss.compileJavaTaskName}"
+ println " ${name}.jarTaskName = ${ss.jarTaskName}"
+ }
}
}
-
-task dumpex {
- // Legacy approach to obtaining files to JAR
- doLast {
- int n = project.ext.exposedDir.length()
- Set<String> exposedClasses = new TreeSet()
- //println "*** files in ${project.ext.exposedDir}:"
- for (f in fileTree(project.ext.exposedDir)) {
- //println project.relativePath(f).substring(n)
- exposedClasses.add( project.relativePath(f).substring(n) )
- }
- //for (f in exposedClasses) { println f }
-
- println "${fileTree(project.ext.compileDir).size()} compiled classes."
-
- n = project.ext.compileDir.length()
- int countx = 0
- for (f in fileTree(project.ext.compileDir)) {
- //println project.relativePath(f).substring(n)
- String name = project.relativePath(f).substring(n)
- if (name in exposedClasses) { countx += 1 }
- }
- println "${exposedClasses.size()} classes from ${countx} exposed."
-
- def compiledToJar = fileTree(project.ext.compileDir).filter({
- File f -> !(project.relativePath(f).substring(n) in exposedClasses)
- })
-
- println "${compiledToJar.size()} to be jarred (after filtering)."
-
- int counti = 0
- for (f in fileTree(project.ext.compileDir)) {
- String name = project.relativePath(f).substring(n)
- String exposed = (name in exposedClasses) ? "EXPOSED" : ""
- // println "${name} ${exposed}"
- if (exposed) { counti += 1 }
- }
-
- println "${counti} in overlap."
- }
-}
-
-
-task dumpSS {
- doLast {
- // Debug
- println '*** source sets ***'
- for ( sourceSet in sourceSets ) {
- println " ${sourceSet}"
- // for ( name in sourceSet.asMap.keys ) {
- // sourceDirectorySet = sourceSet.asMap[name]
- // println " $name = $sourceDirectorySet"
- // }
- }
- }
-}
\ No newline at end of file
--
Repository URL: https://hg.python.org/jython
More information about the Jython-checkins
mailing list