plugins {
    id 'java'
    id 'idea'
    id 'eclipse'
    id 'maven-publish'
    id 'signing'
    id 'jacoco'
    id 'distribution'
    id 'checkstyle'
    id 'com.diffplug.spotless' version "5.12.1"
    id 'com.github.spotbugs' version "4.7.1"
}

tasks.withType(JavaCompile) {
    sourceCompatibility = 1.8
    targetCompatibility = 1.8
    options.encoding = "UTF-8"
    options.compilerArgs = [ "-Xlint:deprecation,unchecked" ]
}

compileTestJava {
    options.compilerArgs = [ ]
}

repositories {
    mavenCentral()
}

sourceSets {
    main {
        java {
            srcDirs 'src', 'toolsrc', 'xmlimplsrc'
        }
        resources {
            srcDirs 'src', 'toolsrc'
            exclude "build.xml"
            exclude "manifest"
        }
    }

    test {
        java {
            srcDirs "testsrc", 'examples'
            exclude 'tests/**'
        }
        resources {
            srcDirs "testsrc"
        }
    }

    jmh {
        java {
            srcDirs "benchmarks"
        }
        compileClasspath += sourceSets.test.runtimeClasspath
        runtimeClasspath += sourceSets.test.runtimeClasspath
    }
}

dependencies {
    testImplementation "junit:junit:4.13.2"
    testImplementation "org.yaml:snakeyaml:1.28"
    testImplementation "javax.xml.soap:javax.xml.soap-api:1.4.0"
    jmhImplementation project
    jmhImplementation 'org.openjdk.jmh:jmh-core:1.27'
    jmhAnnotationProcessor 'org.openjdk.jmh:jmh-generator-annprocess:1.27'
}

test {
    useJUnit()
    exclude "**/benchmarks/**"

    jvmArgs += '-Xss1280k'

    if (JavaVersion.current() > JavaVersion.VERSION_1_8) {
        jvmArgs += ['--add-opens', 'java.desktop/javax.swing.table=ALL-UNNAMED']
    }

    jacoco.excludes = ['**/testsrc_tests_ecma_3_RegExp_perlstress*']

    systemProperty 'java.awt.headless', 'true'
    systemProperty 'mozilla.js.tests', 'testsrc/tests'
    systemProperty 'mozilla.js.tests.timeout', 60000
    systemProperty 'user.language', 'en'
    systemProperty 'user.country', 'US'
    systemProperty 'user.timezone', 'America/Los_Angeles'
    systemProperty 'file.encoding', 'UTF-8'
    if (System.getProperty('quick') != null) {
        systemProperty 'TEST_OPTLEVEL', -1
    } else if (System.getProperty('optLevel')) {
        systemProperty 'TEST_OPTLEVEL', System.getProperty('optLevel')
    }
    systemProperty 'test262properties', System.getProperty('test262properties')
    if (System.getProperty('updateTest262properties') != null) {
        systemProperty 'updateTest262properties', System.getProperty('updateTest262properties')
    }
    maxHeapSize = "1g"
    testLogging.showStandardStreams = true
    // Many tests do not clean up contexts properly. This makes the tests much
    // more resilient at the expense of performance.
    forkEvery = 1
    maxParallelForks = 64
}

task sunSpiderBenchmark(type: JavaExec) {
    classpath = sourceSets.jmh.runtimeClasspath
    mainClass = 'org.openjdk.jmh.Main'
    args '-f', '1', '-bm', 'avgt', '-tu', 'us', 'SunSpider'
}

task v8Benchmark(type: JavaExec) {
    classpath = sourceSets.jmh.runtimeClasspath
    mainClass = 'org.openjdk.jmh.Main'
    args '-f', '1', '-i', '10', '-bm', 'avgt', '-tu', 'us', 'V8'
}

task testBenchmark() {}
testBenchmark.dependsOn sunSpiderBenchmark
testBenchmark.dependsOn v8Benchmark

task microBenchmark(type: JavaExec, description: 'JMH micro benchmark') {
    def benchmark = System.getProperty('benchmark')
    if (benchmark == null) {
        benchmark = "MathBenchmark"
    }
    classpath = sourceSets.jmh.runtimeClasspath
    mainClass = 'org.openjdk.jmh.Main'
    args '-f', '1', '-bm', 'avgt', '-tu', 'ns', '-r', '5', benchmark
}

