use std::path::Path;
use crate::cache_paths;
use crate::channel::Sender;
use crate::http::ServiceKind;
use crate::http::ServiceSignal;
use crate::lint::LintRunOrigin;
use crate::project::AbsolutePath;
use crate::project::CheckoutInfo;
use crate::project::ManifestFingerprint;
use crate::project::RepoInfo;
use crate::project::RootItem;
use crate::project::Submodule;
use crate::project::WorkspaceMetadata;
mod cargo_metadata;
mod ci_cache;
mod constants;
mod discovery;
mod disk_usage;
mod language_stats;
mod test_counts;
mod tree;
pub(crate) use cargo_metadata::CargoMetadataError;
pub(crate) use cargo_metadata::MetadataDispatchContext;
pub(crate) use cargo_metadata::cargo_metadata_roots_for_item;
pub(crate) use cargo_metadata::spawn_cargo_metadata_refresh;
pub(crate) use cargo_metadata::spawn_out_of_tree_target_walk;
pub(crate) use cargo_metadata::spawn_streaming_scan;
pub(crate) use ci_cache::CiFetchResult;
pub(crate) use ci_cache::CratesIoInfo;
pub(crate) use ci_cache::ci_cache_dir_pub;
pub(crate) use ci_cache::clear_exhausted;
pub(crate) use ci_cache::fetch_ci_runs_cached;
pub(crate) use ci_cache::fetch_older_runs;
pub(crate) use ci_cache::is_exhausted;
pub(crate) use ci_cache::mark_exhausted;
pub(crate) use discovery::CachedRepoData;
pub(crate) use discovery::FetchContext;
pub(crate) use discovery::ProjectDetailRequest;
pub(crate) use discovery::RepoCache;
pub(crate) use discovery::RepoMetaInfo;
pub(crate) use discovery::discover_project_item;
pub(crate) use discovery::fetch_project_details;
pub(crate) use discovery::invalidate_cached_repo_data;
pub(crate) use discovery::load_cached_repo_data;
pub(crate) use discovery::new_repo_cache;
pub(crate) use discovery::resolve_include_dirs;
pub(crate) use discovery::store_cached_repo_data;
pub(crate) use disk_usage::DirSizes;
pub(crate) use disk_usage::disk_usage_batch_for_item;
pub(crate) use language_stats::collect_language_stats_single;
pub(crate) use test_counts::collect_test_counts_single;
pub(crate) use tree::build_tree;
pub(crate) use tree::cargo_project_to_item;
pub(crate) use tree::dir_size;
pub(crate) use tree::normalize_workspace_path;
use tui_pane::Appearance;
use crate::ci::CiRun;
use crate::ci::OwnerRepo;
use crate::lint::CacheUsage;
use crate::lint::CachedLintStatus;
use crate::lint::LintRun;
use crate::lint::LintStatus;
use crate::project::LanguageStats;
use crate::project::ProjectPrData;
use crate::project::PullRequestGoneReason;
use crate::project::PullRequestInfo;
use crate::project::TestCounts;
use crate::sccache::StatsResult as SccacheStatsResult;
pub(crate) enum BackgroundMsg {
DiskUsage { path: AbsolutePath, bytes: u64 },
DiskUsageBatch {
root_path: AbsolutePath,
entries: Vec<(AbsolutePath, DirSizes)>,
},
CiRuns {
path: AbsolutePath,
runs: Vec<CiRun>,
github_total: u32,
},
RepoFetchQueued { repo: OwnerRepo },
RepoFetchComplete { repo: OwnerRepo },
CheckoutInfo {
path: AbsolutePath,
info: CheckoutInfo,
},
RepoInfo { path: AbsolutePath, info: RepoInfo },
GitFirstCommit {
path: AbsolutePath,
first_commit: Option<String>,
},
ProjectDetailsDeclared { path: AbsolutePath },
CratesIoVersion {
path: AbsolutePath,
version: String,
prerelease: Option<String>,
downloads: u64,
},
CratesIoFetchQueued { name: String },
CratesIoFetchComplete { name: String },
RepoMeta {
path: AbsolutePath,
stars: u64,
description: Option<String>,
},
PullRequests {
repo: OwnerRepo,
data: ProjectPrData,
},
LanguageStatsProgressPlan { units: usize },
PullRequestCheckPollStopped { repo: OwnerRepo, number: u32 },
PullRequestDisappeared {
repo: OwnerRepo,
pull_request: PullRequestInfo,
reason: PullRequestGoneReason,
},
ScanResult {
projects: Vec<RootItem>,
disk_entries: Vec<(String, AbsolutePath)>,
},
ProjectDiscovered { item: RootItem },
ProjectRefreshed { item: RootItem },
Submodules {
path: AbsolutePath,
submodules: Vec<Submodule>,
},
LintStatus {
path: AbsolutePath,
status: LintStatus,
origin: LintRunOrigin,
},
LintStartupStatus {
path: AbsolutePath,
status: CachedLintStatus,
},
LintCachePruned {
runs_evicted: usize,
bytes_reclaimed: u64,
},
LintCacheUsage { usage: CacheUsage },
LintHistoryLoaded {
entries: Vec<(AbsolutePath, Vec<LintRun>)>,
},
ServiceReachable { service: ServiceKind },
ServiceRecovered { service: ServiceKind },
ServiceUnreachable { service: ServiceKind },
ServiceUnreachableConfirmed { service: ServiceKind },
ServiceRateLimited { service: ServiceKind },
LanguageStatsBatch {
entries: Vec<(AbsolutePath, LanguageStats)>,
},
TestCountsBatch {
entries: Vec<(AbsolutePath, TestCounts)>,
},
SccacheStats {
request_id: u64,
result: SccacheStatsResult,
},
CargoMetadata {
workspace_root: AbsolutePath,
generation: u64,
fingerprint: ManifestFingerprint,
result: Result<WorkspaceMetadata, CargoMetadataError>,
},
OutOfTreeTargetSize {
workspace_root: AbsolutePath,
target_dir: AbsolutePath,
bytes: u64,
},
AppearanceChanged(Appearance),
}
impl BackgroundMsg {
pub(crate) fn detail_relevance(&self) -> Option<&Path> {
match self {
Self::DiskUsage { path, .. } | Self::CiRuns { path, .. } | Self::CheckoutInfo { path, .. } | Self::RepoInfo { path, .. } | Self::GitFirstCommit { path, .. } | Self::CratesIoVersion { path, .. } | Self::RepoMeta { path, .. } | Self::Submodules { path, .. } | Self::LintStartupStatus { path, .. } => Some(path.as_path()),
Self::ProjectDiscovered { item }
| Self::ProjectRefreshed { item } => Some(item.path()),
Self::CargoMetadata { workspace_root, .. }
| Self::OutOfTreeTargetSize { workspace_root, .. } => Some(workspace_root.as_path()),
Self::ScanResult { .. }
| Self::DiskUsageBatch { .. }
| Self::LanguageStatsProgressPlan { .. }
| Self::LanguageStatsBatch { .. }
| Self::TestCountsBatch { .. }
| Self::SccacheStats { .. }
| Self::RepoFetchQueued { .. }
| Self::RepoFetchComplete { .. }
| Self::PullRequests { .. }
| Self::PullRequestCheckPollStopped { .. }
| Self::PullRequestDisappeared { .. }
| Self::CratesIoFetchQueued { .. }
| Self::CratesIoFetchComplete { .. }
| Self::ProjectDetailsDeclared { .. }
| Self::LintStatus { .. }
| Self::LintCachePruned { .. }
| Self::LintCacheUsage { .. }
| Self::LintHistoryLoaded { .. }
| Self::ServiceReachable { .. }
| Self::ServiceRecovered { .. }
| Self::ServiceUnreachable { .. }
| Self::ServiceUnreachableConfirmed { .. }
| Self::ServiceRateLimited { .. }
| Self::AppearanceChanged(_) => None,
}
}
}
pub(super) const fn combine_service_signal(
left: Option<ServiceSignal>,
right: Option<ServiceSignal>,
) -> Option<ServiceSignal> {
match (left, right) {
(Some(ServiceSignal::Unreachable(service)), _)
| (_, Some(ServiceSignal::Unreachable(service))) => {
Some(ServiceSignal::Unreachable(service))
},
(Some(ServiceSignal::RateLimited(service)), _)
| (_, Some(ServiceSignal::RateLimited(service))) => {
Some(ServiceSignal::RateLimited(service))
},
(Some(ServiceSignal::Reachable(service)), _)
| (_, Some(ServiceSignal::Reachable(service))) => Some(ServiceSignal::Reachable(service)),
(None, None) => None,
}
}
pub(crate) fn emit_service_signal(sender: &Sender<BackgroundMsg>, signal: Option<ServiceSignal>) {
let msg = match signal {
Some(ServiceSignal::Reachable(service)) => BackgroundMsg::ServiceReachable { service },
Some(ServiceSignal::Unreachable(service)) => BackgroundMsg::ServiceUnreachable { service },
Some(ServiceSignal::RateLimited(service)) => BackgroundMsg::ServiceRateLimited { service },
None => return,
};
let _ = sender.send(msg);
}
pub(crate) fn emit_service_recovered(sender: &Sender<BackgroundMsg>, service: ServiceKind) {
let _ = sender.send(BackgroundMsg::ServiceRecovered { service });
}
pub(crate) fn emit_git_info(sender: &Sender<BackgroundMsg>, path: &AbsolutePath) {
let Some(repo) = RepoInfo::get(path.as_path()) else {
return;
};
let checkout = CheckoutInfo::get(path.as_path(), repo.local_main_branch.as_deref());
let _ = sender.send(BackgroundMsg::RepoInfo {
path: path.clone(),
info: repo,
});
if let Some(checkout) = checkout {
let _ = sender.send(BackgroundMsg::CheckoutInfo {
path: path.clone(),
info: checkout,
});
}
}
pub(crate) fn cache_dir() -> AbsolutePath { cache_paths::ci_cache_root() }