GZip every file with Gradle 5.x and higher - gradle

We currently have a Gradle (v4.10.3) build script that compresses every static resource during build time. Below is a snippet of the code that we have:
tasks.register("gzipJsFiles") {
doLast {
fileTree(dir: "${buildDir}/classes/main/static/js", include: "**/*.min.js", exclude: "*.gz").eachWithIndex { file, index ->
def dynamicTask = "gzipJs-$file.name"
task "${dynamicTask}" (type: GzipJsTask) {
source = file
dest = Paths.get(file.absolutePath + ".gz").toFile()
}
tasks."$dynamicTask".execute()
}
}}
Now, with the latest versions of Gradle, the Task.execute() is being deprecated.
Is there a way to achieve the GZip task, to zip every file in file tree, individually with the newer versions of Gradle (5.x or higher)?

I don't know where the GzipJsTask comes from, but if it is the one from gradle-js-plugin, you can see from the source code that it is simply a wrapper around some Ant commands. So instead of creating Gradle tasks dynamically at execution time, which is no longer possible, just run the commands directly:
doLast {
fileTree(dir: "${buildDir}/classes/main/static/js", include: "**/*.min.js", exclude: "*.gz").each { file ->
ant.gzip(src: file.absolutePath, destfile: file.absolutePath + ".gz")
}
}

Related

Gradle doesn't emit kotlin.js

I'm trying to compile my Kotlin app and set of Kotlin libraries to JavaScript. I've got that working well, but when I try to run it it can't find kotlin.js.
So what's going on here? When I compile using IDEA (instead of Gradle), it outputs kotlin.js just fine. I tried making my build script more like an example I found, but that wouldn't compile...
Here's a link to the code and project in question: https://github.com/BlueHuskyStudios/Decision-Cruncher/blob/SO/q/53582651/1/build.gradle
This only worked for me. unzip for some reason was no working
task assembleWeb() {
configurations.implementation.setCanBeResolved(true)
configurations.implementation.each { File file ->
if (file.path.indexOf('kotlin-stdlib-js') >= 0) {
exec {
workingDir "$projectDir/web"
standardOutput = new ByteArrayOutputStream()
commandLine "7z", "e", file.absolutePath, "kotlin.js", "-aos", "-r"
}
}
}
dependsOn classes
}
assemble.dependsOn assembleWeb
Be aware of "-aos" param. This flag will prevent from overwriting of existing file
Here you can find the code snippet to extract all .js files from Kotlin/JS libraries:
task assembleWeb(type: Sync) {
configurations.compile.each { File file ->
from(zipTree(file.absolutePath), {
includeEmptyDirs = false
include { fileTreeElement ->
def path = fileTreeElement.path
path.endsWith(".js") && (path.startsWith("META-INF/resources/") ||
!path.startsWith("META-INF/"))
}
})
}
from compileKotlin2Js.destinationDir
into "${projectDir}/web"
dependsOn classes
}
assemble.dependsOn assembleWeb
For any others struggling in the future, I've had the following issue:
IntelliJ Kotlin/JS starter project has been generated with this in the gradle file:
implementation "org.jetbrains.kotlin:kotlin-stdlib-js"
which needs to be this to get the kotlin.js file
compile "org.jetbrains.kotlin:kotlin-stdlib-js"

How to run JBoss TattleTale from inside Gradle build

