Commit 8ef8af22 authored by Samuel GAIST's avatar Samuel GAIST
Browse files

[doc] Add script to generate list of dependencies license

Requires pip-licenses
parent 262d12fc
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
###############################################################################
# #
# Copyright (c) 2019 Idiap Research Institute, http://www.idiap.ch/ #
# Contact: beat.support@idiap.ch #
# #
# This file is part of the beat.editor module of the BEAT platform. #
# #
# Commercial License Usage #
# Licensees holding valid commercial BEAT licenses may use this file in #
# accordance with the terms contained in a written agreement between you #
# and Idiap. For further information contact tto@idiap.ch #
# #
# Alternatively, this file may be used under the terms of the GNU Affero #
# Public License version 3 as published by the Free Software and appearing #
# in the file LICENSE.AGPL included in the packaging of this file. #
# The BEAT platform is distributed in the hope that it will be useful, but #
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY #
# or FITNESS FOR A PARTICULAR PURPOSE. #
# #
# You should have received a copy of the GNU Affero Public License along #
# with the BEAT platform. If not, see http://www.gnu.org/licenses/. #
# #
###############################################################################
"""Dumps the license of all dependencies
Usage:
%(prog)s [-v ... | --verbose ...]
%(prog)s (--help | -h)
Options:
-h, --help Show this screen
-v, --verbose Increases the output verbosity level
"""
import json
import logging
import os
import re
import sys
from subprocess import PIPE # nosec
from subprocess import Popen # nosec
from docopt import docopt
def _run_cmd(cmd_list):
"""Run given command"""
try:
p = Popen(cmd_list, stdout=PIPE, stderr=PIPE) # nosec
except OSError:
raise Exception("could not invoke %r\n" % cmd_list)
return json.loads(p.communicate()[0])
def _call_conda(extra_args):
""" call conda with the list of extra arguments, and return the tuple
stdout, stderr
"""
cmd_list = [os.environ.get("CONDA_EXE")]
cmd_list.extend(extra_args)
return _run_cmd(cmd_list)
def _get_pip_info():
""" Get license info from pip"""
return _run_cmd(["pip-licenses", "--format-json"])
def _clean_pkg_name(name):
""" Cleanup package name:
- lower case
- replace minus and underscore by only minus
"""
return re.sub(r"[_-]", "-", name.lower())
if __name__ == "__main__":
arguments = sys.argv[1:]
prog = os.path.basename(sys.argv[0])
completions = dict(prog=prog)
args = docopt(__doc__ % completions, argv=arguments, options_first=True)
# Setup the logging
formatter = logging.Formatter(
fmt="[%(asctime)s - License - %(name)s] %(levelname)s: %(message)s",
datefmt="%d/%b/%Y %H:%M:%S",
)
handler = logging.StreamHandler()
handler.setFormatter(formatter)
logger = logging.getLogger("beat.editor")
logger.addHandler(handler)
if args["--verbose"] == 1:
logger.setLevel(logging.INFO)
elif args["--verbose"] == 2:
logger.setLevel(logging.DEBUG)
elif args["--verbose"] >= 3:
logger.setLevel(logging.DEBUG)
else:
logger.setLevel(logging.WARNING)
list_args = ["list", "--json"]
logger.info("listing conda packages")
pkg_list = _call_conda(list_args)
logger.info("done")
info_args = ["info", "-l", "--json"]
info_args += ["{}={}".format(item["name"], item["version"]) for item in pkg_list]
logger.info("loading conda packages information")
pkg_info_list = _call_conda(info_args)
logger.info("done")
cleaned_pkg_info_list = []
logger.info("extracting exact package version data")
for pkg in pkg_list:
key = "{}={}".format(pkg["name"], pkg["version"])
build_string = pkg["build_string"]
pkg_info = [
item for item in pkg_info_list[key] if item["build"] == build_string
]
if len(pkg_info) > 0:
cleaned_pkg_info_list.append(pkg_info[0])
else:
logger.warning(
"No information available for {}, {}".format(key, build_string)
)
logger.info("done")
logger.info("loading pip packages information")
pip_pkg_info_list = _get_pip_info()
logger.info("done")
logger.info("unifying data")
pkg_names = [_clean_pkg_name(pkg["name"]) for pkg in pkg_list]
cleaned_pkg_info_list += [
{k.casefold(): v for k, v in item.items()}
for item in pip_pkg_info_list
if _clean_pkg_name(item["Name"]) not in pkg_names
]
logger.info("done")
cleaned_pkg_info_list = sorted(cleaned_pkg_info_list, key=lambda x: x["name"])
name_length = 0
version_length = 0
license_length = 0
for item in cleaned_pkg_info_list:
name_length = max(name_length, len(item["name"]))
version_length = max(version_length, len(item["version"]))
if "license" not in item:
logger.warning(
"Package has no license information: {}".format(item["name"])
)
item["license"] = "Unknown"
license_length = max(license_length, len(item["license"]))
filler = "|{0:-<{fill_name}}|{0:-<{fill_version}}|{0:-<{fill_license}}|\n".format(
"",
fill_name=name_length + 2,
fill_version=version_length + 2,
fill_license=license_length + 2,
)
text = filler
text += "| {0:<{fill_name}} | {1:<{fill_version}} | {2:<{fill_license}} |\n".format(
"Name",
"Version",
"License",
fill_name=name_length,
fill_version=version_length,
fill_license=license_length,
)
text += filler
for item in cleaned_pkg_info_list:
text += "| {name:<{fill_name}} | {version:<{fill_version}} | {license:<{fill_license}} |\n".format(
**item,
fill_name=name_length,
fill_version=version_length,
fill_license=license_length
)
sys.stdout.write(text)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment