Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 104 additions & 63 deletions graal/backends/core/analyzers/cloc.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@
# Authors:
# Valerio Cosentino <[email protected]>
# inishchith <[email protected]>
# Groninger Bugbusters <[email protected]>
#

import os
import subprocess

from graal.graal import (GraalError,
GraalRepository)
from .analyzer import Analyzer
from graal.graal import (GraalError, GraalRepository)
from .analyzer import Analyzer, is_in_paths

DEFAULT_DIFF_TIMEOUT = 60

Expand All @@ -38,98 +39,138 @@ class Cloc(Analyzer):

:param diff_timeout: max time to compute diffs of a given file
"""
version = '0.3.0'
version = '0.3.1'

def __init__(self, diff_timeout=DEFAULT_DIFF_TIMEOUT):
def __init__(self, repository_level, diff_timeout=DEFAULT_DIFF_TIMEOUT):
self.diff_timeout = diff_timeout
self.analyze = self.analyze_repository if repository_level else self.analyze_files

def __analyze_file(self, message):
"""Add information about LOC, blank and commented lines using CLOC for a given file
def analyze_repository(self, **kwargs):
"""
Add information LOC, total files, blank and commented lines
using CLOC for the entire repository

:param message: message from standard output after execution of cloc
:param worktreepath: the directory where to store the working tree
:param in_paths: the target paths of the analysis

:returns result: dict of the results of the analysis over a file
:returns result: dict of the results of the analysis over a repository
"""

flag = False
results = {
"blanks": 0,
"comments": 0,
"loc": 0
}
worktreepath = kwargs["worktreepath"]
in_paths = kwargs["in_paths"]

for line in message.strip().split("\n"):
if flag:
if not line.startswith("-----"):
file_info = line.split()[-3:]
blank_lines, commented_lines, loc = map(int, file_info)
results["blanks"] = blank_lines
results["comments"] = commented_lines
results["loc"] = loc
break
results = []
for file_path in GraalRepository.files(worktreepath):
if in_paths:
found = [p for p in in_paths if file_path.endswith(p)]
if not found:
continue

if line.lower().startswith("language"):
flag = True
result = {
'file_path': os.path.relpath(file_path, worktreepath),
'ext': GraalRepository.extension(file_path)
}

message = self.__decode_cloc_command(file_path=file_path)
result = self.__do_cloc_analysis(message, result)
results.append(result)

return results

def __analyze_repository(self, message):
"""Add information LOC, total files, blank and commented lines using CLOC for the entire repository
def analyze_files(self, **kwargs):
"""
Add information about LOC, blank and
commented lines using CLOC for all files in the commit.

:param commit: to-be-analyzed commit
:param in_paths: the target paths of the analysis
:param worktreepath: the directory where to store the working tree

:returns result: dict of the results of the analysis over all files
"""

results = []

commit = kwargs["commit"]
in_paths = kwargs["in_paths"]
worktreepath = kwargs["worktreepath"]

for commit_file in commit["files"]:
# selects file path; source depends on whether it's new
new_file = commit_file.get("newfile", None)
file_path = new_file if new_file else commit_file['file']

if not is_in_paths(in_paths, file_path):
continue

result = {
'file_path': file_path,
'ext': GraalRepository.extension(file_path)
}

# skips deleted files.
if commit_file.get("action", None) == "D":
results.append(result)
continue

# performs analysis and updates result
local_path = os.path.join(worktreepath, file_path)
if GraalRepository.exists(local_path):
message = self.__decode_cloc_command(file_path=local_path)
result = self.__do_cloc_analysis(message, result)
results.append(result)

return results

def __do_cloc_analysis(self, message, results):
"""
Add information about LOC, blank and
commented lines using CLOC for a given file.

:param message: message from standard output after execution of cloc
:param worktreepath: the directory where to store the working tree

:returns result: dict of the results of the analysis over a repository
:returns result: dict of the results of the analysis over a file
"""

results = {}
flag = False
results.update({
"blanks": 0,
"comments": 0,
"loc": 0
})

for line in message.strip().split("\n"):
if flag:
if line.lower().startswith("sum"):
break
elif not line.startswith("-----"):
digested_split = line.split()
langauge, files_info = digested_split[:-4], digested_split[-4:]
language = " ".join(langauge)
total_files, blank_lines, commented_lines, loc = map(int, files_info)
language_result = {
"total_files": total_files,
"blanks": blank_lines,
"comments": commented_lines,
"loc": loc
}
results[language] = language_result
if not line.startswith("-----") and flag:
file_info = line.split()[-3:]
blank_lines, commented_lines, loc = map(int, file_info)
results.update({
"blanks": blank_lines,
"comments": commented_lines,
"loc": loc
})
break

if line.lower().startswith("language"):
flag = True

return results

def analyze(self, **kwargs):
"""Add information using CLOC
def __decode_cloc_command(self, file_path):
"""
Decodes CLOC command.

:param file_path: file path
:param repository_level: set to True if analysis has to be performed on a repository
:param target_path: targeted file/directory

:returns result: dict of the results of the analysis
:returns: SCC output message
"""

file_path = kwargs['file_path']
repository_level = kwargs.get('repository_level', False)

try:
cloc_command = ['cloc', file_path, '--diff-timeout', str(self.diff_timeout)]
message = subprocess.check_output(cloc_command).decode("utf-8")
except subprocess.CalledProcessError as e:
raise GraalError(cause="Cloc failed at %s, %s" % (file_path, e.output.decode("utf-8")))
return message
except subprocess.CalledProcessError as error:
cause = f"Cloc failed at {file_path}, {error.output.decode('utf-8')}"
raise GraalError(cause=cause) from error
finally:
subprocess._cleanup()

if repository_level:
results = self.__analyze_repository(message)
else:
results = self.__analyze_file(message)
results['ext'] = GraalRepository.extension(file_path)

return results
10 changes: 5 additions & 5 deletions graal/backends/core/analyzers/linguist.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
# Authors:
# inishchith <[email protected]>
# Valerio Cosentino <[email protected]>
# Groninger Bugbusters <[email protected]>
#

import subprocess
Expand All @@ -33,22 +34,22 @@ class Linguist(Analyzer):
parses the result of the analysis and returns it as a dict.
"""

version = '0.1.0'
version = '0.1.1'

def analyze(self, **kwargs):
"""Add information about code language distribution

:param repository_path: repository path
:param worktreepath: repository path
:param details: if True, it returns detailed information about single commit

:returns result: dict of the results of the analysis
"""
repository_path = kwargs['repository_path']
worktreepath = kwargs['worktreepath']
details = kwargs['details']

try:
message = subprocess.check_output(
['github-linguist', repository_path]).decode("utf-8")
['github-linguist', worktreepath]).decode("utf-8")
except subprocess.CalledProcessError as e:
message = e.output.decode("utf-8")
finally:
Expand All @@ -68,6 +69,5 @@ def analyze(self, **kwargs):
TODO: add details of breakdown at directory level
using --breakdown
'''
pass

return results
Loading