1use super::ScpPath;
2use anyhow::{anyhow, Result};
3use regex::Regex;
4use std::str::FromStr;
5use url::Url;
6
7impl ScpPath {
8 pub fn parse(s: &str) -> Result<Self> {
9 s.parse()
10 }
11}
12
13impl FromStr for ScpPath {
14 type Err = anyhow::Error;
15
16 fn from_str(s: &str) -> Result<Self> {
17 let regex = Regex::new(r"^((?:[^@]+@)?)([^:]+):/?(.+)$")?;
19
20 let captures = regex
21 .captures(s)
22 .ok_or_else(|| anyhow!("url: {} does not match scp regex", s))?;
23
24 let username = captures
25 .get(1)
26 .map(|s| s.as_str())
27 .map(|s| s.trim_end_matches('@'))
28 .unwrap_or("git")
29 .to_owned();
30
31 let host = captures.get(2).unwrap().as_str().to_owned();
32 let path = captures
33 .get(3)
34 .unwrap()
35 .as_str()
36 .trim_end_matches(".git")
37 .to_owned();
38
39 Ok(Self {
40 host,
41 username,
42 path,
43 })
44 }
45}
46
47impl ScpPath {
48 pub fn to_url(&self) -> Url {
49 let str = format!("ssh://{}@{}/{}", self.username, self.host, self.path);
50 Url::parse(&str).unwrap()
51 }
52}
53
54#[allow(clippy::from_over_into)]
55impl Into<Url> for ScpPath {
56 fn into(self) -> Url {
57 self.to_url()
58 }
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64
65 #[test]
66 fn git_ssh() {
67 let scp = ScpPath::from_str("git@github.com:edeneast/repo").unwrap();
68
69 assert_eq!(scp.username, "git");
70 assert_eq!(scp.host, "github.com");
71 assert_eq!(scp.path, "edeneast/repo");
72 }
73
74 #[test]
75 fn to_url() {
76 let scp = ScpPath::from_str("git@github.com:edeneast/repo").unwrap();
77 let url = scp.to_url();
78
79 assert_eq!(url.as_str(), "ssh://git@github.com/edeneast/repo");
80 }
81}