Skip to content

Commit

Permalink
Merge branch 'main' into deno_upgrade_prompt
Browse files Browse the repository at this point in the history
  • Loading branch information
bartlomieju committed Aug 26, 2024
2 parents 909bf33 + ba58628 commit 047dbf6
Show file tree
Hide file tree
Showing 27 changed files with 640 additions and 357 deletions.
4 changes: 2 additions & 2 deletions .dprint.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@
"plugins": [
"https://plugins.dprint.dev/typescript-0.91.6.wasm",
"https://plugins.dprint.dev/json-0.19.3.wasm",
"https://plugins.dprint.dev/markdown-0.17.6.wasm",
"https://plugins.dprint.dev/markdown-0.17.8.wasm",
"https://plugins.dprint.dev/toml-0.6.2.wasm",
"https://plugins.dprint.dev/exec-0.5.0.json@8d9972eee71fa1590e04873540421f3eda7674d0f1aae3d7c788615e7b7413d0",
"https://plugins.dprint.dev/g-plane/pretty_yaml-v0.4.0.wasm"
"https://plugins.dprint.dev/g-plane/pretty_yaml-v0.5.0.wasm"
]
}
4 changes: 2 additions & 2 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 cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ dissimilar = "=1.0.4"
dotenvy = "0.15.7"
dprint-plugin-json = "=0.19.3"
dprint-plugin-jupyter = "=0.1.3"
dprint-plugin-markdown = "=0.17.6"
dprint-plugin-markdown = "=0.17.8"
dprint-plugin-typescript = "=0.91.6"
env_logger = "=0.10.0"
fancy-regex = "=0.10.0"
Expand Down
165 changes: 92 additions & 73 deletions cli/cache/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,25 @@ use std::path::PathBuf;
use deno_ast::ModuleSpecifier;
use deno_core::anyhow::anyhow;
use deno_core::error::AnyError;
use deno_core::serde_json;
use deno_core::unsync::sync::AtomicFlag;
use serde::Deserialize;
use serde::Serialize;

use super::DiskCache;
use super::FastInsecureHasher;

#[derive(Debug, Deserialize, Serialize)]
struct EmitMetadata {
pub source_hash: u64,
pub emit_hash: u64,
}

/// The cache that stores previously emitted files.
pub struct EmitCache {
disk_cache: DiskCache,
cli_version: &'static str,
emit_failed_flag: AtomicFlag,
file_serializer: EmitFileSerializer,
}

impl EmitCache {
pub fn new(disk_cache: DiskCache) -> Self {
Self {
disk_cache,
cli_version: crate::version::DENO_VERSION_INFO.deno,
emit_failed_flag: Default::default(),
file_serializer: EmitFileSerializer {
cli_version: crate::version::DENO_VERSION_INFO.deno,
},
}
}

Expand All @@ -48,37 +40,11 @@ impl EmitCache {
specifier: &ModuleSpecifier,
expected_source_hash: u64,
) -> Option<Vec<u8>> {
let meta_filename = self.get_meta_filename(specifier)?;
let emit_filename = self.get_emit_filename(specifier)?;

// load and verify the meta data file is for this source and CLI version
let bytes = self.disk_cache.get(&meta_filename).ok()?;
let meta: EmitMetadata = serde_json::from_slice(&bytes).ok()?;
if meta.source_hash != expected_source_hash {
return None;
}

// load and verify the emit is for the meta data
let emit_bytes = self.disk_cache.get(&emit_filename).ok()?;
if meta.emit_hash != compute_emit_hash(&emit_bytes, self.cli_version) {
return None;
}

// everything looks good, return it
Some(emit_bytes)
}

/// Gets the filepath which stores the emit.
pub fn get_emit_filepath(
&self,
specifier: &ModuleSpecifier,
) -> Option<PathBuf> {
Some(
self
.disk_cache
.location
.join(self.get_emit_filename(specifier)?),
)
let bytes = self.disk_cache.get(&emit_filename).ok()?;
self
.file_serializer
.deserialize(bytes, expected_source_hash)
}

/// Sets the emit code in the cache.
Expand Down Expand Up @@ -107,32 +73,26 @@ impl EmitCache {
return Ok(());
}

let meta_filename = self
.get_meta_filename(specifier)
.ok_or_else(|| anyhow!("Could not get meta filename."))?;
let emit_filename = self
.get_emit_filename(specifier)
.ok_or_else(|| anyhow!("Could not get emit filename."))?;

// save the metadata
let metadata = EmitMetadata {
source_hash,
emit_hash: compute_emit_hash(code, self.cli_version),
};
self
.disk_cache
.set(&meta_filename, &serde_json::to_vec(&metadata)?)?;

// save the emit source
self.disk_cache.set(&emit_filename, code)?;
let cache_data = self.file_serializer.serialize(code, source_hash);
self.disk_cache.set(&emit_filename, &cache_data)?;

Ok(())
}

