Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion crates/pm/src/cmd/config.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::util::config::Config;
use crate::util::config_file::Config;
use anyhow::{Result, anyhow};
use std::collections::HashMap;

Expand Down Expand Up @@ -56,5 +56,8 @@ pub async fn handle_config_list(global: bool) -> Result<()> {
for (key, value) in config.list()? {
println!("{key} = {value}");
}
for (key, values) in config.list_arrays() {
println!("{key} = [{}]", values.join(", "));
}
Ok(())
}
2 changes: 1 addition & 1 deletion crates/pm/src/cmd/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use anyhow::Result;
use std::path::Path;

use crate::service::install::InstallService;
use crate::util::config::get_omit;
use crate::util::save_type::{PackageAction, SaveType};
use crate::util::user_config::get_omit;

pub async fn update_packages(
action: PackageAction,
Expand Down
1 change: 1 addition & 0 deletions crates/pm/src/cmd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub mod init;
pub mod install;
pub mod link;
pub mod list;
pub mod ping;
pub mod rebuild;
pub mod run;
pub mod update;
Expand Down
40 changes: 40 additions & 0 deletions crates/pm/src/cmd/ping.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use anyhow::Result;
use colored::Colorize;

use crate::util::registry::ping_registry;
use crate::util::user_config::{detect_supports_semver, get_registry};

pub async fn ping(registry: Option<&str>) -> Result<()> {
let registry = registry.map(String::from).unwrap_or_else(get_registry);

println!("{} {}", "PING".green(), registry.cyan());

let client = reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(10))
.build()?;

let result = ping_registry(&client, &registry).await;

if result.success {
let supports = detect_supports_semver(&registry, Some(&client)).await;
let semver_info = if supports {
"supports-semver: yes".green()
} else {
"supports-semver: no".yellow()
};
println!(
"{} {}ms ({})",
"PONG".green(),
result.latency_ms.to_string().cyan(),
semver_info
);
} else {
anyhow::bail!(
"{} registry did not respond ({}ms)",
"FAIL".red(),
result.latency_ms
);
}

Ok(())
}
49 changes: 21 additions & 28 deletions crates/pm/src/cmd/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ pub async fn run(
.as_ref()
.map(|args| args.iter().map(|s| s.as_str()).collect::<Vec<&str>>());
run_script(
&updated_cwd,
&script_name,
selected_workspace.as_deref(),
script_args_refs,
Expand All @@ -61,19 +62,16 @@ pub async fn run(
}

pub async fn run_script(
cwd: &Path,
script_name: &str,
workspace: Option<&str>,
script_args: Option<Vec<&str>>,
) -> Result<()> {
let cwd = std::env::current_dir().context("Failed to get current directory")?;
let updated_cwd = update_cwd_to_project(&cwd).await?;
let updated_cwd = update_cwd_to_project(cwd).await?;
let pkg = if let Some(workspace_name) = &workspace {
let workspace_dir = find_workspace_path(
&std::env::current_dir().context("Failed to get current directory")?,
workspace_name,
)
.await
.context("Failed to find workspace path")?;
let workspace_dir = find_workspace_path(&updated_cwd, workspace_name)
.await
.context("Failed to find workspace path")?;
tracing::debug!(
"Using workspace: {} at path: {}",
workspace_name,
Expand All @@ -89,14 +87,11 @@ pub async fn run_script(

let package = PackageInfo {
path: if let Some(workspace_name) = workspace {
find_workspace_path(
&std::env::current_dir().context("Failed to get current directory")?,
workspace_name,
)
.await
.context("Failed to find workspace path")?
find_workspace_path(&updated_cwd, workspace_name)
.await
.context("Failed to find workspace path")?
} else {
std::env::current_dir().context("Failed to get current directory")?
updated_cwd.to_path_buf()
},
bin_files: Default::default(),
scripts: Scripts::default(),
Expand Down Expand Up @@ -248,6 +243,7 @@ pub async fn run_script_in_all_workspaces(
for workspace_name in workspaces_to_run {
let script_name = script_name.to_string();
let script_args = script_args.clone();
let cwd = updated_cwd.clone();

// Spawn concurrent task for each workspace in the layer
join_set.spawn(async move {
Expand All @@ -258,7 +254,7 @@ pub async fn run_script_in_all_workspaces(
let script_args_refs = script_args
.as_ref()
.map(|args| args.iter().map(|s| s.as_str()).collect::<Vec<&str>>());
match run_script(&script_name, Some(&workspace_name), script_args_refs).await {
match run_script(&cwd, &script_name, Some(&workspace_name), script_args_refs).await {
Ok(()) => {
tracing::debug!(
"Successfully completed script '{script_name}' in workspace '{workspace_name}'"
Expand Down Expand Up @@ -329,7 +325,7 @@ mod tests {

#[tokio::test]
async fn test_run_script_not_found() {
let _dir = tempdir().unwrap();
let dir = tempdir().unwrap();
let package_json = r#"
{
"name": "@test/package",
Expand All @@ -339,10 +335,9 @@ mod tests {
}
}"#;

fs::write(_dir.path().join("package.json"), package_json).unwrap();
std::env::set_current_dir(_dir.path()).unwrap();
fs::write(dir.path().join("package.json"), package_json).unwrap();

let result = run_script("nonexistent", None, None).await;
let result = run_script(dir.path(), "nonexistent", None, None).await;

assert!(result.is_err());
assert!(
Expand All @@ -355,20 +350,19 @@ mod tests {

#[tokio::test]
async fn test_run_script_invalid_json() {
let _dir = tempdir().unwrap();
let dir = tempdir().unwrap();
let invalid_json = r#"{ "name": "test", "scripts": { "test": 123 } }"#;

fs::write(_dir.path().join("package.json"), invalid_json).unwrap();
std::env::set_current_dir(_dir.path()).unwrap();
fs::write(dir.path().join("package.json"), invalid_json).unwrap();

let result = run_script("test", None, None).await;
let result = run_script(dir.path(), "test", None, None).await;

assert!(result.is_err());
}

#[tokio::test]
async fn test_get_topo_without_workspaces() {
let _dir = tempdir().unwrap();
let dir = tempdir().unwrap();
let package_json = r#"
{
"name": "test-project",
Expand All @@ -378,10 +372,9 @@ mod tests {
}
}"#;

fs::write(_dir.path().join("package.json"), package_json).unwrap();
std::env::set_current_dir(_dir.path()).unwrap();
fs::write(dir.path().join("package.json"), package_json).unwrap();

let result = WorkspaceService::get_workspace_topology(_dir.path()).await;
let result = WorkspaceService::get_workspace_topology(dir.path()).await;
assert!(result.is_ok());
let topology = result.unwrap();
// Should return empty topology for non-workspace projects
Expand Down
2 changes: 1 addition & 1 deletion crates/pm/src/cmd/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use utoo_ruborist::service::fetch_full_manifest;
use utoo_ruborist::util::parse_package_spec;

use crate::helper::ruborist_context::Context;
use crate::util::config::get_registry;
use crate::util::format_print::print_grid;
use crate::util::user_config::get_registry;

/// View package information from registry, similar to npm view
pub async fn view(package_spec: &str) -> Result<()> {
Expand Down
4 changes: 4 additions & 0 deletions crates/pm/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ pub mod cmd {
pub const INIT_ALIAS: &str = "create";
pub const INIT_ABOUT: &str = "Create a package.json file";

pub const PING_NAME: &str = "ping";
pub const PING_ALIAS: &str = "pg";
pub const PING_ABOUT: &str = "Ping npm registry";

pub const COMPLETIONS_NAME: &str = "completions";
pub const COMPLETIONS_ABOUT: &str = "Generate shell completion scripts\n\nAdd to your shell config:\n bash: echo 'eval \"$(utoo completions bash)\"' >> ~/.bashrc\n zsh: echo 'eval \"$(utoo completions zsh)\"' >> ~/.zshrc\n fish: utoo completions fish > ~/.config/fish/completions/utoo.fish";
}
2 changes: 1 addition & 1 deletion crates/pm/src/helper/auto_update.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::constants::APP_VERSION;
use crate::util::config::get_registry;
use crate::util::user_config::get_registry;
use anyhow::{Context, Result};
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
Expand Down
2 changes: 1 addition & 1 deletion crates/pm/src/helper/lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ use std::path::{Path, PathBuf};

use super::ruborist_context::Context;
use crate::helper::workspace::find_workspaces;
use crate::util::config::get_legacy_peer_deps;
use crate::util::json::{load_package_json_from_path, load_package_lock_json_from_path};
use crate::util::logger::{finish_progress_bar, start_progress_bar};
use crate::util::save_type::{PackageAction, SaveType};
use crate::util::user_config::get_legacy_peer_deps;
use crate::util::{cloner::clone_package, downloader::download_to_cache};
use utoo_ruborist::lock::{LockPackage, PackageLock};
use utoo_ruborist::manifest::PackageJson;
Expand Down
14 changes: 10 additions & 4 deletions crates/pm/src/helper/ruborist_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ use utoo_ruborist::service::{BuildDepsOptions, Glob, UnifiedRegistry};

use crate::service::pipeline::{PipelineChannels, PipelineReceiver};
use crate::util::cache::get_cache_dir;
use crate::util::config::{get_legacy_peer_deps, get_manifests_concurrency_limit, get_registry};
use crate::util::logger::ProgressReceiver;
use crate::util::user_config::{
get_legacy_peer_deps, get_manifests_concurrency_limit, get_registry, get_supports_semver,
};

/// Tokio-based glob implementation.
#[derive(Debug, Clone, Copy, Default)]
Expand Down Expand Up @@ -46,6 +48,7 @@ impl Context {
legacy_peer_deps: get_legacy_peer_deps().await,
glob: TokioGlob,
receiver,
supports_semver: get_supports_semver(),
}
}

Expand All @@ -70,10 +73,13 @@ impl Context {

/// Create a UnifiedRegistry with standard configuration.
pub fn registry() -> Registry {
UnifiedRegistry::builder()
let mut builder = UnifiedRegistry::builder()
.registry(get_registry())
.cache_dir(get_cache_dir())
.build()
.cache_dir(get_cache_dir());
if let Some(semver) = get_supports_semver() {
builder = builder.supports_semver(semver);
}
builder.build()
}

/// Get the glob instance.
Expand Down
2 changes: 1 addition & 1 deletion crates/pm/src/helper/tree_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ use utoo_ruborist::manifest::PackageJson;

use crate::helper::install_runtime::install_runtime;
use crate::helper::workspace::find_workspaces;
use crate::util::config::get_legacy_peer_deps;
use crate::util::json::load_package_json_from_path;
use crate::util::logger::{finish_progress_bar, start_progress_bar};
use crate::util::user_config::get_legacy_peer_deps;

/// TreeBuilder - builds workspace dependency graph.
///
Expand Down
29 changes: 19 additions & 10 deletions crates/pm/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ use cmd::update::update;
use cmd::view::view;
use cmd::{clean::clean, deps::build_workspace};
use helper::auto_update::init_auto_update;
use util::config::{
set_cache_dir, set_legacy_peer_deps, set_manifests_concurrency_limit, set_omit, set_registry,
};
use util::logger::{get_log_file_path, init_tracing, log_time, log_time_end};
use util::save_type::{OmitType, PackageAction, SaveType, parse_save_type};
use util::user_config::{
init_registry, set_cache_dir, set_legacy_peer_deps, set_manifests_concurrency_limit, set_omit,
};

mod cmd;
mod constants;
Expand All @@ -33,10 +33,10 @@ use crate::constants::cmd::{
CLEAN_ABOUT, CLEAN_ALIAS, CLEAN_NAME, COMPLETIONS_ABOUT, COMPLETIONS_NAME, CONFIG_ABOUT,
CONFIG_ALIAS, CONFIG_NAME, DEPS_ABOUT, DEPS_ALIAS, DEPS_NAME, EXECUTE_ABOUT, EXECUTE_ALIAS,
EXECUTE_NAME, INIT_ABOUT, INIT_ALIAS, INIT_NAME, INSTALL_ABOUT, INSTALL_ALIAS, INSTALL_NAME,
LINK_ABOUT, LINK_ALIAS, LINK_NAME, LIST_ALIAS, LIST_NAME, REBUILD_ABOUT, REBUILD_ALIAS,
REBUILD_NAME, RUN_ALIAS, RUN_NAME, UNINSTALL_ABOUT, UNINSTALL_ALIAS, UNINSTALL_NAME,
UPDATE_ABOUT, UPDATE_ALIAS, UPDATE_NAME, VIEW_ABOUT, VIEW_ALIAS, VIEW_ALIAS_INFO,
VIEW_ALIAS_SHOW, VIEW_NAME,
LINK_ABOUT, LINK_ALIAS, LINK_NAME, LIST_ALIAS, LIST_NAME, PING_ABOUT, PING_ALIAS, PING_NAME,
REBUILD_ABOUT, REBUILD_ALIAS, REBUILD_NAME, RUN_ALIAS, RUN_NAME, UNINSTALL_ABOUT,
UNINSTALL_ALIAS, UNINSTALL_NAME, UPDATE_ABOUT, UPDATE_ALIAS, UPDATE_NAME, VIEW_ABOUT,
VIEW_ALIAS, VIEW_ALIAS_INFO, VIEW_ALIAS_SHOW, VIEW_NAME,
};
use crate::constants::{APP_ABOUT, APP_NAME, APP_VERSION};
use crate::helper::workspace::update_cwd_to_root;
Expand Down Expand Up @@ -259,6 +259,12 @@ enum Commands {
prefix: Option<String>,
},

#[command(name = PING_NAME, alias = PING_ALIAS, about = PING_ABOUT)]
Ping {
/// Registry URL to ping (defaults to configured registry)
registry: Option<String>,
},

#[command(name = CONFIG_NAME, alias = CONFIG_ALIAS, about = CONFIG_ABOUT)]
Config {
#[command(subcommand)]
Expand Down Expand Up @@ -315,7 +321,7 @@ async fn async_main() -> Result<()> {

// Check for help flag
if args.len() > 1 && (args[1] == "-h" || args[1] == "--help") {
let config = crate::util::config::Config::load(false).await?;
let config = crate::util::config_file::Config::load(false).await?;
let config_service = crate::service::config::ConfigService::new(config);
config_service.print_help()?;
return Ok(());
Expand Down Expand Up @@ -361,7 +367,7 @@ async fn async_main() -> Result<()> {
);

// global registry
set_registry(cli.registry).await;
init_registry(cli.registry).await;

// set cache directory
set_cache_dir(cli.cache_dir).await;
Expand Down Expand Up @@ -535,6 +541,9 @@ async fn async_main() -> Result<()> {
init(yes, None).await?;
log_time_end("package.json created");
}
Some(Commands::Ping { registry }) => {
cmd::ping::ping(registry.as_deref()).await?;
}
Some(Commands::Config { command }) => match command {
ConfigCommands::Set { key, value, global } => {
handle_config_set(key, value, global).await?;
Expand All @@ -554,7 +563,7 @@ async fn async_main() -> Result<()> {
// Check if there's a script name provided
if let Some(script_name) = &cli.script_name {
// First check if there's a custom command configured for this script name
let config = crate::util::config::Config::load(false).await?;
let config = crate::util::config_file::Config::load(false).await?;
let config_service = crate::service::config::ConfigService::new(config);
// Check if there's a custom command available
if let Ok(Some(_)) = config_service.get_available_cmd(script_name) {
Expand Down
2 changes: 1 addition & 1 deletion crates/pm/src/service/binary.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::fs;
use crate::util::config::get_registry;
use crate::util::json::load_package_json_from_path;
use crate::util::user_config::get_registry;
use anyhow::{Context, Result};
use regex::Regex;
use serde_json::{Map, Value};
Expand Down
2 changes: 1 addition & 1 deletion crates/pm/src/service/config.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::constants::cmd;
use crate::util::config::{Config, ConfigResult};
use crate::util::config_file::{Config, ConfigResult};
use anyhow::anyhow;
use colored::*;
use std::cmp::max;
Expand Down
2 changes: 1 addition & 1 deletion crates/pm/src/util/cache.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::fs;

pub use super::config::get_cache_dir;
pub use super::user_config::get_cache_dir;

pub fn matches_pattern(text: &str, pattern: &str) -> bool {
if pattern == "*" {
Expand Down
Loading
Loading