1#!/usr/bin/python
2# -*- Mode: python -*-
3
4#    Copyright (C) 2001-2006 Artifex Software Inc.
5#    All Rights Reserved.
6#
7# This software is provided AS-IS with no warranty, either express or
8# implied.
9#
10# This software is distributed under license and may not be copied, modified
11# or distributed except as expressly authorized under the terms of that
12# license.  Refer to licensing information at http://www.artifex.com/
13# or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
14# San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
15
16# $Id$
17
18# This script builds a revision of gs, including svn update, configure, make, install
19#
20# If the revision is HEAD, make install is done; and the svn tree is put (HEAD) and installed
21# 	into gsconf.gsroot (usually /home/regression/gshead)
22#
23# If the revision is not HEAD, no install is done; and the tree is put into gs.<revision>
24#
25# If release is not None, then a release is built - in progress
26#
27
28
29import os, sys, shutil
30import time
31import optparse, myoptparse
32import string, re
33import gsconf
34
35myself="build_revision.py"
36myversion="1.00"
37
38def logMessage(message,file,revision,printMessage=True):
39    message_time=time.strftime("%Y-%m-%d-%H:%M:%S", time.localtime())
40    message=myself+" "+revision+" "+message_time+" "+message
41    if printMessage:
42        print message
43    if file:
44        message+="\n"
45        file.write(message)
46        file.flush()
47
48def read_all_lines(f):
49    file = open(f, 'r')
50    lines = file.readlines()
51    file.close()
52    return string.join(lines, '')
53
54def get_revision(dir=None):
55    if dir:
56        cwd=os.getcwd()
57        os.chdir(dir)
58    p = os.popen("svn info")
59    for line in p:
60        if "Revision:" in line:
61            revision=line.strip('Revision: ')
62            revision=revision.strip('\n')
63	    break
64    else:
65        revision = None
66    if dir:
67        os.chdir(cwd)
68    return revision
69
70def change_gsproduct(file):
71    tmpfile = "%s.tmp" % (file,)
72
73    startre = re.compile("^#ifndef\ GS_PRODUCT$")
74    changere = re.compile("^.*?\"[A-Za-z -]+\".*?$")
75    endre = re.compile("^$")
76
77    old = open(file, "r")
78    new = open(tmpfile, "w")
79
80    state = 0
81    for line in old.readlines():
82        if state == 0:
83            m = startre.search(line)
84            if m:
85                state = 1
86
87            new.write(line)
88        elif state == 1:
89            m = changere.search(line)
90            if m:
91                state = 2
92                new.write("\t\"GPL Ghostscript\"\n")
93            else:
94                new.write(line)
95        elif state == 2:
96            m = endre.search(line)
97            if m:
98                state = 0
99
100            new.write(line)
101
102    old.close()
103    new.close()
104
105    os.unlink(file)
106    os.rename(tmpfile, file)
107
108def update_ghostscript(revision,release,
109                       gsroot,
110                       options,
111                       update_stdout,update_stderr,
112                       config_stdout,config_stderr,
113                       make_stdout,make_stderr,
114                       install_stdout,install_stderr,
115                       cumulative_file
116                       ):
117
118    myself=options.myself+" update_ghostscript"
119
120    if options and options.__dict__.has_key("verbose") and options.verbose:
121        print myself,gsroot
122
123    if release:
124        print myself,"release not yet supported"
125
126    if options and options.__dict__.has_key("capture") and options.capture:
127        captureOutput = True
128    else:
129        captureOutput = False
130
131    update_stdout_file = open(update_stdout, "w")
132    message="update_stdout"
133    logMessage(message,update_stdout_file,revision,printMessage=False)
134    update_stdout_file.close()
135
136    update_stderr_file = open(update_stderr, "w")
137    message="update_stderr"
138    logMessage(message,update_stderr_file,revision,printMessage=False)
139    update_stderr_file.close()
140
141    cwd=os.getcwd()
142
143    revision_file = gsroot+"revision"   # remove history until we have successfully completed the update"
144    if os.path.exists(revision_file):
145        os.unlink(revision_file)
146
147    # to prevent errors from left-over installations, remove the install tree
148    if revision == "HEAD":
149        installtree=gsconf.installtree
150        if os.path.exists(installtree):
151            message="remove old installation directory tree "+installtree
152            logMessage(message,cumulative_file,revision)
153            # do a check for sanity of the path
154            if os.path.exists(installtree+"/bin") and os.path.exists(installtree+"/bin/gs"):
155                shutil.rmtree(installtree+"/bin",ignore_errors=True)
156                shutil.rmtree(installtree+"/man",ignore_errors=True)
157                shutil.rmtree(installtree+"/share",ignore_errors=True)
158
159    update_stdout_file = open(update_stdout, "w")
160
161    if options and options.__dict__.has_key("svn") and options.svn:
162
163        product_file = "%sbase/gscdef.c" % (gsroot)
164        if os.path.exists(product_file):
165            os.unlink(product_file)
166
167        # make the source tree corrrect from svn repository
168
169        message="svn checkout "+gsroot
170        logMessage(message,update_stdout_file,revision,printMessage=False)
171        logMessage(message,cumulative_file,revision)
172
173        host="http://svn.ghostscript.com/ghostscript/trunk/gs "
174
175        if os.path.exists(gsroot):
176            revisionarg="-r"+revision+" "
177            command="svn update "+revisionarg+gsroot
178        else:
179            revisionarg="-r"+revision+" "
180            command="svn co "+revisionarg+host+gsroot
181
182        logMessage(message,update_stdout_file,revision,printMessage=False)
183        logMessage(command,cumulative_file,revision)
184
185        if captureOutput:
186            capture=" >> "+update_stdout
187            command+=capture
188        if os.system(command) != 0:
189            msg = "Ghostscript update failed during svn update\n\n"
190            msg = msg + "stdout log:\n\n"
191            msg = msg + read_all_lines(update_stdout)
192            msg = msg + "\nstderr log:\n\n"
193            msg = msg + read_all_lines(update_stderr)
194            logMessage(message,cumulative_file,revision)
195            return (1,msg)
196
197        if revision == "HEAD":
198            revision_value=get_revision(gsroot)
199        else:
200            revision_value = revision
201
202        sys.modules["gsconf"].__dict__["revision"] = revision_value
203
204
205    os.chdir(gsroot)
206
207    message="revision is " + str(revision)
208    logMessage(message,update_stdout_file,revision,printMessage=False)
209    logMessage(message,cumulative_file,revision)
210
211    if options and options.__dict__.has_key("configure") and options.configure:
212        change_gsproduct(product_file)
213
214        message="product change complete:"+product_file
215        logMessage(message,update_stdout_file,revision,printMessage=False)
216        logMessage(message,cumulative_file,revision,)
217
218        if revision == "HEAD":
219            installpath=gsconf.installtree
220            command="./autogen.sh --prefix=" + installpath
221            # HACK: configuring with cups support makes the build script
222            # try to install outside of prefix. Disable for now.
223            command+=" --disable-cups"
224        else:
225            command="./autogen.sh"
226
227        logMessage(command,update_stdout_file,revision,printMessage=False)
228        logMessage(command,cumulative_file,revision)
229        if captureOutput:
230            capture=" > " +  config_stdout + " 2> " + config_stderr
231            command+=capture
232        if os.system(command) != 0:
233            msg = "Ghostscript update failed during configuration.\n\n"
234            msg = msg + "stdout log:\n\n"
235            msg = msg + read_all_lines(make_stdout)
236            msg = msg + "\nstderr log:\n\n"
237            msg = msg + read_all_lines(make_stderr)
238            logMessage(message,cumulative_file,revision)
239            return (1,msg)
240
241        message="configuration complete"
242        logMessage(message,update_stdout_file,revision,printMessage=False)
243        logMessage(message,cumulative_file,revision)
244
245
246    if options and options.__dict__.has_key("makeclean") and options.makeclean:
247        command ="make clean "
248        logMessage(command,update_stdout_file,revision,printMessage=False)
249        logMessage(command,cumulative_file,revision)
250        if captureOutput:
251            capture=" > /dev/null 2> /dev/null"
252            command+=capture
253        if os.system(command) != 0:
254            msg = "Ghostscript update failed during make clean\n\n"
255            logMessage(message,cumulative_file,revision)
256            return (1,msg)
257
258        message="make clean complete"
259        logMessage(message,update_stdout_file,revision,printMessage=False)
260        logMessage(message,cumulative_file,revision)
261
262    if options and options.__dict__.has_key("make") and options.make:
263        command="make "
264        logMessage(command,update_stdout_file,revision,printMessage=False)
265        logMessage(command,cumulative_file,revision)
266        if captureOutput:
267            capture="> " + make_stdout + " 2> " + make_stderr
268            command+=capture
269        if os.system(command) != 0:
270            msg = "Ghostscript update failed during make\n\n"
271            msg = msg + "stdout log:\n\n"
272            msg = msg + read_all_lines(make_stdout)
273            msg = msg + "\nstderr log:\n\n"
274            msg = msg + read_all_lines(make_stderr)
275            logMessage(message,cumulative_file,revision)
276            return (1,msg)
277
278        message="make complete"
279        logMessage(message,update_stdout_file,revision,printMessage=False)
280        logMessage(message,cumulative_file,revision)
281
282    if revision == "HEAD":
283        command="make install "
284        logMessage(command,update_stdout_file,revision,printMessage=False)
285        logMessage(command,cumulative_file,revision)
286        if captureOutput:
287            capture="> " + install_stdout + " 2> " + install_stderr
288            command+=capture
289        if os.system(command) != 0:
290            msg = "Ghostscript update failed during install\n\n"
291            msg = msg + "stdout log:\n\n"
292            msg = msg + read_all_lines(install_stdout)
293            msg = msg + "\nstderr log:\n\n"
294            msg = msg + read_all_lines(install_stderr)
295            logMessage(message,cumulative_file,revision)
296            return (1,msg)
297
298        message="make install complete"
299        logMessage(message,update_stdout_file,revision,printMessage=False)
300        logMessage(message,cumulative_file,revision)
301
302        message="installation directory tree is "+gsroot
303        logMessage(message,cumulative_file,revision)
304
305    revision_file_name="revision"
306    revision_file = open(revision_file_name, "w")
307    message=revision_value+"\n"
308    revision_file.write(message)
309    revision_file.close()
310
311    os.chdir(cwd) # return to directory
312
313    update_stdout_file.close()
314
315    return (0,"success")
316
317#########################################################
318
319if __name__ == "__main__":
320
321    os.umask(0002)
322
323    optionsParser=optparse.OptionParser()
324
325    optionsParser.add_option('--version',action='store_true',help="get my version")
326
327    optionsParser.add_option('--revision',action='store',help="under contruction",default="HEAD")
328    optionsParser.add_option('--release',action='store',help="under contruction",default=None)
329
330    optionsParser.add_option('--time','-m',action='store',help="provide start time",default=None)
331
332    optionsParser.add_option('--nosvn',action='store_true',help="do not update the revision source from the svn repository")
333    optionsParser.add_option('--noconfigure',action='store_true',help="do not run auto configure")
334    optionsParser.add_option('--nomakeclean',action='store_true',help="do not make clean before make")
335    optionsParser.add_option('--nomake',action='store_true',help="do not make")
336
337    optionsParser.add_option('--nocapture',action='store_true',help="do not capture stdout and stderr from commands")
338
339    optionsParser.add_option('--remove',action='store_true',help="remove the built directories")
340
341    (options,arguments)=myoptparse.parseCommandLineBasic(optionsParser)
342
343    myself=options.myself
344
345    if options.version:
346        print options.myself,"version",myversion
347        sys.exit(1)
348
349    options.svn       = not options.nosvn
350    options.configure = not options.noconfigure
351    options.make      = not options.nomake
352    options.makeclean = not options.nomakeclean
353
354    options.capture   = not options.nocapture
355
356    revision          = options.revision
357    release           = options.release
358
359    now=options.time
360
361    logdir=gsconf.logdir
362    if not os.path.exists(logdir):
363        os.mkdir(logdir)
364
365    if now:
366        pass # use command line value of time
367    else:
368        now=time.strftime("%Y-%m-%d-%H:%M:%S", time.localtime())
369
370    print myself,revision
371    if revision == "HEAD":
372        prefix=logdir+now+"."
373        gsroot=gsconf.gsroot
374        gspath=gsconf.installtree+"bin/gs"
375        gsinstall=gsconf.installtree
376    else:
377        prefix=logdir+revision+"."+now+"."
378        gsroot=gsconf.root+"gs."+revision+"/"
379        gspath=gsroot+"bin/gs"
380        gsinstall=None
381
382    update_stdout=prefix+gsconf.update_stdout
383    update_stderr=prefix+gsconf.update_stderr
384    config_stdout=prefix+gsconf.config_stdout
385    config_stderr=prefix+gsconf.config_stderr
386    make_stdout=prefix+gsconf.make_stdout
387    make_stderr=prefix+gsconf.make_stderr
388    install_stdout=prefix+gsconf.install_stdout
389    install_stderr=prefix+gsconf.install_stderr
390
391    cumulative_file=None
392
393    (err,message) = update_ghostscript(revision,release,
394                             gsroot,
395                             options,
396                             update_stdout,update_stderr,
397                             config_stdout,config_stderr,
398                             make_stdout,make_stderr,
399                             install_stdout,install_stderr,
400                             cumulative_file=None
401                             )
402    if err != 0:
403        print message
404        sys.exit(1)
405
406    revision=get_revision(gsroot)
407
408    if not os.path.exists(gspath):
409        message=myself+" FATAL "+"the gs executable does not exist "+gspath
410        logMessage(message,None,revision)
411        sys.exit(1)
412
413    if options.remove:
414        if os.path.exists(gsroot):
415            print "shutil.rmtree(gsroot)",gsroot
416            shutil.rmtree(gsroot)
417            if gsinstall:
418                print "shutil.rmtree(gsinstall)",gsinstall
419                shutil.rmtree(gsinstall)
420
421    print myself,revision,"done"
422
423    sys.exit(0)
424