comparison rust/hg-core/src/utils/files.rs @ 42957:7a01778bc7b7

rust-hgpath: replace all paths and filenames with HgPath/HgPathBuf Differential Revision: https://phab.mercurial-scm.org/D6774
author Rapha?l Gom?s <rgomes@octobus.net>
date Sun, 01 Sep 2019 20:53:14 +0200
parents b1b984f9c01d
children 98d996a138de
comparison
equal deleted inserted replaced
42956:3fe40dd6355d 42957:7a01778bc7b7
7 // This software may be used and distributed according to the terms of the 7 // This software may be used and distributed according to the terms of the
8 // GNU General Public License version 2 or any later version. 8 // GNU General Public License version 2 or any later version.
9 9
10 //! Functions for fiddling with files. 10 //! Functions for fiddling with files.
11 11
12 use crate::utils::hg_path::{HgPath, HgPathBuf};
12 use std::iter::FusedIterator; 13 use std::iter::FusedIterator;
14
13 use std::path::Path; 15 use std::path::Path;
14 16
15 pub fn get_path_from_bytes(bytes: &[u8]) -> &Path { 17 pub fn get_path_from_bytes(bytes: &[u8]) -> &Path {
16 let os_str; 18 let os_str;
17 #[cfg(unix)] 19 #[cfg(unix)]
21 } 23 }
22 #[cfg(windows)] 24 #[cfg(windows)]
23 { 25 {
24 // TODO: convert from Windows MBCS (ANSI encoding) to WTF8. 26 // TODO: convert from Windows MBCS (ANSI encoding) to WTF8.
25 // Perhaps, the return type would have to be Result<PathBuf>. 27 // Perhaps, the return type would have to be Result<PathBuf>.
26 use std::os::windows::ffi::OsStrExt; 28 unimplemented!()
27 os_str = std::ffi::OsString::from_wide(bytes);
28 } 29 }
29 30
30 Path::new(os_str) 31 Path::new(os_str)
31 } 32 }
32 33
33 /// An iterator over repository path yielding itself and its ancestors. 34 /// An iterator over repository path yielding itself and its ancestors.
34 #[derive(Copy, Clone, Debug)] 35 #[derive(Copy, Clone, Debug)]
35 pub struct Ancestors<'a> { 36 pub struct Ancestors<'a> {
36 next: Option<&'a [u8]>, 37 next: Option<&'a HgPath>,
37 } 38 }
38 39
39 impl<'a> Iterator for Ancestors<'a> { 40 impl<'a> Iterator for Ancestors<'a> {
40 // if we had an HgPath type, this would yield &'a HgPath 41 type Item = &'a HgPath;
41 type Item = &'a [u8];
42 42
43 fn next(&mut self) -> Option<Self::Item> { 43 fn next(&mut self) -> Option<Self::Item> {
44 let next = self.next; 44 let next = self.next;
45 self.next = match self.next { 45 self.next = match self.next {
46 Some(s) if s.is_empty() => None, 46 Some(s) if s.is_empty() => None,
47 Some(s) => { 47 Some(s) => {
48 let p = s.iter().rposition(|&c| c == b'/').unwrap_or(0); 48 let p = s.bytes().rposition(|c| *c == b'/').unwrap_or(0);
49 Some(&s[..p]) 49 Some(HgPath::new(&s.as_bytes()[..p]))
50 } 50 }
51 None => None, 51 None => None,
52 }; 52 };
53 next 53 next
54 } 54 }
61 /// 61 ///
62 /// The path is separated by '/', and must not start with '/'. 62 /// The path is separated by '/', and must not start with '/'.
63 /// 63 ///
64 /// The path itself isn't included unless it is b"" (meaning the root 64 /// The path itself isn't included unless it is b"" (meaning the root
65 /// directory.) 65 /// directory.)
66 pub fn find_dirs<'a>(path: &'a [u8]) -> Ancestors<'a> { 66 pub fn find_dirs<'a>(path: &'a HgPath) -> Ancestors<'a> {
67 let mut dirs = Ancestors { next: Some(path) }; 67 let mut dirs = Ancestors { next: Some(path) };
68 if !path.is_empty() { 68 if !path.is_empty() {
69 dirs.next(); // skip itself 69 dirs.next(); // skip itself
70 } 70 }
71 dirs 71 dirs
72 } 72 }
73 73
74 /// TODO improve handling of utf8 file names. Our overall strategy for 74 /// TODO more than ASCII?
75 /// filenames has to be revisited anyway, since Windows is UTF-16. 75 pub fn normalize_case(path: &HgPath) -> HgPathBuf {
76 pub fn normalize_case(bytes: &[u8]) -> Vec<u8> {
77 #[cfg(windows)] // NTFS compares via upper() 76 #[cfg(windows)] // NTFS compares via upper()
78 return bytes.to_ascii_uppercase(); 77 return path.to_ascii_uppercase();
79 #[cfg(unix)] 78 #[cfg(unix)]
80 bytes.to_ascii_lowercase() 79 path.to_ascii_lowercase()
81 } 80 }
82 81
83 #[cfg(test)] 82 #[cfg(test)]
84 mod tests { 83 mod tests {
84 use super::*;
85
85 #[test] 86 #[test]
86 fn find_dirs_some() { 87 fn find_dirs_some() {
87 let mut dirs = super::find_dirs(b"foo/bar/baz"); 88 let mut dirs = super::find_dirs(HgPath::new(b"foo/bar/baz"));
88 assert_eq!(dirs.next(), Some(b"foo/bar".as_ref())); 89 assert_eq!(dirs.next(), Some(HgPath::new(b"foo/bar")));
89 assert_eq!(dirs.next(), Some(b"foo".as_ref())); 90 assert_eq!(dirs.next(), Some(HgPath::new(b"foo")));
90 assert_eq!(dirs.next(), Some(b"".as_ref())); 91 assert_eq!(dirs.next(), Some(HgPath::new(b"")));
91 assert_eq!(dirs.next(), None); 92 assert_eq!(dirs.next(), None);
92 assert_eq!(dirs.next(), None); 93 assert_eq!(dirs.next(), None);
93 } 94 }
94 95
95 #[test] 96 #[test]
96 fn find_dirs_empty() { 97 fn find_dirs_empty() {
97 // looks weird, but mercurial.util.finddirs(b"") yields b"" 98 // looks weird, but mercurial.util.finddirs(b"") yields b""
98 let mut dirs = super::find_dirs(b""); 99 let mut dirs = super::find_dirs(HgPath::new(b""));
99 assert_eq!(dirs.next(), Some(b"".as_ref())); 100 assert_eq!(dirs.next(), Some(HgPath::new(b"")));
100 assert_eq!(dirs.next(), None); 101 assert_eq!(dirs.next(), None);
101 assert_eq!(dirs.next(), None); 102 assert_eq!(dirs.next(), None);
102 } 103 }
103 } 104 }