-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(core): use rust utilities for caching operations #17638
Changes from all commits
426b292
963e29c
3ea3fea
ad6b243
c6fccb8
6e5787e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,32 +4,31 @@ version = '0.1.0' | |
edition = '2021' | ||
|
||
[dependencies] | ||
xxhash-rust = { version = '0.8.5', features = ['xxh3', 'xxh64'] } | ||
napi = { version = '2.12.6', default-features = false, features = ['anyhow', 'napi4', 'tokio_rt'] } | ||
napi-derive = '2.9.3' | ||
ignore = '0.4' | ||
anyhow = "1.0.71" | ||
colored = "2" | ||
crossbeam-channel = '0.5' | ||
|
||
fs_extra = "1.3.0" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is new too right? |
||
globset = "0.4.10" | ||
hashbrown = { version = "0.14.0", features = ["rayon"] } | ||
ignore = '0.4' | ||
ignore-files = "1.3.0" | ||
watchexec = "2.3.0" | ||
watchexec-filterer-ignore = "1.2.1" | ||
watchexec-events = "1.0.0" | ||
watchexec-signals = "1.0.0" | ||
|
||
tracing = "0.1.37" | ||
tracing-subscriber = { version = "0.3.17", features = ["env-filter"]} | ||
anyhow = "1.0.71" | ||
thiserror = "1.0.40" | ||
itertools = "0.10.5" | ||
jsonc-parser = { version = "0.21.1", features = ["serde"] } | ||
napi = { version = '2.12.6', default-features = false, features = ['anyhow', 'napi4', 'tokio_rt'] } | ||
napi-derive = '2.9.3' | ||
rayon = "1.7.0" | ||
hashbrown = {version = "0.14.0", features = ["rayon"]} | ||
|
||
serde = { version = "1.0", features = ["derive"] } | ||
serde_json = "1.0" | ||
jsonc-parser = {version = "0.21.1", features = ["serde"] } | ||
|
||
colored = "2" | ||
thiserror = "1.0.40" | ||
tokio = { version = "1.28.2", features = ["fs"] } | ||
tracing = "0.1.37" | ||
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } | ||
walkdir = '2.3.3' | ||
watchexec = "2.3.0" | ||
watchexec-events = "1.0.0" | ||
watchexec-filterer-ignore = "1.2.1" | ||
watchexec-signals = "1.0.0" | ||
xxhash-rust = { version = '0.8.5', features = ['xxh3', 'xxh64'] } | ||
|
||
[lib] | ||
crate-type = ['cdylib'] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
use std::path::PathBuf; | ||
|
||
use crate::native::utils::glob::build_glob_set; | ||
use crate::native::utils::path::Normalize; | ||
use crate::native::walker::nx_walker_sync; | ||
|
||
#[napi] | ||
/// Expands the given entries into a list of existing files. | ||
/// First checks if the entry exists, if not, it will glob the working directory to find the file. | ||
pub fn expand_outputs(directory: String, entries: Vec<String>) -> anyhow::Result<Vec<String>> { | ||
let directory: PathBuf = directory.into(); | ||
|
||
let (existing_paths, not_found): (Vec<_>, Vec<_>) = entries.into_iter().partition(|entry| { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we rename |
||
let path = directory.join(entry); | ||
path.exists() | ||
}); | ||
|
||
if not_found.is_empty() { | ||
return Ok(existing_paths); | ||
} | ||
|
||
let glob_set = build_glob_set(not_found)?; | ||
let found_paths = nx_walker_sync(directory) | ||
.filter_map(|path| { | ||
if glob_set.is_match(&path) { | ||
Some(path.to_normalized_string()) | ||
} else { | ||
None | ||
} | ||
}) | ||
.chain(existing_paths); | ||
|
||
Ok(found_paths.collect()) | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use super::*; | ||
use assert_fs::prelude::*; | ||
use assert_fs::TempDir; | ||
use std::{assert_eq, vec}; | ||
|
||
fn setup_fs() -> TempDir { | ||
let temp = TempDir::new().unwrap(); | ||
temp.child("test.txt").touch().unwrap(); | ||
temp.child("foo.txt").touch().unwrap(); | ||
temp.child("bar.txt").touch().unwrap(); | ||
temp.child("baz").child("qux.txt").touch().unwrap(); | ||
temp.child("nested") | ||
.child("deeply") | ||
.child("nx.darwin-arm64.node") | ||
.touch() | ||
.unwrap(); | ||
temp.child("folder").child("nested-folder").touch().unwrap(); | ||
temp.child("packages") | ||
.child("nx") | ||
.child("src") | ||
.child("native") | ||
.child("nx.darwin-arm64.node") | ||
.touch() | ||
.unwrap(); | ||
temp | ||
} | ||
#[test] | ||
fn should_expand_outputs() { | ||
let temp = setup_fs(); | ||
let entries = vec![ | ||
"packages/nx/src/native/*.node".to_string(), | ||
"folder/nested-folder".to_string(), | ||
"test.txt".to_string(), | ||
]; | ||
let mut result = expand_outputs(temp.display().to_string(), entries).unwrap(); | ||
result.sort(); | ||
assert_eq!( | ||
result, | ||
vec![ | ||
"folder/nested-folder", | ||
"packages/nx/src/native/nx.darwin-arm64.node", | ||
"test.txt" | ||
] | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,65 @@ | ||||||||||||||
use std::fs; | ||||||||||||||
use std::path::PathBuf; | ||||||||||||||
|
||||||||||||||
#[napi] | ||||||||||||||
pub fn remove(src: String) -> anyhow::Result<()> { | ||||||||||||||
fs_extra::remove_items(&[src]).map_err(anyhow::Error::from) | ||||||||||||||
} | ||||||||||||||
Comment on lines
+5
to
+7
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see a reason why we wouldn't expose the ability to remove multiple. In theory, it makes no difference but it's a little cleaner I guess. Is there a way to get the At the very least, we can make
Suggested change
|
||||||||||||||
|
||||||||||||||
#[napi] | ||||||||||||||
pub fn copy(src: String, dest: String) -> anyhow::Result<()> { | ||||||||||||||
let copy_options = fs_extra::dir::CopyOptions::new() | ||||||||||||||
.overwrite(true) | ||||||||||||||
.skip_exist(false); | ||||||||||||||
|
||||||||||||||
let dest: PathBuf = dest.into(); | ||||||||||||||
let dest_parent = dest.parent().unwrap_or(&dest); | ||||||||||||||
|
||||||||||||||
if !dest_parent.exists() { | ||||||||||||||
fs::create_dir_all(dest_parent)?; | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
fs_extra::copy_items(&[src], dest_parent, ©_options)?; | ||||||||||||||
Ok(()) | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
#[cfg(test)] | ||||||||||||||
mod test { | ||||||||||||||
use super::*; | ||||||||||||||
use assert_fs::prelude::*; | ||||||||||||||
use assert_fs::TempDir; | ||||||||||||||
|
||||||||||||||
#[test] | ||||||||||||||
fn should_copy_directories() { | ||||||||||||||
let temp = TempDir::new().unwrap(); | ||||||||||||||
temp.child("parent") | ||||||||||||||
.child("child") | ||||||||||||||
.child("grand-child") | ||||||||||||||
.child(".config") | ||||||||||||||
.child("file.txt") | ||||||||||||||
.touch() | ||||||||||||||
.unwrap(); | ||||||||||||||
let src = temp.join("parent/child/grand-child/.config"); | ||||||||||||||
let dest = temp.join("new-parent/child/grand-child/.config"); | ||||||||||||||
copy(src.to_string_lossy().into(), dest.to_string_lossy().into()).unwrap(); | ||||||||||||||
|
||||||||||||||
assert!(temp | ||||||||||||||
.child("new-parent/child/grand-child/.config/file.txt") | ||||||||||||||
.exists()); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
#[test] | ||||||||||||||
fn should_copy_single_files() { | ||||||||||||||
let temp = TempDir::new().unwrap(); | ||||||||||||||
temp.child("parent") | ||||||||||||||
.child("file.txt") | ||||||||||||||
.write_str("content") | ||||||||||||||
.unwrap(); | ||||||||||||||
|
||||||||||||||
let src = temp.join("parent/file.txt"); | ||||||||||||||
let dest = temp.join("new-parent/file.txt"); | ||||||||||||||
copy(src.to_string_lossy().into(), dest.to_string_lossy().into()).unwrap(); | ||||||||||||||
|
||||||||||||||
assert!(temp.child("new-parent/file.txt").exists()); | ||||||||||||||
} | ||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
pub mod expand_outputs; | ||
pub mod file_ops; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,8 @@ | ||
pub mod cache; | ||
pub mod hasher; | ||
mod logger; | ||
mod parallel_walker; | ||
mod types; | ||
mod utils; | ||
mod walker; | ||
pub mod watch; | ||
pub mod workspace; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,29 @@ | ||
use std::path::Path; | ||
|
||
pub trait Normalize { | ||
fn to_normalized_string(&self) -> String; | ||
} | ||
|
||
impl Normalize for std::path::Path { | ||
fn to_normalized_string(&self) -> String { | ||
// convert back-slashes in Windows paths, since the js expects only forward-slash path separators | ||
if cfg!(windows) { | ||
self.display().to_string().replace('\\', "/") | ||
} else { | ||
self.display().to_string() | ||
} | ||
normalize_path(self) | ||
} | ||
} | ||
|
||
impl Normalize for std::path::PathBuf { | ||
fn to_normalized_string(&self) -> String { | ||
normalize_path(self) | ||
} | ||
} | ||
|
||
fn normalize_path<P>(path: P) -> String | ||
where | ||
P: AsRef<Path>, | ||
{ | ||
// convert back-slashes in Windows paths, since the js expects only forward-slash path separators | ||
if cfg!(windows) { | ||
path.as_ref().display().to_string().replace('\\', "/") | ||
} else { | ||
path.as_ref().display().to_string() | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added
walkdir
and alphabetized the list