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
use std::env;
use std::ffi::{OsStr, OsString};
use std::fs::File;
use std::fs::OpenOptions;
use std::io::prelude::*;
use std::path::{Path, PathBuf, Component};

use util::{human, internal, CargoResult, ChainError};

pub fn join_paths<T: AsRef<OsStr>>(paths: &[T], env: &str) -> CargoResult<OsString> {
    env::join_paths(paths.iter()).or_else(|e| {
        let paths = paths.iter().map(Path::new).collect::<Vec<_>>();
        internal(format!("failed to join path array: {:?}", paths)).chain_error(|| {
            human(format!("failed to join search paths together: {}\n\
                           Does ${} have an unterminated quote character?",
                          e, env))
        })
    })
}

pub fn dylib_path_envvar() -> &'static str {
    if cfg!(windows) {"PATH"}
    else if cfg!(target_os = "macos") {"DYLD_LIBRARY_PATH"}
    else {"LD_LIBRARY_PATH"}
}

pub fn dylib_path() -> Vec<PathBuf> {
    match env::var_os(dylib_path_envvar()) {
        Some(var) => env::split_paths(&var).collect(),
        None => Vec::new(),
    }
}

pub fn normalize_path(path: &Path) -> PathBuf {
    let mut components = path.components().peekable();
    let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek()
                                                                     .cloned() {
        components.next();
        PathBuf::from(c.as_os_str())
    } else {
        PathBuf::new()
    };

    for component in components {
        match component {
            Component::Prefix(..) => unreachable!(),
            Component::RootDir => { ret.push(component.as_os_str()); }
            Component::CurDir => {}
            Component::ParentDir => { ret.pop(); }
            Component::Normal(c) => { ret.push(c); }
        }
    }
    ret
}

pub fn without_prefix<'a>(a: &'a Path, b: &'a Path) -> Option<&'a Path> {
    let mut a = a.components();
    let mut b = b.components();
    loop {
        match b.next() {
            Some(y) => match a.next() {
                Some(x) if x == y => continue,
                _ => return None,
            },
            None => return Some(a.as_path()),
        }
    }
}

pub fn read(path: &Path) -> CargoResult<String> {
    (|| -> CargoResult<_> {
        let mut ret = String::new();
        let mut f = try!(File::open(path));
        try!(f.read_to_string(&mut ret));
        Ok(ret)
    })().map_err(human).chain_error(|| {
        human(format!("failed to read `{}`", path.display()))
    })
}

pub fn read_bytes(path: &Path) -> CargoResult<Vec<u8>> {
    (|| -> CargoResult<_> {
        let mut ret = Vec::new();
        let mut f = try!(File::open(path));
        try!(f.read_to_end(&mut ret));
        Ok(ret)
    })().map_err(human).chain_error(|| {
        human(format!("failed to read `{}`", path.display()))
    })
}

pub fn write(path: &Path, contents: &[u8]) -> CargoResult<()> {
    (|| -> CargoResult<()> {
        let mut f = try!(File::create(path));
        try!(f.write_all(contents));
        Ok(())
    })().map_err(human).chain_error(|| {
        human(format!("failed to write `{}`", path.display()))
    })
}

pub fn append(path: &Path, contents: &[u8]) -> CargoResult<()> {
    (|| -> CargoResult<()> {
        let mut f = try!(OpenOptions::new()
                            .write(true)
                            .append(true)
                            .create(true)
                            .open(path));

        try!(f.write_all(contents));
        Ok(())
    }).chain_error(|| {
        internal(format!("failed to write `{}`", path.display()))
    })
}

#[cfg(unix)]
pub fn path2bytes(path: &Path) -> CargoResult<&[u8]> {
    use std::os::unix::prelude::*;
    Ok(path.as_os_str().as_bytes())
}
#[cfg(windows)]
pub fn path2bytes(path: &Path) -> CargoResult<&[u8]> {
    match path.as_os_str().to_str() {
        Some(s) => Ok(s.as_bytes()),
        None => Err(human(format!("invalid non-unicode path: {}",
                                  path.display())))
    }
}

#[cfg(unix)]
pub fn bytes2path(bytes: &[u8]) -> CargoResult<PathBuf> {
    use std::os::unix::prelude::*;
    use std::ffi::OsStr;
    Ok(PathBuf::from(OsStr::from_bytes(bytes)))
}
#[cfg(windows)]
pub fn bytes2path(bytes: &[u8]) -> CargoResult<PathBuf> {
    use std::str;
    match str::from_utf8(bytes) {
        Ok(s) => Ok(PathBuf::from(s)),
        Err(..) => Err(human("invalid non-unicode path")),
    }
}