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

configurations {
    sshAntTask
}

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

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

abstract class SshTask extends DefaultTask {
    @InputFiles
    FileCollection sshAntClasspath

    @Input
    String host

    @Input
    String userName

    @Input
    String password

    boolean verbose = false

    @TaskAction
    def executeActions() {
        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')
        doActions()
    }

    abstract void doActions()

    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) {
        withInfoLogging {
            ant.scp(localFile: project.files(source).singleFile, remoteToFile: "${userName}@${host}:${destination}", password: password, verbose: verbose)
        }
    }

    def scpDir(source, destination) {
        withInfoLogging {
            ant.sshexec(host: host, username: userName, password: password, command: "mkdir -p ${destination}")
            ant.scp(remoteTodir: "${userName}@${host}:${destination}", password: password, verbose: verbose) {
                project.files(source).addToAntBuilder(ant, "fileSet", FileCollection.AntType.FileSet)
            }
        }
    }

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

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

    void doActions() {
        isDir ? scpDir(source, destination) : scpFile(source, destination)
    }
}

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

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

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