rust/rhg/src/utils/path_utils.rs
author Mitchell Kember <mkember@janestreet.com>
Mon, 16 Dec 2024 10:52:01 -0500
changeset 52541 f33f37accb43
parent 49914 58074252db3c
permissions -rw-r--r--
rhg: add resolve_file_args to path_utils.rs Extracted logic for resolving `FILE ...` arguments from cat.rs into a new function in path_utils.rs. I plan to use this for rhg annotate. I tried to reuse hg::utils::files::canonical_path instead, but that didn't work. For example it reports a InsideDotHg error for any path containing "..".
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
48174
9ecf802b06e0 rhg: refactor function to relativize paths in utils
Pulkit Goyal <7895pulkit@gmail.com>
parents:
diff changeset
     1
// path utils module
9ecf802b06e0 rhg: refactor function to relativize paths in utils
Pulkit Goyal <7895pulkit@gmail.com>
parents:
diff changeset
     2
//
9ecf802b06e0 rhg: refactor function to relativize paths in utils
Pulkit Goyal <7895pulkit@gmail.com>
parents:
diff changeset
     3
// This software may be used and distributed according to the terms of the
9ecf802b06e0 rhg: refactor function to relativize paths in utils
Pulkit Goyal <7895pulkit@gmail.com>
parents:
diff changeset
     4
// GNU General Public License version 2 or any later version.
9ecf802b06e0 rhg: refactor function to relativize paths in utils
Pulkit Goyal <7895pulkit@gmail.com>
parents:
diff changeset
     5
48342
10c32e1b892a rhg: Propogate manifest parse errors instead of panicking
Simon Sapin <simon.sapin@octobus.net>
parents: 48174
diff changeset
     6
use hg::errors::HgError;
48174
9ecf802b06e0 rhg: refactor function to relativize paths in utils
Pulkit Goyal <7895pulkit@gmail.com>
parents:
diff changeset
     7
use hg::repo::Repo;
9ecf802b06e0 rhg: refactor function to relativize paths in utils
Pulkit Goyal <7895pulkit@gmail.com>
parents:
diff changeset
     8
use hg::utils::current_dir;
9ecf802b06e0 rhg: refactor function to relativize paths in utils
Pulkit Goyal <7895pulkit@gmail.com>
parents:
diff changeset
     9
use hg::utils::files::{get_bytes_from_path, relativize_path};
9ecf802b06e0 rhg: refactor function to relativize paths in utils
Pulkit Goyal <7895pulkit@gmail.com>
parents:
diff changeset
    10
use hg::utils::hg_path::HgPath;
9ecf802b06e0 rhg: refactor function to relativize paths in utils
Pulkit Goyal <7895pulkit@gmail.com>
parents:
diff changeset
    11
use hg::utils::hg_path::HgPathBuf;
9ecf802b06e0 rhg: refactor function to relativize paths in utils
Pulkit Goyal <7895pulkit@gmail.com>
parents:
diff changeset
    12
use std::borrow::Cow;
52541
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    13
use std::ffi::OsString;
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    14
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    15
use crate::error::CommandError;
48174
9ecf802b06e0 rhg: refactor function to relativize paths in utils
Pulkit Goyal <7895pulkit@gmail.com>
parents:
diff changeset
    16
