Skip to content

L2p Service Migration Ant to Gradle

MarcBelsch edited this page Sep 24, 2021 · 10 revisions

Gradle Migration Guide

Preface

Start fresh. Clone the target repository into a new place and initialize a new workspace in your editor for this repository. Some changes may lead to an inconsistent state in your editor configuration and you want to be able to go back.

Migration

  1. Run gradle init (create a java application, as a build script DSL we have chosen Groovy in the template-project).

  2. Rename the newly created app directory to something more applicable.

  3. Also set the new name in settings.gradle ("include"). For multiproject structure, use settings.gradle in the root dirctory and gradle.properties in every project directory.

  4. Move the existing source code underneath the <app>/src/main/java/ tree and delete unnecessary remaining src directories.

  5. Move the tests analogously.

  6. Remove old src dir.

  7. Update the build.gradle in the renamed app directory. You can find a general example in the reference below. There you still have the possibility to change parts, e.g.:

    1. Depending on whether you are using Eclipse as an IDE, you can use the eclipse plugin in gradle. This plugin will automatically generate .classpath and .project files, when importing the project as a gradle project in Eclipse. You can use the configuration for eclipse (see at the end of build.gradle below) to specify how the .classpath file should look like.
    2. Set repositories (see reference below). By default, the build script uses jcenter or mavenCentral and the Archiva.
    3. Convert the dependencies, the simplest way to convert them for gradle was to adapt the ivy properties in the following way: <org>:<name>:<rev>. Make also sure, you declare the dependencies, that were not declared in ivy properties(e.g. libs that relate to import statements).
    4. Take care of the targets in the dependency tree (This article explains the implications of each target). The current implementation models all bundle dependencies as implementation and the platform dependencies, which should not be included in the final jar as compileOnly.
    5. For multi project structure readjust occurences of $rootDir and $projectDir.

    In general it should not be necessary to update more parts of the build script, because the rest can be configured in the gradle.properties.

  8. Try to import your project into your IDE. It might be neccessary to delete .project, .settings and .classpath files (creates backup just in case) to be detected by Eclipse correctly.

  9. Set necessary variables in gradle.properties (core.version of las2peer, service.name, service.class, service.version and java.version).

  10. Create an empty bin folder and add an empty .gitignore file inside it to make git track it.

  11. ./gradlew clean build

  12. Restart the editor, reinitialize with import from gradle.

  13. Remove build.xml, etc/ant_configuration, etc/ivy

  14. Update .gitignore and README

  15. Update CI pipelines and Dockerfiles.

Configuration files

settings.gradle

rootProject.name = 'las2peer-template-project'
include('template_project')

gradle.properties

core.version=1.1.1
service.name=i5.las2peer.services.templateService
service.class=TemplateService
service.version=1.0.0
java.version=14

las2peer_user1.name=alice
las2peer_user1.password=pwalice
las2peer_user1.email=alice@example.org
las2peer_user2.name=bobby
las2peer_user2.password=pwbobby
las2peer_user2.email=bobby@example.org
las2peer_user3.name=joey
las2peer_user3.password=pwjoey
las2peer_user3.email=joey@example.org

<app>/build.gradle

plugins {
    // Apply the application plugin to add support for building a CLI application in Java.
    id 'application'
    //id 'eclipse' // only required when using Eclipse
}

repositories {
    // Use JCenter for resolving dependencies.
    jcenter()

    // DBIS Archiva
    maven {
        url "https://archiva.dbis.rwth-aachen.de:9911/repository/internal/"
    }
}

dependencies {
    // Use JUnit test framework.
    testImplementation "junit:junit:4.13.2"

    // las2peer bundle which is not necessary in the runtime path
    // compileOnly will be moved into the lib dir afterwards
    compileOnly "i5:las2peer-bundle:${project.property('core.version')}"

    // Add service dependencies here
    // example:
    // implementation "net.minidev:json-smart:1.3.1"
}

configurations {
    // This ensures las2peer is available in the tests, but won't be bundled
    testCompile.extendsFrom compileOnly
}

jar {
    manifest {
        attributes "Main-Class": "${project.property('service.name')}.${project.property('service.class')}"
        attributes "Library-Version": "${project.property('service.version')}"
        attributes "Library-SymbolicName": "${project.property('service.name')}"
    }

    from { (configurations.runtimeClasspath).collect { it.isDirectory() ? it : zipTree(it) } } {
        // Exclude signatures to be able to natively bundle signed jars
        exclude 'META-INF/*.RSA', 'META-INF/*.SF', 'META-INF/*.DSA'
    }
}

application {
    // Define the main class for the application.
    mainClass = "${project.property('service.name')}.${project.property('service.class')}"

    group = "${project.property('service.name')}"
    archivesBaseName = group

    version = "${project.property('service.version')}"
    mainClassName = "i5.las2peer.tools.L2pNodeLauncher"
    sourceCompatibility = "${project.property('java.version')}"
    targetCompatibility = "${project.property('java.version')}"
}

// put all .jar files into export/jars folder
tasks.withType(Jar) {
    destinationDir = file("$projectDir/export/jars")
}

javadoc {
    destinationDir = file("$projectDir/export/doc")
}

build.dependsOn "javadoc"

compileJava {
    dependsOn "copyMain"
}

compileTestJava {
    dependsOn "copyTest"
}

// Copies .xml files into build directory
task copyMain(type: Copy) {
    from "src/main/java"
    include "**/*.xml"
    into "$buildDir/classes/java/main"
}

// Copies .xml files into build directory
task copyTest(type: Copy) {
    from "src/test/java"
    include "**/*.xml"
    into "$buildDir/classes/java/test"
}

