Skip to content

Commit 09f1aab

Browse files
rami3lrhysd
andcommitted
fix(component): normalize path separators during ComponentPart::(en|de)code()
Co-authored-by: rhysd <[email protected]>
1 parent 967c12e commit 09f1aab

File tree

1 file changed

+44
-3
lines changed

1 file changed

+44
-3
lines changed

src/dist/component/components.rs

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//! `Components` and `DirectoryPackage` are the two sides of the
33
//! installation / uninstallation process.
44
5+
use std::borrow::Cow;
56
use std::io::BufWriter;
67
use std::path::{Path, PathBuf};
78

@@ -148,12 +149,28 @@ impl<'a> ComponentBuilder<'a> {
148149
pub struct ComponentPart(pub String, pub PathBuf);
149150

150151
impl ComponentPart {
152+
const PATH_SEP_MANIFEST: &str = "/";
153+
const PATH_SEP_MAIN: &str = std::path::MAIN_SEPARATOR_STR;
154+
151155
pub(crate) fn encode(&self) -> String {
152-
format!("{}:{}", &self.0, &self.1.to_string_lossy())
156+
// Lossy conversion is safe here because we assume that `path` comes from
157+
// `ComponentPart::decode()`, i.e. from calling `Path::from()` on a `&str`.
158+
let mut path = self.1.to_string_lossy();
159+
if Self::PATH_SEP_MAIN != Self::PATH_SEP_MANIFEST {
160+
path = Cow::Owned(path.replace(Self::PATH_SEP_MAIN, Self::PATH_SEP_MANIFEST));
161+
};
162+
format!("{}:{path}", self.0)
153163
}
164+
154165
pub(crate) fn decode(line: &str) -> Option<Self> {
155-
line.find(':')
156-
.map(|pos| Self(line[0..pos].to_owned(), PathBuf::from(&line[(pos + 1)..])))
166+
line.find(':').map(|pos| {
167+
let mut path_str = Cow::Borrowed(&line[(pos + 1)..]);
168+
if Self::PATH_SEP_MANIFEST != Self::PATH_SEP_MAIN {
169+
path_str =
170+
Cow::Owned(path_str.replace(Self::PATH_SEP_MANIFEST, Self::PATH_SEP_MAIN));
171+
};
172+
Self(line[0..pos].to_owned(), PathBuf::from(path_str.as_ref()))
173+
})
157174
}
158175
}
159176

@@ -322,3 +339,27 @@ impl Component {
322339
Ok(tx)
323340
}
324341
}
342+
343+
#[cfg(test)]
344+
mod tests {
345+
use super::*;
346+
347+
#[test]
348+
fn decode_component_part() {
349+
let ComponentPart(kind, path) = ComponentPart::decode("dir:share/doc/rust/html").unwrap();
350+
assert_eq!(kind, "dir");
351+
assert_eq!(
352+
path,
353+
Path::new(&"share/doc/rust/html".replace("/", ComponentPart::PATH_SEP_MAIN))
354+
);
355+
}
356+
357+
#[test]
358+
fn encode_component_part() {
359+
let part = ComponentPart(
360+
"dir".to_owned(),
361+
["share", "doc", "rust", "html"].into_iter().collect(),
362+
);
363+
assert_eq!(part.encode(), "dir:share/doc/rust/html");
364+
}
365+
}

0 commit comments

Comments
 (0)