|
"""Generate binary installer for Mercurial or TortoiseHg
Usage: setup.py [OPTIONS]
Options:
-h --help Print this message and exit
--pull Pull from upstream, implied by stable and dev targets
--nopull Disable pull for all targets
--config Show build configuration and exit
-f --force-hg Force the build/hg directory to be recloned
-F --force-thg Force the build/thg directory to be recloned
-c --clean Clean all build remnants
--thg-release Build a TortoiseHg release package
--thg-stable Build a TortoiseHg nightly stable package
--thg-dev Build a TortoiseHg nightly dev package
--thg-fogcreek Build a TortoiseHg nightly Fog Creek package
--thg-fcrelease Build a TortoiseHg for Kiln release package
--thg-doc Only build TortoiseHg documentation in tortoisehg/
--hg-release Build a Mercurial release package
--hg-stable Build a Mercurial nightly stable package
--hg-dev Build a Mercurial nightly dev package
--all Build all four nightly targets
--cert <file> Sign output using the specified cert file (pfx)
--only-msi Only build new msi packages (implies nopull)
--update Update parent repos to the built revisions
"""
#### Package Respins ####
# TortoiseHg 0.9.2-1 used mercurial.iss from changeset 275690997c5f
# TortoiseHg 1.1.1 used Mercurial revision 6f44bd4cc4f2, tag -l 1.6.1023
import os
import sys
import datetime
import subprocess
import fileinput
import getopt
import re
import shutil
import uuid
import urllib2
import getpass
import hashlib
from distutils.spawn import find_executable
import distutils.sysconfig
def set_syspath():
# make sure we can use mercurial from python source
hgrepodir = os.path.abspath('../hg')
for p in (hgrepodir, hgrepodir + "/mercurial/pure"):
if p not in sys.path:
sys.path.append(p)
set_syspath()
from mercurial import ui, hg, util
def get_environ():
env = os.environ
pp = []
if 'PYTHONPATH' in env:
pp = env['PYTHONPATH'].split(';')
hgrepodir = os.path.abspath('../hg')
for p in (hgrepodir, hgrepodir + "/mercurial/pure"):
if p not in pp:
pp.append(p)
pp = list(set(pp))
if '' in pp:
pp.remove('')
env['PYTHONPATH'] = ';'.join(pp)
return env
installenv = get_environ()
win7sdk = None
vs2010 = None
sdkenvs = {}
# default to TortoiseHg nightly stable build config
hgbranch = 'stable'
hgtag = 'tip'
thgbranch = 'stable'
thgtag = 'tip'
forcehg = False
forcethg = False
buildhg = False
builddoc = False
buildthg = False
dopull = None
showconfig = False
cert = None
all = False
onlymsi = False
doupdate = False
sslcertfile = 'misc/cacert.pem'
usefcshell = False
URL = {
'hg' : 'http://selenic.com/repo/hg/',
'thg' : 'https://developers.kilnhg.com/Repo/Kiln/TortoiseHg/TortoiseHg/',
'shellext' : 'https://bitbucket.org/tortoisehg/shellext/',
'cacert.pem': 'http://curl.haxx.se/ca/cacert.pem',
'perfarce' : 'http://www.kingswood-consulting.co.uk/hg/perfarce/',
'hgfold' : 'https://bitbucket.org/bradobro/hgfold/',
'zipdoc' : 'https://bitbucket.org/gobell/hg-zipdoc/',
'keyring' : 'https://bitbucket.org/kang/python-keyring-lib/',
'hgkeyring' : 'https://bitbucket.org/Mekk/mercurial_keyring/',
'dulwich' : 'https://bitbucket.org/abderrahim/dulwich/',
'iniparse' : 'https://bitbucket.org/sborho/iniparse/',
'hgcr-gui' : 'https://bitbucket.org/glimchb/hgcr-gui/',
}
extensions = [
'hgfold',
'perfarce',
'keyring',
'hgkeyring',
'dulwich',
'iniparse',
'zipdoc',
'hgcr-gui',
]
thg_source_repos = ['thg', 'hg'] + extensions
extfiles = {
'hgfold': ['hgfold/fold.py'],
'zipdoc': ['zipdoc/zipdoc.py'],
'perfarce': ['perfarce/perfarce.py'],
'hgkeyring': ['hgkeyring/mercurial_keyring.py'],
'hgcr-gui': ['hgcr-gui/hgcr-gui-qt.py'],
}
# Extensions which require PYTHONPATH insertion
path_extensions = ('dulwich', 'keyring', 'iniparse')
# Specify the exact revision to ship for given extension
extversions = {
'iniparse': 'bd83edee7300ce0a4fdddc3eddf743dc6ea98602', # 0.4
'dulwich' : 'ed3596b25fd1039b880c2f46cb38202a6289be95', # 0.8.0
}
# Extensions which require compiled C++ Python extensions
compiled_extensions = ('dulwich', 'keyring')
locales = ('cs', 'da', 'de', 'es', 'fr', 'it', 'ja', 'pt', 'pt_BR',
'ru', 'uk', 'zh_CN')
import platform
if platform.architecture()[0] == '64bit':
arch = 'x64'
else:
arch = 'x86'
pwd = None
if '--cert' in sys.argv:
# Seed the password at startup
pwd = getpass.getpass('password for signing: ')
def sign(file, desc, cwd):
global pwd
while True:
try:
if not pwd:
pwd = getpass.getpass('password for signing: ')
miscabspath = os.path.abspath('misc')
run(r'%s\sign.cmd %s %s %s "%s"' % (miscabspath, cert, pwd, file, desc),
cwd, hide=True)
return
except StandardError:
pwd = None
def run(cmd, cwd='.', hide=False, env=installenv):
if not hide:
print cwd + "> " + cmd
try:
subprocess.check_call(cmd, shell=True, cwd=cwd, env=env)
except subprocess.CalledProcessError:
if hide:
raise StandardError("subprocess.CalledProcessError was raised")
else:
raise
def run_python(cmd, cwd='.', hide=False, env=installenv):
cmd = ' '.join([sys.executable, cmd])
run(cmd, cwd, hide, env)
sdkenv_vars = ('include', 'lib', 'mssdk', 'path', 'regkeypath', 'sdksetupdir',
'sdktools', 'targetos', 'vcinstalldir', 'vcroot', 'vsregkeypath')
def get_pruned_env(arch, usefcshell=False):
# Remove folders from %PATH% that contain QtCore4.dll, unless it is the
# PyQt4\bin folder for the executing Python environment
prefix = sys.exec_prefix.lower() + os.sep
deletions = []
fenv = get_sdkenv(arch, usefcshell).copy()
path = fenv.get('PATH', '').split(os.pathsep)
for dir in path:
if dir.lower().startswith(prefix):
continue
if os.path.exists(os.path.join(dir, 'QtCore4.dll')):
deletions.append(dir)
for dir in deletions:
print 'removing', dir, 'from PATH'
path.remove(dir)
fenv['PATH'] = os.pathsep.join(path)
return fenv
def get_sdkenv(arch, usefcshell=False):
if arch in sdkenvs:
return sdkenvs[arch]
if usefcshell:
if arch == 'x64':
vcvars = vs2010 + '/bin/amd64/vcvars64.bat'
else:
vcvars = vs2010 + '/bin/vcvars32.bat'
p = subprocess.Popen(r'cmd /e:on /v:on /c call "%s" && set' % vcvars,
shell=False,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
else:
p = subprocess.Popen(r'cmd /e:on /v:on /c call "%s\Bin\SetEnv.cmd" /xp /%s /release && set' %
(win7sdk, arch),
shell=False,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
out, err = p.communicate()
newenv = {}
for line in out.splitlines():
if '=' in line:
k, v = line.split('=', 1)
if k.lower() in sdkenv_vars:
newenv[k.upper()] = v
env = installenv.copy()
env.update(newenv)
sdkenvs[arch] = env
return env
def lasttag(reponame, branch):
"return latest tag that lives on specified branch"
cmd = ('hg', '--repository', '../%s' % reponame, 'log',
'--rev', 'tagged() and branch(%s)' % branch,
'--template={tags}$')
p = subprocess.Popen(cmd,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
shell=False)
stdout_text, stderr_text = p.communicate('')
# use -2 to ignore trailing blank output
return stdout_text.split('$')[-2]
def repoversion(verfile):
globals = {}
execfile(verfile, globals)
return globals.get('version', 'unknown')
def windowsversion(name, version):
extra = None
if '+' in version:
version, extra = version.split('+', 1)
v = [int(x) for x in version.split('.')]
while len(v) < 3:
v.append(0)
major, minor, periodic = v[:3]
if extra != None:
tagdistance = int(extra.split('-', 1)[0])
periodic *= 1000
if 'unstable' in name:
periodic += tagdistance + 500
else:
periodic += tagdistance + 100
return [str(x) for x in (major, minor, periodic)]
def pipetofile(cmdlist, outfile, cwd):
print '> ', ' '.join(cmdlist), '>', outfile
p = subprocess.Popen( cmdlist,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
shell=False,
cwd=cwd)
out, err = p.communicate('')
fp = open(outfile, 'wb')
fp.write(out)
fp.close
def candle(file, sourcedir=None, cwd='.', defines=None):
args = []
if sourcedir:
args.append('-dSourceDir="%s"' % sourcedir)
if defines:
args += ['-d%s="%s"' % item for item in defines]
run(r'candle -nologo "%s" %s' % (file, ' '.join(args)), cwd)
def light(output, cwd, *files):
run(r'light -nologo -ext WixUIExtension -sw1076 -spdb -o %s %s' %
(output, ' '.join(f + '.wixobj' for f in files)), cwd)
def generate_hgext_index(branch):
"""Generate list of extensions under hgext/"""
run(r'del build\hg\hgext\__index__.*')
run_python(r'setup.py build_hgextindex', 'build/hg')
def build_hg(force, branch, tag, arch, usefcshell=False):
if onlymsi:
return
if force or not os.path.exists('build/hg'):
run(r'if not exist build mkdir build')
run(r'if exist build\hg rmdir /s /q build\hg')
run(r'hg clone file:../hg -u %s file:build/hg' % branch)
else:
run(r'hg -R build/hg pull')
run(r'hg -R build/hg update ' + branch)
if tag == 'tip':
run(r'hg -R build/hg update')
else:
run(r'hg -R build/hg update ' + tag)
# Clear files added by previous installer runs
run(r'hg -R build/hg --config extensions.purge= purge --all')
run('copy misc\\setup.cfg build\\hg\\')
run_python(r'setup.py --version', 'build/hg')
run_python(r'setup.py build_py -c -d . build_mo', 'build/hg')
run_python(r'setup.py build_ext -i', 'build/hg', env=get_sdkenv(arch, usefcshell))
generate_hgext_index(branch)
# Build man pages
pipetofile((sys.executable, 'gendoc.py'),
'build/hg/doc/hg.1.gendoc.txt',
'build/hg/doc')
cmd = 'runrst html'
cmdtemplate = r'%s --link-stylesheet --stylesheet-path style.css %s %s'
manfiles = ('hg.1.txt', 'hgignore.5.txt', 'hgrc.5.txt')
for man in manfiles:
outfile = man[:-3] + 'html'
run_python(cmdtemplate % (cmd, man, outfile), 'build/hg/doc')
def build_hg_installer(name, arch):
version = repoversion('build/hg/mercurial/__version__.py')
comments = 'Installs Mercurial version %s' % version
version = '.'.join(windowsversion(name, version))
if not onlymsi:
run_python(r'setup.py py2exe -b3', 'build/hg', env=get_sdkenv(arch))
if cert is not None:
print "signing using cert '%s'" % (cert,)
desc = '%s %s' % (name, version)
sign(r'dist\hg.exe', desc, 'build/hg')
package = r'..\..\output\%s-%s-%s.msi' % (name, version, arch)
wixobj = [
(r'..\hg\contrib\wix\help.wxs', r'..\hg\mercurial\help'),
(r'..\hg\contrib\wix\templates.wxs', r'..\hg\mercurial\templates'),
(r'..\hg\contrib\wix\locale.wxs', r'..\hg\mercurial\locale'),
(r'..\hg\contrib\wix\i18n.wxs', r'..\hg\i18n'),
(r'..\hg\contrib\wix\doc.wxs', r'..\hg\doc'),
(r'..\hg\contrib\wix\dist.wxs', r'..\hg\dist'),
(r'..\hg\contrib\wix\contrib.wxs', r'..\hg\contrib')]
for file, sourcedir in wixobj:
candle(file, sourcedir=sourcedir, cwd='build/hg', defines=[('Platform', arch)])
candle(r'..\hg\contrib\wix\mercurial.wxs', cwd='build/hg', defines=[
('Platform', arch),
('Version', version),
('Comments', comments),
('VCRedistSrcDir', win7sdk + r'\Redist\VC')])
light(package, 'build', 'hg/help', 'hg/templates', 'hg/locale', 'hg/i18n', 'hg/doc',
'hg/contrib', 'hg/dist', 'hg/mercurial')
if cert is not None:
print "signing using cert '%s'" % (cert,)
desc = '%s %s' % (name, version)
sign(package, desc, 'build')
def build_thg(force, branch, tag, name, productid, arch, usefcshell=False):
if onlymsi:
return
if force or not os.path.exists('build/thg'):
run(r'if not exist build mkdir build')
run(r'if exist build\thg rmdir /s /q build\thg')
run(r'hg clone file:../thg -u %s file:build/thg' % branch)
else:
run(r'hg pull ../../../thg', 'build/thg')
run(r'hg update ' + branch, 'build/thg')
if tag == 'tip':
run(r'hg update', 'build/thg')
else:
run(r'hg update ' + tag, 'build/thg')
# Clear files added by previous installer runs
run(r'hg -R build/thg --config extensions.purge= purge --all')
run_python(r'setup.py --version', 'build/thg')
# Build locales
run_python(r'setup.py build_mo', 'build/thg')
# Build cmenu translation registry files
run_python(r'reggen.py', 'build/thg/win32')
# Use build helpers from win32
run(r'copy win32\config.py tortoisehg\util', 'build/thg')
run(r'copy win32\setup.cfg .', 'build/thg')
print "# Copy bundled Mercurial extensions into build/hg/hgext"
for ext in extensions:
for loc in extfiles.get(ext, []):
loc = '../' + loc
if os.path.exists(loc):
print "copying extension %s" % loc
shutil.copy(loc, 'build/hg/hgext')
else:
print "extension %s doesn't exist, skipping" % loc
if ext == 'hgcr-gui':
shutil.copy('../hgcr-gui/hgcr.ui', 'build/thg/tortoisehg/hgqt')
generate_hgext_index(branch)
# Build docs
run(r'build chm', 'build/thg/doc')
run(r'build pdf', 'build/thg/doc')
print "# compiling all Mercurial extensions that have C++ Python extensions"
for ext in extensions:
if ext in compiled_extensions:
ext = '../' + ext
print "compiling extension %s" % ext
run(r'hg --config extensions.purge= purge --all', ext)
run_python(r'setup.py build_ext -i', ext, env=get_sdkenv(arch, usefcshell))
def build_shellext(force, branch, tag, name, productid, arch, usefcshell=False):
if onlymsi:
return
if usefcshell:
shellrepo = '../fcshell'
shelldir = 'build/fcshell'
shellbranch = 'default'
else:
shellrepo = '../shellext'
shelldir = 'build/shellext'
shellbranch = branch
if force or not os.path.exists(shelldir):
run(r'if exist %s rmdir /s /q %s' % (shelldir, shelldir))
run(r'hg clone file:%s -u %s file:%s' % (shellrepo, shellbranch, shelldir))
else:
run(r'hg pull ../../' + shellrepo, shelldir)
run(r'hg update ' + shellbranch, shelldir)
if tag == 'tip':
run(r'hg update', shelldir)
else:
run(r'hg update ' + tag, shelldir)
# Clear files added by previous installer runs
run(r'hg -R %s --config extensions.purge= purge --all' % shelldir)
# Build x64 and x86 shell extensions
hgversion = repoversion('build/hg/mercurial/__version__.py')
hgperiodic = windowsversion(name, hgversion)[2]
thgversion = repoversion('build/thg/tortoisehg/util/__version__.py')
v = windowsversion(name, thgversion)
if '-stable' in name or '-dev' in name:
v.append(hgperiodic)
thgversion = '.'.join(v)
a, b, c, d = v
else:
thgversion = '.'.join(v)
a, b, c = v
def compile_shell_ext(arch):
print '*************** %s ******************' % arch
env = get_sdkenv(arch).copy()
env['DEBUG'] = '1'
env['THG_PLATFORM'] = arch
env['THG_EXTRA_CPPFLAGS'] = '/DTHG_PRODUCT_ID=%s' % productid
env['THG_EXTRA_RCFLAGS'] = (
'/dTHG_VERSION_FIRST=%s /dTHG_VERSION_SECOND=%s /dTHG_VERSION_THIRD=%s /dTHG_PRODUCT_ID="%s"' %
(a, b, c, productid))
builddir = r'build\shellext\src'
run('nmake.exe /nologo /f Makefile.nmake clean', builddir, env=env)
run('nmake.exe /nologo /f Makefile.nmake', builddir, env=env)
if cert is not None:
print "signing using cert '%s'" % (cert,)
package = r'src\ThgShell%s.dll' % arch
desc = "%s %s %s shell extension" % (name, arch, thgversion)
sign(package, desc, 'build/shellext')
def compile_fogcreek_shell_ext(arch):
print '*************** %s ******************' % arch
env = get_sdkenv(arch, True).copy()
env['THG_EXTRA_CPPFLAGS'] = '/DTHG_PRODUCT_ID=%s' % productid
env['THG_EXTRA_RCFLAGS'] = (
'/dTHG_VERSION_FIRST=%s /dTHG_VERSION_SECOND=%s /dTHG_VERSION_THIRD=%s /dTHG_PRODUCT_ID="%s"' %
(a, b, c, productid))
builddir = r'build/fcshell/src'
run('msbuild.exe /p:Platform=%s /p:Configuration=Release FCShell.sln' % arch, builddir, env=env)
if usefcshell:
compile_fogcreek_shell_ext('Win32')
if arch != 'x86':
compile_fogcreek_shell_ext('x64')
else:
if arch == 'x86':
compile_shell_ext(arch)
else:
compile_shell_ext('x86')
compile_shell_ext('x64')
def build_thg_docs():
run(r'build clean', r'thg\doc')
run(r'build chm', r'thg\doc')
run(r'build pdf', r'thg\doc')
def build_thg_installer(name, productid, arch, branch, usefcshell=False):
if not onlymsi:
env = get_pruned_env(arch, usefcshell)
env['MERCURIAL_PATH'] = '../hg/mercurial'
env['HGEXT_PATH'] = '../hg/hgext'
run(r'if exist dist rmdir /s /q dist', 'build/thg')
run_python(r'setup.py py2exe -b3', 'build/thg', env=env)
path = os.path.join(sys.exec_prefix, 'lib', 'site-packages', 'PyQt4')
binpath = os.path.join(path, 'bin')
if os.path.exists(binpath):
path = binpath
for f in ('qscintilla2.dll', 'QtSvg4.dll', 'QtXml4.dll'):
p = os.path.join(path, f)
run(r'copy %s dist' % p, r'build/thg')
hgversion = repoversion('build/hg/mercurial/__version__.py')
hgperiodic = windowsversion(name, hgversion)[2]
longthgversion = repoversion('build/thg/tortoisehg/util/__version__.py')
v = windowsversion(name, longthgversion)
if '-stable' in name or '-dev' in name:
v.append(hgperiodic)
thgversion = '.'.join(v)
if not onlymsi and cert is not None:
print "signing using cert '%s'" % (cert,)
desc = 'TortoiseHg %s' % thgversion
for exe in ('hg', 'thg', 'thgw', 'TortoiseHgOverlayServer'):
package = r'dist\%s.exe' % exe
if os.path.exists('build/thg/' + package):
sign(package, desc, 'build/thg')
if usefcshell:
shelldir = 'fcshell'
else:
shelldir = 'shellext'
serepo = hg.repository(ui.ui(), path='build/' + shelldir)
shellextversion = str(serepo['.'])
write_extension_versions()
wixobj = [
(r'..\..\misc\diff-scripts.wxs', r'..\contrib\diff-scripts'),
(r'win32\wix\dist.wxs', r'dist'),
(r'win32\wix\icons.wxs', r'dist/icons'),
(r'win32\wix\thg-locale.wxs', r'locale'),
(r'win32\wix\thg-i18n.wxs', r'i18n'),
(r'..\%s\wix\cmenu-i18n.wxs' % shelldir, r'win32'),
(r'..\%s\wix\thgshell.wxs' % shelldir, '..\%s' % shelldir),
(r'win32\wix\help.wxs', r'..\hg\mercurial\help'),
(r'win32\wix\templates.wxs', r'..\hg\mercurial\templates'),
(r'win32\wix\locale.wxs', r'..\hg\mercurial\locale'),
(r'win32\wix\i18n.wxs', r'..\hg\i18n'),
(r'win32\wix\doc.wxs', r'..\hg\doc'),
(r'win32\wix\contrib.wxs', r'..\hg\contrib')]
defs = [('Platform', arch), ('ShellextVersion', shellextversion)]
for file, sourcedir in wixobj:
candle(file, sourcedir=sourcedir, cwd='build/thg', defines=defs)
package = r"..\..\output\%s-%s" % (name, thgversion)
commentsfmt = 'Installs TortoiseHg %s, Mercurial %s on %s'
comments = commentsfmt % (longthgversion, hgversion, arch)
productid = productid.lower()
buildabspath = os.path.abspath('build')
defines = [('Version', thgversion),
('ProductId', productid),
('Platform', arch),
('Comments', comments),
('VCRedistSrcDir', win7sdk + r'\Redist\VC'),
('ShellextRepoFolder', os.path.join(buildabspath, shelldir))]
if usefcshell:
defines += [('ProductName', 'TortoiseHg for Kiln')]
candle(r'win32\wix\tortoisehg.wxs', cwd='build/thg', defines=defines)
m = hashlib.sha1()
m.update(comments)
m.update(productid)
msifile = '%s-%s-%s.msi' % (package, arch, m.hexdigest()[:12])
light(msifile, 'build', 'thg/help', 'thg/templates', 'thg/locale',
'thg/i18n', 'thg/doc', 'thg/contrib', 'thg/diff-scripts',
'thg/icons', 'thg/thg-locale', 'thg/dist', 'thg/thg-i18n',
'thg/cmenu-i18n', 'thg/thgshell', 'thg/tortoisehg')
if cert is not None:
print "signing using cert '%s'" % (cert,)
desc = '%s %s %s' % (name, arch, thgversion)
sign(msifile, desc, 'build')
def write_repo_version(f, base, mod):
repo = hg.repository(ui.ui(), path=base + '/' + mod)
ctx = repo['.']
date = util.shortdate(ctx.date())
f.write('%12s:\t%s\t%s\t%s\n' % (mod, str(ctx), date, URL[mod]))
def write_extension_versions():
out = 'extension-versions.txt'
f = open(out, 'w')
f.write('Extensions/modules included in this TortoiseHg package:\n\n')
for mod in extensions:
write_repo_version(f, '..', mod)
try:
from svn import core
ver = '%d.%d.%d' % (core.SVN_VER_MAJOR, core.SVN_VER_MINOR, core.SVN_VER_MICRO)
url = 'http://bitbucket.org/tortoisehg/thg/downloads'
f.write('%12s:\t%-12s\t%10s\t%s\n' % ('python-svn', ver, '', url))
except ImportError:
pass
try:
import pygments
ver = pygments.__version__
url = 'http://pygments.org/download/'
f.write('%12s:\t%-12s\t%10s\t%s\n' % ('pygments', ver, '', url))
except ImportError:
pass
pywin32file = sys.prefix + r'\lib\site-packages\pywin32.version.txt'
if os.path.exists(pywin32file):
ver = open(pywin32file, 'r').read().strip()
url = 'http://sourceforge.net/projects/pywin32/'
f.write('%12s:\t%-12s\t%10s\t%s\n' % ('pywin32', ver, '', url))
f.close()
def update():
'''update the master repos to the revisions in the build repos'''
for r in ('hg', 'thg', 'shellext'):
repo = hg.repository(ui.ui(), path='build/' + r)
rev = str(repo['.'])
run(r'hg update -R ../%s %s' % (r, rev))
def try_paths(paths):
for env in ('ProgramFiles', 'ProgramFiles(x86)', 'ProgramW6432'):
if env not in installenv: continue
prefix = installenv[env]
for file in paths:
candidate = prefix + file
if os.path.exists(candidate):
return candidate
else:
return None
def verify_hg_env(usefcshell=False):
global installenv
global win7sdk
global vs2010
if usefcshell:
vs2010 = try_paths([r'\Microsoft Visual Studio 10.0\VC\bin'])
if not vs2010:
print 'Unable to find Microsoft Visual Studio 2010, please install'
sys.exit(1)
vs2010 = vs2010[:-3]
win7sdk = try_paths([r'\Microsoft SDKs\Windows\v7.0\Bin'])
if not win7sdk:
print 'Unable to find Microsoft Windows SDK 7.0, please install'
sys.exit(1)
win7sdk = win7sdk[:-4]
try:
import py2exe
except ImportError:
print 'Unable to find py2exe'
print 'http://sourceforge.net/projects/py2exe/'
sys.exit(1)
try:
import win32api
except ImportError:
print 'Unable to find pywin32'
print 'http://sourceforge.net/projects/pywin32/'
sys.exit(1)
path = installenv.get('PATH', '').split(os.pathsep)
scrpath = sys.exec_prefix + os.sep + 'Scripts'
path.append(scrpath)
if not os.path.exists(os.path.join(scrpath, 'rst2html.py')):
print 'Unable to find rst2html'
print 'easy_install docutils'
sys.exit(1)
msgfmt = find_executable('msgfmt')
if not msgfmt:
found = try_paths([r'\GnuWin32\bin\msgfmt.exe'])
if found:
path.append(os.path.dirname(found))
else:
if os.path.exists(r'\MinGW\bin\msgfmt.exe'):
path.append(r'\MinGW\bin')
else:
print 'Unable to find msgfmt. Please download from'
print 'http://gnuwin32.sourceforge.net/packages/gettext.htm'
sys.exit(1)
if 'WIX' in installenv:
path.append(installenv['WIX'] + 'bin')
else:
print 'Unable to find WIX. Please download from'
print 'http://sourceforge.net/projects/wix/files/'
sys.exit(1)
installenv['HGPLAIN'] = '1'
installenv['PATH'] = os.pathsep.join(path)
installenv['DISTUTILS_USE_SDK'] = '1'
installenv['hhc_compiler'] = 'hhc.exe'
def verify_doc_env():
global installenv
path = installenv.get('PATH', '').split(os.pathsep)
scrpath = os.path.dirname(sys.executable) + os.sep + 'Scripts'
path.append(scrpath)
# Find HTML Help compiler, add to path
hhc = find_executable('hhc')
if not hhc:
found = try_paths([r'\HTML Help Workshop\hhc.exe'])
if found:
path.append(os.path.dirname(found))
else:
print 'Unable to find HTML Help Workshop'
print 'http://go.microsoft.com/fwlink/?LinkId=14188'
sys.exit(1)
# Find MiKTex, add to path
pdflatex = find_executable('pdflatex')
if not pdflatex:
found = try_paths([r'\MiKTeX 2.7\miktex\bin\Pdflatex.exe',
r'\MiKTeX 2.8\miktex\bin\Pdflatex.exe'])
if found:
path.append(os.path.dirname(found))
else:
print 'Unable to find MiKTeX'
print 'http://miktex.org/2.8/setup'
sys.exit(1)
# Verify sphinx
if not os.path.exists(os.path.join(scrpath, 'sphinx-build.exe')):
print 'Unable to find sphinx'
print 'easy_install sphinx'
sys.exit(1)
installenv['PATH'] = os.pathsep.join(path)
def verify_thg_env():
global installenv
site_packages_path = distutils.sysconfig.get_python_lib()
included_packages = ('mercurial', 'iniparse', 'dulwich', 'keyring')
# make sure that packages globally installed with e.g. easy_install
# don't override packages we want to bundle and build ourselves
err = set()
for m in included_packages:
try:
mod = __import__(m)
except ImportError:
continue
fm = mod.__file__
if fm.lower().startswith(site_packages_path.lower()):
print "Error: '%s' overrides included package '%s'" % (
os.path.dirname(fm), m)
err.add(m)
if err:
print "(uninstall or hide these installed packages: %s)" % ', '.join(err)
sys.exit(1)
try:
import comtypes
except ImportError:
print 'comtypes not found'
print 'download and install comtypes-0.6.2.win32.exe from'
print 'http://sourceforge.net/projects/comtypes/files/'
sys.exit(1)
try:
from svn import core
except ImportError:
print 'svn bindings not found'
print 'See README for download location and install instructions'
sys.exit(1)
oldpath = os.environ.get('PYTHONPATH', '').split(os.pathsep)
path = ['../hg']
for ext in extensions:
if ext in path_extensions:
path.append('../../../' + ext)
path.extend(oldpath)
installenv['PYTHONPATH'] = os.pathsep.join(path)
def usage(code, msg=''):
print >> sys.stderr, __doc__
if msg:
print >> sys.stderr, msg
sys.exit(code)
if len(sys.argv) < 2:
usage(0)
try:
opts, args = getopt.getopt(sys.argv[1:], 'hcfF',
['clean', 'forcehg', 'forcethg',
'thg-release', 'thg-stable', 'thg-dev', 'thg-fogcreek',
'thg-fcrelease', 'thg-doc', 'hg-release', 'hg-stable', 'hg-dev',
'pull', 'nopull', 'config', 'all', 'cert=', 'only-msi', 'update'])
except getopt.error, msg:
usage(1, msg)
# parse options (first pass)
for opt, arg in opts:
if opt == '--cert':
cert = os.path.abspath(arg)
# parse options (second pass)
for opt, arg in opts:
if opt in ('-h', '--help'):
usage(0)
elif opt in ('-f', '--force-hg'):
forcehg = True
elif opt in ('-F', '--force-thg'):
forcethg = True
elif opt in ('-c', '--clean'):
run(r'if exist build rmdir /s /q build')
if os.path.exists(sslcertfile):
os.unlink(sslcertfile)
sys.exit(0)
elif opt == '--thg-doc':
builddoc = True
elif opt == '--thg-release':
if dopull is None:
dopull = True
buildthg = True
thgbranch = 'stable'
thgtag = lasttag('thg', 'stable')
hgbranch = 'stable'
hgtag = lasttag('hg', 'stable')
packagename = 'tortoisehg'
elif opt == '--thg-stable':
if dopull is None:
dopull = True
buildthg = True
thgbranch = 'stable'
thgtag = 'tip'
hgbranch = 'stable'
hgtag = 'tip'
packagename = 'tortoisehg-stable'
elif opt == '--thg-dev':
if dopull is None:
dopull = True
buildthg = True
thgbranch = 'default'
thgtag = 'tip'
hgbranch = 'default'
hgtag = 'tip'
packagename = 'tortoisehg-dev'
elif opt == '--thg-fogcreek':
if dopull is None:
dopull = False
buildthg = True
thgbranch = 'fogcreek'
thgtag = 'tip'
hgbranch = 'stable'
hgtag = 'tip'
packagename = 'tortoisehg-fogcreek'
usefcshell = True
elif opt == '--thg-fcrelease':
if dopull is None:
dopull = False
buildthg = True
thgbranch = 'fogcreek'
thgtag = lasttag('thg', 'fogcreek')
hgbranch = 'stable'
hgtag = lasttag('hg', 'stable')
packagename = 'tortoisehg-kiln'
usefcshell = True
elif opt == '--hg-release':
buildhg = True
hgbranch = 'stable'
hgtag = lasttag('hg', 'stable')
packagename = 'mercurial'
elif opt == '--hg-stable':
if dopull is None:
dopull = True
buildhg = True
hgbranch = 'stable'
hgtag = 'tip'
packagename = 'mercurial-stable'
elif opt == '--hg-dev':
if dopull is None:
dopull = True
buildhg = True
hgbranch = 'default'
hgtag = 'tip'
packagename = 'mercurial-dev'
elif opt == '--pull':
dopull = True
elif opt == '--nopull':
dopull = False
elif opt == '--config':
showconfig = True
elif opt == '--only-msi':
onlymsi = True
elif opt == '--all':
all = True
onlymsi = False
if dopull is None:
dopull = True
elif opt == '--update':
doupdate = True
print 'Build config:'
print '[tortoisehg] branch=%s, tag=%s' % (thgbranch, thgtag)
print '[mercurial] branch=%s, tag=%s\n' % (hgbranch, hgtag)
if showconfig:
sys.exit(0)
if not os.path.exists(sslcertfile) or all:
print 'fetching cacert.pem from', URL['cacert.pem']
contents = urllib2.urlopen(URL['cacert.pem']).read()
file(sslcertfile, 'wb').write(contents)
if dopull and not onlymsi:
run(r'hg -R ../hg pull')
run(r'hg -R ../thg pull')
for mod in ['shellext'] + extensions:
run(r'hg -R ../%s pull' % mod)
if buildthg or all:
for mod in extensions:
if mod in extversions:
run(r'hg update -R ../%s %s' % (mod, extversions[mod]))
else:
run(r'hg update -R ../' + mod)
if all:
verify_hg_env()
verify_doc_env()
verify_thg_env()
run(r'title Building hg-stable...')
build_hg(True, 'stable', 'tip', arch)
build_hg_installer('mercurial-stable', arch)
run(r'title Building hg-dev...')
build_hg(False, 'default', 'tip', arch)
build_hg_installer('mercurial-dev', arch)
run(r'title Building thg-stable...')
productid = str(uuid.uuid4()).upper()
build_hg(False, 'stable', 'tip', arch)
build_thg(True, 'stable', 'tip', 'tortoisehg-stable', productid, arch)
build_shellext(True, 'stable', 'tip', 'tortoisehg-stable', productid, arch)
build_thg_installer('tortoisehg-stable', productid, arch)
run(r'title Building thg-dev...')
productid = str(uuid.uuid4()).upper()
build_hg(False, 'default', 'tip', arch)
build_thg(True, 'default', 'tip', 'tortoisehg-dev', productid, arch)
build_shellext(True, 'default', 'tip', 'tortoisehg-dev', productid, arch)
build_thg_installer('tortoisehg-dev', productid, arch, thgbranch)
elif builddoc:
verify_doc_env()
build_thg_docs()
elif buildhg:
verify_hg_env()
build_hg(forcehg, hgbranch, hgtag, arch)
build_hg_installer(packagename, arch)
elif buildthg:
verify_hg_env(usefcshell)
verify_doc_env()
verify_thg_env()
build_hg(forcehg, hgbranch, hgtag, arch, usefcshell)
productid = str(uuid.uuid4()).upper()
build_thg(forcethg, thgbranch, thgtag, packagename, productid, arch, usefcshell)
build_shellext(forcethg, thgbranch, thgtag, packagename, productid, arch, usefcshell)
build_thg_installer(packagename, productid, arch, thgbranch, usefcshell)
if doupdate:
update()
|
Loading...