// These two tasks restore the build and runtime environment used
// in the ant environment
task copyJar(type: Copy) {
    from jar // here it automatically reads jar file produced from jar task
    into "$rootDir/service"
}

task copyToLib(type: Copy) {
    from configurations.compileClasspath
    into "$rootDir/lib"
}

build.dependsOn copyJar
build.dependsOn copyToLib

task startscripts {
    new File("$rootDir/bin", "start_network.sh").text = """#!/bin/bash
# this script is autogenerated by 'gradle startscripts'
# it starts a las2peer node providing the service '${project.property('service.name')}.${project.property('service.class')}' of this project
# pls execute it from the root folder of your deployment, e. g. ./bin/start_network.sh
java -cp "lib/*" i5.las2peer.tools.L2pNodeLauncher --port 9011 --service-directory service uploadStartupDirectory startService\\(\\'${project.property('service.name')}.${project.property('service.class')}@${project.property('service.version')}\\'\\) startWebConnector interactive
""" 
    new File("$rootDir/bin", "start_network.bat").text = """:: this script is autogenerated by 'gradle startscripts'
:: it starts a las2peer node providing the service '${project.property('service.name')}.${project.property('service.class')}' of this project
:: pls execute it from the bin folder of your deployment by double-clicking on it
%~d0
cd %~p0
cd ..
set BASE=%CD%
set CLASSPATH="%BASE%/lib/*;"
java -cp %CLASSPATH% i5.las2peer.tools.L2pNodeLauncher --port 9011 --service-directory service uploadStartupDirectory startService('${project.property('service.name')}.${project.property('service.class')}@${project.property('service.version')}') startWebConnector interactive
pause
"""
}

build.dependsOn "startscripts"

def startup = "$rootDir/etc/startup"
def userAgent1Path = "${startup}/agent-user-${project.property('las2peer_user1.name')}.xml"
def userAgent2Path = "${startup}/agent-user-${project.property('las2peer_user2.name')}.xml"
def userAgent3Path = "${startup}/agent-user-${project.property('las2peer_user3.name')}.xml"
def passphrasesPath = "${startup}/passphrases.txt"

task generateUserAgent1 {
    dependsOn "jar"

    onlyIf { !(new File(userAgent1Path).exists()) }

    doLast {
        tasks.create("generateUserAgent1Help", JavaExec) {
            println "Writing User Agent xml to ${userAgent1Path}"

            main = "i5.las2peer.tools.UserAgentGenerator"
            classpath = sourceSets.main.compileClasspath
            args "${project.property('las2peer_user1.password')}", "${project.property('las2peer_user1.name')}", "${project.property('las2peer_user1.email')}"
            mkdir "${startup}"
            standardOutput new FileOutputStream(userAgent1Path)
        }.exec()
    }
}

task generateUserAgent2 {
    dependsOn "jar"

    onlyIf { !(new File(userAgent2Path).exists()) }

    doLast {
        tasks.create("generateUserAgent2Help", JavaExec) {
            println "Writing User Agent xml to ${userAgent2Path}"

            main = "i5.las2peer.tools.UserAgentGenerator"
            classpath = sourceSets.main.compileClasspath
            args "${project.property('las2peer_user2.password')}", "${project.property('las2peer_user2.name')}", "${project.property('las2peer_user2.email')}"
            mkdir "${startup}"
            standardOutput new FileOutputStream(userAgent2Path)
        }.exec()
    }
}

task generateUserAgent3 {
    dependsOn "jar"

    onlyIf { !(new File(userAgent3Path).exists()) }

    doLast {
        tasks.create("generateUserAgent3Help", JavaExec) {
            println "Writing User Agent xml to ${userAgent3Path}"

            main = "i5.las2peer.tools.UserAgentGenerator"
            classpath = sourceSets.main.compileClasspath
            args "${project.property('las2peer_user3.password')}", "${project.property('las2peer_user3.name')}", "${project.property('las2peer_user3.email')}"
            mkdir "${startup}"
            standardOutput new FileOutputStream(userAgent3Path)
        }.exec()
    }
}

// generate example user agents
task generateAgents {
    description "Generate example user agents"
    dependsOn "generateUserAgent1"
    dependsOn "generateUserAgent2"
    dependsOn "generateUserAgent3"

    doLast {
        new File(passphrasesPath).text = """agent-user-${project.property('las2peer_user1.name')}.xml;${project.property('las2peer_user1.password')}
agent-user-${project.property('las2peer_user2.name')}.xml;${project.property('las2peer_user2.password')}
agent-user-${project.property('las2peer_user3.name')}.xml;${project.property('las2peer_user3.password')}
        """
    }
}

build.dependsOn "generateAgents"

clean.doLast {
    file("$rootDir/tmp").deleteDir()
    file("$rootDir/lib").deleteDir()
    file("$rootDir/servicebundle").deleteDir()
    file("$rootDir/service").deleteDir()
    file("$rootDir/etc/startup").deleteDir()
    file("$projectDir/export").deleteDir()
}

task cleanAll {
    dependsOn "clean"

    doLast {
        file("$rootDir/log").deleteDir()
        file("$rootDir/node-storage").deleteDir()
    }
}

test {
    workingDir = file("$rootDir")
}

// Only required when using Eclipse:
// configuration for eclipse (this allows to import the project as a gradle project in eclipse without any problems)
/*eclipse {
    classpath {
      file {
            whenMerged {
                // change output directory for test, main, resources and default
                def main = entries.find { it.path == "src/main/java" }
                main.output = "output/main"

                def test = entries.find { it.path == "src/test/java" }
                test.output = "output/test"

                def defaultEntry = entries.find { it.kind == "output" && it.path == "bin/default" }
                defaultEntry.path = "output/default"
            }
        }
    }
}*/
Clone this wiki locally