rhq_core/
query.rs

1use std::str::FromStr;
2use url::Url;
3use scp::ScpPath;
4
5
6/// Represents query from user.
7///
8/// Available patterns are:
9///
10/// * `<scheme>://[<username>[:<password>]@]<host>/<path-to-repo>.git`
11///   - Available schemes are: `http[s]`, `ssh` and `git`.
12/// * `<username>@<host>:<path-to-repo>`
13///   - Equivalent to `ssh://<username>@<host>/<path-to-repo>.git`
14/// * `<path-to-repo>`
15pub enum Query {
16    Url(Url),
17    Scp(ScpPath),
18    Path(String),
19}
20
21impl Query {
22    /// Returns the host name if available.
23    pub fn host(&self) -> Option<&str> {
24        match *self {
25            Query::Url(ref url) => url.host_str(),
26            Query::Scp(ref scp) => Some(scp.host()),
27            Query::Path(_) => None,
28        }
29    }
30
31    pub fn path(&self) -> &str {
32        match *self {
33            Query::Url(ref url) => url.path().trim_left_matches("/").trim_right_matches(".git"),
34            Query::Scp(ref scp) => scp.path(),
35            Query::Path(ref path) => path,
36        }
37    }
38}
39
40impl FromStr for Query {
41    type Err = ::Error;
42
43    fn from_str(s: &str) -> ::Result<Query> {
44        if let Ok(url) = Url::parse(s) {
45            match url.scheme() {
46                "http" | "https" | "ssh" | "git" => {}
47                scheme => return Err(format!("'{}' is invalid scheme", scheme).into()),
48            }
49            Ok(Query::Url(url))
50        } else if let Ok(scp) = ScpPath::from_str(s) {
51            Ok(Query::Scp(scp))
52        } else {
53            if s.starts_with("./") || s.starts_with("../") || s.starts_with(".\\") || s.starts_with("..\\") {
54                Err("The path must be not a relative path.")?;
55            }
56            Ok(Query::Path(s.to_owned()))
57        }
58    }
59}
60
61
62#[cfg(test)]
63mod tests_query {
64    use super::Query;
65
66    #[test]
67    fn https_url() {
68        let s = "https://github.com/peco/peco.git";
69
70        if let Ok(Query::Url(url)) = s.parse() {
71            assert_eq!(url.scheme(), "https");
72            assert_eq!(url.username(), "");
73            assert_eq!(url.password(), None);
74            assert_eq!(url.host_str(), Some("github.com"));
75            assert_eq!(url.path(), "/peco/peco.git");
76        } else {
77            panic!("does not matches");
78        }
79    }
80
81    #[test]
82    fn ssh_url() {
83        let s = "ssh://gituser@github.com:2222/peco/peco.git";
84
85        if let Ok(Query::Url(url)) = s.parse() {
86            assert_eq!(url.scheme(), "ssh");
87            assert_eq!(url.username(), "gituser");
88            assert_eq!(url.password(), None);
89            assert_eq!(url.host_str(), Some("github.com"));
90            assert_eq!(url.port(), Some(2222));
91            assert_eq!(url.path(), "/peco/peco.git");
92        } else {
93            panic!("does not matches");
94        }
95    }
96
97    #[test]
98    fn scp_pattern() {
99        let ss = &["git@github.com:peco/peco.git", "git@github.com:peco/peco"];
100        for s in ss {
101            if let Ok(Query::Scp(scp)) = s.parse() {
102                assert_eq!(scp.username(), "git");
103                assert_eq!(scp.host(), "github.com");
104                assert_eq!(scp.path(), "peco/peco");
105            } else {
106                panic!("does not matches");
107            }
108        }
109    }
110
111    #[test]
112    fn short_pattern_with_host() {
113        let s = "github.com/peco/peco";
114
115        if let Ok(Query::Path(path)) = s.parse() {
116            assert_eq!(path, "github.com/peco/peco");
117        } else {
118            panic!("does not matches")
119        }
120    }
121
122    #[test]
123    fn short_pattern_without_host() {
124        let s = "peco/peco";
125
126        if let Ok(Query::Path(path)) = s.parse() {
127            assert_eq!(path, "peco/peco");
128        } else {
129            panic!("does not matches")
130        }
131    }
132}
133
134
135#[cfg(test)]
136mod test_methods {
137    use super::Query;
138
139    #[test]
140    fn case_url() {
141        let url = "https://github.com/ubnt-intrepid/dot.git";
142        let query: Query = url.parse().unwrap();
143
144        assert_eq!(query.host(), Some("github.com"));
145        assert_eq!(query.path(), "ubnt-intrepid/dot");
146    }
147
148    #[test]
149    fn case_scp() {
150        let s = "git@github.com:ubnt-intrepid/dot.git";
151        let query: Query = s.parse().unwrap();
152
153        assert_eq!(query.host(), Some("github.com"));
154        assert_eq!(query.path(), "ubnt-intrepid/dot");
155    }
156
157    #[test]
158    fn case_relative() {
159        let s = "ubnt-intrepid/dot";
160        let query: Query = s.parse().unwrap();
161
162        assert_eq!(query.host(), None);
163        assert_eq!(query.path(), "ubnt-intrepid/dot");
164    }
165}