48453
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    17
pub struct RelativizePaths {
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    18
    repo_root: HgPathBuf,
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    19
    cwd: HgPathBuf,
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    20
    outside_repo: bool,
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    21
}
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    22
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    23
impl RelativizePaths {
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    24
    pub fn new(repo: &Repo) -> Result<Self, HgError> {
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    25
        let cwd = current_dir()?;
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    26
        let repo_root = repo.working_directory_path();
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    27
        let repo_root = cwd.join(repo_root); // Make it absolute
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    28
        let repo_root_hgpath =
49914
58074252db3c rust: run `cargo clippy`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48453
diff changeset
    29
            HgPathBuf::from(get_bytes_from_path(&repo_root));
48174
9ecf802b06e0 rhg: refactor function to relativize paths in utils
Pulkit Goyal <7895pulkit@gmail.com>
parents:
diff changeset
    30
48453
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    31
        if let Ok(cwd_relative_to_repo) = cwd.strip_prefix(&repo_root) {
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    32
            // The current directory is inside the repo, so we can work with
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    33
            // relative paths
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    34
            Ok(Self {
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    35
                repo_root: repo_root_hgpath,
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    36
                cwd: HgPathBuf::from(get_bytes_from_path(
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    37
                    cwd_relative_to_repo,
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    38
                )),
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    39
                outside_repo: false,
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    40
            })
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    41
        } else {
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    42
            Ok(Self {
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    43
                repo_root: repo_root_hgpath,
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    44
                cwd: HgPathBuf::from(get_bytes_from_path(cwd)),
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    45
                outside_repo: true,
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    46
            })
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    47
        }
48174
9ecf802b06e0 rhg: refactor function to relativize paths in utils
Pulkit Goyal <7895pulkit@gmail.com>
parents:
diff changeset
    48
    }
9ecf802b06e0 rhg: refactor function to relativize paths in utils
Pulkit Goyal <7895pulkit@gmail.com>
parents:
diff changeset
    49
48453
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    50
    pub fn relativize<'a>(&self, path: &'a HgPath) -> Cow<'a, [u8]> {
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    51
        if self.outside_repo {
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    52
            let joined = self.repo_root.join(path);
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    53
            Cow::Owned(relativize_path(&joined, &self.cwd).into_owned())
48174
9ecf802b06e0 rhg: refactor function to relativize paths in utils
Pulkit Goyal <7895pulkit@gmail.com>
parents:
diff changeset
    54
        } else {
48453
9b0e1f64656f rhg: refactor relativize_path into a struct + method
Simon Sapin <simon.sapin@octobus.net>
parents: 48342
diff changeset
    55
            relativize_path(path, &self.cwd)
48174
9ecf802b06e0 rhg: refactor function to relativize paths in utils
Pulkit Goyal <7895pulkit@gmail.com>
parents:
diff changeset
    56
        }
9ecf802b06e0 rhg: refactor function to relativize paths in utils
Pulkit Goyal <7895pulkit@gmail.com>
parents:
diff changeset
    57
    }
9ecf802b06e0 rhg: refactor function to relativize paths in utils
Pulkit Goyal <7895pulkit@gmail.com>
parents:
diff changeset
    58
}
52541
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    59
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    60
/// Resolves `FILE ...` arguments to a list of paths in the repository.
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    61
pub fn resolve_file_args<'a>(
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    62
    repo: &Repo,
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    63
    file_args: impl Iterator<Item = &'a OsString>,
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    64
) -> Result<Vec<HgPathBuf>, CommandError> {
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    65
    let cwd = hg::utils::current_dir()?;
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    66
    let root = cwd.join(repo.working_directory_path());
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    67
    let mut result = Vec::new();
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    68
    for pattern in file_args {
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    69
        // TODO: Support all the formats in `hg help patterns`.
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    70
        if pattern.as_encoded_bytes().contains(&b':') {
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    71
            return Err(CommandError::unsupported(
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    72
                "rhg does not support file patterns",
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    73
            ));
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    74
        }
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    75
        // TODO: use hg::utils::files::canonical_path (currently doesn't work).
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    76
        let path = cwd.join(pattern);
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    77
        let dotted = path.components().any(|c| c.as_os_str() == "..");
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    78
        if pattern.as_encoded_bytes() == b"." || dotted {
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    79
            let message = "`..` or `.` path segment";
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    80
            return Err(CommandError::unsupported(message));
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    81
        }
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    82
        let relative_path = root.strip_prefix(&cwd).unwrap_or(&root);
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    83
        let stripped = path.strip_prefix(&root).map_err(|_| {
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    84
            CommandError::abort(format!(
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    85
                "abort: {} not under root '{}'\n(consider using '--cwd {}')",
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    86
                String::from_utf8_lossy(pattern.as_encoded_bytes()),
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    87
                root.display(),
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    88
                relative_path.display(),
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    89
            ))
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    90
        })?;
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    91
        let hg_file = HgPathBuf::try_from(stripped.to_path_buf())
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    92
            .map_err(|e| CommandError::abort(e.to_string()))?;
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    93
        result.push(hg_file);
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    94
    }
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    95
    Ok(result)
f33f37accb43 rhg: add resolve_file_args to path_utils.rs
Mitchell Kember <mkember@janestreet.com>
parents: 49914
diff changeset
    96
}