Ok(file)
}
- fn write_rendered(path: &str, rendered: &str) -> usize {
+ fn write_rendered(&self, path: &str, rendered: &str) -> usize {
+ // Ensure that the requested output path is actually a child
+ // of the output directory, as a sanity check to ensure we
+ // aren't writing out of bounds.
+ let canonical_root = self.settings.outputs.path.canonicalize().expect(&format!(
+ "Cannot find canonical version of output path: {}",
+ self.settings.outputs.path.display()
+ ));
+ let canonical_path = PathBuf::from(path);
+ let has_relative_dirs = canonical_path.ancestors().any(|x| x.file_name().is_none() &&
+ x != Path::new("/"));
+ assert!(
+ canonical_path.is_absolute(),
+ "ERROR: write_rendered called with a relative path: {}",
+ path
+ );
+ assert!(
+ !has_relative_dirs,
+ "ERROR: write_rendered called with a relative path: {}",
+ path
+ );
+ let _ = canonical_path
+ .ancestors()
+ .find(|x| x == &canonical_root)
+ .expect(&format!(
+ "Output file {} not contained in output path: {}",
+ canonical_path.display(),
+ canonical_root.display()
+ ));
+
+ // Write the file to disk
let mut file = File::create(path).expect(&format!("Unable to write to output path: {}", path));
file.write(rendered.as_bytes())
.expect(&format!("Failed to save rendered html to path: {}", path));
if let Some(templ_file) = self.settings.templates.repo_summary.as_deref() {
match tera.render(templ_file, &local_ctx) {
Ok(rendered) => {
- repo_bytes += GitsyGenerator::write_rendered(
- &self.settings.outputs.repo_summary(Some(&summary), None),
- &rendered,
- );
+ repo_bytes +=
+ self.write_rendered(&self.settings.outputs.repo_summary(Some(&summary), None), &rendered);
}
Err(x) => match x.kind {
_ => error!("ERROR: {:?}", x),
paged_ctx.insert("branches", &page);
match tera.render(templ_file, &paged_ctx) {
Ok(rendered) => {
- repo_bytes += GitsyGenerator::write_rendered(&pagination.cur_page, &rendered);
+ repo_bytes += self.write_rendered(&pagination.cur_page, &rendered);
}
Err(x) => match x.kind {
_ => error!("ERROR: {:?}", x),
if let Some(templ_file) = self.settings.templates.branch.as_deref() {
match tera.render(templ_file, &local_ctx) {
Ok(rendered) => {
- repo_bytes += GitsyGenerator::write_rendered(
- &self.settings.outputs.branch(Some(&summary), Some(branch)),
- &rendered,
- );
+ repo_bytes += self
+ .write_rendered(&self.settings.outputs.branch(Some(&summary), Some(branch)), &rendered);
}
Err(x) => match x.kind {
_ => error!("ERROR: {:?}", x),
paged_ctx.insert("tags", &page);
match tera.render(templ_file, &paged_ctx) {
Ok(rendered) => {
- repo_bytes += GitsyGenerator::write_rendered(&pagination.cur_page, &rendered);
+ repo_bytes += self.write_rendered(&pagination.cur_page, &rendered);
}
Err(x) => match x.kind {
_ => error!("ERROR: {:?}", x),
if let Some(templ_file) = self.settings.templates.tag.as_deref() {
match tera.render(templ_file, &local_ctx) {
Ok(rendered) => {
- repo_bytes += GitsyGenerator::write_rendered(
- &self.settings.outputs.tag(Some(&summary), Some(tag)),
- &rendered,
- );
+ repo_bytes +=
+ self.write_rendered(&self.settings.outputs.tag(Some(&summary), Some(tag)), &rendered);
}
Err(x) => match x.kind {
_ => error!("ERROR: {:?}", x),
paged_ctx.insert("history", &page);
match tera.render(templ_file, &paged_ctx) {
Ok(rendered) => {
- repo_bytes += GitsyGenerator::write_rendered(&pagination.cur_page, &rendered);
+ repo_bytes += self.write_rendered(&pagination.cur_page, &rendered);
}
Err(x) => match x.kind {
_ => error!("ERROR: {:?}", x),
if let Some(templ_file) = self.settings.templates.commit.as_deref() {
match tera.render(templ_file, &local_ctx) {
Ok(rendered) => {
- repo_bytes += GitsyGenerator::write_rendered(
- &self.settings.outputs.commit(Some(&summary), Some(commit)),
- &rendered,
- );
+ repo_bytes += self
+ .write_rendered(&self.settings.outputs.commit(Some(&summary), Some(commit)), &rendered);
}
Err(x) => match x.kind {
_ => error!("ERROR: {:?}", x),
.expect("Invalid syntax highlighting theme specified.");
let css: String = css_for_theme_with_class_style(theme, syntect::html::ClassStyle::Spaced)
.expect("Invalid syntax highlighting theme specified.");
- repo_bytes += GitsyGenerator::write_rendered(
- &self.settings.outputs.syntax_css(Some(&summary), None),
- css.as_str(),
- );
+ repo_bytes +=
+ self.write_rendered(&self.settings.outputs.syntax_css(Some(&summary), None), css.as_str());
}
// TODO: parallelize the rest of the processing steps. This one is
if let Some(templ_file) = self.settings.templates.file.as_deref() {
match tera.render(templ_file, &local_ctx) {
Ok(rendered) => {
- local_bytes = GitsyGenerator::write_rendered(
+ local_bytes = self.write_rendered(
&self.settings.outputs.file(Some(&summary), Some(&file)),
&rendered,
);
if let Some(templ_file) = self.settings.templates.dir.as_deref() {
match tera.render(templ_file, &local_ctx) {
Ok(rendered) => {
- repo_bytes += GitsyGenerator::write_rendered(
- &self.settings.outputs.dir(Some(&summary), Some(dir)),
- &rendered,
- );
+ repo_bytes +=
+ self.write_rendered(&self.settings.outputs.dir(Some(&summary), Some(dir)), &rendered);
}
Err(x) => match x.kind {
_ => error!("ERROR: {:?}", x),
if let Some(templ_file) = self.settings.templates.repo_list.as_deref() {
match tera.render(templ_file, &global_ctx) {
Ok(rendered) => {
- global_bytes +=
- GitsyGenerator::write_rendered(&self.settings.outputs.repo_list(None, None), &rendered);
+ global_bytes += self.write_rendered(&self.settings.outputs.repo_list(None, None), &rendered);
}
Err(x) => match x.kind {
_ => error!("ERROR: {:?}", x),
if let Some(templ_file) = self.settings.templates.error.as_deref() {
match tera.render(templ_file, &global_ctx) {
Ok(rendered) => {
- global_bytes += GitsyGenerator::write_rendered(&self.settings.outputs.error(None, None), &rendered);
+ global_bytes += self.write_rendered(&self.settings.outputs.error(None, None), &rendered);
}
Err(x) => match x.kind {
_ => error!("ERROR: {:?}", x),
_ => tmpl_str,
};
let tmpl = PathBuf::from(tmpl_str);
- let mut path = self.path.clone();
+ let mut path = self.path.clone().canonicalize()
+ .expect(&format!("ERROR: unable to canonicalize output path: {}", self.path.display()));
path.push(tmpl);
match $is_dir {
true => {