comparison rust/hg-core/src/utils/files.rs @ 45436:1b3197047f5c

rhg: make output of `files` relative to the current directory and the root This matches the behavior of `hg files`. The util is added in `hg-core` instead of `rhg` because this operation could be useful for other external tools. (this was definitely not prompted by rust issue #50784, I swear) Differential Revision: https://phab.mercurial-scm.org/D8872
author Rapha?l Gom?s <rgomes@octobus.net>
date Thu, 30 Jul 2020 16:55:44 +0200
parents 26114bd6ec60
children 95d6f31e88db
comparison
equal deleted inserted replaced
45435:64de86fd0984 45436:1b3197047f5c
14 path_auditor::PathAuditor, 14 path_auditor::PathAuditor,
15 replace_slice, 15 replace_slice,
16 }; 16 };
17 use lazy_static::lazy_static; 17 use lazy_static::lazy_static;
18 use same_file::is_same_file; 18 use same_file::is_same_file;
19 use std::borrow::ToOwned; 19 use std::borrow::{Cow, ToOwned};
20 use std::fs::Metadata; 20 use std::fs::Metadata;
21 use std::iter::FusedIterator; 21 use std::iter::FusedIterator;
22 use std::ops::Deref; 22 use std::ops::Deref;
23 use std::path::{Path, PathBuf}; 23 use std::path::{Path, PathBuf};
24 24
246 root: root.to_owned(), 246 root: root.to_owned(),
247 }) 247 })
248 } 248 }
249 } 249 }
250 250
251 /// Returns the representation of the path relative to the current working
252 /// directory for display purposes.
253 ///
254 /// `cwd` is a `HgPath`, so it is considered relative to the root directory
255 /// of the repository.
256 ///
257 /// # Examples
258 ///
259 /// ```
260 /// use hg::utils::hg_path::HgPath;
261 /// use hg::utils::files::relativize_path;
262 /// use std::borrow::Cow;
263 ///
264 /// let file = HgPath::new(b"nested/file");
265 /// let cwd = HgPath::new(b"");
266 /// assert_eq!(relativize_path(file, cwd), Cow::Borrowed(b"nested/file"));
267 ///
268 /// let cwd = HgPath::new(b"nested");
269 /// assert_eq!(relativize_path(file, cwd), Cow::Borrowed(b"file"));
270 ///
271 /// let cwd = HgPath::new(b"other");
272 /// assert_eq!(relativize_path(file, cwd), Cow::Borrowed(b"../nested/file"));
273 /// ```
274 pub fn relativize_path(path: &HgPath, cwd: impl AsRef<HgPath>) -> Cow<[u8]> {
275 if cwd.as_ref().is_empty() {
276 Cow::Borrowed(path.as_bytes())
277 } else {
278 let mut res: Vec<u8> = Vec::new();
279 let mut path_iter = path.as_bytes().split(|b| *b == b'/').peekable();
280 let mut cwd_iter =
281 cwd.as_ref().as_bytes().split(|b| *b == b'/').peekable();
282 loop {
283 match (path_iter.peek(), cwd_iter.peek()) {
284 (Some(a), Some(b)) if a == b => (),
285 _ => break,
286 }
287 path_iter.next();
288 cwd_iter.next();
289 }
290 let mut need_sep = false;
291 for _ in cwd_iter {
292 if need_sep {
293 res.extend(b"/")
294 } else {
295 need_sep = true
296 };
297 res.extend(b"..");
298 }
299 for c in path_iter {
300 if need_sep {
301 res.extend(b"/")
302 } else {
303 need_sep = true
304 };
305 res.extend(c);
306 }
307 Cow::Owned(res)
308 }
309 }
310
251 #[cfg(test)] 311 #[cfg(test)]
252 mod tests { 312 mod tests {
253 use super::*; 313 use super::*;
254 use pretty_assertions::assert_eq; 314 use pretty_assertions::assert_eq;
255 315