User:Bugman/subsystems: Difference between revisions
Jump to navigation
Jump to search
m (Sectioning.) |
(→Script: Newest version of the script.) |
||
Line 7: | Line 7: | ||
{{collapsible script | {{collapsible script | ||
| type = Python script | | type = Python script | ||
| title = Python script for finding all subsystems within the C++ code | | title = Python script for finding all subsystems within the flightgear and simgear C++ code bases. | ||
| intro = This script requires the ''grep'' Unix command, which can be installed on any OS. And it must be run with Python3. | |||
| lang = python | | lang = python | ||
| script = | | script = | ||
#! /usr/bin/env python3 | #! /usr/bin/env python3 | ||
# Python module imports. | |||
import operator | import operator | ||
from re import search, split | from re import search, split | ||
from subprocess import PIPE, Popen | from subprocess import PIPE, Popen | ||
import sys | |||
# Source code repository paths. | |||
SIMGEAR_PATH = "/flightgear/src/flightgear-simgear" | |||
FLIGHTGEAR_PATH = "/flightgear/src/flightgear-flightgear" | |||
class FindSubsystems: | class FindSubsystems: | ||
"""Class for finding all subsystems and subsystem groups.""" | |||
def __init__(self): | def __init__(self): | ||
"""Find all subsystems and subsystem groups.""" | |||
# SGSubsystem storage lists. | |||
self.subsystems = [[], [], [], []] | |||
self.groups = [[], [], [], []] | |||
# The base objects. | |||
subsystem_base = Subsystem("SGSubsystem") | |||
group_base = Subsystem("SGSubsystemGroup", base_class=Subsystem("SGSubsystem")) | |||
# Add some problematic non-parsable classes. | |||
self.subsystems[1].append(Subsystem("FGAISim", base_class=Subsystem("FGInterface", base_class=Subsystem("SGSubsystem")), file_name="src/FDM/SP/AISim.hpp")) | |||
# Find all SGSubsystem and SGSubsystemGroup derived classes. | |||
paths = [SIMGEAR_PATH, FLIGHTGEAR_PATH] | |||
printout = [False, True] | |||
for i in range(len(paths)): | |||
self.find_primary(path=paths[i], text="classes", primary=self.subsystems[0], base_name="SGSubsystem", base=subsystem_base, skip=["SGSubsystemGroup"], printout=printout[i]) | |||
self.find_primary(path=paths[i], text="groups", primary=self.groups[0], base_name="SGSubsystemGroup", base=group_base, printout=printout[i]) | |||
self.find_secondary(path=paths[i], text="classes", primary=self.subsystems[0], secondary=self.subsystems[1], printout=printout[i]) | |||
self.find_secondary(path=paths[i], text="groups", primary=self.groups[0], secondary=self.groups[1], printout=printout[i]) | |||
self.find_tertiary(path=paths[i], text="classes", secondary=self.subsystems[1], tertiary=self.subsystems[2], printout=printout[i]) | |||
self.find_tertiary(path=paths[i], text="groups", secondary=self.groups[1], tertiary=self.groups[2], printout=printout[i]) | |||
self.find_quaternary(path=paths[i], text="classes", tertiary=self.subsystems[2], quaternary=self.subsystems[3], printout=printout[i]) | |||
self.find_quaternary(path=paths[i], text="groups", tertiary=self.groups[2], quaternary=self.groups[3], printout=printout[i]) | |||
# Final summary. | |||
print("\nTotal: %i subsystem classes." % len(self.subsystems[0] + self.subsystems[1] + self.subsystems[2] + self.subsystems[3])) | |||
print("Total: %i subsystem groups." % len(self.groups[0] + self.groups[1] + self.groups[2] + self.groups[3])) | |||
def count(self, storage_list): | |||
"""Count the number of subsystems and subsystem groups. | |||
@param storage_list: The data structure to count. | |||
@type storage_list: list of Subsystem instances | |||
@return: The number of subsystems and number of groups. | |||
@rtype: int, int | |||
""" | |||
# Init. | # Init. | ||
subsystems = 0 | |||
groups = 0 | |||
for element in storage_list: | |||
if element.is_group(): | |||
groups += 1 | |||
else: | |||
subsystems += 1 | |||
# Return the counts. | |||
return subsystems, groups | |||
def find_primary(self, path=None, text=None, primary=None, base_name=None, base=None, skip=[], printout=False): | |||
"""Find all primary subsystems and groups | |||
@keyword path: The path to the repository to search through. | |||
@type path: str | |||
for | @keyword text: Text identifying subsystems vs. subsystem groups. | ||
@type text: str | |||
if self. | @keyword primary: The primary list of subsystems or groups. | ||
print("\ | @type primary: list of Subsystem instances | ||
for subsystem in | @keyword base_name: The name of the base class. | ||
@type base_name: str | |||
@keyword base: The base class object. | |||
@type base: Subsystem instance | |||
@keyword skip: A list of class names to skip. | |||
@type skip: list of str | |||
@keyword printout: A flag which if True will activate the printout of subsystems. | |||
@type printout: bool | |||
""" | |||
# Find all subsystems or groups. | |||
for file_name, class_name in self.grep(path=path, base_name=base_name): | |||
if class_name in skip: | |||
continue | |||
primary.append(Subsystem(class_name, base_class=base, file_name=file_name)) | |||
# Sort the subsystems by name. | |||
primary.sort(key=operator.attrgetter('name')) | |||
# Printout. | |||
if printout: | |||
counts = self.count(primary) | |||
print("\nPrimary %s (%i subsystems, %i groups):" % (text, counts[0], counts[1])) | |||
for subsystem in primary: | |||
print(" %s" % subsystem) | print(" %s" % subsystem) | ||
if self. | |||
print("\ | |||
for subsystem in | def find_secondary(self, path=None, text=None, primary=None, secondary=None, printout=False): | ||
"""Find all secondary subsystems and groups | |||
@keyword path: The path to the repository to search through. | |||
@type path: str | |||
@keyword text: Text identifying subsystems vs. subsystem groups. | |||
@type text: str | |||
@keyword primary: The primary list of subsystems or groups. | |||
@type primary: list of Subsystem instances | |||
@keyword secondary: The secondary list of subsystems or groups. | |||
@type secondary: list of Subsystem instances | |||
@keyword printout: A flag which if True will activate the printout of subsystems. | |||
@type printout: bool | |||
""" | |||
# Loop over all primary subsystems. | |||
for subsystem in primary: | |||
for file_name, derived_class in self.grep(path=path, base_name=subsystem.name): | |||
secondary.append(Subsystem(derived_class, base_class=subsystem, file_name=file_name)) | |||
# Sort the subsystems by name. | |||
secondary.sort(key=operator.attrgetter('name')) | |||
# Printout. | |||
if printout and secondary: | |||
counts = self.count(secondary) | |||
print("\nSecondary %s (%i subsystems, %i groups):" % (text, counts[0], counts[1])) | |||
for subsystem in secondary: | |||
print(" %s" % subsystem) | print(" %s" % subsystem) | ||
if self. | |||
print("\ | |||
for subsystem in | def find_tertiary(self, path=None, text=None, secondary=None, tertiary=None, printout=False): | ||
"""Find all tertiary subsystems and groups | |||
@keyword path: The path to the repository to search through. | |||
@type path: str | |||
@keyword text: Text identifying subsystems vs. subsystem groups. | |||
@type text: str | |||
@keyword secondary: The secondary list of subsystems or groups. | |||
@type secondary: list of Subsystem instances | |||
@keyword tertiary: The tertiary list of subsystems or groups. | |||
@type tertiary: list of Subsystem instances | |||
@keyword printout: A flag which if True will activate the printout of subsystems. | |||
@type printout: bool | |||
""" | |||
# Loop over all secondary subsystems. | |||
for subsystem in secondary: | |||
for file_name, derived_class in self.grep(path=path, base_name=subsystem.name): | |||
tertiary.append(Subsystem(derived_class, base_class=subsystem, file_name=file_name)) | |||
# Sort all subsystems by name. | |||
tertiary.sort(key=operator.attrgetter('name')) | |||
# Printout. | |||
if printout and tertiary: | |||
counts = self.count(tertiary) | |||
print("\nTertiary %s (%i subsystems, %i groups):" % (text, counts[0], counts[1])) | |||
for subsystem in tertiary: | |||
print(" %s" % subsystem) | print(" %s" % subsystem) | ||
def | def find_quaternary(self, path=None, text=None, tertiary=None, quaternary=None, printout=False): | ||
"""Find all tertiary subsystems and groups | |||
@keyword path: The path to the repository to search through. | |||
@type path: str | |||
@keyword text: Text identifying subsystems vs. subsystem groups. | |||
@type text: str | |||
@keyword tertiary: The tertiary list of subsystems or groups. | |||
@type tertiary: list of Subsystem instances | |||
@keyword quaternary: The quaternary list of subsystems or groups. | |||
@type quaternary: list of Subsystem instances | |||
@keyword printout: A flag which if True will activate the printout of subsystems. | |||
@type printout: bool | |||
""" | |||
# Loop over all tertiary subsystems. | |||
for subsystem in | for subsystem in tertiary: | ||
for file_name, derived_class in self.grep(subsystem.name): | for file_name, derived_class in self.grep(path=path, base_name=subsystem.name): | ||
quaternary.append(Subsystem(derived_class, base_class=subsystem, file_name=file_name)) | |||
# Sort all subsystems by name. | |||
quaternary.sort(key=operator.attrgetter('name')) | |||
# Printout. | |||
if printout and quaternary: | |||
counts = self.count(quaternary) | |||
print("\nQuaternary %s (%i subsystems, %i groups):" % (text, counts[0], counts[1])) | |||
for subsystem in quaternary: | |||
print(" %s" % subsystem) | |||
def | def grep(self, path=None, base_name=None): | ||
for | """Generator method for finding all classes derived from the given base name and repository. | ||
@keyword path: The path to the repository to search through. | |||
@type path: str | |||
@keyword base_name: The name of the base class. | |||
@type base_name: str | |||
@return: The source file and the name of the derived class. | |||
@rtype: str, str | |||
""" | |||
# The Unix grep command to run. | |||
cmd = 'grep -rI "public \<%s\>" | cmd = 'cd %s; grep -rI "public \<%s\>" | grep -v "%s::"' % (path, base_name, base_name) | ||
pipe = Popen(cmd, shell=True, stdout=PIPE) | pipe = Popen(cmd, shell=True, stdout=PIPE) | ||
# Read all output. | |||
for line in pipe.stdout.readlines(): | for line in pipe.stdout.readlines(): | ||
# Convert the byte-array. | |||
line = line.decode() | line = line.decode() | ||
# Skip this script. | |||
if search("grep ", line): | if search("grep ", line): | ||
continue | continue | ||
# Cannot handle this line! | |||
if not search("class ", line): | if not search("class ", line): | ||
sys.stderr.write("\nSkipping: %s\n" % repr(line[:-1])) | |||
continue | continue | ||
# Split by single colons. | |||
elements = split("(?<!:):(?!:)", line) | elements = split("(?<!:):(?!:)", line) | ||
# The file and class name. | |||
file_name = elements[0] | file_name = elements[0] | ||
class_name = elements[1] | class_name = elements[1] | ||
class_name = class_name.replace("class", "") | class_name = class_name.replace("class", "") | ||
class_name = class_name.strip() | class_name = class_name.strip() | ||
# Generator method. | |||
yield file_name, class_name | yield file_name, class_name | ||
Line 100: | Line 258: | ||
class Subsystem: | class Subsystem: | ||
"""Object for storing the information for a specific subsystem.""" | |||
def __init__(self, name, base_class=None, file_name=None): | def __init__(self, name, base_class=None, file_name=None): | ||
"""Set up the object. | |||
@param name: The name of the subsystem. | |||
@type name: str | |||
@keyword base_class: The name of the base class. | |||
@type base_class: str | |||
@keyword file_name: The name of the file containing the subsystem declaration. | |||
@type file_name: str | |||
""" | |||
# Store the data. | |||
self.name = name | self.name = name | ||
self.base_class = base_class | self.base_class = base_class | ||
Line 107: | Line 278: | ||
def __repr__(self): | def __repr__(self): | ||
"""Overwrite the string representation of the object. | |||
@return: The string representation. | |||
@rtype: str | |||
""" | |||
# The subsystem name. | |||
string = "<%s" % self.name | string = "<%s" % self.name | ||
# The inheritance chain. | |||
if self.base_class: | if self.base_class: | ||
string += " | string += " : %s" % self.base_class.name | ||
if self.base_class.base_class: | if self.base_class.base_class: | ||
string += " : %s" % self.base_class.base_class.name | string += " : %s" % self.base_class.base_class.name | ||
Line 116: | Line 296: | ||
if self.base_class.base_class.base_class.base_class: | if self.base_class.base_class.base_class.base_class: | ||
string += " : %s" % self.base_class.base_class.base_class.base_class.name | string += " : %s" % self.base_class.base_class.base_class.base_class.name | ||
if self.base_class.base_class.base_class.base_class.base_class: | |||
string += " : %s" % self.base_class.base_class.base_class.base_class.base_class.name | |||
# Add the source file name. | |||
string += " in %s" % repr(self.file_name) | |||
# Closure. | |||
string += ">" | string += ">" | ||
# Return the representation. | |||
return string | return string | ||
def is_group(self): | |||
"""Determine this is a subsystem or subsystem group. | |||
@return: True if this is a subsystem group. | |||
@rtype: bool | |||
""" | |||
# Chase the base name as far as possible. | |||
if self.name == "SGSubsystemGroup": | |||
return True | |||
if self.base_class.name == "SGSubsystemGroup": | |||
return True | |||
if self.base_class.base_class: | |||
if self.base_class.base_class.name == "SGSubsystemGroup": | |||
return True | |||
if self.base_class.base_class.base_class: | |||
if self.base_class.base_class.base_class.name == "SGSubsystemGroup": | |||
return True | |||
if self.base_class.base_class.base_class.base_class: | |||
if self.base_class.base_class.base_class.base_class.name == "SGSubsystemGroup": | |||
return True | |||
if self.base_class.base_class.base_class.base_class.base_class: | |||
if self.base_class.base_class.base_class.base_class.name.base_class.name == "SGSubsystemGroup": | |||
return True | |||
# A normal subsystem. | |||
return False | |||
# Instantiate the class if run as a script. | |||
if __name__ == "__main__": | if __name__ == "__main__": | ||
FindSubsystems() | FindSubsystems() |
Revision as of 10:07, 18 April 2018
Tracking down subsystems
Script
The following script is for finding all FlightGear dependencies:
Python script: Python script for finding all subsystems within the flightgear and simgear C++ code bases.
All subsystems
The result is:
Text output: Output from the Python script for finding all subsystems within the C++ code base.
Refactoring
To check that all subsystems on a branch have been updated or refactored:
Python script: Python script verifying if all subsystems have been updated.