summaryrefslogtreecommitdiff
path: root/cli/lsp
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2023-07-08 16:06:45 -0400
committerGitHub <noreply@github.com>2023-07-08 16:06:45 -0400
commit21cc279481ac5bffc29641e917e868dca42189d3 (patch)
tree4e0201da6a5d6beaff5139a84e4c52ec5e9affd6 /cli/lsp
parentf3095b8d311c85f633d280a980f76062015f8974 (diff)
refactor: abstract away file system to be buried inside HttpCache (#19760)
This improves the HttpCache to make it being stored on the file system an implementation detail.
Diffstat (limited to 'cli/lsp')
-rw-r--r--cli/lsp/cache.rs46
-rw-r--r--cli/lsp/completions.rs3
-rw-r--r--cli/lsp/diagnostics.rs21
-rw-r--r--cli/lsp/documents.rs56
-rw-r--r--cli/lsp/language_server.rs7
-rw-r--r--cli/lsp/registries.rs13
-rw-r--r--cli/lsp/tsc.rs36
7 files changed, 109 insertions, 73 deletions
diff --git a/cli/lsp/cache.rs b/cli/lsp/cache.rs
index 9ce47a11b..e14497156 100644
--- a/cli/lsp/cache.rs
+++ b/cli/lsp/cache.rs
@@ -1,7 +1,7 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use crate::cache::CachedUrlMetadata;
use crate::cache::HttpCache;
+use crate::util::path::specifier_to_file_path;
use deno_core::parking_lot::Mutex;
use deno_core::ModuleSpecifier;
@@ -12,8 +12,21 @@ use std::path::PathBuf;
use std::sync::Arc;
use std::time::SystemTime;
+pub fn calculate_fs_version(
+ cache: &HttpCache,
+ specifier: &ModuleSpecifier,
+) -> Option<String> {
+ match specifier.scheme() {
+ "npm" | "node" | "data" | "blob" => None,
+ "file" => specifier_to_file_path(specifier)
+ .ok()
+ .and_then(|path| calculate_fs_version_at_path(&path)),
+ _ => calculate_fs_version_in_cache(cache, specifier),
+ }
+}
+
/// Calculate a version for for a given path.
-pub fn calculate_fs_version(path: &Path) -> Option<String> {
+pub fn calculate_fs_version_at_path(path: &Path) -> Option<String> {
let metadata = fs::metadata(path).ok()?;
if let Ok(modified) = metadata.modified() {
if let Ok(n) = modified.duration_since(SystemTime::UNIX_EPOCH) {
@@ -26,6 +39,22 @@ pub fn calculate_fs_version(path: &Path) -> Option<String> {
}
}
+fn calculate_fs_version_in_cache(
+ cache: &HttpCache,
+ specifier: &ModuleSpecifier,
+) -> Option<String> {
+ match cache.get_modified_time(specifier) {
+ Ok(Some(modified)) => {
+ match modified.duration_since(SystemTime::UNIX_EPOCH) {
+ Ok(n) => Some(n.as_millis().to_string()),
+ Err(_) => Some("1".to_string()),
+ }
+ }
+ Ok(None) => None,
+ Err(_) => Some("1".to_string()),
+ }
+}
+
/// Populate the metadata map based on the supplied headers
fn parse_metadata(
headers: &HashMap<String, String>,
@@ -49,7 +78,7 @@ struct Metadata {
version: Option<String>,
}
-#[derive(Debug, Default, Clone)]
+#[derive(Debug, Clone)]
pub struct CacheMetadata {
cache: HttpCache,
metadata: Arc<Mutex<HashMap<ModuleSpecifier, Metadata>>>,
@@ -75,10 +104,7 @@ impl CacheMetadata {
) {
return None;
}
- let version = self
- .cache
- .get_cache_filename(specifier)
- .and_then(|ref path| calculate_fs_version(path));
+ let version = calculate_fs_version_in_cache(&self.cache, specifier);
let metadata = self.metadata.lock().get(specifier).cloned();
if metadata.as_ref().and_then(|m| m.version.clone()) != version {
self.refresh(specifier).map(|m| m.values)
@@ -94,10 +120,10 @@ impl CacheMetadata {
) {
return None;
}
- let cache_filename = self.cache.get_cache_filename(specifier)?;
- let specifier_metadata = CachedUrlMetadata::read(&cache_filename).ok()?;
+ let specifier_metadata =
+ self.cache.get(specifier).ok()?.read_metadata().ok()??;
let values = Arc::new(parse_metadata(&specifier_metadata.headers));
- let version = calculate_fs_version(&cache_filename);
+ let version = calculate_fs_version_in_cache(&self.cache, specifier);
let mut metadata_map = self.metadata.lock();
let metadata = Metadata { values, version };
metadata_map.insert(specifier.clone(), metadata.clone());
diff --git a/cli/lsp/completions.rs b/cli/lsp/completions.rs
index 17a00010b..73ec5a918 100644
--- a/cli/lsp/completions.rs
+++ b/cli/lsp/completions.rs
@@ -519,7 +519,8 @@ mod tests {
source_fixtures: &[(&str, &str)],
location: &Path,
) -> Documents {
- let mut documents = Documents::new(location.to_path_buf());
+ let cache = HttpCache::new(location.to_path_buf());
+ let mut documents = Documents::new(cache);
for (specifier, source, version, language_id) in fixtures {
let specifier =
resolve_url(specifier).expect("failed to create specifier");
diff --git a/cli/lsp/diagnostics.rs b/cli/lsp/diagnostics.rs
index 415fe142d..b202e47d6 100644
--- a/cli/lsp/diagnostics.rs
+++ b/cli/lsp/diagnostics.rs
@@ -1169,6 +1169,7 @@ async fn generate_deno_diagnostics(
#[cfg(test)]
mod tests {
use super::*;
+ use crate::cache::HttpCache;
use crate::lsp::config::ConfigSnapshot;
use crate::lsp::config::Settings;
use crate::lsp::config::SpecifierSettings;
@@ -1187,7 +1188,8 @@ mod tests {
location: &Path,
maybe_import_map: Option<(&str, &str)>,
) -> StateSnapshot {
- let mut documents = Documents::new(location.to_path_buf());
+ let cache = HttpCache::new(location.to_path_buf());
+ let mut documents = Documents::new(cache);
for (specifier, source, version, language_id) in fixtures {
let specifier =
resolve_url(specifier).expect("failed to create specifier");
@@ -1209,7 +1211,12 @@ mod tests {
StateSnapshot {
documents,
maybe_import_map,
- ..Default::default()
+ assets: Default::default(),
+ cache_metadata: cache::CacheMetadata::new(HttpCache::new(
+ location.to_path_buf(),
+ )),
+ maybe_node_resolver: None,
+ maybe_npm_resolver: None,
}
}
@@ -1242,7 +1249,7 @@ mod tests {
async fn test_enabled_then_disabled_specifier() {
let temp_dir = TempDir::new();
let specifier = ModuleSpecifier::parse("file:///a.ts").unwrap();
- let (snapshot, _) = setup(
+ let (snapshot, cache_location) = setup(
&temp_dir,
&[(
"file:///a.ts",
@@ -1256,7 +1263,8 @@ let c: number = "a";
None,
);
let snapshot = Arc::new(snapshot);
- let ts_server = TsServer::new(Default::default());
+ let cache = HttpCache::new(cache_location);
+ let ts_server = TsServer::new(Default::default(), cache);
// test enabled
{
@@ -1337,7 +1345,7 @@ let c: number = "a";
#[tokio::test]
async fn test_cancelled_ts_diagnostics_request() {
let temp_dir = TempDir::new();
- let (snapshot, _) = setup(
+ let (snapshot, cache_location) = setup(
&temp_dir,
&[(
"file:///a.ts",
@@ -1348,7 +1356,8 @@ let c: number = "a";
None,
);
let snapshot = Arc::new(snapshot);
- let ts_server = TsServer::new(Default::default());
+ let cache = HttpCache::new(cache_location);
+ let ts_server = TsServer::new(Default::default(), cache);
let config = mock_config();
let token = CancellationToken::new();
diff --git a/cli/lsp/documents.rs b/cli/lsp/documents.rs
index f18284db7..11662a8fc 100644
--- a/cli/lsp/documents.rs
+++ b/cli/lsp/documents.rs
@@ -1,6 +1,7 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
use super::cache::calculate_fs_version;
+use super::cache::calculate_fs_version_at_path;
use super::text::LineIndex;
use super::tsc;
use super::tsc::AssetDocument;
@@ -9,7 +10,6 @@ use crate::args::package_json;
use crate::args::package_json::PackageJsonDeps;
use crate::args::ConfigFile;
use crate::args::JsxImportSourceConfig;
-use crate::cache::CachedUrlMetadata;
use crate::cache::FastInsecureHasher;
use crate::cache::HttpCache;
use crate::file_fetcher::get_source_from_bytes;
@@ -656,7 +656,7 @@ fn recurse_dependents(
}
}
-#[derive(Debug, Default)]
+#[derive(Debug)]
struct SpecifierResolver {
cache: HttpCache,
redirects: Mutex<HashMap<ModuleSpecifier, ModuleSpecifier>>,
@@ -698,10 +698,12 @@ impl SpecifierResolver {
specifier: &ModuleSpecifier,
redirect_limit: usize,
) -> Option<ModuleSpecifier> {
- let cache_filename = self.cache.get_cache_filename(specifier)?;
- if redirect_limit > 0 && cache_filename.is_file() {
- let headers = CachedUrlMetadata::read(&cache_filename)
+ if redirect_limit > 0 {
+ let headers = self
+ .cache
+ .get(specifier)
.ok()
+ .and_then(|i| i.read_metadata().ok()?)
.map(|m| m.headers)?;
if let Some(location) = headers.get("location") {
let redirect =
@@ -732,8 +734,7 @@ impl FileSystemDocuments {
let fs_version = if specifier.scheme() == "data" {
Some("1".to_string())
} else {
- get_document_path(cache, specifier)
- .and_then(|path| calculate_fs_version(&path))
+ calculate_fs_version(cache, specifier)
};
let file_system_doc = self.docs.get(specifier);
if file_system_doc.map(|d| d.fs_version().to_string()) != fs_version {
@@ -753,8 +754,8 @@ impl FileSystemDocuments {
specifier: &ModuleSpecifier,
) -> Option<Document> {
let doc = if specifier.scheme() == "file" {
- let path = get_document_path(cache, specifier)?;
- let fs_version = calculate_fs_version(&path)?;
+ let path = specifier_to_file_path(specifier).ok()?;
+ let fs_version = calculate_fs_version_at_path(&path)?;
let bytes = fs::read(path).ok()?;
let maybe_charset =
Some(text_encoding::detect_charset(&bytes).to_string());
@@ -776,11 +777,10 @@ impl FileSystemDocuments {
resolver,
)
} else {
- let path = get_document_path(cache, specifier)?;
- let fs_version = calculate_fs_version(&path)?;
- let bytes = fs::read(path).ok()?;
- let cache_filename = cache.get_cache_filename(specifier)?;
- let specifier_metadata = CachedUrlMetadata::read(&cache_filename).ok()?;
+ let fs_version = calculate_fs_version(cache, specifier)?;
+ let cache_item = cache.get(specifier).ok()?;
+ let bytes = cache_item.read_to_bytes().ok()??;
+ let specifier_metadata = cache_item.read_metadata().ok()??;
let maybe_content_type = specifier_metadata.headers.get("content-type");
let (_, maybe_charset) = map_content_type(specifier, maybe_content_type);
let maybe_headers = Some(specifier_metadata.headers);
@@ -799,17 +799,6 @@ impl FileSystemDocuments {
}
}
-fn get_document_path(
- cache: &HttpCache,
- specifier: &ModuleSpecifier,
-) -> Option<PathBuf> {
- match specifier.scheme() {
- "npm" | "node" | "data" | "blob" => None,
- "file" => specifier_to_file_path(specifier).ok(),
- _ => cache.get_cache_filename(specifier),
- }
-}
-
pub struct UpdateDocumentConfigOptions<'a> {
pub enabled_urls: Vec<Url>,
pub document_preload_limit: usize,
@@ -831,7 +820,7 @@ pub enum DocumentsFilter {
OpenDiagnosable,
}
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone)]
pub struct Documents {
/// The DENO_DIR that the documents looks for non-file based modules.
cache: HttpCache,
@@ -864,8 +853,7 @@ pub struct Documents {
}
impl Documents {
- pub fn new(location: PathBuf) -> Self {
- let cache = HttpCache::new(location);
+ pub fn new(cache: HttpCache) -> Self {
Self {
cache: cache.clone(),
dirty: true,
@@ -990,8 +978,13 @@ impl Documents {
if specifier.scheme() == "data" {
return true;
}
- if let Some(path) = get_document_path(&self.cache, &specifier) {
- return path.is_file();
+ if specifier.scheme() == "file" {
+ return specifier_to_file_path(&specifier)
+ .map(|p| p.is_file())
+ .unwrap_or(false);
+ }
+ if self.cache.contains(&specifier) {
+ return true;
}
}
false
@@ -1859,7 +1852,8 @@ mod tests {
fn setup(temp_dir: &TempDir) -> (Documents, PathRef) {
let location = temp_dir.path().join("deps");
- let documents = Documents::new(location.to_path_buf());
+ let cache = HttpCache::new(location.to_path_buf());
+ let documents = Documents::new(cache);
(documents, location)
}
diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs
index 61bd64eef..d8fa7a7b4 100644
--- a/cli/lsp/language_server.rs
+++ b/cli/lsp/language_server.rs
@@ -184,7 +184,7 @@ struct LspConfigFileInfo {
pub struct LanguageServer(Arc<tokio::sync::RwLock<Inner>>);
/// Snapshot of the state used by TSC.
-#[derive(Debug, Default)]
+#[derive(Debug)]
pub struct StateSnapshot {
pub assets: AssetsSnapshot,
pub cache_metadata: cache::CacheMetadata,
@@ -610,11 +610,12 @@ impl Inner {
http_client.clone(),
);
let location = dir.deps_folder_path();
- let documents = Documents::new(location.clone());
let deps_http_cache = HttpCache::new(location);
+ let documents = Documents::new(deps_http_cache.clone());
let cache_metadata = cache::CacheMetadata::new(deps_http_cache.clone());
let performance = Arc::new(Performance::default());
- let ts_server = Arc::new(TsServer::new(performance.clone()));
+ let ts_server =
+ Arc::new(TsServer::new(performance.clone(), deps_http_cache.clone()));
let config = Config::new();
let diagnostics_server = DiagnosticsServer::new(
client.clone(),
diff --git a/cli/lsp/registries.rs b/cli/lsp/registries.rs
index 9454f77f5..9586997c5 100644
--- a/cli/lsp/registries.rs
+++ b/cli/lsp/registries.rs
@@ -13,7 +13,6 @@ use super::path_to_regex::StringOrVec;
use super::path_to_regex::Token;
use crate::args::CacheSetting;
-use crate::cache::DenoDir;
use crate::cache::HttpCache;
use crate::file_fetcher::FileFetcher;
use crate::http_util::HttpClient;
@@ -418,18 +417,6 @@ pub struct ModuleRegistry {
file_fetcher: FileFetcher,
}
-impl Default for ModuleRegistry {
- fn default() -> Self {
- // This only gets used when creating the tsc runtime and for testing, and so
- // it shouldn't ever actually access the DenoDir, so it doesn't support a
- // custom root.
- let dir = DenoDir::new(None).unwrap();
- let location = dir.registries_folder_path();
- let http_client = Arc::new(HttpClient::new(None, None));
- Self::new(location, http_client)
- }
-}
-
impl ModuleRegistry {
pub fn new(location: PathBuf, http_client: Arc<HttpClient>) -> Self {
let http_cache = HttpCache::new(location);
diff --git a/cli/lsp/tsc.rs b/cli/lsp/tsc.rs
index 40c823d5b..662b48061 100644
--- a/cli/lsp/tsc.rs
+++ b/cli/lsp/tsc.rs
@@ -22,6 +22,9 @@ use super::urls::LspUrlMap;
use super::urls::INVALID_SPECIFIER;
use crate::args::TsConfig;
+use crate::cache::HttpCache;
+use crate::lsp::cache::CacheMetadata;
+use crate::lsp::documents::Documents;
use crate::lsp::logging::lsp_warn;
use crate::tsc;
use crate::tsc::ResolveArgs;
@@ -96,10 +99,10 @@ type Request = (
pub struct TsServer(mpsc::UnboundedSender<Request>);
impl TsServer {
- pub fn new(performance: Arc<Performance>) -> Self {
+ pub fn new(performance: Arc<Performance>, cache: HttpCache) -> Self {
let (tx, mut rx) = mpsc::unbounded_channel::<Request>();
let _join_handle = thread::spawn(move || {
- let mut ts_runtime = js_runtime(performance);
+ let mut ts_runtime = js_runtime(performance, cache);
let runtime = create_basic_runtime();
runtime.block_on(async {
@@ -3242,9 +3245,9 @@ fn op_script_version(
/// Create and setup a JsRuntime based on a snapshot. It is expected that the
/// supplied snapshot is an isolate that contains the TypeScript language
/// server.
-fn js_runtime(performance: Arc<Performance>) -> JsRuntime {
+fn js_runtime(performance: Arc<Performance>, cache: HttpCache) -> JsRuntime {
JsRuntime::new(RuntimeOptions {
- extensions: vec![deno_tsc::init_ops(performance)],
+ extensions: vec![deno_tsc::init_ops(performance, cache)],
startup_snapshot: Some(tsc::compiler_snapshot()),
..Default::default()
})
@@ -3261,11 +3264,19 @@ deno_core::extension!(deno_tsc,
op_script_version,
],
options = {
- performance: Arc<Performance>
+ performance: Arc<Performance>,
+ cache: HttpCache,
},
state = |state, options| {
state.put(State::new(
- Arc::new(StateSnapshot::default()),
+ Arc::new(StateSnapshot {
+ assets: Default::default(),
+ cache_metadata: CacheMetadata::new(options.cache.clone()),
+ documents: Documents::new(options.cache.clone()),
+ maybe_import_map: None,
+ maybe_node_resolver: None,
+ maybe_npm_resolver: None,
+ }),
options.performance,
));
},
@@ -3897,6 +3908,7 @@ mod tests {
use super::*;
use crate::cache::HttpCache;
use crate::http_util::HeadersMap;
+ use crate::lsp::cache::CacheMetadata;
use crate::lsp::config::WorkspaceSettings;
use crate::lsp::documents::Documents;
use crate::lsp::documents::LanguageId;
@@ -3911,7 +3923,8 @@ mod tests {
fixtures: &[(&str, &str, i32, LanguageId)],
location: &Path,
) -> StateSnapshot {
- let mut documents = Documents::new(location.to_path_buf());
+ let cache = HttpCache::new(location.to_path_buf());
+ let mut documents = Documents::new(cache.clone());
for (specifier, source, version, language_id) in fixtures {
let specifier =
resolve_url(specifier).expect("failed to create specifier");
@@ -3924,7 +3937,11 @@ mod tests {
}
StateSnapshot {
documents,
- ..Default::default()
+ assets: Default::default(),
+ cache_metadata: CacheMetadata::new(cache),
+ maybe_import_map: None,
+ maybe_node_resolver: None,
+ maybe_npm_resolver: None,
}
}
@@ -3935,8 +3952,9 @@ mod tests {
sources: &[(&str, &str, i32, LanguageId)],
) -> (JsRuntime, Arc<StateSnapshot>, PathBuf) {
let location = temp_dir.path().join("deps").to_path_buf();
+ let cache = HttpCache::new(location.clone());
let state_snapshot = Arc::new(mock_state_snapshot(sources, &location));
- let mut runtime = js_runtime(Default::default());
+ let mut runtime = js_runtime(Default::default(), cache);
start(&mut runtime, debug).unwrap();
let ts_config = TsConfig::new(config);
assert_eq!(