rust/hg-core/src/utils/path.rs
author Gregory Szorc <gregory.szorc@gmail.com>
Sat, 07 Dec 2019 10:26:28 -0800
changeset 44067 6a1729ed223d
child 44068 4b953cb17612
permissions -rw-r--r--
hg-core: vendor Facebook's path utils module The added file was imported from https://github.com/facebookexperimental/eden/blob/d1d8fb939a39aa331ae7f162c39cbcaa511d474b/eden/scm/lib/util/src/path.rs without modifications. The file is not yet integrated into our project. This will be done in subsequent commits. Differential Revision: https://phab.mercurial-scm.org/D7573
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
44067
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     1
/*
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     2
 * Copyright (c) Facebook, Inc. and its affiliates.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     3
 *
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     4
 * This software may be used and distributed according to the terms of the
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     5
 * GNU General Public License version 2.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     6
 */
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     7
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     8
//! Path-related utilities.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
     9
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    10
use std::env;
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    11
#[cfg(not(unix))]
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    12
use std::fs::rename;
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    13
use std::fs::{self, remove_file as fs_remove_file};
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    14
use std::io::{self, ErrorKind};
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    15
use std::path::{Component, Path, PathBuf};
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    16
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    17
use anyhow::Result;
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    18
#[cfg(not(unix))]
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    19
use tempfile::Builder;
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    20
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    21
/// Normalize a canonicalized Path for display.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    22
///
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    23
/// This removes the UNC prefix `\\?\` on Windows.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    24
pub fn normalize_for_display(path: &str) -> &str {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    25
    if cfg!(windows) && path.starts_with(r"\\?\") {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    26
        &path[4..]
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    27
    } else {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    28
        path
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    29
    }
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    30
}
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    31
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    32
/// Similar to [`normalize_for_display`]. But work on bytes.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    33
pub fn normalize_for_display_bytes(path: &[u8]) -> &[u8] {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    34
    if cfg!(windows) && path.starts_with(br"\\?\") {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    35
        &path[4..]
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    36
    } else {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    37
        path
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    38
    }
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    39
}
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    40
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    41
/// Return the absolute and normalized path without accessing the filesystem.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    42
///
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    43
/// Unlike [`fs::canonicalize`], do not follow symlinks.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    44
///
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    45
/// This function does not access the filesystem. Therefore it can behave
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    46
/// differently from the kernel or other library functions in corner cases.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    47
/// For example:
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    48
///
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    49
/// - On some systems with symlink support, `foo/bar/..` and `foo` can be
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    50
///   different as seen by the kernel, if `foo/bar` is a symlink. This
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    51
///   function always returns `foo` in this case.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    52
/// - On Windows, the official normalization rules are much more complicated.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    53
///   See https://github.com/rust-lang/rust/pull/47363#issuecomment-357069527.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    54
///   For example, this function cannot translate "drive relative" path like
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    55
///   "X:foo" to an absolute path.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    56
///
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    57
/// Return an error if `std::env::current_dir()` fails or if this function
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    58
/// fails to produce an absolute path.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    59
pub fn absolute(path: impl AsRef<Path>) -> io::Result<PathBuf> {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    60
    let path = path.as_ref();
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    61
    let path = if path.is_absolute() {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    62
        path.to_path_buf()
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    63
    } else {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    64
        std::env::current_dir()?.join(path)
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    65
    };
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    66
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    67
    if !path.is_absolute() {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    68
        return Err(io::Error::new(
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    69
            io::ErrorKind::Other,
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    70
            format!("cannot get absoltue path from {:?}", path),
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    71
        ));
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    72
    }
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    73
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    74
    let mut result = PathBuf::new();
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    75
    for component in path.components() {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    76
        match component {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    77
            Component::Normal(_) | Component::RootDir | Component::Prefix(_) => {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    78
                result.push(component);
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    79
            }
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    80
            Component::ParentDir => {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    81
                result.pop();
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    82
            }
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    83
            Component::CurDir => (),
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    84
        }
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    85
    }
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    86
    Ok(result)
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    87
}
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    88
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    89
/// Remove the file pointed by `path`.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    90
#[cfg(unix)]
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    91
pub fn remove_file<P: AsRef<Path>>(path: P) -> Result<()> {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    92
    fs_remove_file(path)?;
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    93
    Ok(())
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    94
}
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    95
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    96
/// Remove the file pointed by `path`.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    97
///
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    98
/// On Windows, removing a file can fail for various reasons, including if the file is memory
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
    99
