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

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

Added stub license file for the cairns example

File size: 10.2 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    first_time = True
65    all_files_accounted_for = True
66    for dirpath, datafile in identify_datafiles(directory,
67                                                extensions_to_ignore,
68                                                directories_to_ignore,
69                                                files_to_ignore):
70       
71        filename = join(dirpath, datafile)
72        basename, ext = splitext(datafile)
73
74        # Look for a XML license file with the .lic
75        status = 'OK'
76        try:
77            fid = open(join(dirpath, basename + '.lic'))
78        except IOError:
79            status = 'NO LICENSE FILE'
80            all_files_accounted_for = False
81        else:
82            try:
83                license_file_is_valid(fid, datafile, dirpath,
84                                      verbose=verbose)
85            except audit_exceptions, e:
86                all_files_accounted_for = False                               
87                status = 'LICENSE FILE NOT VALID\n'
88                status += 'REASON: %s\n' %e
89
90                try:
91                    doc = xml2object(fid)
92                except:
93                    status += 'XML file could not be read:'
94                    fid.seek(0)
95                    status += fid.read()                   
96                else:   
97                    status += str(doc)
98
99            fid.close()
100           
101        if status != 'OK' or verbose is True:
102            if first_time is True:
103                # Print header
104                print '---------------------------------------------'
105                print 'Files that need to be assessed for IP issuses'.ljust(dirwidth), 'Status'
106                print '---------------------------------------------'
107                first_time = False
108
109            print filename + ' (Checksum=%s): '\
110                  %str(compute_checksum(filename)), status
111
112
113
114    # Return result       
115    return all_files_accounted_for
116
117
118
119#------------------
120# Private functions
121#------------------
122def identify_datafiles(root,
123                       extensions_to_ignore=None,
124                       directories_to_ignore=None,
125                       files_to_ignore=None):
126    """ Identify files that might contain data
127
128    See function IP_verified() for details about optinoal parmeters
129    """
130
131    for dirpath, dirnames, filenames in walk(root):
132
133        for ignore in directories_to_ignore:
134            if ignore in dirnames:
135                dirnames.remove(ignore)  # don't visit ignored directories
136
137
138        for filename in filenames:
139
140
141            # Ignore extensions that need no IP check
142            ignore = False
143            for ext in extensions_to_ignore:
144                if filename.endswith(ext):
145                    ignore = True
146
147            if filename in files_to_ignore:
148                ignore = True
149
150            if ignore is False:
151                yield dirpath, filename
152
153
154def license_file_is_valid(fid, filename_to_verify,
155                          dirpath='.', verbose=False):
156    """Check that XML license file for given filename_to_verify is valid.
157
158    Input:
159        fid: Open file object for XML license file
160        file_name_to_verify: The data filename that is being audited
161        dir_path: Where the files live
162        verbose: Optional verbosity
163       
164
165    Check for each datafile listed that
166
167    * Datafile tags are there and match the one specified
168    * Fields are non empty
169    * Datafile exists
170    * Checksum is correct
171    * Datafile is flagged as publishable
172
173    If anything is violated an appropriate exception is raised.
174    If everything is honky dory the function will return True.
175    """
176
177    license_filename = fid.name
178
179    doc = xml2object(fid)
180    #print doc
181
182   
183    # Check that file is valid (e.g. all elements there)
184    if not doc.has_key('ga_license_file'):
185        msg = 'License file %s must have two elements' %license_filename
186        msg += ' at the root level. They are\n'
187        msg += '  <?xml version="1.0" encoding="iso-8859-1"?>\n'
188        msg += '  <ga_license_file>\n'
189        msg += 'The second element was found to be %s' %doc.keys()
190        raise WrongTags, msg
191   
192
193    # Validate elements: metadata, datafile, datafile, ...
194    # FIXME (Ole): I'd like this to verified by the parser
195    # using a proper DTD template one day....
196    # For not, let's check the main ones.
197    elements = doc['ga_license_file']
198    if not elements.has_key('metadata'):
199        msg = 'Tag %s must have the element "metadata"'\
200              %doc.keys()[0]
201        msg += 'The element found was %s' %elements[0].nodeName
202        raise WrongTags, msg
203
204    if not elements.has_key('datafile'):
205        msg = 'Tag %s must have the element "datafile"'\
206              %doc.keys()[0]
207        msg += 'The element found was %s' %elements[0].nodeName
208        raise WrongTags, msg   
209
210    for key in elements.keys():
211        msg = 'Invalid tag: %s' %key
212        if not key in ['metadata', 'datafile']:
213            raise WrongTags, msg                   
214
215   
216    # Extract information for metadata section
217    if verbose: print
218    metadata = elements['metadata']
219
220    author = metadata['author']
221    if verbose: print 'Author:   ', author
222    if author == '':
223        msg = 'Missing author'
224        raise Exception, msg               
225   
226    #svn_keywords = metadata['svn_keywords']
227    #if verbose: print 'SVN keywords:   ', svn_keywords
228   
229       
230    # Extract information for datafile sections
231    datafile = elements['datafile']
232    if isinstance(datafile, XML_element):
233        datafile = [datafile]
234
235
236    # Check that filename to verify is listed in license file
237    found = False
238    for data in datafile:   
239        if data['filename'] == filename_to_verify:
240            found = True
241    if not found:
242        msg = 'Specified filename to verify %s ' %filename_to_verify
243        msg += 'did not appear in license file %s' %license_filename
244        raise FilenameMismatch, msg               
245           
246       
247    # Check contents
248    for data in datafile:
249        if verbose: print
250
251        # Filename
252        if data['filename'] == '':
253            msg = 'Missing filename'
254            raise FilenameMismatch, msg           
255        else:
256            filename = join(dirpath, data['filename'])
257            if verbose: print 'Filename: "%s"' %filename
258            try:
259                fid = open(filename, 'r')
260            except:
261                msg = 'Specified filename %s could not be opened'\
262                      %filename
263                raise FilenameMismatch, msg
264
265        # CRC
266        reported_crc = data['checksum']
267        if verbose: print 'Checksum: "%s"' %reported_crc
268       
269        file_crc = str(compute_checksum(filename))
270        if reported_crc != file_crc:
271            msg = 'Bad checksum (CRC).\n'
272            msg += '  The CRC reported in license file "%s" is "%s"\n'\
273                   %(license_filename, reported_crc)
274            msg += '  The CRC computed from file "%s" is "%s"'\
275                   %(filename, file_crc)
276            raise CRCMismatch, msg
277               
278        # Accountable
279        accountable = data['accountable']
280        if verbose: print 'Accountable: "%s"' %accountable
281        if accountable == '':
282            msg = 'No accountable person specified'
283            raise Exception, msg
284
285        # Source
286        source = data['source']
287        if verbose: print 'Source: "%s"' %source
288        if source == '':
289            msg = 'No source specified'
290            raise Exception, msg               
291
292        # IP owner
293        ip_owner = data['IP_owner']
294        if verbose: print 'IP owner: "%s"' %ip_owner
295        if ip_owner == '':
296            msg = 'No IP owner specified'
297            raise Exception, msg                               
298               
299        # IP info
300        ip_info = data['IP_info']
301        if verbose: print 'IP info: "%s"' %ip_info
302        if ip_info == '':
303            msg = 'No IP info specified'
304            raise Exception, msg                                               
305
306        # Publishable
307        publishable = data['publishable']
308        if verbose: print 'Publishable: "%s"' %publishable
309        if publishable == '':
310            msg = 'No publishable value specified'
311            raise NotPublishable, msg
312       
313        print 'PUB', publishable
314        if publishable.upper() != 'YES':
315            msg = 'Data file %s is not flagged as publishable'\
316                  %fid.name
317            raise NotPublishable, msg
318
319
320
321    # If we get this far, the license file is OK
322    return True
Note: See TracBrowser for help on using the repository browser.