Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add deno update and deno outdated subcommands [WIP] #26219

Closed
wants to merge 7 commits into from
Closed
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
36 changes: 36 additions & 0 deletions cli/args/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,11 @@ impl LintFlags {
}
}

#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct OutdatedFlags {
pub filters: Vec<String>,
}

#[derive(Clone, Debug, Eq, PartialEq, Default)]
pub struct ReplFlags {
pub eval_files: Option<Vec<String>>,
Expand Down Expand Up @@ -456,6 +461,7 @@ pub enum DenoSubcommand {
Uninstall(UninstallFlags),
Lsp,
Lint(LintFlags),
Outdated(OutdatedFlags),
Repl(ReplFlags),
Run(RunFlags),
Serve(ServeFlags),
Expand Down Expand Up @@ -1375,6 +1381,7 @@ pub fn flags_from_vec(args: Vec<OsString>) -> clap::error::Result<Flags> {
"jupyter" => jupyter_parse(&mut flags, &mut m),
"lint" => lint_parse(&mut flags, &mut m)?,
"lsp" => lsp_parse(&mut flags, &mut m),
"outdated" => outdated_parse(&mut flags, &mut m)?,
"repl" => repl_parse(&mut flags, &mut m)?,
"run" => run_parse(&mut flags, &mut m, app, false)?,
"serve" => serve_parse(&mut flags, &mut m, app)?,
Expand Down Expand Up @@ -1594,6 +1601,7 @@ pub fn clap_root() -> Command {
.subcommand(uninstall_subcommand())
.subcommand(lsp_subcommand())
.subcommand(lint_subcommand())
.subcommand(outdated_subcommand())
.subcommand(publish_subcommand())
.subcommand(repl_subcommand())
.subcommand(task_subcommand())
Expand Down Expand Up @@ -2741,6 +2749,22 @@ To ignore linting on an entire file, you can add an ignore comment at the top of
})
}

fn outdated_subcommand() -> Command {
command(
"outdated",
"Check for outdated dependencies",
UnstableArgsConfig::None,
)
.defer(|cmd| {
cmd.arg(
Arg::new("filters")
.num_args(0..)
.action(ArgAction::Append)
.help("List of filters used for checking outdated packages"),
)
})
}

fn repl_subcommand() -> Command {
command("repl", "Read Eval Print Loop", UnstableArgsConfig::ResolutionAndRuntime)
.defer(|cmd| runtime_args(cmd, true, true)
Expand Down Expand Up @@ -4756,6 +4780,18 @@ fn lsp_parse(flags: &mut Flags, _matches: &mut ArgMatches) {
flags.subcommand = DenoSubcommand::Lsp;
}

fn outdated_parse(
flags: &mut Flags,
matches: &mut ArgMatches,
) -> clap::error::Result<()> {
let filters = match matches.remove_many::<String>("filters") {
Some(f) => f.collect(),
None => vec![],
};
flags.subcommand = DenoSubcommand::Outdated(OutdatedFlags { filters });
Ok(())
}

fn lint_parse(
flags: &mut Flags,
matches: &mut ArgMatches,
Expand Down
2 changes: 1 addition & 1 deletion cli/factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ impl CliFactory {
let fs = self.fs();
let cli_options = self.cli_options()?;
// For `deno install` we want to force the managed resolver so it can set up `node_modules/` directory.
create_cli_npm_resolver(if cli_options.use_byonm() && !matches!(cli_options.sub_command(), DenoSubcommand::Install(_) | DenoSubcommand::Add(_) | DenoSubcommand::Remove(_)) {
create_cli_npm_resolver(if cli_options.use_byonm() && !matches!(cli_options.sub_command(), DenoSubcommand::Install(_) | DenoSubcommand::Outdated(_) | DenoSubcommand::Add(_) | DenoSubcommand::Remove(_)) {
CliNpmResolverCreateOptions::Byonm(CliNpmResolverByonmCreateOptions {
fs: fs.clone(),
root_node_modules_dir: Some(match cli_options.node_modules_dir_path() {
Expand Down
3 changes: 3 additions & 0 deletions cli/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,9 @@ async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
"This deno was built without the \"upgrade\" feature. Please upgrade using the installation method originally used to install Deno.",
1,
),
DenoSubcommand::Outdated(outdated_flags) => spawn_subcommand(async {
tools::registry::outdated(flags, outdated_flags).await
}),
DenoSubcommand::Vendor => exit_with_message("⚠️ `deno vendor` was removed in Deno 2.\n\nSee the Deno 1.x to 2.x Migration Guide for migration instructions: https://docs.deno.com/runtime/manual/advanced/migrate_deprecations", 1),
DenoSubcommand::Publish(publish_flags) => spawn_subcommand(async {
tools::registry::publish(flags, publish_flags).await
Expand Down
6 changes: 5 additions & 1 deletion cli/npm/managed/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -461,13 +461,17 @@ impl ManagedCliNpmResolver {
self.resolve_pkg_folder_from_pkg_id(&pkg_id)
}

fn resolve_pkg_id_from_pkg_req(
pub fn resolve_pkg_id_from_pkg_req(
&self,
req: &PackageReq,
) -> Result<NpmPackageId, PackageReqNotFoundError> {
self.resolution.resolve_pkg_id_from_pkg_req(req)
}

pub fn npm_deps_provider(&self) -> Arc<NpmInstallDepsProvider> {
self.npm_install_deps_provider.clone()
}

/// Ensures that the top level `package.json` dependencies are installed.
/// This may set up the `node_modules` directory.
///
Expand Down
1 change: 1 addition & 0 deletions cli/tools/registry/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ use auth::get_auth_method;
use auth::AuthMethod;
pub use pm::add;
pub use pm::cache_top_level_deps;
pub use pm::outdated;
pub use pm::remove;
pub use pm::AddCommandName;
use publish_order::PublishOrderGraph;
Expand Down
9 changes: 7 additions & 2 deletions cli/tools/registry/pm.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

mod cache_deps;

pub use cache_deps::cache_top_level_deps;
use deno_semver::jsr::JsrPackageReqReference;
use deno_semver::npm::NpmPackageReqReference;
Expand Down Expand Up @@ -38,6 +36,11 @@ use crate::file_fetcher::FileFetcher;
use crate::jsr::JsrFetchResolver;
use crate::npm::NpmFetchResolver;

mod cache_deps;
mod outdated;

pub use outdated::outdated;

enum DenoConfigFormat {
Json,
Jsonc,
Expand Down Expand Up @@ -568,13 +571,15 @@ pub async fn add(
Ok(())
}

#[derive(Debug, PartialEq)]
struct SelectedPackage {
import_name: String,
package_name: String,
version_req: String,
selected_version: String,
}

#[derive(Debug, PartialEq)]
enum PackageAndVersion {
NotFound {
package: String,
Expand Down
89 changes: 89 additions & 0 deletions cli/tools/registry/pm/cache_deps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,97 @@ use crate::graph_container::ModuleGraphUpdatePermit;
use deno_core::error::AnyError;
use deno_core::futures::stream::FuturesUnordered;
use deno_core::futures::StreamExt;
use deno_core::url::Url;
use deno_semver::package::PackageReq;

pub async fn find_top_level_deps(
factory: &CliFactory,
jsr_resolver: Option<Arc<crate::jsr::JsrFetchResolver>>,
) -> Result<Vec<Url>, 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?;
// }
// }

let mut roots = Vec::new();

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 info_futures = FuturesUnordered::new();

let mut seen_reqs = std::collections::HashSet::new();

for entry in import_map.imports().entries() {
let Some(specifier) = entry.value else {
continue;
};

match specifier.scheme() {
"jsr" => {
let specifier_str = specifier.as_str();
let specifier_str =
specifier_str.strip_prefix("jsr:").unwrap_or(specifier_str);
if let Ok(req) = PackageReq::from_str(specifier_str) {
if !seen_reqs.insert(req.clone()) {
continue;
}
let jsr_resolver = jsr_resolver.clone();
info_futures.push(async move {
if let Some(nv) = jsr_resolver.req_to_nv(&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;
}
roots.push(specifier.clone());
}
}
}

while let Some(info_future) = info_futures.next().await {
if let Some((specifier, info)) = info_future {
if info.export(".").is_some() {
roots.push(specifier.clone());
continue;
}
let exports = info.exports();
for (k, _) in exports {
if let Ok(spec) = specifier.join(k) {
roots.push(spec);
}
}
}
}
}

Ok(roots)
}

pub async fn cache_top_level_deps(
factory: &CliFactory,
jsr_resolver: Option<Arc<crate::jsr::JsrFetchResolver>>,
Expand Down
Loading