Skip to content

Commit c1fa550

Browse files
committed
Add options options.compiler.halt_on_error and options.compiler.silent
1 parent 4a3b56f commit c1fa550

7 files changed

Lines changed: 253 additions & 127 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# CHANGELOG
22

3+
## 2025-09-23-2
4+
5+
* Kill all children processes on timeout
6+
* Do not return partial PDF on timeout
7+
* Add option `options.compiler.halt_on_error`
8+
* Add option `options.compiler.silent`
9+
310
## 2025-09-23-1
411

512
* Fix timeout for compilation, with proper error return

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@ Payload (json)
155155
* URL to a file, with `url` (the resource pointed by the URL will be downloaded and decoded with UTF-8).
156156
* `options` properties:
157157
* `options.bibliography.command` defaults to `bibtex`. Available bibliography commands: `bibtex` and `biber`.
158+
* `options.compiler.halt_on_error` to enable `-halt-on-error` option (stop on first error, even if non fatal). Default to `false`.
159+
* `options.compiler.silent` to enable `-interaction=batchmode` option and Latexmk `-silent` (non verbose mode). Default to `false` (will use `-interaction=nonstopmode`).
158160
* `options.response.log_files_on_failure` to return full log files on compilation error. Defaults to `true`.
159161

160162

examples/basic_curl_cli/compile.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
# TODO Create example with multiple files (eg. image file).
44

5+
# Or https://latex.ytotech.com/builds/sync
56
curl -v -X POST http://localhost:8080/builds/sync \
67
-F "sample.tex=@sample.tex" \
8+
-F "compiler=xelatex" \
9+
-F "options.compiler.halt_on_error=false" \
10+
-F "options.compiler.silent=true" \
11+
-F "options.response.log_files_on_failure=false" \
712
-o sample.pdf

examples/basic_curl_cli/sample.pdf

32.3 KB
Binary file not shown.

examples/basic_curl_cli/sample.tex