/// mapped. This can happen when the repository is accessed concurrently while a background task is
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   100
/// trying to remove a packfile. To solve this, we can rename the file before trying to remove it.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   101
/// If the remove operation fails, a future repack will clean it up.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   102
#[cfg(not(unix))]
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   103
pub fn remove_file<P: AsRef<Path>>(path: P) -> Result<()> {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   104
    let path = path.as_ref();
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   105
    let extension = path
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   106
        .extension()
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   107
        .and_then(|ext| ext.to_str())
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   108
        .map_or(".to-delete".to_owned(), |ext| ".".to_owned() + ext + "-tmp");
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   109
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   110
    let dest_path = Builder::new()
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   111
        .prefix("")
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   112
        .suffix(&extension)
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   113
        .rand_bytes(8)
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   114
        .tempfile_in(path.parent().unwrap())?
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   115
        .into_temp_path();
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   116
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   117
    rename(path, &dest_path)?;
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   118
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   119
    // Ignore errors when removing the file, it will be cleaned up at a later time.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   120
    let _ = fs_remove_file(dest_path);
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   121
    Ok(())
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   122
}
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   123
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   124
/// Create the directory and ignore failures when a directory of the same name already exists.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   125
pub fn create_dir(path: impl AsRef<Path>) -> io::Result<()> {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   126
    match fs::create_dir(path.as_ref()) {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   127
        Ok(()) => Ok(()),
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   128
        Err(e) => {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   129
            if e.kind() == ErrorKind::AlreadyExists && path.as_ref().is_dir() {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   130
                Ok(())
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   131
            } else {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   132
                Err(e)
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   133
            }
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   134
        }
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   135
    }
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   136
}
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   137
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   138
/// Expand the user's home directory and any environment variables references in
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   139
/// the given path.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   140
///
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   141
/// This function is designed to emulate the behavior of Mercurial's `util.expandpath`
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   142
/// function, which in turn uses Python's `os.path.expand{user,vars}` functions. This
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   143
/// results in behavior that is notably different from the default expansion behavior
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   144
/// of the `shellexpand` crate. In particular:
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   145
///
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   146
/// - If a reference to an environment variable is missing or invalid, the reference
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   147
///   is left unchanged in the resulting path rather than emitting an error.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   148
///
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   149
/// - Home directory expansion explicitly happens after environment variable
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   150
///   expansion, meaning that if an environment variable is expanded into a
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   151
///   string starting with a tilde (`~`), the tilde will be expanded into the
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   152
///   user's home directory.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   153
///
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   154
pub fn expand_path(path: impl AsRef<str>) -> PathBuf {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   155
    expand_path_impl(path.as_ref(), |k| env::var(k).ok(), dirs::home_dir)
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   156
}
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   157
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   158
/// Same as `expand_path` but explicitly takes closures for environment variable
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   159
/// and home directory lookup for the sake of testability.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   160
fn expand_path_impl<E, H>(path: &str, getenv: E, homedir: H) -> PathBuf
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   161
where
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   162
    E: FnMut(&str) -> Option<String>,
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   163
    H: FnOnce() -> Option<PathBuf>,
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   164
{
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   165
    // The shellexpand crate does not expand Windows environment variables
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   166
    // like `%PROGRAMDATA%`. We'd like to expand them too. So let's do some
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   167
    // pre-processing.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   168
    //
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   169
    // XXX: Doing this preprocessing has the unfortunate side-effect that
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   170
    // if an environment variable fails to expand on Windows, the resulting
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   171
    // string will contain a UNIX-style environment variable reference.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   172
    //
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   173
    // e.g., "/foo/%MISSING%/bar" will expand to "/foo/${MISSING}/bar"
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   174
    //
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   175
    // The current approach is good enough for now, but likely needs to
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   176
    // be improved later for correctness.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   177
    let path = {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   178
        let mut new_path = String::new();
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   179
        let mut is_starting = true;
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   180
        for ch in path.chars() {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   181
            if ch == '%' {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   182
                if is_starting {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   183
                    new_path.push_str("${");
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   184
                } else {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   185
                    new_path.push('}');
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   186
                }
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   187
                is_starting = !is_starting;
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   188
            } else if cfg!(windows) && ch == '/' {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   189
                // Only on Windows, change "/" to "\" automatically.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   190
                // This makes sure "%include /foo" works as expected.
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   191
                new_path.push('\\')
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   192
            } else {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   193
                new_path.push(ch);
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   194
            }
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   195
        }
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   196
        new_path
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   197
    };
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   198
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   199
    let path = shellexpand::env_with_context_no_errors(&path, getenv);
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   200
    shellexpand::tilde_with_context(&path, homedir)
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   201
        .as_ref()
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   202
        .into()
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   203
}
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   204
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   205
#[cfg(test)]
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   206
mod tests {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   207
    use super::*;
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   208
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   209
    use std::fs::File;
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   210
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   211
    use tempfile::TempDir;
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   212
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   213
    #[cfg(windows)]
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   214
    mod windows {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   215
        use super::*;
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   216
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   217
        #[test]
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   218
        fn test_absolute_fullpath() {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   219
            assert_eq!(absolute("C:/foo").unwrap(), Path::new("C:\\foo"));
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   220
            assert_eq!(
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   221
                absolute("x:\\a/b\\./.\\c").unwrap(),
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   222
                Path::new("x:\\a\\b\\c")
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   223
            );
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   224
            assert_eq!(
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   225
                absolute("y:/a/b\\../..\\c\\../d\\./.").unwrap(),
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   226
                Path::new("y:\\d")
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   227
            );
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   228
            assert_eq!(
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   229
                absolute("z:/a/b\\../..\\../..\\..").unwrap(),
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   230
                Path::new("z:\\")
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   231
            );
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   232
        }
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   233
    }
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   234
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   235
    #[cfg(unix)]
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   236
    mod unix {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   237
        use super::*;
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   238
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   239
        #[test]
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   240
        fn test_absolute_fullpath() {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   241
            assert_eq!(absolute("/a/./b\\c/../d/.").unwrap(), Path::new("/a/d"));
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   242
            assert_eq!(absolute("/a/../../../../b").unwrap(), Path::new("/b"));
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   243
            assert_eq!(absolute("/../../..").unwrap(), Path::new("/"));
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   244
            assert_eq!(absolute("/../../../").unwrap(), Path::new("/"));
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   245
            assert_eq!(
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   246
                absolute("//foo///bar//baz").unwrap(),
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   247
                Path::new("/foo/bar/baz")
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   248
            );
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   249
            assert_eq!(absolute("//").unwrap(), Path::new("/"));
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   250
        }
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   251
    }
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   252
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   253
    #[test]
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   254
    fn test_create_dir_non_exist() -> Result<()> {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   255
        let tempdir = TempDir::new()?;
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   256
        let mut path = tempdir.path().to_path_buf();
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   257
        path.push("dir");
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   258
        create_dir(&path)?;
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   259
        assert!(path.is_dir());
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   260
        Ok(())
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   261
    }
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   262
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   263
    #[test]
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   264
    fn test_create_dir_exist() -> Result<()> {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   265
        let tempdir = TempDir::new()?;
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   266
        let mut path = tempdir.path().to_path_buf();
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   267
        path.push("dir");
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   268
        create_dir(&path)?;
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   269
        assert!(&path.is_dir());
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   270
        create_dir(&path)?;
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   271
        assert!(&path.is_dir());
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   272
        Ok(())
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   273
    }
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   274
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   275
    #[test]
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   276
    fn test_create_dir_file_exist() -> Result<()> {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   277
        let tempdir = TempDir::new()?;
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   278
        let mut path = tempdir.path().to_path_buf();
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   279
        path.push("dir");
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   280
        File::create(&path)?;
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   281
        let err = create_dir(&path).unwrap_err();
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   282
        assert_eq!(err.kind(), ErrorKind::AlreadyExists);
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   283
        Ok(())
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   284
    }
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   285
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   286
    #[test]
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   287
    fn test_path_expansion() {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   288
        fn getenv(key: &str) -> Option<String> {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   289
            match key {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   290
                "foo" => Some("~/a".into()),
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   291
                "bar" => Some("b".into()),
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   292
                _ => None,
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   293
            }
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   294
        }
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   295
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   296
        fn homedir() -> Option<PathBuf> {
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   297
            Some(PathBuf::from("/home/user"))
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   298
        }
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   299
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   300
        let path = "$foo/${bar}/$baz";
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   301
        let expected = PathBuf::from("/home/user/a/b/$baz");
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   302
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   303
        assert_eq!(expand_path_impl(&path, getenv, homedir), expected);
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   304
    }
6a1729ed223d hg-core: vendor Facebook's path utils module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
diff changeset
   305
}