source: anuga_core/source/anuga/utilities/data_audit.py @ 5040

Last change on this file since 5040 was 5040, checked in by ole, 16 years ago

Work and data audit. Added a bunch of license files.

File size: 10.9 KB
Line 
1"""Track IP of data files in an entire directory tree.
2See docstring for the public function IP_verified()
3for details.
4"""
5
6from os import remove, walk, sep
7from os.path import join, splitext
8
9from anuga.utilities.xml_tools import xml2object, XML_element
10from anuga.utilities.system_tools import compute_checksum
11
12
13# Audit exceptions
14class NotPublishable(Exception): pass
15class FilenameMismatch(Exception): pass
16class CRCMismatch(Exception): pass
17class Invalid(Exception): pass
18class WrongTags(Exception): pass
19class Empty(Exception): pass
20
21audit_exceptions = (NotPublishable,
22                    FilenameMismatch,
23                    CRCMismatch,
24                    Invalid,
25                    WrongTags,
26                    Empty)
27
28
29def IP_verified(directory,
30                extensions_to_ignore=None,
31                directories_to_ignore=None,
32                files_to_ignore=None,
33                verbose=False):
34    """Find and audit potential data files that might violate IP
35
36    This is the public function to be used to ascertain that
37    all data in the specified directory tree has been audited according
38    to the GA data IP tracking process.
39
40    if IP_verified is False:
41        # Stop and take remedial action
42        ...
43    else:
44        # Proceed boldly with confidence
45       
46    verbose controls standard output.
47    If verbose is False, only diagnostics about failed audits will appear.
48    All files that check OK will pass silently.
49
50    Optional arguments extensions_to_ignore, directories_to_ignore, and
51    files_to_ignore are lists of things to skip.
52
53    Examples are:
54    extensions_to_ignore = ['.py','.c','.h', '.f'] # Ignore source code
55    files_to_ignore = ['README.txt']
56    directories_to_ignore = ['.svn', 'misc']
57
58    None is also OK for these parameters.
59   
60    """
61
62    # Identify data files
63    oldpath = None
64    all_files = 0
65    ok_files = 0
66    first_time = True
67    all_files_accounted_for = True
68    for dirpath, filename in identify_datafiles(directory,
69                                                extensions_to_ignore,
70                                                directories_to_ignore,
71                                                files_to_ignore):
72
73
74        if oldpath != dirpath:
75            dir_change = True
76            oldpath = dirpath
77        else:
78            dir_change = False
79
80        all_files += 1
81       
82        basename, ext = splitext(filename)
83        license_filename = join(dirpath, basename + '.lic')
84
85
86        # Look for a XML license file with the .lic
87        status = 'OK'
88        try:
89            fid = open(license_filename)
90        except IOError:
91            status = 'NO LICENSE FILE'
92            all_files_accounted_for = False
93        else:
94            fid.close()
95           
96            try:
97                license_file_is_valid(license_filename,
98                                      filename,
99                                      dirpath,
100                                      verbose=False)
101            except audit_exceptions, e:
102                all_files_accounted_for = False                               
103                status = 'LICENSE FILE NOT VALID\n'
104                status += 'REASON: %s\n' %e
105
106                try:
107                    doc = xml2object(license_filename)
108                except:
109                    status += 'XML file %s could not be read:'\
110                              %license_filename
111                    fid = open(license_filename)
112                    status += fid.read()
113                    fid.close()
114                else:
115                    pass
116                    #if verbose is True:
117                    #    status += str(doc)
118
119
120
121       # Only print status if there is a problem (no news is good news)
122        if dir_change is True:
123            print
124            print '------------------------------------'
125            msg = 'Files without licensing info in dir:'
126            print msg, dirpath
127            print '------------------------------------'
128               
129
130        if status == 'OK':
131            ok_files += 1
132        else:
133            #print dir_change, dirpath, filename + ' (Checksum=%s): '\
134            print filename + ' (Checksum=%s): '\
135                  %str(compute_checksum(join(dirpath, filename))),\
136                  status
137
138
139    if verbose is True:
140        print
141        print '---------------------'       
142        print 'Audit result for dir: %s:' %directory
143        print '---------------------'               
144        print 'Number of files audited:  %d' %(all_files)
145        print 'Number of files verified: %d' %(ok_files)       
146        print
147
148    # Return result       
149    return all_files_accounted_for
150
151
152
153#------------------
154# Private functions
155#------------------
156def identify_datafiles(root,
157                       extensions_to_ignore=None,
158                       directories_to_ignore=None,
159                       files_to_ignore=None):
160    """ Identify files that might contain data
161
162    See function IP_verified() for details about optinoal parmeters
163    """
164
165    for dirpath, dirnames, filenames in walk(root):
166
167        for ignore in directories_to_ignore:
168            if ignore in dirnames:
169                dirnames.remove(ignore)  # don't visit ignored directories
170
171
172        for filename in filenames:
173
174
175            # Ignore extensions that need no IP check
176            ignore = False
177            for ext in extensions_to_ignore:
178                if filename.endswith(ext):
179                    ignore = True
180
181            if filename in files_to_ignore:
182                ignore = True
183
184            if ignore is False:
185                yield dirpath, filename
186
187
188def license_file_is_valid(license_filename, data_filename,
189                          dirpath='.', verbose=False):
190    """Check that XML license file for given filename_to_verify is valid.
191
192    Input:
193        license_filename: XML license file (must be an absolute path name)
194        data_filename: The data filename that is being audited
195        dir_path: Where the files live
196        verbose: Optional verbosity
197       
198
199    Check for each datafile listed that
200
201    * Datafile tags are there and match the one specified
202    * Fields are non empty (except IP_info which can be left blank)
203    * Datafile exists
204    * Checksum is correct
205    * Datafile is flagged as publishable
206
207    If anything is violated an appropriate exception is raised.
208    If everything is honky dory the function will return True.
209    """
210
211    doc = xml2object(license_filename)
212   
213    # Check that file is valid (e.g. all elements there)
214    if not doc.has_key('ga_license_file'):
215        msg = 'License file %s must have two elements' %license_filename
216        msg += ' at the root level. They are\n'
217        msg += '  <?xml version="1.0" encoding="iso-8859-1"?>\n'
218        msg += '  <ga_license_file>\n'
219        msg += 'The second element was found to be %s' %doc.keys()
220        raise WrongTags, msg
221   
222
223    # Validate elements: metadata, datafile, datafile, ...
224    # FIXME (Ole): I'd like this to verified by the parser
225    # using a proper DTD template one day....
226    # For not, let's check the main ones.
227    elements = doc['ga_license_file']
228    if not elements.has_key('metadata'):
229        msg = 'Tag %s must have the element "metadata"'\
230              %doc.keys()[0]
231        msg += 'The element found was %s' %elements[0].nodeName
232        raise WrongTags, msg
233
234    if not elements.has_key('datafile'):
235        msg = 'Tag %s must have the element "datafile"'\
236              %doc.keys()[0]
237        msg += 'The element found was %s' %elements[0].nodeName
238        raise WrongTags, msg   
239
240    for key in elements.keys():
241        msg = 'Invalid tag: %s' %key
242        if not key in ['metadata', 'datafile']:
243            raise WrongTags, msg                   
244
245   
246    # Extract information for metadata section
247    if verbose: print
248    metadata = elements['metadata']
249
250    author = metadata['author']
251    if verbose: print 'Author:   ', author
252    if author == '':
253        msg = 'Missing author'
254        raise Exception, msg               
255   
256    #svn_keywords = metadata['svn_keywords']
257    #if verbose: print 'SVN keywords:   ', svn_keywords
258   
259       
260    # Extract information for datafile sections
261    datafile = elements['datafile']
262    if isinstance(datafile, XML_element):
263        datafile = [datafile]
264
265
266    # Check that filename to verify is listed in license file
267    found = False
268    for data in datafile:   
269        if data['filename'] == data_filename:
270            found = True
271            break
272           
273    if not found:
274        msg = 'Specified filename to verify %s ' %data_filename
275        msg += 'did not appear in license file %s' %license_filename
276        raise FilenameMismatch, msg               
277           
278       
279    # Check contents for selected data_filename
280    #for data in datafile:
281    #    if verbose: print
282
283    # Filename
284    if data['filename'] == '':
285        msg = 'Missing filename'
286        raise FilenameMismatch, msg           
287    else:
288        filename = join(dirpath, data['filename'])
289        if verbose: print 'Filename: "%s"' %filename
290        try:
291            fid = open(filename, 'r')
292        except:
293            msg = 'Specified filename %s could not be opened'\
294                  %filename
295            raise FilenameMismatch, msg
296
297    # CRC
298    reported_crc = data['checksum']
299    if verbose: print 'Checksum: "%s"' %reported_crc
300   
301    file_crc = str(compute_checksum(filename))
302    if reported_crc != file_crc:
303        msg = 'Bad checksum (CRC).\n'
304        msg += '  The CRC reported in license file "%s" is "%s"\n'\
305               %(license_filename, reported_crc)
306        msg += '  The CRC computed from file "%s" is "%s"'\
307               %(filename, file_crc)
308        raise CRCMismatch, msg
309           
310    # Accountable
311    accountable = data['accountable']
312    if verbose: print 'Accountable: "%s"' %accountable
313    if accountable == '':
314        msg = 'No accountable person specified'
315        raise Empty, msg
316
317    # Source
318    source = data['source']
319    if verbose: print 'Source: "%s"' %source
320    if source == '':
321        msg = 'No source specified'
322        raise Empty, msg               
323
324    # IP owner
325    ip_owner = data['IP_owner']
326    if verbose: print 'IP owner: "%s"' %ip_owner
327    if ip_owner == '':
328        msg = 'No IP owner specified'
329        raise Empty, msg                               
330           
331    # IP info
332    ip_info = data['IP_info']
333    if verbose: print 'IP info: "%s"' %ip_info
334    #if ip_info == '':
335    #    msg = 'No IP info specified'
336    #    raise Empty, msg                                               
337
338    # Publishable
339    publishable = data['publishable']
340    if verbose: print 'Publishable: "%s"' %publishable
341    if publishable == '':
342        msg = 'No publishable value specified'
343        raise NotPublishable, msg
344   
345    if publishable.upper() != 'YES':
346        msg = 'Data file %s is not flagged as publishable'\
347              %fid.name
348        raise NotPublishable, msg
349
350
351
352    # If we get this far, the license file is OK
353    return True
Note: See TracBrowser for help on using the repository browser.