summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Tismer <tismer@stackless.com>2018-12-09 20:05:57 +0100
committerChristian Tismer <tismer@stackless.com>2018-12-10 08:53:39 +0000
commitf1b6fa25e4bae5330c768014dbc61762f190e18c (patch)
tree221814f11c4c5ae733aaaca384b5fc9ed5046412
parent4207871c7f570f1ce3e268b9255b4d3c120cb247 (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>
-rw-r--r--sources/pyside2/PySide2/support/generate_pyi.py120
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 bd3e7500..256f303a 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__":