beryx / badass-jlink-plugin

Create a custom runtime image of your modular application
https://badass-jlink-plugin.beryx.org
Apache License 2.0
379 stars 25 forks source link

Add proguard support? #4

Closed Burtan closed 4 years ago

Burtan commented 6 years ago

Do you think it might be possible to add proguard into the jlink build process? I think it is always a nice addition to deployment methods.

siordache commented 6 years ago

Proguard already offers a Gradle task, which is also available in Maven Central. It should be therefore possible to integrate it into the badass-jlink plugin. I put the help wanted label to this issue because I have only minimal knowledge of proguard. Besides, I just started working on the next version (2.0) of the plugin and this will keep me busy for a while.

msgilligan commented 5 years ago

Doesn't the jlink command support plugins? I don't know how they work or if they made it out of the experimental phase, but it might make sense to make a Proguard jlink plugin and configure it through the options variable. I don't know if this is possible, but the Java 9 Modularity book talks about jlink plugins in the Improving Performance section of Chapter 13.

If a jlink plugin is possible it should work with this plugin, a Maven plugin, and the raw command line.

rashaverak commented 5 years ago

I was able to successfully proguard my code with

buildscript {
    repositories {
        flatDir dirs: "path-to-proguard/lib/"
    }
    dependencies {
        classpath ':proguard'
    }
}

task proguardMagic(type: proguard.gradle.ProGuardTask) {
    //Keep module-info.class
    keep 'class module-info'
    keepattributes 'Module*'

    injars "${mainJarDir}main.jar"
    outjars proguardOutDir
}

You can either load your proguard config file or write all rules directly in groovy.

frantisekhanzlikbl commented 4 years ago

Sorry to dig this up after such a long time, but how were you able to make the jlink task depend on the proguardMagic task @rashaverak? The JlinkPluginExtension, which is what is configured by tasks.jlink does not even provide dependsOn.

Did you do it with another helper task? Mind sharing a full repository, or at least full build file?

rashaverak commented 4 years ago

Dobry den, pane Frantisku :-)

I am everything but gradle/groovy expert, I literally hate writing in groovy which reminds me javascript I despise so much. But here is the way I did it. It is very simple actually

task macCompleteBuild {
    dependsOn ordered(":jpackage", ":proguard", ":copyOldUpdater", ":macSign")

    doLast {
        prepareZipPackages(platform, modulesPath, zipRoot, "mac")
        notarize()
        sendNotificationToTeams(platform)
    }
}

'ordered' is just fix for one of the things which are driving me crazy, that the dependsOn is not ordered how you write it. Copied somewhere from stackoverflow.

def ordered(String... dependencyPaths) {
    def dependencies = dependencyPaths.collect { tasks.getByPath(it) }
    for (int i = 0; i < dependencies.size() - 1; i++) {
        dependencies[i + 1].mustRunAfter(dependencies[i])
    }
    return dependencies
}
frantisekhanzlikbl commented 4 years ago

Thanks so much for the build script!

I get your dislike for groovy, and I honestly have no idea how can someone ever understand what is happening there as one syntax is used for doing five different things. In that regard, I would guess that even JavaScript is a bit more readable. That's also the reason why I use the Kotlin DSL as much as I can.

For the ordered, I guess it's a good thing that Gradle does not guarantee dependency execution order, as it leaves a room for concurrent execution of them.

Thanks again for the build file!

frantisekhanzlikbl commented 4 years ago

Looking at this again, I quite don't understand how this works. ':-) To my understanding, the task macCompleteBuild runs jpackage first, which runs jar, then packages the result and the the proguard task is run. But from what I thought, the proguard task uses the outputs of the jar task as input, right? How can it modify the image produced by jlink when that version already contains the old jar?

RationalityFrontline commented 3 years ago

I ran into the same problem, and solved it with the following build script (kotlin dsl), hope it could help someone wanting to use proguard.

buildscript {
    repositories {
        jcenter()
        google()
    }
    dependencies {
        classpath("com.guardsquare:proguard-gradle:7.0.0")
    }
}
tasks {
    jar {
        finalizedBy("proguard")
    }
    register<proguard.gradle.ProGuardTask>("proguard") {
        verbose()
        val filter = mapOf(
                "jarfilter" to "!**.jar",
                "filter" to "!module-info.class"
        )
        injars(sourceSets.main.get().output)
        outjars(jar.get().archiveFile.get().asFile)
        libraryjars(filter, "${System.getProperty("java.home")}/jmods/java.base.jmod")
        libraryjars(filter, configurations.compileClasspath.get().files)
        allowaccessmodification()
        printmapping("build/mapping.txt")
        keepclasseswithmembers("""
            class ${application.mainClassName} {
                public static void main(java.lang.String[]);
            }
        """.trimIndent())
        keep("class module-info")
        keepattributes("Module*")
    }
}
siordache commented 3 years ago

@RationalityFrontline Thanks for sharing this!