2
# ***** BEGIN LICENSE BLOCK *****
3
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
5
# The contents of this file are subject to the Mozilla Public License Version
6
# 1.1 (the "License"); you may not use this file except in compliance with
7
# the License. You may obtain a copy of the License at
8
# http://www.mozilla.org/MPL/
10
# Software distributed under the License is distributed on an "AS IS" basis,
11
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
# for the specific language governing rights and limitations under the
15
# The Original Code is l10n test automation.
17
# The Initial Developer of the Original Code is
19
# Portions created by the Initial Developer are Copyright (C) 2006
20
# the Initial Developer. All Rights Reserved.
23
# Axel Hecht <l10n@mozilla.com>
25
# Alternatively, the contents of this file may be used under the terms of
26
# either the GNU General Public License Version 2 or later (the "GPL"), or
27
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28
# in which case the provisions of the GPL or the LGPL are applicable instead
29
# of those above. If you wish to allow use of your version of this file only
30
# under the terms of either the GPL or the LGPL, and not to allow others to
31
# use your version of this file under the terms of the MPL, indicate your
32
# decision by deleting the provisions above and replace them with the notice
33
# and other provisions required by the GPL or the LGPL. If you do not delete
34
# the provisions above, a recipient may use your version of this file under
35
# the terms of any one of the MPL, the GPL or the LGPL.
37
# ***** END LICENSE BLOCK *****
44
from datetime import datetime
46
from optparse import OptionParser
50
from Mozilla import Parser, CompareLocales, Paths, Tests
60
class LogHandler(logging.Handler):
63
logging.Handler.__init__(self)
64
def emit(self, record):
65
self.log.append((record.name, record.levelname, record.getMessage().strip()))
68
# JSON with optional gzip
71
def __init__(self, path, name):
72
self.p = os.path.join(path, name)
82
self.f = open(self.p, mode)
84
self.f = gzip.GzipFile(fileobj = self.f, filename = self.n)
85
self.w = codecs.getwriter('utf-8')(self.f)
86
self.r = codecs.getreader('utf-8')(self.f)
89
def read(self, size = -1):
90
return self.r.read(size)
102
self.w = self.r = self.f = None
104
# Helper function for JSON output with optional gzip
106
def saveJSON(dic, localName):
107
name = os.path.join(basePath, localName) ;
109
f = open(name + '.gz', 'wb')
110
s = gzip.GzipFile(fileobj = f, filename = localName)
114
sw = codecs.getwriter('utf-8')(s)
115
sw.write(simplejson.dumps(dic, sort_keys=True))
122
lvl = logging.WARNING
123
date = datetime.utcnow().replace(second=0,microsecond=0).isoformat(' ')
124
# parse commandline arguments
125
cp = OptionParser(version='0.2')
126
cp.add_option('-v', '--verbose', action='count', dest='v', default=0,
127
help='Make more noise')
128
cp.add_option('-q', '--quiet', action='count', dest='q', default=0,
129
help='Make less noise')
130
cp.add_option('-O', '--base-dir', type='string', dest='target',
132
help='Destination base directory')
133
cp.add_option('-c', '--checkout', action='store_true', dest='checkout',
135
help='Run make -f client.mk l10n-checkout [Default: not]')
136
cp.add_option('-d', '--date', type='string', dest='date',
137
help='Explicit start date or subdir [Default: now]')
138
cp.add_option('-z',action="store_true", dest="gzip", default=False,
139
help='Use gzip compression for output')
140
cp.add_option('-w','--enable-waterfall', action="store_true",
141
dest="waterfall", default=False,
142
help='Update waterfall data')
143
cp.add_option('--end-date', type='string', dest='enddate',
144
help='Explicit (faked) end date')
145
opts, optlist = cp.parse_args(sys.argv[1:])
150
logging.basicConfig(level=(logging.WARNING + 10*(opts.q - opts.v)))
151
# Add a handler to store the output
153
logging.getLogger('').addHandler(h)
156
# Check that we're in the right location and check out if requested
162
l = logging.getLogger('cvsco')
164
env = 'MOZ_CO_DATE="' + opts.date + ' +0" '
165
fh = os.popen(env + 'make -f client.mk l10n-checkout')
169
raise Exception('cvs checkout failed')
175
opts.date = date # use default set above
177
logging.debug(' Ensure output directory')
179
opts.date = opts.date.replace(':','-')
180
if not os.path.isdir(opts.target):
181
sys.exit('error: ' + opts.target + ' is not a directory')
183
startdate = time.mktime(time.strptime(opts.date, '%Y-%m-%d %H-%M-%S')) + time.altzone
184
basePath = os.path.join(opts.target, opts.date)
185
if not os.path.isdir(basePath):
189
tests = [Tests.CompareTest(),
191
Tests.RSSReaderTest()]
192
# disable bookmarks test, that's hard to fix. XXX
193
# Tests.BookmarksTest()]
197
test.serialize(res, saveJSON)
199
test.failureTest(res, drop)
201
if not opts.waterfall:
202
saveJSON(h.log, 'buildlog.json')
207
endtime = time.mktime(time.strptime(opts.enddate, '%Y-%m-%d %H:%M:%S')) + time.altzone
209
endtime = time.mktime(datetime.now().timetuple())
211
w = Wrapper(opts.target, 'waterfall.json')
212
if os.path.isfile(w.p):
214
water = simplejson.load(w)
218
water.append((opts.date, (startdate, endtime), drop))
220
# Check if we need to rotate the waterfall
223
if len(water) > rotateLen * 1.5:
224
# rotate, maximum of 16 logs
228
fnames = [os.path.join(opts.target, 'waterfall-%x.json'%i) + suffix for i in range(16)]
230
if os.path.isfile(fnames[15]):
231
os.remove(fnames[15])
232
for l in range(14, -1, -1):
233
if os.path.isfile(fnames[l]):
234
os.rename(fnames[l], fnames[l+1])
235
w0 = Wrapper('.', fnames[0])
237
simplejson.dump(water[:rotateLen], w0, sort_keys=True)
239
water = water[rotateLen:]
242
simplejson.dump(water, w, sort_keys=True)
245
saveJSON(h.log, 'buildlog.json')