/*
 * 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.util.TeeOutputStream

// This project puts together a "distribution", assembling dependencies from
// various other projects.

plugins {
  id 'base'
  id 'distribution'
}

description = 'Solr distribution packaging'

ext {
  distDir = file("$buildDir/solr-${version}")
  slimDistDir = file("$buildDir/solr-${version}-slim")
  devDir = file("$buildDir/dev")
  slimDevDir = file("$buildDir/dev-slim")
}

configurations {
  modules
  example
  prometheusExporter
  crossDcManager
  server
  docs
  docker
  solrFullTgz
  solrSlimTgz
  solrFullTgzSignature
  solrSlimTgzSignature
}

dependencies {
  project(":solr:modules").childProjects.values().stream().map(project -> project.path).each { module ->
    modules project(path: module, configuration: "packaging")
  }

  prometheusExporter project(path: ":solr:prometheus-exporter", configuration: "packaging")

  crossDcManager project(path: ":solr:cross-dc-manager", configuration: "packaging")

  example project(path: ":solr:example", configuration: "packaging")
  server project(path: ":solr:server", configuration: "packaging")

  // Copy files from documentation output
  docs project(path: ':solr:documentation', configuration: 'minimalSite')

  docker project(path: ':solr:docker', configuration: 'packaging')

  solrFullTgzSignature files("$buildDir/distributions/solr-${version}.tgz.asc") {
    builtBy ":solr:distribution:signFullBinaryTgz"
  }

  solrSlimTgzSignature files("$buildDir/distributions/solr-${version}-slim.tgz.asc") {
    builtBy ":solr:distribution:signSlimBinaryTgz"
  }
}

distributions {
  slim {
    distributionBaseName = 'solr'
    distributionClassifier = "slim"
    contents {

      from(rootDir, {
        include "LICENSE.txt"
        include "NOTICE.txt"
      })

      from(project(":solr").projectDir, {
        include "bin/**"
        include "licenses/**"
        exclude "licenses/README.committers.txt"
        include "CHANGES.txt"
      })

      from(projectDir, {
        include "README.txt"
      })

      from ('static/lib', {
        into 'lib'
      })

      from(configurations.example, {
        into "example"
      })

      from(configurations.server, {
        into "server"
      })

      from(configurations.docs, {
        into "docs"
      })

      from(configurations.docker, {
        into "docker"
        filesMatching([
            "scripts/**",
        ]) { copy ->
          copy.setMode(0755)
        }
      })

      // Manually correct posix permissions (matters when packaging on Windows).
      filesMatching([
          "**/*.sh",
          "**/bin/solr",
          "**/bin/systemd/solr.service",
      ]) { copy ->
        copy.setMode(0755)
      }

    }
  }
  full {
    distributionBaseName = 'solr'
    contents {
      // Build on-top of the slim distribution
      with(distributions.slim.getContents())

      from(configurations.modules, {
        into "modules"
      })

      from(configurations.prometheusExporter, {
        into "prometheus-exporter"
        filesMatching([
                "bin/*",
        ]) { copy ->
          copy.setMode(0755)
        }
      })

      from(configurations.crossDcManager, {
        into "cross-dc-manager"
        filesMatching([
                "bin/*",
        ]) { copy ->
          copy.setMode(0755)
        }
      })
    }
  }
}

installFullDist {
  into distDir
}

installSlimDist {
  into slimDistDir
}

assembleDist {
  dependsOn tasks.assembleFullDist
  dependsOn tasks.assembleSlimDist
}

installDist {
  dependsOn tasks.installFullDist
  dependsOn tasks.installSlimDist
}

task devFull(type: Copy) {
  description "Assemble Full Solr distribution into 'development' folder at ${devDir}"
  group "build"

  from installFullDist.outputs
  into devDir
}

task devSlim(type: Copy) {
  description "Assemble Slim Solr distribution into 'development' folder at ${slimDevDir}"
  group "build"

  from installSlimDist.outputs
  into slimDevDir
}

task dev {
  description "Assemble Solr distributions into 'development' folders at ${devDir} and ${slimDevDir}"
  group "build"

  dependsOn tasks.devFull
  dependsOn tasks.devSlim
}

