Project utils
Directory utils
Utilities related to project directory.
create_understand_database(project_dir=None, db_dir=None)
This function creates understand database for the given project directory.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
project_dir |
str |
The absolute path of project's directory. |
None |
db_dir |
str |
The absolute directory path to save Understand database (.udb or .und binary file) |
None |
Returns:
Type | Description |
---|---|
str |
Understand database path |
Source code in codart\utility\directory_utils.py
def create_understand_database(project_dir: str = None, db_dir: str = None):
"""
This function creates understand database for the given project directory.
Args:
project_dir (str): The absolute path of project's directory.
db_dir (str): The absolute directory path to save Understand database (.udb or .und binary file)
Returns:
str: Understand database path
"""
assert os.path.isdir(project_dir)
db_name = os.path.basename(os.path.normpath(project_dir)) + ".und"
db_path = os.path.join(db_dir, db_name)
# print(project_dir, db_name, db_path)
# quit()
if os.path.exists(db_path):
return db_path
# An example of command-line is:
# und create -languages c++ add @myFiles.txt analyze -all myDb.udb
understand_5_cmd = ['und', 'create', '-languages', 'Java', 'add', project_dir, 'analyze', '-all', db_path]
understand_6_cmd = ['und', 'create', '-db', db_path, '-languages', 'java']
result = subprocess.run(understand_6_cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
if result.returncode != 0:
error_ = result.stderr.decode('utf-8')
config.logger.debug(f'return code: {result.returncode} msg: {error_}')
else:
config.logger.debug(f'Understand project was created successfully!')
return db_path
export_understand_dependencies_csv(csv_path, db_path)
Exports understand dependencies into a csv file.
:param csv_path: The absolute address of csv file to generate. :param db_path: The absolute address of project path. :return: None
Source code in codart\utility\directory_utils.py
def export_understand_dependencies_csv(csv_path: str, db_path: str):
"""
Exports understand dependencies into a csv file.
:param csv_path: The absolute address of csv file to generate.
:param db_path: The absolute address of project path.
:return: None
"""
command = ['und', 'export', '-format', 'long', '-dependencies', 'class', 'csv', csv_path, db_path]
result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
trials = 0
while result.returncode != 0:
result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
error_ = result.stderr.decode('utf-8')
config.logger.debug(f'return code: {result.returncode} msg: {error_}')
trials += 1
if trials > 5:
break
config.logger.debug("Modular dependency graph (MDG.csv) was exported.")
# Try to close und.exe process if it has not been killed automatically
result = subprocess.run(['taskkill', '/f', '/im', 'und.exe'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if result.returncode != 0:
config.logger.debug('The und.exe process is not running')
else:
config.logger.debug('The und.exe process killed manually')
export_understand_dependencies_csv2(csv_path, db_path)
Exports understand dependencies into a csv file.
:param csv_path: The absolute address of csv file to generate. :param db_path: The absolute address of project path. :return: None
Source code in codart\utility\directory_utils.py
def export_understand_dependencies_csv2(csv_path: str, db_path: str):
"""
Exports understand dependencies into a csv file.
:param csv_path: The absolute address of csv file to generate.
:param db_path: The absolute address of project path.
:return: None
"""
command = ['und', 'export', '-format', 'long', '-dependencies', 'class', 'csv', csv_path, db_path]
subprocess.Popen(
command,
stdout=open(os.devnull, 'wb')
).wait()
config.logger.debug("Modular dependency graph (MDG.csv) was exported.")
git_restore(project_dir)
This function returns a git supported project back to the initial commit
Parameters:
Name | Type | Description | Default |
---|---|---|---|
project_dir |
str |
The absolute path of project's directory. |
required |
Returns:
Type | Description |
---|---|
None |
Source code in codart\utility\directory_utils.py
def git_restore(project_dir):
"""
This function returns a git supported project back to the initial commit
Args:
project_dir (str): The absolute path of project's directory.
Returns:
None
"""
assert os.path.isdir(project_dir)
assert os.path.isdir(os.path.join(project_dir, '.git'))
subprocess.Popen(["git", "restore", "."], cwd=project_dir, stdout=open(os.devnull, 'wb')).wait()
subprocess.Popen(["git", "clean", "-f", "-d"], cwd=project_dir, stdout=open(os.devnull, 'wb')).wait()
update_understand_database(udb_path)
This function updates database due to file changes. If any error, such as database is locked or read only, occurred it tries again and again to update db.
Arges:
udb_path (str): The absolute path of understand database.
Returns:
Type | Description |
---|---|
None |
Source code in codart\utility\directory_utils.py
def update_understand_database(udb_path):
"""
This function updates database due to file changes.
If any error, such as database is locked or read only, occurred it tries again and again to update db.
Arges:
udb_path (str): The absolute path of understand database.
Return:
None
"""
understand_5_cmd = ['und', 'analyze', '-rescan', '-changed', udb_path]
understand_6_cmd = ['und', 'analyze', '-changed', udb_path] # -rescan option is not required for understand >= 6.0
result = subprocess.run(understand_6_cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
# info_ = result.stdout.decode('utf-8')
# error_ = result.stderr.decode('utf-8')
# print(info_[:85])
# print(f'return code: {result.returncode} --- error: {error_}')
trials = 0
while result.returncode != 0:
try:
db: und.Db = und.open(config.UDB_PATH)
db.close()
except:
pass
finally:
result = subprocess.run(understand_6_cmd, #
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
# info_ = result.stdout.decode('utf-8')
error_ = result.stderr.decode('utf-8')
# print(info_[:85])
config.logger.debug(f'return code: {result.returncode} msg: {error_}')
trials += 1
if trials > 5:
break
# Try to close und.exe process if it has not been killed automatically
result = subprocess.run(['taskkill', '/f', '/im', 'und.exe'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if result.returncode != 0:
config.logger.debug('The und.exe process is not running')
else:
config.logger.debug('The und.exe process killed manually')
update_understand_database2(udb_path)
This function updates database due to file changes. Error message raised by understand 6.x: Error: The Analysis cannot be performed because the database is locked or read only
Arges:
udb_path (str): The absolute path of understand database.
Returns:
Type | Description |
---|---|
None |
Source code in codart\utility\directory_utils.py
def update_understand_database2(udb_path):
"""
This function updates database due to file changes.
Error message raised by understand 6.x:
Error: The Analysis cannot be performed because the database is locked or read only
Arges:
udb_path (str): The absolute path of understand database.
Return:
None
"""
understand_5_cmd = ['und', 'analyze', '-rescan', '-changed', udb_path]
understand_6_cmd = ['und', 'analyze', '-changed', udb_path] # -rescan option is not required for understand >= 6.0
subprocess.Popen(
understand_6_cmd,
stdout=open(os.devnull, 'wb')
).wait()
Performance meter
ProjectParseUsage
Source code in codart\utility\cpu_ram_usage.py
class ProjectParseUsage:
def __init__(self, project_dir):
"""
This by calling this class you can measure:
- Total consumed memory for keeping all parse trees
- Total consumed time for parsing in seconds
"""
self.project_root = project_dir
self.parse_trees = []
self.counter = 0
@staticmethod
def java_explorer(path):
result = list(Path(path).rglob("*.java"))
for file_path in result:
yield file_path.absolute()
@staticmethod
def generate_tree(file_path):
# Step 1: Load input source into stream
stream = FileStream(file_path, encoding='utf8', errors='ignore')
# Step 2: Create an instance of AssignmentStLexer
lexer = JavaLexer(stream)
# Step 3: Convert the input source into a list of tokens
token_stream = CommonTokenStream(lexer)
# Step 4: Create an instance of the AssignmentStParser
parser = JavaParser(token_stream)
# Step 5: Create parse tree
parse_tree = parser.compilationUnit()
return parse_tree
def run(self):
print("Parsing...")
total_time = 0
generator = self.java_explorer(self.project_root)
for file_path in generator:
self.counter += 1
print(f"Parsing {self.counter}: {file_path}")
start = time.time()
tree = self.generate_tree(file_path)
end = time.time()
self.parse_trees.append(tree)
total_time += end - start
print(f"Execute time is {total_time} seconds.")
print(f"Memory used for all trees is {sys.getsizeof(self.parse_trees) / 1000} KB")
__init__(self, project_dir)
special
This by calling this class you can measure: - Total consumed memory for keeping all parse trees - Total consumed time for parsing in seconds
Source code in codart\utility\cpu_ram_usage.py
def __init__(self, project_dir):
"""
This by calling this class you can measure:
- Total consumed memory for keeping all parse trees
- Total consumed time for parsing in seconds
"""
self.project_root = project_dir
self.parse_trees = []
self.counter = 0