diff options
-rw-r--r-- | rules/post/ptxd_make_license_report.make | 48 | ||||
-rw-r--r-- | rules/post/ptxd_make_world_common.make | 3 | ||||
-rw-r--r-- | rules/post/ptxd_make_world_license.make | 12 | ||||
-rw-r--r-- | scripts/lib/ptxd_lib_dgen.awk | 1 | ||||
-rw-r--r-- | scripts/lib/ptxd_make_license_report.awk | 3 | ||||
-rw-r--r-- | scripts/lib/ptxd_make_license_report.sh | 199 | ||||
-rw-r--r-- | scripts/lib/ptxd_make_spdx.sh | 356 | ||||
-rw-r--r-- | scripts/lib/ptxd_make_world_common.sh | 5 | ||||
-rw-r--r-- | scripts/lib/ptxd_make_world_license.sh | 341 | ||||
-rw-r--r-- | scripts/ptxdist_vars.sh | 2 | ||||
-rwxr-xr-x | scripts/update_spdx.sh | 109 |
11 files changed, 1022 insertions, 57 deletions
diff --git a/rules/post/ptxd_make_license_report.make b/rules/post/ptxd_make_license_report.make index 8eac2ee06..9ec60f273 100644 --- a/rules/post/ptxd_make_license_report.make +++ b/rules/post/ptxd_make_license_report.make @@ -8,33 +8,55 @@ # see the README file. # +PTX_PACKAGES_TOOLS := \ + $(CROSS_PACKAGES) \ + $(HOST_PACKAGES) \ + $(LAZY_PACKAGES) + PHONY += license-report license-report: \ - $(STATEDIR)/license-report.pdf \ - $(STATEDIR)/license-report-tools.pdf + $(REPORTDIR)/license-report.pdf \ + $(REPORTDIR)/license-report-tools.pdf -$(STATEDIR)/license-report.pdf: $(addprefix $(STATEDIR)/,$(addsuffix .report,$(PTX_PACKAGES_INSTALL))) +$(REPORTDIR)/license-report.pdf: $(addprefix $(STATEDIR)/,$(addsuffix .report,$(PTX_PACKAGES_INSTALL))) @$(call targetinfo) + @mkdir -p $(REPORTDIR) @$(image/env) \ - ptx_report_dir="$(STATEDIR)/report" \ ptx_license_target="$@" \ - ptx_license_package_filter="target" \ ptxd_make_license_report $(sort $(PTX_PACKAGES_INSTALL)) @$(call finish) -PTX_PACKAGES_TOOLS := \ - $(CROSS_PACKAGES) \ - $(HOST_PACKAGES) \ - $(LAZY_PACKAGES) - -$(STATEDIR)/license-report-tools.pdf: $(addprefix $(STATEDIR)/,$(addsuffix .report,$(PTX_PACKAGES_TOOLS))) +$(REPORTDIR)/license-report-tools.pdf: $(addprefix $(STATEDIR)/,$(addsuffix .report,$(PTX_PACKAGES_TOOLS))) @$(call targetinfo) + @mkdir -p $(REPORTDIR) @$(image/env) \ - ptx_report_dir="$(STATEDIR)/report" \ ptx_license_target="$@" \ - ptx_license_package_filter="tools" \ ptxd_make_license_report $(sort $(PTX_PACKAGES_TOOLS)) @$(call finish) +PTXDIST_LICENSE_COMPLIANCE_OSS_ARCHIVE := $(RELEASEDIR)/OSS-$(call remove_quotes,$(PTXCONF_PROJECT_VENDOR)-$(PTXCONF_PROJECT)$(PTXCONF_PROJECT_VERSION)).tar.gz + +PHONY += license-compliance-distribution + +license-compliance-distribution: \ + $(RELEASEDIR)/license-compliance.pdf \ + $(PTXDIST_LICENSE_COMPLIANCE_OSS_ARCHIVE) + +$(PTXDIST_LICENSE_COMPLIANCE_OSS_ARCHIVE): $(addprefix $(STATEDIR)/,$(addsuffix .release,$(PTX_PACKAGES_INSTALL) $(PTX_PACKAGES_TOOLS))) + @$(call targetinfo) + @tar -C "$(RELEASEDIR)" \ + --exclude=license-compliance.pdf --exclude $(notdir $@) \ + --transform 's;^./;$(notdir $(basename $(basename $@)))/;' -cf "$@" . + @$(call finish) + + +$(RELEASEDIR)/license-compliance.pdf: $(addprefix $(STATEDIR)/,$(addsuffix .report,$(PTX_PACKAGES_INSTALL))) + @$(call targetinfo) + @mkdir -p $(RELEASEDIR) + @$(image/env) \ + ptx_license_target="$@" \ + ptxd_make_license_compliance $(sort $(PTX_PACKAGES_INSTALL)) + @$(call finish) + # vim: syntax=make diff --git a/rules/post/ptxd_make_world_common.make b/rules/post/ptxd_make_world_common.make index 14fce7eb6..dc882bf04 100644 --- a/rules/post/ptxd_make_world_common.make +++ b/rules/post/ptxd_make_world_common.make @@ -23,6 +23,8 @@ ptx/env = \ \ ptx_state_dir="$(call ptx/escape,$(STATEDIR))" \ ptx_image_dir="$(call ptx/escape,$(IMAGEDIR))" \ + ptx_report_dir="$(call ptx/escape,$(REPORTDIR))" \ + ptx_release_dir="$(call ptx/escape,$(RELEASEDIR))" \ ptx_lib_dir="$(call ptx/escape,$(PTXDIST_LIB_DIR))" \ ptx_pkg_dir="$(call ptx/escape,$(PKGDIR))" \ ptx_pkg_dev_dir="$(call ptx/escape,$(PTXDIST_DEVPKG_PLATFORMDIR))" \ @@ -71,6 +73,7 @@ world/env/impl = \ pkg_config="$(call ptx/escape,$($(1)_CONFIG))" \ pkg_path="$(call ptx/escape,$($(1)_PATH))" \ pkg_src="$(call ptx/escape,$($(1)_SOURCE))" \ + pkg_srcs="$(call ptx/escape,$($(1)_SOURCES))" \ pkg_md5="$(call ptx/escape,$($(1)_MD5))" \ pkg_url="$(call ptx/escape,$($(1)_URL))" \ \ diff --git a/rules/post/ptxd_make_world_license.make b/rules/post/ptxd_make_world_license.make index ba811de48..11d9fcc2d 100644 --- a/rules/post/ptxd_make_world_license.make +++ b/rules/post/ptxd_make_world_license.make @@ -20,4 +20,16 @@ $(STATEDIR)/%.report: @$(call world/license, $(PTX_MAP_TO_PACKAGE_$(*))) @$(call touch) +# create a "release" of all required information including licenses, sources and patches + +world/release = \ + $(call world/env, $(1)) \ + ptxd_make_world_release + +$(STATEDIR)/%.release: + @$(call targetinfo) + @$(call world/release, $(PTX_MAP_TO_PACKAGE_$(*))) + @$(call touch) + + # vim: syntax=make diff --git a/scripts/lib/ptxd_lib_dgen.awk b/scripts/lib/ptxd_lib_dgen.awk index 531dba11d..5c8280ba2 100644 --- a/scripts/lib/ptxd_lib_dgen.awk +++ b/scripts/lib/ptxd_lib_dgen.awk @@ -277,6 +277,7 @@ function write_deps_pkg_active(this_PKG, this_pkg, prefix) { print "$(STATEDIR)/" this_pkg ".targetinstall.post: " "$(STATEDIR)/" this_pkg ".targetinstall" > DGEN_DEPS_POST; } print "$(STATEDIR)/" this_pkg ".report: " "$(STATEDIR)/" this_pkg ".extract" > DGEN_DEPS_POST; + print "$(STATEDIR)/" this_pkg ".release: " "$(STATEDIR)/" this_pkg ".extract" > DGEN_DEPS_POST; # # conditional dependencies diff --git a/scripts/lib/ptxd_make_license_report.awk b/scripts/lib/ptxd_make_license_report.awk index a8d3476c6..a1320abe7 100644 --- a/scripts/lib/ptxd_make_license_report.awk +++ b/scripts/lib/ptxd_make_license_report.awk @@ -29,6 +29,7 @@ $1 == "LICENSE" { gsub("^host-", "", $3); gsub("^cross-", "", $3); names[$2] = $3 + license_type[$2] = $5 } function make_more_dot(pkg, file, level, deps, i) { @@ -52,7 +53,7 @@ function make_more_dot(pkg, file, level, deps, i) { } function make_dot(pkg) { - file = report_dir"/"raw_names[pkg]"/graph.dot" + file = report_dir"/"license_type[pkg]"/"raw_names[pkg]"/graph.dot" delete hit_deps printf "digraph \"%s\" {\n", pkg > file printf "rankdir=LR;\n" > file diff --git a/scripts/lib/ptxd_make_license_report.sh b/scripts/lib/ptxd_make_license_report.sh index ad90c99b9..d2083df91 100644 --- a/scripts/lib/ptxd_make_license_report.sh +++ b/scripts/lib/ptxd_make_license_report.sh @@ -9,21 +9,33 @@ # ptxd_make_license_report_header() { - local project_desc="$(ptxd_get_ptxconf PTXCONF_PROJECT_VENDOR) $(ptxd_get_ptxconf PTXCONF_PROJECT) $(ptxd_get_ptxconf PTXCONF_PROJECT_VERSION)" + local project_desc="$(ptxd_get_ptxconf PTXCONF_PROJECT_VENDOR)-$(ptxd_get_ptxconf PTXCONF_PROJECT)$(ptxd_get_ptxconf PTXCONF_PROJECT_VERSION)" cat <<- EOF - \documentclass[pointlessnumbers,bibtotocnumbered,openany,DIV14,paper=a4,twoside=false]{scrbook} + \documentclass[pointlessnumbers,bibtotocnumbered,openany,DIV14,paper=a4,twoside=false,listof=totoc]{scrbook} \usepackage{graphicx} - \usepackage{listings} + \usepackage{imakeidx} \usepackage[xetex]{hyperref} - \usepackage{tocbibind} \usepackage{scrtime} \usepackage{tikz} \usepackage{adjustbox} + \usepackage{spverbatim} \hypersetup{colorlinks=true,linkcolor=blue,urlcolor=blue} + \usepackage{tocstyle} + \usetocstyle{KOMAlike} + %% Something like this may be needed depending on the package list + %\usepackage[CJK]{ucharclasses} + %\usepackage{fontspec} + %\newfontfamily\mycjk{VL-Gothic-Regular} + %\setTransitionsForCJK{\mycjk}{} - \lstset{breaklines=true,basicstyle=\footnotesize\ttfamily} + \newif\iflicensereport + \licensereporttrue + + \makeindex[name=attribution,intoc,title=attribution Package Index] + \makeindex[name=nosource,intoc,title=nosource Package Index] + \makeindex[name=nopatches,intoc,title=nopatches Package Index] \begin{document} @@ -51,6 +63,8 @@ ptxd_make_license_report_header() { \vfill \end{titlepage} + \phantomsection + \pdfbookmark[1]{Contents}{toc} \tableofcontents EOF } @@ -58,6 +72,35 @@ export -f ptxd_make_license_report_header ptxd_make_license_report_footer() { cat <<- EOF + \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. + + \printindex[attribution] + \printindex[nosource] + \printindex[nopatches] + \listoffigures \end{document} @@ -80,41 +123,169 @@ ptxd_make_license_report_build() { } export -f ptxd_make_license_report_build +# $1 list of packages (short names) +# We are called twice here: once for the target packages, once for the host tools +# Note: the 'package.list' contains license info for both runs ptxd_make_license_report() { local -a ptxd_reply - local ptx_license_target_tex pkg + local ptx_license_target_tex pkg_lic pkg + local -A ptxd_package_license_association + + # regenerate license info and sort out unused packages + for pkg in $(cat "${ptx_report_dir}/package.list"); do + ptxd_package_license_association[$(basename ${pkg})]=$(dirname ${pkg}) + done + ptxd_in_path PTXDIST_PATH_SCRIPTS lib/ptxd_make_license_report.awk || return + + echo -n "Extracting package's license information and dependencies..." local make_license_report="${ptxd_reply}" ( for pkg in "${@}"; do - echo "LICENSE:$(ptxd_name_to_NAME ${pkg}):${pkg}:$(<"${ptx_report_dir}/${pkg}/license-name"):" + pkg_lic=${ptxd_package_license_association[${pkg}]} + if [ -z ${pkg_lic} ]; then + # sort out no used packages for this run + continue + fi + echo "LICENSE:$(ptxd_name_to_NAME ${pkg}):${pkg}:$(<"${ptx_report_dir}/${pkg_lic}/${pkg}/license-name"):${pkg_lic}:" done for config in ptx platform; do PTXDIST_DEP_TARGET="build" ptxd_kconfig dep ${config} || return done ) | gawk -f "${make_license_report}" && + echo "done" + echo -n "Generating license dependencies graphs..." { echo "SHELL = bash" echo "%.tex: %.dot" echo ' @echo " DOT2TEX `ptxd_print_path $<`"' echo ' @dot2tex --docpreamble="\usepackage[xetex]{hyperref}" --figonly -fpgf --autosize -o $@ $<' for pkg in "${@}"; do - echo "all: ${ptx_report_dir}/${pkg}/graph.tex" + pkg_lic="${ptxd_package_license_association[${pkg}]}" + if [ -z "${pkg_lic}" ]; then + continue + fi + echo "all: ${ptx_report_dir}/${pkg_lic}/${pkg}/graph.tex" done - } | make -f - ${PTXDIST_PARALLELMFLAGS_INTERN} all || return + } | make -f - ${PTXDIST_PARALLELMFLAGS_INTERN} all || return + echo "done" - ptx_license_target_tex="${ptx_report_dir}/$(basename "${ptx_license_target%.pdf}.tex")" +# +# combine all package related info into one document +# + ptx_license_target_tex="${ptx_report_dir}/${pkg_section}/$(basename "${ptx_license_target%.pdf}.tex")" ( ptxd_make_license_report_header - for file in "${@}"; do - echo "\\input{${file#${ptx_report_dir}/}/license-report.tex}" + for pkg in ${@}; do + pkg_lic="${ptxd_package_license_association[${pkg}]}" + if [ -z ${pkg_lic} ]; then + continue + fi + pkg_lic="${pkg_lic}/${pkg}" + echo "\\input{${pkg_lic#${ptx_report_dir}/${pkg_section}}/license-report.tex}" done ptxd_make_license_report_footer ) > "${ptx_license_target_tex}" - ptxd_make_license_report_build && - mv "${ptx_license_target_tex%.tex}.pdf" "${ptx_license_target}" + ptxd_make_license_report_build +# mv "${ptx_license_target_tex%.tex}.pdf" "${ptx_license_target}" } export -f ptxd_make_license_report +ptxd_make_license_compliance_header() { + local project_desc="$(ptxd_get_ptxconf PTXCONF_PROJECT_VENDOR)-$(ptxd_get_ptxconf PTXCONF_PROJECT)$(ptxd_get_ptxconf PTXCONF_PROJECT_VERSION)" + cat <<- EOF + \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} + \hypersetup{colorlinks=true,linkcolor=blue,urlcolor=blue} + \usepackage{tocstyle} + \usetocstyle{KOMAlike} + + %% Something like this may be needed depending on the package list + %\usepackage[CJK]{ucharclasses} + %\usepackage{fontspec} + %\newfontfamily\mycjk{VL-Gothic-Regular} + %\setTransitionsForCJK{\mycjk}{} + + \newif\iflicensereport + \licensereportfalse + + \begin{document} + + \thispagestyle{empty} + \begin{titlepage} + \null + \vfill + \begin{center} + + {\Huge \textbf{Open Source Software Licenses}} + {\huge \vfill for project \vfill ${project_desc}} + {\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} + \tableofcontents + EOF +} +export -f ptxd_make_license_compliance_header + +ptxd_make_license_compliance_footer() { + cat <<- EOF + \end{document} + EOF +} +export -f ptxd_make_license_compliance_footer + +ptxd_make_license_compliance() { + local -a ptxd_reply + local ptx_license_target_tex pkg_lic pkg + local -A ptxd_package_license_association + + # regenerate license info and sort out unused packages + for pkg in $(cat "${ptx_report_dir}/package.list"); do + ptxd_package_license_association[$(basename ${pkg})]=$(dirname ${pkg}) + done + +# +# combine all package related info into one document +# + ptx_license_target_tex="${ptx_report_dir}/${pkg_section}/$(basename "${ptx_license_target%.pdf}.tex")" + ( + ptxd_make_license_compliance_header + for pkg in ${@}; do + pkg_lic="${ptxd_package_license_association[${pkg}]}" + if [ -z "${pkg_lic}" -o "${pkg_lic}" = "proprietary" ]; then + continue + fi + pkg_lic="${pkg_lic}/${pkg}" + echo "\\input{${pkg_lic#${ptx_report_dir}/${pkg_section}}/license-report.tex}" + done + ptxd_make_license_compliance_footer + ) > "${ptx_license_target_tex}" + + ptxd_make_license_report_build && + cp "${ptx_license_target_tex%.tex}.pdf" "${ptx_license_target}" +} +export -f ptxd_make_license_compliance + diff --git a/scripts/lib/ptxd_make_spdx.sh b/scripts/lib/ptxd_make_spdx.sh new file mode 100644 index 000000000..301551050 --- /dev/null +++ b/scripts/lib/ptxd_make_spdx.sh @@ -0,0 +1,356 @@ +#!/bin/bash +# +# Copyright (C) 2015 by Michael Olbrich <m.olbrich@pengutronix.de> +# +# See CREDITS for details about who has contributed to this project. +# +# For further information about the PTXdist project and license conditions +# see the README file. +# + +# +# WARNING: This file is generated with 'update_spdx.sh' from +# 'spdx_licenselist_v2.2.csv' and 'spdx_licenselist_v2.2_exceptions.csv'. +# +# To regenerate this file export the license and exception sheets from the +# original SPDX license list using '|' as field delimiter and run +# 'update_spdx.sh'. + +ptxd_make_spdx() { + license="${1}" + + case "${license}" in + Glide) ;; + Abstyles) ;; + AFL-1.1) osi="true" ;; + AFL-1.2) osi="true" ;; + AFL-2.0) osi="true" ;; + AFL-2.1) osi="true" ;; + AFL-3.0) osi="true" ;; + AMPAS) ;; + APL-1.0) osi="true" ;; + Adobe-Glyph) ;; + APAFML) ;; + Adobe-2006) ;; + AGPL-1.0) ;; + Afmparse) ;; + Aladdin) ;; + ADSL) ;; + AMDPLPA) ;; + ANTLR-PD) ;; + Apache-1.0) ;; + Apache-1.1) osi="true" ;; + Apache-2.0) osi="true" ;; + AML) ;; + APSL-1.0) osi="true" ;; + APSL-1.1) osi="true" ;; + APSL-1.2) osi="true" ;; + APSL-2.0) osi="true" ;; + Artistic-1.0) osi="true" ;; + Artistic-1.0-Perl) osi="true" ;; + Artistic-1.0-cl8) osi="true" ;; + Artistic-2.0) osi="true" ;; + AAL) osi="true" ;; + Bahyph) ;; + Barr) ;; + Beerware) ;; + BitTorrent-1.0) ;; + BitTorrent-1.1) ;; + BSL-1.0) osi="true" ;; + Borceux) ;; + BSD-2-Clause) osi="true" ;; + BSD-2-Clause-FreeBSD) ;; + BSD-2-Clause-NetBSD) ;; + BSD-3-Clause) osi="true" ;; + BSD-3-Clause-Clear) ;; + BSD-4-Clause) ;; + BSD-Protection) ;; + BSD-3-Clause-Attribution) ;; + 0BSD) ;; + BSD-4-Clause-UC) ;; + bzip2-1.0.5) ;; + bzip2-1.0.6) ;; + Caldera) ;; + CECILL-1.0) ;; + CECILL-1.1) ;; + CECILL-2.0) ;; + CECILL-2.1) osi="true" ;; + CECILL-B) ;; + CECILL-C) ;; + ClArtistic) ;; + MIT-CMU) ;; + CNRI-Jython) ;; + CNRI-Python) osi="true" ;; + CNRI-Python-GPL-Compatible) ;; + CPOL-1.02) ;; + CDDL-1.0) osi="true" ;; + CDDL-1.1) ;; + CPAL-1.0) osi="true" ;; + CPL-1.0) osi="true" ;; + CATOSL-1.1) osi="true" ;; + Condor-1.1) ;; + CC-BY-1.0) ;; + CC-BY-2.0) ;; + CC-BY-2.5) ;; + CC-BY-3.0) ;; + CC-BY-4.0) ;; + CC-BY-ND-1.0) ;; + CC-BY-ND-2.0) ;; + CC-BY-ND-2.5) ;; + CC-BY-ND-3.0) ;; + CC-BY-ND-4.0) ;; + CC-BY-NC-1.0) ;; + CC-BY-NC-2.0) ;; + CC-BY-NC-2.5) ;; + CC-BY-NC-3.0) ;; + CC-BY-NC-4.0) ;; + CC-BY-NC-ND-1.0) ;; + CC-BY-NC-ND-2.0) ;; + CC-BY-NC-ND-2.5) ;; + CC-BY-NC-ND-3.0) ;; + CC-BY-NC-ND-4.0) ;; + CC-BY-NC-SA-1.0) ;; + CC-BY-NC-SA-2.0) ;; + CC-BY-NC-SA-2.5) ;; + CC-BY-NC-SA-3.0) ;; + CC-BY-NC-SA-4.0) ;; + CC-BY-SA-1.0) ;; + CC-BY-SA-2.0) ;; + CC-BY-SA-2.5) ;; + CC-BY-SA-3.0) ;; + CC-BY-SA-4.0) ;; + CC0-1.0) ;; + Crossword) ;; + CrystalStacker) ;; + CUA-OPL-1.0) osi="true" ;; + Cube) ;; + D-FSL-1.0) ;; + diffmark) ;; + WTFPL) ;; + DOC) ;; + Dotseqn) ;; + DSDP) ;; + dvipdfm) ;; + EPL-1.0) osi="true" ;; + ECL-1.0) osi="true" ;; + ECL-2.0) osi="true" ;; + eGenix) ;; + EFL-1.0) osi="true" ;; + EFL-2.0) osi="true" ;; + MIT-advertising) ;; + MIT-enna) ;; + Entessa) osi="true" ;; + ErlPL-1.1) ;; + EUDatagrid) osi="true" ;; + EUPL-1.0) ;; + EUPL-1.1) osi="true" ;; + Eurosym) ;; + Fair) osi="true" ;; + MIT-feh) ;; + Frameworx-1.0) osi="true" ;; + FreeImage) ;; + FTL) ;; + FSFUL) ;; + FSFULLR) ;; + Giftware) ;; + GL2PS) ;; + Glulxe) ;; + AGPL-3.0) osi="true" ;; + GFDL-1.1) ;; + GFDL-1.2) ;; + GFDL-1.3) ;; + GPL-1.0) ;; + GPL-2.0) osi="true" ;; + GPL-3.0) osi="true" ;; + LGPL-2.1) osi="true" ;; + LGPL-3.0) osi="true" ;; + LGPL-2.0) osi="true" ;; + gnuplot) ;; + gSOAP-1.3b) ;; + HaskellReport) ;; + HPND) osi="true" ;; + IBM-pibs) ;; + IPL-1.0) osi="true" ;; + ICU) ;; + ImageMagick) ;; + iMatix) ;; + Imlib2) ;; + IJG) ;; + Intel-ACPI) ;; + Intel) osi="true" ;; + Interbase-1.0) ;; + IPA) osi="true" ;; + ISC) osi="true" ;; + JasPer-2.0) ;; + JSON) ;; + LPPL-1.3a) ;; + LPPL-1.0) ;; + LPPL-1.1) ;; + LPPL-1.2) ;; + LPPL-1.3c) osi="true" ;; + Latex2e) ;; + BSD-3-Clause-LBNL) ;; + Leptonica) ;; + LGPLLR) ;; + Libpng) ;; + libtiff) ;; + LPL-1.02) osi="true" ;; + LPL-1.0) osi="true" ;; + MakeIndex) ;; + MTLL) ;; + MS-PL) osi="true" ;; + MS-RL) osi="true" ;; + MirOS) osi="true" ;; + MITNFA) ;; + MIT) osi="true" ;; + Motosoto) osi="true" ;; + MPL-1.0) osi="true" ;; + MPL-1.1) osi="true" ;; + MPL-2.0) osi="true" ;; + MPL-2.0-no-copyleft-exception) osi="true" ;; + mpich2) ;; + Multics) osi="true" ;; + Mup) ;; + NASA-1.3) osi="true" ;; + Naumen) osi="true" ;; + NBPL-1.0) ;; + NetCDF) ;; + NGPL) osi="true" ;; + NOSL) ;; + NPL-1.0) ;; + NPL-1.1) ;; + Newsletr) ;; + NLPL) ;; + Nokia) osi="true" ;; + NPOSL-3.0) osi="true" ;; + Noweb) ;; + NRL) ;; + NTP) osi="true" ;; + Nunit) ;; + OCLC-2.0) osi="true" ;; + ODbL-1.0) ;; + PDDL-1.0) ;; + OGTSL) osi="true" ;; + OLDAP-2.2.2) ;; + OLDAP-1.1) ;; + OLDAP-1.2) ;; + OLDAP-1.3) ;; + OLDAP-1.4) ;; + OLDAP-2.0) ;; + OLDAP-2.0.1) ;; + OLDAP-2.1) ;; + OLDAP-2.2) ;; + OLDAP-2.2.1) ;; + OLDAP-2.3) ;; + OLDAP-2.4) ;; + OLDAP-2.5) ;; + OLDAP-2.6) ;; + OLDAP-2.7) ;; + OLDAP-2.8) ;; + OML) ;; + OPL-1.0) ;; + OSL-1.0) osi="true" ;; + OSL-1.1) ;; + OSL-2.0) osi="true" ;; + OSL-2.1) osi="true" ;; + OSL-3.0) osi="true" ;; + OpenSSL) ;; + PHP-3.0) osi="true" ;; + PHP-3.01) ;; + Plexus) ;; + PostgreSQL) osi="true" ;; + psfrag) ;; + psutils) ;; + Python-2.0) osi="true" ;; + QPL-1.0) osi="true" ;; + Qhull) ;; + Rdisc) ;; + RPSL-1.0) osi="true" ;; + RPL-1.1) osi="true" ;; + RPL-1.5) osi="true" ;; + RHeCos-1.1) ;; + RSCPL) osi="true" ;; + RSA-MD) ;; + Ruby) ;; + SAX-PD) ;; + Saxpath) ;; + SCEA) ;; + SWL) ;; + Sendmail) ;; + SGI-B-1.0) ;; + SGI-B-1.1) ;; + SGI-B-2.0) ;; + OFL-1.0) ;; + OFL-1.1) osi="true" ;; + SimPL-2.0) osi="true" ;; + Sleepycat) osi="true" ;; + SNIA) ;; + Spencer-86) ;; + Spencer-94) ;; + Spencer-99) ;; + SMLNJ) ;; + SugarCRM-1.1.3) ;; + SISSL) osi="true" ;; + SISSL-1.2) ;; + SPL-1.0) osi="true" ;; + Watcom-1.0) osi="true" ;; + TCL) ;; + Unlicense) ;; + TMate) ;; + TORQUE-1.1) ;; + TOSL) ;; + Unicode-TOU) ;; + UPL-1.0) osi="true" ;; + NCSA) osi="true" ;; + Vim) ;; + VOSTROM) ;; + VSL-1.0) osi="true" ;; + W3C-19980720) ;; + W3C) osi="true" ;; + Wsuipa) ;; + Xnet) osi="true" ;; + X11) ;; + Xerox) ;; + XFree86-1.1) ;; + xinetd) ;; + xpp) ;; + XSkat) ;; + YPL-1.0) ;; + YPL-1.1) ;; + Zed) ;; + Zend-2.0) ;; + Zimbra-1.3) ;; + Zimbra-1.4) ;; + Zlib) osi="true" ;; + zlib-acknowledgement) ;; + ZPL-1.1) ;; + ZPL-2.0) osi="true" ;; + ZPL-2.1) ;; + 389-exception) exception="true" ;; + Autoconf-exception-2.0) exception="true" ;; + Autoconf-exception-3.0) exception="true" ;; + Bison-exception-2.2) exception="true" ;; + Classpath-exception-2.0) exception="true" ;; + CLISP-exception-2.0) exception="true" ;; + DigiRule-FOSS-exception) exception="true" ;; + eCos-exception-2.0) exception="true" ;; + Fawkes-Runtime-exception) exception="true" ;; + FLTK-exception) exception="true" ;; + Font-exception-2.0) exception="true" ;; + freertos-exception-2.0) exception="true" ;; + GCC-exception-2.0) exception="true" ;; + GCC-exception-3.1) exception="true" ;; + gnu-javamail-exception) exception="true" ;; + i2p-gpl-java-exception) exception="true" ;; + Libtool-exception) exception="true" ;; + LZMA-exception) exception="true" ;; + mif-exception) exception="true" ;; + Nokia-Qt-exception-1.1) exception="true" ;; + openvpn-openssl-exception) exception="true" ;; + Qwt-exception-1.0) exception="true" ;; + u-boot-exception-2.0) exception="true" ;; + WxWindows-exception-3.1) exception="true" ;; + *) return 1 ;; + esac +} +export -f ptxd_make_spdx diff --git a/scripts/lib/ptxd_make_world_common.sh b/scripts/lib/ptxd_make_world_common.sh index d32a166af..424502b97 100644 --- a/scripts/lib/ptxd_make_world_common.sh +++ b/scripts/lib/ptxd_make_world_common.sh @@ -240,11 +240,6 @@ ptxd_make_world_init() { pkg_fake_env="${ptx_state_dir}/${pkg_label}.fakeroot" # - # license dir - # - pkg_license_dir="${ptx_state_dir}/report/${pkg_label}" - - # # path # local path_ptr="ptx_path_${pkg_type}" diff --git a/scripts/lib/ptxd_make_world_license.sh b/scripts/lib/ptxd_make_world_license.sh index 5e590c204..a6743c134 100644 --- a/scripts/lib/ptxd_make_world_license.sh +++ b/scripts/lib/ptxd_make_world_license.sh @@ -27,9 +27,11 @@ ptxd_make_world_parse_license_files() { unset orig_ifs file="" + filename="" startline="1" endline="$" md5="" + encoding="" guess="" while [ ${#} -ne 0 ]; do @@ -40,6 +42,9 @@ ptxd_make_world_parse_license_files() { "file://"*) file="${arg##file://}" ;; + "encoding="*) + encoding="${arg##encoding=}" + ;; "beginline="*) startline="${arg##beginline=}" ;; @@ -61,7 +66,14 @@ ptxd_make_world_parse_license_files() { esac done - if [ ! -e "${pkg_dir}/${file}" ]; then + if [[ "${file}" == /* ]]; then + filename="$(basename "${file}")" + else + filename="${file}" + file="${pkg_dir}/${file}" + fi + + if [ ! -e "${file}" ]; then ptxd_bailout " license file '$(ptxd_print_path "${file}")' @@ -116,12 +128,22 @@ export -f ptxd_make_latex_escape ptxd_make_world_license_write() { local guess local pkg_chapter="$(ptxd_make_latex_escape ${pkg_label})" + local packages_url="${pkg_url}" + local packages_md5="${pkg_md5}" + local -a flags=( "${!pkg_license_flags[@]}" ) + local -a index=( "${!pkg_license_flags[@]}" ) + flags=( "${flags[@]/#/\\nameref\{}" ) + flags=( "${flags[@]/%/\}}" ) pkg_chapter="${pkg_chapter#host-}" pkg_chapter="${pkg_chapter#cross-}" + index=( "${index[@]/#/\\index[}" ) + index=( "${index[@]/%/]\{${pkg_chapter}\}}" ) case "${pkg_license}" in *proprietary*) pkg_chapter="${pkg_chapter} *** Proprietary License!" + packages_url="*not available*" + packages_md5="*not available*" ;; *unknown*) pkg_chapter="${pkg_chapter} *** Unknown License!" @@ -136,69 +158,276 @@ ptxd_make_world_license_write() { \chapter{${pkg_chapter}\label{${pkg_label}}} \begin{description} - \item[Package:] $(ptxd_make_latex_escape ${pkg_label}) $(ptxd_make_latex_escape ${pkg_version}) - \item[License:] $(ptxd_make_latex_escape ${pkg_license}) - \item[URL:] \begin{flushleft}$(ptxd_make_latex_escape ${pkg_url})\end{flushleft} - \item[MD5:] {\ttfamily ${pkg_md5}} + \item[Package:] $(ptxd_make_latex_escape "${pkg_label}") $(ptxd_make_latex_escape "${pkg_version}") + \item[License:] $(ptxd_make_latex_escape "${pkg_license}") + \iflicensereport + ${index[*]} + \item[Flags:] $(ptxd_make_latex_escape "${flags[*]}") + \item[URL:] \begin{flushleft}$(ptxd_make_latex_escape "${packages_url}")\end{flushleft} + \item[MD5:] {\ttfamily ${packages_md5}} + \fi \end{description} EOF if [ -n "${pkg_dot}" ]; then cat <<- EOF + \iflicensereport \begin{figure}[!ht] \centering \hspace*{-0.5in}\maxsizebox{0.9\paperwidth}{!}{ - \input{${pkg_tex}}} - \caption{Dependency tree for $(ptxd_make_latex_escape ${pkg_label})} + \input{${pkg_tex#${ptx_report_dir}/}}} + \caption{Dependency tree for $(ptxd_make_latex_escape "${pkg_label}")} \label{${pkg_label}-deps} \end{figure} + \fi EOF fi for license in "${pkg_license_texts[@]}" - "${pkg_license_texts_guessed[@]}"; do if [ "${license}" = "-" ]; then - guess=" [automatically found]" + guess="\iflicensereport [automatically found]\fi" continue fi title="$(basename "${license}")" cat <<- EOF - \section{$(ptxd_make_latex_escape ${title})${guess}} - \begin{lstlisting} + \section{$(ptxd_make_latex_escape "${title}")${guess}} + \begin{small} + \begin{spverbatim} EOF - cat "${license}" | sed -e 's/\f/\n/g' + if [ -f "${license}.utf-8" ]; then + cat "${license}.utf-8" + else + cat "${license}" + fi | sed -e 's/\f/\n/g' + check_pipe_status || return cat <<- EOF - \end{lstlisting} + \end{spverbatim} + \end{small} EOF done } export -f ptxd_make_world_license_write +# Copy all patches according to the series file +# $1 full path to the series file +# $2 source directory +# $3 destination directory +# +ptxd_make_world_copy_patch_files() { + local patch para junk + + echo -n "Copy patches for package: '${pkg_label}'..." + while read patch para junk; do + local cat + + case "${patch}" in + ""|"#"*) continue ;; # skip empty lines and comments + *) ;; + esac + + cp ${2}/${patch} ${3} && check_pipe_status || return + pushd "${3}" > /dev/null && + md5sum ${patch} >> MD5SUM 2>/dev/null && + popd > /dev/null && +# copy only the plain content without the metadata + echo "${patch}" >> "${3}/series" + done < "${1}" + pushd "${3}" > /dev/null && + md5sum series >> MD5SUM 2>/dev/null && + popd > /dev/null && + echo "done" + + return 0 +} +export -f ptxd_make_world_copy_patch_files + +# +# If the package was patched, ensure the patches are part of the release report +# $1 path to the extracted and patched sources [1] +# $2 base directory where to copy the patches to (without the trailing 'patches') +# +# [1] assumed here is the existance of the '.ptxdist' directory which contains +# the selected patch stack if any +ptxd_make_world_copy_patches() { + local patches_directory="" + local series_file="" + + if [ -d "${1}/.ptxdist" ]; then + if [ -d "${1}/.ptxdist/patches" ]; then + patches_directory=`readlink -n "${1}/.ptxdist/patches"` + series_file=`readlink -n "${1}/.ptxdist/series"` + if [ -d ${patches_directory} ]; then + mkdir -p "${2}/patches" && + ptxd_make_world_copy_patch_files "${series_file}" "${patches_directory}" "${2}/patches" || + ptxd_bailout " + +Failed to copy the required patches from '${patches_directory}' to '${2}/patches'. +" + fi + else + ptxd_bailout " + +Patched sources do not follow the PTXdist style. '${1}/.ptxdist/patches' not found. +" + fi + fi + + return 0 +} +export -f ptxd_make_world_copy_patches + +# +# Define a section the license type falls in +# $1 License string or list of license strings from the package's rule file +# +ptxd_create_section_from_license() +{ + local -A section + local orig_IFS="${IFS}" + IFS=$', ' + + for license in ${1}; do + local osi="false" + local exception="false" + # remove the 'or later' modifier + license="${license%+}" + if ptxd_make_spdx "${license}"; then + if [ "${osi}" == "true" ]; then + section[osi-conform]="true" + elif [ "${exception}" != "true" ]; then + section[misc]="true" + fi + continue; + fi + case "${license}" in + *proprietary*) + section[proprietary]="true" + ;; + *unknown*) + section[unknown]="true" + ;; + public_domain) + section[public_domain]="true" + ;; + ignore) # META packages + echo ignore + return 0 + ;; + *) + section[other]="true" + ;; + esac + done + + IFS="${orig_IFS}" + + if [ ${#section[@]} -eq 1 ]; then + echo "${!section[@]}" + return 0 + fi + if [ "${section[other]}" = "true" ]; then + echo "other" + else + echo "mixed" + fi + return 0 +} +export -f ptxd_create_section_from_license + +ptxd_make_world_license_add_flag() { + local flag="${1}" + + pkg_license_flags["${flag}"]="true" + shopt -s extglob + pkg_license="${pkg_license/*([, ])${flag}}" + shopt -u extglob +} +export -f ptxd_make_world_license_add_flag + +ptxd_make_world_license_flags() { + local orig_IFS="${IFS}" + IFS=$', ' + + for license in ${pkg_license}; do + case "${license}" in + *proprietary*) + ptxd_make_world_license_add_flag nosource + ptxd_make_world_license_add_flag nopatches + ;; + BSD-*-Clause*|MIT*|X11|Apache-*) + ptxd_make_world_license_add_flag attribution + ;; + nosource|nopatches|attribution) + ptxd_make_world_license_add_flag "${license}" + ;; + esac + done + + IFS="${orig_IFS}" +} +export -f ptxd_make_world_license_flags + +ptxd_make_world_license_init() { + ptxd_make_world_init || return + + local name + + pkg_license="${pkg_license:-unknown}" + + ptxd_make_world_license_flags || return + + pkg_section="$(ptxd_create_section_from_license "${pkg_license}")" + + name="${pkg_label#host-}" + name="${name#cross-}" + + pkg_license_dir="${ptx_report_dir}/${pkg_section}/${pkg_label}" + pkg_release_dir="${ptx_release_dir}/${pkg_section}/${name}" +} +export -f ptxd_make_world_license_init # # extract and process all available license information # ptxd_make_world_license() { - ptxd_make_world_init || return + declare -A pkg_license_flags + ptxd_make_world_license_init || return local arg - local -a ptxd_reply local -a pkg_license_texts local -a pkg_license_texts_guessed - local pkg_dot=${pkg_license_dir}/graph.dot - local pkg_tex=${pkg_license_dir}/graph.tex - pkg_license="${pkg_license:-unknown}" + local pkg_dot + local pkg_tex + local pkg_dot="${pkg_license_dir}/graph.dot" + local pkg_tex="${pkg_license_dir}/graph.tex" + + + rm -rf "${pkg_license_dir}" || return + + if [ "${pkg_section}" == "ignore" ]; then + echo "Package to be ignored: metapackage for example" + return 0 + fi - rm -rf "${pkg_license_dir}" && - mkdir -p "${pkg_license_dir}" && + mkdir -p ${pkg_license_dir} && + echo ${pkg_section}/${pkg_label} >> "${ptx_report_dir}/package.list" && - ptxd_make_world_license_expand + ptxd_make_world_license_expand && + if [ -n "${pkg_license_files}" ]; then + mkdir -p "${pkg_license_dir}/license" + fi && + + echo "Copy licenses for package: '${pkg_section}/${pkg_label}'..." && for arg in ${pkg_license_files}; do local file startline endline md5 guess ptxd_make_world_parse_license_files "${arg}" && - local lic="${pkg_license_dir}/${file//\//_}" && - sed -n "${startline},${endline}p" "${pkg_dir}/${file}" > "${lic}" && + local lic="${pkg_license_dir}/license/${filename//\//_}" && + sed -n "${startline},${endline}p" "${file}" > "${lic}" && + if [ -n "${encoding}" ]; then + iconv -f "${encoding}" -t "utf-8" -o "${lic}.utf-8" "${lic}" + fi && if ! echo "${md5} ${lic}" | md5sum --check > /dev/null 2>&1; then ptxd_bailout " @@ -207,16 +436,80 @@ checksum of license file '$(ptxd_print_path "${file}")' changed: ${md5} -> $(md5sum "${lic}" | sed 's/ .*//') " fi && + ( + cd "${pkg_license_dir}/license" && + md5sum `basename ${lic}` >> MD5SUM 2>/dev/null + ) && if [ -z "${guess}" ]; then pkg_license_texts[${#pkg_license_texts[@]}]="${lic}" else pkg_license_texts_guessed[${#pkg_license_texts_guessed[@]}]="${lic}" - fi + fi || + ptxd_bailout "Failed to copy '$(ptxd_print_path "${file}")'" done && ptxd_make_world_license_write | \ sed -e 's/%/\\%/g' > "${pkg_license_dir}/license-report.tex" && + check_pipe_status && - echo "${pkg_license}" > "${pkg_license_dir}/license-name" + echo "${pkg_license}" > "${pkg_license_dir}/license-name" && + if [ "${#pkg_license_flags[@]}" -gt 0 ]; then + echo "${!pkg_license_flags[@]}" > "${pkg_license_dir}/license-flags" + fi } export -f ptxd_make_world_license + +ptxd_make_world_release() { + declare -A pkg_license_flags + ptxd_make_world_license_init || return + local src + + rm -rf "${pkg_release_dir}" || return + + if [ "${pkg_license_flags[nosource]}" = "true" ]; then + echo "Package to be ignored: source release disabled" + echo + return + fi + + mkdir -p ${pkg_release_dir} && + + # BSP local packages do not have ${pkg_srcs} filled + if [[ -z "${pkg_srcs}" && "${pkg_url}" =~ "file://${PTXDIST_WORKSPACE}" && -f "${pkg_url#file://}" ]]; then + # Use the URL for local archives + pkg_srcs="${pkg_url#file://}" + fi + if [ -z "${pkg_srcs}" ]; then + if [ -z "${pkg_url}" ]; then + # FIXME no sources! This is an error + # does not work, since some packages (udev for example, refer to systemd and has no own sources) + echo "Error: unable to detect source files/archives for package '${pkg_label}'" > "${pkg_release_dir}/source" + else + if [[ "${pkg_url}" =~ "file://${PTXDIST_WORKSPACE}" ]]; then + echo "Note: this package has BSP internal source code" > "${pkg_release_dir}/source" + else + if [[ "${pkg_url}" =~ "lndir://${PTXDIST_WORKSPACE}" ]]; then + echo "Note: this package has BSP internal source code" > "${pkg_release_dir}/source" + else + echo "Warning: direct/plain sources outside the BSP are unsupported!" > "${pkg_release_dir}/source" + fi + fi + fi + else + for src in ${pkg_srcs}; do + # copy only if required + echo -n "Copy sources for package: '${pkg_label}', source: '$(basename "${src}")'..." && + mkdir -p "${pkg_release_dir}/source" && + cp ${src} "${pkg_release_dir}/source" && + ( + cd "${pkg_release_dir}/source" && + md5sum `basename "${src}"` >> MD5SUM + ) && + echo " done" || break + done + if [ "${pkg_license_flags[nopatches]}" != "true" ]; then + ptxd_make_world_copy_patches "${pkg_dir}" "${pkg_release_dir}" + fi + fi +} +export -f ptxd_make_world_release diff --git a/scripts/ptxdist_vars.sh b/scripts/ptxdist_vars.sh index b0be2c7e4..11167a897 100644 --- a/scripts/ptxdist_vars.sh +++ b/scripts/ptxdist_vars.sh @@ -11,6 +11,8 @@ CROSS_BUILDDIR=${PTXDIST_PLATFORMDIR}/build-cross HOST_BUILDDIR=${PTXDIST_PLATFORMDIR}/build-host PKGDIR=${PTXDIST_PLATFORMDIR}/packages STATEDIR=${PTXDIST_PLATFORMDIR}/state +REPORTDIR=${PTXDIST_PLATFORMDIR}/report +RELEASEDIR=${PTXDIST_PLATFORMDIR}/release IMAGEDIR=${PTXDIST_PLATFORMDIR}/images ROOTDIR=${PTXDIST_PLATFORMDIR}/root ROOTDIR_DEBUG=${PTXDIST_PLATFORMDIR}/root-debug diff --git a/scripts/update_spdx.sh b/scripts/update_spdx.sh new file mode 100755 index 000000000..d601b1869 --- /dev/null +++ b/scripts/update_spdx.sh @@ -0,0 +1,109 @@ +#!/bin/bash +# +# Copyright (C) 2015 by Michael Olbrich <m.olbrich@pengutronix.de> +# +# See CREDITS for details about who has contributed to this project. +# +# For further information about the PTXdist project and license conditions +# see the README file. +# + +license_file="${1}" +exception_file="${2}" +output="$(dirname "$0")/lib/ptxd_make_spdx.sh" +delim='|' + +if [ "${#}" -ne 2 ]; then + echo "usage: $0 <license-file> <exception-file>" + exit 1 +fi +if [ ! -f "${license_file}" ]; then + echo "license file missing!" + exit 1 +fi +if [ ! -f "${exception_file}" ]; then + echo "exception file missing!" + exit 1 +fi + +export IFS="${delim}" + +( + sed '/^$/q' "$0" + + cat <<EOF +# +# WARNING: This file is generated with '$(basename "${0}")' from +# '$(basename "${license_file}")' and '$(basename "${exception_file}")'. +# +# To regenerate this file export the license and exception sheets from the +# original SPDX license list using '${delim}' as field delimiter and run +# '$(basename "${0}")'. + +ptxd_make_spdx() { + license="\${1}" + + case "\${license}" in +EOF + + last= + cols=0 + echo "parsing license file ..." >&2 + cat "${license_file}" | while read line; do + line="${last} ${line}" + last= + count="$(echo "${line}" | sed "s/[^${delim}]//g" | wc -c)" + if [ "${cols}" -eq 0 ]; then + cols="${count}" + fi + if [ "${count}" -lt "${cols}" ]; then + last="${line}" + continue + fi + if [ "${count}" -gt "${cols}" ]; then + echo "Too many columns: ${count}!" >&2 + exit 1 + fi + set -- ${line} + if [ "${2}" = "License Identifier" -o -z "${2}" ]; then + continue + fi + echo -n " ${2}) " + if [ "${5}" = "YES" ]; then + echo -n 'osi="true" ' + fi + echo ";;" + done + last= + cols=0 + echo "parsing exception file ..." >&2 + cat "${exception_file}" | while read line; do + line="${last} ${line}" + last= + count="$(echo "${line}" | sed "s/[^${delim}]//g" | wc -c)" + if [ "${cols}" -eq 0 ]; then + cols="${count}" + fi + if [ "${count}" -lt "${cols}" ]; then + last="${line}" + continue + fi + if [ "${count}" -gt "${cols}" ]; then + echo "Too many columns: ${count}!" >&2 + exit 1 + fi + set -- ${line} + if [ "${2}" = "Exception Identifier" -o -z "${2}" ]; then + continue + fi + echo -n " ${2}) exception=\"true\" " + echo ";;" + done + +cat <<EOF + *) return 1 ;; + esac +} +export -f ptxd_make_spdx +EOF +) > "${output}" |