Add script to print out list of unconverted .pro files
Also prints some statistics. Change-Id: Ieb55618c0d39604ca76d7a44390e61e02824a01f Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
parent
f896a5019a
commit
4f07e711c9
218
util/cmake/pro_conversion_rate.py
Executable file
218
util/cmake/pro_conversion_rate.py
Executable file
@ -0,0 +1,218 @@
|
||||
#!/usr/bin/env python3
|
||||
#############################################################################
|
||||
##
|
||||
## Copyright (C) 2019 The Qt Company Ltd.
|
||||
## Contact: https://www.qt.io/licensing/
|
||||
##
|
||||
## This file is part of the plugins of the Qt Toolkit.
|
||||
##
|
||||
## $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||
## Commercial License Usage
|
||||
## Licensees holding valid commercial Qt licenses may use this file in
|
||||
## accordance with the commercial license agreement provided with the
|
||||
## Software or, alternatively, in accordance with the terms contained in
|
||||
## a written agreement between you and The Qt Company. For licensing terms
|
||||
## and conditions see https://www.qt.io/terms-conditions. For further
|
||||
## information use the contact form at https://www.qt.io/contact-us.
|
||||
##
|
||||
## GNU General Public License Usage
|
||||
## Alternatively, this file may be used under the terms of the GNU
|
||||
## General Public License version 3 as published by the Free Software
|
||||
## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
## included in the packaging of this file. Please review the following
|
||||
## information to ensure the GNU General Public License requirements will
|
||||
## be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
##
|
||||
## $QT_END_LICENSE$
|
||||
##
|
||||
#############################################################################
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
"""
|
||||
This utility script shows statistics about
|
||||
converted .pro -> CMakeLists.txt files.
|
||||
|
||||
To execute: python3 pro_conversion_rate.py <src dir>
|
||||
where <src dir> can be any qt source directory. For better statistics,
|
||||
specify a module root source dir (like ./qtbase or ./qtsvg).
|
||||
|
||||
"""
|
||||
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import os
|
||||
import typing
|
||||
from timeit import default_timer
|
||||
|
||||
|
||||
def _parse_commandline():
|
||||
parser = ArgumentParser(description='Find pro files for which there are no CMakeLists.txt.')
|
||||
parser.add_argument('source_directory', metavar='<src dir>', type=str,
|
||||
help='The source directory')
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
class Blacklist:
|
||||
""" Class to check if a certain dir_name / dir_path is blacklisted """
|
||||
|
||||
def __init__(self, names: typing.List[str], path_parts: typing.List[str]):
|
||||
self.names = names
|
||||
self.path_parts = path_parts
|
||||
|
||||
# The lookup algorithm
|
||||
self.lookup = self.is_blacklisted_part
|
||||
self.tree = None
|
||||
|
||||
try:
|
||||
# If package is available, use Aho-Corasick algorithm,
|
||||
from ahocorapy.keywordtree import KeywordTree
|
||||
self.tree = KeywordTree(case_insensitive=True)
|
||||
|
||||
for p in self.path_parts:
|
||||
self.tree.add(p)
|
||||
self.tree.finalize()
|
||||
|
||||
self.lookup = self.is_blacklisted_part_aho
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
def is_blacklisted(self, dir_name: str, dir_path: str) -> bool:
|
||||
# First check if exact dir name is blacklisted.
|
||||
if dir_name in self.names:
|
||||
return True
|
||||
|
||||
# Check if a path part is blacklisted (e.g. util/cmake)
|
||||
return self.lookup(dir_path)
|
||||
|
||||
def is_blacklisted_part(self, dir_path: str) -> bool:
|
||||
if any(part in dir_path for part in self.path_parts):
|
||||
return True
|
||||
return False
|
||||
|
||||
def is_blacklisted_part_aho(self, dir_path: str) -> bool:
|
||||
return self.tree.search(dir_path) is not None
|
||||
|
||||
|
||||
def recursive_scan(path: str, extension: str, result_paths: typing.List[str], blacklist: Blacklist):
|
||||
""" Find files ending with a certain extension, filtering out blacklisted entries """
|
||||
try:
|
||||
for entry in os.scandir(path):
|
||||
entry: os.DirEntry = entry
|
||||
|
||||
if entry.is_file() and entry.path.endswith(extension):
|
||||
result_paths.append(entry.path)
|
||||
elif entry.is_dir():
|
||||
if blacklist.is_blacklisted(entry.name, entry.path):
|
||||
continue
|
||||
recursive_scan(entry.path, extension, result_paths, blacklist)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
def check_for_cmake_project(pro_path: str) -> bool:
|
||||
pro_dir_name = os.path.dirname(pro_path)
|
||||
cmake_project_path = os.path.join(pro_dir_name, "CMakeLists.txt")
|
||||
return os.path.exists(cmake_project_path)
|
||||
|
||||
|
||||
def compute_stats(src_path: str, pros_with_missing_project: typing.List[str],
|
||||
total_pros: int, existing_pros: int, missing_pros: int) -> dict:
|
||||
stats = {}
|
||||
stats['total projects'] = {'label': 'Total pro files found',
|
||||
'value': total_pros}
|
||||
stats['existing projects'] = {'label': 'Existing CMakeLists.txt files found',
|
||||
'value': existing_pros}
|
||||
stats['missing projects'] = {'label': 'Missing CMakeLists.txt files found',
|
||||
'value': missing_pros}
|
||||
stats['missing examples'] = {'label': 'Missing examples', 'value': 0}
|
||||
stats['missing tests'] = {'label': 'Missing tests', 'value': 0}
|
||||
stats['missing src'] = {'label': 'Missing src/**/**', 'value': 0}
|
||||
stats['missing plugins'] = {'label': 'Missing plugins', 'value': 0}
|
||||
|
||||
for p in pros_with_missing_project:
|
||||
rel_path = os.path.relpath(p, src_path)
|
||||
if rel_path.startswith("examples"):
|
||||
stats['missing examples']['value'] += 1
|
||||
elif rel_path.startswith("tests"):
|
||||
stats['missing tests']['value'] += 1
|
||||
elif rel_path.startswith(os.path.join("src", "plugins")):
|
||||
stats['missing plugins']['value'] += 1
|
||||
elif rel_path.startswith("src"):
|
||||
stats['missing src']['value'] += 1
|
||||
|
||||
for stat in stats:
|
||||
if stats[stat]['value'] > 0:
|
||||
stats[stat]['percentage'] = round(stats[stat]['value'] * 100 / total_pros, 2)
|
||||
return stats
|
||||
|
||||
|
||||
def print_stats(src_path: str, pros_with_missing_project: typing.List[str], stats: dict,
|
||||
scan_time: float, script_time: float):
|
||||
|
||||
if stats['total projects']['value'] == 0:
|
||||
print("No .pro files found. Did you specify a correct source path?")
|
||||
return
|
||||
|
||||
if stats['total projects']['value'] == stats['existing projects']['value']:
|
||||
print("All projects were converted.")
|
||||
else:
|
||||
print("Missing CMakeLists.txt files for the following projects: \n")
|
||||
|
||||
for p in pros_with_missing_project:
|
||||
rel_path = os.path.relpath(p, src_path)
|
||||
print(rel_path)
|
||||
|
||||
print("\nStatistics: \n")
|
||||
|
||||
for stat in stats:
|
||||
if stats[stat]['value'] > 0:
|
||||
print("{:<40}: {} ({}%)".format(stats[stat]['label'],
|
||||
stats[stat]['value'],
|
||||
stats[stat]['percentage']))
|
||||
|
||||
print("\n{:<40}: {:.10f} seconds".format("Scan time", scan_time))
|
||||
print("{:<40}: {:.10f} seconds".format("Total script time", script_time))
|
||||
|
||||
|
||||
def main():
|
||||
args = _parse_commandline()
|
||||
src_path = os.path.abspath(args.source_directory)
|
||||
pro_paths = []
|
||||
|
||||
extension = ".pro"
|
||||
|
||||
blacklist_names = ["config.tests", "doc", "3rdparty", "angle"]
|
||||
blacklist_path_parts = [
|
||||
os.path.join("util", "cmake")
|
||||
]
|
||||
|
||||
script_start_time = default_timer()
|
||||
blacklist = Blacklist(blacklist_names, blacklist_path_parts)
|
||||
|
||||
scan_time_start = default_timer()
|
||||
recursive_scan(src_path, extension, pro_paths, blacklist)
|
||||
scan_time_end = default_timer()
|
||||
scan_time = scan_time_end - scan_time_start
|
||||
|
||||
total_pros = len(pro_paths)
|
||||
|
||||
pros_with_missing_project = []
|
||||
for pro_path in pro_paths:
|
||||
if not check_for_cmake_project(pro_path):
|
||||
pros_with_missing_project.append(pro_path)
|
||||
|
||||
missing_pros = len(pros_with_missing_project)
|
||||
existing_pros = total_pros - missing_pros
|
||||
|
||||
stats = compute_stats(src_path, pros_with_missing_project, total_pros, existing_pros,
|
||||
missing_pros)
|
||||
script_end_time = default_timer()
|
||||
script_time = script_end_time - script_start_time
|
||||
|
||||
print_stats(src_path, pros_with_missing_project, stats, scan_time, script_time)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
x
Reference in New Issue
Block a user