let get_file ?timeout t ~path =
  match connection t with
  | `Localhost ->
    begin IO.read_file Path.(to_string path)
      >>< function
      | `Ok c -> return c
      | `Error (`IO (`Read_file_exn (path, ex))) ->
        Log.(s "I/O, writing " % s path % s " → " % exn ex @ verbose);
        fail (`Cannot_read_file ("localhost", path))
    end
  | `Ssh ssh ->
    let temp = Filename.temp_file "ketrew" "ssh_get_file" in
    let scp_cmd = Ssh.(scp_pull ssh ~dest:temp ~src:[Path.to_string path]) in
    begin run_with_timeout ?timeout t
        ~run:(fun ~log () ->
            Ketrew_unix_process.succeed scp_cmd
            >>= fun _ ->
            IO.read_file temp)
      >>< function
      | `Ok c -> return c
      | `Error (`IO (`Read_file_exn (path, ex))) ->
        Log.(s "I/O, writing " % s path % s " → " % exn ex @ verbose);
        fail (`Cannot_read_file ("localhost", path))
      | `Error (`System (`Sleep time, `Exn e)) ->
        Log.(s "Scp-cmd " % OCaml.list (sf "%S") scp_cmd
             % s " failed: System.sleep " % f time % s " error: " % exn e @ error);
        fail (`Cannot_read_file (ssh.Ketrew_host.Ssh.address,
                                 Path.(to_string path)))
      | `Error (`Process _ as process_error) ->
        let msg = Ketrew_unix_process.error_to_string process_error in
        Log.(s "Scp-cmd " % OCaml.list (sf "%S") scp_cmd
             % s " failed: " %s msg @ verbose);
        fail (`Cannot_read_file (ssh.Ketrew_host.Ssh.address, Path.(to_string path)))
      | `Error (`Timeout _ as t) -> fail t
    end