Fix: PDF - Add dpdk plots
[csit.git] / resources / tools / presentation / generator_report.py
1 # Copyright (c) 2017 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
5 #
6 #     http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
13
14 """Report generation.
15 """
16
17 import subprocess
18 import logging
19 import datetime
20
21 from os import makedirs, environ
22 from os.path import isdir
23 from shutil import copy, Error, make_archive
24
25 from utils import get_files
26 from errors import PresentationError
27
28
29 # .css file for the html format of the report
30 THEME_OVERRIDES = """/* override table width restrictions */
31 @media screen and (min-width: 767px) {
32     .wy-table-responsive table td, .wy-table-responsive table th {
33         white-space: normal !important;
34     }
35
36     .wy-table-responsive {
37         font-size: small;
38         margin-bottom: 24px;
39         max-width: 100%;
40         overflow: visible !important;
41     }
42 }
43 .rst-content blockquote {
44     margin-left: 0px;
45     line-height: 18px;
46     margin-bottom: 0px;
47 }
48 """
49
50 # Command to build the html format of the report
51 HTML_BUILDER = 'sphinx-build -v -c . -a ' \
52                '-b html -E ' \
53                '-t html ' \
54                '-D release={release} ' \
55                '-D version="{release} report - {date}" ' \
56                '{working_dir} ' \
57                '{build_dir}/'
58
59 # Command to build the pdf format of the report
60 PDF_BUILDER = 'sphinx-build -v -c . -a ' \
61               '-b latex -E ' \
62               '-t latex ' \
63               '-D release={release} ' \
64               '-D version="{release} report - {date}" ' \
65               '{working_dir} ' \
66               '{build_dir}'
67
68
69 def generate_report(release, spec):
70     """Generate all formats and versions of the report.
71
72     :param release: Release string of the product.
73     :param spec: Specification read from the specification file.
74     :type release: str
75     :type spec: Specification
76     """
77
78     logging.info("Generating the report ...")
79
80     report = {
81         "html": generate_html_report,
82         "pdf": generate_pdf_report
83     }
84
85     for report_format, versions in spec.output.items():
86         report[report_format](release, spec, versions)
87
88     archive_input_data(spec)
89     archive_report(spec)
90
91     logging.info("Done.")
92
93
94 def generate_html_report(release, spec, versions):
95     """Generate html format of the report.
96
97     :param release: Release string of the product.
98     :param spec: Specification read from the specification file.
99     :param versions: List of versions to generate.
100     :type release: str
101     :type spec: Specification
102     :type versions: list
103     """
104
105     logging.info("  Generating the html report, give me a few minutes, please "
106                  "...")
107
108     cmd = HTML_BUILDER.format(
109         release=release,
110         date=datetime.date.today().strftime('%d-%b-%Y'),
111         working_dir=spec.environment["paths"]["DIR[WORKING,SRC]"],
112         build_dir=spec.environment["paths"]["DIR[BUILD,HTML]"])
113     _execute_command(cmd)
114
115     with open(spec.environment["paths"]["DIR[CSS_PATCH_FILE]"], "w") as \
116             css_file:
117         css_file.write(THEME_OVERRIDES)
118
119     with open(spec.environment["paths"]["DIR[CSS_PATCH_FILE2]"], "w") as \
120             css_file:
121         css_file.write(THEME_OVERRIDES)
122
123     logging.info("  Done.")
124
125
126 def generate_pdf_report(release, spec, versions):
127     """Generate html format of the report.
128
129     :param release: Release string of the product.
130     :param spec: Specification read from the specification file.
131     :param versions: List of versions to generate. Not implemented yet.
132     :type release: str
133     :type spec: Specification
134     :type versions: list
135     """
136
137     logging.info("  Generating the pdf report, give me a few minutes, please "
138                  "...")
139
140     convert_plots = "xvfb-run -a wkhtmltopdf {html} {pdf}.pdf"
141
142     # Convert PyPLOT graphs in HTML format to PDF.
143     plots = get_files(spec.environment["paths"]["DIR[STATIC,VPP]"], "html")
144     plots.extend(get_files(spec.environment["paths"]["DIR[STATIC,DPDK]"],
145                            "html"))
146     for plot in plots:
147         file_name = "{0}".format(plot.rsplit(".", 1)[0])
148         cmd = convert_plots.format(html=plot, pdf=file_name)
149         _execute_command(cmd)
150
151     # Generate the LaTeX documentation
152     build_dir = spec.environment["paths"]["DIR[BUILD,LATEX]"]
153     cmd = PDF_BUILDER.format(
154         release=release,
155         date=datetime.date.today().strftime('%d-%b-%Y'),
156         working_dir=spec.environment["paths"]["DIR[WORKING,SRC]"],
157         build_dir=build_dir)
158     _execute_command(cmd)
159
160     # Build pdf documentation
161     archive_dir = spec.environment["paths"]["DIR[STATIC,ARCH]"]
162     cmds = [
163         'cd {build_dir} && '
164         'pdflatex -shell-escape -interaction nonstopmode csit.tex || true'.
165         format(build_dir=build_dir),
166         'cd {build_dir} && '
167         'pdflatex -interaction nonstopmode csit.tex || true'.
168         format(build_dir=build_dir),
169         'cd {build_dir} && '
170         'cp csit.pdf ../{archive_dir}/csit_{release}.pdf'.
171         format(build_dir=build_dir,
172                archive_dir=archive_dir,
173                release=release)
174     ]
175
176     for cmd in cmds:
177         _execute_command(cmd)
178
179     logging.info("  Done.")
180
181
182 def archive_report(spec):
183     """Archive the report.
184
185     :param spec: Specification read from the specification file.
186     :type spec: Specification
187     """
188
189     logging.info("  Archiving the report ...")
190
191     make_archive("csit.report",
192                  "gztar",
193                  base_dir=spec.environment["paths"]["DIR[BUILD,HTML]"])
194
195     logging.info("  Done.")
196
197
198 def archive_input_data(spec):
199     """Archive the report.
200
201     :param spec: Specification read from the specification file.
202     :type spec: Specification
203     :raises PresentationError: If it is not possible to archive the input data.
204     """
205
206     logging.info("    Archiving the input data files ...")
207
208     if spec.is_debug:
209         extension = spec.debug["input-format"]
210     else:
211         extension = spec.input["file-format"]
212     data_files = get_files(spec.environment["paths"]["DIR[WORKING,DATA]"],
213                            extension=extension)
214     dst = spec.environment["paths"]["DIR[STATIC,ARCH]"]
215     logging.info("      Destination: {0}".format(dst))
216
217     try:
218         if not isdir(dst):
219             makedirs(dst)
220
221         for data_file in data_files:
222             logging.info("      Copying the file: {0} ...".format(data_file))
223             copy(data_file, dst)
224
225     except (Error, OSError) as err:
226         raise PresentationError("Not possible to archive the input data.",
227                                 str(err))
228
229     logging.info("    Done.")
230
231
232 def _execute_command(cmd):
233     """Execute the command in a subprocess and log the stdout and stderr.
234
235     :param cmd: Command to execute.
236     :type cmd: str
237     :returns: Return code of the executed command.
238     :rtype: int
239     """
240
241     env = environ.copy()
242     proc = subprocess.Popen(
243         [cmd],
244         stdout=subprocess.PIPE,
245         stderr=subprocess.PIPE,
246         shell=True,
247         env=env)
248
249     stdout, stderr = proc.communicate()
250
251     logging.info(stdout)
252     logging.info(stderr)
253
254     if proc.returncode != 0:
255         logging.error("    Command execution failed.")
256     return proc.returncode