fm/modes/menu/
remote.rs

1use std::process::Command;
2
3use crate::common::{is_in_path, tilde, SSHFS_EXECUTABLE};
4use crate::io::{command_with_path, execute_and_capture_output_with_path};
5use crate::{log_info, log_line};
6
7/// Used to remember the setting of this remote.
8/// it's used to mount the remote in the current directory using sshfs.
9pub struct Remote {
10    pub username: String,
11    pub hostname: String,
12    pub remote_path: String,
13    pub local_path: String,
14    pub current_path: String,
15    pub port: String,
16}
17
18impl Remote {
19    /// Converts an input like "username hostname:33 /remote/path /local/path" into
20    /// a separated list of arguments for sshfs.
21    /// Returns `None` if the input string can't be parsed correctly.
22    /// Returns also `None` if "sshfs" isn't in the current `$PATH`.
23    pub fn from_input(input: String, current_path: &str) -> Option<Self> {
24        if !is_in_path(SSHFS_EXECUTABLE) {
25            log_info!("{SSHFS_EXECUTABLE} isn't in path");
26            return None;
27        }
28
29        Self::parse_remote_args(input, current_path)
30    }
31
32    fn parse_remote_args(input: String, current_path: &str) -> Option<Self> {
33        let user_host_port_remotepath_localpath: Vec<&str> = input.trim().split(' ').collect();
34        let number_of_args = user_host_port_remotepath_localpath.len();
35        if number_of_args != 3 && number_of_args != 4 {
36            log_info!(
37                "Wrong number of parameters for {SSHFS_EXECUTABLE}, expected 3 or 4, got {number_of_args}",
38            );
39            return None;
40        };
41
42        let (username, host_port, remote_path) = (
43            user_host_port_remotepath_localpath[0],
44            user_host_port_remotepath_localpath[1],
45            user_host_port_remotepath_localpath[2],
46        );
47
48        let host_port_splitted: Vec<&str> = host_port.trim().split(':').collect();
49        let hostname = host_port_splitted[0];
50        let port = if host_port_splitted.len() == 1 {
51            "22"
52        } else {
53            host_port_splitted[1]
54        };
55
56        let local_path = if number_of_args == 3 {
57            current_path
58        } else {
59            &tilde(user_host_port_remotepath_localpath[3])
60        };
61        Some(Self {
62            username: username.to_owned(),
63            hostname: hostname.to_owned(),
64            remote_path: remote_path.to_owned(),
65            current_path: current_path.to_owned(),
66            local_path: local_path.to_owned(),
67            port: port.to_owned(),
68        })
69    }
70
71    /// Returns a demonstration command with current path & args to be executed.
72    /// The command is only used for display and is never executed.
73    pub fn command(&self) -> Command {
74        let first_arg = format!(
75            "{username}@{hostname}:{remote_path}",
76            username = self.username,
77            hostname = self.hostname,
78            remote_path = self.remote_path
79        );
80        command_with_path(
81            SSHFS_EXECUTABLE,
82            &self.current_path,
83            &[&first_arg, &self.local_path, "-p", &self.port],
84        )
85    }
86
87    /// Run sshfs with typed parameters to mount a remote directory in current directory.
88    /// sshfs should be reachable in path.
89    /// The user must type 3 arguments like this : `username hostname remote_path`.
90    /// If the user doesn't provide 3 arguments,
91    pub fn mount(&self) {
92        let first_arg = format!(
93            "{username}@{hostname}:{remote_path}",
94            username = self.username,
95            hostname = self.hostname,
96            remote_path = self.remote_path
97        );
98        let output = execute_and_capture_output_with_path(
99            SSHFS_EXECUTABLE,
100            &self.current_path,
101            &[&first_arg, &self.local_path, "-p", &self.port],
102        );
103        log_info!("{SSHFS_EXECUTABLE} {first_arg} output {output:?}");
104        log_line!("{SSHFS_EXECUTABLE} {first_arg} output {output:?}");
105    }
106}