/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import org.apache.tools.ant.filters.ReplaceTokens

buildscript {
    repositories {
        // mavenCentral without https:
        maven {
            url 'http://repo1.maven.org/maven2'
        }
        mavenLocal()
        jcenter {
            url 'http://jcenter.bintray.com/'
        }
        maven {
            url 'http://repository.jboss.org/nexus/content/groups/public'
        }
    }

    dependencies {
        classpath "com.netflix.nebula:gradle-ospackage-plugin:2.2.6"
        classpath "de.undercouch:gradle-download-task:2.1.0"
        classpath 'com.netflix.nebula:gradle-aggregate-javadocs-plugin:2.2.+'
    }   
}

// Hadoop distribution (can be hdp or null which would default to apache) - needed to set correct classpaths
// can be set with -Dhd=<value>
def hddist = System.properties['hd'] ?: '';
if (hddist != 'hdp' && hddist != '') {
    throw new GradleException("hadoop distribution parameter (hd) set to invalid value: $hddist")
}

// Some package names need to be renamed to include the version number
// as part of the package name to enable side by side install of two versions of the same package.

def versionedPackageName(packageName) {
    if (System.properties['hd'] == 'hdp') {
        packageName + "_" + "${version}".replace(".", "_")
    } else {
        packageName
    }
}

subprojects { subProject ->
    group = 'org.apache.hawq.pxf'
    apply plugin: 'java'
    apply plugin: 'idea'
    apply plugin: 'eclipse'
    apply plugin: 'os-package'
    apply plugin: 'maven-publish'

    compileJava.options*.compilerArgs = [
            "-g", "-Xlint:varargs", "-Xlint:cast", "-Xlint:classfile", "-Xlint:dep-ann", "-Xlint:divzero", "-Xlint:empty",
            "-Xlint:finally", "-Xlint:overrides", "-Xlint:path", "-Xlint:processing", "-Xlint:static", "-Xlint:try",
            "-Xlint:fallthrough", "-Xlint:deprecation", "-Xlint:unchecked", "-Xlint:-options", "-Werror"
    ]

    compileTestJava.options*.compilerArgs = [
            "-Xlint:varargs", "-Xlint:cast", "-Xlint:classfile", "-Xlint:dep-ann", "-Xlint:divzero", "-Xlint:empty",
            "-Xlint:finally", "-Xlint:overrides", "-Xlint:path", "-Xlint:processing", "-Xlint:static", "-Xlint:try",
            "-Xlint:-fallthrough", "-Xlint:-deprecation", "-Xlint:-unchecked", "-Xlint:-options"
    ]

    repositories {
        // mavenCentral without https:
        maven { url 'http://repo1.maven.org/maven2' }
        mavenLocal()
        maven { url 'http://repo.hortonworks.com/content/repositories/releases/'}
    }

    dependencies {
        compile 'commons-logging:commons-logging:1.1.3'
        compile 'commons-collections:commons-collections:3.2.1'
        compile 'commons-codec:commons-codec:1.4'
        compile 'commons-configuration:commons-configuration:1.6'
        compile 'org.codehaus.jackson:jackson-mapper-asl:1.9.13'
        testCompile 'junit:junit:4.11'
        testCompile 'org.powermock:powermock-core:1.5.1'
        testCompile 'org.powermock:powermock-module-junit4:1.5.1'
        testCompile 'org.powermock:powermock-api-mockito:1.5.1'
        testCompile 'org.mockito:mockito-core:1.9.5'
    }

    configurations.all {
        resolutionStrategy {
            // force versions that were specified in dependencies:
            // hbase/hive has a different versions than other hadoop components
            force 'commons-codec:commons-codec:1.4'
            force 'commons-collections:commons-collections:3.2.1'
            force 'commons-logging:commons-logging:1.1.3'
            force 'org.apache.avro:avro:1.7.4'
            force 'org.apache.zookeeper:zookeeper:3.4.6'
            force 'org.codehaus.jackson:jackson-mapper-asl:1.9.13'
            force 'junit:junit:4.11'
        }
    }

    task distTar(type: Tar) {
        classifier = buildNumber()
        compression = Compression.GZIP
        extension = 'tar.gz'
        from jar.outputs.files
        into "${project.name}-${project.version}"
    }

    //buildRpm
    ospackage {
        vendor = project.vendor
        release = buildNumber()
        version = subProject.version.split('-')[0];
        os = LINUX
        license = project.license
        obsoletes('gpxf')
        user = 'root'
        permissionGroup = 'root'
    }
}

