Refactor android test results logging.
[chromium-blink-merge.git] / ppapi / generators / idl_outfile.py
blobbb9b84905a8f73217d7be6db16e6335d70cae942
1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """ Output file objects for generator. """
8 import difflib
9 import os
10 import time
11 import sys
13 from idl_log import ErrOut, InfoOut, WarnOut
14 from idl_option import GetOption, Option, ParseOptions
15 from stat import *
17 Option('diff', 'Generate a DIFF when saving the file.')
19 def IsEquivalent(intext, outtext):
20 if not intext: return False
21 inlines = intext.split('\n')
22 outlines = outtext.split('\n')
24 # If number of lines don't match, it's a mismatch
25 if len(inlines) != len(outlines): return False
27 for index in range(len(inlines)):
28 inline = inlines[index]
29 outline = outlines[index]
31 if inline == outline: continue
33 # If the line is not an exact match, check for comment deltas
34 inwords = inline.split()
35 outwords = outline.split()
37 if not inwords or not outwords: return False
38 if inwords[0] != outwords[0] or inwords[0] not in ('/*', '*', '//'):
39 return False
41 # Neither the year, nor the modified date need an exact match
42 if inwords[1] == 'Copyright':
43 if inwords[4:] == outwords[4:]: continue
44 elif inwords[1] == 'From': # Un-wrapped modified date.
45 if inwords[0:4] == outwords[0:4]: continue
46 elif inwords[1] == 'modified': # Wrapped modified date.
47 if inwords[0:2] == outwords[0:2]: continue
48 return False
49 return True
53 # IDLOutFile
55 # IDLOutFile provides a temporary output file. By default, the object will
56 # not write the output if the file already exists, and matches what will be
57 # written. This prevents the timestamp from changing to optimize cases where
58 # the output files are used by a timestamp dependent build system
60 class IDLOutFile(object):
61 def __init__(self, filename, always_write = False, create_dir = True):
62 self.filename = filename
63 self.always_write = always_write
64 self.create_dir = create_dir
65 self.outlist = []
66 self.open = True
68 # Return the file name
69 def Filename(self):
70 return self.filename
72 # Append to the output if the file is still open
73 def Write(self, string):
74 if not self.open:
75 raise RuntimeError('Could not write to closed file %s.' % self.filename)
76 self.outlist.append(string)
78 # Close the file
79 def Close(self):
80 filename = os.path.realpath(self.filename)
81 self.open = False
82 outtext = ''.join(self.outlist)
83 if not self.always_write:
84 if os.path.isfile(filename):
85 intext = open(filename, 'rb').read()
86 else:
87 intext = ''
89 if IsEquivalent(intext, outtext):
90 if GetOption('verbose'):
91 InfoOut.Log('Output %s unchanged.' % self.filename)
92 return False
94 if GetOption('diff'):
95 for line in difflib.unified_diff(intext.split('\n'), outtext.split('\n'),
96 'OLD ' + self.filename,
97 'NEW ' + self.filename,
98 n=1, lineterm=''):
99 ErrOut.Log(line)
101 try:
102 # If the directory does not exit, try to create it, if we fail, we
103 # still get the exception when the file is openned.
104 basepath, leafname = os.path.split(filename)
105 if basepath and not os.path.isdir(basepath) and self.create_dir:
106 InfoOut.Log('Creating directory: %s\n' % basepath)
107 os.makedirs(basepath)
109 if not GetOption('test'):
110 outfile = open(filename, 'wb')
111 outfile.write(outtext)
112 InfoOut.Log('Output %s written.' % self.filename)
113 return True
115 except IOError as (errno, strerror):
116 ErrOut.Log("I/O error(%d): %s" % (errno, strerror))
117 except:
118 ErrOut.Log("Unexpected error: %s" % sys.exc_info()[0])
119 raise
121 return False
124 def TestFile(name, stringlist, force, update):
125 errors = 0
127 # Get the old timestamp
128 if os.path.exists(name):
129 old_time = os.stat(filename)[ST_MTIME]
130 else:
131 old_time = 'NONE'
133 # Create the file and write to it
134 out = IDLOutFile(filename, force)
135 for item in stringlist:
136 out.Write(item)
138 # We wait for flush to force the timestamp to change
139 time.sleep(2)
141 wrote = out.Close()
142 cur_time = os.stat(filename)[ST_MTIME]
143 if update:
144 if not wrote:
145 ErrOut.Log('Failed to write output %s.' % filename)
146 return 1
147 if cur_time == old_time:
148 ErrOut.Log('Failed to update timestamp for %s.' % filename)
149 return 1
150 else:
151 if wrote:
152 ErrOut.Log('Should not have writen output %s.' % filename)
153 return 1
154 if cur_time != old_time:
155 ErrOut.Log('Should not have modified timestamp for %s.' % filename)
156 return 1
157 return 0
160 def main():
161 errors = 0
162 stringlist = ['Test', 'Testing\n', 'Test']
163 filename = 'outtest.txt'
165 # Test forcibly writing a file
166 errors += TestFile(filename, stringlist, force=True, update=True)
168 # Test conditionally writing the file skipping
169 errors += TestFile(filename, stringlist, force=False, update=False)
171 # Test conditionally writing the file updating
172 errors += TestFile(filename, stringlist + ['X'], force=False, update=True)
174 # Clean up file
175 os.remove(filename)
176 if not errors: InfoOut.Log('All tests pass.')
177 return errors
180 if __name__ == '__main__':
181 sys.exit(main())