mirror of
https://github.com/denoland/deno.git
synced 2025-09-27 12:49:10 +00:00

Some checks are pending
ci / build libs (push) Blocked by required conditions
ci / test debug linux-aarch64 (push) Blocked by required conditions
ci / test release linux-aarch64 (push) Blocked by required conditions
ci / test debug macos-aarch64 (push) Blocked by required conditions
ci / bench release linux-x86_64 (push) Blocked by required conditions
ci / lint debug linux-x86_64 (push) Blocked by required conditions
ci / pre-build (push) Waiting to run
ci / test release macos-aarch64 (push) Blocked by required conditions
ci / lint debug macos-x86_64 (push) Blocked by required conditions
ci / lint debug windows-x86_64 (push) Blocked by required conditions
ci / test debug linux-x86_64 (push) Blocked by required conditions
ci / test release linux-x86_64 (push) Blocked by required conditions
ci / test debug macos-x86_64 (push) Blocked by required conditions
ci / test release macos-x86_64 (push) Blocked by required conditions
ci / test debug windows-x86_64 (push) Blocked by required conditions
ci / test release windows-x86_64 (push) Blocked by required conditions
ci / publish canary (push) Blocked by required conditions
This commit updates output of `deno install` to look like so: ``` $ deno install Packages: 20 +++++++++++++++++ Resolved: 32, reused: 8, downloaded: 12, added: 10 Dependencies: + jsr:@std/http 1.0.2 + npm:express 1.0.1 ... ``` --------- Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
358 lines
11 KiB
Rust
358 lines
11 KiB
Rust
// Copyright 2018-2025 the Deno authors. MIT license.
|
|
|
|
use std::sync::Arc;
|
|
|
|
use deno_npm::resolution::PackageIdNotFoundError;
|
|
use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot;
|
|
use deno_npm_cache::NpmCache;
|
|
use deno_npm_cache::NpmCacheHttpClient;
|
|
use deno_npm_cache::NpmCacheSetting;
|
|
use deno_npm_cache::RegistryInfoProvider;
|
|
use deno_npm_cache::TarballCache;
|
|
use deno_resolver::factory::ResolverFactory;
|
|
use deno_resolver::factory::WorkspaceFactory;
|
|
use deno_resolver::factory::WorkspaceFactorySys;
|
|
use deno_resolver::lockfile::LockfileLock;
|
|
use deno_resolver::lockfile::LockfileNpmPackageInfoApiAdapter;
|
|
use futures::FutureExt;
|
|
|
|
use crate::LifecycleScriptsConfig;
|
|
use crate::NpmInstaller;
|
|
use crate::Reporter;
|
|
use crate::graph::NpmCachingStrategy;
|
|
use crate::graph::NpmDenoGraphResolver;
|
|
use crate::initializer::NpmResolutionInitializer;
|
|
use crate::initializer::NpmResolverManagedSnapshotOption;
|
|
use crate::lifecycle_scripts::LifecycleScriptsExecutor;
|
|
use crate::package_json::NpmInstallDepsProvider;
|
|
use crate::resolution::NpmResolutionInstaller;
|
|
|
|
// todo(https://github.com/rust-lang/rust/issues/109737): remove once_cell after get_or_try_init is stabilized
|
|
type Deferred<T> = once_cell::sync::OnceCell<T>;
|
|
|
|
#[sys_traits::auto_impl]
|
|
pub trait NpmInstallerFactorySys:
|
|
crate::NpmInstallerSys + WorkspaceFactorySys
|
|
{
|
|
}
|
|
|
|
type ResolveNpmResolutionSnapshotFn = Box<
|
|
dyn Fn() -> Result<
|
|
Option<ValidSerializedNpmResolutionSnapshot>,
|
|
PackageIdNotFoundError,
|
|
>,
|
|
>;
|
|
|
|
pub struct NpmInstallerFactoryOptions {
|
|
pub cache_setting: NpmCacheSetting,
|
|
pub caching_strategy: NpmCachingStrategy,
|
|
pub lifecycle_scripts_config: LifecycleScriptsConfig,
|
|
/// Resolves the npm resolution snapshot from the environment.
|
|
pub resolve_npm_resolution_snapshot: ResolveNpmResolutionSnapshotFn,
|
|
}
|
|
|
|
pub trait InstallReporter:
|
|
deno_npm::resolution::Reporter
|
|
+ deno_graph::source::Reporter
|
|
+ deno_npm_cache::TarballCacheReporter
|
|
+ crate::InstallProgressReporter
|
|
{
|
|
}
|
|
|
|
impl<
|
|
T: deno_npm::resolution::Reporter
|
|
+ deno_graph::source::Reporter
|
|
+ deno_npm_cache::TarballCacheReporter
|
|
+ crate::InstallProgressReporter,
|
|
> InstallReporter for T
|
|
{
|
|
}
|
|
|
|
pub struct NpmInstallerFactory<
|
|
TNpmCacheHttpClient: NpmCacheHttpClient,
|
|
TReporter: Reporter,
|
|
TSys: NpmInstallerFactorySys,
|
|
> {
|
|
resolver_factory: Arc<ResolverFactory<TSys>>,
|
|
http_client: Arc<TNpmCacheHttpClient>,
|
|
lifecycle_scripts_executor: Arc<dyn LifecycleScriptsExecutor>,
|
|
reporter: TReporter,
|
|
lockfile_npm_package_info_provider:
|
|
Deferred<LockfileNpmPackageInfoApiAdapter>,
|
|
npm_cache: Deferred<Arc<NpmCache<TSys>>>,
|
|
npm_deno_graph_resolver: async_once_cell::OnceCell<
|
|
Arc<NpmDenoGraphResolver<TNpmCacheHttpClient, TSys>>,
|
|
>,
|
|
npm_installer:
|
|
async_once_cell::OnceCell<Arc<NpmInstaller<TNpmCacheHttpClient, TSys>>>,
|
|
npm_resolution_initializer:
|
|
async_once_cell::OnceCell<Arc<NpmResolutionInitializer<TSys>>>,
|
|
npm_resolution_installer: async_once_cell::OnceCell<
|
|
Arc<NpmResolutionInstaller<TNpmCacheHttpClient, TSys>>,
|
|
>,
|
|
registry_info_provider:
|
|
Deferred<Arc<RegistryInfoProvider<TNpmCacheHttpClient, TSys>>>,
|
|
tarball_cache: Deferred<Arc<TarballCache<TNpmCacheHttpClient, TSys>>>,
|
|
options: NpmInstallerFactoryOptions,
|
|
install_reporter: Option<Arc<dyn InstallReporter + 'static>>,
|
|
}
|
|
|
|
impl<
|
|
TNpmCacheHttpClient: NpmCacheHttpClient,
|
|
TReporter: Reporter,
|
|
TSys: NpmInstallerFactorySys,
|
|
> NpmInstallerFactory<TNpmCacheHttpClient, TReporter, TSys>
|
|
{
|
|
pub fn new(
|
|
resolver_factory: Arc<ResolverFactory<TSys>>,
|
|
http_client: Arc<TNpmCacheHttpClient>,
|
|
lifecycle_scripts_executor: Arc<dyn LifecycleScriptsExecutor>,
|
|
reporter: TReporter,
|
|
install_reporter: Option<Arc<dyn InstallReporter + 'static>>,
|
|
options: NpmInstallerFactoryOptions,
|
|
) -> Self {
|
|
Self {
|
|
resolver_factory,
|
|
http_client,
|
|
lifecycle_scripts_executor,
|
|
reporter,
|
|
lockfile_npm_package_info_provider: Default::default(),
|
|
npm_cache: Default::default(),
|
|
npm_deno_graph_resolver: Default::default(),
|
|
npm_installer: Default::default(),
|
|
npm_resolution_initializer: Default::default(),
|
|
npm_resolution_installer: Default::default(),
|
|
registry_info_provider: Default::default(),
|
|
tarball_cache: Default::default(),
|
|
install_reporter,
|
|
options,
|
|
}
|
|
}
|
|
|
|
pub fn http_client(&self) -> &Arc<TNpmCacheHttpClient> {
|
|
&self.http_client
|
|
}
|
|
|
|
pub async fn initialize_npm_resolution_if_managed(
|
|
&self,
|
|
) -> Result<(), anyhow::Error> {
|
|
let npm_resolver = self.resolver_factory().npm_resolver()?;
|
|
if npm_resolver.is_managed() {
|
|
self
|
|
.npm_resolution_initializer()
|
|
.await?
|
|
.ensure_initialized()
|
|
.await?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub fn lockfile_npm_package_info_provider(
|
|
&self,
|
|
) -> Result<&LockfileNpmPackageInfoApiAdapter, anyhow::Error> {
|
|
self.lockfile_npm_package_info_provider.get_or_try_init(|| {
|
|
Ok(LockfileNpmPackageInfoApiAdapter::new(
|
|
self.registry_info_provider()?.clone(),
|
|
self
|
|
.workspace_factory()
|
|
.workspace_npm_link_packages()?
|
|
.clone(),
|
|
))
|
|
})
|
|
}
|
|
|
|
pub async fn maybe_lockfile(
|
|
&self,
|
|
) -> Result<Option<&Arc<LockfileLock<TSys>>>, anyhow::Error> {
|
|
let workspace_factory = self.workspace_factory();
|
|
let package_info_provider = self.lockfile_npm_package_info_provider()?;
|
|
workspace_factory
|
|
.maybe_lockfile(package_info_provider)
|
|
.await
|
|
}
|
|
|
|
pub fn npm_cache(&self) -> Result<&Arc<NpmCache<TSys>>, anyhow::Error> {
|
|
self.npm_cache.get_or_try_init(|| {
|
|
let workspace_factory = self.workspace_factory();
|
|
Ok(Arc::new(NpmCache::new(
|
|
workspace_factory.npm_cache_dir()?.clone(),
|
|
workspace_factory.sys().clone(),
|
|
self.options.cache_setting.clone(),
|
|
workspace_factory.npmrc()?.clone(),
|
|
)))
|
|
})
|
|
}
|
|
|
|
pub async fn npm_deno_graph_resolver(
|
|
&self,
|
|
) -> Result<
|
|
&Arc<NpmDenoGraphResolver<TNpmCacheHttpClient, TSys>>,
|
|
anyhow::Error,
|
|
> {
|
|
self
|
|
.npm_deno_graph_resolver
|
|
.get_or_try_init(
|
|
async {
|
|
Ok(Arc::new(NpmDenoGraphResolver::new(
|
|
self.npm_installer_if_managed().await?.cloned(),
|
|
self
|
|
.resolver_factory()
|
|
.found_package_json_dep_flag()
|
|
.clone(),
|
|
self.options.caching_strategy,
|
|
)))
|
|
}
|
|
.boxed_local(),
|
|
)
|
|
.await
|
|
}
|
|
|
|
pub async fn npm_resolution_initializer(
|
|
&self,
|
|
) -> Result<&Arc<NpmResolutionInitializer<TSys>>, anyhow::Error> {
|
|
self
|
|
.npm_resolution_initializer
|
|
.get_or_try_init(async move {
|
|
let workspace_factory = self.workspace_factory();
|
|
Ok(Arc::new(NpmResolutionInitializer::new(
|
|
self.resolver_factory.npm_resolution().clone(),
|
|
workspace_factory.workspace_npm_link_packages()?.clone(),
|
|
match (self.options.resolve_npm_resolution_snapshot)()? {
|
|
Some(snapshot) => {
|
|
NpmResolverManagedSnapshotOption::Specified(Some(snapshot))
|
|
}
|
|
None => match self.maybe_lockfile().await? {
|
|
Some(lockfile) => {
|
|
NpmResolverManagedSnapshotOption::ResolveFromLockfile(
|
|
lockfile.clone(),
|
|
)
|
|
}
|
|
None => NpmResolverManagedSnapshotOption::Specified(None),
|
|
},
|
|
},
|
|
)))
|
|
})
|
|
.await
|
|
}
|
|
|
|
pub async fn npm_resolution_installer(
|
|
&self,
|
|
) -> Result<
|
|
&Arc<NpmResolutionInstaller<TNpmCacheHttpClient, TSys>>,
|
|
anyhow::Error,
|
|
> {
|
|
self
|
|
.npm_resolution_installer
|
|
.get_or_try_init(async move {
|
|
Ok(Arc::new(NpmResolutionInstaller::new(
|
|
self.registry_info_provider()?.clone(),
|
|
self.resolver_factory.npm_resolution().clone(),
|
|
self.maybe_lockfile().await?.cloned(),
|
|
self
|
|
.workspace_factory()
|
|
.workspace_npm_link_packages()?
|
|
.clone(),
|
|
self
|
|
.install_reporter
|
|
.as_ref()
|
|
.map(|r| r.clone() as Arc<dyn deno_npm::resolution::Reporter>),
|
|
)))
|
|
})
|
|
.await
|
|
}
|
|
|
|
pub async fn npm_installer_if_managed(
|
|
&self,
|
|
) -> Result<
|
|
Option<&Arc<NpmInstaller<TNpmCacheHttpClient, TSys>>>,
|
|
anyhow::Error,
|
|
> {
|
|
if self.resolver_factory().use_byonm()? || self.workspace_factory().no_npm()
|
|
{
|
|
Ok(None)
|
|
} else {
|
|
Ok(Some(self.npm_installer().await?))
|
|
}
|
|
}
|
|
|
|
pub async fn npm_installer(
|
|
&self,
|
|
) -> Result<&Arc<NpmInstaller<TNpmCacheHttpClient, TSys>>, anyhow::Error> {
|
|
self
|
|
.npm_installer
|
|
.get_or_try_init(
|
|
async move {
|
|
let workspace_factory = self.workspace_factory();
|
|
let npm_cache = self.npm_cache()?;
|
|
let registry_info_provider = self.registry_info_provider()?;
|
|
let workspace_npm_link_packages =
|
|
workspace_factory.workspace_npm_link_packages()?;
|
|
Ok(Arc::new(NpmInstaller::new(
|
|
self.lifecycle_scripts_executor.clone(),
|
|
npm_cache.clone(),
|
|
Arc::new(NpmInstallDepsProvider::from_workspace(
|
|
&workspace_factory.workspace_directory()?.workspace,
|
|
)),
|
|
registry_info_provider.clone(),
|
|
self.resolver_factory.npm_resolution().clone(),
|
|
self.npm_resolution_initializer().await?.clone(),
|
|
self.npm_resolution_installer().await?.clone(),
|
|
&self.reporter,
|
|
workspace_factory.sys().clone(),
|
|
self.tarball_cache()?.clone(),
|
|
self.maybe_lockfile().await?.cloned(),
|
|
workspace_factory
|
|
.node_modules_dir_path()?
|
|
.map(|p| p.to_path_buf()),
|
|
self.options.lifecycle_scripts_config.clone(),
|
|
self.resolver_factory.npm_system_info().clone(),
|
|
workspace_npm_link_packages.clone(),
|
|
self.install_reporter.clone(),
|
|
)))
|
|
}
|
|
.boxed_local(),
|
|
)
|
|
.await
|
|
}
|
|
|
|
pub fn registry_info_provider(
|
|
&self,
|
|
) -> Result<
|
|
&Arc<RegistryInfoProvider<TNpmCacheHttpClient, TSys>>,
|
|
anyhow::Error,
|
|
> {
|
|
self.registry_info_provider.get_or_try_init(|| {
|
|
Ok(Arc::new(RegistryInfoProvider::new(
|
|
self.npm_cache()?.clone(),
|
|
self.http_client().clone(),
|
|
self.workspace_factory().npmrc()?.clone(),
|
|
)))
|
|
})
|
|
}
|
|
|
|
pub fn tarball_cache(
|
|
&self,
|
|
) -> Result<&Arc<TarballCache<TNpmCacheHttpClient, TSys>>, anyhow::Error> {
|
|
self.tarball_cache.get_or_try_init(|| {
|
|
let workspace_factory = self.workspace_factory();
|
|
Ok(Arc::new(TarballCache::new(
|
|
self.npm_cache()?.clone(),
|
|
self.http_client.clone(),
|
|
workspace_factory.sys().clone(),
|
|
workspace_factory.npmrc()?.clone(),
|
|
self
|
|
.install_reporter
|
|
.as_ref()
|
|
.map(|r| r.clone() as Arc<dyn deno_npm_cache::TarballCacheReporter>),
|
|
)))
|
|
})
|
|
}
|
|
|
|
pub fn resolver_factory(&self) -> &Arc<ResolverFactory<TSys>> {
|
|
&self.resolver_factory
|
|
}
|
|
|
|
pub fn workspace_factory(&self) -> &Arc<WorkspaceFactory<TSys>> {
|
|
self.resolver_factory.workspace_factory()
|
|
}
|
|
}
|