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:
Victor Stinner
2014-12-19 17:07:56 +01:00
parent 023fdeb8d3
commit 692066b2c2

View File

@@ -28,6 +28,47 @@ HG = 'hg'
SDK_ROOT = r"C:\Program Files\Microsoft SDKs\Windows"
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):
def __init__(self):
root = os.path.dirname(__file__)
@@ -37,11 +78,17 @@ class Release(object):
self.sdist = False
self.dry_run = 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
def _popen(self, args, **kw):
print('+ ' + ' '.join(args))
verbose = kw.pop('verbose', True)
if self.verbose and verbose:
print('+ ' + ' '.join(args))
if PY3:
kw['universal_newlines'] = True
proc = subprocess.Popen(args, **kw)
@@ -49,9 +96,11 @@ class Release(object):
yield proc
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()
return stdout
return proc.returncode, stdout
def run_command(self, *args, **kw):
with self._popen(args, **kw) as proc:
@@ -60,65 +109,42 @@ class Release(object):
sys.exit(exitcode)
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()
if not line.startswith("?")]
def remove_directory(self, name):
path = os.path.join(self.root, name)
if os.path.exists(path):
print("Remove directory: %s" % name)
if self.verbose:
print("Remove directory: %s" % name)
shutil.rmtree(path)
def remove_file(self, name):
path = os.path.join(self.root, name)
if os.path.exists(path):
print("Remove file: %s" % name)
if self.verbose:
print("Remove file: %s" % name)
os.unlink(path)
def windows_sdk_setenv(self, pyver, bits):
if pyver >= (3, 3):
def windows_sdk_setenv(self, pyver):
if (pyver.major, pyver.minor) >= (3, 3):
sdkver = "v7.1"
else:
sdkver = "v7.0"
setenv = os.path.join(SDK_ROOT, sdkver, 'Bin', 'SetEnv.cmd')
if not os.path.exists(setenv):
print("Unable to find Windows SDK %s for Python %s.%s"
% (sdkver, pyver[0], pyver[1]))
print("Unable to find Windows SDK %s for %s"
% (sdkver, pyver))
print("Please download and install it")
print("%s does not exists" % setenv)
sys.exit(1)
if bits == 64:
if pyver.bits == 64:
arch = '/x64'
else:
arch = '/x86'
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):
if not re.search("[ '\"]", arg):
return arg
@@ -129,6 +155,8 @@ class Release(object):
return ' '.join(self.quote(arg) for arg in args)
def cleanup(self):
if self.verbose:
print("Cleanup")
self.remove_directory('build')
self.remove_directory('dist')
self.remove_file('_overlapped.pyd')
@@ -138,16 +166,18 @@ class Release(object):
self.cleanup()
self.run_command(sys.executable, 'setup.py', 'sdist', 'upload')
def runtests(self, pyver, bits):
pythonstr = "%s.%s (%s bits)" % (pyver[0], pyver[1], bits)
python = self.get_python(pyver, bits)
def runtests(self, pyver):
print("Run tests on %s" % pyver)
self.build(pyver, bits, 'build')
if bits == 64:
python = pyver.get_executable(self)
print("Build _overlapped.pyd for %s" % pyver)
self.build(pyver, 'build')
if pyver.bits == 64:
arch = 'win-amd64'
else:
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')
dst = os.path.join(self.root, PROJECT, '_overlapped.pyd')
shutil.copyfile(src, dst)
@@ -159,26 +189,27 @@ class Release(object):
dbg_env[DEBUG_ENV_VAR] = '1'
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)
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)
if self.aiotest:
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)
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)
print("")
def build(self, pyver, bits, *cmds):
def build(self, pyver, *cmds):
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)
@@ -196,15 +227,25 @@ class Release(object):
print(BATCH_FAIL_ON_ERROR, file=temp)
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:
os.unlink(temp.name)
def test_wheel(self, pyver, bits):
self.build(pyver, bits, 'bdist_wheel')
def test_wheel(self, pyver):
print("Test building wheel package for %s" % pyver)
self.build(pyver, 'bdist_wheel')
def publish_wheel(self, pyver, bits):
self.build(pyver, bits, 'bdist_wheel', 'upload')
def publish_wheel(self, pyver):
self.build(pyver, 'bdist_wheel', 'upload')
def main(self):
try:
@@ -235,14 +276,19 @@ class Release(object):
sys.exit(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:
for pyver, bits in PYTHON_VERSIONS:
self.runtests(pyver, bits)
for pyver in self.python_versions:
self.runtests(pyver)
for pyver, bits in PYTHON_VERSIONS:
self.test_wheel(pyver, bits)
for pyver in self.python_versions:
self.test_wheel(pyver)
if self.dry_run:
sys.exit(0)
@@ -253,8 +299,8 @@ class Release(object):
if self.sdist:
self.sdist_upload()
for pyver, bits in PYTHON_VERSIONS:
self.publish_wheel(pyver, bits)
for pyver in self.python_versions:
self.publish_wheel(pyver)
print("")
if self.register:
@@ -262,9 +308,8 @@ class Release(object):
print("Uploaded:")
if self.sdist:
print("- sdist")
for pyver, bits in PYTHON_VERSIONS:
print("- Windows wheel %s bits package for Python %s.%s"
% (bits, pyver[0], pyver[1]))
for pyver in self.python_versions:
print("- Windows wheel package for %s" % pyver)
if __name__ == "__main__":
Release().main()