I am in love with JBoss TattleTale. Typically, in my Ant builds, I follow the docs to define the Tattletale tasks and then run them like so:
<taskdef name="report"
classname="org.jboss.tattletale.ant.ReportTask"
classpathref="tattletale.lib.path.id"/>
...
<tattletale:report source="${src.dir]" destination="${dest.dir}"/>
I am now converting my builds over to Gradle and am struggling to figure out how to get Tattletale running in Gradle. There doesn't appear to be a Gradle-Tattletale plugin, and I'm not experienced enough with Gradle to contribute one. But I also know that Gradle can run any Ant plugin and can also executing stuff from the system shell; I'm just not sure how to do this in Gradle because there aren't any docs on this (yet).
So I ask: How do I run the Tattletale ReportTask from inside a Gradle build?
Update
Here is what the Gradle/Ant docs show as an example:
task loadfile << {
def files = file('../antLoadfileResources').listFiles().sort()
files.each { File file ->
if (file.isFile()) {
ant.loadfile(srcFile: file, property: file.name)
println " *** $file.name ***"
println "${ant.properties[file.name]}"
}
}
}
However, no where in here do I see how/where to customize this for Tattletale and its ReportTask.
The following is adapted from https://github.com/roguePanda/tycho-gen/blob/master/build.gradle
It bypasses ant and directly invokes the Tattletale Java class.
It was changed to process a WAR, and mandates a newer javassist in order to handle Java 8 features such as lambdas.
configurations {
tattletale
}
configurations.tattletale {
resolutionStrategy {
force 'org.javassist:javassist:3.20.0-GA'
}
}
dependencies {
// other dependencies here...
tattletale "org.jboss.tattletale:tattletale:1.2.0.Beta2"
}
task createTattletaleProperties {
ext.props = [reports:"*", enableDot:"true"]
ext.destFile = new File(buildDir, "tattletale.properties")
inputs.properties props
outputs.file destFile
doLast {
def properties = new Properties()
properties.putAll(props)
destFile.withOutputStream { os ->
properties.store(os, null)
}
}
}
task tattletale(type: JavaExec, dependsOn: [createTattletaleProperties, war]) {
ext.outputDir = new File(buildDir, "reports/tattletale")
outputs.dir outputDir
inputs.files configurations.runtime.files
inputs.file war.archivePath
doFirst {
outputDir.mkdirs()
}
main = "org.jboss.tattletale.Main"
classpath = configurations.tattletale
systemProperties "jboss-tattletale.properties": createTattletaleProperties.destFile
args([configurations.runtime.files, war.archivePath].flatten().join("#"))
args outputDir
}
The previous answers either are incomplete or excessively complicated. What I did was use the ant task from gradle which works fine. Let's assume your tattletale jars are beneath rootDir/tools/...
ant.taskdef(name: "tattleTaleTask", classname: "org.jboss.tattletale.ant.ReportTask", classpath: "${rootDir}/tools/tattletale-1.1.2.Final/tattletale-ant.jar:${rootDir}/tools/tattletale-1.1.2.Final/tattletale.jar:${rootDir}/tools/tattletale-1.1.2.Final/javassist.jar")
sources = "./src:./src2:./etcetera"
ant.tattleTaleTask(
source: sources,
destination: "tattleTaleReport",
classloader: "org.jboss.tattletale.reporting.classloader.NoopClassLoaderStructure",
profiles: "java5, java6",
reports: "*",
excludes: "notthisjar.jar,notthisjareither.jar,etcetera.jar"
){
}
So the above code will generate the report beneath ./tattleTaleReport. It's that simple. The annoyance is that the source variable only accepts directories so if there are jars present in those directories you do not wish to scan you need to add them to the excludes parameter.

how to download external files in gradle?