fn get_meta_filename(&self, specifier: &ModuleSpecifier) -> Option<PathBuf> {
self
.disk_cache
.get_cache_filename_with_extension(specifier, "meta")
/// Gets the filepath which stores the emit.
pub fn get_emit_filepath(
&self,
specifier: &ModuleSpecifier,
) -> Option<PathBuf> {
Some(
self
.disk_cache
.location
.join(self.get_emit_filename(specifier)?),
)
}

fn get_emit_filename(&self, specifier: &ModuleSpecifier) -> Option<PathBuf> {
Expand All @@ -142,15 +102,68 @@ impl EmitCache {
}
}

fn compute_emit_hash(bytes: &[u8], cli_version: &str) -> u64 {
// it's ok to use an insecure hash here because
// if someone can change the emit source then they
// can also change the version hash
FastInsecureHasher::new_without_deno_version() // use cli_version param instead
.write(bytes)
// emit should not be re-used between cli versions
.write_str(cli_version)
.finish()
const LAST_LINE_PREFIX: &str = "\n// denoCacheMetadata=";

struct EmitFileSerializer {
cli_version: &'static str,
}

impl EmitFileSerializer {
pub fn deserialize(
&self,
mut bytes: Vec<u8>,
expected_source_hash: u64,
) -> Option<Vec<u8>> {
let last_newline_index = bytes.iter().rposition(|&b| b == b'\n')?;
let (content, last_line) = bytes.split_at(last_newline_index);
let hashes = last_line.strip_prefix(LAST_LINE_PREFIX.as_bytes())?;
let hashes = String::from_utf8_lossy(hashes);
let (source_hash, emit_hash) = hashes.split_once(',')?;

// verify the meta data file is for this source and CLI version
let source_hash = source_hash.parse::<u64>().ok()?;
if source_hash != expected_source_hash {
return None;
}
let emit_hash = emit_hash.parse::<u64>().ok()?;
// prevent using an emit from a different cli version or emits that were tampered with
if emit_hash != self.compute_emit_hash(content) {
return None;
}

// everything looks good, truncate and return it
bytes.truncate(content.len());
Some(bytes)
}

pub fn serialize(&self, code: &[u8], source_hash: u64) -> Vec<u8> {
let source_hash = source_hash.to_string();
let emit_hash = self.compute_emit_hash(code).to_string();
let capacity = code.len()
+ LAST_LINE_PREFIX.len()
+ source_hash.len()
+ 1
+ emit_hash.len();
let mut cache_data = Vec::with_capacity(capacity);
cache_data.extend(code);
cache_data.extend(LAST_LINE_PREFIX.as_bytes());
cache_data.extend(source_hash.as_bytes());
cache_data.push(b',');
cache_data.extend(emit_hash.as_bytes());
debug_assert_eq!(cache_data.len(), capacity);
cache_data
}

fn compute_emit_hash(&self, bytes: &[u8]) -> u64 {
// it's ok to use an insecure hash here because
// if someone can change the emit source then they
// can also change the version hash
crate::cache::FastInsecureHasher::new_without_deno_version() // use cli_version property instead
.write(bytes)
// emit should not be re-used between cli versions
.write_str(self.cli_version)
.finish()
}
}

#[cfg(test)]
Expand All @@ -165,7 +178,9 @@ mod test {
let disk_cache = DiskCache::new(temp_dir.path().as_path());
let cache = EmitCache {
disk_cache: disk_cache.clone(),
cli_version: "1.0.0",
file_serializer: EmitFileSerializer {
cli_version: "1.0.0",
},
emit_failed_flag: Default::default(),
};
let to_string =
Expand Down Expand Up @@ -197,7 +212,9 @@ mod test {
// try changing the cli version (should not load previous ones)
let cache = EmitCache {
disk_cache: disk_cache.clone(),
cli_version: "2.0.0",
file_serializer: EmitFileSerializer {
cli_version: "2.0.0",
},
emit_failed_flag: Default::default(),
};
assert_eq!(cache.get_emit_code(&specifier1, 10), None);
Expand All @@ -206,7 +223,9 @@ mod test {
// recreating the cache should still load the data because the CLI version is the same
let cache = EmitCache {
disk_cache,
cli_version: "2.0.0",
file_serializer: EmitFileSerializer {
cli_version: "2.0.0",
},
emit_failed_flag: Default::default(),
};
assert_eq!(
Expand Down
Loading

0 comments on commit 047dbf6

Please sign in to comment.