files.rs
136 lines
| 3.7 KiB
| application/rls-services+xml
|
RustLexer
Raphaël Gomès
|
r42996 | // files.rs | ||
// | ||||
// Copyright 2019 | ||||
// Raphaël Gomès <rgomes@octobus.net>, | ||||
// Yuya Nishihara <yuya@tcha.org> | ||||
// | ||||
// This software may be used and distributed according to the terms of the | ||||
// GNU General Public License version 2 or any later version. | ||||
//! Functions for fiddling with files. | ||||
Raphaël Gomès
|
r43227 | use crate::utils::hg_path::{HgPath, HgPathBuf}; | ||
Yuya Nishihara
|
r42789 | use std::iter::FusedIterator; | ||
Raphaël Gomès
|
r43227 | |||
Raphaël Gomès
|
r43565 | use std::fs::Metadata; | ||
Raphaël Gomès
|
r42630 | use std::path::Path; | ||
pub fn get_path_from_bytes(bytes: &[u8]) -> &Path { | ||||
let os_str; | ||||
#[cfg(unix)] | ||||
{ | ||||
use std::os::unix::ffi::OsStrExt; | ||||
os_str = std::ffi::OsStr::from_bytes(bytes); | ||||
} | ||||
Raphaël Gomès
|
r43544 | // TODO Handle other platforms | ||
// TODO: convert from WTF8 to Windows MBCS (ANSI encoding). | ||||
// Perhaps, the return type would have to be Result<PathBuf>. | ||||
Raphaël Gomès
|
r42630 | |||
Path::new(os_str) | ||||
} | ||||
Yuya Nishihara
|
r42789 | |||
Yuya Nishihara
|
r44320 | // TODO: need to convert from WTF8 to MBCS bytes on Windows. | ||
// that's why Vec<u8> is returned. | ||||
#[cfg(unix)] | ||||
pub fn get_bytes_from_path(path: impl AsRef<Path>) -> Vec<u8> { | ||||
use std::os::unix::ffi::OsStrExt; | ||||
path.as_ref().as_os_str().as_bytes().to_vec() | ||||
} | ||||
Yuya Nishihara
|
r42789 | /// An iterator over repository path yielding itself and its ancestors. | ||
#[derive(Copy, Clone, Debug)] | ||||
pub struct Ancestors<'a> { | ||||
Raphaël Gomès
|
r43227 | next: Option<&'a HgPath>, | ||
Yuya Nishihara
|
r42789 | } | ||
impl<'a> Iterator for Ancestors<'a> { | ||||
Raphaël Gomès
|
r43227 | type Item = &'a HgPath; | ||
Yuya Nishihara
|
r42789 | |||
fn next(&mut self) -> Option<Self::Item> { | ||||
let next = self.next; | ||||
self.next = match self.next { | ||||
Some(s) if s.is_empty() => None, | ||||
Some(s) => { | ||||
Raphaël Gomès
|
r43227 | let p = s.bytes().rposition(|c| *c == b'/').unwrap_or(0); | ||
Some(HgPath::new(&s.as_bytes()[..p])) | ||||
Yuya Nishihara
|
r42789 | } | ||
None => None, | ||||
}; | ||||
next | ||||
} | ||||
} | ||||
impl<'a> FusedIterator for Ancestors<'a> {} | ||||
/// Returns an iterator yielding ancestor directories of the given repository | ||||
/// path. | ||||
/// | ||||
/// The path is separated by '/', and must not start with '/'. | ||||
/// | ||||
/// The path itself isn't included unless it is b"" (meaning the root | ||||
/// directory.) | ||||
Raphaël Gomès
|
r43227 | pub fn find_dirs<'a>(path: &'a HgPath) -> Ancestors<'a> { | ||
Yuya Nishihara
|
r42789 | let mut dirs = Ancestors { next: Some(path) }; | ||
if !path.is_empty() { | ||||
dirs.next(); // skip itself | ||||
} | ||||
dirs | ||||
} | ||||
Raphaël Gomès
|
r43227 | /// TODO more than ASCII? | ||
pub fn normalize_case(path: &HgPath) -> HgPathBuf { | ||||
Raphaël Gomès
|
r43108 | #[cfg(windows)] // NTFS compares via upper() | ||
Raphaël Gomès
|
r43227 | return path.to_ascii_uppercase(); | ||
Raphaël Gomès
|
r43108 | #[cfg(unix)] | ||
Raphaël Gomès
|
r43227 | path.to_ascii_lowercase() | ||
Raphaël Gomès
|
r43108 | } | ||
Raphaël Gomès
|
r43565 | #[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)] | ||
pub struct HgMetadata { | ||||
pub st_dev: u64, | ||||
pub st_mode: u32, | ||||
pub st_nlink: u64, | ||||
pub st_size: u64, | ||||
pub st_mtime: i64, | ||||
pub st_ctime: i64, | ||||
} | ||||
// TODO support other plaforms | ||||
#[cfg(unix)] | ||||
impl HgMetadata { | ||||
pub fn from_metadata(metadata: Metadata) -> Self { | ||||
use std::os::unix::fs::MetadataExt; | ||||
Self { | ||||
st_dev: metadata.dev(), | ||||
st_mode: metadata.mode(), | ||||
st_nlink: metadata.nlink(), | ||||
st_size: metadata.size(), | ||||
st_mtime: metadata.mtime(), | ||||
st_ctime: metadata.ctime(), | ||||
} | ||||
} | ||||
} | ||||
Yuya Nishihara
|
r42789 | #[cfg(test)] | ||
mod tests { | ||||
Raphaël Gomès
|
r43227 | use super::*; | ||
Yuya Nishihara
|
r42789 | #[test] | ||
fn find_dirs_some() { | ||||
Raphaël Gomès
|
r43227 | let mut dirs = super::find_dirs(HgPath::new(b"foo/bar/baz")); | ||
assert_eq!(dirs.next(), Some(HgPath::new(b"foo/bar"))); | ||||
assert_eq!(dirs.next(), Some(HgPath::new(b"foo"))); | ||||
assert_eq!(dirs.next(), Some(HgPath::new(b""))); | ||||
Yuya Nishihara
|
r42789 | assert_eq!(dirs.next(), None); | ||
assert_eq!(dirs.next(), None); | ||||
} | ||||
#[test] | ||||
fn find_dirs_empty() { | ||||
Martin von Zweigbergk
|
r44032 | // looks weird, but mercurial.pathutil.finddirs(b"") yields b"" | ||
Raphaël Gomès
|
r43227 | let mut dirs = super::find_dirs(HgPath::new(b"")); | ||
assert_eq!(dirs.next(), Some(HgPath::new(b""))); | ||||
Yuya Nishihara
|
r42789 | assert_eq!(dirs.next(), None); | ||
assert_eq!(dirs.next(), None); | ||||
} | ||||
} | ||||