Skip to content

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