1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
mod error;
pub use error::*;

mod log;
pub use log::*;

mod build_check;
pub use build_check::*;

mod project;
pub use project::*;

mod build;
pub use build::*;

mod generate;
use generate::*;

use std::fs::{remove_dir_all, File};
use std::io::BufWriter;
use std::path::PathBuf;

/// Wrapper for the build pipeline
pub struct LatexBuild<'a, L>
where
    L: Logger,
{
    /// Path to the config
    pub config_path: PathBuf,
    /// A mutable reference to the logger
    pub logger: &'a mut L,
}

impl<'a, L> LatexBuild<'a, L>
where
    L: Logger,
{
    /// Load a project and call `use_root_path` on it. In another word,
    /// load a project and make all the paths absolute
    pub fn load_project(&self) -> Result<Project, Error> {
        let mut root_path = self.config_path.clone();
        root_path.pop();

        let mut project = Project::load(&self.config_path)?;
        project.use_root_path(&root_path);

        return Ok(project);
    }

    /// Run the build pipeline
    pub fn build(&mut self) -> Result<(), Error> {
        let project = self.load_project()?;

        match project.can_build() {
            Err(error) => match error {
                Error::NoEntry => {
                    self.logger.error("no entry file");
                    return Ok(());
                }
                _ => {}
            },
            _ => {}
        }

        let mut needs_build_checker = NeedsBuildChecker::new(&project);

        while needs_build_checker.needs_build()? {
            self.logger.message("building project");

            if !project.build(self.logger)? {
                self.logger.error("build stopped due to error");
                break;
            }
        }

        return Ok(());
    }

    pub fn clean(&mut self) -> Result<(), Error> {
        let project = self.load_project()?;
        self.logger.message("cleaning bin directory");

        match remove_dir_all(project.bin()) {
            Ok(_a) => {}
            Err(err) => {
                let message = format!("{}", err);
                self.logger.error(&message);
            }
        }

        return Ok(());
    }

    pub fn generate_make(&mut self) -> Result<(), Error> {
        let makefile = Project::load(&self.config_path)?.to_make()?;

        let mut file = self.config_path.clone();
        file.pop();
        file.push("Makefile");

        let file = match File::create(file) {
            Ok(file) => file,
            Err(error) => return Err(Error::IO(error)),
        };

        let mut file_writer = BufWriter::new(file);

        makefile.generate(&mut file_writer)?;

        return Ok(());
    }
}