Lines changed: 151 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,153 @@
1-
% !TeX program = pdflatex
2-
\documentclass[varwidth=210mm, border=0pt]{standalone}
3-
\usepackage[utf8]{inputenc}
4-
\usepackage[T2A]{fontenc}
5-
\usepackage[russian]{babel}
6-
\usepackage{tikz}
7-
\usepackage{xcolor}
8-
\usepackage{pagecolor}
9-
\usetikzlibrary{decorations.text, shapes.geometric, backgrounds}
10-
11-
% Цвета
12-
\definecolor{bgred}{HTML}{B71C1C}
13-
\definecolor{badge}{HTML}{7A0F0F}
14-
\definecolor{wood}{HTML}{8B5A2B}
15-
\definecolor{wood2}{HTML}{D0A06A}
16-
\definecolor{metal}{HTML}{2B2B2B}
17-
\definecolor{fire1}{HTML}{FF6F00}
18-
\definecolor{fire2}{HTML}{FFD54F}
19-
\definecolor{spike}{HTML}{111111}
20-
21-
\pagecolor{bgred}
1+
%!TEX TS-program = xelatex
2+
%!TEX encoding = UTF-8 Unicode
3+
4+
\documentclass[10pt, a4paper]{article}
5+
6+
% LAYOUT
7+
%--------------------------------
8+
\usepackage{geometry}
9+
\geometry{a4paper, left=43mm, right=43mm, top=51mm, bottom=17mm}
10+
11+
% No page numbers
12+
\pagenumbering{gobble}
13+
14+
% Left align
15+
\usepackage[document]{ragged2e}
16+
17+
18+
% TYPOGRAPHY
19+
%--------------------------------
20+
\usepackage{fontspec}
21+
\usepackage{xunicode}
22+
\usepackage{xltxtra}
23+
24+
% converts LaTeX specials (quotes, dashes etc.) to Unicode
25+
\defaultfontfeatures{Mapping=tex-text}
26+
\setromanfont [Ligatures={Common}, Numbers={OldStyle}]{Linux Libertine O}
27+
\setsansfont[Scale=0.9]{Liberation Sans}
28+
29+
% Set paragraph break
30+
\setlength{\parskip}{1em}
31+
32+
% Custom ampersand
33+
\newcommand{\amper}{{\fontspec[Scale=.95]{Linux Libertine O}\selectfont\itshape\&}}
34+
35+
\setmainfont[SmallCapsFeatures={LetterSpace=5,Letters=SmallCaps}]{Linux Libertine O}
36+
\setsansfont{Liberation Sans}
37+
38+
% Command required by how Pandoc handles the list conversion
39+
\providecommand{\tightlist}{%
40+
\setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
41+
42+
% TABLE CUSTOMIZATION
43+
%--------------------------------
44+
\usepackage{spreadtab}
45+
\usepackage[compact]{titlesec} % For customizing title sections
46+
\titlespacing*{\section}{0pt}{3pt}{-7pt} % Remove margin bottom from the title
47+
\usepackage{arydshln} % For the dotted line on the table
48+
\renewcommand{\arraystretch}{1.5} % Apply vertical padding to table cells
49+
\usepackage{hhline} % For single-cell borders
50+
\usepackage{enumitem} % For customizing lists
51+
\setlist{nolistsep} % No whitespace around list items
52+
\setlist[itemize]{leftmargin=0.5cm} % Reduce list left indent
53+
\setlength{\tabcolsep}{9pt} % Larger gutter between columns
54+
55+
56+
% LANGUAGE
57+
%--------------------------------
58+
\usepackage{polyglossia}
59+
\setmainlanguage{english}
60+
61+
% PDF SETUP
62+
%--------------------------------
63+
\usepackage[xetex, bookmarks, colorlinks, breaklinks]{hyperref}
64+
\hypersetup
65+
{
66+
pdfauthor=Max Mustermann,
67+
pdfsubject=Invoice Nr. 2015-11-04,
68+
pdftitle=Invoice Nr. 2015-11-04,
69+
linkcolor=blue,
70+
citecolor=blue,
71+
filecolor=black,
72+
urlcolor=blue
73+
}
74+
75+
% To display custom date
76+
% \usepackage[nodayofweek]{datetime}
77+
% \newdate{date}{01}{12}{1867}
78+
% \date{\displaydate{date}}
79+
% Use this instead of \today: % \displaydate{date}
80+
81+
% DOCUMENT
82+
%--------------------------------
2283
\begin{document}
23-
\begin{tikzpicture}[scale=2, every node/.style={transform shape}]
24-
% Центр и размеры
25-
\coordinate (C) at (0,0);
26-
\def\R{2} % радиус круглого бэйджа
27-
28-
% Круглый бэйдж (слегка тон-у тон)
29-
\shade[ball color=badge!90!black] (C) circle (\R);
30-
\fill[white, opacity=0.02] (C) circle (\R-0.02);
31-
32-
% Внутренний круг для контраста
33-
\fill[black!8, draw=black!30, line width=0.6pt] (C) circle (\R-0.3);
34-
35-
% Крест-накрест: два деревянных молотка
36-
% Параметры молотка
37-
\def\handlelen{2.2}
38-
\def\handlewid{0.12}
39-
\def\headlen{0.7}
40-
\def\headwid{0.45}
41-
\def\spikecount{5}
42-
43-
% Функция: рисуем один молоток, ориентированный по углу #1 градусов, сдвиг по центру
44-
\newcommand{\drawmallet}[2]{% #1 = angle, #2 = scale sign (1 or -1) for minor offset
45-
\begin{scope}[rotate=#1]
46-
% Ручка
47-
\shade[bottom color=wood!60, top color=wood2] ( -\handlelen, -\handlewid) rectangle (0, \handlewid);
48-
\draw[line width=0.6pt, brown!60] ( -\handlelen, -\handlewid) rectangle (0, \handlewid);
49-
% Скругление хвоста ручки
50-
\fill[wood] (-\handlelen-0.08,-\handlewid) ++(0,0) circle (0.08);
51-
% Головка молотка
52-
\begin{scope}[shift={( -0.1,0)}, xshift=0pt]
53-
\fill[metal!15!black] (0.05, -\headwid) rectangle (\headlen, \headwid);
54-
\draw[line width=0.8pt] (0.05, -\headwid) rectangle (\headlen, \headwid);
55-
% Шипы сверху
56-
\foreach \i in {0,...,4} {
57-
\pgfmathsetmacro{\x}{0.05 + (\i+0.3)*(\headlen-0.05)/\spikecount}
58-
\path[fill=spike] (\x, \headwid) -- (\x+0.06, \headwid+0.18) -- (\x+0.12, \headwid) -- cycle;
59-
}
60-
% Шипы снизу
61-
\foreach \i in {0,...,4} {
62-
\pgfmathsetmacro{\x}{0.05 + (\i+0.3)*(\headlen-0.05)/\spikecount}
63-
\path[fill=spike] (\x, -\headwid) -- (\x+0.06, -\headwid-0.18) -- (\x+0.12, -\headwid) -- cycle;
64-
}
65-
\end{scope}
66-
67-
% Небольшие трещины и текстура на ручке
68-
\draw[line width=0.4pt, brown!40] (-0.4,0.05) to[out=10,in=190] (-1.0,0.06);
69-
\draw[line width=0.4pt, brown!40] (-0.9,-0.03) to[out=-10,in=210] (-1.6,-0.04);
70-
\end{scope}
71-
}
72-
73-
% Рисуем два молотка крест-накрест
74-
\begin{scope}
75-
\drawmallet{30}{1}
76-
\drawmallet{-35}{-1}
77-
\end{scope}
78-
79-
% Огонь, исходящий из-за молотков
80-
\begin{scope}
81-
\clip (C) circle (\R-0.35);
82-
% Слой огня — несколько форм
83-
\fill[fire2] (-1.1,-0.15) .. controls (-0.9,0.8) and (-0.4,1.2) .. (0,1.05) .. controls (0.35,0.95) and (0.7,0.6) .. (0.9,0.15) -- (0.9,-0.6) .. controls (0.55,-0.2) and (0.2,-0.4) .. (-0.1,-0.25) -- cycle;
84-
\fill[fire1] (-0.95,-0.05) .. controls (-0.75,0.6) and (-0.35,0.9) .. (0,0.85) .. controls (0.3,0.78) and (0.6,0.5) .. (0.75,0.18) -- (0.75,-0.4) .. controls (0.45,-0.05) and (0.15,-0.25) .. (-0.05,-0.15) -- cycle;
85-
% Внутренние языки
86-
\fill[yellow!80!orange] (-0.5,0.03) .. controls (-0.3,0.45) and (-0.12,0.6) .. (0,0.55) .. controls (0.09,0.52) and (0.22,0.4) .. (0.28,0.3) -- (0.28,-0.05) .. controls (0.05,0.1) and (-0.15,0.0) .. (-0.3,0.01) -- cycle;
87-
\end{scope}
88-
89-
% Текст по дуге внизу (название)
90-
\begin{scope}
91-
\def\textstr{КОЛОТУШКИ}
92-
\draw[white] (0,-1.2) arc (200:340:1.4) node[midway, sloped, below, text=white, font=\bfseries\Large]{\textstr};
93-
% Более аккуратно — с использованием decorations.text
94-
\path[decorate, decoration={text along path, text={\bfseries\Large \textstr}, raise=3pt}] (180:-1.45) arc (180:0:1.45);
95-
\end{scope}
96-
97-
% Маленькая центральная эмблема (опционально)
98-
\fill[black!10] (0,0.9) circle (0.18);
99-
\draw[line width=0.6pt, white] (0,0.9) circle (0.18);
100-
\node[text=white, font=\bfseries\small] at (0,0.9) {KS};
101-
102-
% Контур внешнего круга
103-
\draw[line width=1.2pt, color=black!50] (C) circle (\R);
104-
105-
\end{tikzpicture}
106-
\end{document}
84+
\small
85+
\textsc{\textbf{Max Mustermann}}
86+
\textbullet{} \textsc{Musterstraße 37}
87+
\textbullet{} \textsc{12345 Musterstadt}
88+
89+
\vspace{1em}
90+
91+
\normalsize \sffamily
92+
Erika Mustermann\\
93+
Musterallee 1\\
94+
12345 Musterstadt\\
95+
Germany\\
96+
97+
\vspace{6em}
98+
99+
\begin{flushright}
100+
\small
101+
Musterstadt, \today
102+
\end{flushright}
103+
104+
\vspace{1em}
105+
106+
107+
\section*{\textsc{Invoice} \textsc{\#2015-11-04}}
108+
\footnotesize
109+
\newcounter{pos}
110+
\setcounter{pos}{0}
111+
\STautoround*{2} % Get spreadtab to always display the decimal part
112+
% Use comma as decimal separator
113+
114+
\begin{spreadtab}{{tabular}[t t t]{lp{8.2cm}r}}
115+
\hdashline[1pt/1pt]
116+
@ \noalign{\vskip 2mm} \textbf{Pos.} & @ \textbf{Description} & @ \textbf{Prices in EUR} \\ \hline
117+
@ \noalign{\vskip 2mm} \refstepcounter{pos} \thepos
118+
& @ The first service provided
119+
& 320\\ @ \noalign{\vskip 2mm} \refstepcounter{pos} \thepos
120+
& @ And another one, with a list of details
121+
\newline \begin{itemize}
122+
\scriptsize \item Some more detailed explanation
123+
\scriptsize \item of the service provided
124+
\scriptsize \item Looking good
125+
\end{itemize}
126+
& 245\\ @ \noalign{\vskip 2mm} \refstepcounter{pos} \thepos
127+
& @ The last service provided
128+
& 65\\ \noalign{\vskip 2mm} \hline
129+
@ & @ \multicolumn{1}{r}{Subtotal:} & :={sum(c1:[0,-1])} \\ \hhline{~~-}
130+
@ & @ \multicolumn{1}{r}{VAT 20\%:} & 20/100*[0,-1] \\ \hhline{~~-}
131+
@ & @ \multicolumn{1}{r}{\textbf{Total:}} & \textbf{:={[0,-1]+[0,-2]}} \\ \hhline{~~-}
132+
\end{spreadtab}
107133

134+
\vspace{15mm}
135+
136+
\sffamily
137+
\small
138+
Please transfer the due amount to the following bank account within the
139+
next 14 days:
140+
141+
Mustermann GmbH Kreditinstitut: Deutsche Postbank AG IBAN: DE18 3601
142+
0043 9999 9999 99 BIC: PBNKDEFF
143+
144+
We really appreciate your business and look forward to future projects
145+
together.
146+
147+
Best regards,
148+
149+
\medskip
150+
151+
Max Mustermann
152+
153+
\end{document}

latexonhttp/api/builds.py

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,40 @@ def default(self, obj):
116116
"allowed": AVAILABLE_BIBLIOGRAPHY_COMMANDS,
117117
}
118118
},
119-
}
119+
},
120+
"response": {
121+
"type": "dict",
122+
"schema": {
123+
"log_files_on_failure": {
124+
"type": ["boolean", "string", "integer"],
125+
}
126+
},
127+
},
128+
"compiler": {
129+
"type": "dict",
130+
"schema": {
131+
"halt_on_error": {
132+
"type": ["boolean", "string", "integer"],
133+
},
134+
"silent": {
135+
"type": ["boolean", "string", "integer"],
136+
},
137+
},
138+
},
120139
},
121140
},
122141
}
123142
input_spec_validator = cerberus.Validator(input_spec_schema)
124143

