3232
3333import attr
3434
35+ from packagedcode .utils import combine_expressions
3536from plugincode .post_scan import PostScanPlugin
3637from plugincode .post_scan import post_scan_impl
3738from scancode import CommandLineOption
3839from scancode import POST_SCAN_GROUP
3940
4041
42+ # Tracing flags
43+ TRACE = True
44+
45+
46+ def logger_debug (* args ):
47+ pass
48+
49+
50+ if TRACE :
51+ import logging
52+ import sys
53+
54+ logger = logging .getLogger (__name__ )
55+ # logging.basicConfig(level=logging.DEBUG, stream=sys.stdout)
56+ logging .basicConfig (stream = sys .stdout )
57+ logger .setLevel (logging .DEBUG )
58+
59+ def logger_debug (* args ):
60+ return logger .debug (
61+ ' ' .join (isinstance (a , unicode ) and a or repr (a ) for a in args ))
62+
63+
4164@post_scan_impl
4265class OriginSummary (PostScanPlugin ):
4366 """
@@ -46,24 +69,27 @@ class OriginSummary(PostScanPlugin):
4669 """
4770 resource_attributes = dict (
4871 origin_summary = attr .ib (default = attr .Factory (OrderedDict )),
49- is_summary = attr .ib (default = False , type = bool ),
50- is_summarized = attr .ib (default = False , type = bool )
72+ summarized_to = attr .ib (default = None , type = str )
5173 )
5274
5375 sort_order = 8
5476
5577 options = [
5678 CommandLineOption (('--origin-summary' ,),
5779 is_flag = True , default = False ,
58- required_options = ['copyright' ,'license' ],
5980 help = 'Origin summary' ,
6081 help_group = POST_SCAN_GROUP )
6182 ]
6283
63- def is_enabled (self , origin_summary , copyright , license , ** kwargs ):
64- return origin_summary and copyright and license
84+ def is_enabled (self , origin_summary , ** kwargs ):
85+ return origin_summary
6586
6687 def process_codebase (self , codebase , ** kwargs ):
88+ root = codebase .get_resource (0 )
89+ if not hasattr (root , 'copyrights' ) or not hasattr (root , 'licenses' ):
90+ # TODO: Raise warning(?) if these fields are not there
91+ return
92+
6793 for resource in codebase .walk (topdown = False ):
6894 # TODO: Consider facets for later
6995 # TODO: Group summarizations by copyright holders and license expressions
@@ -75,64 +101,43 @@ def process_codebase(self, codebase, **kwargs):
75101 if not children :
76102 continue
77103
78- dir_license_expressions_count = Counter ()
79- dir_holders_count = Counter ()
104+ # TODO: Consider using a list of resource id's to avoid walking a codebase multiple times
105+ origin_count = Counter ()
80106
81107 for child in children :
82- for license_expression in child .license_expressions :
83- if child .is_file :
84- license_expressions_count = 1
85- else :
86- child_license_expressions_count = child .origin_summary .get ('license_expressions' )
87- license_expressions_count = child_license_expressions_count [license_expression ]
88- dir_license_expressions_count .update ({license_expression : license_expressions_count })
89-
90- for holder in child .holders :
91- holder_value = holder ['value' ]
92- if child .is_file :
93- holder_count = 1
94- else :
95- child_holders_count = child .origin_summary .get ('holders' )
96- holder_count = child_holders_count [holder_value ]
97- dir_holders_count .update ({holder_value : holder_count })
98-
99- file_count = resource .files_count
100-
101- # TODO: Check for contradictions when performing summarizations
102- for k , v in dir_license_expressions_count .items ():
103- if is_majority (v , file_count ):
104- resource .license_expressions .append (k )
105- resource .is_summary = True
108+ if child .is_file :
109+ license_expression = combine_expressions (child .license_expressions )
110+ holders = tuple (h ['value' ] for h in child .holders if h ['value' ])
111+ if not license_expression or not holders :
112+ continue
113+ origin = holders , license_expression
114+ origin_count [origin ] += 1
115+ else :
116+ # We are in a subdirectory
117+ child_origin_count = child .extra_data .get ('origin_count' , {})
118+ origin_count .update (child_origin_count )
119+
120+ if origin_count :
121+ resource .extra_data ['origin_count' ] = origin_count
122+ resource .save (codebase )
123+ (holders , license_expression ), top_count = origin_count .most_common (1 )[0 ]
124+ # TODO: Check for contradictions when performing summarizations
125+ if is_majority (top_count , resource .files_count ):
126+ resource .origin_summary ['license_expression' ] = license_expression
127+ resource .origin_summary ['holders' ] = holders
128+ resource .origin_summary ['count' ] = top_count
106129 codebase .save_resource (resource )
107130
108- for k , v in dir_holders_count .items ():
109- if is_majority (v , file_count ):
110- resource .holders .append (OrderedDict (value = k , start_line = None , end_line = None ))
111- resource .is_summary = True
112- codebase .save_resource (resource )
113-
114- resource .origin_summary ['license_expressions' ] = dir_license_expressions_count
115- resource .origin_summary ['holders' ] = dir_holders_count
116- codebase .save_resource (resource )
117-
118- # Pass 2: tag the Resources that have been summarized
119- for resource in codebase .walk (topdown = True ):
120- if resource .is_file or not resource .is_summary :
121- continue
122-
123- children = resource .children (codebase )
124- if not children :
125- continue
126-
127- # TODO: There's probably a more pleasing way to do this
128- for child in children :
129- for child_license_expression in child .license_expressions :
130- for child_holder in child .holders :
131- for resource_holder in resource .holders :
132- if (child_license_expression in resource .license_expressions
133- and child_holder ['value' ] == resource_holder ['value' ]):
134- child .is_summarized = True
135- codebase .save_resource (child )
131+ for descendant in resource .walk (codebase , topdown = True ):
132+ if descendant .is_file :
133+ d_license_expression = combine_expressions (descendant .license_expressions )
134+ d_holders = tuple (h ['value' ] for h in descendant .holders )
135+ else :
136+ d_license_expression = descendant .origin_summary .get ('license_expression' )
137+ d_holders = descendant .origin_summary .get ('holders' )
138+ if (d_holders , d_license_expression ) == (holders , license_expression ):
139+ descendant .summarized_to = resource .path
140+ descendant .save (codebase )
136141
137142
138143def is_majority (count , files_count ):
0 commit comments