mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-05 14:44:24 -04:00
242 lines
6.7 KiB
Python
242 lines
6.7 KiB
Python
#!/usr/bin/env python2
|
|
# vim:fileencoding=utf-8
|
|
# License: GPLv3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
|
|
|
from __future__ import absolute_import, division, print_function, unicode_literals
|
|
|
|
import io
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import tarfile
|
|
import time
|
|
|
|
if sys.version_info.major > 2:
|
|
import winreg
|
|
else:
|
|
try:
|
|
import _winreg as winreg
|
|
except ImportError:
|
|
import winreg
|
|
is64bit = os.environ.get('PLATFORM') != 'x86'
|
|
|
|
|
|
def vcvars(): # {{{
|
|
RegOpenKeyEx = winreg.OpenKeyEx
|
|
RegEnumValue = winreg.EnumValue
|
|
RegError = winreg.error
|
|
|
|
HKEYS = (
|
|
winreg.HKEY_USERS, winreg.HKEY_CURRENT_USER, winreg.HKEY_LOCAL_MACHINE,
|
|
winreg.HKEY_CLASSES_ROOT
|
|
)
|
|
VS_BASE = r"Software\Wow6432Node\Microsoft\VisualStudio\%0.1f"
|
|
|
|
def get_reg_value(path, key):
|
|
for base in HKEYS:
|
|
d = read_values(base, path)
|
|
if d and key in d:
|
|
return d[key]
|
|
raise KeyError(key)
|
|
|
|
def convert_mbcs(s):
|
|
dec = getattr(s, "decode", None)
|
|
if dec is not None:
|
|
try:
|
|
s = dec("mbcs")
|
|
except UnicodeError:
|
|
pass
|
|
return s
|
|
|
|
def read_values(base, key):
|
|
"""Return dict of registry keys and values.
|
|
|
|
All names are converted to lowercase.
|
|
"""
|
|
try:
|
|
handle = RegOpenKeyEx(base, key)
|
|
except RegError:
|
|
return None
|
|
d = {}
|
|
i = 0
|
|
while True:
|
|
try:
|
|
name, value, type = RegEnumValue(handle, i)
|
|
except RegError:
|
|
break
|
|
name = name.lower()
|
|
d[convert_mbcs(name)] = convert_mbcs(value)
|
|
i += 1
|
|
return d
|
|
|
|
def find_vcvarsall(version=14.0):
|
|
vsbase = VS_BASE % version
|
|
try:
|
|
productdir = get_reg_value(r"%s\Setup\VC" % vsbase, "productdir")
|
|
except KeyError:
|
|
raise SystemExit(
|
|
"Unable to find Visual Studio product directory in the registry"
|
|
)
|
|
|
|
if not productdir:
|
|
raise SystemExit("No productdir found")
|
|
vcvarsall = os.path.join(productdir, "vcvarsall.bat")
|
|
if os.path.isfile(vcvarsall):
|
|
return vcvarsall
|
|
raise SystemExit("Unable to find vcvarsall.bat in productdir: " + productdir)
|
|
|
|
def remove_dups(variable):
|
|
old_list = variable.split(os.pathsep)
|
|
new_list = []
|
|
for i in old_list:
|
|
if i not in new_list:
|
|
new_list.append(i)
|
|
return os.pathsep.join(new_list)
|
|
|
|
def query_process(cmd):
|
|
if is64bit and 'PROGRAMFILES(x86)' not in os.environ:
|
|
os.environ['PROGRAMFILES(x86)'] = os.environ['PROGRAMFILES'] + ' (x86)'
|
|
result = {}
|
|
popen = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
try:
|
|
stdout, stderr = popen.communicate()
|
|
if popen.wait() != 0:
|
|
raise RuntimeError(stderr.decode("mbcs"))
|
|
|
|
stdout = stdout.decode("mbcs")
|
|
for line in stdout.splitlines():
|
|
if '=' not in line:
|
|
continue
|
|
line = line.strip()
|
|
key, value = line.split('=', 1)
|
|
key = key.lower()
|
|
if key == 'path':
|
|
if value.endswith(os.pathsep):
|
|
value = value[:-1]
|
|
value = remove_dups(value)
|
|
result[key] = value
|
|
|
|
finally:
|
|
popen.stdout.close()
|
|
popen.stderr.close()
|
|
return result
|
|
|
|
def query_vcvarsall():
|
|
plat = 'amd64' if is64bit else 'x86'
|
|
vcvarsall = find_vcvarsall()
|
|
env = query_process('"%s" %s & set' % (vcvarsall, plat))
|
|
|
|
def g(k):
|
|
try:
|
|
return env[k]
|
|
except KeyError:
|
|
return env[k.lower()]
|
|
|
|
# We have to insert the correct path to MSBuild.exe so that the one
|
|
# from the .net frameworks is not used.
|
|
paths = g('PATH').split(os.pathsep)
|
|
for i, p in enumerate(tuple(paths)):
|
|
if os.path.exists(os.path.join(p, 'MSBuild.exe')):
|
|
if '.net' in p.lower():
|
|
paths.insert(
|
|
i, r'C:\Program Files (x86)\MSBuild\14.0\bin' +
|
|
(r'\amd64' if is64bit else '')
|
|
)
|
|
env["PATH"] = os.pathsep.join(paths)
|
|
break
|
|
|
|
return {
|
|
k: g(k)
|
|
for k in
|
|
'PATH LIB INCLUDE LIBPATH WINDOWSSDKDIR VS140COMNTOOLS UCRTVERSION UNIVERSALCRTSDKDIR'.
|
|
split()
|
|
}
|
|
|
|
return query_vcvarsall()
|
|
|
|
|
|
# }}}
|
|
|
|
|
|
def printf(*args, **kw):
|
|
print(*args, **kw)
|
|
sys.stdout.flush()
|
|
|
|
|
|
def download_file(url):
|
|
for i in range(5):
|
|
try:
|
|
printf('Downloading', url)
|
|
return subprocess.check_output(['curl.exe', '-fSL', url])
|
|
except subprocess.CalledProcessError:
|
|
time.sleep(1)
|
|
raise SystemExit('Failed to download: {}'.format(url))
|
|
|
|
|
|
def sw():
|
|
sw = os.environ['SW']
|
|
os.makedirs(sw)
|
|
os.chdir(sw)
|
|
url = 'https://download.calibre-ebook.com/travis/win-{}.tar.xz'.format(
|
|
'64' if is64bit else '32')
|
|
tarball = download_file(url)
|
|
with tarfile.open(fileobj=io.BytesIO(tarball)) as tf:
|
|
tf.extractall()
|
|
printf('Download complete')
|
|
|
|
|
|
def sanitize_path():
|
|
needed_paths = []
|
|
executables = 'git.exe curl.exe rapydscript.cmd node.exe'.split()
|
|
for p in os.environ['PATH'].split(os.pathsep):
|
|
for x in tuple(executables):
|
|
if os.path.exists(os.path.join(p, x)):
|
|
needed_paths.append(p)
|
|
executables.remove(x)
|
|
sw = os.environ['SW']
|
|
paths = r'{0}\private\python\DLLs {0}\private\python\Lib\site-packages\pywin32_system32 {0}\bin {0}\qt\bin C:\Windows\System32'.format(
|
|
sw
|
|
).split() + needed_paths
|
|
os.environ['PATH'] = os.pathsep.join(paths)
|
|
print('PATH:', os.environ['PATH'])
|
|
|
|
|
|
def vcenv():
|
|
env = os.environ.copy()
|
|
env.update(vcvars())
|
|
return {str(k): str(v) for k, v in env.items()}
|
|
|
|
|
|
def build():
|
|
sanitize_path()
|
|
cmd = [sys.executable, 'setup.py', 'bootstrap', '--ephemeral']
|
|
printf(*cmd)
|
|
p = subprocess.Popen(cmd, env=vcenv())
|
|
raise SystemExit(p.wait())
|
|
|
|
|
|
def test():
|
|
sanitize_path()
|
|
cmd = [sys.executable, 'setup.py', 'test']
|
|
printf(*cmd)
|
|
p = subprocess.Popen(cmd)
|
|
raise SystemExit(p.wait())
|
|
|
|
|
|
def main():
|
|
q = sys.argv[-1]
|
|
if q == 'build':
|
|
build()
|
|
elif q == 'test':
|
|
test()
|
|
elif q == 'sw':
|
|
sw()
|
|
else:
|
|
if len(sys.argv) == 1:
|
|
raise SystemExit('Usage: win-ci.py sw|build|test')
|
|
raise SystemExit('%r is not a valid action' % sys.argv[-1])
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|