125144

145+
def parse_bool_str_arg(value):
146+
if value is None:
147+
return None
148+
if isinstance(value, bool):
149+
return value
150+
return str(value).lower() in ["true", "1", "t"]
151+
152+
126153
@builds_app.route("/sync", methods=["GET", "POST"])
127154
def compiler_latex():
128155
input_spec = None
@@ -202,11 +229,31 @@ def compiler_latex():
202229
glom.glom(input_spec, "options.bibliography.command", default="bibtex"),
203230
missing=dict,
204231
)
232+
# -options.compiler.halt_on_error
233+
glom.assign(
234+
input_spec,
235+
"options.compiler.halt_on_error",
236+
parse_bool_str_arg(
237+
glom.glom(input_spec, "options.compiler.halt_on_error", default=False)
238+
),
239+
missing=dict,
240+
)
241+
# -options.compiler.silent
242+
glom.assign(
243+
input_spec,
244+
"options.compiler.silent",
245+
parse_bool_str_arg(
246+
glom.glom(input_spec, "options.compiler.silent", default=False)
247+
),
248+
missing=dict,
249+
)
205250
# -options.log_files_on_failure
206251
glom.assign(
207252
input_spec,
208253
"options.response.log_files_on_failure",
209-
glom.glom(input_spec, "options.response.log_files_on_failure", default=True),
254+
parse_bool_str_arg(
255+
glom.glom(input_spec, "options.response.log_files_on_failure", default=True)
256+
),
210257
missing=dict,
211258
)
212259

@@ -305,6 +352,7 @@ def on_fetched(resource, data):
305352
compilerName,
306353
get_workspace_root_path(workspace_id),
307354
main_resource,
355+
workspace_id,
308356
input_spec["options"],
309357
)
310358
# TODO Update entry in db with status, size of PDF or logs,
@@ -314,7 +362,7 @@ def on_fetched(resource, data):
314362
# Response creation.
315363
# -------------
316364

317-
if not latexToPdfOutput["pdf"]:
365+
if latexToPdfOutput["status"] != "ok":
318366
error_compilation = latexToPdfOutput["logs"]
319367
return (
320368
{
@@ -323,6 +371,7 @@ def on_fetched(resource, data):
323371
if latexToPdfOutput["is_timeout"]
324372
else "COMPILATION_ERROR"
325373
),
374+
"duration": round(latexToPdfOutput["duration"], 2),
326375
"logs": latexToPdfOutput["logs"],
327376
**(
328377
{

0 commit comments

Comments
 (0)