project('pxf-service') {

// Copy existing sources and replace any occurrences of @tokenName@ with desired values
    task generateSources {
        doFirst {
            copy {
                from('src/main/java') {
                    include '**/*.java'
                    filter(ReplaceTokens,
                        tokens:['pxfProtocolVersion': project.pxfProtocolVersion ])}
                into "tmp/generatedSources"
            }
        }
    }

// Call cleanup taskAfter Java code compilation
    compileJava.doLast {
        tasks.cleanGeneratedSources.execute()
    }

// Delete "tmp" directory under current project directory
// rm -r pxf-service/tmp
    task cleanGeneratedSources() {
        doFirst {
            delete "tmp"
        }
    }

// Call generateSources task before Java compilation
    gradle.projectsEvaluated {
        compileJava.dependsOn(generateSources)
    }

// Use custom sources directory with generated sources
    sourceSets {
        main {
            java {
                srcDirs = ["tmp/generatedSources"]
            }
        }
    }

    apply plugin: 'war'
    tasks.war {
        archiveName = 'pxf.war'
        processResources {
            filesMatching('**/pxf-private*.classpath') {
                details ->
                if (details.name == "pxf-private${hddist}.classpath") {
                    details.name = "pxf-private.classpath"
                } else { 
                    // exclude classpath file for a different distribution
                    details.exclude()
                }
            }
        }
    }
    dependencies {
        compile(project(':pxf-api'))
        compile 'com.sun.jersey:jersey-core:1.9'
        providedCompile "org.apache.hadoop:hadoop-common:$hadoopVersion"
        providedCompile "org.apache.hadoop:hadoop-hdfs:$hadoopVersion"
        providedCompile "org.apache.hadoop:hadoop-auth:$hadoopVersion"
        providedCompile "org.apache.hadoop:hadoop-annotations:$hadoopVersion"
        providedCompile "org.apache.hadoop:hadoop-mapreduce-client-core:$hadoopVersion"
        providedCompile "org.apache.tomcat:tomcat-catalina:$tomcatVersion"
        providedCompile("org.apache.hive:hive-exec:$hiveVersion") {
            exclude module: 'calcite-core'
            exclude module: 'calcite-avatica'
        }
    }

    ospackage {
        packageName = versionedPackageName("${project.name}")
        summary = 'HAWQ Extension Framework (PXF), service REST API'
        description = 'Rest API for the HAWQ Extenstion framework'
        packager = ' '
        packageGroup = 'Development/Libraries'
        release = buildNumber() + '.' + project.osFamily
        buildHost = ' '

        requires('apache-tomcat', "$tomcatVersion", GREATER | EQUAL)
        requires('hadoop', "$hadoopVersion", GREATER | EQUAL)
        requires('hadoop-hdfs', "$hadoopVersion", GREATER | EQUAL)

        // Upgrades pxf-core, pxf-api to pxf-service
        obsoletes('pxf-core')
        obsoletes('pxf-api')

        from('src/main/resources/pxf-profiles-default.xml') {
            fileType CONFIG | NOREPLACE
            into "/etc/pxf-${project.version}/conf"
            rename { 'pxf-profiles.xml' }
        }

        from('src/configs/pxf-site.xml') {
            fileType CONFIG | NOREPLACE
            into "/etc/pxf-${project.version}/conf"
        }

        from("src/main/resources") {
            into("/etc/pxf-${project.version}/conf")
            include("**/pxf-private*.classpath")
            exclude("**/pxf-private.classpath")
        }

        from("src/main/resources/pxf-private${hddist}.classpath") {
            into("/etc/pxf-${project.version}/conf")
            rename("pxf-private${hddist}.classpath", "pxf-private.classpath") 
        }

        from('src/main/resources/pxf-public.classpath') {
            fileType CONFIG | NOREPLACE
            into "/etc/pxf-${project.version}/conf"
        }

        from('src/scripts/pxf-env.sh') {
            fileMode 0755
            fileType NOREPLACE
            into "/etc/pxf-${project.version}/conf"
        }
        
        from('src/main/resources/pxf-log4j.properties') {
            fileType CONFIG | NOREPLACE
            into "/etc/pxf-${project.version}/conf"
        }

        from(war.outputs.files) {
            into "/usr/lib/pxf-${project.version}"
        }

        from(jar.outputs.files) {
            into "/usr/lib/pxf-${project.version}"
        }
        
        //tomcat configuration files
        from('src/configs/tomcat') {
            fileType CONFIG | NOREPLACE
            into "/opt/pxf-${project.version}/tomcat-templates"
        }

        from('src/scripts/pxf-service') {
            fileMode 0755
            addParentDirs false
            into "/opt/pxf-${project.version}"
        }

        link("/usr/lib/pxf-${project.version}/${project.name}.jar", "${project.name}-${project.version}.jar")

    }

    project.distTar {
        from('src/main/resources/pxf-profiles-default.xml') { into 'conf' rename { 'pxf-profiles.xml' } }
        from("src/main/resources") { into 'conf' include '**/pxf-private*.classpath'}
        from("src/main/resources/pxf-private${hddist}.classpath") { into 'conf' rename {'pxf-private.classpath'} }
        from('src/main/resources/pxf-public.classpath') { into 'conf' }
        from(project(':pxf-api').jar.outputs.files)
        from(war.outputs.files)
    }
}

