#!/usr/bin/env python # Copyright (C) 2016 Codethink Limited # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 2 of the License. # # This program 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. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import errno import os import re import subprocess import sys import tempfile import yaml gpl3_chunks = ["autoconf", "automake", "bash", "binutils", "bison", "ccache", "cmake", "flex", "gawk", "gcc", "gdbm", "gettext", "gperf", "groff", "libtool", "m4-tarball", "make", "nano", "patch", "rsync", "texinfo-tarball"] def definitions_root(): return subprocess.check_output( ["git", "rev-parse", "--show-toplevel"]).strip() def load_yaml_file(yaml_file): with open(yaml_file, 'r') as f: return yaml.safe_load(f) def usage(): print ("Usage: ./licensecheck.py SYSTEM") exit() def license_file_name(repo_name, sha): license_file = os.path.join(definitions_root(), "licenses", repo_name + '-' + sha).strip() return license_file def check_license(repo_name, sha, clone_path): license_file = license_file_name(repo_name, sha) licenses_dir = os.path.dirname(license_file) try: os.makedirs(licenses_dir) except OSError as e: if e.errno != errno.EEXIST: raise _, license_file_temp = tempfile.mkstemp(dir=licenses_dir) with open(license_file_temp,"wb") as out: sys.stderr.write("Checking license of '%s' ...\n" % repo_name) with open(os.devnull, 'w') as devnull: subprocess.call("perl scripts/licensecheck.pl -r " + clone_path + "|cut -d: -f2- | sort -u", stdout=out, stderr=devnull, shell=True) os.rename(license_file_temp, license_file) return license_file def check_repo_if_needed(name, repo, ref): repo_name = re.split('/|:',repo)[-1] if repo_name.endswith(".git"): repo_name = repo_name[:-4] # Check if ref is sha1 to speedup pattern = re.compile("[0-9a-f]{40}") if pattern.match(ref): if os.path.isfile(license_file_name(repo_name, ref)): return (repo, license_file_name(repo_name, ref)) clone_path = os.path.join(definitions_root(), "repos", repo_name) if os.path.isdir(clone_path): sys.stderr.write("Updating repo '%s' ...\n" % repo_name) with open(os.devnull, 'w') as devnull: subprocess.call(["git", "checkout", ref], stderr=devnull, stdout=devnull, cwd=clone_path) else: sys.stderr.write("Geting repo '%s' ...\n" % repo_name) with open(os.devnull, 'w') as devnull: subprocess.call(["morph", "get-repo", name, clone_path], stdout=devnull, stderr=devnull) sha = subprocess.check_output( ["git", "rev-parse", "HEAD"], cwd=clone_path) if os.path.isfile(license_file_name(repo_name, sha)): return (repo, license_file_name(repo_name, sha)) return (repo, check_license(repo_name, sha, clone_path)) def check_stratum(stratum_file): stratum = load_yaml_file(stratum_file) license_files = [] for chunk in stratum['chunks']: name = chunk.get("name") build_mode = chunk.get("build-mode") # Don't include bootstrap chunks and stripped gplv3 chunks if name in gpl3_chunks or build_mode == "bootstrap": continue repo = chunk.get("repo") ref = chunk.get("ref") license_to_append = check_repo_if_needed(name, repo, ref) license_files.append(license_to_append) return license_files def main(): if len(sys.argv) != 2: usage() elif (sys.argv[1] == "-h") or (sys.argv[1] == "--help"): usage() system_file = sys.argv[1] system = load_yaml_file(system_file) license_files = [] for stratum in system['strata']: stratum_file = stratum['morph'] stratum_path = os.path.join(definitions_root(), stratum_file) license_files += check_stratum(stratum_path) for chunk in license_files: try: # Print repo name sys.stdout.write("%s\n%s\n" % (chunk[0], '-' * len(chunk[0]))) # Print license file of the repo with open(chunk[1], 'r') as f: for line in f: sys.stdout.write(line) sys.stdout.write("\n") except IOError: # stdout is closed, no point in continuing # Attempt to close them explicitly to prevent cleanup problems: try: sys.stdout.flush() sys.stdout.close() except IOError: pass finally: exit() if __name__ == "__main__": main()