I have a gradle project which requires some data files available somewhere on the internet using http. The goal is that this immutable remote file is pulled once upon first build. Subsequent build should not download again.
How can I instruct gradle to fetch the given file to a local directory?
I've tried
task fetch(type:Copy) {
from 'http://<myurl>'
into 'data'
}
but it seems that copy task type cannot deal with http.
Bonus question: is there a way to resume a previously aborted/interrupted download just like wget -c does?
How about just:
def f = new File('the file path')
if (!f.exists()) {
new URL('the url').withInputStream{ i -> f.withOutputStream{ it << i }}
}
You could probably use the Ant task Get for this. I believe this Ant task does not support resuming a download.
In order to do so, you can create a custom task with name MyDownload. That can be any class name basically. This custom task defines inputs and outputs that determine whether the task need to be executed. For example if the file was already downloaded to the specified directory then the task is marked UP-TO-DATE. Internally, this custom task uses the Ant task Get via the built-in AntBuilder.
With this custom task in place, you can create a new enhanced task of type MyDownload (your custom task class). This task set the input and output properties. If you want this task to be executed, hook it up to the task you usually run via task dependencies (dependsOn method). The following code snippet should give you the idea:
task downloadSomething(type: MyDownload) {
sourceUrl = 'http://www.someurl.com/my.zip'
target = new File('data')
}
someOtherTask.dependsOn downloadSomething
class MyDownload extends DefaultTask {
#Input
String sourceUrl
#OutputFile
File target
#TaskAction
void download() {
ant.get(src: sourceUrl, dest: target)
}
}
Try like that:
plugins {
id "de.undercouch.download" version "1.2"
}
apply plugin: 'java'
apply plugin: 'de.undercouch.download'
import de.undercouch.gradle.tasks.download.Download
task downloadFile(type: Download) {
src 'http://localhost:8081/example/test-jar-test_1.jar'
dest 'localDir'
}
You can check more here: https://github.com/michel-kraemer/gradle-download-task
For me works fine..
The suggestion in Ben Manes's comment has the advantage that it can take advantage of maven coordinates and maven dependency resolution. For example, for downloading a Derby jar:
Define a new configuration:
configurations {
derby
}
In the dependencies section, add a line for the custom configuration
dependencies {
derby "org.apache.derby:derby:10.12.1.1"
}
Then you can add a task which will pull down the right files when needed (while taking advantage of the maven cache):
task deployDependencies() << {
String derbyDir = "${some.dir}/derby"
new File(derbyDir).mkdirs();
configurations.derby.resolve().each { file ->
//Copy the file to the desired location
copy {
from file
into derbyDir
// Strip off version numbers
rename '(.+)-[\\.0-9]+\\.(.+)', '$1.$2'
}
}
}
(I learned this from https://jiraaya.wordpress.com/2014/06/05/download-non-jar-dependency-in-gradle/).
Using following plugin:
plugins {
id "de.undercouch.download" version "3.4.3"
}
For a task which has the purpose of only downloading
task downloadFile(type: Download) {
src DownloadURL
dest destDir
}
For including download option into your task:
download {
src DownloadURL
dest destDir
}
For including download option with multiple downloads into your task:
task downloadFromURLs(){
download {
src ([
DownloadURL1,
DownloadURL2,
DownloadURL3
])
dest destDir
}
}
Hope it helped :)
just now ran into post on upcoming download task on gradle forum.
Looks like the perfect solution to me.. Not (yet) available in an official gradle release though
Kotlin Version of #Benjamin's Answer
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath("com.android.tools.build:gradle:4.0.1")
}
}
tasks.register("downloadPdf"){
val path = "myfile.pdf"
val sourceUrl = "https://file-examples-com.github.io/uploads/2017/10/file-sample_150kB.pdf"
download(sourceUrl,path)
}
fun download(url : String, path : String){
val destFile = File(path)
ant.invokeMethod("get", mapOf("src" to url, "dest" to destFile))
}

How can I access the source artifacts of my gradle compile dependencies?

