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

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

fiddled

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