From 72e8a88214c3ba21e7a3f17d6b62c0fc80cdbfb7 Mon Sep 17 00:00:00 2001 From: Robin Sonnabend <robin@fsmpi.rwth-aachen.de> Date: Thu, 23 Feb 2017 00:14:40 +0100 Subject: [PATCH] Compiling the latex version works --- parser.py | 2 +- static/tex/protokoll2.cls | 175 ++++++++++++++++++++++ tasks.py | 95 ++++++------ templates/{protokoll.tex => protocol.tex} | 6 +- 4 files changed, 229 insertions(+), 49 deletions(-) create mode 100644 static/tex/protokoll2.cls rename templates/{protokoll.tex => protocol.tex} (89%) diff --git a/parser.py b/parser.py index 5ded4da..f5cf680 100644 --- a/parser.py +++ b/parser.py @@ -243,7 +243,7 @@ class Remark(Element): class Fork(Element): def __init__(self, environment, name, parent, linenumber, children=None): self.environment = environment if environment is None or len(environment) > 0 else None - self.name = name if name is None or len(name) > 0 else None + self.name = name.strip() if (name is not None and len(name) > 0) else None self.parent = parent self.linenumber = linenumber self.children = [] if children is None else children diff --git a/static/tex/protokoll2.cls b/static/tex/protokoll2.cls new file mode 100644 index 0000000..d12c78f --- /dev/null +++ b/static/tex/protokoll2.cls @@ -0,0 +1,175 @@ +% protokoll.cls -- version 0.1 -- last changed: see mtime of the file ;) +% +% +% Author: Sebastian G�nther <samson@asta.rwth-aachen.de> + +% zuerst mal LaTeX's formalzeug +\NeedsTeXFormat{LaTeX2e} +\ProvidesClass{protokoll2}[2004/06/04 protokoll.cls v0.1 macht Protokolle (VV)] +\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}} +%\ExecuteOptions{draft} +\ProcessOptions\relax + +% die restlichen optionen geben wir an article weiter +\LoadClass[a4paper]{article} + +% so ein paar sachen die wir eh immer brauchen +\RequirePackage{ngerman} +\RequirePackage[T1]{fontenc} +\RequirePackage[utf8]{inputenc} +\RequirePackage[vmargin=1.5cm,hmargin={1.5cm,1.2cm},bindingoffset=8mm]{geometry} +%\RequirePackage{lineno} +\RequirePackage{longtable} +\RequirePackage{framed} +\RequirePackage{eurosym} +\RequirePackage{csquotes} + + +% nicht einr�cken und benutzerinnendefinierte kopfzeile +\setlength{\parindent}{0cm} +\setlength{\parskip}{1ex} +\pagestyle{myheadings} + +\renewcommand*{\rmdefault}{phv} +\renewcommand*{\sfdefault}{phv} + +% Titel +\newcommand{\Kopf}[1]{\markboth{#1}{#1}} +\newcommand{\Titel}[2]{ + \markboth{#2}{#2} + \markright{#2} + \thispagestyle{plain} + \begin{center} + \textbf{#1} + \end{center} +} + +% Tops +\renewcommand{\thesection}{TOP~\arabic{section}} +\renewcommand{\thesubsection}{TOP~\arabic{section}~(\alph{subsection})} +\newcommand{\TOP}[1]{\section{#1}} +\newcommand{\unterTOP}[1]{\subsection{#1}} +% F�rs Inhaltsverzeichnisanpassen +\renewcommand{\l@section}{\@dottedtocline{1}{1.5em}{4em}} +\renewcommand{\l@subsection}{\@dottedtocline{2}{5.5em}{5.2em}} +\renewcommand{\contentsname}{Tagesordnung} +\newcommand{\Inhalt}{\tableofcontents} + +% Zeilen-Numerierungen +\newcommand{\ZeilenNummerierung}{\pagewiselinenumbers\linenumbers} +\newcommand{\EndeZeilenNummerierung}{\nolinenumbers} + +% Anwesenheit +\newenvironment{Anw}{\begin{list}{}{% + \renewcommand{\makelabel}[1]{\hfill ##1 }% + \settowidth{\labelwidth}{Anwesenheit:~}% + \addtolength{\labelwidth}{\labelsep}% + \setlength{\leftmargin}{\labelwidth}% + \addtolength{\leftmargin}{\labelsep}% + \addtolength{\leftmargin}{\labelsep}% + \setlength{\itemsep}{0pt}% + \setlength{\parsep}{0pt}% + \setlength{\topsep}{0pt}% + }% +}% +{\end{list}} + +% Abwesenheit +\newenvironment{Abw}{\begin{list}{}{% + \renewcommand{\makelabel}[1]{\hfill ##1 }% + \settowidth{\labelwidth}{Anwesenheit:~}% + \addtolength{\labelwidth}{\labelsep}% + \setlength{\leftmargin}{\labelwidth}% + \addtolength{\leftmargin}{\labelsep}% + \addtolength{\leftmargin}{\labelsep}% + \setlength{\itemsep}{0pt}% + \setlength{\parsep}{0pt}% + \setlength{\topsep}{0pt}% + }% +}% +{\end{list}} + +% Abk�rzungen +\newenvironment{Abk}{% + \begin{list}{}{% + Abkürzungen: + \renewcommand{\makelabel}[1]{\hfill ##1 }% + \setlength{\labelwidth}{2cm}% + \addtolength{\labelwidth}{\labelsep}% + \setlength{\leftmargin}{\labelwidth}% + \addtolength{\leftmargin}{\labelsep}% + \addtolength{\leftmargin}{\labelsep}% + \setlength{\itemsep}{0pt}% + \setlength{\parsep}{0pt}% + \setlength{\topsep}{0pt}% + }% +}% +{\end{list}} + +% Unterschriften f�r eine und zwei Personen +\newcommand{\Unterschrift}[2]{ + \vspace*{1.4cm} + \begin{center} + \rule{.4\linewidth}{.15mm} \\ + #1 \\ + \footnotesize{(#2)} + \end{center} +} +\newcommand{\ZweiUnterschrift}[4]{ + \vspace*{1.4cm} + \begin{center} + \parbox[t]{.4\linewidth}{ + \rule{\linewidth}{.15mm} \\ + \vspace*{-.4cm}\begin{center} + #1 \\ + \footnotesize{(#2)} + \end{center} + } + \hspace*{.1\linewidth} + \parbox[t]{.4\linewidth}{ + \rule{\linewidth}{.15mm} \\ + \vspace*{-.4cm}\begin{center} + #3 \\ + \footnotesize{(#4)} + \end{center} + } + \end{center} +} + +% \newcommand{\Antrag}[1]{ +% % \setlength{\arrayrulewidth}{2mm} +% % \begin{longtable}{|ll} +% % \hspace{2mm} & \parbox[t]{17cm}{#1} +% % \end{longtable} +% \begingroup +% \rule{2mm}{2mm} +% \leftskip10cm +% % \rightskip\leftskip +% #1 +% \par +% \endgroup +% } + +\newcommand{\Antrag}[1]{ + \setlength{\arrayrulewidth}{2mm} + \begin{longtable}{|ll} + % \hspace{2mm} & \parbox[t]{17cm}{#1} + \hspace{2mm} & \begin{minipage}{17cm} #1\end{minipage} + \end{longtable} +} + +\newenvironment{antrag} +{% + \par% + \begingroup% + \leftskip1cm% +} +{\par\endgroup} + + +\newcommand{\Bericht}[1]{ + \Antrag{#1} +} + +\newcommand{\PE}[2]{\textbf{Persönliche Erklärung von #1:}\\\emph{\glqq{}#2\grqq{}}\\} + diff --git a/tasks.py b/tasks.py index 47102ca..52dfac1 100644 --- a/tasks.py +++ b/tasks.py @@ -3,6 +3,7 @@ from flask import render_template import os import subprocess import shutil +import tempfile from models.database import Document, Protocol, Error, Todo, Decision, TOP, DefaultTOP from server import celery, app @@ -49,7 +50,8 @@ def parse_protocol_async(protocol_id, encoded_kwargs): protocol = Protocol.query.filter_by(id=protocol_id).first() if protocol is None: raise Exception("No protocol given. Aborting parsing.") - for error in protocol.errors: + old_errors = list(protocol.errors) + for error in old_errors: protocol.errors.remove(error) db.session.commit() if protocol.source is None: @@ -158,55 +160,58 @@ def parse_protocol_async(protocol_id, encoded_kwargs): top = TOP(protocol.id, fork.name, index, False) db.session.add(top) db.session.commit() - protocol.done = True - db.session.commit() + latex_source = texenv.get_template("protocol.tex").render(protocol=protocol, tree=tree) + compile(latex_source, protocol) - + protocol.done = True + db.session.commit() +def compile(content, protocol): + compile_async.delay(content, protocol.id) @celery.task -def compile_async(name, document_id): - is_error = False - try: - current = os.getcwd() - os.chdir("latex") - os.makedirs("bin", exist_ok=True) - command = [ - "/usr/bin/xelatex", - "-halt-on-error", - "-file-line-error", - "-output-directory", "bin", - "{}.tex".format(name) - ] - subprocess.check_call(command, universal_newlines=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - subprocess.check_call(command, universal_newlines=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - os.chdir(current) - os.makedirs("documents/pdf", exist_ok=True) - shutil.copy("latex/bin/{}.pdf".format(name), "documents/pdf/") - for typ in ["pdf", "log", "aux", "out"]: - silent_remove("latex/bin/{}.{}".format(name, typ)) - silent_remove("latex/{}.tex".format(name)) - except subprocess.SubprocessError: - is_error = True - with app.app_context(): - document = Document.query.filter_by(id=document_id).first() - if document is not None: - document.ready = False - document.error = True - db.session.commit() - finally: - # TODO: activate deleting files in error case too - #for typ in ["pdf", "log", "aux", "out"]: - # silent_remove("latex/bin/{}.{}".format(name, typ)) - #silent_remove("latex/{}.tex".format(name)) - os.chdir(current) - if not is_error: - with app.app_context(): - document = Document.query.filter_by(id=document_id).first() - if document is not None: - document.ready = True - db.session.commit() +def compile_async(content, protocol_id): + with tempfile.TemporaryDirectory() as compile_dir, app.app_context(): + protocol = Protocol.query.filter_by(id=protocol_id).first() + try: + current = os.getcwd() + protocol_source_filename = "protocol.tex" + protocol_target_filename = "protocol.tex" + log_filename = "protocol.log" + with open(os.path.join(compile_dir, protocol_source_filename), "w") as source_file: + source_file.write(content) + shutil.copy("static/tex/protokoll2.cls", compile_dir) + os.chdir(compile_dir) + command = [ + "/usr/bin/xelatex", + "-halt-on-error", + "-file-line-error", + protocol_source_filename + ] + subprocess.check_call(command, universal_newlines=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + subprocess.check_call(command, universal_newlines=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + os.chdir(current) + document = Document(protocol.id, name="protokoll_{}_{}.pdf".format(protocol.protocoltype.short_name, date_filter(protocol.date)), filename="", is_compiled=True) + db.session.add(document) + db.session.commit() + target_filename = "compiled-{}.pdf".format(document.id) + document.filename = target_filename + shutil.copy(os.path.join(compile_dir, protocol_target_filename), os.path.join("documents", target_filename)) + db.session.commit() + except subprocess.SubprocessError: + log = "" + total_log_filename = os.path.join(compile_dir, log_filename) + if os.path.isfile(total_log_filename): + with open(total_log_filename, "r") as log_file: + log = log_file.read() + else: + log = "Logfile not found." + error = protocol.create_error("Compiling", "Compiling LaTeX failed", log) + db.session.add(error) + db.session.commit() + finally: + os.chdir(current) def send_mail(mail): send_mail_async.delay(mail.id) diff --git a/templates/protokoll.tex b/templates/protocol.tex similarity index 89% rename from templates/protokoll.tex rename to templates/protocol.tex index 5616e1b..1bf29fd 100644 --- a/templates/protokoll.tex +++ b/templates/protocol.tex @@ -33,7 +33,7 @@ \begin{itemize} \ENV{if protocol.decisions|length > 0} \ENV{for decision in protocol.decisions} - \item \VAR{decisions.content|escape_tex} + \item \VAR{decision.content|escape_tex} \ENV{endfor} \ENV{else} \item Keine Beschlüsse @@ -43,8 +43,8 @@ Beginn der Sitzung: \VAR{protocol.start_time|timify} \ENV{for top in tree.children} - \TOP{\VAR{top.name}} % here we probably have information doubly - \VAR{top.render()} + \TOP{\VAR{top.name|escape_tex}} % here we probably have information doubly + \VAR{top.render()|escape_tex} \ENV{endfor} Ende der Sitzung: \VAR{protocol.end_time|timify} -- GitLab