1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//! UI-layer location handling
use pyo3::prelude::*;
use url::Url;
/// Convert a CVS root string to a URL.
///
/// # Arguments
///
/// * `cvsroot` - The CVS root string to convert
///
/// # Returns
///
/// A URL representing the CVS repository location
pub fn cvs_to_url(cvsroot: &str) -> Url {
Python::attach(|py| {
let breezy_location = py.import("breezy.location").unwrap();
breezy_location
.call_method1("cvs_to_url", (cvsroot,))
.unwrap()
.extract::<String>()
.unwrap()
.parse()
.unwrap()
})
}
#[test]
fn test_cvs_to_url() {
assert_eq!(
cvs_to_url(":pserver:anonymous@localhost:/var/lib/cvs"),
Url::parse("cvs+pserver://anonymous@localhost/var/lib/cvs").unwrap()
);
}
/// Convert an RCP (remote copy) location string to a URL.
///
/// RCP locations are in the format "user@host:/path/to/repo" and are converted
/// to URLs like "ssh://user@host/path/to/repo".
///
/// # Arguments
///
/// * `rcp_location` - The RCP location string to convert
///
/// # Returns
///
/// A Result containing the converted URL or an error string
pub fn rcp_location_to_url(rcp_location: &str) -> Result<Url, String> {
Python::attach(|py| {
let breezy_location = py.import("breezy.location").unwrap();
Ok(breezy_location
.call_method1("rcp_location_to_url", (rcp_location,))
.map_err(|e| e.to_string())?
.extract::<String>()
.unwrap()
.parse()
.unwrap())
})
}
#[test]
fn test_rcp_location_to_url() {
assert_eq!(
rcp_location_to_url("user@host:/path/to/repo").unwrap(),
Url::parse("ssh://user@host/path/to/repo").unwrap()
);
}
/// Trait for types that can be converted to a location that Breezy understands.
///
/// This trait is implemented by types that can be converted to a string
/// representation that can be used as a location in Breezy API calls.
pub trait AsLocation {
/// Convert the object to a Python object representing a location.
///
/// # Returns
///
/// A Python object (string) representing the location
fn as_location(&self) -> Py<PyAny>;
}
impl AsLocation for &url::Url {
fn as_location(&self) -> Py<PyAny> {
Python::attach(|py| {
pyo3::types::PyString::new(py, self.as_ref())
.unbind()
.into()
})
}
}
#[test]
fn test_as_location_url() {
Python::attach(|py| {
assert_eq!(
Url::parse("ssh://user@host/path/to/repo")
.unwrap()
.as_ref()
.as_location()
.extract::<String>(py)
.unwrap(),
"ssh://user@host/path/to/repo"
);
});
}
impl AsLocation for &str {
fn as_location(&self) -> Py<PyAny> {
Python::attach(|py| pyo3::types::PyString::new(py, self).unbind().into())
}
}
#[test]
fn test_as_location_str() {
Python::attach(|py| {
assert_eq!(
"ssh://user@host/path/to/repo"
.as_location()
.extract::<String>(py)
.unwrap(),
"ssh://user@host/path/to/repo"
);
});
}
impl AsLocation for &std::path::Path {
fn as_location(&self) -> Py<PyAny> {
Python::attach(|py| {
pyo3::types::PyString::new(py, self.to_str().unwrap())
.unbind()
.into()
})
}
}
#[test]
fn test_as_location_path() {
Python::attach(|py| {
assert_eq!(
std::path::Path::new("/path/to/repo")
.as_location()
.extract::<String>(py)
.unwrap(),
"/path/to/repo"
);
});
}