Enhance release.py
* Only get the python executable once per python version * Much lesser verbose output: by default, hide all logs when building trollius
This commit is contained in:
169
release.py
169
release.py
@@ -28,6 +28,47 @@ HG = 'hg'
|
|||||||
SDK_ROOT = r"C:\Program Files\Microsoft SDKs\Windows"
|
SDK_ROOT = r"C:\Program Files\Microsoft SDKs\Windows"
|
||||||
BATCH_FAIL_ON_ERROR = "@IF %errorlevel% neq 0 exit /b %errorlevel%"
|
BATCH_FAIL_ON_ERROR = "@IF %errorlevel% neq 0 exit /b %errorlevel%"
|
||||||
|
|
||||||
|
|
||||||
|
class PythonVersion:
|
||||||
|
def __init__(self, major, minor, bits):
|
||||||
|
self.major = major
|
||||||
|
self.minor = minor
|
||||||
|
self.bits = bits
|
||||||
|
self._executable = None
|
||||||
|
|
||||||
|
def get_executable(self, app):
|
||||||
|
if self._executable:
|
||||||
|
return self._executable
|
||||||
|
|
||||||
|
if self.bits == 32:
|
||||||
|
python = 'c:\\Python%s%s_32bit\\python.exe' % (self.major, self.minor)
|
||||||
|
else:
|
||||||
|
python = 'c:\\Python%s%s\\python.exe' % (self.major, self.minor)
|
||||||
|
if not os.path.exists(python):
|
||||||
|
print("Unable to find python %s" % self)
|
||||||
|
print("%s does not exists" % python)
|
||||||
|
sys.exit(1)
|
||||||
|
code = (
|
||||||
|
'import platform, sys; '
|
||||||
|
'print("{ver.major}.{ver.minor} {bits}".format('
|
||||||
|
'ver=sys.version_info, '
|
||||||
|
'bits=platform.architecture()[0]))'
|
||||||
|
)
|
||||||
|
exitcode, stdout = app.get_output(python, '-c', code)
|
||||||
|
stdout = stdout.rstrip()
|
||||||
|
expected = "%s.%s %sbit" % (self.major, self.minor, self.bits)
|
||||||
|
if stdout != expected:
|
||||||
|
print("Python version or architecture doesn't match")
|
||||||
|
print("got %r, expected %r" % (stdout, expected))
|
||||||
|
print(python)
|
||||||
|
sys.exit(1)
|
||||||
|
self._executable = python
|
||||||
|
return python
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Python %s.%s (%s bits)' % (self.major, self.minor, self.bits)
|
||||||
|
|
||||||
|
|
||||||
class Release(object):
|
class Release(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
root = os.path.dirname(__file__)
|
root = os.path.dirname(__file__)
|
||||||
@@ -37,10 +78,16 @@ class Release(object):
|
|||||||
self.sdist = False
|
self.sdist = False
|
||||||
self.dry_run = True
|
self.dry_run = True
|
||||||
self.test = True
|
self.test = True
|
||||||
self.aiotest = True
|
self.aiotest = False
|
||||||
|
self.verbose = False
|
||||||
|
self.python_versions = [
|
||||||
|
PythonVersion(pyver[0], pyver[1], bits)
|
||||||
|
for pyver, bits in PYTHON_VERSIONS]
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def _popen(self, args, **kw):
|
def _popen(self, args, **kw):
|
||||||
|
verbose = kw.pop('verbose', True)
|
||||||
|
if self.verbose and verbose:
|
||||||
print('+ ' + ' '.join(args))
|
print('+ ' + ' '.join(args))
|
||||||
if PY3:
|
if PY3:
|
||||||
kw['universal_newlines'] = True
|
kw['universal_newlines'] = True
|
||||||
@@ -49,9 +96,11 @@ class Release(object):
|
|||||||
yield proc
|
yield proc
|
||||||
|
|
||||||
def get_output(self, *args, **kw):
|
def get_output(self, *args, **kw):
|
||||||
with self._popen(args, stdout=subprocess.PIPE, **kw) as proc:
|
kw['stdout'] = subprocess.PIPE
|
||||||
|
kw['stderr'] = subprocess.STDOUT
|
||||||
|
with self._popen(args, **kw) as proc:
|
||||||
stdout, stderr = proc.communicate()
|
stdout, stderr = proc.communicate()
|
||||||
return stdout
|
return proc.returncode, stdout
|
||||||
|
|
||||||
def run_command(self, *args, **kw):
|
def run_command(self, *args, **kw):
|
||||||
with self._popen(args, **kw) as proc:
|
with self._popen(args, **kw) as proc:
|
||||||
@@ -60,65 +109,42 @@ class Release(object):
|
|||||||
sys.exit(exitcode)
|
sys.exit(exitcode)
|
||||||
|
|
||||||
def get_local_changes(self):
|
def get_local_changes(self):
|
||||||
status = self.get_output(HG, 'status')
|
exitcode, status = self.get_output(HG, 'status')
|
||||||
return [line for line in status.splitlines()
|
return [line for line in status.splitlines()
|
||||||
if not line.startswith("?")]
|
if not line.startswith("?")]
|
||||||
|
|
||||||
def remove_directory(self, name):
|
def remove_directory(self, name):
|
||||||
path = os.path.join(self.root, name)
|
path = os.path.join(self.root, name)
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
|
if self.verbose:
|
||||||
print("Remove directory: %s" % name)
|
print("Remove directory: %s" % name)
|
||||||
shutil.rmtree(path)
|
shutil.rmtree(path)
|
||||||
|
|
||||||
def remove_file(self, name):
|
def remove_file(self, name):
|
||||||
path = os.path.join(self.root, name)
|
path = os.path.join(self.root, name)
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
|
if self.verbose:
|
||||||
print("Remove file: %s" % name)
|
print("Remove file: %s" % name)
|
||||||
os.unlink(path)
|
os.unlink(path)
|
||||||
|
|
||||||
def windows_sdk_setenv(self, pyver, bits):
|
def windows_sdk_setenv(self, pyver):
|
||||||
if pyver >= (3, 3):
|
if (pyver.major, pyver.minor) >= (3, 3):
|
||||||
sdkver = "v7.1"
|
sdkver = "v7.1"
|
||||||
else:
|
else:
|
||||||
sdkver = "v7.0"
|
sdkver = "v7.0"
|
||||||
setenv = os.path.join(SDK_ROOT, sdkver, 'Bin', 'SetEnv.cmd')
|
setenv = os.path.join(SDK_ROOT, sdkver, 'Bin', 'SetEnv.cmd')
|
||||||
if not os.path.exists(setenv):
|
if not os.path.exists(setenv):
|
||||||
print("Unable to find Windows SDK %s for Python %s.%s"
|
print("Unable to find Windows SDK %s for %s"
|
||||||
% (sdkver, pyver[0], pyver[1]))
|
% (sdkver, pyver))
|
||||||
print("Please download and install it")
|
print("Please download and install it")
|
||||||
print("%s does not exists" % setenv)
|
print("%s does not exists" % setenv)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if bits == 64:
|
if pyver.bits == 64:
|
||||||
arch = '/x64'
|
arch = '/x64'
|
||||||
else:
|
else:
|
||||||
arch = '/x86'
|
arch = '/x86'
|
||||||
return ["CALL", setenv, "/release", arch]
|
return ["CALL", setenv, "/release", arch]
|
||||||
|
|
||||||
def get_python(self, version, bits):
|
|
||||||
if bits == 32:
|
|
||||||
python = 'c:\\Python%s%s_32bit\\python.exe' % version
|
|
||||||
else:
|
|
||||||
python = 'c:\\Python%s%s\\python.exe' % version
|
|
||||||
if not os.path.exists(python):
|
|
||||||
print("Unable to find python%s.%s" % version)
|
|
||||||
print("%s does not exists" % python)
|
|
||||||
sys.exit(1)
|
|
||||||
code = (
|
|
||||||
'import platform, sys; '
|
|
||||||
'print("{ver.major}.{ver.minor} {bits}".format('
|
|
||||||
'ver=sys.version_info, '
|
|
||||||
'bits=platform.architecture()[0]))'
|
|
||||||
)
|
|
||||||
stdout = self.get_output(python, '-c', code)
|
|
||||||
stdout = stdout.rstrip()
|
|
||||||
expected = "%s.%s %sbit" % (version[0], version[1], bits)
|
|
||||||
if stdout != expected:
|
|
||||||
print("Python version or architecture doesn't match")
|
|
||||||
print("got %r, expected %r" % (stdout, expected))
|
|
||||||
print(python)
|
|
||||||
sys.exit(1)
|
|
||||||
return python
|
|
||||||
|
|
||||||
def quote(self, arg):
|
def quote(self, arg):
|
||||||
if not re.search("[ '\"]", arg):
|
if not re.search("[ '\"]", arg):
|
||||||
return arg
|
return arg
|
||||||
@@ -129,6 +155,8 @@ class Release(object):
|
|||||||
return ' '.join(self.quote(arg) for arg in args)
|
return ' '.join(self.quote(arg) for arg in args)
|
||||||
|
|
||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
|
if self.verbose:
|
||||||
|
print("Cleanup")
|
||||||
self.remove_directory('build')
|
self.remove_directory('build')
|
||||||
self.remove_directory('dist')
|
self.remove_directory('dist')
|
||||||
self.remove_file('_overlapped.pyd')
|
self.remove_file('_overlapped.pyd')
|
||||||
@@ -138,16 +166,18 @@ class Release(object):
|
|||||||
self.cleanup()
|
self.cleanup()
|
||||||
self.run_command(sys.executable, 'setup.py', 'sdist', 'upload')
|
self.run_command(sys.executable, 'setup.py', 'sdist', 'upload')
|
||||||
|
|
||||||
def runtests(self, pyver, bits):
|
def runtests(self, pyver):
|
||||||
pythonstr = "%s.%s (%s bits)" % (pyver[0], pyver[1], bits)
|
print("Run tests on %s" % pyver)
|
||||||
python = self.get_python(pyver, bits)
|
|
||||||
|
|
||||||
self.build(pyver, bits, 'build')
|
python = pyver.get_executable(self)
|
||||||
if bits == 64:
|
|
||||||
|
print("Build _overlapped.pyd for %s" % pyver)
|
||||||
|
self.build(pyver, 'build')
|
||||||
|
if pyver.bits == 64:
|
||||||
arch = 'win-amd64'
|
arch = 'win-amd64'
|
||||||
else:
|
else:
|
||||||
arch = 'win32'
|
arch = 'win32'
|
||||||
build_dir = 'lib.%s-%s.%s' % (arch, pyver[0], pyver[1])
|
build_dir = 'lib.%s-%s.%s' % (arch, pyver.major, pyver.minor)
|
||||||
src = os.path.join(self.root, 'build', build_dir, PROJECT, '_overlapped.pyd')
|
src = os.path.join(self.root, 'build', build_dir, PROJECT, '_overlapped.pyd')
|
||||||
dst = os.path.join(self.root, PROJECT, '_overlapped.pyd')
|
dst = os.path.join(self.root, PROJECT, '_overlapped.pyd')
|
||||||
shutil.copyfile(src, dst)
|
shutil.copyfile(src, dst)
|
||||||
@@ -159,26 +189,27 @@ class Release(object):
|
|||||||
dbg_env[DEBUG_ENV_VAR] = '1'
|
dbg_env[DEBUG_ENV_VAR] = '1'
|
||||||
|
|
||||||
args = (python, 'runtests.py', '-r')
|
args = (python, 'runtests.py', '-r')
|
||||||
print("Run runtests.py in release mode with %s" % pythonstr)
|
print("Run runtests.py in release mode on %s" % pyver)
|
||||||
self.run_command(*args, env=release_env)
|
self.run_command(*args, env=release_env)
|
||||||
|
|
||||||
print("Run runtests.py in debug mode with %s" % pythonstr)
|
print("Run runtests.py in debug mode on %s" % pyver)
|
||||||
self.run_command(*args, env=dbg_env)
|
self.run_command(*args, env=dbg_env)
|
||||||
|
|
||||||
if self.aiotest:
|
if self.aiotest:
|
||||||
args = (python, 'run_aiotest.py')
|
args = (python, 'run_aiotest.py')
|
||||||
print("Run aiotest in release mode with %s" % pythonstr)
|
print("Run aiotest in release mode on %s" % pyver)
|
||||||
self.run_command(*args, env=release_env)
|
self.run_command(*args, env=release_env)
|
||||||
|
|
||||||
print("Run aiotest in debug mode with %s" % pythonstr)
|
print("Run aiotest in debug mode on %s" % pyver)
|
||||||
self.run_command(*args, env=dbg_env)
|
self.run_command(*args, env=dbg_env)
|
||||||
|
print("")
|
||||||
|
|
||||||
def build(self, pyver, bits, *cmds):
|
def build(self, pyver, *cmds):
|
||||||
self.cleanup()
|
self.cleanup()
|
||||||
|
|
||||||
setenv = self.windows_sdk_setenv(pyver, bits)
|
setenv = self.windows_sdk_setenv(pyver)
|
||||||
|
|
||||||
python = self.get_python(pyver, bits)
|
python = pyver.get_executable(self)
|
||||||
|
|
||||||
cmd = [python, 'setup.py'] + list(cmds)
|
cmd = [python, 'setup.py'] + list(cmds)
|
||||||
|
|
||||||
@@ -196,15 +227,25 @@ class Release(object):
|
|||||||
print(BATCH_FAIL_ON_ERROR, file=temp)
|
print(BATCH_FAIL_ON_ERROR, file=temp)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.run_command(temp.name)
|
if self.verbose:
|
||||||
|
print("Setup Windows SDK")
|
||||||
|
print("+ " + ' '.join(cmd))
|
||||||
|
if self.verbose:
|
||||||
|
self.run_command(temp.name, verbose=False)
|
||||||
|
else:
|
||||||
|
exitcode, stdout = self.get_output(temp.name, verbose=False)
|
||||||
|
if exitcode:
|
||||||
|
sys.stdout.write(stdout)
|
||||||
|
sys.stdout.flush()
|
||||||
finally:
|
finally:
|
||||||
os.unlink(temp.name)
|
os.unlink(temp.name)
|
||||||
|
|
||||||
def test_wheel(self, pyver, bits):
|
def test_wheel(self, pyver):
|
||||||
self.build(pyver, bits, 'bdist_wheel')
|
print("Test building wheel package for %s" % pyver)
|
||||||
|
self.build(pyver, 'bdist_wheel')
|
||||||
|
|
||||||
def publish_wheel(self, pyver, bits):
|
def publish_wheel(self, pyver):
|
||||||
self.build(pyver, bits, 'bdist_wheel', 'upload')
|
self.build(pyver, 'bdist_wheel', 'upload')
|
||||||
|
|
||||||
def main(self):
|
def main(self):
|
||||||
try:
|
try:
|
||||||
@@ -235,14 +276,19 @@ class Release(object):
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
hg_tag = sys.argv[1]
|
hg_tag = sys.argv[1]
|
||||||
self.run_command(HG, 'up', hg_tag)
|
print("Update repository to revision %s" % hg_tag)
|
||||||
|
exitcode, output = self.get_output(HG, 'update', hg_tag)
|
||||||
|
if exitcode:
|
||||||
|
sys.stdout.write(output)
|
||||||
|
sys.stdout.flush()
|
||||||
|
sys.exit(exitcode)
|
||||||
|
|
||||||
if self.test:
|
if self.test:
|
||||||
for pyver, bits in PYTHON_VERSIONS:
|
for pyver in self.python_versions:
|
||||||
self.runtests(pyver, bits)
|
self.runtests(pyver)
|
||||||
|
|
||||||
for pyver, bits in PYTHON_VERSIONS:
|
for pyver in self.python_versions:
|
||||||
self.test_wheel(pyver, bits)
|
self.test_wheel(pyver)
|
||||||
|
|
||||||
if self.dry_run:
|
if self.dry_run:
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
@@ -253,8 +299,8 @@ class Release(object):
|
|||||||
if self.sdist:
|
if self.sdist:
|
||||||
self.sdist_upload()
|
self.sdist_upload()
|
||||||
|
|
||||||
for pyver, bits in PYTHON_VERSIONS:
|
for pyver in self.python_versions:
|
||||||
self.publish_wheel(pyver, bits)
|
self.publish_wheel(pyver)
|
||||||
|
|
||||||
print("")
|
print("")
|
||||||
if self.register:
|
if self.register:
|
||||||
@@ -262,9 +308,8 @@ class Release(object):
|
|||||||
print("Uploaded:")
|
print("Uploaded:")
|
||||||
if self.sdist:
|
if self.sdist:
|
||||||
print("- sdist")
|
print("- sdist")
|
||||||
for pyver, bits in PYTHON_VERSIONS:
|
for pyver in self.python_versions:
|
||||||
print("- Windows wheel %s bits package for Python %s.%s"
|
print("- Windows wheel package for %s" % pyver)
|
||||||
% (bits, pyver[0], pyver[1]))
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
Release().main()
|
Release().main()
|
||||||
|
|||||||
Reference in New Issue
Block a user