summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config/report/license-compliance/body.tex11
-rw-r--r--config/report/license-compliance/footer.tex2
-rw-r--r--config/report/license-compliance/generator1
-rw-r--r--config/report/license-compliance/header.tex52
l---------config/report/license-compliance/logo.png1
-rw-r--r--config/report/license-compliance/package.tex23
-rw-r--r--config/report/license-report/body.tex12
-rw-r--r--config/report/license-report/footer.tex37
-rw-r--r--config/report/license-report/generator1
-rw-r--r--config/report/license-report/header.tex57
l---------config/report/license-report/logo.png1
-rw-r--r--config/report/license-report/package.tex40
-rw-r--r--rules/post/ptxd_make_image_common.make3
-rw-r--r--rules/post/ptxd_make_world_report.make44
-rw-r--r--rules/project-name.in9
-rwxr-xr-xscripts/generate-report.py275
-rw-r--r--scripts/lib/ptxd_lib_dgen.awk6
-rw-r--r--scripts/lib/ptxd_make_world_report.sh29
18 files changed, 603 insertions, 1 deletions
diff --git a/config/report/license-compliance/body.tex b/config/report/license-compliance/body.tex
new file mode 100644
index 000000000..ce9eb4860
--- /dev/null
+++ b/config/report/license-compliance/body.tex
@@ -0,0 +1,11 @@
+{% from "package.tex" import package %}
+{{ raise("Invalid image name '" + target + "'!") if not target in images }}
+{{ raise("Image '" + target + "' has no packages!") if not images.get(target).pkgs }}
+{% if target %}
+{% set pkgs = images.get(target).pkgs|sort %}
+{% else %}
+{% set pkgs = packages.keys()|sort %}
+{% endif %}
+{%- for pkg in pkgs if not packages.get(pkg).licenses in ('ignore', 'proprietary') +%}
+{{- package(packages.get(pkg)) }}
+{%- endfor %}
diff --git a/config/report/license-compliance/footer.tex b/config/report/license-compliance/footer.tex
new file mode 100644
index 000000000..d4bf52671
--- /dev/null
+++ b/config/report/license-compliance/footer.tex
@@ -0,0 +1,2 @@
+\end{document}
+
diff --git a/config/report/license-compliance/generator b/config/report/license-compliance/generator
new file mode 100644
index 000000000..dba411b45
--- /dev/null
+++ b/config/report/license-compliance/generator
@@ -0,0 +1 @@
+latex
diff --git a/config/report/license-compliance/header.tex b/config/report/license-compliance/header.tex
new file mode 100644
index 000000000..cac7c0dd6
--- /dev/null
+++ b/config/report/license-compliance/header.tex
@@ -0,0 +1,52 @@
+\documentclass[pointlessnumbers,bibtotocnumbered,openany,DIV14,paper=a4,twoside=false,listof=totoc]{scrbook}
+
+\usepackage{graphicx}
+\usepackage[xetex]{hyperref}
+\usepackage{scrtime}
+\usepackage{tikz}
+\usepackage{adjustbox}
+\usepackage{spverbatim}
+\usepackage{pdfpages}
+\usepackage{tocloft}
+\hypersetup{colorlinks=true,linkcolor=blue,urlcolor=blue}
+
+%% Something like this may be needed depending on the package list
+%\usepackage[CJK]{ucharclasses}
+%\usepackage{fontspec}
+%\newfontfamily\mycjk{VL-Gothic-Regular}
+%\setTransitionsForCJK{\mycjk}{}
+
+\begin{document}
+
+\thispagestyle{empty}
+\begin{titlepage}
+\null
+\vfill
+\begin{center}
+
+\includegraphics[width=4cm]{ {{- find_file("logo.png") }} }
+\vskip 1cm
+{\Huge \textbf{Open Source Software Licenses}}
+{\huge \vfill for project \vfill {{ bsp.vendor }}-{{ bsp.project }}{{ bsp.get('project-version') }}}
+{\LARGE \vfill created \today, \thistime}
+
+\vskip 5cm
+
+{\huge !Attention!}
+\end{center}
+\vskip 0.5cm
+
+This list of licenses is automatically generated and asserts no claims to
+completeness or correctness. It is not legally binding, and comes without
+warranty of any kind. We advise a manual counter-check before
+publication or legal use.
+\vfill
+\vfill
+\end{titlepage}
+
+\phantomsection
+\pdfbookmark[1]{Contents}{toc}
+\setlength{\cftchapnumwidth}{\widthof{\large\bfseries{}888}}
+\tableofcontents
+
+
diff --git a/config/report/license-compliance/logo.png b/config/report/license-compliance/logo.png
new file mode 120000
index 000000000..a7e99e642
--- /dev/null
+++ b/config/report/license-compliance/logo.png
@@ -0,0 +1 @@
+../../../doc/_static/logo.png \ No newline at end of file
diff --git a/config/report/license-compliance/package.tex b/config/report/license-compliance/package.tex
new file mode 100644
index 000000000..691a6db6a
--- /dev/null
+++ b/config/report/license-compliance/package.tex
@@ -0,0 +1,23 @@
+{% macro package(pkg) %}
+\chapter{ {{- build_chapter(pkg) }} \label{ {{- pkg.name }}}}
+
+\begin{description}
+\item[Package:] {{ escape(pkg.name) }} {{ escape(pkg.get('version', '')) }}
+\item[License:] {{ escape(pkg.licenses) }}
+\end{description}
+
+{%- if pkg.get('license-files') %}
+{%- for name, license in pkg.get('license-files').items() %}
+\section{ {{- escape(name)}}}
+{%- if name.endswith('.pdf') %}
+\includepdf[pages=-]{ {{- license.file}}}
+{% else %}
+\begin{small}
+\begin{spverbatim}
+{{ source_file(license.file) }}
+\end{spverbatim}
+\end{small}
+{% endif %}
+{%- endfor %}
+{% endif %}
+{% endmacro %}
diff --git a/config/report/license-report/body.tex b/config/report/license-report/body.tex
new file mode 100644
index 000000000..7b03f7cfa
--- /dev/null
+++ b/config/report/license-report/body.tex
@@ -0,0 +1,12 @@
+{% from "package.tex" import package %}
+{{ raise("Invalid image name '" + target + "'!") if not target in images }}
+{{ raise("Image '" + target + "' has no packages!") if not images.get(target).pkgs }}
+{% if target %}
+{% set pkgs = images.get(target).pkgs|sort %}
+{% else %}
+{% set pkgs = packages.keys()|sort %}
+{% endif %}
+{{ init_dot(packages, pkgs) }}
+{%- for pkg in pkgs if not packages.get(pkg).licenses in ('ignore') +%}
+{{- package(packages.get(pkg)) }}
+{%- endfor %}
diff --git a/config/report/license-report/footer.tex b/config/report/license-report/footer.tex
new file mode 100644
index 000000000..106911b42
--- /dev/null
+++ b/config/report/license-report/footer.tex
@@ -0,0 +1,37 @@
+\appendix
+\chapter{Flags\label{Flags}}
+Note: This list of tags and the packages marked with them is meant
+as a starting point for further work. It is by no means complete.
+There are most likely packages that e.g. require attribution but
+are missing the corresponding flag.
+
+For individual packages, adding the flag name to
+\textless{}PKG\textgreater\_LICENSE
+sets the corresponding flag. To add flags to groups of packages,
+e.g. based on the package license,
+\emph{ptxd\_make\_world\_license\_expand()} can be overwritten and
+expanded.
+\section{nosource\label{nosource}}
+For packages marked with the {\it nosource} flag, the source
+archive(s) will not be part of the license compliance package.
+\section{nopatches\label{nopatches}}
+For packages marked with the {\it nopatches} flag, the patches
+for this package will not be part of the license compliance
+package.
+\section{attribution\label{attribution}}
+Packages marked with the {\it attribution} flag require some sort
+of attribution. Please refer to the package license for further
+details.
+\section{choice\label{choice}}
+Packages marked with the {\it choice} flag require the licensee to
+make some kind of license choice. Please refer to the package
+license for further details.
+
+\printindex[attribution]
+\printindex[choice]
+\printindex[nosource]
+\printindex[nopatches]
+
+\listoffigures
+
+\end{document}
diff --git a/config/report/license-report/generator b/config/report/license-report/generator
new file mode 100644
index 000000000..dba411b45
--- /dev/null
+++ b/config/report/license-report/generator
@@ -0,0 +1 @@
+latex
diff --git a/config/report/license-report/header.tex b/config/report/license-report/header.tex
new file mode 100644
index 000000000..8b271cbe4
--- /dev/null
+++ b/config/report/license-report/header.tex
@@ -0,0 +1,57 @@
+\documentclass[pointlessnumbers,bibtotocnumbered,openany,DIV14,paper=a4,twoside=false,listof=totoc]{scrbook}
+
+\usepackage{graphicx}
+\usepackage{imakeidx}
+\usepackage[xetex]{hyperref}
+\usepackage{scrtime}
+\usepackage{tikz}
+\usepackage{adjustbox}
+\usepackage{spverbatim}
+\usepackage{pdfpages}
+\usepackage{tocloft}
+\usepackage{placeins}
+\hypersetup{colorlinks=true,linkcolor=blue,urlcolor=blue}
+
+%% Something like this may be needed depending on the package list
+%\usepackage[CJK]{ucharclasses}
+%\usepackage{fontspec}
+%\newfontfamily\mycjk{VL-Gothic-Regular}
+%\setTransitionsForCJK{\mycjk}{}
+
+\makeindex[name=attribution,intoc,title=attribution Package Index]
+\makeindex[name=choice,intoc,title=choice Package Index]
+\makeindex[name=nosource,intoc,title=nosource Package Index]
+\makeindex[name=nopatches,intoc,title=nopatches Package Index]
+
+\begin{document}
+
+\thispagestyle{empty}
+\begin{titlepage}
+\null
+\vfill
+\begin{center}
+
+\includegraphics[width=4cm]{ {{- find_file("logo.png") }} }
+\vskip 1cm
+{\Huge \textbf{License Report}}
+{\huge \vfill for project \vfill {{ bsp.vendor }}-{{ bsp.project }}{{ bsp.get('project-version') }}}
+{\LARGE \vfill created \today, \thistime}
+
+\vskip 5cm
+
+{\huge !Attention!}
+\end{center}
+\vskip 0.5cm
+
+This list of licenses is automatically generated and asserts no claims to
+completeness or correctness. It is not legally binding, and comes without
+warranty of any kind. We advise a manual counter-check before
+publication or legal use.
+\vfill
+\vfill
+\end{titlepage}
+
+\phantomsection
+\pdfbookmark[1]{Contents}{toc}
+\setlength{\cftchapnumwidth}{\widthof{\large\bfseries{}888}}
+\tableofcontents
diff --git a/config/report/license-report/logo.png b/config/report/license-report/logo.png
new file mode 120000
index 000000000..a7e99e642
--- /dev/null
+++ b/config/report/license-report/logo.png
@@ -0,0 +1 @@
+../../../doc/_static/logo.png \ No newline at end of file
diff --git a/config/report/license-report/package.tex b/config/report/license-report/package.tex
new file mode 100644
index 000000000..3f2f94e8a
--- /dev/null
+++ b/config/report/license-report/package.tex
@@ -0,0 +1,40 @@
+{% macro package(pkg) %}
+\chapter{ {{- build_chapter(pkg) }} \label{ {{- pkg.name }}}}
+
+\begin{description}
+\item[Package:] {{ escape(pkg.name) }} {{ escape(pkg.get('version', '')) }}
+\item[License:] {{ escape(pkg.licenses) }}
+{% for flag in pkg.get('license-flags') or [] %}
+\index[{{ flag }}]{ {{- pkg.name }}}
+{%- endfor %}
+\item[Flags:]{% for flag in pkg.get('license-flags') or [] %} \nameref{ {{- escape(flag) }}}{% endfor %}
+\item[URL:]\begin{flushleft}{% for url in pkg.url %}{{ escape(url)}}\\ {% endfor %}\end{flushleft}
+\item[MD5:] {\ttfamily {{ escape(pkg.get('md5', ''))}}}
+\end{description}
+{% if dot(pkg.name) %}
+\begin{figure}[!ht]
+\centering
+\hspace*{-0.5in}\maxsizebox{0.9\paperwidth}{!}{
+{{ dot(pkg.name) }}
+}
+\caption{Dependency tree for {{ escape(pkg.name)}}}
+\label{ {{- pkg.name }}-deps}
+\end{figure}
+\FloatBarrier
+{% endif %}
+
+{%- if pkg.get('license-files') %}
+{%- for name, license in pkg.get('license-files').items() %}
+\section{ {{- escape(name) }}{% if license.guessed %} [automatically found]{% endif %}}
+{%- if name.endswith('.pdf') %}
+\includepdf[pages=-]{ {{- license.file}}}
+{% else %}
+\begin{small}
+\begin{spverbatim}
+{{ source_file(license.file) }}
+\end{spverbatim}
+\end{small}
+{% endif %}
+{%- endfor %}
+{% endif %}
+{% endmacro %}
diff --git a/rules/post/ptxd_make_image_common.make b/rules/post/ptxd_make_image_common.make
index 3ad573700..aefff54e9 100644
--- a/rules/post/ptxd_make_image_common.make
+++ b/rules/post/ptxd_make_image_common.make
@@ -19,7 +19,8 @@ world/image/env/impl = \
image_pkgs="$(call ptx/escape,$($(1)_PKGS))" \
image_files="$(call ptx/escape,$($(1)_FILES))" \
image_image="$(call ptx/escape,$($(1)_IMAGE))" \
- image_label="$(call ptx/escape,$($(1)_LABEL))"
+ image_label="$(call ptx/escape,$($(1)_LABEL))" \
+ image_reports="$(call ptx/escape,$($(1)_REPORTS))"
world/image/env = \
$(call world/image/env/impl,$(strip $(1)))
diff --git a/rules/post/ptxd_make_world_report.make b/rules/post/ptxd_make_world_report.make
new file mode 100644
index 000000000..b939a22c5
--- /dev/null
+++ b/rules/post/ptxd_make_world_report.make
@@ -0,0 +1,44 @@
+# -*-makefile-*-
+#
+# Copyright (C) 2023 by Michael Olbrich <m.olbrich@pengutronix.de>
+#
+# For further information about the PTXdist project and license conditions
+# see the README file.
+#
+
+#
+# image/reports
+#
+image/reports = \
+ $(call world/image/env,$(1)) \
+ ptxd_make_image_reports
+
+$(STATEDIR)/image-%.reports: $(RELEASEDIR)/full-bsp-report.yaml
+ @$(call targetinfo)
+ @$(call image/reports, $(PTX_MAP_TO_PACKAGE_image-$(*)))
+ @$(call touch)
+
+define _generate_report_impl
+$(strip $(if $($(1)_PKGS),$(if $(filter NO,$($(1)_REPORTS)),,y)))
+endef
+
+define _generate_report
+$(strip $(call _generate_report_impl,$(PTX_MAP_TO_PACKAGE_$(strip $(1)))))
+endef
+
+PTX_IMAGES_REPORT += $(strip $(foreach image,$(IMAGE_PACKAGES),$(if $(call _generate_report,$(image)),$(image))))
+
+$(if $(PTXDIST_OVERRIDE_REPORTS), \
+$(foreach image,$(PTX_IMAGES_REPORT), \
+$(eval $(PTX_MAP_TO_PACKAGE_$(image))_REPORTS := $(PTXDIST_OVERRIDE_REPORTS)) \
+))
+
+PTXDIST_DEFAULT_REPORTS ?= license-compliance
+
+$(foreach image,$(PTX_IMAGES_REPORT), \
+$(eval $(PTX_MAP_TO_PACKAGE_$(image))_REPORTS ?= $(PTXDIST_DEFAULT_REPORTS)) \
+)
+
+image-reports: $(addprefix $(STATEDIR)/,$(addsuffix .reports,$(PTX_IMAGES_REPORT)))
+
+# vim: syntax=make
diff --git a/rules/project-name.in b/rules/project-name.in
index 6566c3257..977bb9779 100644
--- a/rules/project-name.in
+++ b/rules/project-name.in
@@ -81,6 +81,15 @@ config PROJECT_CHECK_LICENSES
process. As a result all specified md5 sums for license files are
verified.
+config PROJECT_GENERATE_REPORTS
+ bool
+ prompt "generate reports with all relevant images"
+ help
+ If this es enabled <image>.reports is build before the
+ coresponding image. This is only relevant for images that are
+ build from packages since the document covers all packages that
+ are part of the image.
+
comment "------------------------------------"
comment "reproducible builds"
comment "------------------------------------"
diff --git a/scripts/generate-report.py b/scripts/generate-report.py
new file mode 100755
index 000000000..1fe19cd9d
--- /dev/null
+++ b/scripts/generate-report.py
@@ -0,0 +1,275 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 by Michael Olbrich <m.olbrich@pengutronix.de>
+#
+# For further information about the PTXdist project and license conditions
+# see the README file.
+#
+
+
+from os import path, environ, makedirs
+from chardet.universaldetector import UniversalDetector
+from multiprocessing import Pool
+from dot2tex import dot2tex
+import argparse
+import jinja2
+import yaml
+import subprocess
+import hashlib
+
+
+class ReportException(BaseException):
+ pass
+
+def find_file(search_path, name):
+ for file in [path.join(d, name) for d in search_path]:
+ if path.exists(file):
+ return file
+ return None
+
+
+class Generator:
+ def __init__(self, args):
+ self.input_suffix = '.txt'
+ self.output_suffix = '.txt'
+ self.__template = args.template
+ self.__data = args.input
+ self.__output = args.output
+ self.__env = args.env or []
+ self.verbose = args.verbose
+ self.detector = UniversalDetector()
+ self.path = args.path
+
+ def create_loader(self):
+ return jinja2.ChoiceLoader([jinja2.FileSystemLoader(d) for d in self.path])
+
+ def escape(self, text):
+ return text
+
+ def raise_exception(self, message):
+ raise ReportException(message)
+
+ def build_chapter(self, pkg):
+ chapter = self.escape(pkg.get('name'))
+ chapter = chapter.removeprefix('host-').removeprefix('cross-')
+ if pkg.get('licenses', '').find('proprietary') >= 0:
+ chapter += ' *** Proprietary License!'
+ if pkg.get('licenses', '').find('unknown') >= 0:
+ chapter += ' *** Unknown License!'
+ return chapter
+
+ def source_file(self, name):
+ raw = True
+ if path.exists(name + '.utf-8'):
+ name = name + '.utf-8'
+ raw = False
+ if self.verbose:
+ print(f'Reading "{name}" ...')
+ if raw:
+ raw_data = open(name, 'rb').read()
+ try:
+ data = raw_data.decode('UTF-8')
+ except UnicodeDecodeError:
+ self.detector.reset()
+ self.detector.feed(raw_data)
+ self.detector.close()
+ encoding = self.detector.result['encoding']
+ if self.verbose:
+ print(f'Assuming encoding {encoding}.')
+ data = raw_data.decode(encoding)
+ else:
+ data = open(name, encoding='utf-8').read()
+ return data.replace('\f', '\n')
+
+ def create_dot_recurse(self, pkgs, pkg, level, hit_deps):
+ if level > 3:
+ return ''
+
+ display_name = self.escape(
+ pkg['name'].removeprefix('host-').removeprefix('cross-'))
+ licenses = self.escape(pkg['licenses']).split()
+ licenses = ' '.join(i + '\\\\' * (w % 3 == 2)
+ for w, i in enumerate(licenses))
+
+ data = """"%s" [ shape=box style="rounded corners" fixedsize=false texlbl="\\small\\begin{tabular}{c}{\\Large\\hyperref[%s]{%s}}\\\\%s\\end{tabular}" ];
+""" % (pkg['name'], pkg['name'], self.escape(pkg['name']), licenses)
+
+ if not 'builddeps' in pkg:
+ return data
+
+ for dep in pkg['builddeps']:
+ if f'{pkg["name"]} {dep}' in hit_deps:
+ continue
+ if not dep in pkgs:
+ continue
+ hit_deps.add(f'{pkg["name"]} {dep}')
+ data += """"%s" -> "%s"[dir=back];
+""" % (pkg['name'], dep)
+ data += self.create_dot_recurse(pkgs,
+ pkgs[dep], level + 1, hit_deps)
+ return data
+
+ def create_dot(self, pkgs, pkg):
+ dot = """
+digraph "%s" {
+rankdir=LR;
+ratio=compress;
+nodesep=0.1;
+ranksep=0.1;
+node [ shape=point fixedsize=true width=0.1 ];
+""" % pkg['name']
+ dot += self.create_dot_recurse(pkgs, pkg, 0, set())
+ dot += """}
+"""
+ return dot
+
+ def load(self, data):
+ return yaml.load(open(data).read(), Loader=yaml.SafeLoader)
+
+ def setup_env(self, loader):
+ env = jinja2.Environment(
+ loader=loader, autoescape=jinja2.select_autoescape())
+
+ def _find_file(name):
+ return find_file(self.path, name)
+
+ env.globals['find_file'] = _find_file
+ env.globals['source_file'] = self.source_file
+ env.globals['escape'] = self.escape
+ env.globals['raise'] = self.raise_exception
+ env.globals['build_chapter'] = self.build_chapter
+ for tmp in self.__env:
+ tmp = tmp.split('=', 2)
+ env.globals[tmp[0]] = tmp[1]
+ return env
+
+ def build(self, data, loader):
+ env = self.setup_env(loader)
+ header = env.get_template("header" + self.input_suffix)
+ body = env.get_template("body" + self.input_suffix)
+ footer = env.get_template("footer" + self.input_suffix)
+ return header.render(**data) + body.render(**data) + footer.render(**data)
+
+ def finalize(self, document, output):
+ makedirs(path.dirname(output), exist_ok=True)
+ with open(output, mode='w') as f:
+ f.write(document)
+ return output
+
+ def run(self):
+ data = self.load(self.__data)
+ try:
+ document = self.build(data, self.create_loader())
+ except jinja2.exceptions.TemplateNotFound:
+ raise ReportException(f'Invalid template "{self.__template}"!')
+ if self.__output:
+ output = self.__output
+ if not output.endswith(self.output_suffix):
+ output += self.output_suffix
+ else:
+ output = self.__template + self.output_suffix
+ return self.finalize(document, output)
+
+
+class LatexGenerator(Generator):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.input_suffix = '.tex'
+ self.output_suffix = '.pdf'
+
+ def escape(self, text):
+ return text.replace('_', '\\_').replace('&', '\\&')
+
+ def dot(self, pkg):
+ return self.__dot.get(pkg, None)
+
+ def format_dot(self, args):
+ dot = self.create_dot(args[0], args[1])
+ return (args[1]['name'], dot2tex(dot, docpreamble='\\usepackage[xetex]{hyperref}', figonly=True,
+ format='pgf', autosize=True))
+
+ def init_dot(self, pkgs, limit):
+ from dot2tex import dot2tex
+
+ if limit:
+ packages = {pkg: pkgs[pkg] for pkg in limit}
+ else:
+ packages = pkgs
+
+ with Pool() as pool:
+ dots = pool.map(self.format_dot, [
+ (packages, pkg) for pkg in packages.values()])
+ self.__dot = {}
+ for pkg, dot in dots:
+ self.__dot[pkg] = dot
+
+ def setup_env(self, loader):
+ env = super().setup_env(loader)
+ env.globals['init_dot'] = self.init_dot
+ env.globals['dot'] = self.dot
+ return env
+
+ def finalize(self, document, output):
+ base = output.removesuffix(self.output_suffix)
+ tmp = super().finalize(document, base + self.input_suffix)
+ env = environ.copy()
+ env['max_print_line'] = '1000'
+ output_directory = path.dirname(tmp) or '.'
+ aux_hash = None
+ print(f'generating {output}...')
+ while True:
+ ret = subprocess.run(['xelatex', '-halt-on-error', path.basename(tmp)], env=env,
+ capture_output=not self.verbose, text=True, cwd=path.realpath(output_directory))
+ if ret.returncode != 0:
+ if not self.verbose:
+ print(ret.stdout + ret.stderr)
+ raise ReportException('Failed to execute xelatex')
+
+ new_aux_hash = hashlib.sha256(
+ open(base + '.aux', 'rb').read()).hexdigest()
+ if aux_hash == new_aux_hash:
+ break
+ aux_hash = new_aux_hash
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('-t', '--template', help='Template to use')
+ parser.add_argument(
+ '-p', '--path', help='Colon separated search path that contain the templates')
+ parser.add_argument('-o', '--output', help='Output file name')
+ parser.add_argument('-i', '--input', help='Input file name')
+ parser.add_argument(
+ '-e', '--env', help='Extra variables for the jinja2 env', action='append')
+ parser.add_argument('-g', '--generator',
+ help='Generator to use (plain, latex)')
+ parser.add_argument('-v', '--verbose', action='store_true')
+
+ args = parser.parse_args()
+
+ args.path = [path.abspath(path.join(d, args.template))
+ for d in args.path.split(':')] if args.path else ['']
+
+ if not args.generator:
+ file = find_file(args.path, 'generator')
+ if file:
+ args.generator = open(file).read().strip()
+ else:
+ args.generator = 'latex'
+
+ if args.generator == 'plain':
+ generator = Generator(args)
+ elif args.generator == 'latex':
+ generator = LatexGenerator(args)
+ else:
+ raise ReportException(f'Invalid generator type: "{args.generator}"')
+
+ generator.run()
+
+
+if __name__ == "__main__":
+ try:
+ main()
+ except ReportException as e:
+ print(f'Report Generation failed: {e.args[0]}')
+ exit(1)
diff --git a/scripts/lib/ptxd_lib_dgen.awk b/scripts/lib/ptxd_lib_dgen.awk
index f1ad577e7..a172ebfe9 100644
--- a/scripts/lib/ptxd_lib_dgen.awk
+++ b/scripts/lib/ptxd_lib_dgen.awk
@@ -26,6 +26,7 @@ BEGIN {
DEP = DIRTY == "true" ? "|" : ""
PTXDIST_HASHLIST = PTXDIST_TEMPDIR "/pkghash.list"
CHECK_LICENSES = 0
+ GENERATE_REPORTS = 0
}
#
@@ -253,6 +254,9 @@ $1 ~ /^PTXCONF_/ {
if (this_PKG == "PROJECT_CHECK_LICENSES")
CHECK_LICENSES = 1;
+ if (this_PKG == "PROJECT_GENERATE_REPORTS")
+ GENERATE_REPORTS = 1;
+
do {
if (this_PKG in PKG_to_pkg || this_PKG in virtual_pkg) {
PKG_HASHFILE = PTXDIST_TEMPDIR "/pkghash-" this_PKG;
@@ -650,6 +654,8 @@ function write_deps_pkg_active_image(this_PKG, this_pkg, prefix) {
print "$(" this_PKG "_IMAGE): " \
"$(STATEDIR)/" this_pkg ".$(" this_PKG "_CFGHASH).cfghash" > DGEN_DEPS_POST;
print "$(" this_PKG "_IMAGE): " "$(" this_PKG "_FILES)" > DGEN_DEPS_POST;
+ if (GENERATE_REPORTS)
+ print "$(" this_PKG "_IMAGE): $(STATEDIR)/" this_pkg ".reports" > DGEN_DEPS_POST
print "$(STATEDIR)/" this_pkg ".install.post: " "$(" this_PKG "_IMAGE)" > DGEN_DEPS_POST;
print "images: " "$(" this_PKG "_IMAGE)" > DGEN_DEPS_POST;
#
diff --git a/scripts/lib/ptxd_make_world_report.sh b/scripts/lib/ptxd_make_world_report.sh
index dbdae5736..6f1f4d9f0 100644
--- a/scripts/lib/ptxd_make_world_report.sh
+++ b/scripts/lib/ptxd_make_world_report.sh
@@ -108,3 +108,32 @@ ptxd_make_world_fast_report() {
ptxd_make_world_report_yaml fast > "${ptx_report_dir}/fast/${pkg_label}.yaml"
}
export -f ptxd_make_world_fast_report
+
+ptxd_make_image_reports() {
+ local generate_report report
+ local -a verbose
+
+ ptxd_make_image_init || return
+
+ ptxd_in_path PTXDIST_PATH_SCRIPTS generate-report.py &&
+ generate_report="${ptxd_reply}" &&
+
+ if [ "${PTXDIST_VERBOSE}" = "1" ]; then
+ verbose=( --verbose )
+ fi
+
+ for report in ${image_reports}; do
+ ptxd_eval \
+ pkg_stamp= \
+ PYTHONUNBUFFERED=1 \
+ "${generate_report}" \
+ "${verbose[@]}" \
+ --path "${PTXDIST_PATH//://config/report:}" \
+ --template "${report}" \
+ --input "${ptx_release_dir}/full-bsp-report.yaml" \
+ --output "${ptx_release_dir}/${pkg_pkg}-${report}" \
+ --env target="${pkg_pkg}" || return
+ done
+ echo
+}
+export -f ptxd_make_image_reports