I have written the following task, which extracts all the compile dependencies for each of my sub-projects and puts them in a per sub-project directory:
task exportCompileLibs << {
subprojects.each { iSubProject ->
iSubProject.configurations.findAll{it.name == "compile"}.each{ jConfig ->
println "copying compile libs for ${iSubProject.name}..."
copy {
into "${iSubProject.buildDir}/gradle-lib-export"
from jConfig
eachFile {println it.name}
}
}
}
}
I'd like to extend this to also export the source artifacts that Gradle does already know about (I can see the source jars in the cache directory), I just can't figure out how to use the object model to get a handle to them.
The IDEA and Eclipse plugins seem to be able to do this (they point the project files they build directly into the gradle cache), but I can't figure out how to do it - and looking at the IDE plugin source code, it looks... tricky. I'm hoping there's something obvious that I'm missing in the gradle DSL or API.
Anyone got any ideas?
For anyone looking for at least an interim solution to this, the following seems to be doing pretty much exactly what I want at the moment.
You have to apply the IDEA plugin to the build.gradle file for each project you want to export the dependencies for:
apply plugin: 'idea'
And then define this task:
task exportDependencies << {
def deps = project.extensions.getByType(IdeaModel).module.resolveDependencies()
copy {
from deps*.classes.file
into "${buildDir}/gradle-lib-export/libs"
}
copy {
from deps*.sources.file
into "${buildDir}/gradle-lib-export/sources"
}
}
And here's my horrific hack so I don't have to apply the plugin for each sub-project:
task exportDependencies(description: "export project dependency jars") << {
subprojects.each { Project iSubProject ->
String target = "${iSubProject.buildDir}/gradle-lib-export"
IdeaPlugin ideaPlugin = new IdeaPlugin()
ideaPlugin.apply(iSubProject)
Set<Dependency> deps = ideaPlugin.model.module.resolveDependencies()
println "exporting dependencies for $iSubProject.name into $target"
copy {
from deps*.classes.file
into "${target}/libs"
eachFile { println "lib -> $it.name" }
}
copy {
from deps*.sources.file
into "${target}/sources"
eachFile{ println "source -> $it.name" }
}
}
}
+10 points for not cluttering my build task list with stuff I don't want, -several million points for ewwwww.
There isn't currently a simpler way than what the IDE plugins are doing. This will hopefully change in the future.

Extract specific JARs from dependencies

I am new to gradle but learning quickly. I need to get some specific JARs from logback into a new directory in my release task. The dependencies are resolving OK, but I can't figure out how, in the release task, to extract just logback-core-1.0.6.jar and logback-access-1.0.6.jar into a directory called 'lib/ext'. Here are the relevant excerpts from my build.gradle.
dependencies {
...
compile 'org.slf4j:slf4j-api:1.6.4'
compile 'ch.qos.logback:logback-core:1.0.6'
compile 'ch.qos.logback:logback-classic:1.0.6'
runtime 'ch.qos.logback:logback-access:1.0.6'
...
}
...
task release(type: Tar, dependsOn: war) {
extension = "tar.gz"
classifier = project.classifier
compression = Compression.GZIP
into('lib') {
from configurations.release.files
from configurations.providedCompile.files
}
into('lib/ext') {
// TODO: Right here I want to extract just logback-core-1.0.6.jar and logback-access-1.0.6.jar
}
...
}
How do I iterated over the dependencies to locate those specific files and drop them in the lib/ext directory created by into('lib/ext')?
Configurations are just (lazy) collections. You can iterate over them, filter them, etc. Note that you typically only want to do this in the execution phase of the build, not in the configuration phase. The code below achieves this by using the lazy FileCollection.filter() method. Another approach would have been to pass a closure to the Tar.from() method.
task release(type: Tar, dependsOn: war) {
...
into('lib/ext') {
from findJar('logback-core')
from findJar('logback-access')
}
}
def findJar(prefix) {
configurations.runtime.filter { it.name.startsWith(prefix) }
}
It is worth nothing that the accepted answer filters the Configuration as a FileCollection so within the collection you can only access the attributes of a file. If you want to filter on the dependency itself (on group, name, or version) rather than its filename in the cache then you can use something like:
task copyToLib(type: Copy) {
from findJarsByGroup(configurations.compile, 'org.apache.avro')
into "$buildSrc/lib"
}
def findJarsByGroup(Configuration config, groupName) {
configurations.compile.files { it.group.equals(groupName) }
}
files takes a dependencySpecClosure which is just a filter function on a Dependency, see: https://gradle.org/docs/current/javadoc/org/gradle/api/artifacts/Dependency.html

Resources