project.ext.Scp = Scp.class
project.ext.SshExec = SshExec.class
project.ext.SshTask = SshTask.class

configurations {
  sshAntTask
}

dependencies {
  sshAntTask "org.apache.ant:ant-jsch:1.8.2"
}

tasks.withType(SshTask) {
  sshAntClasspath = configurations.sshAntTask
}

class SshTask extends DefaultTask {
  @InputFiles
  FileCollection sshAntClasspath

  @Input
  String host

  @Input
  String userName

  @Input
  String password

  boolean verbose = false

  private boolean antInited = false

  protected initAnt() {
    if (!antInited) {
      ant.taskdef(name: 'scp',
        classname: 'org.apache.tools.ant.taskdefs.optional.ssh.Scp',
        classpath: sshAntClasspath.asPath,
        loaderref: 'ssh')
      ant.taskdef(name: 'sshexec',
        classname: 'org.apache.tools.ant.taskdefs.optional.ssh.SSHExec',
        classpath: sshAntClasspath.asPath,
        loaderref: 'ssh')
      antInited = true
    }
  }

  protected withInfoLogging(Closure action) {
    def oldLogLevel = logging.level
    logging.level = [LogLevel.INFO, oldLogLevel].min()
    try {
      action()
    } finally {
      if (oldLogLevel) {
        logging.level = oldLogLevel
      }
    }
  }

  def scpFile(source, destination) {
    initAnt()
    withInfoLogging {
      ant.scp(localFile: project.files(source).singleFile, remoteToFile: "${userName}@${host}:${destination}", keyfile : "${System.properties['user.home']}/.ssh/id_dsa", verbose: verbose)
    }
  }

  def scpDir(source, destination) {
    initAnt()
    withInfoLogging {
      ant.sshexec(host: host, username: userName, password: password, command: "mkdir -p ${destination}")
      ant.scp(remoteTodir: "${userName}@${host}:${destination}", keyfile : "${System.properties['user.home']}/.ssh/id_dsa", verbose: verbose) {
        project.files(source).addToAntBuilder(ant, "fileSet", FileCollection.AntType.FileSet)
      }
    }
  }

  def ssh(Object... commandLine) {
    initAnt()
    withInfoLogging {
      ant.sshexec(host: host, username: userName, password: password, command: commandLine.join(' '))
    }
  }
}

class Scp extends SshTask {
  @InputFiles @SkipWhenEmpty source
  @Input destination
  boolean isDir = false

  @TaskAction
  void doActions() {
    if (isDir) {
      scpDir(source, destination)
      return
    }

    project.files(source).each { doFile(it) }
  }

  void doFile(File file) {

    if (file.directory) {
      file.eachFile { doFile(it) }
    } else {
      scpFile(file, destination)
    }
  }
}

class SshExec extends SshTask {
  @Input
  List<String[]> commandLines = []

  void commandLine(String... commandLine) {
    commandLines << commandLine
  }

  @TaskAction
  void doActions() {
    commandLines.each { commandLine ->
      ssh(* commandLine)
    }
  }
}