src/Pure/General/ssh.scala
changeset 79633 c59231722f10
parent 78924 0481c84f6919
child 79635 8d2539a13502
equal deleted inserted replaced
79632:463f94c504a4 79633:c59231722f10
    93 
    93 
    94   def open_session(
    94   def open_session(
    95     options: Options,
    95     options: Options,
    96     host: String,
    96     host: String,
    97     port: Int = 0,
    97     port: Int = 0,
    98     user: String = ""
    98     user: String = "",
       
    99     user_home: String = ""
    99   ): Session = {
   100   ): Session = {
   100     if (is_local(host)) error("Illegal SSH host name " + quote(host))
   101     if (is_local(host)) error("Illegal SSH host name " + quote(host))
   101 
   102 
   102     val multiplex = options.bool("ssh_multiplexing") && !Platform.is_windows
   103     val multiplex = options.bool("ssh_multiplexing") && !Platform.is_windows
   103     val (control_master, control_path) =
   104     val (control_master, control_path) =
   104       if (multiplex) (true, Isabelle_System.tmp_file("ssh", initialized = false).getPath)
   105       if (multiplex) (true, Isabelle_System.tmp_file("ssh", initialized = false).getPath)
   105       else (false, "")
   106       else (false, "")
   106     new Session(options, host, port, user, control_master, control_path)
   107     new Session(options, host, port, user, user_home, control_master, control_path)
   107   }
   108   }
   108 
   109 
   109   class Session private[SSH](
   110   class Session private[SSH](
   110     val options: Options,
   111     val options: Options,
   111     val host: String,
   112     val host: String,
   112     val port: Int,
   113     val port: Int,
   113     val user: String,
   114     val user: String,
       
   115     user_home0: String,
   114     control_master: Boolean,
   116     control_master: Boolean,
   115     val control_path: String
   117     val control_path: String
   116   ) extends System {
   118   ) extends System {
   117     ssh =>
   119     ssh =>
   118 
   120 
   176     }
   178     }
   177 
   179 
   178 
   180 
   179     /* init and exit */
   181     /* init and exit */
   180 
   182 
   181     val user_home: String = {
   183     override val home: String = {
   182       run_ssh(master = control_master, args = "printenv HOME \";\" printenv SHELL").check.out_lines
   184       run_ssh(master = control_master, args = "printenv HOME \";\" printenv SHELL").check.out_lines
   183       match {
   185       match {
   184         case List(user_home, shell) =>
   186         case List(home, shell) =>
   185           if (shell.endsWith("/bash")) user_home
   187           if (shell.endsWith("/bash")) home
   186           else {
   188           else {
   187             error("Bad SHELL for " + quote(toString) + " -- expected GNU bash, but found " + shell)
   189             error("Bad SHELL for " + quote(toString) + " -- expected GNU bash, but found " + shell)
   188           }
   190           }
   189         case _ => error("Malformed remote environment for " + quote(toString))
   191         case _ => error("Malformed remote environment for " + quote(toString))
   190       }
   192       }
   191     }
   193     }
   192 
   194 
   193     val settings: Isabelle_System.Settings =
   195     override val user_home: String = {
   194       (name: String) => if (name == "HOME" || name == "USER_HOME") user_home else ""
   196       val path1 =
       
   197         try { Path.explode(home).expand_env(Isabelle_System.No_Env) }
       
   198         catch { case ERROR(msg) => error(msg + " -- in SSH HOME") }
       
   199       val path2 =
       
   200         try { Path.explode(user_home0).expand_env(Isabelle_System.No_Env) }
       
   201         catch { case ERROR(msg) => error(msg + "-- in SSH USER_HOME") }
       
   202       (path1 + path2).implode
       
   203     }
       
   204 
       
   205     val settings: Isabelle_System.Settings = {
       
   206       case "HOME" => home
       
   207       case "USER_HOME" => user_home
       
   208       case _ => ""
       
   209     }
   195 
   210 
   196     override def close(): Unit = {
   211     override def close(): Unit = {
   197       if (control_path.nonEmpty) run_ssh(opts = "-O exit").check
   212       if (control_path.nonEmpty) run_ssh(opts = "-O exit").check
   198     }
   213     }
   199 
   214 
   205       progress_stderr: String => Unit = (_: String) => (),
   220       progress_stderr: String => Unit = (_: String) => (),
   206       redirect: Boolean = false,
   221       redirect: Boolean = false,
   207       settings: Boolean = true,
   222       settings: Boolean = true,
   208       strict: Boolean = true
   223       strict: Boolean = true
   209     ): Process_Result = {
   224     ): Process_Result = {
       
   225       val script = Isabelle_System.export_env(user_home = user_home) + cmd_line
   210       run_command("ssh",
   226       run_command("ssh",
   211         args = Bash.string(host) + " " + Bash.string(cmd_line),
   227         args = Bash.string(host) + " " + Bash.string(script),
   212         progress_stdout = progress_stdout,
   228         progress_stdout = progress_stdout,
   213         progress_stderr = progress_stderr,
   229         progress_stderr = progress_stderr,
   214         redirect = redirect,
   230         redirect = redirect,
   215         strict = strict)
   231         strict = strict)
   216     }
   232     }
   234     /* remote file-system */
   250     /* remote file-system */
   235 
   251 
   236     override def expand_path(path: Path): Path = path.expand_env(settings)
   252     override def expand_path(path: Path): Path = path.expand_env(settings)
   237     override def absolute_path(path: Path): Path = {
   253     override def absolute_path(path: Path): Path = {
   238       val path1 = expand_path(path)
   254       val path1 = expand_path(path)
   239       if (path1.is_absolute) path1 else Path.explode(user_home) + path1
   255       if (path1.is_absolute) path1 else Path.explode(home) + path1
   240     }
   256     }
   241 
   257 
   242     def remote_path(path: Path): String = expand_path(path).implode
   258     def remote_path(path: Path): String = expand_path(path).implode
   243 
   259 
   244     override def bash_path(path: Path): String = Bash.string(remote_path(path))
   260     override def bash_path(path: Path): String = Bash.string(remote_path(path))
   385   def open_server(
   401   def open_server(
   386     options: Options,
   402     options: Options,
   387     host: String,
   403     host: String,
   388     port: Int = 0,
   404     port: Int = 0,
   389     user: String = "",
   405     user: String = "",
       
   406     user_home: String = "",
   390     remote_port: Int = 0,
   407     remote_port: Int = 0,
   391     remote_host: String = "localhost",
   408     remote_host: String = "localhost",
   392     local_port: Int = 0,
   409     local_port: Int = 0,
   393     local_host: String = "localhost"
   410     local_host: String = "localhost"
   394   ): Server = {
   411   ): Server = {
   395     val ssh = open_session(options, host, port = port, user = user)
   412     val ssh = open_session(options, host, port = port, user = user, user_home = user_home)
   396     try {
   413     try {
   397       ssh.open_server(remote_port = remote_port, remote_host = remote_host,
   414       ssh.open_server(remote_port = remote_port, remote_host = remote_host,
   398         local_port = local_port, local_host = local_host, ssh_close = true)
   415         local_port = local_port, local_host = local_host, ssh_close = true)
   399     }
   416     }
   400     catch { case exn: Throwable => ssh.close(); throw exn }
   417     catch { case exn: Throwable => ssh.close(); throw exn }
   428 
   445 
   429   def open_system(
   446   def open_system(
   430     options: Options,
   447     options: Options,
   431     host: String,
   448     host: String,
   432     port: Int = 0,
   449     port: Int = 0,
   433     user: String = ""
   450     user: String = "",
       
   451     user_home: String = ""
   434   ): System = {
   452   ): System = {
   435     if (is_local(host)) Local
   453     if (is_local(host)) Local
   436     else open_session(options, host = host, port = port, user = user)
   454     else open_session(options, host = host, port = port, user = user, user_home = user_home)
   437   }
   455   }
   438 
   456 
   439   trait System extends AutoCloseable {
   457   trait System extends AutoCloseable {
   440     def ssh_session: Option[Session]
   458     def ssh_session: Option[Session]
   441     def is_local: Boolean = ssh_session.isEmpty
   459     def is_local: Boolean = ssh_session.isEmpty
       
   460 
       
   461     def home: String = ""
       
   462     def user_home: String = ""
   442 
   463 
   443     def close(): Unit = ()
   464     def close(): Unit = ()
   444 
   465 
   445     override def toString: String = LOCAL
   466     override def toString: String = LOCAL
   446     def print: String = ""
   467     def print: String = ""