1#!/usr/bin/env python3 2# 3# Copyright (C) 2021 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the 'License'); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an 'AS IS' BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# 17 18import argparse 19import glob 20import logging 21import os 22 23import utils 24 25LICENSE_KINDS_PREFIX = 'SPDX-license-identifier-' 26LICENSE_KEYWORDS = { 27 'Apache-2.0': ('Apache License', 'Version 2.0',), 28 'BSD': ('BSD ',), 29 'CC0-1.0': ('CC0 Public Domain Dedication license',), 30 'FTL': ('FreeType Project LICENSE',), 31 'ISC': ('Internet Systems Consortium',), 32 'ISC': ('ISC license',), 33 'MIT': (' MIT ',), 34 'MPL-2.0': ('Mozilla Public License Version 2.0',), 35 'MPL': ('Mozilla Public License',), 36 'NCSA': ('University of Illinois', 'NCSA',), 37 'OpenSSL': ('The OpenSSL Project',), 38 'Zlib': ('zlib License',), 39} 40RESTRICTED_LICENSE_KEYWORDS = { 41 'LGPL-3.0': ('LESSER GENERAL PUBLIC LICENSE', 'Version 3,',), 42 'LGPL-2.1': ('LESSER GENERAL PUBLIC LICENSE', 'Version 2.1',), 43 'LGPL-2.0': ('GNU LIBRARY GENERAL PUBLIC LICENSE', 'Version 2,',), 44 'LGPL': ('LESSER GENERAL PUBLIC LICENSE',), 45 'GPL-2.0': ('GNU GENERAL PUBLIC LICENSE', 'Version 2,',), 46 'GPL': ('GNU GENERAL PUBLIC LICENSE',), 47} 48 49LICENSE_INCLUDE = ['legacy_permissive', 'legacy_unencumbered'] 50 51class LicenseCollector(object): 52 """ Collect licenses from a VNDK snapshot directory 53 54 This is to collect the license_kinds to be used in license modules. 55 It also lists the modules with the restricted licenses. 56 57 Initialize the LicenseCollector with a vndk snapshot directory. 58 After run() is called, 'license_kinds' will include the licenses found from 59 the snapshot directory. 60 'restricted' will have the files that have the restricted licenses. 61 """ 62 def __init__(self, install_dir): 63 self._install_dir = install_dir 64 self._paths_to_check = [os.path.join(install_dir, 65 utils.NOTICE_FILES_DIR_PATH),] 66 self._paths_to_check = self._paths_to_check + glob.glob(os.path.join(self._install_dir, '*/include')) 67 68 self.license_kinds = set() 69 self.restricted = set() 70 71 def read_and_check_licenses(self, license_text, license_keywords): 72 """ Read the license keywords and check if all keywords are in the file. 73 74 The found licenses will be added to license_kinds set. This function will 75 return True if any licenses are found, False otherwise. 76 """ 77 found = False 78 for lic, patterns in license_keywords.items(): 79 for pattern in patterns: 80 if pattern not in license_text: 81 break 82 else: 83 self.license_kinds.add(LICENSE_KINDS_PREFIX + lic) 84 found = True 85 return found 86 87 def read_and_check_dir_for_licenses(self, path): 88 """ Check licenses for all files under the directory 89 """ 90 for (root, _, files) in os.walk(path): 91 for f in files: 92 with open(os.path.join(root, f), 'r') as file_to_check: 93 file_string = file_to_check.read() 94 self.read_and_check_licenses(file_string, LICENSE_KEYWORDS) 95 if self.read_and_check_licenses(file_string, RESTRICTED_LICENSE_KEYWORDS): 96 self.restricted.add(f) 97 98 def run(self): 99 """ search licenses in vndk snapshots 100 """ 101 for path in self._paths_to_check: 102 logging.info('Reading {}'.format(path)) 103 self.read_and_check_dir_for_licenses(path) 104 self.license_kinds.update(LICENSE_INCLUDE) 105 106def get_args(): 107 parser = argparse.ArgumentParser() 108 parser.add_argument( 109 'vndk_version', 110 type=utils.vndk_version_int, 111 help='VNDK snapshot version to check, e.g. "{}".'.format( 112 utils.MINIMUM_VNDK_VERSION)) 113 parser.add_argument( 114 '-v', 115 '--verbose', 116 action='count', 117 default=0, 118 help='Increase output verbosity, e.g. "-v", "-vv".') 119 return parser.parse_args() 120 121def main(): 122 """ For the local testing purpose. 123 """ 124 ANDROID_BUILD_TOP = utils.get_android_build_top() 125 PREBUILTS_VNDK_DIR = utils.join_realpath(ANDROID_BUILD_TOP, 126 'prebuilts/vndk') 127 args = get_args() 128 vndk_version = args.vndk_version 129 install_dir = os.path.join(PREBUILTS_VNDK_DIR, 'v{}'.format(vndk_version)) 130 utils.set_logging_config(args.verbose) 131 132 license_collector = LicenseCollector(install_dir) 133 license_collector.run() 134 print(sorted(license_collector.license_kinds)) 135 print(sorted(license_collector.restricted)) 136 137if __name__ == '__main__': 138 main() 139