project('pxf') {
    jar.enabled = false
    ospackage {
        summary = 'HAWQ Extension Framework (PXF)'
        description = 'HAWQ Extension framework Virtual RPM'
        packager = ' '
        packageGroup = 'Development/Libraries'
        release = buildNumber() + '.' + project.osFamily
        buildHost = ' '

        requires(versionedPackageName('pxf-hdfs'), project.version, GREATER | EQUAL)
        requires(versionedPackageName('pxf-hive'), project.version, GREATER | EQUAL)
        requires(versionedPackageName('pxf-hbase'), project.version, GREATER | EQUAL)
        requires(versionedPackageName('pxf-json'), project.version, GREATER | EQUAL)

        preInstall file('src/scripts/pre-install.sh')
        postInstall file('src/scripts/post-install.sh')

        link('/usr/lib/pxf', "/usr/lib/pxf-${project.version}")
        link('/etc/pxf', "/etc/pxf-${project.version}")
        link('/opt/pxf', "/opt/pxf-${project.version}")
        link('/etc/init.d/pxf-service', "/opt/pxf/pxf-service")
    }
}

project('pxf-hdfs') {
    dependencies {
        compile(project(':pxf-api'))
        compile 'org.apache.avro:avro-mapred:1.7.4'
        compile "org.apache.hadoop:hadoop-mapreduce-client-core:$hadoopVersion"
        compile "org.apache.hadoop:hadoop-common:$hadoopVersion"
        compile "org.apache.hadoop:hadoop-hdfs:$hadoopVersion"
    }

    ospackage {
        packageName = versionedPackageName("${project.name}")
        summary = 'HAWQ Extension Framework (PXF), HDFS plugin'
        description = 'Querying external data stored in HDFS'
        packager = ' '
        packageGroup = 'Development/Libraries'
        release = buildNumber() + '.' + project.osFamily
        buildHost = ' '

        requires(versionedPackageName('pxf-service'), project.version, GREATER | EQUAL)
        requires('hadoop', "$hadoopVersion", GREATER | EQUAL)
        requires('hadoop-mapreduce', "$hadoopVersion", GREATER | EQUAL)

        from(jar.outputs.files) {
            into "/usr/lib/pxf-${project.version}"
        }

        link("/usr/lib/pxf-${project.version}/${project.name}.jar", "${project.name}-${project.version}.jar")
    }
}

