• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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