1212import attr
1313import fingerprints
1414from commoncode .cliutils import POST_SCAN_GROUP , PluggableCommandLineOption
15- from plugincode .post_scan import PostScanPlugin , post_scan_impl
1615from license_expression import Licensing
16+ from plugincode .post_scan import PostScanPlugin , post_scan_impl
17+
1718from cluecode .copyrights import CopyrightDetector
1819from packagedcode .utils import combine_expressions
19- from summarycode .copyright_summary import canonical_holder
2020from summarycode .score import (compute_license_score ,
2121 get_field_values_from_codebase_resources ,
2222 unique )
23- from summarycode .utils import ( get_resource_summary , set_resource_summary ,
24- sorted_counter )
23+ from summarycode .tallies import compute_codebase_tallies
24+
2525
2626# Tracing flags
27- TRACE = False
27+ TRACE = True
2828TRACE_LIGHT = False
2929
3030
@@ -72,11 +72,11 @@ def is_enabled(self, summary, **kwargs):
7272 def process_codebase (self , codebase , summary , ** kwargs ):
7373 if TRACE_LIGHT : logger_debug ('ScanSummary:process_codebase' )
7474
75- # Get summary data
76- summary = summarize_codebase (codebase , keep_details = False , ** kwargs )
77- license_expressions_summary = summary .get ('license_expressions' ) or []
78- holders_summary = summary .get ('holders' ) or []
79- programming_language_summary = summary .get ('programming_language' ) or []
75+ # Get tallies
76+ tallies = compute_codebase_tallies (codebase , keep_details = False , ** kwargs )
77+ license_expressions_tallies = tallies .get ('license_expressions' ) or []
78+ holders_tallies = tallies .get ('holders' ) or []
79+ programming_language_tallies = tallies .get ('programming_language' ) or []
8080
8181 # Get Package data from key files
8282 key_files_package_data = get_field_values_from_codebase_resources (
@@ -100,15 +100,15 @@ def process_codebase(self, codebase, summary, **kwargs):
100100 # If we did not get a declared license expression from detected
101101 # package data, then we use the results from `compute_license_score`
102102 scoring_elements , declared_license_expression = compute_license_score (codebase )
103- other_license_expressions = remove_from_summary (declared_license_expression , license_expressions_summary )
103+ other_license_expressions = remove_from_tallies (declared_license_expression , license_expressions_tallies )
104104
105105 if not declared_holder :
106- declared_holder = get_declared_holder (codebase , holders_summary )
107- other_holders = remove_from_summary (declared_holder , holders_summary )
106+ declared_holder = get_declared_holder (codebase , holders_tallies )
107+ other_holders = remove_from_tallies (declared_holder , holders_tallies )
108108
109109 if not primary_language :
110- primary_language = get_primary_language (programming_language_summary )
111- other_languages = remove_from_summary (primary_language , programming_language_summary )
110+ primary_language = get_primary_language (programming_language_tallies )
111+ other_languages = remove_from_tallies (primary_language , programming_language_tallies )
112112
113113 # Save summary info to codebase
114114 codebase .attributes .summary ['declared_license_expression' ] = declared_license_expression
@@ -120,215 +120,23 @@ def process_codebase(self, codebase, summary, **kwargs):
120120 codebase .attributes .summary ['other_languages' ] = other_languages
121121
122122
123- def remove_from_summary (entry , summary_data ):
123+ def remove_from_tallies (entry , tallies ):
124124 """
125- Return an list containing the elements of `summary_data `, without `entry`
125+ Return an list containing the elements of `tallies `, without `entry`
126126 """
127- pruned_summary_data = []
128- for s in summary_data :
127+ pruned_tallies = []
128+ for t in tallies :
129129 if (
130- isinstance (entry , dict ) and s == entry
131- or isinstance (entry , (list , tuple )) and s in entry
132- or s .get ('value' ) == entry
130+ isinstance (entry , dict ) and t == entry
131+ or isinstance (entry , (list , tuple )) and t in entry
132+ or t .get ('value' ) == entry
133133 ):
134134 continue
135- pruned_summary_data .append (s )
136- return pruned_summary_data
137-
138-
139- def summarize_codebase (codebase , keep_details , ** kwargs ):
140- """
141- Summarize a scan at the codebase level for available scans.
142-
143- If `keep_details` is True, also keep file and directory details in the
144- `summary` file attribute for every file and directory.
145-
146- If `legacy` is True, summarize copyrights, authors, programming languages,
147- and packages.
148- """
149- from summarycode .copyright_summary import holder_summarizer
150-
151- attrib_summarizers = [
152- ('license_expressions' , license_summarizer ),
153- ('holders' , holder_summarizer ),
154- ('programming_language' , language_summarizer ),
155- ]
156-
157- # find which attributes are available for summarization by checking the root
158- # resource
159- root = codebase .root
160- summarizers = [s for a , s in attrib_summarizers if hasattr (root , a )]
161- if TRACE : logger_debug ('summarize_codebase with summarizers:' , summarizers )
162-
163- # collect and set resource-level summaries
164- for resource in codebase .walk (topdown = False ):
165- children = resource .children (codebase )
166-
167- for summarizer in summarizers :
168- _summary_data = summarizer (resource , children , keep_details = keep_details )
169- if TRACE : logger_debug ('summary for:' , resource .path , 'after summarizer:' , summarizer , 'is:' , _summary_data )
170-
171- codebase .save_resource (resource )
172-
173- # set the summary from the root resource at the codebase level
174- if keep_details :
175- summary = root .summary
176- else :
177- summary = root .extra_data .get ('summary' , {})
178-
179- if TRACE : logger_debug ('codebase summary:' , summary )
180-
181- return summary
182-
183-
184- def license_summarizer (resource , children , keep_details = False ):
185- """
186- Populate a license_expressions list of mappings such as
187- {value: "expression", count: "count of occurences"}
188- sorted by decreasing count.
189- """
190- LIC_EXP = 'license_expressions'
191- license_expressions = []
192-
193- # Collect current data
194- lic_expressions = getattr (resource , LIC_EXP , [])
195- if not lic_expressions and resource .is_file :
196- # also count files with no detection
197- license_expressions .append (None )
198- else :
199- license_expressions .extend (lic_expressions )
200-
201- # Collect direct children expression summary
202- for child in children :
203- child_summaries = get_resource_summary (child , key = LIC_EXP , as_attribute = keep_details ) or []
204- for child_summary in child_summaries :
205- # TODO: review this: this feels rather weird
206- child_sum_val = child_summary .get ('value' )
207- if child_sum_val :
208- values = [child_sum_val ] * child_summary ['count' ]
209- license_expressions .extend (values )
210-
211- # summarize proper
212- licenses_counter = summarize_licenses (license_expressions )
213- summarized = sorted_counter (licenses_counter )
214- set_resource_summary (resource , key = LIC_EXP , value = summarized , as_attribute = keep_details )
215- return summarized
216-
217-
218- def summarize_licenses (license_expressions ):
219- """
220- Given a list of license expressions, return a mapping of {expression: count
221- of occurences}
222- """
223- # TODO: we could normalize and/or sort each license_expression before
224- # summarization and consider other equivalence or containment checks
225- return Counter (license_expressions )
226-
227-
228- def language_summarizer (resource , children , keep_details = False ):
229- """
230- Populate a programming_language summary list of mappings such as
231- {value: "programming_language", count: "count of occurences"}
232- sorted by decreasing count.
233- """
234- PROG_LANG = 'programming_language'
235- languages = []
236- prog_lang = getattr (resource , PROG_LANG , [])
237- if not prog_lang :
238- if resource .is_file :
239- # also count files with no detection
240- languages .append (None )
241- else :
242- languages .append (prog_lang )
243-
244- # Collect direct children expression summaries
245- for child in children :
246- child_summaries = get_resource_summary (child , key = PROG_LANG , as_attribute = keep_details ) or []
247- for child_summary in child_summaries :
248- child_sum_val = child_summary .get ('value' )
249- if child_sum_val :
250- values = [child_sum_val ] * child_summary ['count' ]
251- languages .extend (values )
252-
253- # summarize proper
254- languages_counter = summarize_languages (languages )
255- summarized = sorted_counter (languages_counter )
256- set_resource_summary (resource , key = PROG_LANG , value = summarized , as_attribute = keep_details )
257- return summarized
258-
259-
260- def summarize_languages (languages ):
261- """
262- Given a list of languages, return a mapping of {language: count
263- of occurences}
264- """
265- # TODO: consider aggregating related langauges (C/C++, etc)
266- return Counter (languages )
267-
268-
269- SUMMARIZABLE_ATTRS = set ([
270- 'license_expressions' ,
271- 'copyrights' ,
272- 'holders' ,
273- 'authors' ,
274- 'programming_language' ,
275- # 'packages',
276- ])
277-
278-
279- def add_files (packages , resource ):
280- """
281- Update in-place every package mapping in the `packages` list by updating or
282- creating the the "files" attribute from the `resource`. Yield back the
283- packages.
284- """
285- for package in packages :
286- files = package ['files' ] = package .get ('files' ) or []
287- fil = resource .to_dict (skinny = True )
288- if fil not in files :
289- files .append (fil )
290- yield package
291-
292-
293- def package_summarizer (resource , children , keep_details = False ):
294- """
295- Populate a packages summary list of packages mappings.
296-
297- Note: `keep_details` is never used, as we are not keeping details of
298- packages as this has no value.
299- """
300- packages = []
301-
302- # Collect current data
303- current_packages = getattr (resource , 'packages' ) or []
304-
305- if TRACE_LIGHT and current_packages :
306- from packagedcode .models import Package
307- packs = [Package .create (** p ) for p in current_packages ]
308- logger_debug ('package_summarizer: for:' , resource ,
309- 'current_packages are:' , packs )
310-
311- current_packages = add_files (current_packages , resource )
312- packages .extend (current_packages )
313-
314- if TRACE_LIGHT and packages :
315- logger_debug ()
316- from packagedcode .models import Package # NOQA
317- packs = [Package .create (** p ) for p in packages ]
318- logger_debug ('package_summarizer: for:' , resource ,
319- 'packages are:' , packs )
320-
321- # Collect direct children packages summary
322- for child in children :
323- child_summaries = get_resource_summary (child , key = 'packages' , as_attribute = False ) or []
324- packages .extend (child_summaries )
325-
326- # summarize proper
327- set_resource_summary (resource , key = 'packages' , value = packages , as_attribute = False )
328- return packages
135+ pruned_tallies .append (t )
136+ return pruned_tallies
329137
330138
331- def get_declared_holder (codebase , holders_summary ):
139+ def get_declared_holder (codebase , holders_tallies ):
332140 """
333141 Determine the declared holders of a codebase from the holders detected from
334142 key files.
@@ -338,7 +146,7 @@ def get_declared_holder(codebase, holders_summary):
338146 """
339147 entry_by_holders = {
340148 fingerprints .generate (entry ['value' ]): entry
341- for entry in holders_summary if entry ['value' ]
149+ for entry in holders_tallies if entry ['value' ]
342150 }
343151 key_file_holders = get_field_values_from_codebase_resources (codebase , 'holders' , key_files_only = True )
344152 entry_by_key_file_holders = {
@@ -367,13 +175,13 @@ def get_declared_holder(codebase, holders_summary):
367175 return declared_holder
368176
369177
370- def get_primary_language (programming_language_summary ):
178+ def get_primary_language (programming_language_tallies ):
371179 """
372180 Return the most common detected programming language as the primary language.
373181 """
374182 programming_languages_by_count = {
375183 entry ['count' ]: entry ['value' ]
376- for entry in programming_language_summary
184+ for entry in programming_language_tallies
377185 }
378186 primary_language = ''
379187 if programming_languages_by_count :
0 commit comments