1*9e94795aSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*9e94795aSAndroid Build Coastguard Worker# 3*9e94795aSAndroid Build Coastguard Worker# Copyright (C) 2024 The Android Open Source Project 4*9e94795aSAndroid Build Coastguard Worker# 5*9e94795aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*9e94795aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*9e94795aSAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*9e94795aSAndroid Build Coastguard Worker# 9*9e94795aSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*9e94795aSAndroid Build Coastguard Worker# 11*9e94795aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*9e94795aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*9e94795aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*9e94795aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*9e94795aSAndroid Build Coastguard Worker# limitations under the License. 16*9e94795aSAndroid Build Coastguard Worker 17*9e94795aSAndroid Build Coastguard Workerimport sqlite3 18*9e94795aSAndroid Build Coastguard Worker 19*9e94795aSAndroid Build Coastguard Workerclass MetadataDb: 20*9e94795aSAndroid Build Coastguard Worker def __init__(self, db): 21*9e94795aSAndroid Build Coastguard Worker self.conn = sqlite3.connect(':memory') 22*9e94795aSAndroid Build Coastguard Worker self.conn.row_factory = sqlite3.Row 23*9e94795aSAndroid Build Coastguard Worker with sqlite3.connect(db) as c: 24*9e94795aSAndroid Build Coastguard Worker c.backup(self.conn) 25*9e94795aSAndroid Build Coastguard Worker self.reorg() 26*9e94795aSAndroid Build Coastguard Worker 27*9e94795aSAndroid Build Coastguard Worker def reorg(self): 28*9e94795aSAndroid Build Coastguard Worker # package_license table 29*9e94795aSAndroid Build Coastguard Worker self.conn.execute("create table package_license as " 30*9e94795aSAndroid Build Coastguard Worker "select name as package, pkg_default_applicable_licenses as license " 31*9e94795aSAndroid Build Coastguard Worker "from modules " 32*9e94795aSAndroid Build Coastguard Worker "where module_type = 'package' ") 33*9e94795aSAndroid Build Coastguard Worker cursor = self.conn.execute("select package,license from package_license where license like '% %'") 34*9e94795aSAndroid Build Coastguard Worker multi_licenses_packages = cursor.fetchall() 35*9e94795aSAndroid Build Coastguard Worker cursor.close() 36*9e94795aSAndroid Build Coastguard Worker rows = [] 37*9e94795aSAndroid Build Coastguard Worker for p in multi_licenses_packages: 38*9e94795aSAndroid Build Coastguard Worker licenses = p['license'].strip().split(' ') 39*9e94795aSAndroid Build Coastguard Worker for lic in licenses: 40*9e94795aSAndroid Build Coastguard Worker rows.append((p['package'], lic)) 41*9e94795aSAndroid Build Coastguard Worker self.conn.executemany('insert into package_license values (?, ?)', rows) 42*9e94795aSAndroid Build Coastguard Worker self.conn.commit() 43*9e94795aSAndroid Build Coastguard Worker 44*9e94795aSAndroid Build Coastguard Worker self.conn.execute("delete from package_license where license like '% %'") 45*9e94795aSAndroid Build Coastguard Worker self.conn.commit() 46*9e94795aSAndroid Build Coastguard Worker 47*9e94795aSAndroid Build Coastguard Worker # module_license table 48*9e94795aSAndroid Build Coastguard Worker self.conn.execute("create table module_license as " 49*9e94795aSAndroid Build Coastguard Worker "select distinct name as module, package, licenses as license " 50*9e94795aSAndroid Build Coastguard Worker "from modules " 51*9e94795aSAndroid Build Coastguard Worker "where licenses != '' ") 52*9e94795aSAndroid Build Coastguard Worker cursor = self.conn.execute("select module,package,license from module_license where license like '% %'") 53*9e94795aSAndroid Build Coastguard Worker multi_licenses_modules = cursor.fetchall() 54*9e94795aSAndroid Build Coastguard Worker cursor.close() 55*9e94795aSAndroid Build Coastguard Worker rows = [] 56*9e94795aSAndroid Build Coastguard Worker for m in multi_licenses_modules: 57*9e94795aSAndroid Build Coastguard Worker licenses = m['license'].strip().split(' ') 58*9e94795aSAndroid Build Coastguard Worker for lic in licenses: 59*9e94795aSAndroid Build Coastguard Worker rows.append((m['module'], m['package'],lic)) 60*9e94795aSAndroid Build Coastguard Worker self.conn.executemany('insert into module_license values (?, ?, ?)', rows) 61*9e94795aSAndroid Build Coastguard Worker self.conn.commit() 62*9e94795aSAndroid Build Coastguard Worker 63*9e94795aSAndroid Build Coastguard Worker self.conn.execute("delete from module_license where license like '% %'") 64*9e94795aSAndroid Build Coastguard Worker self.conn.commit() 65*9e94795aSAndroid Build Coastguard Worker 66*9e94795aSAndroid Build Coastguard Worker # module_installed_file table 67*9e94795aSAndroid Build Coastguard Worker self.conn.execute("create table module_installed_file as " 68*9e94795aSAndroid Build Coastguard Worker "select id as module_id, name as module_name, package, installed_files as installed_file " 69*9e94795aSAndroid Build Coastguard Worker "from modules " 70*9e94795aSAndroid Build Coastguard Worker "where installed_files != '' ") 71*9e94795aSAndroid Build Coastguard Worker cursor = self.conn.execute("select module_id, module_name, package, installed_file " 72*9e94795aSAndroid Build Coastguard Worker "from module_installed_file where installed_file like '% %'") 73*9e94795aSAndroid Build Coastguard Worker multi_installed_file_modules = cursor.fetchall() 74*9e94795aSAndroid Build Coastguard Worker cursor.close() 75*9e94795aSAndroid Build Coastguard Worker rows = [] 76*9e94795aSAndroid Build Coastguard Worker for m in multi_installed_file_modules: 77*9e94795aSAndroid Build Coastguard Worker installed_files = m['installed_file'].strip().split(' ') 78*9e94795aSAndroid Build Coastguard Worker for f in installed_files: 79*9e94795aSAndroid Build Coastguard Worker rows.append((m['module_id'], m['module_name'], m['package'], f)) 80*9e94795aSAndroid Build Coastguard Worker self.conn.executemany('insert into module_installed_file values (?, ?, ?, ?)', rows) 81*9e94795aSAndroid Build Coastguard Worker self.conn.commit() 82*9e94795aSAndroid Build Coastguard Worker 83*9e94795aSAndroid Build Coastguard Worker self.conn.execute("delete from module_installed_file where installed_file like '% %'") 84*9e94795aSAndroid Build Coastguard Worker self.conn.commit() 85*9e94795aSAndroid Build Coastguard Worker 86*9e94795aSAndroid Build Coastguard Worker # module_built_file table 87*9e94795aSAndroid Build Coastguard Worker self.conn.execute("create table module_built_file as " 88*9e94795aSAndroid Build Coastguard Worker "select id as module_id, name as module_name, package, built_files as built_file " 89*9e94795aSAndroid Build Coastguard Worker "from modules " 90*9e94795aSAndroid Build Coastguard Worker "where built_files != '' ") 91*9e94795aSAndroid Build Coastguard Worker cursor = self.conn.execute("select module_id, module_name, package, built_file " 92*9e94795aSAndroid Build Coastguard Worker "from module_built_file where built_file like '% %'") 93*9e94795aSAndroid Build Coastguard Worker multi_built_file_modules = cursor.fetchall() 94*9e94795aSAndroid Build Coastguard Worker cursor.close() 95*9e94795aSAndroid Build Coastguard Worker rows = [] 96*9e94795aSAndroid Build Coastguard Worker for m in multi_built_file_modules: 97*9e94795aSAndroid Build Coastguard Worker built_files = m['installed_file'].strip().split(' ') 98*9e94795aSAndroid Build Coastguard Worker for f in built_files: 99*9e94795aSAndroid Build Coastguard Worker rows.append((m['module_id'], m['module_name'], m['package'], f)) 100*9e94795aSAndroid Build Coastguard Worker self.conn.executemany('insert into module_built_file values (?, ?, ?, ?)', rows) 101*9e94795aSAndroid Build Coastguard Worker self.conn.commit() 102*9e94795aSAndroid Build Coastguard Worker 103*9e94795aSAndroid Build Coastguard Worker self.conn.execute("delete from module_built_file where built_file like '% %'") 104*9e94795aSAndroid Build Coastguard Worker self.conn.commit() 105*9e94795aSAndroid Build Coastguard Worker 106*9e94795aSAndroid Build Coastguard Worker 107*9e94795aSAndroid Build Coastguard Worker # Indexes 108*9e94795aSAndroid Build Coastguard Worker self.conn.execute('create index idx_modules_id on modules (id)') 109*9e94795aSAndroid Build Coastguard Worker self.conn.execute('create index idx_modules_name on modules (name)') 110*9e94795aSAndroid Build Coastguard Worker self.conn.execute('create index idx_package_licnese_package on package_license (package)') 111*9e94795aSAndroid Build Coastguard Worker self.conn.execute('create index idx_package_licnese_license on package_license (license)') 112*9e94795aSAndroid Build Coastguard Worker self.conn.execute('create index idx_module_licnese_module on module_license (module)') 113*9e94795aSAndroid Build Coastguard Worker self.conn.execute('create index idx_module_licnese_license on module_license (license)') 114*9e94795aSAndroid Build Coastguard Worker self.conn.execute('create index idx_module_installed_file_module_id on module_installed_file (module_id)') 115*9e94795aSAndroid Build Coastguard Worker self.conn.execute('create index idx_module_installed_file_installed_file on module_installed_file (installed_file)') 116*9e94795aSAndroid Build Coastguard Worker self.conn.execute('create index idx_module_built_file_module_id on module_built_file (module_id)') 117*9e94795aSAndroid Build Coastguard Worker self.conn.execute('create index idx_module_built_file_built_file on module_built_file (built_file)') 118*9e94795aSAndroid Build Coastguard Worker self.conn.commit() 119*9e94795aSAndroid Build Coastguard Worker 120*9e94795aSAndroid Build Coastguard Worker def dump_debug_db(self, debug_db): 121*9e94795aSAndroid Build Coastguard Worker with sqlite3.connect(debug_db) as c: 122*9e94795aSAndroid Build Coastguard Worker self.conn.backup(c) 123*9e94795aSAndroid Build Coastguard Worker 124*9e94795aSAndroid Build Coastguard Worker def get_installed_files(self): 125*9e94795aSAndroid Build Coastguard Worker # Get all records from table make_metadata, which contains all installed files and corresponding make modules' metadata 126*9e94795aSAndroid Build Coastguard Worker cursor = self.conn.execute('select installed_file, module_path, is_prebuilt_make_module, product_copy_files, kernel_module_copy_files, is_platform_generated, license_text from make_metadata') 127*9e94795aSAndroid Build Coastguard Worker rows = cursor.fetchall() 128*9e94795aSAndroid Build Coastguard Worker cursor.close() 129*9e94795aSAndroid Build Coastguard Worker installed_files_metadata = [] 130*9e94795aSAndroid Build Coastguard Worker for row in rows: 131*9e94795aSAndroid Build Coastguard Worker metadata = dict(zip(row.keys(), row)) 132*9e94795aSAndroid Build Coastguard Worker installed_files_metadata.append(metadata) 133*9e94795aSAndroid Build Coastguard Worker return installed_files_metadata 134*9e94795aSAndroid Build Coastguard Worker 135*9e94795aSAndroid Build Coastguard Worker def get_soong_modules(self): 136*9e94795aSAndroid Build Coastguard Worker # Get all records from table modules, which contains metadata of all soong modules 137*9e94795aSAndroid Build Coastguard Worker cursor = self.conn.execute('select name, package, package as module_path, module_type as soong_module_type, built_files, installed_files, static_dep_files, whole_static_dep_files from modules') 138*9e94795aSAndroid Build Coastguard Worker rows = cursor.fetchall() 139*9e94795aSAndroid Build Coastguard Worker cursor.close() 140*9e94795aSAndroid Build Coastguard Worker soong_modules = [] 141*9e94795aSAndroid Build Coastguard Worker for row in rows: 142*9e94795aSAndroid Build Coastguard Worker soong_module = dict(zip(row.keys(), row)) 143*9e94795aSAndroid Build Coastguard Worker soong_modules.append(soong_module) 144*9e94795aSAndroid Build Coastguard Worker return soong_modules 145*9e94795aSAndroid Build Coastguard Worker 146*9e94795aSAndroid Build Coastguard Worker def get_package_licenses(self, package): 147*9e94795aSAndroid Build Coastguard Worker cursor = self.conn.execute('select m.name, m.package, m.lic_license_text as license_text ' 148*9e94795aSAndroid Build Coastguard Worker 'from package_license pl join modules m on pl.license = m.name ' 149*9e94795aSAndroid Build Coastguard Worker 'where pl.package = ?', 150*9e94795aSAndroid Build Coastguard Worker ('//' + package,)) 151*9e94795aSAndroid Build Coastguard Worker rows = cursor.fetchall() 152*9e94795aSAndroid Build Coastguard Worker licenses = {} 153*9e94795aSAndroid Build Coastguard Worker for r in rows: 154*9e94795aSAndroid Build Coastguard Worker licenses[r['name']] = r['license_text'] 155*9e94795aSAndroid Build Coastguard Worker return licenses 156*9e94795aSAndroid Build Coastguard Worker 157*9e94795aSAndroid Build Coastguard Worker def get_module_licenses(self, module_name, package): 158*9e94795aSAndroid Build Coastguard Worker licenses = {} 159*9e94795aSAndroid Build Coastguard Worker # If property "licenses" is defined on module 160*9e94795aSAndroid Build Coastguard Worker cursor = self.conn.execute('select m.name, m.package, m.lic_license_text as license_text ' 161*9e94795aSAndroid Build Coastguard Worker 'from module_license ml join modules m on ml.license = m.name ' 162*9e94795aSAndroid Build Coastguard Worker 'where ml.module = ? and ml.package = ?', 163*9e94795aSAndroid Build Coastguard Worker (module_name, package)) 164*9e94795aSAndroid Build Coastguard Worker rows = cursor.fetchall() 165*9e94795aSAndroid Build Coastguard Worker for r in rows: 166*9e94795aSAndroid Build Coastguard Worker licenses[r['name']] = r['license_text'] 167*9e94795aSAndroid Build Coastguard Worker if len(licenses) > 0: 168*9e94795aSAndroid Build Coastguard Worker return licenses 169*9e94795aSAndroid Build Coastguard Worker 170*9e94795aSAndroid Build Coastguard Worker # Use default package license 171*9e94795aSAndroid Build Coastguard Worker cursor = self.conn.execute('select m.name, m.package, m.lic_license_text as license_text ' 172*9e94795aSAndroid Build Coastguard Worker 'from package_license pl join modules m on pl.license = m.name ' 173*9e94795aSAndroid Build Coastguard Worker 'where pl.package = ?', 174*9e94795aSAndroid Build Coastguard Worker ('//' + package,)) 175*9e94795aSAndroid Build Coastguard Worker rows = cursor.fetchall() 176*9e94795aSAndroid Build Coastguard Worker for r in rows: 177*9e94795aSAndroid Build Coastguard Worker licenses[r['name']] = r['license_text'] 178*9e94795aSAndroid Build Coastguard Worker return licenses 179*9e94795aSAndroid Build Coastguard Worker 180*9e94795aSAndroid Build Coastguard Worker def get_soong_module_of_installed_file(self, installed_file): 181*9e94795aSAndroid Build Coastguard Worker cursor = self.conn.execute('select name, m.package, m.package as module_path, module_type as soong_module_type, built_files, installed_files, static_dep_files, whole_static_dep_files ' 182*9e94795aSAndroid Build Coastguard Worker 'from modules m join module_installed_file mif on m.id = mif.module_id ' 183*9e94795aSAndroid Build Coastguard Worker 'where mif.installed_file = ?', 184*9e94795aSAndroid Build Coastguard Worker (installed_file,)) 185*9e94795aSAndroid Build Coastguard Worker rows = cursor.fetchall() 186*9e94795aSAndroid Build Coastguard Worker cursor.close() 187*9e94795aSAndroid Build Coastguard Worker if rows: 188*9e94795aSAndroid Build Coastguard Worker soong_module = dict(zip(rows[0].keys(), rows[0])) 189*9e94795aSAndroid Build Coastguard Worker return soong_module 190*9e94795aSAndroid Build Coastguard Worker 191*9e94795aSAndroid Build Coastguard Worker return None 192*9e94795aSAndroid Build Coastguard Worker 193*9e94795aSAndroid Build Coastguard Worker def get_soong_module_of_built_file(self, built_file): 194*9e94795aSAndroid Build Coastguard Worker cursor = self.conn.execute('select name, m.package, m.package as module_path, module_type as soong_module_type, built_files, installed_files, static_dep_files, whole_static_dep_files ' 195*9e94795aSAndroid Build Coastguard Worker 'from modules m join module_built_file mbf on m.id = mbf.module_id ' 196*9e94795aSAndroid Build Coastguard Worker 'where mbf.built_file = ?', 197*9e94795aSAndroid Build Coastguard Worker (built_file,)) 198*9e94795aSAndroid Build Coastguard Worker rows = cursor.fetchall() 199*9e94795aSAndroid Build Coastguard Worker cursor.close() 200*9e94795aSAndroid Build Coastguard Worker if rows: 201*9e94795aSAndroid Build Coastguard Worker soong_module = dict(zip(rows[0].keys(), rows[0])) 202*9e94795aSAndroid Build Coastguard Worker return soong_module 203*9e94795aSAndroid Build Coastguard Worker 204*9e94795aSAndroid Build Coastguard Worker return None