1use crate::objects;
2use crate::objects::ObjectKind;
3use serde::{Deserialize, Serialize};
4use std::path::{Path, PathBuf};
5use std::{fs, io};
6
7#[derive(Debug, thiserror::Error)]
9#[non_exhaustive]
10pub enum WriterError {
11 #[error("IO error: {0}")]
12 IO(io::Error),
13
14 #[error("Failed to serialize query: {0}")]
15 Parse(serde_json::Error),
16
17 #[error("Client name not set")]
18 ClientNameNotSet,
19}
20
21impl From<io::Error> for WriterError {
22 fn from(err: io::Error) -> Self {
23 WriterError::IO(err)
24 }
25}
26
27impl From<serde_json::Error> for WriterError {
28 fn from(err: serde_json::Error) -> Self {
29 WriterError::Parse(err)
30 }
31}
32
33#[derive(Default)]
47pub struct Writer {
48 query: Query,
49 client_name: Option<String>,
50}
51
52impl Writer {
53 pub fn request_object<T: objects::Object>(&mut self) -> &mut Self {
55 self.query.requests.push(Request {
56 kind: T::kind(),
57 version: OptionalVersion {
58 major: T::major(),
59 minor: None,
60 },
61 });
62 self
63 }
64
65 pub fn add_request_exact<T: objects::Object>(&mut self, minor: u32) -> &mut Self {
67 self.query.requests.push(Request {
68 kind: T::kind(),
69 version: OptionalVersion {
70 major: T::major(),
71 minor: Some(minor),
72 },
73 });
74 self
75 }
76
77 pub fn request_all_objects(&mut self) -> &mut Self {
79 self.request_object::<objects::CodeModelV2>()
80 .request_object::<objects::ConfigureLogV1>()
81 .request_object::<objects::CacheV2>()
82 .request_object::<objects::ToolchainsV1>()
83 .request_object::<objects::CMakeFilesV1>()
84 }
85
86 pub fn set_client(&mut self, client_name: &str, client_data: serde_json::Value) -> &mut Self {
94 self.query.client = Some(client_data);
95 self.client_name = Some(client_name.to_owned());
96 self
97 }
98
99 pub fn write_stateless<P: AsRef<Path>>(&self, build_dir: P) -> Result<(), WriterError> {
107 let query_dir = dir(build_dir);
108
109 fs::create_dir_all(&query_dir)?;
111
112 for obj in &self.query.requests {
113 let query_file =
114 query_dir.join(format!("{}-v{}", obj.kind.as_str(), obj.version.major));
115 fs::write(&query_file, "")?;
116 }
117
118 Ok(())
119 }
120
121 pub fn write_stateful<P: AsRef<Path>>(&self, build_dir: P) -> Result<(), WriterError> {
132 let query_dir = dir(build_dir);
133 let client_dir = query_dir.join(
134 self.client_name
135 .as_ref()
136 .ok_or(WriterError::ClientNameNotSet)?,
137 );
138
139 fs::create_dir_all(&client_dir)?;
141
142 let query_file = client_dir.join("query.json");
144 let query = serde_json::to_string(&self.query)?;
145 fs::write(query_file, query)?;
146
147 Ok(())
148 }
149}
150
151#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
152struct OptionalVersion {
153 major: u32,
154 #[serde(skip_serializing_if = "Option::is_none")]
155 minor: Option<u32>,
156}
157
158#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
159struct Request {
160 kind: ObjectKind,
161 version: OptionalVersion,
162}
163
164#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
165struct Query {
166 requests: Vec<Request>,
167 client: Option<serde_json::Value>,
168}
169pub fn dir<P: AsRef<Path>>(build_dir: P) -> PathBuf {
171 Path::new(build_dir.as_ref())
172 .join(".cmake")
173 .join("api")
174 .join("v1")
175 .join("query")
176}