Skip to content

Commit 7576219

Browse files
authored
refactor: move CliFileFetcher and DenoGraphLoader into deno_resolver::file_fetcher (#29473)
1 parent 4794dc1 commit 7576219

File tree

16 files changed

+910
-715
lines changed

16 files changed

+910
-715
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/cache/mod.rs

Lines changed: 2 additions & 251 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,5 @@
11
// Copyright 2018-2025 the Deno authors. MIT license.
22

3-
use std::collections::HashMap;
4-
use std::path::PathBuf;
5-
use std::sync::Arc;
6-
7-
use deno_cache_dir::file_fetcher::CacheSetting;
8-
use deno_cache_dir::file_fetcher::FetchLocalOptions;
9-
use deno_cache_dir::file_fetcher::FetchNoFollowErrorKind;
10-
use deno_cache_dir::file_fetcher::FileOrRedirect;
11-
use deno_core::futures::FutureExt;
12-
use deno_core::ModuleSpecifier;
13-
use deno_graph::source::CacheInfo;
14-
use deno_graph::source::LoadFuture;
15-
use deno_graph::source::LoadResponse;
16-
use deno_graph::source::Loader;
17-
use deno_resolver::npm::DenoInNpmPackageChecker;
18-
use deno_runtime::deno_permissions::PermissionsContainer;
19-
use node_resolver::InNpmPackageChecker;
20-
21-
use crate::args::jsr_url;
22-
use crate::file_fetcher::CliFetchNoFollowErrorKind;
23-
use crate::file_fetcher::CliFileFetcher;
24-
use crate::file_fetcher::FetchNoFollowOptions;
25-
use crate::file_fetcher::FetchPermissionsOptionRef;
26-
use crate::sys::CliSys;
27-
283
mod cache_db;
294
mod caches;
305
mod check;
@@ -55,232 +30,8 @@ pub use node::NodeAnalysisCache;
5530
pub use parsed_source::LazyGraphSourceParser;
5631
pub use parsed_source::ParsedSourceCache;
5732

33+
use crate::sys::CliSys;
34+
5835
pub type GlobalHttpCache = deno_cache_dir::GlobalHttpCache<CliSys>;
5936
pub type LocalLspHttpCache = deno_cache_dir::LocalLspHttpCache<CliSys>;
6037
pub use deno_cache_dir::HttpCache;
61-
use deno_error::JsErrorBox;
62-
63-
pub struct FetchCacherOptions {
64-
pub file_header_overrides: HashMap<ModuleSpecifier, HashMap<String, String>>,
65-
pub permissions: PermissionsContainer,
66-
/// If we're publishing for `deno publish`.
67-
pub is_deno_publish: bool,
68-
}
69-
70-
/// A "wrapper" for the FileFetcher and DiskCache for the Deno CLI that provides
71-
/// a concise interface to the DENO_DIR when building module graphs.
72-
pub struct FetchCacher {
73-
pub file_header_overrides: HashMap<ModuleSpecifier, HashMap<String, String>>,
74-
file_fetcher: Arc<CliFileFetcher>,
75-
global_http_cache: Arc<GlobalHttpCache>,
76-
in_npm_pkg_checker: DenoInNpmPackageChecker,
77-
permissions: PermissionsContainer,
78-
sys: CliSys,
79-
is_deno_publish: bool,
80-
cache_info_enabled: bool,
81-
}
82-
83-
impl FetchCacher {
84-
pub fn new(
85-
file_fetcher: Arc<CliFileFetcher>,
86-
global_http_cache: Arc<GlobalHttpCache>,
87-
in_npm_pkg_checker: DenoInNpmPackageChecker,
88-
sys: CliSys,
89-
options: FetchCacherOptions,
90-
) -> Self {
91-
Self {
92-
file_fetcher,
93-
global_http_cache,
94-
in_npm_pkg_checker,
95-
sys,
96-
file_header_overrides: options.file_header_overrides,
97-
permissions: options.permissions,
98-
is_deno_publish: options.is_deno_publish,
99-
cache_info_enabled: false,
100-
}
101-
}
102-
103-
/// The cache information takes a bit of time to fetch and it's
104-
/// not always necessary. It should only be enabled for deno info.
105-
pub fn enable_loading_cache_info(&mut self) {
106-
self.cache_info_enabled = true;
107-
}
108-
109-
/// Only use this for `deno info`.
110-
fn get_local_path(&self, specifier: &ModuleSpecifier) -> Option<PathBuf> {
111-
// TODO(@kitsonk) fix when deno_graph does not query cache for synthetic
112-
// modules
113-
if specifier.scheme() == "flags" {
114-
None
115-
} else if specifier.scheme() == "file" {
116-
specifier.to_file_path().ok()
117-
} else {
118-
self.global_http_cache.local_path_for_url(specifier).ok()
119-
}
120-
}
121-
}
122-
123-
impl Loader for FetchCacher {
124-
fn get_cache_info(&self, specifier: &ModuleSpecifier) -> Option<CacheInfo> {
125-
if !self.cache_info_enabled {
126-
return None;
127-
}
128-
129-
#[allow(deprecated)]
130-
let local = self.get_local_path(specifier)?;
131-
if local.is_file() {
132-
Some(CacheInfo { local: Some(local) })
133-
} else {
134-
None
135-
}
136-
}
137-
138-
fn load(
139-
&self,
140-
specifier: &ModuleSpecifier,
141-
options: deno_graph::source::LoadOptions,
142-
) -> LoadFuture {
143-
use deno_graph::source::CacheSetting as LoaderCacheSetting;
144-
145-
if specifier.scheme() == "file"
146-
&& specifier.path().contains("/node_modules/")
147-
{
148-
// The specifier might be in a completely different symlinked tree than
149-
// what the node_modules url is in (ex. `/my-project-1/node_modules`
150-
// symlinked to `/my-project-2/node_modules`), so first we checked if the path
151-
// is in a node_modules dir to avoid needlessly canonicalizing, then now compare
152-
// against the canonicalized specifier.
153-
let specifier = node_resolver::resolve_specifier_into_node_modules(
154-
&self.sys, specifier,
155-
);
156-
if self.in_npm_pkg_checker.in_npm_package(&specifier) {
157-
return Box::pin(std::future::ready(Ok(Some(
158-
LoadResponse::External { specifier },
159-
))));
160-
}
161-
}
162-
163-
if self.is_deno_publish
164-
&& matches!(specifier.scheme(), "http" | "https")
165-
&& !specifier.as_str().starts_with(jsr_url().as_str())
166-
{
167-
// mark non-JSR remote modules as external so we don't need --allow-import
168-
// permissions as these will error out later when publishing
169-
return Box::pin(std::future::ready(Ok(Some(LoadResponse::External {
170-
specifier: specifier.clone(),
171-
}))));
172-
}
173-
174-
let file_fetcher = self.file_fetcher.clone();
175-
let file_header_overrides = self.file_header_overrides.clone();
176-
let permissions = self.permissions.clone();
177-
let specifier = specifier.clone();
178-
let is_statically_analyzable = !options.was_dynamic_root;
179-
180-
async move {
181-
let maybe_cache_setting = match options.cache_setting {
182-
LoaderCacheSetting::Use => None,
183-
LoaderCacheSetting::Reload => {
184-
if matches!(file_fetcher.cache_setting(), CacheSetting::Only) {
185-
return Err(deno_graph::source::LoadError::Other(Arc::new(JsErrorBox::generic(
186-
"Could not resolve version constraint using only cached data. Try running again without --cached-only"
187-
))));
188-
}
189-
Some(CacheSetting::ReloadAll)
190-
}
191-
LoaderCacheSetting::Only => Some(CacheSetting::Only),
192-
};
193-
file_fetcher
194-
.fetch_no_follow(
195-
&specifier,
196-
FetchPermissionsOptionRef::Restricted(&permissions,
197-
if is_statically_analyzable {
198-
deno_runtime::deno_permissions::CheckSpecifierKind::Static
199-
} else {
200-
deno_runtime::deno_permissions::CheckSpecifierKind::Dynamic
201-
}),
202-
FetchNoFollowOptions {
203-
local: FetchLocalOptions {
204-
// only include the mtime in dynamic branches because we only
205-
// need to know about it then in order to tell whether to reload
206-
// or not
207-
include_mtime: options.in_dynamic_branch,
208-
},
209-
maybe_auth: None,
210-
maybe_accept: None,
211-
maybe_cache_setting: maybe_cache_setting.as_ref(),
212-
maybe_checksum: options.maybe_checksum.as_ref(),
213-
})
214-
.await
215-
.map(|file_or_redirect| {
216-
match file_or_redirect {
217-
FileOrRedirect::File(file) => {
218-
let maybe_headers =
219-
match (file.maybe_headers, file_header_overrides.get(&specifier)) {
220-
(Some(headers), Some(overrides)) => {
221-
Some(headers.into_iter().chain(overrides.clone()).collect())
222-
}
223-
(Some(headers), None) => Some(headers),
224-
(None, Some(overrides)) => Some(overrides.clone()),
225-
(None, None) => None,
226-
};
227-
Ok(Some(LoadResponse::Module {
228-
specifier: file.url,
229-
maybe_headers,
230-
mtime: file.mtime,
231-
content: file.source,
232-
}))
233-
},
234-
FileOrRedirect::Redirect(redirect_specifier) => {
235-
Ok(Some(LoadResponse::Redirect {
236-
specifier: redirect_specifier,
237-
}))
238-
},
239-
}
240-
})
241-
.unwrap_or_else(|err| {
242-
let err = err.into_kind();
243-
match err {
244-
CliFetchNoFollowErrorKind::FetchNoFollow(err) => {
245-
let err = err.into_kind();
246-
match err {
247-
FetchNoFollowErrorKind::NotFound(_) => Ok(None),
248-
FetchNoFollowErrorKind::UrlToFilePath { .. } |
249-
FetchNoFollowErrorKind::ReadingBlobUrl { .. } |
250-
FetchNoFollowErrorKind::ReadingFile { .. } |
251-
FetchNoFollowErrorKind::FetchingRemote { .. } |
252-
FetchNoFollowErrorKind::ClientError { .. } |
253-
FetchNoFollowErrorKind::NoRemote { .. } |
254-
FetchNoFollowErrorKind::DataUrlDecode { .. } |
255-
FetchNoFollowErrorKind::RedirectResolution { .. } |
256-
FetchNoFollowErrorKind::CacheRead { .. } |
257-
FetchNoFollowErrorKind::CacheSave { .. } |
258-
FetchNoFollowErrorKind::UnsupportedScheme { .. } |
259-
FetchNoFollowErrorKind::RedirectHeaderParse { .. } |
260-
FetchNoFollowErrorKind::InvalidHeader { .. } => Err(deno_graph::source::LoadError::Other(Arc::new(JsErrorBox::from_err(err)))),
261-
FetchNoFollowErrorKind::NotCached { .. } => {
262-
if options.cache_setting == LoaderCacheSetting::Only {
263-
Ok(None)
264-
} else {
265-
Err(deno_graph::source::LoadError::Other(Arc::new(JsErrorBox::from_err(err))))
266-
}
267-
},
268-
FetchNoFollowErrorKind::ChecksumIntegrity(err) => {
269-
// convert to the equivalent deno_graph error so that it
270-
// enhances it if this is passed to deno_graph
271-
Err(
272-
deno_graph::source::LoadError::ChecksumIntegrity(deno_graph::source::ChecksumIntegrityError {
273-
actual: err.actual,
274-
expected: err.expected,
275-
}),
276-
)
277-
}
278-
}
279-
},
280-
CliFetchNoFollowErrorKind::PermissionCheck(permission_check_error) => Err(deno_graph::source::LoadError::Other(Arc::new(JsErrorBox::from_err(permission_check_error)))),
281-
}
282-
})
283-
}
284-
.boxed_local()
285-
}
286-
}

cli/factory.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@ use crate::cache::ModuleInfoCache;
7575
use crate::cache::NodeAnalysisCache;
7676
use crate::cache::ParsedSourceCache;
7777
use crate::emit::Emitter;
78+
use crate::file_fetcher::create_cli_file_fetcher;
7879
use crate::file_fetcher::CliFileFetcher;
80+
use crate::file_fetcher::CreateCliFileFetcherOptions;
7981
use crate::file_fetcher::TextDecodedFile;
8082
use crate::graph_container::MainModuleGraphContainer;
8183
use crate::graph_util::FileWatcherReporter;
@@ -503,15 +505,17 @@ impl CliFactory {
503505
pub fn file_fetcher(&self) -> Result<&Arc<CliFileFetcher>, AnyError> {
504506
self.services.file_fetcher.get_or_try_init(|| {
505507
let cli_options = self.cli_options()?;
506-
Ok(Arc::new(CliFileFetcher::new(
508+
Ok(Arc::new(create_cli_file_fetcher(
509+
self.blob_store().clone(),
507510
self.http_cache()?.clone(),
508511
self.http_client_provider().clone(),
509512
self.sys(),
510-
self.blob_store().clone(),
511-
Some(self.text_only_progress_bar().clone()),
512-
!cli_options.no_remote(),
513-
cli_options.cache_setting(),
514-
log::Level::Info,
513+
CreateCliFileFetcherOptions {
514+
allow_remote: !cli_options.no_remote(),
515+
cache_setting: cli_options.cache_setting(),
516+
download_log_level: log::Level::Info,
517+
progress_bar: Some(self.text_only_progress_bar().clone()),
518+
},
515519
)))
516520
})
517521
}

0 commit comments

Comments
 (0)