Show More
@@ -30,31 +30,101 b' class PDFPostProcessor(PostProcessorBase):' | |||||
30 | How many times pdflatex will be called. |
|
30 | How many times pdflatex will be called. | |
31 | """) |
|
31 | """) | |
32 |
|
32 | |||
33 | command = List(["pdflatex", "{filename}"], config=True, help=""" |
|
33 | pdflatex_command = List(["pdflatex", "{filename}"], config=True, help=""" | |
34 | Shell command used to compile PDF.""") |
|
34 | Shell command used to compile PDF.""") | |
35 |
|
35 | |||
|
36 | bibtex_command = List(["bibtex", "{filename}"], config=True, help=""" | |||
|
37 | Shell command used to run bibtex.""") | |||
|
38 | ||||
36 | verbose = Bool(False, config=True, help=""" |
|
39 | verbose = Bool(False, config=True, help=""" | |
37 | Whether or not to display the output of the compile call. |
|
40 | Whether or not to display the output of the compile call. | |
38 | """) |
|
41 | """) | |
39 |
|
42 | |||
40 | def postprocess(self, input): |
|
43 | temp_file_exts = List(['.aux', '.bbl', '.blg', '.idx', '.log', '.out'], | |
41 | """ |
|
44 | config=True, help=""" | |
42 | Consume and write Jinja output a PDF. |
|
45 | Filename extensions of temp files to remove after running | |
43 | See files.py for more... |
|
46 | """) | |
44 | """ |
|
47 | ||
45 | command = [c.format(filename=input) for c in self.command] |
|
48 | def run_command(self, command_list, filename, count, log_function): | |
46 | self.log.info("Building PDF: %s", command) |
|
49 | """Run pdflatex or bibtext count times. | |
47 | with open(os.devnull, 'rb') as null: |
|
50 | ||
48 | stdout = subprocess.PIPE if not self.verbose else None |
|
51 | Parameters | |
49 | for index in range(self.iteration_count): |
|
52 | ---------- | |
50 | p = subprocess.Popen(command, stdout=stdout, stdin=null) |
|
53 | command_list : list | |
51 | out, err = p.communicate() |
|
54 | A list of args to provide to Popen. Each element of this | |
52 | if p.returncode: |
|
55 | list will be interpolated with the filename to convert. | |
53 | if self.verbose: |
|
56 | filename : unicode | |
54 | # verbose means I didn't capture stdout with PIPE, |
|
57 | The name of the file to convert. | |
55 | # so it's already been displayed and `out` is None. |
|
58 | count : int | |
56 | out = u'' |
|
59 | How many times to run the command. | |
57 | else: |
|
60 | ||
58 | out = out.decode('utf-8', 'replace') |
|
61 | Returns | |
59 | self.log.critical(u"PDF conversion failed: %s\n%s", command, out) |
|
62 | ------- | |
60 | return |
|
63 | continue : bool | |
|
64 | A boolean indicating if the command was successful (True) | |||
|
65 | or failed (False). | |||
|
66 | """ | |||
|
67 | command = [c.format(filename=filename) for c in command_list] | |||
|
68 | times = 'time' if count == 1 else 'times' | |||
|
69 | self.log.info("Running %s %i %s: %s", command_list[0], count, times, command) | |||
|
70 | with open(os.devnull, 'rb') as null: | |||
|
71 | stdout = subprocess.PIPE if not self.verbose else None | |||
|
72 | for index in range(count): | |||
|
73 | p = subprocess.Popen(command, stdout=stdout, stdin=null) | |||
|
74 | out, err = p.communicate() | |||
|
75 | if p.returncode: | |||
|
76 | if self.verbose: | |||
|
77 | # verbose means I didn't capture stdout with PIPE, | |||
|
78 | # so it's already been displayed and `out` is None. | |||
|
79 | out = u'' | |||
|
80 | else: | |||
|
81 | out = out.decode('utf-8', 'replace') | |||
|
82 | log_function(command, out) | |||
|
83 | return False # failure | |||
|
84 | return True # success | |||
|
85 | ||||
|
86 | def run_pdflatex(self, filename): | |||
|
87 | """Run pdflatex self.iteration_count times.""" | |||
|
88 | ||||
|
89 | def log_error(command, out): | |||
|
90 | self.log.critical(u"pdflatex failed: %s\n%s", command, out) | |||
|
91 | ||||
|
92 | return self.run_command(self.pdflatex_command, filename, | |||
|
93 | self.iteration_count, log_error) | |||
|
94 | ||||
|
95 | def run_bibtex(self, filename): | |||
|
96 | """Run bibtex self.iteration_count times.""" | |||
|
97 | filename = filename.rstrip('.tex') | |||
|
98 | ||||
|
99 | def log_error(command, out): | |||
|
100 | self.log.warn('bibtex had problems, most likely because there were no citations') | |||
|
101 | self.log.debug(u"bibtex output: %s\n%s", command, out) | |||
|
102 | ||||
|
103 | return self.run_command(self.bibtex_command, filename, 1, log_error) | |||
|
104 | ||||
|
105 | def clean_temp_files(self, filename): | |||
|
106 | """Remove temporary files created by pdflatex/bibtext.""" | |||
|
107 | self.log.info("Removing temporary LaTeX files") | |||
|
108 | filename = filename.strip('.tex') | |||
|
109 | for ext in self.temp_file_exts: | |||
|
110 | try: | |||
|
111 | os.remove(filename+ext) | |||
|
112 | except OSError: | |||
|
113 | pass | |||
|
114 | ||||
|
115 | def postprocess(self, filename): | |||
|
116 | """Build a PDF by running pdflatex and bibtex""" | |||
|
117 | self.log.info("Building PDF") | |||
|
118 | cont = self.run_pdflatex(filename) | |||
|
119 | if cont: | |||
|
120 | cont = self.run_bibtex(filename) | |||
|
121 | else: | |||
|
122 | self.clean_temp_files(filename) | |||
|
123 | return | |||
|
124 | if cont: | |||
|
125 | cont = self.run_pdflatex(filename) | |||
|
126 | self.clean_temp_files(filename) | |||
|
127 | if os.path.isfile(filename.rstrip('.tex')+'.pdf'): | |||
|
128 | self.log.info('PDF successfully created') | |||
|
129 | return | |||
|
130 |
@@ -62,3 +62,7 b' class TestPDF(TestsBase):' | |||||
62 |
|
62 | |||
63 | # Check that the PDF was created. |
|
63 | # Check that the PDF was created. | |
64 | assert os.path.isfile('a.pdf') |
|
64 | assert os.path.isfile('a.pdf') | |
|
65 | ||||
|
66 | # Make sure that temp files are cleaned up | |||
|
67 | for ext in processor.temp_file_exts: | |||
|
68 | assert not os.path.isfile('a'+ext) |
General Comments 0
You need to be logged in to leave comments.
Login now