Start work on introducing RelPath type
This commit is contained in:
parent
fd1beedb16
commit
d8b791d3a6
10 changed files with 398 additions and 243 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -12871,6 +12871,7 @@ dependencies = [
|
||||||
"prost-build 0.9.0",
|
"prost-build 0.9.0",
|
||||||
"serde",
|
"serde",
|
||||||
"typed-path",
|
"typed-path",
|
||||||
|
"util",
|
||||||
"workspace-hack",
|
"workspace-hack",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -27,6 +27,7 @@ use std::{
|
||||||
use sum_tree::MapSeekTarget;
|
use sum_tree::MapSeekTarget;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use util::command::{new_smol_command, new_std_command};
|
use util::command::{new_smol_command, new_std_command};
|
||||||
|
use util::rel_path::RelPath;
|
||||||
use util::{ResultExt, paths};
|
use util::{ResultExt, paths};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
@ -662,14 +663,22 @@ impl GitRepository for RealGitRepository {
|
||||||
for (path, status_code) in changes {
|
for (path, status_code) in changes {
|
||||||
match status_code {
|
match status_code {
|
||||||
StatusCode::Modified => {
|
StatusCode::Modified => {
|
||||||
writeln!(&mut stdin, "{commit}:{}", path.display())?;
|
write!(&mut stdin, "{commit}:")?;
|
||||||
writeln!(&mut stdin, "{parent_sha}:{}", path.display())?;
|
stdin.write_all(path.as_bytes())?;
|
||||||
|
stdin.write_all(b"\n")?;
|
||||||
|
write!(&mut stdin, "{parent_sha}:")?;
|
||||||
|
stdin.write_all(path.as_bytes())?;
|
||||||
|
stdin.write_all(b"\n")?;
|
||||||
}
|
}
|
||||||
StatusCode::Added => {
|
StatusCode::Added => {
|
||||||
writeln!(&mut stdin, "{commit}:{}", path.display())?;
|
write!(&mut stdin, "{commit}:")?;
|
||||||
|
stdin.write_all(path.as_bytes())?;
|
||||||
|
stdin.write_all(b"\n")?;
|
||||||
}
|
}
|
||||||
StatusCode::Deleted => {
|
StatusCode::Deleted => {
|
||||||
writeln!(&mut stdin, "{parent_sha}:{}", path.display())?;
|
write!(&mut stdin, "{parent_sha}:")?;
|
||||||
|
stdin.write_all(path.as_bytes())?;
|
||||||
|
stdin.write_all(b"\n")?;
|
||||||
}
|
}
|
||||||
_ => continue,
|
_ => continue,
|
||||||
}
|
}
|
||||||
|
@ -1652,7 +1661,7 @@ fn git_status_args(path_prefixes: &[RepoPath]) -> Vec<OsString> {
|
||||||
OsString::from("-z"),
|
OsString::from("-z"),
|
||||||
];
|
];
|
||||||
args.extend(path_prefixes.iter().map(|path_prefix| {
|
args.extend(path_prefixes.iter().map(|path_prefix| {
|
||||||
if path_prefix.0.as_ref() == Path::new("") {
|
if path_prefix.0.as_ref() == RelPath::new("") {
|
||||||
Path::new(".").into()
|
Path::new(".").into()
|
||||||
} else {
|
} else {
|
||||||
path_prefix.as_os_str().into()
|
path_prefix.as_os_str().into()
|
||||||
|
@ -1905,64 +1914,33 @@ async fn run_askpass_command(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static WORK_DIRECTORY_REPO_PATH: LazyLock<RepoPath> =
|
pub static WORK_DIRECTORY_REPO_PATH: LazyLock<RepoPath> =
|
||||||
LazyLock::new(|| RepoPath(Path::new("").into()));
|
LazyLock::new(|| RepoPath(RelPath::new("").into()));
|
||||||
|
|
||||||
#[derive(Clone, Debug, Ord, Hash, PartialOrd, Eq, PartialEq)]
|
#[derive(Clone, Debug, Ord, Hash, PartialOrd, Eq, PartialEq)]
|
||||||
pub struct RepoPath(pub Arc<Path>);
|
pub struct RepoPath(pub Arc<RelPath>);
|
||||||
|
|
||||||
impl RepoPath {
|
impl RepoPath {
|
||||||
pub fn new(path: PathBuf) -> Self {
|
|
||||||
debug_assert!(path.is_relative(), "Repo paths must be relative");
|
|
||||||
|
|
||||||
RepoPath(path.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_str(path: &str) -> Self {
|
pub fn from_str(path: &str) -> Self {
|
||||||
let path = Path::new(path);
|
RepoPath(RelPath::new(path).into())
|
||||||
debug_assert!(path.is_relative(), "Repo paths must be relative");
|
|
||||||
|
|
||||||
RepoPath(path.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_unix_style(&self) -> Cow<'_, OsStr> {
|
pub fn to_unix_style(&self) -> Cow<'_, OsStr> {
|
||||||
#[cfg(target_os = "windows")]
|
self.0.as_os_str()
|
||||||
{
|
|
||||||
use std::ffi::OsString;
|
|
||||||
|
|
||||||
let path = self.0.as_os_str().to_string_lossy().replace("\\", "/");
|
|
||||||
Cow::Owned(OsString::from(path))
|
|
||||||
}
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
|
||||||
{
|
|
||||||
Cow::Borrowed(self.0.as_os_str())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for RepoPath {
|
impl From<&RelPath> for RepoPath {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn from(value: &RelPath) -> Self {
|
||||||
self.0.to_string_lossy().fmt(f)
|
RepoPath(value.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&Path> for RepoPath {
|
impl From<Arc<RelPath>> for RepoPath {
|
||||||
fn from(value: &Path) -> Self {
|
fn from(value: Arc<RelPath>) -> Self {
|
||||||
RepoPath::new(value.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Arc<Path>> for RepoPath {
|
|
||||||
fn from(value: Arc<Path>) -> Self {
|
|
||||||
RepoPath(value)
|
RepoPath(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<PathBuf> for RepoPath {
|
|
||||||
fn from(value: PathBuf) -> Self {
|
|
||||||
RepoPath::new(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&str> for RepoPath {
|
impl From<&str> for RepoPath {
|
||||||
fn from(value: &str) -> Self {
|
fn from(value: &str) -> Self {
|
||||||
Self::from_str(value)
|
Self::from_str(value)
|
||||||
|
@ -1971,32 +1949,32 @@ impl From<&str> for RepoPath {
|
||||||
|
|
||||||
impl Default for RepoPath {
|
impl Default for RepoPath {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
RepoPath(Path::new("").into())
|
RepoPath(RelPath::new("").into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<Path> for RepoPath {
|
impl AsRef<RelPath> for RepoPath {
|
||||||
fn as_ref(&self) -> &Path {
|
fn as_ref(&self) -> &RelPath {
|
||||||
self.0.as_ref()
|
self.0.as_ref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::Deref for RepoPath {
|
impl std::ops::Deref for RepoPath {
|
||||||
type Target = Path;
|
type Target = RelPath;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Borrow<Path> for RepoPath {
|
impl Borrow<RelPath> for RepoPath {
|
||||||
fn borrow(&self) -> &Path {
|
fn borrow(&self) -> &RelPath {
|
||||||
self.0.as_ref()
|
self.0.as_ref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct RepoPathDescendants<'a>(pub &'a Path);
|
pub struct RepoPathDescendants<'a>(pub &'a RelPath);
|
||||||
|
|
||||||
impl MapSeekTarget<RepoPath> for RepoPathDescendants<'_> {
|
impl MapSeekTarget<RepoPath> for RepoPathDescendants<'_> {
|
||||||
fn cmp_cursor(&self, key: &RepoPath) -> Ordering {
|
fn cmp_cursor(&self, key: &RepoPath) -> Ordering {
|
||||||
|
|
|
@ -1663,7 +1663,7 @@ impl GitStore {
|
||||||
.payload
|
.payload
|
||||||
.paths
|
.paths
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(PathBuf::from)
|
.map(RelPath::new)
|
||||||
.map(RepoPath::new)
|
.map(RepoPath::new)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ doctest = false
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
prost.workspace = true
|
prost.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
|
util.workspace = true
|
||||||
workspace-hack.workspace = true
|
workspace-hack.workspace = true
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|
|
@ -9,6 +9,7 @@ use std::{
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use std::{marker::PhantomData, time::Instant};
|
use std::{marker::PhantomData, time::Instant};
|
||||||
|
use util::rel_path::RelPath;
|
||||||
|
|
||||||
pub trait EnvelopedMessage: Clone + Debug + Serialize + Sized + Send + Sync + 'static {
|
pub trait EnvelopedMessage: Clone + Debug + Serialize + Sized + Send + Sync + 'static {
|
||||||
const NAME: &'static str;
|
const NAME: &'static str;
|
||||||
|
@ -158,6 +159,12 @@ impl FromProto for Arc<Path> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FromProto for Arc<RelPath> {
|
||||||
|
fn from_proto(proto: String) -> Self {
|
||||||
|
RelPath::new(proto.as_bytes()).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ToProto for PathBuf {
|
impl ToProto for PathBuf {
|
||||||
fn to_proto(self) -> String {
|
fn to_proto(self) -> String {
|
||||||
to_proto_path(&self)
|
to_proto_path(&self)
|
||||||
|
|
171
crates/util/src/rel_path.rs
Normal file
171
crates/util/src/rel_path.rs
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
use std::{
|
||||||
|
borrow::Cow,
|
||||||
|
ffi::OsStr,
|
||||||
|
path::{Display, Path, PathBuf},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct RelPath([u8]);
|
||||||
|
|
||||||
|
impl RelPath {
|
||||||
|
pub fn new<S: AsRef<[u8]> + ?Sized>(s: &S) -> &Self {
|
||||||
|
unsafe { &*(s.as_ref() as *const [u8] as *const Self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn components(&self) -> RelPathComponents {
|
||||||
|
RelPathComponents(&self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn file_name(&self) -> Option<&[u8]> {
|
||||||
|
self.components().next_back()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parent(&self) -> Option<&Self> {
|
||||||
|
let mut components = self.components();
|
||||||
|
components.next_back()?;
|
||||||
|
Some(Self::new(components.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn starts_with(&self, other: &Self) -> bool {
|
||||||
|
let mut components = self.components();
|
||||||
|
other.components().all(|other_component| {
|
||||||
|
components
|
||||||
|
.next()
|
||||||
|
.map_or(false, |component| component == other_component)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn strip_prefix(&self, other: &Self) -> Result<&Self, ()> {
|
||||||
|
let mut components = self.components();
|
||||||
|
other
|
||||||
|
.components()
|
||||||
|
.all(|other_component| {
|
||||||
|
components
|
||||||
|
.next()
|
||||||
|
.map_or(false, |component| component == other_component)
|
||||||
|
})
|
||||||
|
.then(|| Self::new(components.0))
|
||||||
|
.ok_or_else(|| ())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn append_to_abs_path(&self, abs_path: &Path) -> PathBuf {
|
||||||
|
// TODO: implement this differently
|
||||||
|
let mut result = abs_path.to_path_buf();
|
||||||
|
for component in self.components() {
|
||||||
|
result.push(String::from_utf8_lossy(component).as_ref());
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_proto(&self) -> String {
|
||||||
|
String::from_utf8_lossy(&self.0).to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_bytes(&self) -> &[u8] {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_os_str(&self) -> Cow<'_, OsStr> {
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
{
|
||||||
|
use std::ffi::OsString;
|
||||||
|
let path = String::from_utf8_lossy(&self.0);
|
||||||
|
match path {
|
||||||
|
Cow::Borrowed(s) => Cow::Borrowed(OsStr::new(s)),
|
||||||
|
Cow::Owned(s) => Cow::Owned(OsString::from(s)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
{
|
||||||
|
Cow::Borrowed(self.0.as_os_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&RelPath> for Arc<RelPath> {
|
||||||
|
fn from(rel_path: &RelPath) -> Self {
|
||||||
|
let bytes: Arc<[u8]> = Arc::from(&rel_path.0);
|
||||||
|
unsafe { Arc::from_raw(Arc::into_raw(bytes) as *const RelPath) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<RelPath> for &str {
|
||||||
|
fn as_ref(&self) -> &RelPath {
|
||||||
|
RelPath::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for RelPath {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
if let Ok(str) = std::str::from_utf8(&self.0) {
|
||||||
|
write!(f, "RelPath({})", str)
|
||||||
|
} else {
|
||||||
|
write!(f, "RelPath({:?})", &self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RelPathComponents<'a>(&'a [u8]);
|
||||||
|
|
||||||
|
const SEPARATOR: u8 = b'/';
|
||||||
|
|
||||||
|
impl<'a> Iterator for RelPathComponents<'a> {
|
||||||
|
type Item = &'a [u8];
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if let Some(sep_ix) = self.0.iter().position(|&byte| byte == SEPARATOR) {
|
||||||
|
let (head, tail) = self.0.split_at(sep_ix);
|
||||||
|
self.0 = &tail[1..];
|
||||||
|
Some(head)
|
||||||
|
} else if self.0.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let result = self.0;
|
||||||
|
self.0 = &[];
|
||||||
|
Some(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DoubleEndedIterator for RelPathComponents<'a> {
|
||||||
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
|
if let Some(sep_ix) = self.0.iter().rposition(|&byte| byte == SEPARATOR) {
|
||||||
|
let (head, tail) = self.0.split_at(sep_ix);
|
||||||
|
self.0 = head;
|
||||||
|
Some(&tail[1..])
|
||||||
|
} else if self.0.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let result = self.0;
|
||||||
|
self.0 = &[];
|
||||||
|
Some(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rel_path_components() {
|
||||||
|
let path = RelPath::new("foo/bar/baz");
|
||||||
|
let mut components = path.components();
|
||||||
|
assert_eq!(components.next(), Some("foo".as_bytes()));
|
||||||
|
assert_eq!(components.next(), Some("bar".as_bytes()));
|
||||||
|
assert_eq!(components.next(), Some("baz".as_bytes()));
|
||||||
|
assert_eq!(components.next(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rel_path_parent() {
|
||||||
|
assert_eq!(
|
||||||
|
RelPath::new("foo/bar/baz").parent().unwrap(),
|
||||||
|
RelPath::new("foo/bar")
|
||||||
|
);
|
||||||
|
assert_eq!(RelPath::new("foo").parent().unwrap(), RelPath::new(""));
|
||||||
|
assert_eq!(RelPath::new("").parent(), None);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ pub mod fs;
|
||||||
pub mod markdown;
|
pub mod markdown;
|
||||||
pub mod paths;
|
pub mod paths;
|
||||||
pub mod redact;
|
pub mod redact;
|
||||||
|
pub mod rel_path;
|
||||||
pub mod schemars;
|
pub mod schemars;
|
||||||
pub mod serde;
|
pub mod serde;
|
||||||
pub mod shell_env;
|
pub mod shell_env;
|
||||||
|
|
|
@ -67,6 +67,7 @@ use text::{LineEnding, Rope};
|
||||||
use util::{
|
use util::{
|
||||||
ResultExt,
|
ResultExt,
|
||||||
paths::{PathMatcher, SanitizedPath, home_dir},
|
paths::{PathMatcher, SanitizedPath, home_dir},
|
||||||
|
rel_path::RelPath,
|
||||||
};
|
};
|
||||||
pub use worktree_settings::WorktreeSettings;
|
pub use worktree_settings::WorktreeSettings;
|
||||||
|
|
||||||
|
@ -132,12 +133,12 @@ pub struct LocalWorktree {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PathPrefixScanRequest {
|
pub struct PathPrefixScanRequest {
|
||||||
path: Arc<Path>,
|
path: Arc<RelPath>,
|
||||||
done: SmallVec<[barrier::Sender; 1]>,
|
done: SmallVec<[barrier::Sender; 1]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ScanRequest {
|
struct ScanRequest {
|
||||||
relative_paths: Vec<Arc<Path>>,
|
relative_paths: Vec<Arc<RelPath>>,
|
||||||
done: SmallVec<[barrier::Sender; 1]>,
|
done: SmallVec<[barrier::Sender; 1]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +187,7 @@ pub struct Snapshot {
|
||||||
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
|
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
|
||||||
pub enum WorkDirectory {
|
pub enum WorkDirectory {
|
||||||
InProject {
|
InProject {
|
||||||
relative_path: Arc<Path>,
|
relative_path: Arc<RelPath>,
|
||||||
},
|
},
|
||||||
AboveProject {
|
AboveProject {
|
||||||
absolute_path: Arc<Path>,
|
absolute_path: Arc<Path>,
|
||||||
|
@ -197,7 +198,7 @@ pub enum WorkDirectory {
|
||||||
impl WorkDirectory {
|
impl WorkDirectory {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn in_project(path: &str) -> Self {
|
fn in_project(path: &str) -> Self {
|
||||||
let path = Path::new(path);
|
let path = RelPath::new(path);
|
||||||
Self::InProject {
|
Self::InProject {
|
||||||
relative_path: path.into(),
|
relative_path: path.into(),
|
||||||
}
|
}
|
||||||
|
@ -232,9 +233,8 @@ impl WorkDirectory {
|
||||||
/// is a repository in a directory between these two paths
|
/// is a repository in a directory between these two paths
|
||||||
/// external .git folder in a parent folder of the project root.
|
/// external .git folder in a parent folder of the project root.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn directory_contains(&self, path: impl AsRef<Path>) -> bool {
|
pub fn directory_contains(&self, path: impl AsRef<RelPath>) -> bool {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
debug_assert!(path.is_relative());
|
|
||||||
match self {
|
match self {
|
||||||
WorkDirectory::InProject { relative_path } => path.starts_with(relative_path),
|
WorkDirectory::InProject { relative_path } => path.starts_with(relative_path),
|
||||||
WorkDirectory::AboveProject { .. } => true,
|
WorkDirectory::AboveProject { .. } => true,
|
||||||
|
@ -246,9 +246,8 @@ impl WorkDirectory {
|
||||||
/// If the root of the repository (and its .git folder) are located in a parent folder
|
/// If the root of the repository (and its .git folder) are located in a parent folder
|
||||||
/// of the project root folder, then the returned RepoPath is relative to the root
|
/// of the project root folder, then the returned RepoPath is relative to the root
|
||||||
/// of the repository and not a valid path inside the project.
|
/// of the repository and not a valid path inside the project.
|
||||||
pub fn relativize(&self, path: &Path) -> Result<RepoPath> {
|
pub fn relativize(&self, path: &RelPath) -> Result<RepoPath> {
|
||||||
// path is assumed to be relative to worktree root.
|
// path is assumed to be relative to worktree root.
|
||||||
debug_assert!(path.is_relative());
|
|
||||||
match self {
|
match self {
|
||||||
WorkDirectory::InProject { relative_path } => Ok(path
|
WorkDirectory::InProject { relative_path } => Ok(path
|
||||||
.strip_prefix(relative_path)
|
.strip_prefix(relative_path)
|
||||||
|
@ -842,12 +841,12 @@ impl Worktree {
|
||||||
|
|
||||||
pub fn create_entry(
|
pub fn create_entry(
|
||||||
&mut self,
|
&mut self,
|
||||||
path: impl Into<Arc<Path>>,
|
path: impl Into<Arc<RelPath>>,
|
||||||
is_directory: bool,
|
is_directory: bool,
|
||||||
content: Option<Vec<u8>>,
|
content: Option<Vec<u8>>,
|
||||||
cx: &Context<Worktree>,
|
cx: &Context<Worktree>,
|
||||||
) -> Task<Result<CreatedEntry>> {
|
) -> Task<Result<CreatedEntry>> {
|
||||||
let path: Arc<Path> = path.into();
|
let path: Arc<RelPath> = path.into();
|
||||||
let worktree_id = self.id();
|
let worktree_id = self.id();
|
||||||
match self {
|
match self {
|
||||||
Worktree::Local(this) => this.create_entry(path, is_directory, content, cx),
|
Worktree::Local(this) => this.create_entry(path, is_directory, content, cx),
|
||||||
|
@ -914,7 +913,7 @@ impl Worktree {
|
||||||
Some(task)
|
Some(task)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_children_ids_recursive(&self, path: &Path, ids: &mut Vec<ProjectEntryId>) {
|
fn get_children_ids_recursive(&self, path: &RelPath, ids: &mut Vec<ProjectEntryId>) {
|
||||||
let children_iter = self.child_entries(path);
|
let children_iter = self.child_entries(path);
|
||||||
for child in children_iter {
|
for child in children_iter {
|
||||||
ids.push(child.id);
|
ids.push(child.id);
|
||||||
|
@ -1575,7 +1574,7 @@ impl LocalWorktree {
|
||||||
|
|
||||||
fn create_entry(
|
fn create_entry(
|
||||||
&self,
|
&self,
|
||||||
path: impl Into<Arc<Path>>,
|
path: impl Into<Arc<RelPath>>,
|
||||||
is_dir: bool,
|
is_dir: bool,
|
||||||
content: Option<Vec<u8>>,
|
content: Option<Vec<u8>>,
|
||||||
cx: &Context<Worktree>,
|
cx: &Context<Worktree>,
|
||||||
|
@ -1975,7 +1974,7 @@ impl LocalWorktree {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn refresh_entries_for_paths(&self, paths: Vec<Arc<Path>>) -> barrier::Receiver {
|
fn refresh_entries_for_paths(&self, paths: Vec<Arc<RelPath>>) -> barrier::Receiver {
|
||||||
let (tx, rx) = barrier::channel();
|
let (tx, rx) = barrier::channel();
|
||||||
self.scan_requests_tx
|
self.scan_requests_tx
|
||||||
.try_send(ScanRequest {
|
.try_send(ScanRequest {
|
||||||
|
@ -1987,11 +1986,14 @@ impl LocalWorktree {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "test-support")]
|
#[cfg(feature = "test-support")]
|
||||||
pub fn manually_refresh_entries_for_paths(&self, paths: Vec<Arc<Path>>) -> barrier::Receiver {
|
pub fn manually_refresh_entries_for_paths(
|
||||||
|
&self,
|
||||||
|
paths: Vec<Arc<RelPath>>,
|
||||||
|
) -> barrier::Receiver {
|
||||||
self.refresh_entries_for_paths(paths)
|
self.refresh_entries_for_paths(paths)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_path_prefix_to_scan(&self, path_prefix: Arc<Path>) -> barrier::Receiver {
|
pub fn add_path_prefix_to_scan(&self, path_prefix: Arc<RelPath>) -> barrier::Receiver {
|
||||||
let (tx, rx) = barrier::channel();
|
let (tx, rx) = barrier::channel();
|
||||||
self.path_prefixes_to_scan_tx
|
self.path_prefixes_to_scan_tx
|
||||||
.try_send(PathPrefixScanRequest {
|
.try_send(PathPrefixScanRequest {
|
||||||
|
@ -2004,8 +2006,8 @@ impl LocalWorktree {
|
||||||
|
|
||||||
fn refresh_entry(
|
fn refresh_entry(
|
||||||
&self,
|
&self,
|
||||||
path: Arc<Path>,
|
path: Arc<RelPath>,
|
||||||
old_path: Option<Arc<Path>>,
|
old_path: Option<Arc<RelPath>>,
|
||||||
cx: &Context<Worktree>,
|
cx: &Context<Worktree>,
|
||||||
) -> Task<Result<Option<Entry>>> {
|
) -> Task<Result<Option<Entry>>> {
|
||||||
if self.settings.is_path_excluded(&path) {
|
if self.settings.is_path_excluded(&path) {
|
||||||
|
@ -2403,18 +2405,8 @@ impl Snapshot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn absolutize(&self, path: &Path) -> Result<PathBuf> {
|
pub fn absolutize(&self, path: &RelPath) -> Result<PathBuf> {
|
||||||
if path
|
Ok(path.append_to_abs_path(&self.abs_path.0))
|
||||||
.components()
|
|
||||||
.any(|component| !matches!(component, std::path::Component::Normal(_)))
|
|
||||||
{
|
|
||||||
anyhow::bail!("invalid path");
|
|
||||||
}
|
|
||||||
if path.file_name().is_some() {
|
|
||||||
Ok(self.abs_path.as_path().join(path))
|
|
||||||
} else {
|
|
||||||
Ok(self.abs_path.as_path().to_path_buf())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn contains_entry(&self, entry_id: ProjectEntryId) -> bool {
|
pub fn contains_entry(&self, entry_id: ProjectEntryId) -> bool {
|
||||||
|
@ -2585,7 +2577,7 @@ impl Snapshot {
|
||||||
include_files: bool,
|
include_files: bool,
|
||||||
include_dirs: bool,
|
include_dirs: bool,
|
||||||
include_ignored: bool,
|
include_ignored: bool,
|
||||||
path: &Path,
|
path: &RelPath,
|
||||||
) -> Traversal<'_> {
|
) -> Traversal<'_> {
|
||||||
Traversal::new(self, include_files, include_dirs, include_ignored, path)
|
Traversal::new(self, include_files, include_dirs, include_ignored, path)
|
||||||
}
|
}
|
||||||
|
@ -2602,15 +2594,15 @@ impl Snapshot {
|
||||||
self.traverse_from_offset(true, true, include_ignored, start)
|
self.traverse_from_offset(true, true, include_ignored, start)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn paths(&self) -> impl Iterator<Item = &Arc<Path>> {
|
pub fn paths(&self) -> impl Iterator<Item = &Arc<RelPath>> {
|
||||||
let empty_path = Path::new("");
|
let empty_path = RelPath::new("");
|
||||||
self.entries_by_path
|
self.entries_by_path
|
||||||
.cursor::<()>(&())
|
.cursor::<()>(&())
|
||||||
.filter(move |entry| entry.path.as_ref() != empty_path)
|
.filter(move |entry| entry.path.as_ref() != empty_path)
|
||||||
.map(|entry| &entry.path)
|
.map(|entry| &entry.path)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn child_entries<'a>(&'a self, parent_path: &'a Path) -> ChildEntriesIter<'a> {
|
pub fn child_entries<'a>(&'a self, parent_path: &'a RelPath) -> ChildEntriesIter<'a> {
|
||||||
let options = ChildEntriesOptions {
|
let options = ChildEntriesOptions {
|
||||||
include_files: true,
|
include_files: true,
|
||||||
include_dirs: true,
|
include_dirs: true,
|
||||||
|
@ -2621,7 +2613,7 @@ impl Snapshot {
|
||||||
|
|
||||||
pub fn child_entries_with_options<'a>(
|
pub fn child_entries_with_options<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
parent_path: &'a Path,
|
parent_path: &'a RelPath,
|
||||||
options: ChildEntriesOptions,
|
options: ChildEntriesOptions,
|
||||||
) -> ChildEntriesIter<'a> {
|
) -> ChildEntriesIter<'a> {
|
||||||
let mut cursor = self.entries_by_path.cursor(&());
|
let mut cursor = self.entries_by_path.cursor(&());
|
||||||
|
@ -2659,9 +2651,8 @@ impl Snapshot {
|
||||||
self.scan_id
|
self.scan_id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn entry_for_path(&self, path: impl AsRef<Path>) -> Option<&Entry> {
|
pub fn entry_for_path(&self, path: impl AsRef<RelPath>) -> Option<&Entry> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
debug_assert!(path.is_relative());
|
|
||||||
self.traverse_from_path(true, true, true, path)
|
self.traverse_from_path(true, true, true, path)
|
||||||
.entry()
|
.entry()
|
||||||
.and_then(|entry| {
|
.and_then(|entry| {
|
||||||
|
@ -3436,7 +3427,7 @@ impl File {
|
||||||
pub struct Entry {
|
pub struct Entry {
|
||||||
pub id: ProjectEntryId,
|
pub id: ProjectEntryId,
|
||||||
pub kind: EntryKind,
|
pub kind: EntryKind,
|
||||||
pub path: Arc<Path>,
|
pub path: Arc<RelPath>,
|
||||||
pub inode: u64,
|
pub inode: u64,
|
||||||
pub mtime: Option<MTime>,
|
pub mtime: Option<MTime>,
|
||||||
|
|
||||||
|
@ -3510,7 +3501,7 @@ pub struct UpdatedGitRepository {
|
||||||
pub common_dir_abs_path: Option<Arc<Path>>,
|
pub common_dir_abs_path: Option<Arc<Path>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type UpdatedEntriesSet = Arc<[(Arc<Path>, ProjectEntryId, PathChange)]>;
|
pub type UpdatedEntriesSet = Arc<[(Arc<RelPath>, ProjectEntryId, PathChange)]>;
|
||||||
pub type UpdatedGitRepositoriesSet = Arc<[UpdatedGitRepository]>;
|
pub type UpdatedGitRepositoriesSet = Arc<[UpdatedGitRepository]>;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -3786,7 +3777,7 @@ impl<'a> sum_tree::Dimension<'a, PathEntrySummary> for ProjectEntryId {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub struct PathKey(pub Arc<Path>);
|
pub struct PathKey(pub Arc<RelPath>);
|
||||||
|
|
||||||
impl Default for PathKey {
|
impl Default for PathKey {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
@ -5188,7 +5179,7 @@ impl WorktreeModelHandle for Entity<Worktree> {
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct TraversalProgress<'a> {
|
struct TraversalProgress<'a> {
|
||||||
max_path: &'a Path,
|
max_path: &'a RelPath,
|
||||||
count: usize,
|
count: usize,
|
||||||
non_ignored_count: usize,
|
non_ignored_count: usize,
|
||||||
file_count: usize,
|
file_count: usize,
|
||||||
|
@ -5250,7 +5241,7 @@ impl<'a> Traversal<'a> {
|
||||||
include_files: bool,
|
include_files: bool,
|
||||||
include_dirs: bool,
|
include_dirs: bool,
|
||||||
include_ignored: bool,
|
include_ignored: bool,
|
||||||
start_path: &Path,
|
start_path: &RelPath,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut cursor = snapshot.entries_by_path.cursor(&());
|
let mut cursor = snapshot.entries_by_path.cursor(&());
|
||||||
cursor.seek(&TraversalTarget::path(start_path), Bias::Left);
|
cursor.seek(&TraversalTarget::path(start_path), Bias::Left);
|
||||||
|
@ -5343,12 +5334,12 @@ impl<'a> Iterator for Traversal<'a> {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum PathTarget<'a> {
|
pub enum PathTarget<'a> {
|
||||||
Path(&'a Path),
|
Path(&'a RelPath),
|
||||||
Successor(&'a Path),
|
Successor(&'a RelPath),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PathTarget<'_> {
|
impl PathTarget<'_> {
|
||||||
fn cmp_path(&self, other: &Path) -> Ordering {
|
fn cmp_path(&self, other: &RelPath) -> Ordering {
|
||||||
match self {
|
match self {
|
||||||
PathTarget::Path(path) => path.cmp(&other),
|
PathTarget::Path(path) => path.cmp(&other),
|
||||||
PathTarget::Successor(path) => {
|
PathTarget::Successor(path) => {
|
||||||
|
@ -5386,11 +5377,11 @@ enum TraversalTarget<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TraversalTarget<'a> {
|
impl<'a> TraversalTarget<'a> {
|
||||||
fn path(path: &'a Path) -> Self {
|
fn path(path: &'a RelPath) -> Self {
|
||||||
Self::Path(PathTarget::Path(path))
|
Self::Path(PathTarget::Path(path))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn successor(path: &'a Path) -> Self {
|
fn successor(path: &'a RelPath) -> Self {
|
||||||
Self::Path(PathTarget::Successor(path))
|
Self::Path(PathTarget::Successor(path))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ use std::{
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use util::{ResultExt, path, test::TempTree};
|
use util::{ResultExt, path, rel_path::RelPath, test::TempTree};
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_traversal(cx: &mut TestAppContext) {
|
async fn test_traversal(cx: &mut TestAppContext) {
|
||||||
|
@ -56,10 +56,10 @@ async fn test_traversal(cx: &mut TestAppContext) {
|
||||||
.map(|entry| entry.path.as_ref())
|
.map(|entry| entry.path.as_ref())
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
vec![
|
vec![
|
||||||
Path::new(""),
|
RelPath::new(""),
|
||||||
Path::new(".gitignore"),
|
RelPath::new(".gitignore"),
|
||||||
Path::new("a"),
|
RelPath::new("a"),
|
||||||
Path::new("a/c"),
|
RelPath::new("a/c"),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -67,11 +67,11 @@ async fn test_traversal(cx: &mut TestAppContext) {
|
||||||
.map(|entry| entry.path.as_ref())
|
.map(|entry| entry.path.as_ref())
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
vec![
|
vec![
|
||||||
Path::new(""),
|
RelPath::new(""),
|
||||||
Path::new(".gitignore"),
|
RelPath::new(".gitignore"),
|
||||||
Path::new("a"),
|
RelPath::new("a"),
|
||||||
Path::new("a/b"),
|
RelPath::new("a/b"),
|
||||||
Path::new("a/c"),
|
RelPath::new("a/c"),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
@ -121,14 +121,14 @@ async fn test_circular_symlinks(cx: &mut TestAppContext) {
|
||||||
.map(|entry| entry.path.as_ref())
|
.map(|entry| entry.path.as_ref())
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
vec![
|
vec![
|
||||||
Path::new(""),
|
RelPath::new(""),
|
||||||
Path::new("lib"),
|
RelPath::new("lib"),
|
||||||
Path::new("lib/a"),
|
RelPath::new("lib/a"),
|
||||||
Path::new("lib/a/a.txt"),
|
RelPath::new("lib/a/a.txt"),
|
||||||
Path::new("lib/a/lib"),
|
RelPath::new("lib/a/lib"),
|
||||||
Path::new("lib/b"),
|
RelPath::new("lib/b"),
|
||||||
Path::new("lib/b/b.txt"),
|
RelPath::new("lib/b/b.txt"),
|
||||||
Path::new("lib/b/lib"),
|
RelPath::new("lib/b/lib"),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -147,14 +147,14 @@ async fn test_circular_symlinks(cx: &mut TestAppContext) {
|
||||||
.map(|entry| entry.path.as_ref())
|
.map(|entry| entry.path.as_ref())
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
vec![
|
vec![
|
||||||
Path::new(""),
|
RelPath::new(""),
|
||||||
Path::new("lib"),
|
RelPath::new("lib"),
|
||||||
Path::new("lib/a"),
|
RelPath::new("lib/a"),
|
||||||
Path::new("lib/a/a.txt"),
|
RelPath::new("lib/a/a.txt"),
|
||||||
Path::new("lib/a/lib-2"),
|
RelPath::new("lib/a/lib-2"),
|
||||||
Path::new("lib/b"),
|
RelPath::new("lib/b"),
|
||||||
Path::new("lib/b/b.txt"),
|
RelPath::new("lib/b/b.txt"),
|
||||||
Path::new("lib/b/lib"),
|
RelPath::new("lib/b/lib"),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -236,18 +236,20 @@ async fn test_symlinks_pointing_outside(cx: &mut TestAppContext) {
|
||||||
.map(|entry| (entry.path.as_ref(), entry.is_external))
|
.map(|entry| (entry.path.as_ref(), entry.is_external))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
vec![
|
vec![
|
||||||
(Path::new(""), false),
|
(RelPath::new(""), false),
|
||||||
(Path::new("deps"), false),
|
(RelPath::new("deps"), false),
|
||||||
(Path::new("deps/dep-dir2"), true),
|
(RelPath::new("deps/dep-dir2"), true),
|
||||||
(Path::new("deps/dep-dir3"), true),
|
(RelPath::new("deps/dep-dir3"), true),
|
||||||
(Path::new("src"), false),
|
(RelPath::new("src"), false),
|
||||||
(Path::new("src/a.rs"), false),
|
(RelPath::new("src/a.rs"), false),
|
||||||
(Path::new("src/b.rs"), false),
|
(RelPath::new("src/b.rs"), false),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
tree.entry_for_path("deps/dep-dir2").unwrap().kind,
|
tree.entry_for_path(RelPath::new("deps/dep-dir2"))
|
||||||
|
.unwrap()
|
||||||
|
.kind,
|
||||||
EntryKind::UnloadedDir
|
EntryKind::UnloadedDir
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -256,7 +258,7 @@ async fn test_symlinks_pointing_outside(cx: &mut TestAppContext) {
|
||||||
tree.read_with(cx, |tree, _| {
|
tree.read_with(cx, |tree, _| {
|
||||||
tree.as_local()
|
tree.as_local()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.refresh_entries_for_paths(vec![Path::new("deps/dep-dir3").into()])
|
.refresh_entries_for_paths(vec![RelPath::new("deps/dep-dir3").into()])
|
||||||
})
|
})
|
||||||
.recv()
|
.recv()
|
||||||
.await;
|
.await;
|
||||||
|
@ -269,24 +271,27 @@ async fn test_symlinks_pointing_outside(cx: &mut TestAppContext) {
|
||||||
.map(|entry| (entry.path.as_ref(), entry.is_external))
|
.map(|entry| (entry.path.as_ref(), entry.is_external))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
vec![
|
vec![
|
||||||
(Path::new(""), false),
|
(RelPath::new(""), false),
|
||||||
(Path::new("deps"), false),
|
(RelPath::new("deps"), false),
|
||||||
(Path::new("deps/dep-dir2"), true),
|
(RelPath::new("deps/dep-dir2"), true),
|
||||||
(Path::new("deps/dep-dir3"), true),
|
(RelPath::new("deps/dep-dir3"), true),
|
||||||
(Path::new("deps/dep-dir3/deps"), true),
|
(RelPath::new("deps/dep-dir3/deps"), true),
|
||||||
(Path::new("deps/dep-dir3/src"), true),
|
(RelPath::new("deps/dep-dir3/src"), true),
|
||||||
(Path::new("src"), false),
|
(RelPath::new("src"), false),
|
||||||
(Path::new("src/a.rs"), false),
|
(RelPath::new("src/a.rs"), false),
|
||||||
(Path::new("src/b.rs"), false),
|
(RelPath::new("src/b.rs"), false),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mem::take(&mut *tree_updates.lock()),
|
mem::take(&mut *tree_updates.lock()),
|
||||||
&[
|
&[
|
||||||
(Path::new("deps/dep-dir3").into(), PathChange::Loaded),
|
(RelPath::new("deps/dep-dir3").into(), PathChange::Loaded),
|
||||||
(Path::new("deps/dep-dir3/deps").into(), PathChange::Loaded),
|
(
|
||||||
(Path::new("deps/dep-dir3/src").into(), PathChange::Loaded)
|
RelPath::new("deps/dep-dir3/deps").into(),
|
||||||
|
PathChange::Loaded
|
||||||
|
),
|
||||||
|
(RelPath::new("deps/dep-dir3/src").into(), PathChange::Loaded)
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -294,7 +299,7 @@ async fn test_symlinks_pointing_outside(cx: &mut TestAppContext) {
|
||||||
tree.read_with(cx, |tree, _| {
|
tree.read_with(cx, |tree, _| {
|
||||||
tree.as_local()
|
tree.as_local()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.refresh_entries_for_paths(vec![Path::new("deps/dep-dir3/src").into()])
|
.refresh_entries_for_paths(vec![RelPath::new("deps/dep-dir3/src").into()])
|
||||||
})
|
})
|
||||||
.recv()
|
.recv()
|
||||||
.await;
|
.await;
|
||||||
|
@ -306,17 +311,17 @@ async fn test_symlinks_pointing_outside(cx: &mut TestAppContext) {
|
||||||
.map(|entry| (entry.path.as_ref(), entry.is_external))
|
.map(|entry| (entry.path.as_ref(), entry.is_external))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
vec![
|
vec![
|
||||||
(Path::new(""), false),
|
(RelPath::new(""), false),
|
||||||
(Path::new("deps"), false),
|
(RelPath::new("deps"), false),
|
||||||
(Path::new("deps/dep-dir2"), true),
|
(RelPath::new("deps/dep-dir2"), true),
|
||||||
(Path::new("deps/dep-dir3"), true),
|
(RelPath::new("deps/dep-dir3"), true),
|
||||||
(Path::new("deps/dep-dir3/deps"), true),
|
(RelPath::new("deps/dep-dir3/deps"), true),
|
||||||
(Path::new("deps/dep-dir3/src"), true),
|
(RelPath::new("deps/dep-dir3/src"), true),
|
||||||
(Path::new("deps/dep-dir3/src/e.rs"), true),
|
(RelPath::new("deps/dep-dir3/src/e.rs"), true),
|
||||||
(Path::new("deps/dep-dir3/src/f.rs"), true),
|
(RelPath::new("deps/dep-dir3/src/f.rs"), true),
|
||||||
(Path::new("src"), false),
|
(RelPath::new("src"), false),
|
||||||
(Path::new("src/a.rs"), false),
|
(RelPath::new("src/a.rs"), false),
|
||||||
(Path::new("src/b.rs"), false),
|
(RelPath::new("src/b.rs"), false),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -324,13 +329,13 @@ async fn test_symlinks_pointing_outside(cx: &mut TestAppContext) {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mem::take(&mut *tree_updates.lock()),
|
mem::take(&mut *tree_updates.lock()),
|
||||||
&[
|
&[
|
||||||
(Path::new("deps/dep-dir3/src").into(), PathChange::Loaded),
|
(RelPath::new("deps/dep-dir3/src").into(), PathChange::Loaded),
|
||||||
(
|
(
|
||||||
Path::new("deps/dep-dir3/src/e.rs").into(),
|
RelPath::new("deps/dep-dir3/src/e.rs").into(),
|
||||||
PathChange::Loaded
|
PathChange::Loaded
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
Path::new("deps/dep-dir3/src/f.rs").into(),
|
RelPath::new("deps/dep-dir3/src/f.rs").into(),
|
||||||
PathChange::Loaded
|
PathChange::Loaded
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
@ -368,7 +373,7 @@ async fn test_renaming_case_only(cx: &mut TestAppContext) {
|
||||||
tree.entries(true, 0)
|
tree.entries(true, 0)
|
||||||
.map(|entry| entry.path.as_ref())
|
.map(|entry| entry.path.as_ref())
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
vec![Path::new(""), Path::new(OLD_NAME)]
|
vec![RelPath::new(""), RelPath::new(OLD_NAME)]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -390,7 +395,7 @@ async fn test_renaming_case_only(cx: &mut TestAppContext) {
|
||||||
tree.entries(true, 0)
|
tree.entries(true, 0)
|
||||||
.map(|entry| entry.path.as_ref())
|
.map(|entry| entry.path.as_ref())
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
vec![Path::new(""), Path::new(NEW_NAME)]
|
vec![RelPath::new(""), RelPath::new(NEW_NAME)]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -446,13 +451,13 @@ async fn test_open_gitignored_files(cx: &mut TestAppContext) {
|
||||||
.map(|entry| (entry.path.as_ref(), entry.is_ignored))
|
.map(|entry| (entry.path.as_ref(), entry.is_ignored))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
vec![
|
vec![
|
||||||
(Path::new(""), false),
|
(RelPath::new(""), false),
|
||||||
(Path::new(".gitignore"), false),
|
(RelPath::new(".gitignore"), false),
|
||||||
(Path::new("one"), false),
|
(RelPath::new("one"), false),
|
||||||
(Path::new("one/node_modules"), true),
|
(RelPath::new("one/node_modules"), true),
|
||||||
(Path::new("two"), false),
|
(RelPath::new("two"), false),
|
||||||
(Path::new("two/x.js"), false),
|
(RelPath::new("two/x.js"), false),
|
||||||
(Path::new("two/y.js"), false),
|
(RelPath::new("two/y.js"), false),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -473,24 +478,24 @@ async fn test_open_gitignored_files(cx: &mut TestAppContext) {
|
||||||
.map(|entry| (entry.path.as_ref(), entry.is_ignored))
|
.map(|entry| (entry.path.as_ref(), entry.is_ignored))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
vec![
|
vec![
|
||||||
(Path::new(""), false),
|
(RelPath::new(""), false),
|
||||||
(Path::new(".gitignore"), false),
|
(RelPath::new(".gitignore"), false),
|
||||||
(Path::new("one"), false),
|
(RelPath::new("one"), false),
|
||||||
(Path::new("one/node_modules"), true),
|
(RelPath::new("one/node_modules"), true),
|
||||||
(Path::new("one/node_modules/a"), true),
|
(RelPath::new("one/node_modules/a"), true),
|
||||||
(Path::new("one/node_modules/b"), true),
|
(RelPath::new("one/node_modules/b"), true),
|
||||||
(Path::new("one/node_modules/b/b1.js"), true),
|
(RelPath::new("one/node_modules/b/b1.js"), true),
|
||||||
(Path::new("one/node_modules/b/b2.js"), true),
|
(RelPath::new("one/node_modules/b/b2.js"), true),
|
||||||
(Path::new("one/node_modules/c"), true),
|
(RelPath::new("one/node_modules/c"), true),
|
||||||
(Path::new("two"), false),
|
(RelPath::new("two"), false),
|
||||||
(Path::new("two/x.js"), false),
|
(RelPath::new("two/x.js"), false),
|
||||||
(Path::new("two/y.js"), false),
|
(RelPath::new("two/y.js"), false),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
loaded.file.path.as_ref(),
|
loaded.file.path.as_ref(),
|
||||||
Path::new("one/node_modules/b/b1.js")
|
RelPath::new("one/node_modules/b/b1.js")
|
||||||
);
|
);
|
||||||
|
|
||||||
// Only the newly-expanded directories are scanned.
|
// Only the newly-expanded directories are scanned.
|
||||||
|
@ -513,26 +518,26 @@ async fn test_open_gitignored_files(cx: &mut TestAppContext) {
|
||||||
.map(|entry| (entry.path.as_ref(), entry.is_ignored))
|
.map(|entry| (entry.path.as_ref(), entry.is_ignored))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
vec![
|
vec![
|
||||||
(Path::new(""), false),
|
(RelPath::new(""), false),
|
||||||
(Path::new(".gitignore"), false),
|
(RelPath::new(".gitignore"), false),
|
||||||
(Path::new("one"), false),
|
(RelPath::new("one"), false),
|
||||||
(Path::new("one/node_modules"), true),
|
(RelPath::new("one/node_modules"), true),
|
||||||
(Path::new("one/node_modules/a"), true),
|
(RelPath::new("one/node_modules/a"), true),
|
||||||
(Path::new("one/node_modules/a/a1.js"), true),
|
(RelPath::new("one/node_modules/a/a1.js"), true),
|
||||||
(Path::new("one/node_modules/a/a2.js"), true),
|
(RelPath::new("one/node_modules/a/a2.js"), true),
|
||||||
(Path::new("one/node_modules/b"), true),
|
(RelPath::new("one/node_modules/b"), true),
|
||||||
(Path::new("one/node_modules/b/b1.js"), true),
|
(RelPath::new("one/node_modules/b/b1.js"), true),
|
||||||
(Path::new("one/node_modules/b/b2.js"), true),
|
(RelPath::new("one/node_modules/b/b2.js"), true),
|
||||||
(Path::new("one/node_modules/c"), true),
|
(RelPath::new("one/node_modules/c"), true),
|
||||||
(Path::new("two"), false),
|
(RelPath::new("two"), false),
|
||||||
(Path::new("two/x.js"), false),
|
(RelPath::new("two/x.js"), false),
|
||||||
(Path::new("two/y.js"), false),
|
(RelPath::new("two/y.js"), false),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
loaded.file.path.as_ref(),
|
loaded.file.path.as_ref(),
|
||||||
Path::new("one/node_modules/a/a2.js")
|
RelPath::new("one/node_modules/a/a2.js")
|
||||||
);
|
);
|
||||||
|
|
||||||
// Only the newly-expanded directory is scanned.
|
// Only the newly-expanded directory is scanned.
|
||||||
|
@ -592,7 +597,7 @@ async fn test_dirs_no_longer_ignored(cx: &mut TestAppContext) {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let tree = Worktree::local(
|
let tree = Worktree::local(
|
||||||
Path::new("/root"),
|
RelPath::new("/root"),
|
||||||
true,
|
true,
|
||||||
fs.clone(),
|
fs.clone(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
|
@ -610,7 +615,7 @@ async fn test_dirs_no_longer_ignored(cx: &mut TestAppContext) {
|
||||||
tree.read_with(cx, |tree, _| {
|
tree.read_with(cx, |tree, _| {
|
||||||
tree.as_local()
|
tree.as_local()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.refresh_entries_for_paths(vec![Path::new("node_modules/d/d.js").into()])
|
.refresh_entries_for_paths(vec![RelPath::new("node_modules/d/d.js").into()])
|
||||||
})
|
})
|
||||||
.recv()
|
.recv()
|
||||||
.await;
|
.await;
|
||||||
|
@ -622,18 +627,18 @@ async fn test_dirs_no_longer_ignored(cx: &mut TestAppContext) {
|
||||||
.map(|e| (e.path.as_ref(), e.is_ignored))
|
.map(|e| (e.path.as_ref(), e.is_ignored))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
&[
|
&[
|
||||||
(Path::new(""), false),
|
(RelPath::new(""), false),
|
||||||
(Path::new(".gitignore"), false),
|
(RelPath::new(".gitignore"), false),
|
||||||
(Path::new("a"), false),
|
(RelPath::new("a"), false),
|
||||||
(Path::new("a/a.js"), false),
|
(RelPath::new("a/a.js"), false),
|
||||||
(Path::new("b"), false),
|
(RelPath::new("b"), false),
|
||||||
(Path::new("b/b.js"), false),
|
(RelPath::new("b/b.js"), false),
|
||||||
(Path::new("node_modules"), true),
|
(RelPath::new("node_modules"), true),
|
||||||
(Path::new("node_modules/c"), true),
|
(RelPath::new("node_modules/c"), true),
|
||||||
(Path::new("node_modules/d"), true),
|
(RelPath::new("node_modules/d"), true),
|
||||||
(Path::new("node_modules/d/d.js"), true),
|
(RelPath::new("node_modules/d/d.js"), true),
|
||||||
(Path::new("node_modules/d/e"), true),
|
(RelPath::new("node_modules/d/e"), true),
|
||||||
(Path::new("node_modules/d/f"), true),
|
(RelPath::new("node_modules/d/f"), true),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -654,23 +659,23 @@ async fn test_dirs_no_longer_ignored(cx: &mut TestAppContext) {
|
||||||
.map(|e| (e.path.as_ref(), e.is_ignored))
|
.map(|e| (e.path.as_ref(), e.is_ignored))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
&[
|
&[
|
||||||
(Path::new(""), false),
|
(RelPath::new(""), false),
|
||||||
(Path::new(".gitignore"), false),
|
(RelPath::new(".gitignore"), false),
|
||||||
(Path::new("a"), false),
|
(RelPath::new("a"), false),
|
||||||
(Path::new("a/a.js"), false),
|
(RelPath::new("a/a.js"), false),
|
||||||
(Path::new("b"), false),
|
(RelPath::new("b"), false),
|
||||||
(Path::new("b/b.js"), false),
|
(RelPath::new("b/b.js"), false),
|
||||||
// This directory is no longer ignored
|
// This directory is no longer ignored
|
||||||
(Path::new("node_modules"), false),
|
(RelPath::new("node_modules"), false),
|
||||||
(Path::new("node_modules/c"), false),
|
(RelPath::new("node_modules/c"), false),
|
||||||
(Path::new("node_modules/c/c.js"), false),
|
(RelPath::new("node_modules/c/c.js"), false),
|
||||||
(Path::new("node_modules/d"), false),
|
(RelPath::new("node_modules/d"), false),
|
||||||
(Path::new("node_modules/d/d.js"), false),
|
(RelPath::new("node_modules/d/d.js"), false),
|
||||||
// This subdirectory is now ignored
|
// This subdirectory is now ignored
|
||||||
(Path::new("node_modules/d/e"), true),
|
(RelPath::new("node_modules/d/e"), true),
|
||||||
(Path::new("node_modules/d/f"), false),
|
(RelPath::new("node_modules/d/f"), false),
|
||||||
(Path::new("node_modules/d/f/f1.js"), false),
|
(RelPath::new("node_modules/d/f/f1.js"), false),
|
||||||
(Path::new("node_modules/d/f/f2.js"), false),
|
(RelPath::new("node_modules/d/f/f2.js"), false),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -711,7 +716,7 @@ async fn test_write_file(cx: &mut TestAppContext) {
|
||||||
worktree
|
worktree
|
||||||
.update(cx, |tree, cx| {
|
.update(cx, |tree, cx| {
|
||||||
tree.write_file(
|
tree.write_file(
|
||||||
Path::new("tracked-dir/file.txt"),
|
RelPath::new("tracked-dir/file.txt"),
|
||||||
"hello".into(),
|
"hello".into(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
cx,
|
cx,
|
||||||
|
@ -722,7 +727,7 @@ async fn test_write_file(cx: &mut TestAppContext) {
|
||||||
worktree
|
worktree
|
||||||
.update(cx, |tree, cx| {
|
.update(cx, |tree, cx| {
|
||||||
tree.write_file(
|
tree.write_file(
|
||||||
Path::new("ignored-dir/file.txt"),
|
RelPath::new("ignored-dir/file.txt"),
|
||||||
"world".into(),
|
"world".into(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
cx,
|
cx,
|
||||||
|
@ -1421,7 +1426,7 @@ async fn test_random_worktree_operations_during_initial_scan(
|
||||||
.map(|o| o.parse().unwrap())
|
.map(|o| o.parse().unwrap())
|
||||||
.unwrap_or(20);
|
.unwrap_or(20);
|
||||||
|
|
||||||
let root_dir = Path::new(path!("/test"));
|
let root_dir = RelPath::new(path!("/test"));
|
||||||
let fs = FakeFs::new(cx.background_executor.clone()) as Arc<dyn Fs>;
|
let fs = FakeFs::new(cx.background_executor.clone()) as Arc<dyn Fs>;
|
||||||
fs.as_fake().insert_tree(root_dir, json!({})).await;
|
fs.as_fake().insert_tree(root_dir, json!({})).await;
|
||||||
for _ in 0..initial_entries {
|
for _ in 0..initial_entries {
|
||||||
|
@ -1512,7 +1517,7 @@ async fn test_random_worktree_changes(cx: &mut TestAppContext, mut rng: StdRng)
|
||||||
.map(|o| o.parse().unwrap())
|
.map(|o| o.parse().unwrap())
|
||||||
.unwrap_or(20);
|
.unwrap_or(20);
|
||||||
|
|
||||||
let root_dir = Path::new(path!("/test"));
|
let root_dir = RelPath::new(path!("/test"));
|
||||||
let fs = FakeFs::new(cx.background_executor.clone()) as Arc<dyn Fs>;
|
let fs = FakeFs::new(cx.background_executor.clone()) as Arc<dyn Fs>;
|
||||||
fs.as_fake().insert_tree(root_dir, json!({})).await;
|
fs.as_fake().insert_tree(root_dir, json!({})).await;
|
||||||
for _ in 0..initial_entries {
|
for _ in 0..initial_entries {
|
||||||
|
@ -1702,11 +1707,11 @@ fn randomly_mutate_worktree(
|
||||||
let entry = snapshot.entries(false, 0).choose(rng).unwrap();
|
let entry = snapshot.entries(false, 0).choose(rng).unwrap();
|
||||||
|
|
||||||
match rng.gen_range(0_u32..100) {
|
match rng.gen_range(0_u32..100) {
|
||||||
0..=33 if entry.path.as_ref() != Path::new("") => {
|
0..=33 if entry.path.as_ref() != RelPath::new("") => {
|
||||||
log::info!("deleting entry {:?} ({})", entry.path, entry.id.0);
|
log::info!("deleting entry {:?} ({})", entry.path, entry.id.0);
|
||||||
worktree.delete_entry(entry.id, false, cx).unwrap()
|
worktree.delete_entry(entry.id, false, cx).unwrap()
|
||||||
}
|
}
|
||||||
..=66 if entry.path.as_ref() != Path::new("") => {
|
..=66 if entry.path.as_ref() != RelPath::new("") => {
|
||||||
let other_entry = snapshot.entries(false, 0).choose(rng).unwrap();
|
let other_entry = snapshot.entries(false, 0).choose(rng).unwrap();
|
||||||
let new_parent_path = if other_entry.is_dir() {
|
let new_parent_path = if other_entry.is_dir() {
|
||||||
other_entry.path.clone()
|
other_entry.path.clone()
|
||||||
|
@ -1759,7 +1764,7 @@ fn randomly_mutate_worktree(
|
||||||
|
|
||||||
async fn randomly_mutate_fs(
|
async fn randomly_mutate_fs(
|
||||||
fs: &Arc<dyn Fs>,
|
fs: &Arc<dyn Fs>,
|
||||||
root_path: &Path,
|
root_path: &RelPath,
|
||||||
insertion_probability: f64,
|
insertion_probability: f64,
|
||||||
rng: &mut impl Rng,
|
rng: &mut impl Rng,
|
||||||
) {
|
) {
|
||||||
|
@ -1931,7 +1936,7 @@ async fn test_private_single_file_worktree(cx: &mut TestAppContext) {
|
||||||
fs.insert_tree("/", json!({".env": "PRIVATE=secret\n"}))
|
fs.insert_tree("/", json!({".env": "PRIVATE=secret\n"}))
|
||||||
.await;
|
.await;
|
||||||
let tree = Worktree::local(
|
let tree = Worktree::local(
|
||||||
Path::new("/.env"),
|
RelPath::new("/.env"),
|
||||||
true,
|
true,
|
||||||
fs.clone(),
|
fs.clone(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
|
@ -1952,18 +1957,18 @@ fn test_unrelativize() {
|
||||||
let work_directory = WorkDirectory::in_project("");
|
let work_directory = WorkDirectory::in_project("");
|
||||||
pretty_assertions::assert_eq!(
|
pretty_assertions::assert_eq!(
|
||||||
work_directory.try_unrelativize(&"crates/gpui/gpui.rs".into()),
|
work_directory.try_unrelativize(&"crates/gpui/gpui.rs".into()),
|
||||||
Some(Path::new("crates/gpui/gpui.rs").into())
|
Some(RelPath::new("crates/gpui/gpui.rs").into())
|
||||||
);
|
);
|
||||||
|
|
||||||
let work_directory = WorkDirectory::in_project("vendor/some-submodule");
|
let work_directory = WorkDirectory::in_project("vendor/some-submodule");
|
||||||
pretty_assertions::assert_eq!(
|
pretty_assertions::assert_eq!(
|
||||||
work_directory.try_unrelativize(&"src/thing.c".into()),
|
work_directory.try_unrelativize(&"src/thing.c".into()),
|
||||||
Some(Path::new("vendor/some-submodule/src/thing.c").into())
|
Some(RelPath::new("vendor/some-submodule/src/thing.c").into())
|
||||||
);
|
);
|
||||||
|
|
||||||
let work_directory = WorkDirectory::AboveProject {
|
let work_directory = WorkDirectory::AboveProject {
|
||||||
absolute_path: Path::new("/projects/zed").into(),
|
absolute_path: RelPath::new("/projects/zed").into(),
|
||||||
location_in_repo: Path::new("crates/gpui").into(),
|
location_in_repo: RelPath::new("crates/gpui").into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
pretty_assertions::assert_eq!(
|
pretty_assertions::assert_eq!(
|
||||||
|
@ -1973,14 +1978,14 @@ fn test_unrelativize() {
|
||||||
|
|
||||||
pretty_assertions::assert_eq!(
|
pretty_assertions::assert_eq!(
|
||||||
work_directory.unrelativize(&"crates/util/util.rs".into()),
|
work_directory.unrelativize(&"crates/util/util.rs".into()),
|
||||||
Path::new("../util/util.rs").into()
|
RelPath::new("../util/util.rs").into()
|
||||||
);
|
);
|
||||||
|
|
||||||
pretty_assertions::assert_eq!(work_directory.try_unrelativize(&"README.md".into()), None,);
|
pretty_assertions::assert_eq!(work_directory.try_unrelativize(&"README.md".into()), None,);
|
||||||
|
|
||||||
pretty_assertions::assert_eq!(
|
pretty_assertions::assert_eq!(
|
||||||
work_directory.unrelativize(&"README.md".into()),
|
work_directory.unrelativize(&"README.md".into()),
|
||||||
Path::new("../../README.md").into()
|
RelPath::new("../../README.md").into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2023,7 +2028,7 @@ async fn test_repository_above_root(executor: BackgroundExecutor, cx: &mut TestA
|
||||||
.map(|entry| entry.work_directory_abs_path.clone())
|
.map(|entry| entry.work_directory_abs_path.clone())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
});
|
});
|
||||||
pretty_assertions::assert_eq!(repos, [Path::new(path!("/root")).into()]);
|
pretty_assertions::assert_eq!(repos, [RelPath::new(path!("/root")).into()]);
|
||||||
|
|
||||||
eprintln!(">>>>>>>>>> touch");
|
eprintln!(">>>>>>>>>> touch");
|
||||||
fs.touch_path(path!("/root/subproject")).await;
|
fs.touch_path(path!("/root/subproject")).await;
|
||||||
|
@ -2043,7 +2048,7 @@ async fn test_repository_above_root(executor: BackgroundExecutor, cx: &mut TestA
|
||||||
.map(|entry| entry.work_directory_abs_path.clone())
|
.map(|entry| entry.work_directory_abs_path.clone())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
});
|
});
|
||||||
pretty_assertions::assert_eq!(repos, [Path::new(path!("/root")).into()]);
|
pretty_assertions::assert_eq!(repos, [RelPath::new(path!("/root")).into()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue