diff options
author | Christian Tismer <tismer@stackless.com> | 2018-12-09 20:05:57 +0100 |
---|---|---|
committer | Christian Tismer <tismer@stackless.com> | 2018-12-10 08:53:39 +0000 |
commit | f1b6fa25e4bae5330c768014dbc61762f190e18c (patch) | |
tree | 221814f11c4c5ae733aaaca384b5fc9ed5046412 /sources | |
parent | 4207871c7f570f1ce3e268b9255b4d3c120cb247 (diff) |
Fix locking in generate_pyi.py
The file locking was written for Windows in mind.
But file operations are quite different on Linux.
This was no problem during normal builds, but showed
up das a possible racing condition when using the
"--reuse-build" flag.
This version uses a directory to create a lock and has
no platform specific code.
Task-number: PYSIDE-735
Change-Id: I9f27839b0697b49b4dbfea26d6f6949ec466c9d5
Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
Diffstat (limited to 'sources')
-rw-r--r-- | sources/pyside2/PySide2/support/generate_pyi.py | 120 |
1 files changed, 47 insertions, 73 deletions
diff --git a/sources/pyside2/PySide2/support/generate_pyi.py b/sources/pyside2/PySide2/support/generate_pyi.py index bd3e7500a..256f303a2 100644 --- a/sources/pyside2/PySide2/support/generate_pyi.py +++ b/sources/pyside2/PySide2/support/generate_pyi.py @@ -177,29 +177,6 @@ def find_imports(text): return [imp for imp in PySide2.__all__ if imp + "." in text] -def safe_create(filename): - pid = os.getpid() - locname = "{filename}.{pid}".format(**locals()) - f = io.open(locname, "w") # do not close for atomic rename on Linux - if sys.platform == "win32": - f.close() - try: - os.rename(locname, filename) - logger.debug("{pid}:File {filename} created".format(**locals())) - if sys.platform == "win32": - f = io.open(filename, "w") - return f - except OSError: - logger.debug("{pid}:Could not rename {locname} to {filename}" - .format(**locals())) - try: - os.remove(locname) - except OSError as e: - logger.warning("{pid}: unexpected os.remove error in safe_create: {e}" - .format(**locals())) - return None - - def generate_pyi(import_name, outpath, options): """ Generates a .pyi file. @@ -208,18 +185,11 @@ def generate_pyi(import_name, outpath, options): """ pid = os.getpid() plainname = import_name.split(".")[-1] - if not outpath: - outpath = os.path.dirname(PySide2.__file__) outfilepath = os.path.join(outpath, plainname + ".pyi") if options.skip and os.path.exists(outfilepath): - logger.debug("{pid}:Skipped existing: {outfilepath}".format(**locals())) + logger.debug("{pid}:Skipped existing: {op}" + .format(op=os.path.basename(outfilepath), **locals())) return 1 - workpath = outfilepath + ".working" - if os.path.exists(workpath): - return 0 - realfile = safe_create(workpath) - if not realfile: - return 0 try: top = __import__(import_name) @@ -249,42 +219,28 @@ def generate_pyi(import_name, outpath, options): except ImportError as e: logger.debug("{pid}:Import problem with module {plainname}: {e}".format(**locals())) - try: - os.remove(workpath) - except OSError as e: - logger.warning("{pid}: unexpected os.remove error in generate_pyi: {e}" - .format(**locals())) return 0 - wr = Writer(realfile) - outfile.seek(0) - while True: - line = outfile.readline() - if not line: - break - line = line.rstrip() - # we remove the IMPORTS marker and insert imports if needed - if line == "IMPORTS": - if need_imports: - for mod_name in find_imports(outfile.getvalue()): - imp = "PySide2." + mod_name - if imp != import_name: - wr.print("import " + imp) - wr.print("import " + import_name) - wr.print() - wr.print() - else: - wr.print(line) - realfile.close() - - if os.path.exists(outfilepath): - os.remove(outfilepath) - try: - os.rename(workpath, outfilepath) - except OSError: - logger.warning("{pid}: probable duplicate generated: {outfilepath}"# - .format(**locals())) - return 0 + with open(outfilepath, "w") as realfile: + wr = Writer(realfile) + outfile.seek(0) + while True: + line = outfile.readline() + if not line: + break + line = line.rstrip() + # we remove the IMPORTS marker and insert imports if needed + if line == "IMPORTS": + if need_imports: + for mod_name in find_imports(outfile.getvalue()): + imp = "PySide2." + mod_name + if imp != import_name: + wr.print("import " + imp) + wr.print("import " + import_name) + wr.print() + wr.print() + else: + wr.print(line) logger.info("Generated: {outfilepath}".format(**locals())) if sys.version_info[0] == 3: # Python 3: We can check the file directly if the syntax is ok. @@ -292,6 +248,19 @@ def generate_pyi(import_name, outpath, options): return 1 +@contextmanager +def single_process(lockdir): + try: + os.mkdir(lockdir) + try: + yield lockdir + finally: + # make sure to cleanup, even if we leave with CTRL-C + os.rmdir(lockdir) + except OSError: + yield None + + def generate_all_pyi(outpath, options): ps = os.pathsep if options.sys_path: @@ -315,13 +284,18 @@ def generate_all_pyi(outpath, options): from PySide2.support.signature.lib.enum_sig import HintingEnumerator valid = 0 - for mod_name in PySide2.__all__: - import_name = "PySide2." + mod_name - valid += generate_pyi(import_name, outpath, options) - - npyi = len(PySide2.__all__) - if valid == npyi: - logger.info("+++ All {npyi} .pyi files have been created.".format(**locals())) + if not outpath: + outpath = os.path.dirname(PySide2.__file__) + lockdir = os.path.join(outpath, "generate_pyi.lockfile") + with single_process(lockdir) as locked: + if locked: + for mod_name in PySide2.__all__: + import_name = "PySide2." + mod_name + valid += generate_pyi(import_name, outpath, options) + + npyi = len(PySide2.__all__) + if valid == npyi: + logger.info("+++ All {npyi} .pyi files have been created.".format(**locals())) if __name__ == "__main__": |