summaryrefslogtreecommitdiffstats
path: root/src/generator.rs
diff options
context:
space:
mode:
authorMinijackson <minijackson@riseup.net>2019-12-18 20:56:53 +0100
committerMinijackson <minijackson@riseup.net>2019-12-18 20:56:53 +0100
commitde896baff7e97fac4dde79078c9a2fa1c652576b (patch)
tree512b67b91d64e51d63f7ac5ff925a5c96d9aaf3c /src/generator.rs
parent860b73f1644ecd6548ae403ec483625fb7b625ea (diff)
downloadposeidoc-de896baff7e97fac4dde79078c9a2fa1c652576b.tar.gz
poseidoc-de896baff7e97fac4dde79078c9a2fa1c652576b.zip
Big refactoring
- entities should be more coherent when parsing multiple files - well defined, language agnostic entity tree - each module has its own configuration - less dead code
Diffstat (limited to 'src/generator.rs')
-rw-r--r--src/generator.rs219
1 files changed, 0 insertions, 219 deletions
diff --git a/src/generator.rs b/src/generator.rs
deleted file mode 100644
index 0fa5a94..0000000
--- a/src/generator.rs
+++ /dev/null
@@ -1,219 +0,0 @@
1use crate::config::Config;
2use crate::entities::{
3 Description, DynEntity, EntitiesManager, EntitiesManagerComponents, Usr,
4};
5use crate::pandoc::into_pandoc;
6
7use anyhow::{ensure, Context, Result};
8use rayon::Scope;
9use thiserror::Error;
10
11use std::collections::HashMap;
12use std::io::Write;
13use std::path::Path;
14
15const DEFAULT_CSS: &[u8] = include_bytes!("../res/style.css");
16
17pub(crate) fn generate(base_dir: &Path, manager: EntitiesManager, config: &Config) -> Result<()> {
18 let EntitiesManagerComponents {
19 toplevel_entities,
20 descriptions,
21 } = manager.decompose();
22
23 let md_output_dir = base_dir.join("markdown");
24 let html_output_dir = base_dir.join("html");
25
26 std::fs::create_dir_all(&md_output_dir)
27 .context("Failed to create the markdown output directory")?;
28 std::fs::create_dir_all(&html_output_dir)
29 .context("Failed to create the HTML output directory")?;
30
31 let mut css_tempfile = tempfile::Builder::new()
32 .prefix("style")
33 .suffix(".css")
34 .tempfile()?;
35 css_tempfile.write_all(DEFAULT_CSS)?;
36
37 let css_path = css_tempfile.path();
38 debug!("Generated temporary file with CSS at: {:?}", css_path);
39
40 rayon::scope(|scope| {
41 for (usr, entity) in &toplevel_entities {
42 generate_recursively(
43 &usr,
44 entity.as_ref(),
45 scope,
46 &descriptions,
47 &md_output_dir,
48 &html_output_dir,
49 css_path,
50 );
51 }
52 });
53
54 Ok(())
55}
56
57fn generate_recursively<'a>(
58 usr: &'a Usr,
59 entity: &'a DynEntity,
60 pool: &Scope<'a>,
61 descriptions: &'a HashMap<Usr, Description>,
62 md_output_dir: &'a Path,
63 html_output_dir: &'a Path,
64 css_path: &'a Path,
65) {
66 pool.spawn(move |pool| {
67 trace!("Trying to generate {}", usr.0);
68
69 let leftovers = generate_single(
70 &usr,
71 entity,
72 descriptions.get(&usr).unwrap(),
73 &descriptions,
74 &md_output_dir,
75 &html_output_dir,
76 &css_path,
77 )
78 .unwrap();
79
80 for (usr, entity) in leftovers {
81 generate_recursively(
82 usr,
83 entity,
84 pool,
85 descriptions,
86 md_output_dir,
87 html_output_dir,
88 css_path,
89 );
90 }
91 });
92}
93
94fn generate_single<'e>(
95 usr: &Usr,
96 entity: &'e DynEntity,
97 description: &Description,
98 descriptions: &HashMap<Usr, Description>,
99 md_output_dir: impl AsRef<Path>,
100 html_output_dir: impl AsRef<Path>,
101 css_path: impl AsRef<Path>,
102) -> Result<HashMap<&'e Usr, &'e DynEntity>> {
103 use std::io::prelude::*;
104 use std::process::{Command, Stdio};
105
106 let md_output_file = md_output_dir.as_ref().join(&usr.0);
107 let html_output_file = html_output_dir.as_ref().join(&usr.0);
108
109 let mut command = Command::new("pandoc");
110
111 command
112 .stdin(Stdio::piped())
113 .stdout(Stdio::piped())
114 .stderr(Stdio::piped())
115 .args(&[
116 "--from=json",
117 "--to=markdown",
118 "--output",
119 md_output_file
120 .to_str()
121 .context("Entity name is not valid UTF-8")?,
122 ]);
123
124 debug!("Launching command: {:?}", command);
125
126 let mut pandoc = command
127 .spawn()
128 .context("Failed to execute Pandoc command")?;
129
130 let (pandoc_ast, leftovers) = into_pandoc(entity, description, descriptions);
131
132 if log_enabled!(log::Level::Trace) {
133 let json =
134 serde_json::to_string(&pandoc_ast).context("Failed to convert Pandoc AST to JSON")?;
135 trace!("Sending json: {}", json);
136 write!(
137 pandoc.stdin.as_mut().expect("Pandoc stdin not captured"),
138 "{}",
139 &json,
140 )
141 .context("Failed to convert Pandoc AST to JSON")?;
142 } else {
143 serde_json::to_writer(
144 pandoc.stdin.as_mut().expect("Pandoc stdin not captured"),
145 &pandoc_ast,
146 )
147 .context("Failed to convert Pandoc AST to JSON")?;
148 }
149
150 let command_str = format!("{:?}", pandoc);
151
152 let output = pandoc
153 .wait_with_output()
154 .expect("Pandoc command wasn't running");
155
156 ensure!(
157 output.status.success(),
158 CommandError {
159 command: format!("{:?}", command_str),
160 status: output.status,
161 stderr: String::from_utf8(output.stderr).expect("Pandoc outputted invalid UTF-8"),
162 }
163 );
164
165 let mut command = Command::new("pandoc");
166 command
167 .stdin(Stdio::piped())
168 .stdout(Stdio::piped())
169 .stderr(Stdio::piped())
170 .args(&[
171 "--from=markdown",
172 "--to=html",
173 "--css",
174 css_path
175 .as_ref()
176 .to_str()
177 .context("CSS path is not valid UTF-8")?,
178 "--standalone",
179 "--self-contained",
180 md_output_file
181 .to_str()
182 .context("Entity name is not valid UTF-8")?,
183 "--output",
184 html_output_file
185 .to_str()
186 .context("Entity name is not valid UTF-8")?,
187 ]);
188
189 let command_str = format!("{:?}", command);
190 debug!("Launching command: {}", command_str);
191
192 let output = command
193 .output()
194 .context("Failed to execute Pandoc command")?;
195
196 ensure!(
197 output.status.success(),
198 CommandError {
199 command: command_str,
200 status: output.status,
201 stderr: String::from_utf8(output.stderr).expect("Pandoc outputted invalid UTF-8"),
202 }
203 );
204
205 Ok(leftovers)
206}
207
208#[derive(Debug, Clone, Error)]
209#[error(
210 "Command {} returned status {:?} and stderr {:?}",
211 command,
212 status,
213 stderr
214)]
215struct CommandError {
216 command: String,
217 status: std::process::ExitStatus,
218 stderr: String,
219}