Skip to content

Commit 0596e79

Browse files
authored
refactor(pm): tokio fs (#2219)
* refactor: tokio fs * fix: ci
1 parent abc55a6 commit 0596e79

27 files changed

+331
-269
lines changed

crates/pm/src/cmd/config.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,18 @@ fn parse_key_val(s: &str) -> Result<(String, String)> {
1010
Ok((s[..pos].to_string(), s[pos + 1..].to_string()))
1111
}
1212

13-
pub fn handle_config_set(key: String, value: String, global: bool) -> Result<()> {
14-
let mut config = Config::load(global)?;
13+
pub async fn handle_config_set(key: String, value: String, global: bool) -> Result<()> {
14+
let mut config = Config::load(global).await?;
1515
config.set(&key, value, global)?;
1616
println!("Successfully set {key} (global: {global})");
1717
Ok(())
1818
}
1919

20-
pub fn handle_config_get(key: String, global: bool, override_values: Vec<String>) -> Result<()> {
20+
pub async fn handle_config_get(
21+
key: String,
22+
global: bool,
23+
override_values: Vec<String>,
24+
) -> Result<()> {
2125
let overrides: HashMap<String, String> = override_values
2226
.iter()
2327
.filter_map(|arg| arg.strip_prefix("--").and_then(|s| parse_key_val(s).ok()))
@@ -26,7 +30,7 @@ pub fn handle_config_get(key: String, global: bool, override_values: Vec<String>
2630
if let Some(value) = overrides.get(&key) {
2731
println!("{value}");
2832
} else {
29-
let config = Config::load(global)?;
33+
let config = Config::load(global).await?;
3034
match config.get(&key)? {
3135
Some(value) => println!("{value}"),
3236
None => {
@@ -38,8 +42,8 @@ pub fn handle_config_get(key: String, global: bool, override_values: Vec<String>
3842
Ok(())
3943
}
4044

41-
pub fn handle_config_list(global: bool) -> Result<()> {
42-
let config = Config::load(global)?;
45+
pub async fn handle_config_list(global: bool) -> Result<()> {
46+
let config = Config::load(global).await?;
4347
let config_path = if global {
4448
config.get_global_config_path()?
4549
} else {

crates/pm/src/cmd/link.rs

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ pub async fn link_current_to_global(prefix: Option<&str>) -> Result<()> {
1212
let project_path = update_cwd_to_project(&cwd).await?;
1313

1414
// Create package info from path
15-
let package_info = PackageInfo::from_path(&project_path).with_context(|| {
16-
format!(
17-
"Failed to parse package info from path: {}",
18-
project_path.display()
19-
)
20-
})?;
15+
let package_info = PackageInfo::from_path(&project_path)
16+
.await
17+
.with_context(|| {
18+
format!(
19+
"Failed to parse package info from path: {}",
20+
project_path.display()
21+
)
22+
})?;
2123

2224
// Install dependencies
2325
install(false, &project_path).await.map_err(|e| {
@@ -26,13 +28,15 @@ pub async fn link_current_to_global(prefix: Option<&str>) -> Result<()> {
2628

2729
let global_package_path = get_global_package_dir(prefix)?.join(&package_info.name);
2830
// link local project to global package
29-
link(&project_path, &global_package_path).with_context(|| {
30-
format!(
31-
"Failed to link local project to global package: {} -> {}",
32-
project_path.display(),
33-
global_package_path.display()
34-
)
35-
})?;
31+
link(&project_path, &global_package_path)
32+
.await
33+
.with_context(|| {
34+
format!(
35+
"Failed to link local project to global package: {} -> {}",
36+
project_path.display(),
37+
global_package_path.display()
38+
)
39+
})?;
3640
// If the package has binary files, also link them to global bin directory
3741
if package_info.has_bin_files() {
3842
let global_bin_dir = global_package_path.join("bin");
@@ -58,22 +62,26 @@ pub async fn link_global_to_local(package_name: &str, prefix: Option<&str>) -> R
5862
let global_package_path = get_global_package_dir(prefix)?.join(package_name);
5963

6064
// Create package info from path
61-
let package_info = PackageInfo::from_path(&global_package_path).with_context(|| {
62-
format!(
63-
"Failed to parse package info from path: {}",
64-
global_package_path.display()
65-
)
66-
})?;
65+
let package_info = PackageInfo::from_path(&global_package_path)
66+
.await
67+
.with_context(|| {
68+
format!(
69+
"Failed to parse package info from path: {}",
70+
global_package_path.display()
71+
)
72+
})?;
6773

6874
// Create symlink from global package to local project
6975
let local_link_path = project_path.join("node_modules/").join(package_name);
70-
link(&global_package_path, &local_link_path).with_context(|| {
71-
format!(
72-
"Failed to link global package to local: {} -> {}",
73-
global_package_path.display(),
74-
local_link_path.display()
75-
)
76-
})?;
76+
link(&global_package_path, &local_link_path)
77+
.await
78+
.with_context(|| {
79+
format!(
80+
"Failed to link global package to local: {} -> {}",
81+
global_package_path.display(),
82+
local_link_path.display()
83+
)
84+
})?;
7785

7886
log_verbose(&format!(
7987
"link global package to local: {} -> {}",

crates/pm/src/cmd/list.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub async fn list_dependencies(cwd: &Path, package_name: &str) -> Result<()> {
1313

1414
// Find package-lock.json file
1515
let lock_file_path = cwd.join("package-lock.json");
16-
if !lock_file_path.exists() {
16+
if !tokio::fs::try_exists(&lock_file_path).await? {
1717
return Err(anyhow::anyhow!(
1818
"package-lock.json not found in current directory"
1919
));

crates/pm/src/cmd/rebuild.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::path::Path;
44

55
pub async fn rebuild(root_path: &Path) -> Result<()> {
66
let packages = PackageService::collect_packages(root_path)
7+
.await
78
.map_err(|e| anyhow::anyhow!("Failed to collect packages: {}", e))?;
89

910
let execution_queues = PackageService::create_execution_queues(packages)

crates/pm/src/cmd/run.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ pub async fn run_script(
5252
workspace_name,
5353
workspace_dir.display()
5454
));
55-
load_package_json_from_path(&workspace_dir)?
55+
load_package_json_from_path(&workspace_dir).await?
5656
} else {
57-
load_package_json_from_path(&updated_cwd)?
57+
load_package_json_from_path(&updated_cwd).await?
5858
};
5959

6060
let (scope, name, fullname) =
@@ -141,7 +141,7 @@ async fn need_run(cwd: &Path, workspace_name: &str, script_name: &str) -> Result
141141
};
142142

143143
// Load package.json from workspace
144-
let pkg = match load_package_json_from_path(&workspace_dir) {
144+
let pkg = match load_package_json_from_path(&workspace_dir).await {
145145
Ok(pkg) => pkg,
146146
Err(_) => {
147147
log_info(&format!(

crates/pm/src/helper/auto_update.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ async fn execute_update(version: &str) -> Result<()> {
137137

138138
/// Fast remote version check - short timeout, quick failure
139139
async fn check_remote_version_fast() -> Result<VersionCache> {
140-
let registry_url = format!("{}/utoo/latest", get_registry());
140+
let registry_url = format!("{}/utoo/latest", get_registry().await);
141141
let client = reqwest::Client::builder()
142142
.timeout(std::time::Duration::from_millis(1000)) // 1 second timeout
143143
.build()
@@ -306,8 +306,8 @@ mod tests {
306306
}
307307
}
308308

309-
#[test]
310-
fn test_save_and_read_version_cache() -> Result<()> {
309+
#[tokio::test]
310+
async fn test_save_and_read_version_cache() -> Result<()> {
311311
let temp_dir = tempfile::tempdir()?;
312312
let cache_path = temp_dir.path().join(".utoo").join("remote-version.json");
313313

@@ -318,15 +318,15 @@ mod tests {
318318

319319
// Create directory structure
320320
if let Some(parent) = cache_path.parent() {
321-
std::fs::create_dir_all(parent)?;
321+
tokio::fs::create_dir_all(parent).await?;
322322
}
323323

324324
// Test serialization and file writing manually (without using global HOME)
325325
let content = serde_json::to_string(&cache)?;
326-
std::fs::write(&cache_path, &content)?;
326+
tokio::fs::write(&cache_path, &content).await?;
327327

328328
// Test reading and deserialization
329-
let read_content = std::fs::read_to_string(cache_path)?;
329+
let read_content = tokio::fs::read_to_string(cache_path).await?;
330330
let loaded_cache: VersionCache = serde_json::from_str(&read_content)?;
331331

332332
assert_eq!(loaded_cache.version, cache.version);

crates/pm/src/helper/lock.rs

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,17 @@ fn deps_fields_equal(pkg_field: Option<&Value>, lock_field: Option<&Value>) -> b
7575

7676
pub async fn ensure_package_lock(root_path: &Path) -> Result<()> {
7777
// check package.json exists in cwd
78-
if fs::metadata(root_path.join("package.json")).is_err() {
78+
if tokio::fs::metadata(root_path.join("package.json"))
79+
.await
80+
.is_err()
81+
{
7982
return Err(anyhow!("package.json not found"));
8083
}
8184
// check package-lock.json exists in cwd
82-
if fs::metadata(root_path.join("package-lock.json")).is_err() {
85+
if tokio::fs::metadata(root_path.join("package-lock.json"))
86+
.await
87+
.is_err()
88+
{
8389
log_info("Resolving dependencies");
8490
build_deps(root_path).await?;
8591
Ok(())
@@ -124,7 +130,8 @@ pub async fn update_package_json(
124130

125131
// 3. Read package.json once
126132
let package_json_path = target_dir.join("package.json");
127-
let mut package_json: Value = serde_json::from_reader(fs::File::open(&package_json_path)?)?;
133+
let package_json_content = tokio::fs::read_to_string(&package_json_path).await?;
134+
let mut package_json: Value = serde_json::from_str(&package_json_content)?;
128135

129136
let dep_field = match save_type {
130137
SaveType::Dev => "devDependencies",
@@ -161,10 +168,11 @@ pub async fn update_package_json(
161168
}
162169

163170
// 6. Write back to package.json once
164-
fs::write(
171+
tokio::fs::write(
165172
&package_json_path,
166173
serde_json::to_string_pretty(&package_json)?,
167-
)?;
174+
)
175+
.await?;
168176

169177
Ok(())
170178
}
@@ -212,7 +220,7 @@ pub async fn prepare_global_package_json(npm_spec: &str, prefix: Option<&str>) -
212220
let cache_flag_path = cache_dir.join(format!("{}/{}/_resolved", name, resolved.version));
213221

214222
// Download if not cached
215-
if !cache_flag_path.exists() {
223+
if !tokio::fs::try_exists(&cache_flag_path).await? {
216224
log_verbose(&format!(
217225
"Downloading {} to {}",
218226
tarball_url,
@@ -227,7 +235,7 @@ pub async fn prepare_global_package_json(npm_spec: &str, prefix: Option<&str>) -
227235
// so we need to copy the file to the package directory to avoid effect other packages
228236
if resolved.manifest.get("hasInstallScript") == Some(&json!(true)) {
229237
let has_install_script_flag_path = cache_path.join("_hasInstallScript");
230-
fs::write(has_install_script_flag_path, "")?;
238+
tokio::fs::write(has_install_script_flag_path, "").await?;
231239
}
232240
}
233241

@@ -243,7 +251,8 @@ pub async fn prepare_global_package_json(npm_spec: &str, prefix: Option<&str>) -
243251

244252
// Remove devDependencies from package.json
245253
let package_json_path = package_path.join("package.json");
246-
let mut package_json: Value = serde_json::from_reader(fs::File::open(&package_json_path)?)?;
254+
let package_json_content = tokio::fs::read_to_string(&package_json_path).await?;
255+
let mut package_json: Value = serde_json::from_str(&package_json_content)?;
247256

248257
// Remove specified dependency fields and scripts.prepare
249258
let package_obj = package_json.as_object_mut().unwrap();
@@ -258,10 +267,11 @@ pub async fn prepare_global_package_json(npm_spec: &str, prefix: Option<&str>) -
258267
}
259268

260269
// Write back the modified package.json
261-
fs::write(
270+
tokio::fs::write(
262271
&package_json_path,
263272
serde_json::to_string_pretty(&package_json)?,
264-
)?;
273+
)
274+
.await?;
265275

266276
log_verbose(&format!("package_path: {}", package_path.to_string_lossy()));
267277
Ok(package_path)
@@ -290,8 +300,8 @@ pub struct InvalidDependency {
290300
}
291301

292302
pub async fn is_pkg_lock_outdated(root_path: &Path) -> Result<bool> {
293-
let pkg_file = load_package_json_from_path(root_path)?;
294-
let lock_file = load_package_lock_json_from_path(root_path)?;
303+
let pkg_file = load_package_json_from_path(root_path).await?;
304+
let lock_file = load_package_lock_json_from_path(root_path).await?;
295305

296306
// get packages in package-lock.json
297307
let packages = lock_file
@@ -323,7 +333,7 @@ pub async fn is_pkg_lock_outdated(root_path: &Path) -> Result<bool> {
323333
};
324334

325335
// check dependencies whether changed
326-
for (dep_field, _is_optional) in get_dep_types() {
336+
for (dep_field, _is_optional) in get_dep_types().await {
327337
if !deps_fields_equal(pkg.get(dep_field), lock.get(dep_field)) {
328338
let name = if path.is_empty() { "root" } else { &path };
329339
log_warning(&format!(
@@ -353,7 +363,7 @@ pub async fn validate_deps(
353363

354364
if let Some(packages) = pkgs_in_pkg_lock.as_object() {
355365
for (pkg_path, pkg_info) in packages {
356-
for (dep_field, is_optional) in get_dep_types() {
366+
for (dep_field, is_optional) in get_dep_types().await {
357367
if let Some(dependencies) = pkg_info.get(dep_field).and_then(|d| d.as_object()) {
358368
for (dep_name, req_version) in dependencies {
359369
let req_version_str = req_version.as_str().unwrap_or_default();
@@ -474,8 +484,8 @@ pub async fn validate_deps(
474484
Ok(invalid_deps)
475485
}
476486

477-
fn get_dep_types() -> Vec<(&'static str, bool)> {
478-
let legacy_peer_deps = get_legacy_peer_deps();
487+
async fn get_dep_types() -> Vec<(&'static str, bool)> {
488+
let legacy_peer_deps = get_legacy_peer_deps().await;
479489

480490
if legacy_peer_deps {
481491
vec![

crates/pm/src/helper/ruborist.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use once_cell::sync::Lazy;
3030
static CONCURRENCY_LIMITER: Lazy<Arc<Semaphore>> = Lazy::new(|| Arc::new(Semaphore::new(100)));
3131

3232
pub async fn build_deps(root: Arc<Node>) -> Result<()> {
33-
let legacy_peer_deps = get_legacy_peer_deps();
33+
let legacy_peer_deps = get_legacy_peer_deps().await;
3434
log_verbose(&format!(
3535
"going to build deps for {root}, legacy_peer_deps: {legacy_peer_deps}"
3636
));
@@ -353,7 +353,7 @@ impl Ruborist {
353353

354354
async fn init_tree(&mut self) -> Result<Arc<Node>> {
355355
// load package.json
356-
let pkg = load_package_json_from_path(&self.path)?;
356+
let pkg = load_package_json_from_path(&self.path).await?;
357357

358358
// create root node
359359
let root = Node::new_root(
@@ -367,7 +367,7 @@ impl Ruborist {
367367
self.init_workspaces(root.clone()).await?;
368368

369369
// collect deps type
370-
let legacy_peer_deps = get_legacy_peer_deps();
370+
let legacy_peer_deps = get_legacy_peer_deps().await;
371371
let dep_types = if legacy_peer_deps {
372372
vec![
373373
("dependencies", EdgeType::Prod),
@@ -465,7 +465,7 @@ impl Ruborist {
465465
));
466466

467467
// Process workspace dependencies
468-
let legacy_peer_deps = get_legacy_peer_deps();
468+
let legacy_peer_deps = get_legacy_peer_deps().await;
469469
let dep_types = if legacy_peer_deps {
470470
vec![
471471
("devDependencies", EdgeType::Dev),

0 commit comments

Comments
 (0)