task listBenchmarks(type: JavaExec, description: 'JMH benchmarks') {
    classpath = sourceSets.jmh.runtimeClasspath
    mainClass = 'org.openjdk.jmh.Main'
    args '-lp'
}

task jmhHelp(type: JavaExec, description: 'JMH benchmarks') {
    classpath = sourceSets.jmh.runtimeClasspath
    mainClass = 'org.openjdk.jmh.Main'
    args '-help'
}

idea {
    module {
        excludeDirs += file('testsrc/tests/src')
        excludeDirs += file('buildGradle')
        excludeDirs += file('build')
        excludeDirs += file('.idea')
        excludeDirs += file('lib')
    }
}

tasks.withType(AbstractArchiveTask).configureEach {
    // Reproducible jar files
    preserveFileTimestamps = false
    reproducibleFileOrder = true
}

task runtimeJar(type: Jar) {
    dependsOn compileJava
    archiveBaseName = 'rhino-runtime'
    from sourceSets.main.output
    from ('LICENSE.txt') {
        into 'META-INF'
    }
    from ('NOTICE.txt') {
        into 'META-INF'
    }
    excludes = ["org/mozilla/javascript/tools", "org/mozilla/javascript/engine/**", "META-INF/services/**"]
    manifest {
        attributes(
            "Manifest-Version": "1.0",
            "Implementation-Version": project.version,
            "Implementation-Title":  "Mozilla Rhino",
            "Implementation-Vendor": "Mozilla Foundation",
            "Implementation-URL": "http://www.mozilla.org/rhino",
            "Bundle-ManifestVersion": "2",
            "Bundle-SymbolicName": "org.mozilla.rhino-runtime",
            "Bundle-Version": project.version.replaceAll("-.*", ""),
            "Export-Package": "org.mozilla.javascript,org.mozilla.javascript.ast,org.mozilla.javascript.annotations"
        )
    }
}

task engineJar(type: Jar) {
    dependsOn compileJava
    archiveBaseName = 'rhino-engine'
    from (sourceSets.main.output) {
        include 'org/mozilla/javascript/engine/**'
        include 'META-INF/services/**'
    }
    from ('LICENSE.txt') {
        into 'META-INF'
    }
    manifest {
        attributes(
                "Manifest-Version": "1.0",
                "Implementation-Version": project.version,
                "Implementation-Title":  "Mozilla Rhino ScriptEngine",
                "Implementation-Vendor": "Mozilla Foundation",
                "Implementation-URL": "http://www.mozilla.org/rhino",
                "Automatic-Module-Name": "org.mozilla.rhino.engine"
        )
    }
}

jar {
    dependsOn compileJava
    from ('LICENSE.txt') {
        into 'META-INF'
    }
    from ('NOTICE.txt') {
        into 'META-INF'
    }
    from ('NOTICE-tools.txt') {
        into 'META-INF'
    }
    from sourceSets.main.output
    excludes = ["org/mozilla/javascript/engine/**", "META-INF/services/**"]
    // Class ImplementationVersion uses 'Implementation-Title'
    manifest {
        attributes(
            "Manifest-Version": "1.0",
            "Main-Class": "org.mozilla.javascript.tools.shell.Main",
            "Implementation-Version": project.version,
            "Implementation-Title":  "Mozilla Rhino",
            "Implementation-Vendor": "Mozilla Foundation",
            "Implementation-URL": "http://www.mozilla.org/rhino",
            "Automatic-Module-Name": "org.mozilla.rhino",
            "Bundle-ManifestVersion": "2",
            "Bundle-SymbolicName": "org.mozilla.rhino",
            "Bundle-Version": project.version.replaceAll("-.*", ""),
            "Export-Package": "org.mozilla.javascript,org.mozilla.javascript.ast,org.mozilla.javascript.annotations"
        )
    }
}

javadoc {
    options.addBooleanOption("-allow-script-in-comments", true)
    options.addStringOption('Xdoclint:html', '-quiet')
}

task javadocJar(type: Jar) {
    archiveClassifier = 'javadoc'
    from javadoc
}

task runtimeJavadocJar(type: Jar) {
    archiveClassifier = 'javadoc'
    from javadoc
    exclude 'org/mozilla/javascript/tools', 'org/mozilla/javascript/engine'
}

