2009-06-18 22:17:17 +00:00
|
|
|
#!/usr/bin/python
|
|
|
|
# __________ __ ___.
|
|
|
|
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
|
|
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
|
|
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
|
|
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
|
|
# \/ \/ \/ \/ \/
|
|
|
|
# $Id$
|
|
|
|
#
|
|
|
|
# Copyright (c) 2009 Dominik Riebeling
|
|
|
|
#
|
|
|
|
# All files in this archive are subject to the GNU General Public License.
|
|
|
|
# See the file COPYING in the source tree root for full license agreement.
|
|
|
|
#
|
|
|
|
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
|
|
# KIND, either express or implied.
|
|
|
|
#
|
|
|
|
#
|
|
|
|
# Automate building releases for deployment.
|
2009-10-04 16:45:59 +00:00
|
|
|
# Run from any folder to build
|
|
|
|
# - trunk
|
|
|
|
# - any tag (using the -t option)
|
|
|
|
# - any local folder (using the -p option)
|
|
|
|
# Will build a binary archive (tar.bz2 / zip) and source archive.
|
|
|
|
# The source archive won't be built for local builds. Trunk and
|
|
|
|
# tag builds will retrieve the sources directly from svn and build
|
|
|
|
# below the systems temporary folder.
|
|
|
|
#
|
2009-06-18 22:17:17 +00:00
|
|
|
# If the required Qt installation isn't in PATH use --qmake option.
|
|
|
|
# Tested on Linux and MinGW / W32
|
|
|
|
#
|
|
|
|
# requires python which package (http://code.google.com/p/which/)
|
2009-10-04 16:45:59 +00:00
|
|
|
# requires pysvn package.
|
2009-06-18 22:17:17 +00:00
|
|
|
# requires upx.exe in PATH on Windows.
|
|
|
|
#
|
|
|
|
|
|
|
|
import re
|
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
import tarfile
|
|
|
|
import zipfile
|
|
|
|
import shutil
|
|
|
|
import subprocess
|
|
|
|
import getopt
|
2009-09-20 14:59:29 +00:00
|
|
|
import time
|
2009-10-04 16:45:59 +00:00
|
|
|
import hashlib
|
|
|
|
import tempfile
|
2011-03-06 00:04:26 +00:00
|
|
|
import string
|
2009-06-18 22:17:17 +00:00
|
|
|
|
2009-10-30 21:40:07 +00:00
|
|
|
# modules that are not part of python itself.
|
|
|
|
try:
|
|
|
|
import pysvn
|
|
|
|
except ImportError:
|
|
|
|
print "Fatal: This script requires the pysvn package to run."
|
|
|
|
print " See http://pysvn.tigris.org/."
|
|
|
|
sys.exit(-5)
|
|
|
|
try:
|
|
|
|
import which
|
|
|
|
except ImportError:
|
|
|
|
print "Fatal: This script requires the which package to run."
|
|
|
|
print " See http://code.google.com/p/which/."
|
|
|
|
sys.exit(-5)
|
2010-12-19 20:10:22 +00:00
|
|
|
cpus = 1
|
|
|
|
try:
|
|
|
|
import multiprocessing
|
|
|
|
cpus = multiprocessing.cpu_count()
|
|
|
|
print "Info: %s cores found." % cpus
|
|
|
|
except ImportError:
|
|
|
|
print "Warning: multiprocessing module not found. Assuming 1 core."
|
2009-10-30 21:40:07 +00:00
|
|
|
|
2009-06-18 22:17:17 +00:00
|
|
|
# == Global stuff ==
|
2010-08-30 17:51:53 +00:00
|
|
|
# DLL files to ignore when searching for required DLL files.
|
|
|
|
systemdlls = ['advapi32.dll',
|
|
|
|
'comdlg32.dll',
|
|
|
|
'gdi32.dll',
|
|
|
|
'imm32.dll',
|
|
|
|
'kernel32.dll',
|
|
|
|
'msvcrt.dll',
|
|
|
|
'msvcrt.dll',
|
|
|
|
'netapi32.dll',
|
|
|
|
'ole32.dll',
|
|
|
|
'oleaut32.dll',
|
|
|
|
'setupapi.dll',
|
|
|
|
'shell32.dll',
|
|
|
|
'user32.dll',
|
|
|
|
'winmm.dll',
|
|
|
|
'winspool.drv',
|
|
|
|
'ws2_32.dll']
|
|
|
|
|
|
|
|
|
2009-06-18 22:17:17 +00:00
|
|
|
# == Functions ==
|
|
|
|
def usage(myself):
|
|
|
|
print "Usage: %s [options]" % myself
|
|
|
|
print " -q, --qmake=<qmake> path to qmake"
|
2009-10-04 16:45:59 +00:00
|
|
|
print " -p, --project=<pro> path to .pro file for building with local tree"
|
|
|
|
print " -t, --tag=<tag> use specified tag from svn"
|
2009-10-04 21:17:59 +00:00
|
|
|
print " -a, --add=<file> add file to build folder before building"
|
2009-10-05 18:35:28 +00:00
|
|
|
print " -s, --source-only only create source archive"
|
|
|
|
print " -b, --binary-only only create binary archive"
|
2010-08-08 20:56:58 +00:00
|
|
|
if nsisscript != "":
|
|
|
|
print " -n, --makensis=<file> path to makensis for building Windows setup program."
|
2009-11-29 21:09:21 +00:00
|
|
|
if sys.platform != "darwin":
|
|
|
|
print " -d, --dynamic link dynamically instead of static"
|
2011-03-06 00:04:26 +00:00
|
|
|
if sys.platform != "win32":
|
|
|
|
print " -x, --cross= prefix to cross compile for win32"
|
2010-03-31 20:52:07 +00:00
|
|
|
print " -k, --keep-temp keep temporary folder on build failure"
|
2009-06-18 22:17:17 +00:00
|
|
|
print " -h, --help this help"
|
2009-10-04 16:45:59 +00:00
|
|
|
print " If neither a project file nor tag is specified trunk will get downloaded"
|
|
|
|
print " from svn."
|
|
|
|
|
2011-03-06 00:04:26 +00:00
|
|
|
|
2009-10-04 16:45:59 +00:00
|
|
|
def getsources(svnsrv, filelist, dest):
|
|
|
|
'''Get the files listed in filelist from svnsrv and put it at dest.'''
|
|
|
|
client = pysvn.Client()
|
|
|
|
print "Checking out sources from %s, please wait." % svnsrv
|
|
|
|
|
|
|
|
for elem in filelist:
|
|
|
|
url = re.subn('/$', '', svnsrv + elem)[0]
|
|
|
|
destpath = re.subn('/$', '', dest + elem)[0]
|
2009-11-20 21:04:23 +00:00
|
|
|
# make sure the destination path does exist
|
|
|
|
d = os.path.dirname(destpath)
|
|
|
|
if not os.path.exists(d):
|
|
|
|
os.makedirs(d)
|
|
|
|
# get from svn
|
2009-10-04 16:45:59 +00:00
|
|
|
try:
|
|
|
|
client.export(url, destpath)
|
|
|
|
except:
|
|
|
|
print "SVN client error: %s" % sys.exc_value
|
2009-11-20 21:04:23 +00:00
|
|
|
print "URL: %s, destination: %s" % (url, destpath)
|
2009-10-04 16:45:59 +00:00
|
|
|
return -1
|
|
|
|
print "Checkout finished."
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
2011-05-08 19:34:03 +00:00
|
|
|
def getfolderrev(svnsrv):
|
|
|
|
'''Get the most recent revision for svnsrv'''
|
2009-10-04 16:45:59 +00:00
|
|
|
client = pysvn.Client()
|
|
|
|
entries = client.info2(svnsrv, recurse=False)
|
|
|
|
return entries[0][1].rev.number
|
2009-06-18 22:17:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
def findversion(versionfile):
|
|
|
|
'''figure most recent program version from version.h,
|
|
|
|
returns version string.'''
|
|
|
|
h = open(versionfile, "r")
|
|
|
|
c = h.read()
|
|
|
|
h.close()
|
|
|
|
r = re.compile("#define +VERSION +\"(.[0-9\.a-z]+)\"")
|
|
|
|
m = re.search(r, c)
|
|
|
|
s = re.compile("\$Revision: +([0-9]+)")
|
|
|
|
n = re.search(s, c)
|
|
|
|
if n == None:
|
|
|
|
print "WARNING: Revision not found!"
|
|
|
|
return m.group(1)
|
|
|
|
|
|
|
|
|
2011-03-06 00:04:26 +00:00
|
|
|
def findqt(cross=""):
|
2009-06-18 22:17:17 +00:00
|
|
|
'''Search for Qt4 installation. Return path to qmake.'''
|
|
|
|
print "Searching for Qt"
|
2011-03-06 00:04:26 +00:00
|
|
|
bins = [cross + "qmake", cross + "qmake-qt4"]
|
2009-06-18 22:17:17 +00:00
|
|
|
for binary in bins:
|
2009-10-03 18:16:41 +00:00
|
|
|
try:
|
|
|
|
q = which.which(binary)
|
|
|
|
if len(q) > 0:
|
|
|
|
result = checkqt(q)
|
|
|
|
if not result == "":
|
|
|
|
return result
|
|
|
|
except:
|
|
|
|
print sys.exc_value
|
|
|
|
|
|
|
|
return ""
|
2009-10-03 17:19:07 +00:00
|
|
|
|
2009-06-18 22:17:17 +00:00
|
|
|
|
2009-10-03 17:19:07 +00:00
|
|
|
def checkqt(qmakebin):
|
|
|
|
'''Check if given path to qmake exists and is a suitable version.'''
|
|
|
|
result = ""
|
|
|
|
# check if binary exists
|
|
|
|
if not os.path.exists(qmakebin):
|
|
|
|
print "Specified qmake path does not exist!"
|
|
|
|
return result
|
|
|
|
# check version
|
|
|
|
output = subprocess.Popen([qmakebin, "-version"], stdout=subprocess.PIPE,
|
|
|
|
stderr=subprocess.PIPE)
|
|
|
|
cmdout = output.communicate()
|
|
|
|
# don't check the qmake return code here, Qt3 doesn't return 0 on -version.
|
|
|
|
for ou in cmdout:
|
|
|
|
r = re.compile("Qt[^0-9]+([0-9\.]+[a-z]*)")
|
|
|
|
m = re.search(r, ou)
|
|
|
|
if not m == None:
|
|
|
|
print "Qt found: %s" % m.group(1)
|
|
|
|
s = re.compile("4\..*")
|
|
|
|
n = re.search(s, m.group(1))
|
|
|
|
if not n == None:
|
|
|
|
result = qmakebin
|
2009-06-18 22:17:17 +00:00
|
|
|
return result
|
|
|
|
|
|
|
|
|
2011-03-06 00:04:26 +00:00
|
|
|
def qmake(qmake, projfile, platform=sys.platform, wd=".", static=True, cross=""):
|
2009-10-04 16:45:59 +00:00
|
|
|
print "Running qmake in %s..." % wd
|
2009-10-05 18:35:28 +00:00
|
|
|
command = [qmake, "-config", "release", "-config", "noccache"]
|
|
|
|
if static == True:
|
2011-03-06 00:04:26 +00:00
|
|
|
command.extend(["-config", "-static"])
|
|
|
|
# special spec required?
|
|
|
|
if len(qmakespec[platform]) > 0:
|
|
|
|
command.extend(["-spec", qmakespec[platform]])
|
|
|
|
# cross compiling prefix set?
|
|
|
|
if len(cross) > 0:
|
|
|
|
command.extend(["-config", "cross"])
|
2009-10-05 18:35:28 +00:00
|
|
|
command.append(projfile)
|
2011-03-06 00:04:26 +00:00
|
|
|
output = subprocess.Popen(command, stdout=subprocess.PIPE, cwd=wd)
|
2009-10-03 17:19:07 +00:00
|
|
|
output.communicate()
|
|
|
|
if not output.returncode == 0:
|
|
|
|
print "qmake returned an error!"
|
|
|
|
return -1
|
|
|
|
return 0
|
2009-06-18 22:17:17 +00:00
|
|
|
|
|
|
|
|
2011-03-06 00:04:26 +00:00
|
|
|
def build(wd=".", platform=sys.platform, cross=""):
|
2009-06-18 22:17:17 +00:00
|
|
|
# make
|
|
|
|
print "Building ..."
|
2011-03-06 00:04:26 +00:00
|
|
|
# use the current platforms make here, cross compiling uses the native make.
|
|
|
|
command = [make[sys.platform]]
|
2010-12-19 20:10:22 +00:00
|
|
|
if cpus > 1:
|
|
|
|
command.append("-j")
|
|
|
|
command.append(str(cpus))
|
|
|
|
output = subprocess.Popen(command, stdout=subprocess.PIPE, cwd=wd)
|
2009-10-22 22:02:56 +00:00
|
|
|
while True:
|
|
|
|
c = output.stdout.readline()
|
|
|
|
sys.stdout.write(".")
|
|
|
|
sys.stdout.flush()
|
|
|
|
if not output.poll() == None:
|
|
|
|
sys.stdout.write("\n")
|
|
|
|
sys.stdout.flush()
|
|
|
|
if not output.returncode == 0:
|
|
|
|
print "Build failed!"
|
|
|
|
return -1
|
|
|
|
break
|
2011-03-06 00:04:26 +00:00
|
|
|
if platform != "darwin":
|
2009-11-29 21:09:21 +00:00
|
|
|
# strip. OS X handles this via macdeployqt.
|
|
|
|
print "Stripping binary."
|
2011-03-06 00:04:26 +00:00
|
|
|
output = subprocess.Popen([cross + "strip", progexe[platform]], \
|
|
|
|
stdout=subprocess.PIPE, cwd=wd)
|
2009-11-29 21:09:21 +00:00
|
|
|
output.communicate()
|
|
|
|
if not output.returncode == 0:
|
|
|
|
print "Stripping failed!"
|
|
|
|
return -1
|
2009-10-03 17:19:07 +00:00
|
|
|
return 0
|
2009-06-18 22:17:17 +00:00
|
|
|
|
|
|
|
|
2011-03-06 00:04:26 +00:00
|
|
|
def upxfile(wd=".", platform=sys.platform):
|
2009-06-18 22:17:17 +00:00
|
|
|
# run upx on binary
|
|
|
|
print "UPX'ing binary ..."
|
2011-03-06 00:04:26 +00:00
|
|
|
output = subprocess.Popen(["upx", progexe[platform]], \
|
|
|
|
stdout=subprocess.PIPE, cwd=wd)
|
2009-10-03 17:19:07 +00:00
|
|
|
output.communicate()
|
|
|
|
if not output.returncode == 0:
|
|
|
|
print "UPX'ing failed!"
|
|
|
|
return -1
|
|
|
|
return 0
|
2009-06-18 22:17:17 +00:00
|
|
|
|
|
|
|
|
2010-08-30 17:51:53 +00:00
|
|
|
def runnsis(versionstring, nsis, script, srcfolder):
|
2010-08-08 20:56:58 +00:00
|
|
|
# run script through nsis to create installer.
|
|
|
|
print "Running NSIS ..."
|
2010-08-30 17:51:53 +00:00
|
|
|
|
2010-08-08 20:56:58 +00:00
|
|
|
# Assume the generated installer gets placed in the same folder the nsi
|
|
|
|
# script lives in. This seems to be a valid assumption unless the nsi
|
|
|
|
# script specifies a path. NSIS expects files relative to source folder so
|
2010-08-30 17:51:53 +00:00
|
|
|
# copy progexe. Additional files are injected into the nsis script.
|
|
|
|
|
|
|
|
# FIXME: instead of copying binaries around copy the NSI file and inject
|
|
|
|
# the correct paths.
|
2011-03-06 00:04:26 +00:00
|
|
|
# Only win32 supported as target platform so hard coded.
|
|
|
|
b = srcfolder + "/" + os.path.dirname(script) + "/" \
|
|
|
|
+ os.path.dirname(progexe["win32"])
|
2010-08-30 17:51:53 +00:00
|
|
|
if not os.path.exists(b):
|
|
|
|
os.mkdir(b)
|
2011-03-06 00:04:26 +00:00
|
|
|
shutil.copy(srcfolder + "/" + progexe["win32"], b)
|
|
|
|
output = subprocess.Popen([nsis, srcfolder + "/" + script], \
|
|
|
|
stdout=subprocess.PIPE)
|
2010-08-08 20:56:58 +00:00
|
|
|
output.communicate()
|
|
|
|
if not output.returncode == 0:
|
|
|
|
print "NSIS failed!"
|
|
|
|
return -1
|
|
|
|
setupfile = program + "-" + versionstring + "-setup.exe"
|
2010-08-09 17:44:03 +00:00
|
|
|
# find output filename in nsis script file
|
|
|
|
nsissetup = ""
|
2010-08-30 17:51:53 +00:00
|
|
|
for line in open(srcfolder + "/" + script):
|
2010-08-09 17:44:03 +00:00
|
|
|
if re.match(r'^[^;]*OutFile\s+', line) != None:
|
|
|
|
nsissetup = re.sub(r'^[^;]*OutFile\s+"(.+)"', r'\1', line).rstrip()
|
|
|
|
if nsissetup == "":
|
|
|
|
print "Could not retrieve output file name!"
|
|
|
|
return -1
|
2011-03-06 00:04:26 +00:00
|
|
|
shutil.copy(srcfolder + "/" + os.path.dirname(script) + "/" + nsissetup, \
|
|
|
|
setupfile)
|
2010-08-08 20:56:58 +00:00
|
|
|
return 0
|
|
|
|
|
|
|
|
|
2010-08-30 17:51:53 +00:00
|
|
|
def nsisfileinject(nsis, outscript, filelist):
|
|
|
|
'''Inject files in filelist into NSIS script file after the File line
|
|
|
|
containing the main binary. This assumes that the main binary is present
|
|
|
|
in the NSIS script and that all additiona files (dlls etc) to get placed
|
|
|
|
into $INSTDIR.'''
|
|
|
|
output = open(outscript, "w")
|
|
|
|
for line in open(nsis, "r"):
|
|
|
|
output.write(line)
|
2011-03-06 00:04:26 +00:00
|
|
|
# inject files after the progexe binary.
|
|
|
|
# Match the basename only to avoid path mismatches.
|
|
|
|
if re.match(r'^\s*File\s*.*' + os.path.basename(progexe["win32"]), \
|
|
|
|
line, re.IGNORECASE):
|
2010-08-30 17:51:53 +00:00
|
|
|
for f in filelist:
|
2011-03-06 00:04:26 +00:00
|
|
|
injection = " File /oname=$INSTDIR\\" + os.path.basename(f) \
|
|
|
|
+ " " + os.path.normcase(f) + "\n"
|
2010-08-30 17:51:53 +00:00
|
|
|
output.write(injection)
|
|
|
|
output.write(" ; end of injected files\n")
|
|
|
|
output.close()
|
|
|
|
|
|
|
|
|
2011-03-06 00:04:26 +00:00
|
|
|
def finddlls(program, extrapaths=[], cross=""):
|
2010-08-30 17:51:53 +00:00
|
|
|
'''Check program for required DLLs. Find all required DLLs except ignored
|
|
|
|
ones and return a list of DLL filenames (including path).'''
|
|
|
|
# ask objdump about dependencies.
|
2011-03-06 00:04:26 +00:00
|
|
|
output = subprocess.Popen([cross + "objdump", "-x", program], \
|
|
|
|
stdout=subprocess.PIPE)
|
2010-08-30 17:51:53 +00:00
|
|
|
cmdout = output.communicate()
|
|
|
|
|
|
|
|
# create list of used DLLs. Store as lower case as W32 is case-insensitive.
|
|
|
|
dlls = []
|
|
|
|
for line in cmdout[0].split('\n'):
|
|
|
|
if re.match(r'\s*DLL Name', line) != None:
|
2010-09-23 16:47:23 +00:00
|
|
|
dll = re.sub(r'^\s*DLL Name:\s+([a-zA-Z_\-0-9\.\+]+).*$', r'\1', line)
|
2010-08-30 17:51:53 +00:00
|
|
|
dlls.append(dll.lower())
|
|
|
|
|
|
|
|
# find DLLs in extrapaths and PATH environment variable.
|
|
|
|
dllpaths = []
|
|
|
|
for file in dlls:
|
|
|
|
if file in systemdlls:
|
2011-03-06 17:37:27 +00:00
|
|
|
print "System DLL: " + file
|
2010-08-30 17:51:53 +00:00
|
|
|
continue
|
|
|
|
dllpath = ""
|
|
|
|
for path in extrapaths:
|
|
|
|
if os.path.exists(path + "/" + file):
|
|
|
|
dllpath = re.sub(r"\\", r"/", path + "/" + file)
|
2011-03-06 00:04:26 +00:00
|
|
|
print file + ": found at " + dllpath
|
2010-08-30 17:51:53 +00:00
|
|
|
dllpaths.append(dllpath)
|
|
|
|
break
|
|
|
|
if dllpath == "":
|
|
|
|
try:
|
|
|
|
dllpath = re.sub(r"\\", r"/", which.which(file))
|
2011-03-06 00:04:26 +00:00
|
|
|
print file + ": found at " + dllpath
|
|
|
|
dllpaths.append(dllpath)
|
2010-08-30 17:51:53 +00:00
|
|
|
except:
|
2011-03-06 17:37:27 +00:00
|
|
|
print "MISSING DLL: " + file
|
2010-08-30 17:51:53 +00:00
|
|
|
return dllpaths
|
|
|
|
|
|
|
|
|
2011-03-06 17:37:27 +00:00
|
|
|
def zipball(programfiles, versionstring, buildfolder, platform=sys.platform):
|
2009-06-18 22:17:17 +00:00
|
|
|
'''package created binary'''
|
|
|
|
print "Creating binary zipball."
|
2009-10-04 16:45:59 +00:00
|
|
|
archivebase = program + "-" + versionstring
|
|
|
|
outfolder = buildfolder + "/" + archivebase
|
|
|
|
archivename = archivebase + ".zip"
|
2009-06-18 22:17:17 +00:00
|
|
|
# create output folder
|
|
|
|
os.mkdir(outfolder)
|
|
|
|
# move program files to output folder
|
|
|
|
for f in programfiles:
|
2010-08-30 17:51:53 +00:00
|
|
|
if re.match(r'^(/|[a-zA-Z]:)', f) != None:
|
|
|
|
shutil.copy(f, outfolder)
|
|
|
|
else:
|
|
|
|
shutil.copy(buildfolder + "/" + f, outfolder)
|
2009-06-18 22:17:17 +00:00
|
|
|
# create zipball from output folder
|
|
|
|
zf = zipfile.ZipFile(archivename, mode='w', compression=zipfile.ZIP_DEFLATED)
|
|
|
|
for root, dirs, files in os.walk(outfolder):
|
|
|
|
for name in files:
|
2011-03-06 00:04:26 +00:00
|
|
|
physname = os.path.normpath(os.path.join(root, name))
|
|
|
|
filename = string.replace(physname, os.path.normpath(buildfolder), "")
|
2009-10-04 16:45:59 +00:00
|
|
|
zf.write(physname, filename)
|
2009-06-18 22:17:17 +00:00
|
|
|
for name in dirs:
|
2011-03-06 00:04:26 +00:00
|
|
|
physname = os.path.normpath(os.path.join(root, name))
|
|
|
|
filename = string.replace(physname, os.path.normpath(buildfolder), "")
|
2009-10-04 16:45:59 +00:00
|
|
|
zf.write(physname, filename)
|
2009-06-18 22:17:17 +00:00
|
|
|
zf.close()
|
|
|
|
# remove output folder
|
2009-10-04 16:45:59 +00:00
|
|
|
shutil.rmtree(outfolder)
|
2009-10-03 17:19:07 +00:00
|
|
|
return archivename
|
2009-06-18 22:17:17 +00:00
|
|
|
|
|
|
|
|
2011-03-06 17:37:27 +00:00
|
|
|
def tarball(programfiles, versionstring, buildfolder):
|
2009-06-18 22:17:17 +00:00
|
|
|
'''package created binary'''
|
|
|
|
print "Creating binary tarball."
|
2009-10-04 16:45:59 +00:00
|
|
|
archivebase = program + "-" + versionstring
|
|
|
|
outfolder = buildfolder + "/" + archivebase
|
|
|
|
archivename = archivebase + ".tar.bz2"
|
2009-06-18 22:17:17 +00:00
|
|
|
# create output folder
|
|
|
|
os.mkdir(outfolder)
|
|
|
|
# move program files to output folder
|
|
|
|
for f in programfiles:
|
2009-10-04 16:45:59 +00:00
|
|
|
shutil.copy(buildfolder + "/" + f, outfolder)
|
2009-06-18 22:17:17 +00:00
|
|
|
# create tarball from output folder
|
|
|
|
tf = tarfile.open(archivename, mode='w:bz2')
|
2009-10-04 16:45:59 +00:00
|
|
|
tf.add(outfolder, archivebase)
|
2009-06-18 22:17:17 +00:00
|
|
|
tf.close()
|
|
|
|
# remove output folder
|
2009-10-04 16:45:59 +00:00
|
|
|
shutil.rmtree(outfolder)
|
2009-10-03 17:19:07 +00:00
|
|
|
return archivename
|
2009-06-18 22:17:17 +00:00
|
|
|
|
|
|
|
|
2011-03-06 00:04:26 +00:00
|
|
|
def macdeploy(versionstring, buildfolder, platform=sys.platform):
|
2009-11-29 21:09:21 +00:00
|
|
|
'''package created binary to dmg'''
|
|
|
|
dmgfile = program + "-" + versionstring + ".dmg"
|
2011-03-06 00:04:26 +00:00
|
|
|
appbundle = buildfolder + "/" + progexe[platform]
|
2009-11-29 21:09:21 +00:00
|
|
|
|
2010-07-10 21:22:22 +00:00
|
|
|
# workaround to Qt issues when building out-of-tree. Copy files into bundle.
|
2010-07-28 21:05:16 +00:00
|
|
|
sourcebase = buildfolder + re.sub('[^/]+.pro$', '', project) + "/"
|
|
|
|
print sourcebase
|
2010-07-10 21:22:22 +00:00
|
|
|
for src in bundlecopy:
|
2010-07-28 21:05:16 +00:00
|
|
|
shutil.copy(sourcebase + src, appbundle + "/" + bundlecopy[src])
|
2009-11-29 21:09:21 +00:00
|
|
|
# end of Qt workaround
|
|
|
|
|
2011-03-06 00:04:26 +00:00
|
|
|
output = subprocess.Popen(["macdeployqt", progexe[platform], "-dmg"], \
|
|
|
|
stdout=subprocess.PIPE, cwd=buildfolder)
|
2009-11-29 21:09:21 +00:00
|
|
|
output.communicate()
|
|
|
|
if not output.returncode == 0:
|
|
|
|
print "macdeployqt failed!"
|
|
|
|
return -1
|
|
|
|
# copy dmg to output folder
|
|
|
|
shutil.copy(buildfolder + "/" + program + ".dmg", dmgfile)
|
|
|
|
return dmgfile
|
|
|
|
|
2011-03-06 00:04:26 +00:00
|
|
|
|
2009-10-04 16:45:59 +00:00
|
|
|
def filehashes(filename):
|
|
|
|
'''Calculate md5 and sha1 hashes for a given file.'''
|
|
|
|
if not os.path.exists(filename):
|
|
|
|
return ["", ""]
|
|
|
|
m = hashlib.md5()
|
|
|
|
s = hashlib.sha1()
|
|
|
|
f = open(filename, 'rb')
|
|
|
|
while True:
|
|
|
|
d = f.read(65536)
|
|
|
|
if d == "":
|
|
|
|
break
|
|
|
|
m.update(d)
|
|
|
|
s.update(d)
|
|
|
|
return [m.hexdigest(), s.hexdigest()]
|
|
|
|
|
|
|
|
|
|
|
|
def filestats(filename):
|
|
|
|
if not os.path.exists(filename):
|
|
|
|
return
|
|
|
|
st = os.stat(filename)
|
|
|
|
print filename, "\n", "-" * len(filename)
|
|
|
|
print "Size: %i bytes" % st.st_size
|
|
|
|
h = filehashes(filename)
|
|
|
|
print "md5sum: %s" % h[0]
|
|
|
|
print "sha1sum: %s" % h[1]
|
|
|
|
print "-" * len(filename), "\n"
|
|
|
|
|
|
|
|
|
2010-03-31 20:52:07 +00:00
|
|
|
def tempclean(workfolder, nopro):
|
|
|
|
if nopro == True:
|
|
|
|
print "Cleaning up working folder %s" % workfolder
|
|
|
|
shutil.rmtree(workfolder)
|
|
|
|
else:
|
|
|
|
print "Project file specified or cleanup disabled!"
|
|
|
|
print "Temporary files kept at %s" % workfolder
|
|
|
|
|
|
|
|
|
2010-07-28 18:37:12 +00:00
|
|
|
def deploy():
|
2009-09-20 14:59:29 +00:00
|
|
|
startup = time.time()
|
2010-07-28 18:37:12 +00:00
|
|
|
|
2009-06-18 22:17:17 +00:00
|
|
|
try:
|
2011-05-05 17:19:00 +00:00
|
|
|
opts, args = getopt.getopt(sys.argv[1:], "q:p:t:a:n:sbdkx:i:h",
|
2011-03-06 00:04:26 +00:00
|
|
|
["qmake=", "project=", "tag=", "add=", "makensis=", "source-only",
|
2011-05-05 17:19:00 +00:00
|
|
|
"binary-only", "dynamic", "keep-temp", "cross=", "buildid=", "help"])
|
2009-06-18 22:17:17 +00:00
|
|
|
except getopt.GetoptError, err:
|
|
|
|
print str(err)
|
|
|
|
usage(sys.argv[0])
|
|
|
|
sys.exit(1)
|
|
|
|
qt = ""
|
2009-10-04 16:45:59 +00:00
|
|
|
proj = ""
|
|
|
|
svnbase = svnserver + "trunk/"
|
|
|
|
tag = ""
|
2009-10-04 21:17:59 +00:00
|
|
|
addfiles = []
|
2009-10-04 16:45:59 +00:00
|
|
|
cleanup = True
|
2009-10-05 18:35:28 +00:00
|
|
|
binary = True
|
|
|
|
source = True
|
2010-03-31 20:52:07 +00:00
|
|
|
keeptemp = False
|
2010-08-08 20:56:58 +00:00
|
|
|
makensis = ""
|
2011-03-06 00:04:26 +00:00
|
|
|
cross = ""
|
2011-05-05 17:19:00 +00:00
|
|
|
buildid = None
|
2011-03-06 00:04:26 +00:00
|
|
|
platform = sys.platform
|
2009-11-29 21:09:21 +00:00
|
|
|
if sys.platform != "darwin":
|
|
|
|
static = True
|
|
|
|
else:
|
|
|
|
static = False
|
2009-06-18 22:17:17 +00:00
|
|
|
for o, a in opts:
|
|
|
|
if o in ("-q", "--qmake"):
|
|
|
|
qt = a
|
2009-10-03 20:42:02 +00:00
|
|
|
if o in ("-p", "--project"):
|
|
|
|
proj = a
|
2009-10-04 16:45:59 +00:00
|
|
|
cleanup = False
|
|
|
|
if o in ("-t", "--tag"):
|
|
|
|
tag = a
|
|
|
|
svnbase = svnserver + "tags/" + tag + "/"
|
2009-10-04 21:17:59 +00:00
|
|
|
if o in ("-a", "--add"):
|
|
|
|
addfiles.append(a)
|
2010-08-08 20:56:58 +00:00
|
|
|
if o in ("-n", "--makensis"):
|
|
|
|
makensis = a
|
2009-10-05 18:35:28 +00:00
|
|
|
if o in ("-s", "--source-only"):
|
|
|
|
binary = False
|
|
|
|
if o in ("-b", "--binary-only"):
|
|
|
|
source = False
|
2009-11-29 21:09:21 +00:00
|
|
|
if o in ("-d", "--dynamic") and sys.platform != "darwin":
|
2009-10-05 18:35:28 +00:00
|
|
|
static = False
|
2010-03-31 20:52:07 +00:00
|
|
|
if o in ("-k", "--keep-temp"):
|
|
|
|
keeptemp = True
|
2011-03-06 00:04:26 +00:00
|
|
|
if o in ("-x", "--cross") and sys.platform != "win32":
|
|
|
|
cross = a
|
|
|
|
platform = "win32"
|
2011-05-05 17:19:00 +00:00
|
|
|
if o in ("-i", "--buildid"):
|
|
|
|
buildid = a
|
2009-06-18 22:17:17 +00:00
|
|
|
if o in ("-h", "--help"):
|
|
|
|
usage(sys.argv[0])
|
|
|
|
sys.exit(0)
|
|
|
|
|
2009-10-05 18:35:28 +00:00
|
|
|
if source == False and binary == False:
|
|
|
|
print "Building build neither source nor binary means nothing to do. Exiting."
|
|
|
|
sys.exit(1)
|
|
|
|
|
2011-03-06 00:04:26 +00:00
|
|
|
print "Building " + progexe[platform] + " for " + platform
|
2009-10-04 16:45:59 +00:00
|
|
|
# search for qmake
|
2009-06-18 22:17:17 +00:00
|
|
|
if qt == "":
|
2011-03-06 00:04:26 +00:00
|
|
|
qm = findqt(cross)
|
2009-10-03 17:19:07 +00:00
|
|
|
else:
|
|
|
|
qm = checkqt(qt)
|
|
|
|
if qm == "":
|
2009-06-18 22:17:17 +00:00
|
|
|
print "ERROR: No suitable Qt installation found."
|
2009-10-03 17:19:07 +00:00
|
|
|
sys.exit(1)
|
2009-10-04 16:45:59 +00:00
|
|
|
|
|
|
|
# create working folder. Use current directory if -p option used.
|
|
|
|
if proj == "":
|
|
|
|
w = tempfile.mkdtemp()
|
|
|
|
# make sure the path doesn't contain backslashes to prevent issues
|
|
|
|
# later when running on windows.
|
|
|
|
workfolder = re.sub(r'\\', '/', w)
|
2011-05-08 19:34:03 +00:00
|
|
|
revision = getfolderrev(svnbase)
|
2011-05-05 17:19:00 +00:00
|
|
|
if buildid == None:
|
|
|
|
versionextra = ""
|
|
|
|
else:
|
|
|
|
versionextra = "-" + buildid
|
2011-05-08 19:34:03 +00:00
|
|
|
if tag != "":
|
2009-10-04 16:45:59 +00:00
|
|
|
sourcefolder = workfolder + "/" + tag + "/"
|
2011-05-05 17:19:00 +00:00
|
|
|
archivename = tag + versionextra + "-src.tar.bz2"
|
2009-10-04 16:45:59 +00:00
|
|
|
# get numeric version part from tag
|
|
|
|
ver = "v" + re.sub('^[^\d]+', '', tag)
|
|
|
|
else:
|
2011-05-08 19:34:03 +00:00
|
|
|
sourcefolder = workfolder + "/" + program + "-r" + str(revision) + versionextra + "/"
|
|
|
|
archivename = program + "-r" + str(revision) + versionextra + "-src.tar.bz2"
|
|
|
|
ver = "r" + str(revision)
|
2009-10-04 16:45:59 +00:00
|
|
|
os.mkdir(sourcefolder)
|
|
|
|
else:
|
|
|
|
workfolder = "."
|
|
|
|
sourcefolder = "."
|
|
|
|
archivename = ""
|
|
|
|
# check if project file explicitly given. If yes, don't get sources from svn
|
|
|
|
if proj == "":
|
|
|
|
proj = sourcefolder + project
|
|
|
|
# get sources and pack source tarball
|
|
|
|
if not getsources(svnbase, svnpaths, sourcefolder) == 0:
|
2010-03-31 20:52:07 +00:00
|
|
|
tempclean(workfolder, cleanup and not keeptemp)
|
2009-10-04 16:45:59 +00:00
|
|
|
sys.exit(1)
|
|
|
|
|
2011-05-05 17:19:00 +00:00
|
|
|
# replace version strings.
|
|
|
|
print "Updating version information in sources"
|
|
|
|
for f in regreplace:
|
|
|
|
infile = open(sourcefolder + "/" + f, "r")
|
|
|
|
incontents = infile.readlines()
|
|
|
|
infile.close()
|
|
|
|
|
|
|
|
outfile = open(sourcefolder + "/" + f, "w")
|
|
|
|
for line in incontents:
|
|
|
|
newline = line
|
|
|
|
for r in regreplace[f]:
|
2011-04-06 20:17:29 +00:00
|
|
|
# replacements made on the replacement string:
|
|
|
|
# %REVISION% is replaced with the revision number
|
2011-05-08 19:34:03 +00:00
|
|
|
replacement = re.sub("%REVISION%", str(revision), r[1])
|
2011-05-05 17:19:00 +00:00
|
|
|
# %BUILD% is replace with buildid as passed on the command line
|
|
|
|
if buildid != None:
|
|
|
|
replacement = re.sub("%BUILDID%", str(buildid), replacement)
|
2011-05-08 19:34:03 +00:00
|
|
|
newline = re.sub(r[0], replacement, newline)
|
2011-05-05 17:19:00 +00:00
|
|
|
outfile.write(newline)
|
|
|
|
outfile.close()
|
2011-04-06 20:17:29 +00:00
|
|
|
|
2009-10-05 18:35:28 +00:00
|
|
|
if source == True:
|
2011-05-05 17:19:00 +00:00
|
|
|
print "Creating source tarball %s\n" % archivename
|
2009-10-05 18:35:28 +00:00
|
|
|
tf = tarfile.open(archivename, mode='w:bz2')
|
|
|
|
tf.add(sourcefolder, os.path.basename(re.subn('/$', '', sourcefolder)[0]))
|
|
|
|
tf.close()
|
|
|
|
if binary == False:
|
|
|
|
shutil.rmtree(workfolder)
|
|
|
|
sys.exit(0)
|
2009-10-04 16:45:59 +00:00
|
|
|
else:
|
|
|
|
# figure version from sources. Need to take path to project file into account.
|
|
|
|
versionfile = re.subn('[\w\.]+$', "version.h", proj)[0]
|
|
|
|
ver = findversion(versionfile)
|
2011-05-05 17:19:00 +00:00
|
|
|
# append buildid if any.
|
|
|
|
if buildid != None:
|
|
|
|
ver += "-" + buildid
|
2009-10-04 16:45:59 +00:00
|
|
|
|
2009-10-03 20:42:02 +00:00
|
|
|
# check project file
|
|
|
|
if not os.path.exists(proj):
|
2009-10-04 16:45:59 +00:00
|
|
|
print "ERROR: path to project file wrong."
|
2009-10-03 20:42:02 +00:00
|
|
|
sys.exit(1)
|
2009-06-18 22:17:17 +00:00
|
|
|
|
2009-10-04 21:17:59 +00:00
|
|
|
# copy specified (--add) files to working folder
|
|
|
|
for f in addfiles:
|
|
|
|
shutil.copy(f, sourcefolder)
|
2009-10-04 16:45:59 +00:00
|
|
|
buildstart = time.time()
|
2009-06-18 22:17:17 +00:00
|
|
|
header = "Building %s %s" % (program, ver)
|
|
|
|
print header
|
|
|
|
print len(header) * "="
|
|
|
|
|
|
|
|
# build it.
|
2011-03-06 00:04:26 +00:00
|
|
|
if not qmake(qm, proj, platform, sourcefolder, static, cross) == 0:
|
2010-03-31 20:52:07 +00:00
|
|
|
tempclean(workfolder, cleanup and not keeptemp)
|
2009-10-04 16:45:59 +00:00
|
|
|
sys.exit(1)
|
2011-03-06 00:04:26 +00:00
|
|
|
if not build(sourcefolder, platform, cross) == 0:
|
2010-03-31 20:52:07 +00:00
|
|
|
tempclean(workfolder, cleanup and not keeptemp)
|
2009-10-03 17:19:07 +00:00
|
|
|
sys.exit(1)
|
2010-08-08 20:56:58 +00:00
|
|
|
buildtime = time.time() - buildstart
|
2011-03-06 17:37:27 +00:00
|
|
|
progfiles = programfiles
|
|
|
|
progfiles.append(progexe[platform])
|
2011-03-06 00:04:26 +00:00
|
|
|
if platform == "win32":
|
2010-06-11 20:02:59 +00:00
|
|
|
if useupx == True:
|
2011-03-06 00:04:26 +00:00
|
|
|
if not upxfile(sourcefolder, platform) == 0:
|
2010-06-11 20:02:59 +00:00
|
|
|
tempclean(workfolder, cleanup and not keeptemp)
|
|
|
|
sys.exit(1)
|
2011-03-06 00:04:26 +00:00
|
|
|
dllfiles = finddlls(sourcefolder + "/" + progexe[platform], \
|
|
|
|
[os.path.dirname(qm)], cross)
|
2010-08-30 17:51:53 +00:00
|
|
|
if dllfiles.count > 0:
|
2011-03-06 17:37:27 +00:00
|
|
|
progfiles.extend(dllfiles)
|
|
|
|
archive = zipball(progfiles, ver, sourcefolder, platform)
|
2010-08-30 17:51:53 +00:00
|
|
|
# only when running native right now.
|
|
|
|
if nsisscript != "" and makensis != "":
|
2011-03-06 00:04:26 +00:00
|
|
|
nsisfileinject(sourcefolder + "/" + nsisscript, sourcefolder \
|
|
|
|
+ "/" + nsisscript + ".tmp", dllfiles)
|
2010-08-30 17:51:53 +00:00
|
|
|
runnsis(ver, makensis, nsisscript + ".tmp", sourcefolder)
|
2011-03-06 00:04:26 +00:00
|
|
|
elif platform == "darwin":
|
|
|
|
archive = macdeploy(ver, sourcefolder, platform)
|
2009-06-18 22:17:17 +00:00
|
|
|
else:
|
2010-06-23 20:15:14 +00:00
|
|
|
if os.uname()[4].endswith("64"):
|
|
|
|
ver += "-64bit"
|
2011-03-06 17:37:27 +00:00
|
|
|
archive = tarball(progfiles, ver, sourcefolder)
|
2009-10-04 16:45:59 +00:00
|
|
|
|
|
|
|
# remove temporary files
|
2010-03-31 20:52:07 +00:00
|
|
|
tempclean(workfolder, cleanup)
|
2009-10-04 16:45:59 +00:00
|
|
|
|
|
|
|
# display summary
|
|
|
|
headline = "Build Summary for %s" % program
|
|
|
|
print "\n", headline, "\n", "=" * len(headline)
|
|
|
|
if not archivename == "":
|
|
|
|
filestats(archivename)
|
|
|
|
filestats(archive)
|
2009-09-20 14:59:29 +00:00
|
|
|
duration = time.time() - startup
|
|
|
|
durmins = (int)(duration / 60)
|
2009-10-03 17:19:07 +00:00
|
|
|
dursecs = (int)(duration % 60)
|
2010-08-08 20:56:58 +00:00
|
|
|
buildmins = (int)(buildtime / 60)
|
|
|
|
buildsecs = (int)(buildtime % 60)
|
2009-10-04 16:45:59 +00:00
|
|
|
print "Overall time %smin %ssec, building took %smin %ssec." % \
|
|
|
|
(durmins, dursecs, buildmins, buildsecs)
|
2009-06-18 22:17:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2011-03-06 00:04:26 +00:00
|
|
|
print "You cannot run this module directly!"
|
|
|
|
print "Set required environment and call deploy()."
|