diff -r a9f540881611 -r c3197aeae90b src/Pure/General/ssh.scala --- a/src/Pure/General/ssh.scala Sun Oct 16 17:10:24 2016 +0200 +++ b/src/Pure/General/ssh.scala Sun Oct 16 17:44:37 2016 +0200 @@ -103,17 +103,6 @@ } - /* channel */ - - class Channel[C <: JSch_Channel] private[SSH]( - val session: Session, val kind: String, val channel: C) - { - override def toString: String = kind + " " + session.toString - - def close() { channel.disconnect } - } - - /* Sftp channel */ type Attrs = SftpATTRS @@ -124,88 +113,17 @@ def is_dir: Boolean = attrs.isDir } - class Sftp private[SSH](session: Session, kind: String, channel: ChannelSftp) - extends Channel[ChannelSftp](session, kind, channel) - { - channel.connect(connect_timeout(session.options)) - - val settings: Map[String, String] = - { - val home = channel.getHome - Map("HOME" -> home, "USER_HOME" -> home) - } - def expand_path(path: Path): Path = path.expand_env(settings) - def remote_path(path: Path): String = expand_path(path).implode - - def chmod(permissions: Int, path: Path): Unit = channel.chmod(permissions, remote_path(path)) - def mv(path1: Path, path2: Path): Unit = channel.rename(remote_path(path1), remote_path(path2)) - def rm(path: Path): Unit = channel.rm(remote_path(path)) - def mkdir(path: Path): Unit = channel.mkdir(remote_path(path)) - def rmdir(path: Path): Unit = channel.rmdir(remote_path(path)) - - def stat(path: Path): Option[Dir_Entry] = - try { Some(Dir_Entry(expand_path(path), channel.stat(remote_path(path)))) } - catch { case _: SftpException => None } - - def is_file(path: Path): Boolean = stat(path).map(_.is_file) getOrElse false - def is_dir(path: Path): Boolean = stat(path).map(_.is_dir) getOrElse false - - def mkdirs(path: Path): Unit = - if (!is_dir(path)) { - session.execute( - "perl -e \"use File::Path make_path; make_path('" + remote_path(path) + "');\"") - if (!is_dir(path)) error("Failed to create directory: " + quote(remote_path(path))) - } - - def read_dir(path: Path): List[Dir_Entry] = - { - val dir = channel.ls(remote_path(path)) - (for { - i <- (0 until dir.size).iterator - a = dir.get(i).asInstanceOf[AnyRef] - name = Untyped.get[String](a, "filename") - attrs = Untyped.get[Attrs](a, "attrs") - if name != "." && name != ".." - } yield Dir_Entry(Path.basic(name), attrs)).toList - } - - def find_files(root: Path, pred: Dir_Entry => Boolean = _ => true): List[Dir_Entry] = - { - def find(dir: Path): List[Dir_Entry] = - read_dir(dir).flatMap(entry => - { - val file = dir + entry.name - if (entry.is_dir) find(file) - else if (pred(entry)) List(entry.copy(name = file)) - else Nil - }) - find(root) - } - - def open_input(path: Path): InputStream = channel.get(remote_path(path)) - def open_output(path: Path): OutputStream = channel.put(remote_path(path)) - - def read_file(path: Path, local_path: Path): Unit = - channel.get(remote_path(path), File.platform_path(local_path)) - def read_bytes(path: Path): Bytes = using(open_input(path))(Bytes.read_stream(_)) - def read(path: Path): String = using(open_input(path))(File.read_stream(_)) - - def write_file(path: Path, local_path: Path): Unit = - channel.put(File.platform_path(local_path), remote_path(path)) - def write_bytes(path: Path, bytes: Bytes): Unit = - using(open_output(path))(bytes.write_stream(_)) - def write(path: Path, text: String): Unit = - using(open_output(path))(stream => Bytes(text).write_stream(stream)) - } - /* exec channel */ private val exec_wait_delay = Time.seconds(0.3) - class Exec private[SSH](session: Session, kind: String, channel: ChannelExec) - extends Channel[ChannelExec](session, kind, channel) + class Exec private[SSH](session: Session, channel: ChannelExec) { + override def toString: String = "exec " + session.toString + + def close() { channel.disconnect } + def kill(signal: String) { channel.sendSignal(signal) } val exit_status: Future[Int] = @@ -290,21 +208,90 @@ (if (session.getPort == default_port) "" else ":" + session.getPort) + (if (session.isConnected) "" else " (disconnected)") - def close() { session.disconnect } + + /* sftp channel */ + + val sftp: ChannelSftp = session.openChannel("sftp").asInstanceOf[ChannelSftp] + sftp.connect(connect_timeout(options)) + + def close() { sftp.disconnect; session.disconnect } + + val settings: Map[String, String] = + { + val home = sftp.getHome + Map("HOME" -> home, "USER_HOME" -> home) + } + def expand_path(path: Path): Path = path.expand_env(settings) + def remote_path(path: Path): String = expand_path(path).implode - def sftp(): Sftp = + def chmod(permissions: Int, path: Path): Unit = sftp.chmod(permissions, remote_path(path)) + def mv(path1: Path, path2: Path): Unit = sftp.rename(remote_path(path1), remote_path(path2)) + def rm(path: Path): Unit = sftp.rm(remote_path(path)) + def mkdir(path: Path): Unit = sftp.mkdir(remote_path(path)) + def rmdir(path: Path): Unit = sftp.rmdir(remote_path(path)) + + def stat(path: Path): Option[Dir_Entry] = + try { Some(Dir_Entry(expand_path(path), sftp.stat(remote_path(path)))) } + catch { case _: SftpException => None } + + def is_file(path: Path): Boolean = stat(path).map(_.is_file) getOrElse false + def is_dir(path: Path): Boolean = stat(path).map(_.is_dir) getOrElse false + + def mkdirs(path: Path): Unit = + if (!is_dir(path)) { + execute( + "perl -e \"use File::Path make_path; make_path('" + remote_path(path) + "');\"") + if (!is_dir(path)) error("Failed to create directory: " + quote(remote_path(path))) + } + + def read_dir(path: Path): List[Dir_Entry] = { - val kind = "sftp" - val channel = session.openChannel(kind).asInstanceOf[ChannelSftp] - new Sftp(this, kind, channel) + val dir = sftp.ls(remote_path(path)) + (for { + i <- (0 until dir.size).iterator + a = dir.get(i).asInstanceOf[AnyRef] + name = Untyped.get[String](a, "filename") + attrs = Untyped.get[Attrs](a, "attrs") + if name != "." && name != ".." + } yield Dir_Entry(Path.basic(name), attrs)).toList } + def find_files(root: Path, pred: Dir_Entry => Boolean = _ => true): List[Dir_Entry] = + { + def find(dir: Path): List[Dir_Entry] = + read_dir(dir).flatMap(entry => + { + val file = dir + entry.name + if (entry.is_dir) find(file) + else if (pred(entry)) List(entry.copy(name = file)) + else Nil + }) + find(root) + } + + def open_input(path: Path): InputStream = sftp.get(remote_path(path)) + def open_output(path: Path): OutputStream = sftp.put(remote_path(path)) + + def read_file(path: Path, local_path: Path): Unit = + sftp.get(remote_path(path), File.platform_path(local_path)) + def read_bytes(path: Path): Bytes = using(open_input(path))(Bytes.read_stream(_)) + def read(path: Path): String = using(open_input(path))(File.read_stream(_)) + + def write_file(path: Path, local_path: Path): Unit = + sftp.put(File.platform_path(local_path), remote_path(path)) + def write_bytes(path: Path, bytes: Bytes): Unit = + using(open_output(path))(bytes.write_stream(_)) + def write(path: Path, text: String): Unit = + using(open_output(path))(stream => Bytes(text).write_stream(stream)) + + + /* exec channel */ + def exec(command: String): Exec = { - val kind = "exec" - val channel = session.openChannel(kind).asInstanceOf[ChannelExec] + val channel = session.openChannel("exec").asInstanceOf[ChannelExec] channel.setCommand("export USER_HOME=\"$HOME\"\n" + command) - new Exec(this, kind, channel) + new Exec(this, channel) } def execute(command: String,