task engineJavadocJar(type: Jar) {
    archiveClassifier = 'javadoc'
    from javadoc
    include 'org/mozilla/javascript/engine/**'
}

task sourceJar(type: Jar) {
    from sourceSets.main.allJava
    archiveClassifier = 'sources'
    from ('LICENSE.txt') {
        into 'META-INF'
    }
    from ('NOTICE.txt') {
        into 'META-INF'
    }
    from ('NOTICE-tools.txt') {
        into 'META-INF'
    }
}

task runtimeSourceJar(type: Jar) {
    archiveClassifier = 'sources'
    from sourceSets.main.allJava
    exclude 'org/mozilla/javascript/tools', 'org/mozilla/javascript/engine'
    from ('LICENSE.txt') {
        into 'META-INF'
    }
    from ('NOTICE.txt') {
        into 'META-INF'
    }
}

task engineSourceJar(type: Jar) {
    archiveClassifier = 'sources'
    from sourceSets.main.allJava
    include 'org/mozilla/javascript/engine/**'
    from ('LICENSE.txt') {
        into 'META-INF'
    }
}

publishing {
    publications {
        rhino(MavenPublication) {
            groupId 'org.mozilla'
            artifactId 'rhino'
            artifacts = [jar, sourceJar, javadocJar]

            pom.withXml {
                def root = asNode()

                root.appendNode('description', """
    Rhino is an open-source implementation of JavaScript written entirely in Java.
    It is typically embedded into Java applications to provide scripting to end users.
    Full jar including tools, excluding the JSR-223 Script Engine wrapper.
""")
                root.appendNode("url", "https://mozilla.github.io/rhino/")

                def p = root.appendNode("parent")
                p.appendNode("groupId", "org.sonatype.oss")
                p.appendNode("artifactId", "oss-parent")
                p.appendNode("version", "7")

                def l = root.appendNode("licenses").appendNode("license")
                l.appendNode("name", "Mozilla Public License, Version 2.0")
                l.appendNode("url", "http://www.mozilla.org/MPL/2.0/index.txt")

                def scm = root.appendNode("scm")
                scm.appendNode("connection", "scm:git:git@github.com:mozilla/rhino.git")
                scm.appendNode("developerConnection", "scm:git:git@github.com:mozilla/rhino.git")
                scm.appendNode("url", "git@github.com:mozilla/rhino.git")

                def o = root.appendNode("organization")
                o.appendNode("name", "The Mozilla Foundation")
                o.appendNode("url", "http://www.mozilla.org")

            }
        }

        rhinoruntime(MavenPublication) {
            groupId 'org.mozilla'
            artifactId 'rhino-runtime'
            artifacts = [runtimeJar, runtimeSourceJar, runtimeJavadocJar]

            pom.withXml {
                def root = asNode()

                root.appendNode('description', """
    Rhino JavaScript runtime jar, excludes tools & JSR-223 Script Engine wrapper.
""")
                root.appendNode("url", "https://mozilla.github.io/rhino/")

                def p = root.appendNode("parent")
                p.appendNode("groupId", "org.sonatype.oss")
                p.appendNode("artifactId", "oss-parent")
                p.appendNode("version", "7")

                def l = root.appendNode("licenses").appendNode("license")
                l.appendNode("name", "Mozilla Public License, Version 2.0")
                l.appendNode("url", "http://www.mozilla.org/MPL/2.0/index.txt")

                def scm = root.appendNode("scm")
                scm.appendNode("connection", "scm:git:git@github.com:mozilla/rhino.git")
                scm.appendNode("developerConnection", "scm:git:git@github.com:mozilla/rhino.git")
                scm.appendNode("url", "git@github.com:mozilla/rhino.git")

                def o = root.appendNode("organization")
                o.appendNode("name", "The Mozilla Foundation")
                o.appendNode("url", "http://www.mozilla.org")
            }
        }

        rhinoengine(MavenPublication) {
            groupId 'org.mozilla'
            artifactId 'rhino-engine'
            artifacts = [engineJar, engineSourceJar, engineJavadocJar]

            pom.withXml {
                def root = asNode()

                root.appendNode('description', """
    Rhino Javascript JSR-223 Script Engine wrapper.
""")
                root.appendNode("url", "https://mozilla.github.io/rhino/")

                def p = root.appendNode("parent")
                p.appendNode("groupId", "org.sonatype.oss")
                p.appendNode("artifactId", "oss-parent")
                p.appendNode("version", "7")

                def l = root.appendNode("licenses").appendNode("license")
                l.appendNode("name", "Mozilla Public License, Version 2.0")
                l.appendNode("url", "http://www.mozilla.org/MPL/2.0/index.txt")

                def scm = root.appendNode("scm")
                scm.appendNode("connection", "scm:git:git@github.com:mozilla/rhino.git")
                scm.appendNode("developerConnection", "scm:git:git@github.com:mozilla/rhino.git")
                scm.appendNode("url", "git@github.com:mozilla/rhino.git")

                def o = root.appendNode("organization")
                o.appendNode("name", "The Mozilla Foundation")
                o.appendNode("url", "http://www.mozilla.org")

                def deps = root.appendNode("dependencies")
                def rhino = deps.appendNode("dependency")
                rhino.appendNode("groupId", "org.mozilla")
                rhino.appendNode("artifactId", "rhino")
                rhino.appendNode("version", getVersion())
            }
        }
    }

    if (project.hasProperty("mavenPassword")) {
        repositories {
            maven {
                credentials {
                    username mavenUser
                    password mavenPassword
                }
                if (project.version.endsWith('-SNAPSHOT')) {
                    url mavenSnapshotRepo
                } else {
                    url mavenReleaseRepo
                }
            }
        }
    }
}

