Skip to content

Commit

Permalink
feat(lockfile): track JSR and npm dependencies in config file (#22004)
Browse files Browse the repository at this point in the history
  • Loading branch information
dsherret authored Jan 22, 2024
1 parent d20c9e7 commit 69d5f13
Show file tree
Hide file tree
Showing 18 changed files with 409 additions and 123 deletions.
34 changes: 14 additions & 20 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ deno_runtime = { version = "0.140.0", path = "./runtime" }
napi_sym = { version = "0.62.0", path = "./cli/napi/sym" }
deno_bench_util = { version = "0.126.0", path = "./bench_util" }
test_util = { path = "./test_util" }
deno_lockfile = "0.17.2"
deno_lockfile = "0.18.0"
deno_media_type = { version = "0.1.1", features = ["module_specifier"] }

denokv_proto = "0.5.0"
Expand Down
6 changes: 3 additions & 3 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@ deno_config = "=0.8.1"
deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] }
deno_doc = { version = "=0.93.0", features = ["html"] }
deno_emit = "=0.33.0"
deno_graph = "=0.63.3"
deno_graph = "=0.63.4"
deno_lint = { version = "=0.53.0", features = ["docs"] }
deno_lockfile.workspace = true
deno_npm = "=0.15.3"
deno_npm = "=0.16.0"
deno_runtime = { workspace = true, features = ["include_js_files_for_snapshotting"] }
deno_semver = "=0.5.4"
deno_task_shell = "=0.14.3"
eszip = "=0.57.0"
eszip = "=0.58.0"
napi_sym.workspace = true

async-trait.workspace = true
Expand Down
4 changes: 4 additions & 0 deletions cli/args/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1344,6 +1344,10 @@ impl CliOptions {
self.flags.no_npm
}

pub fn no_config(&self) -> bool {
self.flags.config_flag == deno_config::ConfigFlag::Disabled
}