fullDistTar {
  compression = Compression.GZIP
}

slimDistTar {
  compression = Compression.GZIP
}

distTar.dependsOn tasks.fullDistTar
distTar.dependsOn tasks.slimDistTar

fullDistZip.enabled = false
slimDistZip.enabled = false

assemble.dependsOn tasks.installDist
assemble.dependsOn tasks.installSlimDist

artifacts {
  solrFullTgz(fullDistTar)
  solrSlimTgz(slimDistTar)
}

task downloadBats(type: NpmTask) {
  group = 'Build Dependency Download'
  args = ["install", "https://github.com/bats-core/bats-core#v${libs.versions.bats.core.get()}",
                     "https://github.com/bats-core/bats-assert#v${libs.versions.bats.assert.get()}",
                     "https://github.com/bats-core/bats-file#v${libs.versions.bats.file.get()}",
  ]

  inputs.files("${project.ext.nodeProjectDir}/package.json")
  outputs.dir("${project.ext.nodeProjectDir}/node_modules/bats")
  outputs.dir("${project.ext.nodeProjectDir}/node_modules/bats-support")
  outputs.dir("${project.ext.nodeProjectDir}/node_modules/bats-assert")
  outputs.dir("${project.ext.nodeProjectDir}/node_modules/bats-file")
}

task integrationTests(type: BatsTask) {
  dependsOn installFullDist
  dependsOn downloadBats

  def integrationTestOutput = "$buildDir/test-output"
  def solrHome = "$integrationTestOutput/solr-home"
  def solrTestFailuresDir = "$integrationTestOutput/failure-snapshots"
  var solrPort = Integer.parseInt((String) project.findProperty('bats.port') ?: System.getProperty("bats.port", "-1"))
  while (solrPort > 64000 || solrPort < 0) { // We need room for +1000 for ZK
    try (ServerSocket s = new ServerSocket(0)) {
      solrPort = s.getLocalPort()
    } catch (Exception e) {
      println("WARN: Could not assign random port for Bats tests. Using default port 8983.")
      solrPort = 8983
    }
  }

  inputs.dir(distDir)
  outputs.dir(integrationTestOutput)

  doFirst {
    delete integrationTestOutput
    mkdir integrationTestOutput
    mkdir solrHome
    mkdir solrTestFailuresDir

    // TODO - if quiet then don't tee
    standardOutput = new TeeOutputStream(System.out, new FileOutputStream("$integrationTestOutput/test-output.txt"))
    println("Running BATS tests with Solr base port ${solrPort}")
  }

  environment SOLR_TIP: distDir.toString()
  environment SOLR_HOME: solrHome
  environment SOLR_PID_DIR: solrHome
  environment SOLR_PORT: solrPort
  environment SOLR2_PORT: solrPort + 1
  environment SOLR3_PORT: solrPort + 2
  environment ZK_PORT: solrPort + 1000
  environment SOLR_EXPORTER_PORT: solrPort + 100
  environment SOLR_LOGS_DIR: "$solrHome/logs"
  environment TEST_OUTPUT_DIR: integrationTestOutput
  environment TEST_FAILURE_DIR: solrTestFailuresDir
  environment BATS_LIB_PREFIX: "$nodeProjectDir/node_modules"
}

class BatsTask extends Exec {
  @InputDirectory
  String testDir = 'test'

  @Input
  var testFiles = []

  @Option(option = "tests", description = "Sets test cases to be included")
  public void setTestNamePatterns(List<String> tests) {
    // TODO: bats --filter <regex>
    tests.each { testFiles << "$testDir/$it" }
  }

  @Override
  @TaskAction
  protected void exec() {
    executable "$project.ext.nodeProjectDir/node_modules/bats/bin/bats"

    // Note: tests to run must be listed after all other arguments
    // Additional debugging output: -x, --verbose-run
    setArgs(['-T', '--print-output-on-failure', '--report-formatter', 'junit', '--output', "$project.buildDir/test-output"] + (testFiles.empty ? testDir : testFiles))


    super.exec()
  }
}
