#!/usr/bin/python3 # generate debian/copyright from debian/copyright.template and bower_components # Author: Martin Pitt # # bower.json license: format uses https://spdx.org/licenses/ identifiers, which # are mostly compatible with # https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/#license-specification import os import json import re import subprocess from glob import glob TEMPLATE = 'debian/copyright.template' def template_licenses(template): '''Return set of existing License: short names''' ids = set() for l in template.splitlines(): if l.startswith('License:'): ids.add(l.split(None, 1)[1]) return ids def module_license(moddir): '''Return License: short name for given module''' # First check if bower.json has a "license" field try: with open(os.path.join(moddir, 'bower.json')) as f: l = json.load(f)['license'] if 'and MIT' in l: # https://github.com/requirejs/requirejs/issues/1645 return 'MIT' return l except (FileNotFoundError, KeyError): pass # *LICENSE*/COPYING/README if os.path.exists(os.path.join(moddir, 'MIT-LICENSE.txt')): return 'MIT' try: with open((glob(os.path.join(moddir, 'LICENSE*')) + glob(os.path.join(moddir, 'COPYING')) + glob(os.path.join(moddir, 'README.md')))[0]) as f: text = f.read() if 'Permission is hereby granted,' in text and 'THE SOFTWARE IS PROVIDED "AS IS"' in text: return 'MIT' if 'Redistribution and use in source and binary forms' in text and 'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT' in text: if '4. Neither' in text: return 'BSD-4-clause' else: return 'BSD-3-clause' if re.search('Apache License.*2.0', text): return 'Apache-2.0' if 'GNU LESSER GENERAL PUBLIC LICENSE' in text and 'Version 2.1' in text: return 'LGPL-2.1' except IndexError: pass # missing licenses mod = os.path.basename(moddir) if mod == 'kubernetes-object-describer': # upstream says "same as what we use for origin and origin-web-console which is Apache" # https://github.com/kubernetes-ui/object-describer/issues/31 return 'Apache-2.0' if mod == 'redux': # our tarball only ships the minified version, original source is at # https://github.com/reactjs/redux; as it's "MIT" we don't legally # require to ship the preferred form of modification return 'MIT' raise SystemError('Could not determine license from %s' % moddir) def module_copyright(moddir): '''Return Copyrights for given module''' copyrights = set() try: out = subprocess.check_output(['env', '-u', 'LANGUAGE', 'LC_ALL=C.UTF-8', 'grep', '-hri', 'copyright.*[1-9][0-9]\+'], cwd=moddir, universal_newlines=True) for l in out.splitlines(): # ignore compiled .css.map files if l.startswith('{"version":') or '*//*!' in l: continue # weed out some noise if 'grunt.template.today' in l or 'copyright-mark' in l or '@font-face' in l or 'Binary file' in l: continue l = l.replace('', '').replace('', '') l = l.replace('©', '(c)').replace('copyright = ', '') l = l.strip(' \t*/\'|') if l.startswith("u'") or l.startswith('u"'): # Python unicode prefix l = l[2:] copyrights.add(' ' + l) # space prefix for debian/copyright RFC822 format except subprocess.CalledProcessError: pass # missing copyrights mod = os.path.basename(moddir) if mod == 'angular-bootstrap': # only committer is Wesley Cho, so assume his copyright # https://github.com/angular-ui/bootstrap-bower/issues/74 copyrights.add('Copyright: (C) 2015-2017 Wesley Cho') if mod == 'kubernetes-object-describer': # only committer is Jessica Forrester, working for Red Hat # https://github.com/kubernetes-ui/object-describer/issues/35 copyrights.add('Copyright: (C) 2015-2017 Red Hat, Inc.') if mod == 'redux': # our tarball only ships the minified version, original source is at # https://github.com/reactjs/redux copyrights.add('Copyright (c) 2015-present Dan Abramov') if not copyrights: raise SystemError('Did not find any copyrights in %s' % moddir) return copyrights # # main # with open(TEMPLATE) as f: template = f.read() license_ids = template_licenses(template) paragraphs = [] for module in os.listdir('bower_components'): if module == 'README': continue moddir = os.path.join('bower_components', module) license = module_license(moddir) if license not in license_ids: raise KeyError('%s has license %s which is not in %s' % (module, license, TEMPLATE)) copyrights = module_copyright(moddir) paragraphs.append('''Files: %s/* Copyright:%s License: %s''' % (moddir, '\n'.join(sorted(copyrights)), license)) with open('debian/copyright', 'w') as f: for l in template.splitlines(): if '#BOWER' in l: f.write('\n\n'.join(paragraphs)) else: f.write(l + '\n')