1use crate::{core_config::XCoreConfig, git::GitCli};
5use camino::{Utf8Path, Utf8PathBuf};
6use debug_ignore::DebugIgnore;
7use graph::PackageGraphPlus;
8use guppy::graph::PackageGraph;
9use once_cell::sync::OnceCell;
10
11pub mod core_config;
12mod errors;
13pub mod git;
14mod graph;
15mod workspace_subset;
16
17pub use errors::*;
18pub use workspace_subset::*;
19
20#[derive(Debug)]
22pub struct XCoreContext {
23 project_root: &'static Utf8Path,
24 config: XCoreConfig,
25 current_dir: Utf8PathBuf,
26 current_rel_dir: Utf8PathBuf,
27 git_cli: OnceCell<GitCli>,
28 package_graph_plus: DebugIgnore<OnceCell<PackageGraphPlus>>,
29}
30
31impl XCoreContext {
32 pub fn new(
34 project_root: &'static Utf8Path,
35 current_dir: Utf8PathBuf,
36 config: XCoreConfig,
37 ) -> Result<Self> {
38 let current_rel_dir = match current_dir.strip_prefix(project_root) {
39 Ok(rel_dir) => rel_dir.to_path_buf(),
40 Err(_) => {
41 return Err(SystemError::CwdNotInProjectRoot {
42 current_dir,
43 project_root,
44 })
45 }
46 };
47 Ok(Self {
50 project_root,
51 config,
52 current_dir,
53 current_rel_dir,
54 git_cli: OnceCell::new(),
55 package_graph_plus: DebugIgnore(OnceCell::new()),
56 })
57 }
58
59 pub fn project_root(&self) -> &'static Utf8Path {
61 self.project_root
62 }
63
64 pub fn config(&self) -> &XCoreConfig {
66 &self.config
67 }
68
69 pub fn current_dir(&self) -> &Utf8Path {
71 &self.current_dir
72 }
73
74 pub fn current_rel_dir(&self) -> &Utf8Path {
76 &self.current_rel_dir
77 }
78
79 pub fn current_dir_is_root(&self) -> bool {
81 self.current_rel_dir == ""
82 }
83
84 pub fn git_cli(&self) -> Result<&GitCli> {
86 let root = self.project_root;
87 self.git_cli.get_or_try_init(|| GitCli::new(root))
88 }
89
90 pub fn package_graph(&self) -> Result<&PackageGraph> {
92 Ok(self.package_graph_plus()?.package_graph())
93 }
94
95 pub fn partition_workspace_names<'a, B>(
99 &self,
100 names: impl IntoIterator<Item = &'a str>,
101 ) -> Result<(B, B)>
102 where
103 B: Default + Extend<&'a str>,
104 {
105 let workspace = self.package_graph()?.workspace();
106 let (known, unknown) = names
107 .into_iter()
108 .partition(|name| workspace.contains_name(name));
109 Ok((known, unknown))
110 }
111
112 pub fn subsets(&self) -> Result<&WorkspaceSubsets> {
114 Ok(self.package_graph_plus()?.subsets())
115 }
116
117 fn package_graph_plus(&self) -> Result<&PackageGraphPlus> {
122 self.package_graph_plus
123 .get_or_try_init(|| PackageGraphPlus::create(self))
124 }
125}