summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2022-10-19 23:30:44 +0200
committerGitHub <noreply@github.com>2022-10-19 23:30:44 +0200
commit973069b341de65e8e32b91072ff5a745fe7e704a (patch)
tree48fef8a8e9792b26f2d438b0769c99184d3493a7
parente3a30954811238ce55a9d0f8b193c3a58535b72d (diff)
feat: Add new lockfile format (#16349)
Introduces a new lockfile format that will be used to support locking "npm" dependencies. Currently the format looks as follows: ``` // This file is automatically generated by Deno, do not edit its contents // manually. This file should be commited to your repository. { "version": "2", "remote": { "https://deno.land/std@0.160.0/http/server.ts": "asdwetsw44523asdfgfas..", "https://deno.land/std@0.160.0/http/file_server.ts": "asdwetsw44523asdfgfas.." } } ``` A follow up PR will add "npm" key that will be used to store information related to "npm" dependencies and their resolution. The new format is used when `--lock-write` is present, if user tries to load a lock file using the old format it will still work.
-rw-r--r--cli/lockfile.rs109
-rw-r--r--cli/tests/integration/run_tests.rs34
-rw-r--r--cli/tests/testdata/run/lock_v2_check_err.json7
-rw-r--r--cli/tests/testdata/run/lock_v2_check_err.out3
-rw-r--r--cli/tests/testdata/run/lock_v2_check_err2.json13
-rw-r--r--cli/tests/testdata/run/lock_v2_check_err2.out3
-rw-r--r--cli/tests/testdata/run/lock_v2_check_ok.json7
-rw-r--r--cli/tests/testdata/run/lock_v2_check_ok2.json13
-rw-r--r--cli/tests/testdata/run/lock_v2_dynamic_imports.json9
-rw-r--r--cli/tests/testdata/run/lock_v2_dynamic_imports.out4
10 files changed, 180 insertions, 22 deletions
diff --git a/cli/lockfile.rs b/cli/lockfile.rs
index a2658918d..afbd8d287 100644
--- a/cli/lockfile.rs
+++ b/cli/lockfile.rs
@@ -1,8 +1,12 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+#![allow(dead_code)]
+
use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_core::parking_lot::Mutex;
+use deno_core::serde::Deserialize;
+use deno_core::serde::Serialize;
use deno_core::serde_json;
use deno_core::serde_json::json;
use deno_core::ModuleSpecifier;
@@ -16,9 +20,20 @@ use std::sync::Arc;
use crate::tools::fmt::format_json;
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct LockfileV2Content {
+ version: String,
+ // Mapping between URLs and their checksums
+ remote: BTreeMap<String, String>,
+}
+
+#[derive(Debug, Clone, Deserialize)]
+pub struct LockfileV1Content(BTreeMap<String, String>);
+
#[derive(Debug, Clone)]
-pub struct LockfileContent {
- map: BTreeMap<String, String>,
+enum LockfileContent {
+ V1(LockfileV1Content),
+ V2(LockfileV2Content),
}
#[derive(Debug, Clone)]
@@ -30,19 +45,33 @@ pub struct Lockfile {
impl Lockfile {
pub fn new(filename: PathBuf, write: bool) -> Result<Lockfile, AnyError> {
- let map = if write {
- BTreeMap::new()
+ // Writing a lock file always uses the new format.
+ let content = if write {
+ LockfileContent::V2(LockfileV2Content {
+ version: "2".to_string(),
+ remote: BTreeMap::new(),
+ })
} else {
let s = std::fs::read_to_string(&filename).with_context(|| {
format!("Unable to read lockfile: {}", filename.display())
})?;
- serde_json::from_str(&s)
- .context("Unable to parse contents of the lockfile")?
+ let value: serde_json::Value = serde_json::from_str(&s)
+ .context("Unable to parse contents of the lockfile")?;
+ let version = value.get("version").and_then(|v| v.as_str());
+ if version == Some("2") {
+ let content: LockfileV2Content =
+ serde_json::from_value(value).context("Unable to parse lockfile")?;
+ LockfileContent::V2(content)
+ } else {
+ let content: LockfileV1Content =
+ serde_json::from_value(value).context("Unable to parse lockfile")?;
+ LockfileContent::V1(content)
+ }
};
Ok(Lockfile {
write,
- content: LockfileContent { map },
+ content,
filename,
})
}
@@ -52,13 +81,19 @@ impl Lockfile {
if !self.write {
return Ok(());
}
- let j = json!(&self.content.map);
- let s = serde_json::to_string_pretty(&j).unwrap();
- let format_s = format_json(&s, &Default::default())
+ let json_string = match &self.content {
+ LockfileContent::V1(c) => {
+ let j = json!(&c.0);
+ serde_json::to_string(&j).unwrap()
+ }
+ LockfileContent::V2(c) => serde_json::to_string(&c).unwrap(),
+ };
+
+ let format_s = format_json(&json_string, &Default::default())
.ok()
.flatten()
- .unwrap_or(s);
+ .unwrap_or(json_string);
let mut f = std::fs::OpenOptions::new()
.write(true)
.create(true)
@@ -85,11 +120,23 @@ impl Lockfile {
if specifier.starts_with("file:") {
return true;
}
- if let Some(lockfile_checksum) = self.content.map.get(specifier) {
- let compiled_checksum = crate::checksum::gen(&[code.as_bytes()]);
- lockfile_checksum == &compiled_checksum
- } else {
- false
+ match &self.content {
+ LockfileContent::V1(c) => {
+ if let Some(lockfile_checksum) = c.0.get(specifier) {
+ let compiled_checksum = crate::checksum::gen(&[code.as_bytes()]);
+ lockfile_checksum == &compiled_checksum
+ } else {
+ false
+ }
+ }
+ LockfileContent::V2(c) => {
+ if let Some(lockfile_checksum) = c.remote.get(specifier) {
+ let compiled_checksum = crate::checksum::gen(&[code.as_bytes()]);
+ lockfile_checksum == &compiled_checksum
+ } else {
+ false
+ }
+ }
}
}
@@ -98,7 +145,14 @@ impl Lockfile {
return;
}
let checksum = crate::checksum::gen(&[code.as_bytes()]);
- self.content.map.insert(specifier.to_string(), checksum);
+ match &mut self.content {
+ LockfileContent::V1(c) => {
+ c.0.insert(specifier.to_string(), checksum);
+ }
+ LockfileContent::V2(c) => {
+ c.remote.insert(specifier.to_string(), checksum);
+ }
+ };
}
}
@@ -154,8 +208,11 @@ mod tests {
let mut file = File::create(file_path).expect("write file fail");
let value: serde_json::Value = json!({
- "https://deno.land/std@0.71.0/textproto/mod.ts": "3118d7a42c03c242c5a49c2ad91c8396110e14acca1324e7aaefd31a999b71a4",
- "https://deno.land/std@0.71.0/async/delay.ts": "35957d585a6e3dd87706858fb1d6b551cb278271b03f52c5a2cb70e65e00c26a"
+ "version": "2",
+ "remote": {
+ "https://deno.land/std@0.71.0/textproto/mod.ts": "3118d7a42c03c242c5a49c2ad91c8396110e14acca1324e7aaefd31a999b71a4",
+ "https://deno.land/std@0.71.0/async/delay.ts": "35957d585a6e3dd87706858fb1d6b551cb278271b03f52c5a2cb70e65e00c26a"
+ }
});
file.write_all(value.to_string().as_bytes()).unwrap();
@@ -176,7 +233,11 @@ mod tests {
let result = Lockfile::new(file_path, false).unwrap();
- let keys: Vec<String> = result.content.map.keys().cloned().collect();
+ let remote = match result.content {
+ LockfileContent::V2(c) => c.remote,
+ _ => unreachable!(),
+ };
+ let keys: Vec<String> = remote.keys().cloned().collect();
let expected_keys = vec![
String::from("https://deno.land/std@0.71.0/async/delay.ts"),
String::from("https://deno.land/std@0.71.0/textproto/mod.ts"),
@@ -198,7 +259,11 @@ mod tests {
"Here is some source code",
);
- let keys: Vec<String> = lockfile.content.map.keys().cloned().collect();
+ let remote = match lockfile.content {
+ LockfileContent::V2(c) => c.remote,
+ _ => unreachable!(),
+ };
+ let keys: Vec<String> = remote.keys().cloned().collect();
let expected_keys = vec![
String::from("https://deno.land/std@0.71.0/async/delay.ts"),
String::from("https://deno.land/std@0.71.0/io/util.ts"),
@@ -242,7 +307,7 @@ mod tests {
let contents_json =
serde_json::from_str::<serde_json::Value>(&contents).unwrap();
- let object = contents_json.as_object().unwrap();
+ let object = contents_json["remote"].as_object().unwrap();
assert_eq!(
object
diff --git a/cli/tests/integration/run_tests.rs b/cli/tests/integration/run_tests.rs
index 156940185..71b26b356 100644
--- a/cli/tests/integration/run_tests.rs
+++ b/cli/tests/integration/run_tests.rs
@@ -658,6 +658,40 @@ itest!(lock_check_err2 {
http_server: true,
});
+itest!(lock_v2_check_ok {
+ args:
+ "run --lock=run/lock_v2_check_ok.json http://127.0.0.1:4545/run/003_relative_import.ts",
+ output: "run/003_relative_import.ts.out",
+ http_server: true,
+});
+
+itest!(lock_v2_check_ok2 {
+ args: "run --lock=run/lock_v2_check_ok2.json run/019_media_types.ts",
+ output: "run/019_media_types.ts.out",
+ http_server: true,
+});
+
+itest!(lock_v2_dynamic_imports {
+ args: "run --lock=run/lock_v2_dynamic_imports.json --allow-read --allow-net http://127.0.0.1:4545/run/013_dynamic_import.ts",
+ output: "run/lock_v2_dynamic_imports.out",
+ exit_code: 10,
+ http_server: true,
+});
+
+itest!(lock_v2_check_err {
+ args: "run --lock=run/lock_v2_check_err.json http://127.0.0.1:4545/run/003_relative_import.ts",
+ output: "run/lock_v2_check_err.out",
+ exit_code: 10,
+ http_server: true,
+});
+
+itest!(lock_v2_check_err2 {
+ args: "run --lock=run/lock_v2_check_err2.json run/019_media_types.ts",
+ output: "run/lock_v2_check_err2.out",
+ exit_code: 10,
+ http_server: true,
+});
+
itest!(mts_dmts_mjs {
args: "run subdir/import.mts",
output: "run/mts_dmts_mjs.out",
diff --git a/cli/tests/testdata/run/lock_v2_check_err.json b/cli/tests/testdata/run/lock_v2_check_err.json
new file mode 100644
index 000000000..6bd6491c6
--- /dev/null
+++ b/cli/tests/testdata/run/lock_v2_check_err.json
@@ -0,0 +1,7 @@
+{
+ "version": "2",
+ "remote": {
+ "http://127.0.0.1:4545/subdir/print_hello.ts": "fa6692c8f9ff3fb107e773c3ece5274e9d08be282867a1e3ded1d9c00fcaa63c",
+ "http://127.0.0.1:4545/run/003_relative_import.ts": "bad"
+ }
+}
diff --git a/cli/tests/testdata/run/lock_v2_check_err.out b/cli/tests/testdata/run/lock_v2_check_err.out
new file mode 100644
index 000000000..28ad01cf4
--- /dev/null
+++ b/cli/tests/testdata/run/lock_v2_check_err.out
@@ -0,0 +1,3 @@
+[WILDCARD]The source code is invalid, as it does not match the expected hash in the lock file.
+ Specifier: http://127.0.0.1:4545/run/003_relative_import.ts
+ Lock file: run/lock_v2_check_err.json
diff --git a/cli/tests/testdata/run/lock_v2_check_err2.json b/cli/tests/testdata/run/lock_v2_check_err2.json
new file mode 100644
index 000000000..30fbcdf4b
--- /dev/null
+++ b/cli/tests/testdata/run/lock_v2_check_err2.json
@@ -0,0 +1,13 @@
+{
+ "version": "2",
+ "remote": {
+ "http://localhost:4545/subdir/mt_application_ecmascript.j2.js": "3a3e002e2f92dc8f045bd4a7c66b4791453ad0417b038dd2b2d9d0f277c44f18",
+ "http://localhost:4545/subdir/mt_application_x_javascript.j4.js": "3a3e002e2f92dc8f045bd4a7c66b4791453ad0417b038dd2b2d9d0f277c44f18",
+ "http://localhost:4545/subdir/mt_application_x_typescript.t4.ts": "3a3e002e2f92dc8f045bd4a7c66b4791453ad0417b038dd2b2d9d0f277c44f18",
+ "http://localhost:4545/subdir/mt_text_ecmascript.j3.js": "bad",
+ "http://localhost:4545/subdir/mt_text_javascript.j1.js": "3a3e002e2f92dc8f045bd4a7c66b4791453ad0417b038dd2b2d9d0f277c44f18",
+ "http://localhost:4545/subdir/mt_text_typescript.t1.ts": "3a3e002e2f92dc8f045bd4a7c66b4791453ad0417b038dd2b2d9d0f277c44f18",
+ "http://localhost:4545/subdir/mt_video_mp2t.t3.ts": "3a3e002e2f92dc8f045bd4a7c66b4791453ad0417b038dd2b2d9d0f277c44f18",
+ "http://localhost:4545/subdir/mt_video_vdn.t2.ts": "3a3e002e2f92dc8f045bd4a7c66b4791453ad0417b038dd2b2d9d0f277c44f18"
+ }
+}
diff --git a/cli/tests/testdata/run/lock_v2_check_err2.out b/cli/tests/testdata/run/lock_v2_check_err2.out
new file mode 100644
index 000000000..3d82cba27
--- /dev/null
+++ b/cli/tests/testdata/run/lock_v2_check_err2.out
@@ -0,0 +1,3 @@
+[WILDCARD]The source code is invalid, as it does not match the expected hash in the lock file.
+ Specifier: http://localhost:4545/subdir/mt_text_ecmascript.j3.js
+ Lock file: run/lock_v2_check_err2.json
diff --git a/cli/tests/testdata/run/lock_v2_check_ok.json b/cli/tests/testdata/run/lock_v2_check_ok.json
new file mode 100644
index 000000000..63bec862a
--- /dev/null
+++ b/cli/tests/testdata/run/lock_v2_check_ok.json
@@ -0,0 +1,7 @@
+{
+ "version": "2",
+ "remote": {
+ "http://127.0.0.1:4545/subdir/print_hello.ts": "fa6692c8f9ff3fb107e773c3ece5274e9d08be282867a1e3ded1d9c00fcaa63c",
+ "http://127.0.0.1:4545/run/003_relative_import.ts": "a1572e8fd2c2712b33f04aed2561505b5feb2c8696f1f2cded3de7127931b97e"
+ }
+}
diff --git a/cli/tests/testdata/run/lock_v2_check_ok2.json b/cli/tests/testdata/run/lock_v2_check_ok2.json
new file mode 100644
index 000000000..4356c9421
--- /dev/null
+++ b/cli/tests/testdata/run/lock_v2_check_ok2.json
@@ -0,0 +1,13 @@
+{
+ "version": "2",
+ "remote": {
+ "http://localhost:4545/subdir/mt_application_ecmascript.j2.js": "3a3e002e2f92dc8f045bd4a7c66b4791453ad0417b038dd2b2d9d0f277c44f18",
+ "http://localhost:4545/subdir/mt_application_x_javascript.j4.js": "3a3e002e2f92dc8f045bd4a7c66b4791453ad0417b038dd2b2d9d0f277c44f18",
+ "http://localhost:4545/subdir/mt_application_x_typescript.t4.ts": "3a3e002e2f92dc8f045bd4a7c66b4791453ad0417b038dd2b2d9d0f277c44f18",
+ "http://localhost:4545/subdir/mt_text_ecmascript.j3.js": "3a3e002e2f92dc8f045bd4a7c66b4791453ad0417b038dd2b2d9d0f277c44f18",
+ "http://localhost:4545/subdir/mt_text_javascript.j1.js": "3a3e002e2f92dc8f045bd4a7c66b4791453ad0417b038dd2b2d9d0f277c44f18",
+ "http://localhost:4545/subdir/mt_text_typescript.t1.ts": "3a3e002e2f92dc8f045bd4a7c66b4791453ad0417b038dd2b2d9d0f277c44f18",
+ "http://localhost:4545/subdir/mt_video_mp2t.t3.ts": "3a3e002e2f92dc8f045bd4a7c66b4791453ad0417b038dd2b2d9d0f277c44f18",
+ "http://localhost:4545/subdir/mt_video_vdn.t2.ts": "3a3e002e2f92dc8f045bd4a7c66b4791453ad0417b038dd2b2d9d0f277c44f18"
+ }
+}
diff --git a/cli/tests/testdata/run/lock_v2_dynamic_imports.json b/cli/tests/testdata/run/lock_v2_dynamic_imports.json
new file mode 100644
index 000000000..eadbee272
--- /dev/null
+++ b/cli/tests/testdata/run/lock_v2_dynamic_imports.json
@@ -0,0 +1,9 @@
+{
+ "version": "2",
+ "remote": {
+ "http://127.0.0.1:4545/run/013_dynamic_import.ts": "3f83e653329dc1f963761a986997d710b9763f667fc243eef89b3a5decacda30",
+ "http://127.0.0.1:4545/subdir/mod1.ts": "bfc1037b02c99abc20367f739bca7455813a5950066abd77965bff33b6eece0f",
+ "http://127.0.0.1:4545/subdir/print_hello.ts": "fa6692c8f9ff3fb107e773c3ece5274e9d08be282867a1e3ded1d9c00fcaa63c",
+ "http://127.0.0.1:4545/subdir/subdir2/mod2.ts": "bad"
+ }
+}
diff --git a/cli/tests/testdata/run/lock_v2_dynamic_imports.out b/cli/tests/testdata/run/lock_v2_dynamic_imports.out
new file mode 100644
index 000000000..36c2c9b5c
--- /dev/null
+++ b/cli/tests/testdata/run/lock_v2_dynamic_imports.out
@@ -0,0 +1,4 @@
+[WILDCARD]
+error: The source code is invalid, as it does not match the expected hash in the lock file.
+ Specifier: http://127.0.0.1:4545/subdir/subdir2/mod2.ts
+ Lock file: run/lock_v2_dynamic_imports.json