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