pub fn permissions_options(&self) -> PermissionsOptions {
PermissionsOptions {
allow_env: self.flags.allow_env.clone(),
Expand Down
34 changes: 4 additions & 30 deletions cli/args/package_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use std::path::PathBuf;
use deno_core::anyhow::bail;
use deno_core::error::AnyError;
use deno_npm::registry::parse_dep_entry_name_and_raw_version;
use deno_npm::registry::PackageDepNpmSchemeValueParseError;
use deno_runtime::deno_node::PackageJson;
use deno_semver::package::PackageReq;
use deno_semver::VersionReq;
Expand All @@ -16,8 +15,6 @@ use thiserror::Error;

#[derive(Debug, Error, Clone)]
pub enum PackageJsonDepValueParseError {
#[error(transparent)]
SchemeValue(#[from] PackageDepNpmSchemeValueParseError),
#[error(transparent)]
Specifier(#[from] VersionReqSpecifierParseError),
#[error("Not implemented scheme '{scheme}'")]
Expand All @@ -39,17 +36,17 @@ impl PackageJsonDepsProvider {
self.0.as_ref()
}

pub fn reqs(&self) -> Vec<&PackageReq> {
pub fn reqs(&self) -> Option<Vec<&PackageReq>> {
match &self.0 {
Some(deps) => {
let mut package_reqs = deps
.values()
.filter_map(|r| r.as_ref().ok())
.collect::<Vec<_>>();
package_reqs.sort(); // deterministic resolution
package_reqs
Some(package_reqs)
}
None => Vec::new(),
None => None,
}
}
}
Expand Down Expand Up @@ -77,9 +74,7 @@ pub fn get_local_package_json_version_reqs(
scheme: value.split(':').next().unwrap().to_string(),
});
}
let (name, version_req) = parse_dep_entry_name_and_raw_version(key, value)
.map_err(PackageJsonDepValueParseError::SchemeValue)?;

let (name, version_req) = parse_dep_entry_name_and_raw_version(key, value);
let result = VersionReq::parse_from_specifier(version_req);
match result {
Ok(version_req) => Ok(PackageReq {
Expand Down Expand Up @@ -159,27 +154,6 @@ mod test {

use super::*;

#[test]
fn test_parse_dep_entry_name_and_raw_version() {
let cases = [
("test", "^1.2", Ok(("test", "^1.2"))),
("test", "1.x - 2.6", Ok(("test", "1.x - 2.6"))),
("test", "npm:package@^1.2", Ok(("package", "^1.2"))),
(
"test",
"npm:package",
Err("Could not find @ symbol in npm url 'npm:package'"),
),
];
for (key, value, expected_result) in cases {
let result = parse_dep_entry_name_and_raw_version(key, value);
match result {
Ok(result) => assert_eq!(result, expected_result.unwrap()),
Err(err) => assert_eq!(err.to_string(), expected_result.err().unwrap()),
}
}
}

fn get_local_package_json_version_reqs_for_tests(
package_json: &PackageJson,
) -> IndexMap<String, Result<PackageReq, String>> {
Expand Down
88 changes: 83 additions & 5 deletions cli/factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ use crate::standalone::DenoCompileBinaryWriter;
use crate::tools::check::TypeChecker;
use crate::util::file_watcher::WatcherCommunicator;
use crate::util::fs::canonicalize_path_maybe_not_exists;
use crate::util::import_map::deno_json_deps;
use crate::util::import_map::import_map_deps;
use crate::util::progress_bar::ProgressBar;
use crate::util::progress_bar::ProgressBarStyle;
use crate::worker::CliMainWorkerFactory;
Expand All @@ -54,12 +56,14 @@ use deno_core::parking_lot::Mutex;
use deno_core::FeatureChecker;

use deno_graph::GraphKind;
use deno_lockfile::WorkspaceMemberConfig;
use deno_runtime::deno_fs;
use deno_runtime::deno_node::analyze::NodeCodeTranslator;
use deno_runtime::deno_node::NodeResolver;
use deno_runtime::deno_tls::RootCertStoreProvider;
use deno_runtime::deno_web::BlobStore;
use deno_runtime::inspector_server::InspectorServer;
use deno_semver::package::PackageNv;
use import_map::ImportMap;
use log::warn;
use std::future::Future;
Expand Down Expand Up @@ -289,10 +293,84 @@ impl CliFactory {
}

pub fn maybe_lockfile(&self) -> &Option<Arc<Mutex<Lockfile>>> {
self
.services
.lockfile
.get_or_init(|| self.options.maybe_lockfile())
self.services.lockfile.get_or_init(|| {
let maybe_lockfile = self.options.maybe_lockfile();

// initialize the lockfile with the workspace's configuration
if let Some(lockfile) = &maybe_lockfile {
let package_json_deps = self
.package_json_deps_provider()
.reqs()
.map(|reqs| reqs.into_iter().map(|s| format!("npm:{}", s)).collect())
.unwrap_or_default();
let mut lockfile = lockfile.lock();
let config = match self.options.maybe_workspace_config() {
Some(workspace_config) => deno_lockfile::WorkspaceConfig {
root: WorkspaceMemberConfig {
package_json_deps,
dependencies: import_map_deps(
&workspace_config.base_import_map_value,
)
.into_iter()
.map(|req| req.to_string())
.collect(),
},
members: workspace_config
.members
.iter()
.map(|member| {
(
member.package_name.clone(),
WorkspaceMemberConfig {
package_json_deps: Default::default(),
dependencies: deno_json_deps(&member.config_file)
.into_iter()
.map(|req| req.to_string())
.collect(),
},
)
})
.collect(),
},
None => deno_lockfile::WorkspaceConfig {
root: WorkspaceMemberConfig {
package_json_deps,
dependencies: self
.options
.maybe_config_file()
.as_ref()
.map(|config| {
deno_json_deps(config)
.into_iter()
.map(|req| req.to_string())
.collect()
})
.unwrap_or_default(),
},
members: Default::default(),
},
};
lockfile.set_workspace_config(
deno_lockfile::SetWorkspaceConfigOptions {
no_npm: self.options.no_npm(),
no_config: self.options.no_config(),
config,
nv_to_jsr_url: |nv| {
let nv = PackageNv::from_str(nv).ok()?;
Some(
deno_graph::source::recommended_registry_package_url(
crate::args::deno_registry_url(),
&nv,
)
.to_string(),
)
},
},
);
}

maybe_lockfile
})
}

pub async fn npm_resolver(
Expand Down Expand Up @@ -320,7 +398,7 @@ impl CliFactory {
Some(snapshot) => {
CliNpmResolverManagedSnapshotOption::Specified(Some(snapshot))
}
None => match self.maybe_lockfile() {
None => match self.maybe_lockfile().as_ref() {
Some(lockfile) => {
CliNpmResolverManagedSnapshotOption::ResolveFromLockfile(
lockfile.clone(),
Expand Down
4 changes: 4 additions & 0 deletions cli/graph_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,10 @@ impl ModuleGraphBuilder {
format!("jsr:{}", to),
);
}
for (name, deps) in graph.packages.package_deps() {
lockfile
.insert_package_deps(name.to_string(), deps.map(|s| s.to_string()));
}
}
}

Expand Down
10 changes: 9 additions & 1 deletion cli/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use deno_core::error::AnyError;
use deno_core::error::JsError;
use deno_core::futures::FutureExt;
use deno_core::unsync::JoinHandle;
use deno_npm::resolution::SnapshotFromLockfileError;
use deno_runtime::colors;
use deno_runtime::fmt_errors::format_js_error;
use deno_runtime::tokio_util::create_and_run_current_thread_with_maybe_metrics;
Expand Down Expand Up @@ -261,7 +262,14 @@ fn unwrap_or_exit<T>(result: Result<T, AnyError>) -> T {

if let Some(e) = error.downcast_ref::<JsError>() {
error_string = format_js_error(e);
} else if let Some(e) = error.downcast_ref::<args::LockfileError>() {
} else if let Some(args::LockfileError::IntegrityCheckFailed(e)) =
error.downcast_ref::<args::LockfileError>()
{
error_string = e.to_string();
error_code = 10;
} else if let Some(SnapshotFromLockfileError::IntegrityCheckFailed(e)) =
error.downcast_ref::<SnapshotFromLockfileError>()
{
error_string = e.to_string();
error_code = 10;
}
Expand Down
2 changes: 1 addition & 1 deletion cli/npm/managed/installer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ impl PackageJsonDepsInstaller {
return Ok(()); // already installed by something else
}

let package_reqs = inner.deps_provider.reqs();
let package_reqs = inner.deps_provider.reqs().unwrap_or_default();

// check if something needs resolving before bothering to load all
// the package information (which is slow)
Expand Down
Loading

0 comments on commit 69d5f13

Please sign in to comment.