signing {
    if (project.hasProperty('SIGNINGKEY')) {
        // Check for ORG_GRADLE_PROJECT_SIGNINGKEY environment variable for use in CI system.
        // Otherwise, do not sign.
        def signingKey = getProperty('SIGNINGKEY')
        def signingPassword = getProperty('SIGNINGPASSWORD')
        useInMemoryPgpKeys(signingKey, signingPassword)
        sign publishing.publications.rhino
        sign publishing.publications.rhinoengine
        sign publishing.publications.rhinoruntime
    }
}

spotbugs {
    effort = "less"
    reportLevel = "medium"
    excludeFilter = file("./spotbugs-exclude.xml")
}

spotless {
    ratchetFrom 'code-formatting-required'
    java {
        googleJavaFormat().aosp()
    }
}

if (JavaVersion.current() > JavaVersion.VERSION_15
        && (!System.properties.containsKey('org.gradle.jvmargs')
        || !System.properties.get('org.gradle.jvmargs').contains('com.sun.tools.javac.api'))
        && (!project.hasProperty('org.gradle.jvmargs')
        || !project.property('org.gradle.jvmargs').contains('com.sun.tools.javac.api'))) {
    tasks.named('check') {
        doFirst {
            logger.warn('WARNING: spotless plugin removed from check due to bug, ' + \
                'see README for a workaround when building with Java 16+.')
        }
    }
    spotless.enforceCheck false
}

jacocoTestReport {
    dependsOn test
    reports {
        csv.required = true
        html.required = true
    }
}

checkstyle {
    configFile = file("${projectDir}/checkstyle.xml")
    sourceSets = [ project.sourceSets.main ]
}

distributions {
    main {
        contents {
            from(sourceSets.main.java) {
                into 'rhino' + project.version + '/src'
            }
            from(sourceSets.main.resources) {
                exclude '**/*.java'
                into 'rhino' + project.version + '/src'
            }
            from(javadoc.destinationDir) {
                into 'rhino' + project.version + '/docs'
            }
            from(jar.outputs.files) {
                into 'rhino' + project.version + '/lib'
            }
            from(runtimeJar.outputs.files) {
                into 'rhino' + project.version + '/lib'
            }
            from(engineJar.outputs.files) {
                into 'rhino' + project.version + '/lib'
            }
            from(file(".")) {
                include '*.txt', '*.md', 'build.gradle', 'gradle.properties',
                        'gradle/**', 'gradlew', 'man/*.1'
                into 'rhino' + project.version 
            }
            into "/"
        }
    }
}

distTar {
    dependsOn javadoc, jar
    compression = Compression.GZIP
    archiveExtension = 'tar.gz'
}

distZip.dependsOn javadoc, jar, sourceJar, runtimeSourceJar
