use std::path::{Path, PathBuf};
pub use crate::commands::add::AddToProjectOptions;
pub use crate::commands::install::{
DepSelection, EmbedderInstallOverrides, FrozenMode, INSTALL_OUTPUT_CODE_LIFECYCLE_SCRIPT,
InstallControl, InstallEvent, InstallOutputLevel, InstallOutputMode, InstallPhase,
InstallProgressSnapshot, InstallPrompt, InstallPromptFuture, InstallPromptHandler,
InstallReporter,
};
pub use crate::runtime::{EmbedderRuntime, set_embedder_runtime};
pub use aube_manifest::{Error as ManifestError, PackageJson, Workspaces};
pub use aube_registry::NetworkMode;
pub use aube_util::{AUBE, Embedder as Host};
pub use aube_workspace::{WorkspaceBoundary, WorkspaceDiscoveryOptions};
#[derive(Debug, Clone)]
pub struct InstallOptions {
pub project_dir: PathBuf,
pub frozen_mode: FrozenMode,
pub dep_selection: DepSelection,
pub ignore_scripts: bool,
pub run_root_lifecycle: bool,
pub dry_run: bool,
pub lockfile_only: bool,
pub force: bool,
pub network_mode: NetworkMode,
pub strict_no_lockfile: bool,
pub dangerously_allow_all_builds: bool,
pub osv_transitive_check: bool,
pub control: InstallControl,
pub runtime: Option<EmbedderRuntime>,
}
impl InstallOptions {
pub fn new(project_dir: impl Into<PathBuf>) -> Self {
Self {
project_dir: project_dir.into(),
frozen_mode: FrozenMode::Prefer,
dep_selection: DepSelection::All,
ignore_scripts: false,
run_root_lifecycle: true,
dry_run: false,
lockfile_only: false,
force: false,
network_mode: NetworkMode::Online,
strict_no_lockfile: false,
dangerously_allow_all_builds: false,
osv_transitive_check: false,
control: InstallControl::default(),
runtime: None,
}
}
}
pub type Result<T> = miette::Result<T>;
pub fn initialize(host: &'static Host, setting_defaults: Vec<(String, String)>) {
aube_util::set_embedder(host);
aube_settings::set_embedder_defaults(setting_defaults);
}
pub fn host() -> &'static Host {
aube_util::embedder()
}
pub fn is_workspace_project_root(project_dir: &Path) -> bool {
aube_workspace::is_workspace_project_root(project_dir)
}
pub fn discover_workspace_packages(
project_dir: &Path,
options: WorkspaceDiscoveryOptions,
) -> Result<Vec<PathBuf>> {
aube_workspace::find_workspace_packages_with_options(project_dir, options)
.map_err(miette::Report::new)
}
pub async fn install(options: InstallOptions) -> Result<()> {
install_with_overrides(options, EmbedderInstallOverrides::default()).await
}
pub async fn install_with_overrides(
options: InstallOptions,
overrides: EmbedderInstallOverrides,
) -> Result<()> {
aube_util::diag::init();
let mut command_options =
crate::commands::install::InstallOptions::with_mode(options.frozen_mode);
command_options.project_dir = Some(options.project_dir);
command_options.dep_selection = options.dep_selection;
command_options.ignore_scripts = options.ignore_scripts;
command_options.skip_root_lifecycle = !options.run_root_lifecycle;
command_options.run_dev_preinstall = options.run_root_lifecycle;
command_options.dry_run = options.dry_run;
command_options.lockfile_only = options.lockfile_only;
command_options.force = options.force;
command_options.network_mode = options.network_mode;
command_options.strict_no_lockfile = options.strict_no_lockfile;
command_options.dangerously_allow_all_builds = options.dangerously_allow_all_builds;
command_options.osv_transitive_check = options.osv_transitive_check;
command_options.control = options.control;
command_options.embedder_runtime = options.runtime;
overrides.append_to(&mut command_options.cli_flags);
let result = crate::commands::scope_embedder_install_overrides(
overrides,
crate::commands::install::run(command_options),
)
.await;
aube_util::diag::flush_file();
result
}
pub async fn add(
project_dir: &Path,
packages: &[String],
options: AddToProjectOptions,
) -> Result<()> {
add_with_overrides(
project_dir,
packages,
options,
EmbedderInstallOverrides::default(),
)
.await
}
pub async fn add_with_overrides(
project_dir: &Path,
packages: &[String],
options: AddToProjectOptions,
overrides: EmbedderInstallOverrides,
) -> Result<()> {
aube_util::diag::init();
let result = crate::commands::scope_embedder_install_overrides(
overrides.clone(),
crate::commands::add::add_to_project_with_overrides(
project_dir,
packages,
options,
overrides,
),
)
.await;
aube_util::diag::flush_file();
result
}
pub async fn run(
project_dir: &Path,
script: &str,
args: Vec<String>,
runtime: Option<EmbedderRuntime>,
) -> Result<Option<i32>> {
crate::runtime::with_embedder_runtime(
runtime,
crate::commands::run::run_script_in(
project_dir.to_path_buf(),
script,
&args,
false,
false,
&aube_workspace::selector::EffectiveFilter::default(),
),
)
.await
}
pub async fn exec(
project_dir: &Path,
bin: &str,
args: Vec<String>,
runtime: Option<EmbedderRuntime>,
) -> Result<Option<i32>> {
let exec_args = crate::commands::exec::ExecArgs {
bin: bin.to_string(),
args,
..Default::default()
};
crate::runtime::with_embedder_runtime(
runtime,
crate::commands::exec::run_in(
exec_args,
aube_workspace::selector::EffectiveFilter::default(),
Some(project_dir.to_path_buf()),
),
)
.await
}
pub async fn dlx(
project_dir: &Path,
params: Vec<String>,
packages: Vec<String>,
runtime: Option<EmbedderRuntime>,
) -> Result<Option<i32>> {
let args = crate::commands::dlx::DlxArgs {
params,
package: packages,
..Default::default()
};
crate::runtime::with_embedder_runtime(
runtime,
crate::commands::dlx::run_in(args, Some(project_dir.to_path_buf())),
)
.await
}
pub async fn node(
project_dir: &Path,
args: Vec<std::ffi::OsString>,
runtime: Option<EmbedderRuntime>,
) -> Result<Option<i32>> {
crate::runtime::with_embedder_runtime(
runtime,
crate::commands::node::run_spawn(args, Some(project_dir.to_path_buf())),
)
.await
}
pub fn error_code(error: &miette::Report) -> Option<String> {
error.code().map(|code| code.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn embedded_manifest_types_keep_tolerant_parsing() {
let manifest: PackageJson = serde_json::from_str(
r#"{
"name": "app",
"workspaces": "packages/*",
"dependencies": null,
"devDependencies": {"local": "workspace:*", "junk": false}
}"#,
)
.unwrap();
assert_eq!(manifest.name.as_deref(), Some("app"));
assert_eq!(
manifest.workspaces.as_ref().map(|workspaces| workspaces
.patterns()
.iter()
.map(String::as_str)
.collect()),
Some(vec!["packages/*"])
);
assert!(manifest.dependencies.is_empty());
assert_eq!(
manifest.dev_dependencies.get("local").map(String::as_str),
Some("workspace:*")
);
assert!(!manifest.dev_dependencies.contains_key("junk"));
}
}