mirror of
				https://github.com/kovidgoyal/calibre.git
				synced 2025-11-03 19:17:02 -05: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()
 |