3434import os
3535# FIXME: why posixpath???
3636import posixpath
37- import re
38-
37+ import traceback
3938
4039from attributecode .util import python2
4140
42-
4341if python2 : # pragma: nocover
44- import backports .csv as csv # NOQA
4542 from itertools import izip_longest as zip_longest # NOQA
4643 from urlparse import urljoin , urlparse # NOQA
4744 from urllib2 import urlopen , Request , HTTPError # NOQA
4845else : # pragma: nocover
4946 basestring = str # NOQA
50- import csv # NOQA
5147 from itertools import zip_longest # NOQA
5248 from urllib .parse import urljoin , urlparse # NOQA
5349 from urllib .request import urlopen , Request # NOQA
6460from attributecode import saneyaml
6561from attributecode import util
6662from attributecode .util import add_unc
63+ from attributecode .util import csv
6764from attributecode .util import copy_license_notice_files
6865from attributecode .util import on_windows
6966from attributecode .util import UNC_PREFIX
@@ -508,22 +505,6 @@ def _validate(self, *args, **kwargs):
508505 errors = super (AboutResourceField , self )._validate (* args , ** kwargs )
509506 return errors
510507
511- def resolve (self , about_file_path ):
512- """
513- Resolve resource paths relative to an ABOUT file path.
514- Set a list attribute on self called resolved_paths
515- """
516- self .resolved_paths = []
517- if not about_file_path :
518- # FIXME: should we return an info or warning?
519- # The existence of about_file_path has been checked in the load_inventory()
520- return
521- base_dir = posixpath .dirname (about_file_path ).strip (posixpath .sep )
522- for path in self .value .keys ():
523- resolved = posixpath .join (base_dir , path )
524- resolved = posixpath .normpath (resolved )
525- self .resolved_paths .append (resolved )
526-
527508
528509class FileTextField (PathField ):
529510 """
@@ -786,46 +767,6 @@ def __eq__(self, other):
786767 and self .fields == other .fields
787768 and self .custom_fields == other .custom_fields )
788769
789- @staticmethod
790- def attribution_fields (fields ):
791- """
792- Return attrib-only fields
793- """
794- attrib_fields = ['name' ,
795- 'version' ,
796- 'license_key' ,
797- 'license_name' ,
798- 'license_file' ,
799- 'license_url' ,
800- 'copyright' ,
801- 'notice_file' ,
802- 'notice_url' ,
803- 'redistribute' ,
804- 'attribute' ,
805- 'track_changes' ,
806- 'modified' ,
807- 'changelog_file' ,
808- 'owner' ,
809- 'author' ]
810-
811- return OrderedDict ([(n , o ) for n , o in fields .items ()
812- if n in attrib_fields ])
813-
814- def same_attribution (self , other ):
815- """
816- Equality based on attribution-related fields.
817- """
818- return (isinstance (other , self .__class__ )
819- and self .attribution_fields (self .fields ) == self .attribution_fields (other .fields ))
820-
821- def resolved_resources_paths (self ):
822- """
823- Return a serialized string of resolved resource paths, one per line.
824- """
825- abrf = self .about_resource_path
826- abrf .resolve (self .about_file_path )
827- return u'\n ' .join (abrf .resolved_paths )
828-
829770 def all_fields (self , with_absent = True , with_empty = True ):
830771 """
831772 Return the list of all Field objects.
@@ -996,10 +937,6 @@ def process(self, fields, about_file_path, running_inventory=False,
996937 self .base_dir , self .reference_dir )
997938 errors .extend (validation_errors )
998939
999- # do not forget to resolve about resource paths The
1000- # 'about_resource' field is now a ListField and those do not
1001- # need to resolve
1002- # self.about_resource.resolve(self.about_file_path)
1003940 return errors
1004941
1005942 def load (self , location , mapping_file = None ):
@@ -1015,8 +952,6 @@ def load(self, location, mapping_file=None):
1015952 loc = add_unc (loc )
1016953 with codecs .open (loc , encoding = 'utf-8' ) as txt :
1017954 input_text = txt .read ()
1018- # Check for duplicated key
1019- saneyaml .load (input_text , allow_duplicate_keys = False )
1020955 """
1021956 The running_inventory defines if the current process is 'inventory' or not.
1022957 This is used for the validation of the path of the 'about_resource'.
@@ -1027,15 +962,12 @@ def load(self, location, mapping_file=None):
1027962 and then join with the 'about_resource'
1028963 """
1029964 running_inventory = True
1030- # FIXME: why??
1031- # wrap the value of the boolean field in quote to avoid
1032- # automatically conversion from yaml.load
1033- input = util .wrap_boolean_value (input_text ) # NOQA
1034- data = saneyaml .load (input , allow_duplicate_keys = False )
965+ data = saneyaml .load (input_text , allow_duplicate_keys = False )
1035966 errs = self .load_dict (data , base_dir , running_inventory , mapping_file )
1036967 errors .extend (errs )
1037968 except Exception as e :
1038- msg = 'Cannot load invalid ABOUT file: %(location)r: %(e)r\n ' + str (e )
969+ trace = traceback .format_exc ()
970+ msg = 'Cannot load invalid ABOUT file: %(location)r: %(e)r\n %(trace)s'
1039971 errors .append (Error (CRITICAL , msg % locals ()))
1040972
1041973 self .errors = errors
@@ -1072,10 +1004,10 @@ def load_dict(self, fields_dict, base_dir, running_inventory=False,
10721004 licenses_field = (key , value )
10731005 fields .remove (licenses_field )
10741006 errors = self .process (
1075- fields = fields ,
1076- about_file_path = about_file_path ,
1077- running_inventory = running_inventory ,
1078- base_dir = base_dir ,
1007+ fields = fields ,
1008+ about_file_path = about_file_path ,
1009+ running_inventory = running_inventory ,
1010+ base_dir = base_dir ,
10791011 reference_dir = reference_dir ,
10801012 mapping_file = mapping_file )
10811013 self .errors = errors
@@ -1149,7 +1081,7 @@ def dump(self, location, mapping_file=False, with_absent=False, with_empty=True)
11491081 if about_file_path .endswith ('/' ):
11501082 about_file_path = util .to_posix (os .path .join (parent , os .path .basename (parent )))
11511083 about_file_path += '.ABOUT'
1152-
1084+
11531085 if on_windows :
11541086 about_file_path = add_unc (about_file_path )
11551087
@@ -1189,94 +1121,6 @@ def dump_lic(self, location, license_dict):
11891121 pass
11901122 return license_key_name_context_url
11911123
1192-
1193- # valid field name
1194- field_name = r'(?P<name>[a-z][0-9a-z_]*)'
1195-
1196- valid_field_name = re .compile (field_name , re .UNICODE | re .IGNORECASE ).match # NOQA
1197-
1198- # line in the form of "name: value"
1199- field_declaration = re .compile (
1200- r'^'
1201- + field_name +
1202- r'\s*:\s*'
1203- r'(?P<value>.*)'
1204- r'\s*$'
1205- , re .UNICODE | re .IGNORECASE # NOQA
1206- ).match
1207-
1208-
1209- # continuation line in the form of " value"
1210- continuation = re .compile (
1211- r'^'
1212- r' '
1213- r'(?P<value>.*)'
1214- r'\s*$'
1215- , re .UNICODE | re .IGNORECASE # NOQA
1216- ).match
1217-
1218-
1219- def parse (lines ):
1220- """
1221- Parse a list of unicode lines from an ABOUT file. Return a
1222- list of errors found during parsing and a list of tuples of (name,
1223- value) strings.
1224- """
1225- errors = []
1226- fields = []
1227-
1228- # track current name and value to accumulate possible continuations
1229- name = None
1230- value = []
1231-
1232- for num , line in enumerate (lines ):
1233- has_content = line .strip ()
1234- new_field = field_declaration (line )
1235- cont = continuation (line )
1236-
1237- if cont :
1238- if name :
1239- # name is set, so the continuation is for the field name
1240- # append the value
1241- value .append (cont .group ('value' ))
1242- else :
1243- # name is not set and the line is not empty
1244- if has_content :
1245- msg = 'Invalid continuation line: %(num)d: %(line)r'
1246- errors .append (Error (CRITICAL , msg % locals ()))
1247-
1248- elif not line or not has_content :
1249- # an empty line: append current name/value if any and reset
1250- if name :
1251- fields .append ((name , value ,))
1252- # reset
1253- name = None
1254-
1255- elif new_field :
1256- # new field line: yield current name/value if any
1257- if name :
1258- fields .append ((name , value ,))
1259- # start new field
1260- name = new_field .group ('name' )
1261- # values are always stored in a list
1262- # even simple single string values
1263- value = [new_field .group ('value' )]
1264-
1265- else :
1266- # neither empty, nor new field nor continuation
1267- # this is an error
1268- msg = 'Invalid line: %(num)d: %(line)r'
1269- errors .append (Error (CRITICAL , msg % locals ()))
1270-
1271- # append if any name/value was left over on last iteration
1272- if name :
1273- fields .append ((name , value ,))
1274-
1275- # rejoin eventual multi-line string values
1276- fields = [(name , u'\n ' .join (value ),) for name , value in fields ]
1277- return errors , fields
1278-
1279-
12801124def collect_inventory (location , mapping_file = None ):
12811125 """
12821126 Collect ABOUT files at location and return a list of errors and a list of
@@ -1393,69 +1237,6 @@ def write_output(abouts, location, format, with_absent=False, with_empty=True):
13931237 return errors
13941238
13951239
1396- def by_license (abouts ):
1397- """
1398- Return an ordered dict sorted by key of About objects grouped by license
1399- """
1400- grouped = {}
1401- grouped ['' ] = []
1402- no_license = grouped ['' ]
1403- for about in abouts :
1404- if about .license_expression .value :
1405- special_char_in_expression , lic_list = parse_license_expression (about .license_expression .value )
1406- if not special_char_in_expression :
1407- for lic in lic_list :
1408- if lic in grouped :
1409- grouped [lic ].append (about )
1410- else :
1411- grouped [lic ] = [about ]
1412- else :
1413- no_license .append (about )
1414- return OrderedDict (sorted (grouped .items ()))
1415-
1416-
1417- def by_name (abouts ):
1418- """
1419- Return an ordered dict sorted by key of About objects grouped by component
1420- name.
1421- """
1422- grouped = {}
1423- grouped ['' ] = []
1424- no_name = grouped ['' ]
1425- for about in abouts :
1426- name = about .name .value
1427- if name :
1428- if name in grouped :
1429- grouped [name ].append (about )
1430- else :
1431- grouped [name ] = [about ]
1432- else :
1433- no_name .append (about )
1434- return OrderedDict (sorted (grouped .items ()))
1435-
1436-
1437- def by_license_content (abouts ):
1438- """
1439- Return an ordered dict sorted by key of About objects grouped by license
1440- content.
1441- """
1442- grouped = {}
1443- grouped ['' ] = []
1444- no_license = grouped ['' ]
1445- for about in abouts :
1446- if about .license_key .value :
1447- special_char_in_expression , lic_list = parse_license_expression (about .license_key .value )
1448- if not special_char_in_expression :
1449- for lic in lic_list :
1450- if lic in grouped :
1451- grouped [lic ].append (about )
1452- else :
1453- grouped [lic ] = [about ]
1454- else :
1455- no_license .append (about )
1456- return OrderedDict (sorted (grouped .items ()))
1457-
1458-
14591240def pre_process_and_fetch_license_dict (abouts , api_url , api_key ):
14601241 """
14611242 Modify a list of About data dictionaries by adding license information
@@ -1540,31 +1321,3 @@ def valid_api_url(api_url):
15401321 # All other exceptions yield to invalid api_url
15411322 pass
15421323 return False
1543-
1544-
1545- def verify_license_files_in_location (about , lic_location ):
1546- """
1547- Check the existence of the license file provided in the license_field from the
1548- license_text_location.
1549- Return a dictionary of the path of where the license should be copied to as
1550- the key and the path of where the license should be copied from as the value.
1551- """
1552- license_location_dict = {}
1553- errors = []
1554- # The license_file field is filled if the input has license value and
1555- # the 'fetch_license' option is used.
1556- if about .license_file .value :
1557- for lic in about .license_file .value :
1558- lic_path = util .to_posix (posixpath .join (lic_location , lic ))
1559- if posixpath .exists (lic_path ):
1560- copy_to = os .path .dirname (about .about_file_path )
1561- license_location_dict [copy_to ] = lic_path
1562- else :
1563- msg = (u'The license file : '
1564- u'%(lic)s '
1565- u'does not exist in '
1566- u'%(lic_path)s and therefore cannot be copied' % locals ())
1567- errors .append (Error (ERROR , msg ))
1568- return license_location_dict , errors
1569-
1570-
0 commit comments