project('pxf-hive') {
    dependencies {
        compile(project(':pxf-hdfs'))
        compile(project(':pxf-service'))
        compile("org.apache.hive:hive-exec:$hiveVersion") {
            exclude module: 'calcite-core'
            exclude module: 'calcite-avatica'
        }
        compile "org.apache.hive:hive-metastore:$hiveVersion"
        compile "org.apache.hive:hive-common:$hiveVersion"
        compile "org.apache.hive:hive-serde:$hiveVersion"
        testCompile 'pl.pragmatists:JUnitParams:1.0.2'
    }

    ospackage {
        packageName = versionedPackageName("${project.name}")
        summary = 'HAWQ Extension Framework (PXF), Hive plugin'
        description = 'Querying external data stored in Hive'
        packager = ' '
        packageGroup = 'Development/Libraries'
        release = buildNumber() + '.' + project.osFamily
        buildHost = ' '

        requires(versionedPackageName('pxf-hdfs'), project.version, GREATER | EQUAL)

        from(jar.outputs.files) {
            into "/usr/lib/pxf-${project.version}"
        }

        link("/usr/lib/pxf-${project.version}/${project.name}.jar", "${project.name}-${project.version}.jar")
    }
}

project('pxf-json') {
    dependencies {
      compile(project(':pxf-hdfs'))
      compile(project(':pxf-service'))
      compile "org.apache.commons:commons-lang3:3.0"

      testCompile 'pl.pragmatists:JUnitParams:1.0.2'
    }

    ospackage {
      requires(versionedPackageName('pxf-hdfs'), project.version, GREATER | EQUAL)
        packageName = versionedPackageName("${project.name}")
        summary = 'HAWQ Extension Framework (PXF), Json plugin'
        description = 'Querying external data stored in HDFS in Json format'
        packager = ' '
        packageGroup = 'Development/Libraries'
        release = buildNumber() + '.' + project.osFamily
        buildHost = ' '

      from(jar.outputs.files) {
        into "/usr/lib/pxf-${project.version}"
      }

      link("/usr/lib/pxf-${project.version}/${project.name}.jar", "${project.name}-${project.version}.jar")
    }

    task create_tweets_tgz(type: Exec){
      commandLine 'tar', '-zcf', 'src/test/resources/tweets.tar.gz', '-C', 'src/test/resources', 'tweets-pp.json'
    }
    
    tasks['test'].dependsOn('create_tweets_tgz')
}

project('pxf-hbase') {
    dependencies {
        compile(project(':pxf-api'))
        compile "org.apache.hadoop:hadoop-common:$hadoopVersion"
        compile "org.apache.hbase:hbase-client:$hbaseVersionJar"
    }

    ospackage {
        packageName = versionedPackageName("${project.name}")
        summary = 'HAWQ Extension Framework (PXF), HBase plugin'
        description = 'Querying external data stored in HBase'
        packager = ' '
        packageGroup = 'Development/Libraries'
        release = buildNumber() + '.' + project.osFamily
        buildHost = ' '

        requires(versionedPackageName('pxf-service'), project.version, GREATER | EQUAL)

        from(jar.outputs.files) {
            into "/usr/lib/pxf-${project.version}"
        }

        link("/usr/lib/pxf-${project.version}/${project.name}.jar", "${project.name}-${project.version}.jar")
    }
}


project('pxf-jdbc') {
    dependencies {
        compile(project(':pxf-api'))
        compile(project(':pxf-service'))
        compile "org.apache.hadoop:hadoop-common:$hadoopVersion"
        compile "org.apache.hadoop:hadoop-hdfs:$hadoopVersion"
        testCompile "mysql:mysql-connector-java:5.1.6"
    }
    tasks.withType(JavaCompile) {
        options.encoding = "UTF-8"
    }

    ospackage {
        packageName = versionedPackageName("${project.name}")
        summary = 'HAWQ Extension Framework (PXF), JDBC plugin'
        description = 'Querying external data stored in Relation Database using JDBC.'
        packager = ' '
        packageGroup = 'Development/Libraries'
        release = buildNumber() + '.' + project.osFamily
        buildHost = ' '

        requires(versionedPackageName('pxf-service'), project.version, GREATER | EQUAL)

        from(jar.outputs.files) {
            into "/usr/lib/pxf-${project.version}"
        }

        link("/usr/lib/pxf-${project.version}/${project.name}.jar", "${project.name}-${project.version}.jar")
    }
}

def buildNumber() {
    System.getenv('BUILD_NUMBER') ?: System.getProperty('user.name')
}

task wrapper(type: Wrapper) {
    gradleVersion = '2.11'
}

