grafbase_local_common/
environment.rs1#![allow(dead_code)]
2
3use crate::{
4 consts::{
5 DATABASE_DIRECTORY, DOT_GRAFBASE_DIRECTORY, GRAFBASE_DIRECTORY_NAME, GRAFBASE_SCHEMA_FILE_NAME, REGISTRY_FILE,
6 RESOLVERS_DIRECTORY_NAME,
7 },
8 errors::CommonError,
9};
10use once_cell::sync::OnceCell;
11use std::{
12 env,
13 path::{Path, PathBuf},
14};
15
16#[derive(Debug)]
20pub struct Environment {
21 pub project_path: PathBuf,
24 pub project_dot_grafbase_path: PathBuf,
27 pub project_grafbase_path: PathBuf,
30 pub project_grafbase_schema_path: PathBuf,
33 pub user_dot_grafbase_path: PathBuf,
35 pub project_grafbase_registry_path: PathBuf,
38 pub resolvers_source_path: PathBuf,
40 pub resolvers_build_artifact_path: PathBuf,
42 pub database_directory_path: PathBuf,
44}
45
46static ENVIRONMENT: OnceCell<Environment> = OnceCell::new();
48
49#[must_use]
50pub fn get_user_dot_grafbase_path() -> Option<PathBuf> {
51 dirs::home_dir().map(|home| home.join(DOT_GRAFBASE_DIRECTORY))
52}
53
54impl Environment {
55 pub fn try_init() -> Result<(), CommonError> {
63 let project_grafbase_schema_path =
64 Self::get_project_grafbase_path()?.ok_or(CommonError::FindGrafbaseDirectory)?;
65 let project_grafbase_path = project_grafbase_schema_path
66 .parent()
67 .expect("the schema directory must have a parent by definiton")
68 .to_path_buf();
69 let project_path = project_grafbase_path
70 .parent()
71 .expect("the grafbase directory must have a parent directory by definition")
72 .to_path_buf();
73 let project_dot_grafbase_path = project_path.join(DOT_GRAFBASE_DIRECTORY);
74 let user_dot_grafbase_path =
75 get_user_dot_grafbase_path().unwrap_or_else(|| project_grafbase_path.join(DOT_GRAFBASE_DIRECTORY));
76 let project_grafbase_registry_path = project_dot_grafbase_path.join(REGISTRY_FILE);
77 let resolvers_source_path = project_grafbase_path.join(RESOLVERS_DIRECTORY_NAME);
78 let resolvers_build_artifact_path = project_dot_grafbase_path.join(RESOLVERS_DIRECTORY_NAME);
79 let database_directory_path = project_dot_grafbase_path.join(DATABASE_DIRECTORY);
80 ENVIRONMENT
81 .set(Self {
82 project_path,
83 project_dot_grafbase_path,
84 project_grafbase_path,
85 project_grafbase_schema_path,
86 user_dot_grafbase_path,
87 project_grafbase_registry_path,
88 resolvers_source_path,
89 resolvers_build_artifact_path,
90 database_directory_path,
91 })
92 .expect("cannot set environment twice");
93
94 Ok(())
95 }
96
97 #[must_use]
103 pub fn get() -> &'static Self {
104 match ENVIRONMENT.get() {
105 Some(environment) => environment,
106 #[allow(clippy::panic)]
108 None => panic!("the environment object is uninitialized"),
109 }
110 }
111
112 fn get_project_grafbase_path() -> Result<Option<PathBuf>, CommonError> {
120 let project_grafbase_path = env::current_dir()
121 .map_err(|_| CommonError::ReadCurrentDirectory)?
122 .ancestors()
123 .find_map(|ancestor| {
124 let mut path = PathBuf::from(ancestor);
125
126 if let Some(first) = path.components().next() {
128 if Path::new(&first) == PathBuf::from(GRAFBASE_DIRECTORY_NAME) {
129 path.push(GRAFBASE_SCHEMA_FILE_NAME);
130 if path.is_file() {
131 return Some(path);
132 }
133 path.pop();
134 }
135 }
136
137 path.push(
138 [GRAFBASE_DIRECTORY_NAME, GRAFBASE_SCHEMA_FILE_NAME]
139 .iter()
140 .collect::<PathBuf>(),
141 );
142
143 if path.is_file() {
144 Some(path)
145 } else {
146 None
147 }
148 });
149
150 Ok(project_grafbase_path)
151 }
152}