23
23
import logging
24
24
25
25
from graal .graal import (Graal ,
26
+ GraalError ,
26
27
GraalRepository ,
27
28
GraalCommand ,
28
29
DEFAULT_WORKTREE_PATH )
29
30
from graal .backends .core .analyzers .cloc import Cloc
30
31
from graal .backends .core .analyzers .lizard import Lizard
31
32
from perceval .utils import DEFAULT_DATETIME , DEFAULT_LAST_DATETIME
32
33
33
- CATEGORY_COCOM = 'code_complexity'
34
+ LIZARD_FILE = 'lizard_file'
35
+ LIZARD_REPOSITORY = 'lizard_repository'
36
+
37
+ CATEGORY_COCOM_LIZARD_FILE = 'code_complexity_' + LIZARD_FILE
38
+ CATEGORY_COCOM_LIZARD_REPOSITORY = 'code_complexity_' + LIZARD_REPOSITORY
34
39
35
40
logger = logging .getLogger (__name__ )
36
41
@@ -70,37 +75,55 @@ class CoCom(Graal):
70
75
:raises RepositoryError: raised when there was an error cloning or
71
76
updating the repository.
72
77
"""
73
- version = '0.2.4 '
78
+ version = '0.2.5 '
74
79
75
- CATEGORIES = [CATEGORY_COCOM ]
80
+ CATEGORIES = [CATEGORY_COCOM_LIZARD_FILE ,
81
+ CATEGORY_COCOM_LIZARD_REPOSITORY ]
76
82
77
83
def __init__ (self , uri , git_path , worktreepath = DEFAULT_WORKTREE_PATH ,
78
84
entrypoint = None , in_paths = None , out_paths = None , details = False ,
79
85
tag = None , archive = None ):
80
86
super ().__init__ (uri , git_path , worktreepath ,
81
87
entrypoint = entrypoint , in_paths = in_paths , out_paths = out_paths , details = details ,
82
88
tag = tag , archive = archive )
83
- self .file_analyzer = FileAnalyzer (details )
84
89
85
- def fetch (self , category = CATEGORY_COCOM , paths = None ,
90
+ self .analyzer = None
91
+ self .analyzer_kind = None
92
+
93
+ def fetch (self , category = CATEGORY_COCOM_LIZARD_FILE , paths = None ,
86
94
from_date = DEFAULT_DATETIME , to_date = DEFAULT_LAST_DATETIME ,
87
95
branches = None , latest_items = False ):
88
96
"""Fetch commits and add code complexity information."""
89
97
90
98
items = super ().fetch (category ,
91
99
from_date = from_date , to_date = to_date ,
92
100
branches = branches , latest_items = latest_items )
101
+ if category == CATEGORY_COCOM_LIZARD_FILE :
102
+ self .analyzer_kind = LIZARD_FILE
103
+ self .analyzer = FileAnalyzer (self .details )
104
+ elif category == CATEGORY_COCOM_LIZARD_REPOSITORY :
105
+ self .analyzer_kind = LIZARD_REPOSITORY
106
+ self .analyzer = RepositoryAnalyzer (self .details )
107
+ else :
108
+ raise GraalError (cause = "Unknown category %s" % category )
93
109
94
110
return items
95
111
96
112
@staticmethod
97
113
def metadata_category (item ):
98
114
"""Extracts the category from a Code item.
99
115
100
- This backend only generates one type of item which is
101
- 'code_complexity'.
116
+ This backend generates the following types of item:
117
+ - 'code_complexity_lizard_file'.
118
+ - 'code_complexity_lizard_repository'
102
119
"""
103
- return CATEGORY_COCOM
120
+
121
+ if item ['analyzer' ] == LIZARD_FILE :
122
+ return CATEGORY_COCOM_LIZARD_FILE
123
+ elif item ['analyzer' ] == LIZARD_REPOSITORY :
124
+ return CATEGORY_COCOM_LIZARD_REPOSITORY
125
+ else :
126
+ raise GraalError (cause = "Unknown analyzer %s" % item ['analyzer' ])
104
127
105
128
def _filter_commit (self , commit ):
106
129
"""Filter a commit according to its data (e.g., author, sha, etc.)
@@ -121,51 +144,54 @@ def _filter_commit(self, commit):
121
144
122
145
def _analyze (self , commit ):
123
146
"""Analyse a commit and the corresponding
124
- checkout version of the repository
147
+ checkout version of the repository.
125
148
126
149
:param commit: a Perceval commit item
127
150
"""
128
151
analysis = []
129
152
130
- for committed_file in commit ['files' ]:
131
-
132
- file_path = committed_file ['file' ]
133
- if self .in_paths :
134
- found = [p for p in self .in_paths if file_path .endswith (p )]
135
- if not found :
136
- continue
137
-
138
- local_path = self .worktreepath + '/' + file_path
139
- if not GraalRepository .exists (local_path ):
140
- file_info = {
141
- 'blanks' : None ,
142
- 'comments' : None ,
143
- 'loc' : None ,
144
- 'ccn' : None ,
145
- 'avg_ccn' : None ,
146
- 'avg_loc' : None ,
147
- 'avg_tokens' : None ,
148
- 'num_funs' : None ,
149
- 'tokens' : None ,
150
- 'file_path' : file_path ,
151
- }
152
- if self .details :
153
- file_info ['funs' ] = []
154
-
155
- if committed_file .get ("newfile" , None ):
156
- file_path = committed_file ["newfile" ]
157
- local_path = self .worktreepath + '/' + file_path
158
- analysis .append (file_info )
159
- elif committed_file .get ("action" , None ) == "D" :
160
- analysis .append (file_info )
161
- continue
162
- else :
163
- continue
164
-
165
- file_info = self .file_analyzer .analyze (local_path )
166
- file_info .update ({'file_path' : file_path })
167
- analysis .append (file_info )
168
-
153
+ if self .analyzer_kind == LIZARD_FILE :
154
+ for committed_file in commit ['files' ]:
155
+
156
+ file_path = committed_file ['file' ]
157
+ if self .in_paths :
158
+ found = [p for p in self .in_paths if file_path .endswith (p )]
159
+ if not found :
160
+ continue
161
+
162
+ local_path = self .worktreepath + '/' + file_path
163
+ if not GraalRepository .exists (local_path ):
164
+ file_info = {
165
+ 'blanks' : None ,
166
+ 'comments' : None ,
167
+ 'loc' : None ,
168
+ 'ccn' : None ,
169
+ 'avg_ccn' : None ,
170
+ 'avg_loc' : None ,
171
+ 'avg_tokens' : None ,
172
+ 'num_funs' : None ,
173
+ 'tokens' : None ,
174
+ 'file_path' : file_path ,
175
+ }
176
+ if self .details :
177
+ file_info ['funs' ] = []
178
+
179
+ if committed_file .get ("newfile" , None ):
180
+ file_path = committed_file ["newfile" ]
181
+ local_path = self .worktreepath + '/' + file_path
182
+ analysis .append (file_info )
183
+ elif committed_file .get ("action" , None ) == "D" :
184
+ analysis .append (file_info )
185
+ continue
186
+ else :
187
+ continue
188
+
189
+ file_info = self .analyzer .analyze (local_path )
190
+ file_info .update ({'file_path' : file_path })
191
+ analysis .append (file_info )
192
+ else :
193
+ files_affected = [file_info ['file' ] for file_info in commit ['files' ]]
194
+ analysis = self .analyzer .analyze (self .worktreepath , files_affected )
169
195
return analysis
170
196
171
197
def _post (self , commit ):
@@ -176,6 +202,8 @@ def _post(self, commit):
176
202
commit .pop ('files' , None )
177
203
commit .pop ('parents' , None )
178
204
commit .pop ('refs' , None )
205
+ commit ['analyzer' ] = self .analyzer_kind
206
+
179
207
return commit
180
208
181
209
@@ -192,7 +220,7 @@ def __init__(self, details=False):
192
220
self .lizard = Lizard ()
193
221
194
222
def analyze (self , file_path ):
195
- """Analyze the content of a file using CLOC and Lizard
223
+ """Analyze the content of a file using CLOC and Lizard.
196
224
197
225
:param file_path: file path
198
226
@@ -227,6 +255,43 @@ def analyze(self, file_path):
227
255
return lizard_analysis
228
256
229
257
258
+ class RepositoryAnalyzer :
259
+ """Class to analyse the content of a repository"""
260
+
261
+ def __init__ (self , details = False ):
262
+ self .details = details
263
+ self .lizard = Lizard ()
264
+
265
+ def analyze (self , repository_path , files_affected ):
266
+ """Analyze the content of a repository using CLOC and Lizard.
267
+
268
+ :param repository_path: repository path
269
+
270
+ :returns a list containing the results of the analysis
271
+ [ {
272
+ 'loc': ..,
273
+ 'ccn': ..,
274
+ 'tokens': ..,
275
+ 'num_funs': ..,
276
+ 'file_path': ..,
277
+ 'in_commit': ..,
278
+ 'blanks': ..,
279
+ 'comments': ..,
280
+ },
281
+ ...
282
+ ]
283
+ """
284
+ kwargs = {
285
+ 'repository_path' : repository_path ,
286
+ 'repository_level' : True ,
287
+ 'files_affected' : files_affected ,
288
+ 'details' : self .details
289
+ }
290
+ lizard_analysis = self .lizard .analyze (** kwargs )
291
+
292
+ return lizard_analysis
293
+
294
+
230
295
class CoComCommand (GraalCommand ):
231
296
"""Class to run CoCom backend from the command line."""
232
297
0 commit comments