src/Pure/General/ssh.scala
changeset 76164 5e8bc80df6b3
parent 76163 9df6f51ebf45
child 76165 cf469736000c
equal deleted inserted replaced
76163:9df6f51ebf45 76164:5e8bc80df6b3
     7 
     7 
     8 package isabelle
     8 package isabelle
     9 
     9 
    10 
    10 
    11 import java.util.{Map => JMap}
    11 import java.util.{Map => JMap}
       
    12 import java.io.{File => JFile}
    12 
    13 
    13 
    14 
    14 object SSH {
    15 object SSH {
    15   /* target machine: user@host syntax */
    16   /* target machine: user@host syntax */
    16 
    17 
   114 
   115 
   115     def run_command(command: String,
   116     def run_command(command: String,
   116       master: Boolean = false,
   117       master: Boolean = false,
   117       opts: String = "",
   118       opts: String = "",
   118       args: String = "",
   119       args: String = "",
       
   120       cwd: JFile = null,
   119       progress_stdout: String => Unit = (_: String) => (),
   121       progress_stdout: String => Unit = (_: String) => (),
   120       progress_stderr: String => Unit = (_: String) => (),
   122       progress_stderr: String => Unit = (_: String) => (),
   121       strict: Boolean = true
   123       strict: Boolean = true
   122     ): Process_Result = {
   124     ): Process_Result = {
   123       val config =
   125       val config =
   125           control_master = master, control_path = control_path)
   127           control_master = master, control_path = control_path)
   126       val cmd =
   128       val cmd =
   127         Config.command(command, config) +
   129         Config.command(command, config) +
   128         (if (opts.nonEmpty) " " + opts else "") +
   130         (if (opts.nonEmpty) " " + opts else "") +
   129         (if (args.nonEmpty) " -- " + args else "")
   131         (if (args.nonEmpty) " -- " + args else "")
   130       Isabelle_System.bash(cmd, progress_stdout = progress_stdout,
   132       Isabelle_System.bash(cmd, cwd = cwd, progress_stdout = progress_stdout,
   131         progress_stderr = progress_stderr, strict = strict)
   133         progress_stderr = progress_stderr, strict = strict)
   132     }
   134     }
   133 
   135 
   134     def run_sftp(script: String, opts: String = "", args: String = ""): Process_Result = {
   136     def run_sftp(
   135       Isabelle_System.with_tmp_file("ssh") { tmp_path =>
   137       script: String,
   136         File.write(tmp_path, script)
   138       init: Path => Unit = _ => (),
   137         val opts1 = "-b " + File.bash_path(tmp_path) + (if (opts.nonEmpty) " " + opts else "")
   139       exit: Path => Unit = _ => ()
   138         val args1 = Bash.string(host) + (if (args.nonEmpty) " " + args else "")
   140     ): Process_Result = {
   139         run_command("sftp", opts = opts1, args = args1)
   141       Isabelle_System.with_tmp_dir("ssh") { dir =>
       
   142         init(dir)
       
   143         File.write(dir + Path.explode("script"), script)
       
   144         val result =
       
   145           run_command("sftp", opts = "-b script", args = Bash.string(host), cwd = dir.file).check
       
   146         exit(dir)
       
   147         result
   140       }
   148       }
   141     }
   149     }
   142 
   150 
   143     def run_ssh(master: Boolean = false, opts: String = "", args: String = ""): Process_Result = {
   151     def run_ssh(master: Boolean = false, opts: String = "", args: String = ""): Process_Result = {
   144       val args1 = Bash.string(host) + (if (args.nonEmpty) " " + args else "")
   152       val args1 = Bash.string(host) + (if (args.nonEmpty) " " + args else "")
   145       run_command("ssh", master = master, opts = opts, args = args1)
   153       run_command("ssh", master = master, opts = opts, args = args1)
   146     }
       
   147 
       
   148     def run_scp(opts: String = "", args: String = ""): Process_Result = {
       
   149       val opts1 = "-p -q" + (if (opts.nonEmpty) " " + opts else "")
       
   150       run_command("scp", opts = opts1, args = args)
       
   151     }
   154     }
   152 
   155 
   153 
   156 
   154     /* init and exit */
   157     /* init and exit */
   155 
   158 
   194     def remote_path(path: Path): String = expand_path(path).implode
   197     def remote_path(path: Path): String = expand_path(path).implode
   195 
   198 
   196     override def bash_path(path: Path): String = Bash.string(remote_path(path))
   199     override def bash_path(path: Path): String = Bash.string(remote_path(path))
   197     def sftp_path(path: Path): String = sftp_string(remote_path(path))
   200     def sftp_path(path: Path): String = sftp_string(remote_path(path))
   198 
   201 
   199     def rm(path: Path): Unit = run_sftp("rm " + sftp_path(path)).check
   202     def rm(path: Path): Unit = run_sftp("rm " + sftp_path(path))
   200 
   203 
   201     override def is_dir(path: Path): Boolean = run_ssh(args = "test -d " + bash_path(path)).ok
   204     override def is_dir(path: Path): Boolean = run_ssh(args = "test -d " + bash_path(path)).ok
   202     override def is_file(path: Path): Boolean = run_ssh(args = "test -f " + bash_path(path)).ok
   205     override def is_file(path: Path): Boolean = run_ssh(args = "test -f " + bash_path(path)).ok
   203 
   206 
   204     override def make_directory(path: Path): Path = {
   207     override def make_directory(path: Path): Path = {
   207       }
   210       }
   208       path
   211       path
   209     }
   212     }
   210 
   213 
   211     def read_dir(path: Path): List[String] =
   214     def read_dir(path: Path): List[String] =
   212       run_sftp("ls -1 -a " + sftp_path(path)).check.out_lines.flatMap(s =>
   215       run_sftp("ls -1 -a " + sftp_path(path)).out_lines.flatMap(s =>
   213         if (s == "." || s == ".." || s.endsWith("/.") || s.endsWith("/..")) None
   216         if (s == "." || s == ".." || s.endsWith("/.") || s.endsWith("/..")) None
   214         else Some(Library.perhaps_unprefix("./", s)))
   217         else Some(Library.perhaps_unprefix("./", s)))
   215 
   218 
       
   219     private def get_file[A](path: Path, f: Path => A): A = {
       
   220       var result: Option[A] = None
       
   221       run_sftp("get -p " + sftp_path(path) + " local",
       
   222         exit = dir => result = Some(f(dir + Path.explode("local"))))
       
   223       result.get
       
   224     }
       
   225 
       
   226     private def put_file(path: Path, f: Path => Unit): Unit =
       
   227       run_sftp("put -p local " + sftp_path(path),
       
   228         init = dir => f(dir + Path.explode("local")))
       
   229 
   216     override def read_file(path: Path, local_path: Path): Unit =
   230     override def read_file(path: Path, local_path: Path): Unit =
   217       run_scp(args = Bash.string(host + ":" + remote_path(path)) + " " +
   231       get_file(path, Isabelle_System.copy_file(_, local_path))
   218         File.bash_platform_path(local_path)).check
       
   219 
       
   220     override def read_bytes(path: Path): Bytes =
   232     override def read_bytes(path: Path): Bytes =
   221       Isabelle_System.with_tmp_file("ssh") { local_path =>
   233       get_file(path, Bytes.read)
   222         read_file(path, local_path)
   234     override def read(path: Path): String =
   223         Bytes.read(local_path)
   235       get_file(path, File.read)
   224       }
       
   225 
       
   226     override def read(path: Path): String = read_bytes(path).text
       
   227 
   236 
   228     override def write_file(path: Path, local_path: Path): Unit =
   237     override def write_file(path: Path, local_path: Path): Unit =
   229       run_scp(args = File.bash_platform_path(local_path) + " " +
   238       put_file(path, Isabelle_System.copy_file(local_path, _))
   230         Bash.string(host + ":" + remote_path(path))).check
       
   231 
       
   232     def write_bytes(path: Path, bytes: Bytes): Unit =
   239     def write_bytes(path: Path, bytes: Bytes): Unit =
   233       Isabelle_System.with_tmp_file("ssh") { local_path =>
   240       put_file(path, Bytes.write(_, bytes))
   234         Bytes.write(local_path, bytes)
   241     def write(path: Path, text: String): Unit =
   235         write_file(path, local_path)
   242       put_file(path, File.write(_, text))
   236       }
       
   237 
       
   238     def write(path: Path, text: String): Unit = write_bytes(path, Bytes(text))
       
   239 
   243 
   240 
   244 
   241     /* tmp dirs */
   245     /* tmp dirs */
   242 
   246 
   243     def rm_tree(dir: Path): Unit = rm_tree(remote_path(dir))
   247     def rm_tree(dir: Path): Unit = rm_tree(remote_path(dir))