mirror of
https://github.com/denoland/deno.git
synced 2024-12-28 01:59:06 -05:00
56f31628f7
Closes #20487 Currently spelled ``` deno outdated ``` and ``` deno outdated --update ``` Works across package.json and deno.json, and in workspaces. There's a bit of duplicated code, I'll refactor to reduce this in follow ups ## Currently supported: ### Printing outdated deps (current output below which basically mimics pnpm, but requesting feedback / suggestions) ``` deno outdated ``` ![Screenshot 2024-11-19 at 2 01 56 PM](https://github.com/user-attachments/assets/51fea83a-181a-4082-b388-163313ce15e7) ### Updating deps semver compatible: ``` deno outdated --update ``` latest: ``` deno outdated --latest ``` current output is basic, again would love suggestions ![Screenshot 2024-11-19 at 2 13 46 PM](https://github.com/user-attachments/assets/e4c4db87-cd67-4b74-9ea7-4bd80106d5e9) #### Filters ``` deno outdated --update "@std/*" deno outdated --update --latest "@std/* "!@std/fmt" ``` #### Update to specific versions ``` deno outdated --update @std/fmt@1.0.2 @std/cli@^1.0.3 ``` ### Include all workspace members ``` deno outdated --recursive deno outdated --update --recursive ``` ## Future work - interactive update - update deps in js/ts files - better support for transitive deps Known issues (to be fixed in follow ups): - If no top level dependencies have changed, we won't update transitive deps (even if they could be updated) - Can't filter transitive deps, or update them to specific versions ## TODO (in this PR): - ~~spec tests for filters~~ - ~~spec test for mixed workspace (have tested manually)~~ - tweak output - suggestion when you try `deno update` --------- Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
130 lines
3.8 KiB
Rust
130 lines
3.8 KiB
Rust
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
|
|
|
use std::sync::Arc;
|
|
|
|
use crate::factory::CliFactory;
|
|
use crate::graph_container::ModuleGraphContainer;
|
|
use crate::graph_container::ModuleGraphUpdatePermit;
|
|
use deno_core::error::AnyError;
|
|
use deno_core::futures::stream::FuturesUnordered;
|
|
use deno_core::futures::StreamExt;
|
|
use deno_semver::jsr::JsrPackageReqReference;
|
|
|
|
pub async fn cache_top_level_deps(
|
|
// todo(dsherret): don't pass the factory into this function. Instead use ctor deps
|
|
factory: &CliFactory,
|
|
jsr_resolver: Option<Arc<crate::jsr::JsrFetchResolver>>,
|
|
) -> Result<(), AnyError> {
|
|
let npm_resolver = factory.npm_resolver().await?;
|
|
let cli_options = factory.cli_options()?;
|
|
let root_permissions = factory.root_permissions_container()?;
|
|
if let Some(npm_resolver) = npm_resolver.as_managed() {
|
|
if !npm_resolver.ensure_top_level_package_json_install().await? {
|
|
if let Some(lockfile) = cli_options.maybe_lockfile() {
|
|
lockfile.error_if_changed()?;
|
|
}
|
|
|
|
npm_resolver.cache_packages().await?;
|
|
}
|
|
}
|
|
// cache as many entries in the import map as we can
|
|
let resolver = factory.workspace_resolver().await?;
|
|
if let Some(import_map) = resolver.maybe_import_map() {
|
|
let jsr_resolver = if let Some(resolver) = jsr_resolver {
|
|
resolver
|
|
} else {
|
|
Arc::new(crate::jsr::JsrFetchResolver::new(
|
|
factory.file_fetcher()?.clone(),
|
|
))
|
|
};
|
|
|
|
let mut roots = Vec::new();
|
|
|
|
let mut info_futures = FuturesUnordered::new();
|
|
|
|
let mut seen_reqs = std::collections::HashSet::new();
|
|
|
|
for entry in import_map.imports().entries().chain(
|
|
import_map
|
|
.scopes()
|
|
.flat_map(|scope| scope.imports.entries()),
|
|
) {
|
|
let Some(specifier) = entry.value else {
|
|
continue;
|
|
};
|
|
|
|
match specifier.scheme() {
|
|
"jsr" => {
|
|
let specifier_str = specifier.as_str();
|
|
if let Ok(req) = JsrPackageReqReference::from_str(specifier_str) {
|
|
if let Some(sub_path) = req.sub_path() {
|
|
if sub_path.ends_with('/') {
|
|
continue;
|
|
}
|
|
roots.push(specifier.clone());
|
|
continue;
|
|
}
|
|
if !seen_reqs.insert(req.req().clone()) {
|
|
continue;
|
|
}
|
|
let jsr_resolver = jsr_resolver.clone();
|
|
info_futures.push(async move {
|
|
if let Some(nv) = jsr_resolver.req_to_nv(req.req()).await {
|
|
if let Some(info) = jsr_resolver.package_version_info(&nv).await
|
|
{
|
|
return Some((specifier.clone(), info));
|
|
}
|
|
}
|
|
None
|
|
});
|
|
}
|
|
}
|
|
"npm" => roots.push(specifier.clone()),
|
|
_ => {
|
|
if entry.key.ends_with('/') && specifier.as_str().ends_with('/') {
|
|
continue;
|
|
}
|
|
if specifier.scheme() == "file" {
|
|
if let Ok(path) = specifier.to_file_path() {
|
|
if !path.is_file() {
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
roots.push(specifier.clone());
|
|
}
|
|
}
|
|
}
|
|
|
|
while let Some(info_future) = info_futures.next().await {
|
|
if let Some((specifier, info)) = info_future {
|
|
let exports = info.exports();
|
|
for (k, _) in exports {
|
|
if let Ok(spec) = specifier.join(k) {
|
|
roots.push(spec);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
let mut graph_permit = factory
|
|
.main_module_graph_container()
|
|
.await?
|
|
.acquire_update_permit()
|
|
.await;
|
|
let graph = graph_permit.graph_mut();
|
|
factory
|
|
.module_load_preparer()
|
|
.await?
|
|
.prepare_module_load(
|
|
graph,
|
|
&roots,
|
|
false,
|
|
deno_config::deno_json::TsTypeLib::DenoWorker,
|
|
root_permissions.clone(),
|
|
None,
|
|
)
|
|
.await?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|