def distSubprojects = subprojects - project(':pxf-api')

task release(type: Copy, dependsOn: [subprojects.build, subprojects.javadoc, distSubprojects.buildRpm, distSubprojects.distTar]) {
    delete 'build'
    into 'build'
    subprojects { subProject ->
        from("${project.name}/build/libs") { into 'libs' }
        from("${project.name}/build/distributions") { into 'distributions' }
        from("${project.name}/build/test-results") { into 'test-results' }
    }
}

task tar(type: Copy, dependsOn: [subprojects.build, distSubprojects.distTar]) {
    into 'build'
    distSubprojects.each { project ->
        from("${project.name}/build/distributions") { into 'distributions' }
    }
}

task jar(type: Copy, dependsOn: [subprojects.build]) {
    into 'build'
    subprojects { subProject ->
        from("${project.name}/build/libs") { into 'libs' }
    }
}

task rpm(type: Copy, dependsOn: [subprojects.build, distSubprojects.buildRpm]) {
    into 'build'
    distSubprojects.each { project ->
        from("${project.name}/build/distributions") { into 'distributions' }
    }
}

// tomcat 
def tomcatName = "apache-tomcat-${tomcatVersion}"
def tomcatTargetDir = "tomcat/build"

task tomcatGet << {

    apply plugin: 'de.undercouch.download'
    
    def TarGzSuffix = ".tar.gz"
    def tomcatTar = "${tomcatName}${TarGzSuffix}"
    def tomcatUrl = "http://archive.apache.org/dist/tomcat/tomcat-7/v${tomcatVersion}/bin/${tomcatTar}"

    if (file("${tomcatTargetDir}/${tomcatName}").exists()) {
        println "${tomcatName} already exists, nothing to do"
        return 0
    }

    println "About to download from ${tomcatUrl}..."
    // download tar ball
    download {
        src tomcatUrl
        dest "${tomcatTargetDir}/${tomcatTar}"
    }
    // extract tar ball
    println "Extracting..."
    copy {
        from tarTree(resources.gzip("${tomcatTargetDir}/${tomcatTar}"))
        into tomcatTargetDir
    }
}

apply plugin: 'os-package'

task tomcatRpm(type: Rpm) {
    buildDir = "${tomcatTargetDir}"

    // clean should not delete the downloaded tarball
    // and RPM, so this is a bogus directory to delete instead.
    clean {
        delete = "${tomcatTargetDir}/something"
    }

    ospackage {
        packageName 'apache-tomcat'
        summary = 'Apache Tomcat RPM'
        vendor = project.vendor
        version = tomcatVersion
        os = LINUX
        license = project.license
        user = 'root'
        permissionGroup = 'root'
        packager = ' '
        packageDescription = 'Apache Tomcat is an open source software implementation of the Java Servlet and JavaServer Pages technologies.'
        packageGroup = 'Development/Libraries'
        release = project.osFamily
        buildHost = ' '

        preInstall file('tomcat/src/scripts/pre-install.sh')

        from("${tomcatTargetDir}/${tomcatName}") {
            user 'tomcat'
            permissionGroup 'tomcat'
            addParentDirs false
            into "/opt/${tomcatName}"
        }

        link("/opt/${packageName}", "${tomcatName}")
    }
}

tomcatRpm.dependsOn tomcatGet

def pxfTargetDir = System.properties['deployPath'] ?: "build/"

task install(type: Copy, dependsOn: [subprojects.build, tomcatGet]) {
    into "${pxfTargetDir}"
    subprojects { subProject ->
        from("${project.name}/build/libs") { into 'lib' }
    }
    from("pxf-service/src/scripts/pxf-service") {
        into 'bin'
        fileMode 0755
        rename('pxf-service', 'pxf')
    }

    from("${tomcatTargetDir}/${tomcatName}") { into 'apache-tomcat' }
    from("pxf-service/src/main/resources") { into 'conf' }
    from("pxf-service/src/configs/pxf-site.xml") { into 'conf' }
    from("pxf-service/src/scripts/pxf-env.sh") { into 'conf' }
    from("pxf-service/src/configs/tomcat") { into 'tomcat-templates' }
}


buildDir = '.'
apply plugin: 'nebula-aggregate-javadocs'
