src/Pure/General/ssh.scala
changeset 64191 1dcb5acd9a71
parent 64190 c62b99e3ec07
child 64222 184e3a932778
equal deleted inserted replaced
64190:c62b99e3ec07 64191:1dcb5acd9a71
   109     val session: Session, val kind: String, val channel: C)
   109     val session: Session, val kind: String, val channel: C)
   110   {
   110   {
   111     override def toString: String = kind + " " + session.toString
   111     override def toString: String = kind + " " + session.toString
   112 
   112 
   113     def close() { channel.disconnect }
   113     def close() { channel.disconnect }
       
   114   }
       
   115 
       
   116 
       
   117   /* Sftp channel */
       
   118 
       
   119   type Attrs = SftpATTRS
       
   120 
       
   121   sealed case class Dir_Entry(name: String, attrs: Attrs)
       
   122   {
       
   123     def is_file: Boolean = attrs.isReg
       
   124     def is_dir: Boolean = attrs.isDir
       
   125   }
       
   126 
       
   127   class Sftp private[SSH](session: Session, kind: String, channel: ChannelSftp)
       
   128     extends Channel[ChannelSftp](session, kind, channel)
       
   129   {
       
   130     channel.connect(connect_timeout(session.options))
       
   131 
       
   132     def home: String = channel.getHome()
       
   133 
       
   134     def chmod(permissions: Int, remote_path: String) { channel.chmod(permissions, remote_path) }
       
   135     def mv(remote_path1: String, remote_path2: String): Unit =
       
   136       channel.rename(remote_path1, remote_path2)
       
   137     def rm(remote_path: String) { channel.rm(remote_path) }
       
   138     def mkdir(remote_path: String) { channel.mkdir(remote_path) }
       
   139     def rmdir(remote_path: String) { channel.rmdir(remote_path) }
       
   140 
       
   141     def stat(remote_path: String): Dir_Entry =
       
   142       Dir_Entry(remote_path, channel.stat(remote_path))
       
   143 
       
   144     def read_dir(remote_path: String): List[Dir_Entry] =
       
   145     {
       
   146       val dir = channel.ls(remote_path)
       
   147       (for {
       
   148         i <- (0 until dir.size).iterator
       
   149         a = dir.get(i).asInstanceOf[AnyRef]
       
   150         name = Untyped.get[String](a, "filename")
       
   151         attrs = Untyped.get[Attrs](a, "attrs")
       
   152         if name != "." && name != ".."
       
   153       } yield Dir_Entry(name, attrs)).toList
       
   154     }
       
   155 
       
   156     def find_files(remote_path: String, pred: Dir_Entry => Boolean = _ => true): List[Dir_Entry] =
       
   157     {
       
   158       def find(dir: String): List[Dir_Entry] =
       
   159         read_dir(dir).flatMap(entry =>
       
   160           {
       
   161             val file = dir + "/" + entry.name
       
   162             if (entry.is_dir) find(file)
       
   163             else if (pred(entry)) List(entry.copy(name = file))
       
   164             else Nil
       
   165           })
       
   166       find(remote_path)
       
   167     }
       
   168 
       
   169     def open_input(remote_path: String): InputStream = channel.get(remote_path)
       
   170     def open_output(remote_path: String): OutputStream = channel.put(remote_path)
       
   171 
       
   172     def read_file(remote_path: String, local_path: Path): Unit =
       
   173       channel.get(remote_path, File.platform_path(local_path))
       
   174     def read_bytes(remote_path: String): Bytes =
       
   175       using(open_input(remote_path))(Bytes.read_stream(_))
       
   176     def read(remote_path: String): String =
       
   177       using(open_input(remote_path))(File.read_stream(_))
       
   178 
       
   179     def write_file(remote_path: String, local_path: Path): Unit =
       
   180       channel.put(File.platform_path(local_path), remote_path)
       
   181     def write_bytes(remote_path: String, bytes: Bytes): Unit =
       
   182       using(open_output(remote_path))(bytes.write_stream(_))
       
   183     def write(remote_path: String, text: String): Unit =
       
   184       using(open_output(remote_path))(stream => Bytes(text).write_stream(stream))
   114   }
   185   }
   115 
   186 
   116 
   187 
   117   /* exec channel */
   188   /* exec channel */
   118 
   189 
   191       Process_Result(rc, out_lines.join, err_lines.join)
   262       Process_Result(rc, out_lines.join, err_lines.join)
   192     }
   263     }
   193   }
   264   }
   194 
   265 
   195 
   266 
   196   /* Sftp channel */
       
   197 
       
   198   type Attrs = SftpATTRS
       
   199 
       
   200   sealed case class Dir_Entry(name: String, attrs: Attrs)
       
   201   {
       
   202     def is_file: Boolean = attrs.isReg
       
   203     def is_dir: Boolean = attrs.isDir
       
   204   }
       
   205 
       
   206   class Sftp private[SSH](session: Session, kind: String, channel: ChannelSftp)
       
   207     extends Channel[ChannelSftp](session, kind, channel)
       
   208   {
       
   209     channel.connect(connect_timeout(session.options))
       
   210 
       
   211     def home: String = channel.getHome()
       
   212 
       
   213     def chmod(permissions: Int, remote_path: String) { channel.chmod(permissions, remote_path) }
       
   214     def mv(remote_path1: String, remote_path2: String): Unit =
       
   215       channel.rename(remote_path1, remote_path2)
       
   216     def rm(remote_path: String) { channel.rm(remote_path) }
       
   217     def mkdir(remote_path: String) { channel.mkdir(remote_path) }
       
   218     def rmdir(remote_path: String) { channel.rmdir(remote_path) }
       
   219 
       
   220     def stat(remote_path: String): Dir_Entry =
       
   221       Dir_Entry(remote_path, channel.stat(remote_path))
       
   222 
       
   223     def read_dir(remote_path: String): List[Dir_Entry] =
       
   224     {
       
   225       val dir = channel.ls(remote_path)
       
   226       (for {
       
   227         i <- (0 until dir.size).iterator
       
   228         a = dir.get(i).asInstanceOf[AnyRef]
       
   229         name = Untyped.get[String](a, "filename")
       
   230         attrs = Untyped.get[Attrs](a, "attrs")
       
   231         if name != "." && name != ".."
       
   232       } yield Dir_Entry(name, attrs)).toList
       
   233     }
       
   234 
       
   235     def find_files(remote_path: String, pred: Dir_Entry => Boolean = _ => true): List[Dir_Entry] =
       
   236     {
       
   237       def find(dir: String): List[Dir_Entry] =
       
   238         read_dir(dir).flatMap(entry =>
       
   239           {
       
   240             val file = dir + "/" + entry.name
       
   241             if (entry.is_dir) find(file)
       
   242             else if (pred(entry)) List(entry.copy(name = file))
       
   243             else Nil
       
   244           })
       
   245       find(remote_path)
       
   246     }
       
   247 
       
   248     def open_input(remote_path: String): InputStream = channel.get(remote_path)
       
   249     def open_output(remote_path: String): OutputStream = channel.put(remote_path)
       
   250 
       
   251     def read_file(remote_path: String, local_path: Path): Unit =
       
   252       channel.get(remote_path, File.platform_path(local_path))
       
   253     def read_bytes(remote_path: String): Bytes =
       
   254       using(open_input(remote_path))(Bytes.read_stream(_))
       
   255     def read(remote_path: String): String =
       
   256       using(open_input(remote_path))(File.read_stream(_))
       
   257 
       
   258     def write_file(remote_path: String, local_path: Path): Unit =
       
   259       channel.put(File.platform_path(local_path), remote_path)
       
   260     def write_bytes(remote_path: String, bytes: Bytes): Unit =
       
   261       using(open_output(remote_path))(bytes.write_stream(_))
       
   262     def write(remote_path: String, text: String): Unit =
       
   263       using(open_output(remote_path))(stream => Bytes(text).write_stream(stream))
       
   264   }
       
   265 
       
   266 
       
   267   /* session */
   267   /* session */
   268 
   268 
   269   class Session private[SSH](val options: Options, val session: JSch_Session)
   269   class Session private[SSH](val options: Options, val session: JSch_Session)
   270   {
   270   {
   271     def update_options(new_options: Options): Session = new Session(new_options, session)
   271     def update_options(new_options: Options): Session = new Session(new_options, session)
   276       (if (session.getPort == default_port) "" else ":" + session.getPort) +
   276       (if (session.getPort == default_port) "" else ":" + session.getPort) +
   277       (if (session.isConnected) "" else " (disconnected)")
   277       (if (session.isConnected) "" else " (disconnected)")
   278 
   278 
   279     def close() { session.disconnect }
   279     def close() { session.disconnect }
   280 
   280 
       
   281     def sftp(): Sftp =
       
   282     {
       
   283       val kind = "sftp"
       
   284       val channel = session.openChannel(kind).asInstanceOf[ChannelSftp]
       
   285       new Sftp(this, kind, channel)
       
   286     }
       
   287 
       
   288     def exec(command: String): Exec =
       
   289     {
       
   290       val kind = "exec"
       
   291       val channel = session.openChannel(kind).asInstanceOf[ChannelExec]
       
   292       channel.setCommand("export USER_HOME=\"$HOME\"\n" + command)
       
   293       new Exec(this, kind, channel)
       
   294     }
       
   295 
   281     def execute(command: String,
   296     def execute(command: String,
   282         progress_stdout: String => Unit = (_: String) => (),
   297         progress_stdout: String => Unit = (_: String) => (),
   283         progress_stderr: String => Unit = (_: String) => (),
   298         progress_stderr: String => Unit = (_: String) => (),
   284         strict: Boolean = true): Process_Result =
   299         strict: Boolean = true): Process_Result =
   285       exec(command).result(progress_stdout, progress_stderr, strict)
   300       exec(command).result(progress_stdout, progress_stderr, strict)
   286 
   301 
   287     def exec(command: String): Exec =
       
   288     {
       
   289       val kind = "exec"
       
   290       val channel = session.openChannel(kind).asInstanceOf[ChannelExec]
       
   291       channel.setCommand("export USER_HOME=\"$HOME\"\n" + command)
       
   292       new Exec(this, kind, channel)
       
   293     }
       
   294 
       
   295     def sftp(): Sftp =
       
   296     {
       
   297       val kind = "sftp"
       
   298       val channel = session.openChannel(kind).asInstanceOf[ChannelSftp]
       
   299       new Sftp(this, kind, channel)
       
   300     }
       
   301 
       
   302 
   302 
   303     /* tmp dirs */
   303     /* tmp dirs */
   304 
   304 
   305     def rm_tree(remote_dir: String): Unit =
   305     def rm_tree(remote_dir: String): Unit =
   306       execute("rm -r -f " + File.bash_string(remote_dir)).check
   306       execute("rm -r -f " + File.bash_string(remote_dir)).check