aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph Reiter <reiter.christoph@gmail.com>2020-11-20 15:30:37 +0100
committerDylan Baker <dylan@pnwbakers.com>2020-11-23 09:26:41 -0800
commitabc7e6af01714206100a752898c325282436501f (patch)
treed057fb165f38b1ad71fe483634c11967a6e5b942
parent1db800bf67fc80abee313381aac0528ee33103c9 (diff)
downloadmeson-abc7e6af01714206100a752898c325282436501f.zip
meson-abc7e6af01714206100a752898c325282436501f.tar.gz
meson-abc7e6af01714206100a752898c325282436501f.tar.bz2
Add a variant of TemporaryDirectory that uses windows_proof_rmtree()
Adds TemporaryDirectoryWinProof which calls windows_proof_rmtree() on error. Use instead of hacky error handling (which might shadow other OSError) in Compiler.compile().
-rw-r--r--mesonbuild/compilers/compilers.py101
-rw-r--r--mesonbuild/mesonlib.py20
2 files changed, 68 insertions, 53 deletions
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py
index 4e9b86b..5c9e1ae 100644
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -13,7 +13,7 @@
# limitations under the License.
import abc
-import contextlib, os.path, re, tempfile
+import contextlib, os.path, re
import enum
import itertools
import typing as T
@@ -25,7 +25,7 @@ from .. import mesonlib
from ..linkers import LinkerEnvVarsMixin
from ..mesonlib import (
EnvironmentException, MachineChoice, MesonException,
- Popen_safe, split_args, LibType
+ Popen_safe, split_args, LibType, TemporaryDirectoryWinProof
)
from ..envconfig import (
get_env_var
@@ -735,57 +735,52 @@ class Compiler(metaclass=abc.ABCMeta):
# TODO: there isn't really any reason for this to be a contextmanager
if extra_args is None:
extra_args = []
- try:
- with tempfile.TemporaryDirectory(dir=temp_dir) as tmpdirname:
- no_ccache = False
- if isinstance(code, str):
- srcname = os.path.join(tmpdirname,
- 'testfile.' + self.default_suffix)
- with open(srcname, 'w') as ofile:
- ofile.write(code)
- # ccache would result in a cache miss
- no_ccache = True
- contents = code
- elif isinstance(code, mesonlib.File):
- srcname = code.fname
- with open(code.fname, 'r') as f:
- contents = f.read()
-
- # Construct the compiler command-line
- commands = self.compiler_args()
- commands.append(srcname)
- # Preprocess mode outputs to stdout, so no output args
- if mode != 'preprocess':
- output = self._get_compile_output(tmpdirname, mode)
- commands += self.get_output_args(output)
- commands.extend(self.get_compiler_args_for_mode(CompileCheckMode(mode)))
- # extra_args must be last because it could contain '/link' to
- # pass args to VisualStudio's linker. In that case everything
- # in the command line after '/link' is given to the linker.
- commands += extra_args
- # Generate full command-line with the exelist
- command_list = self.get_exelist() + commands.to_native()
- mlog.debug('Running compile:')
- mlog.debug('Working directory: ', tmpdirname)
- mlog.debug('Command line: ', ' '.join(command_list), '\n')
- mlog.debug('Code:\n', contents)
- os_env = os.environ.copy()
- os_env['LC_ALL'] = 'C'
- if no_ccache:
- os_env['CCACHE_DISABLE'] = '1'
- p, stdo, stde = Popen_safe(command_list, cwd=tmpdirname, env=os_env)
- mlog.debug('Compiler stdout:\n', stdo)
- mlog.debug('Compiler stderr:\n', stde)
-
- result = CompileResult(stdo, stde, list(commands), p.returncode, p.pid, input_name=srcname)
- if want_output:
- result.output_name = output
- yield result
- except OSError:
- # On Windows antivirus programs and the like hold on to files so
- # they can't be deleted. There's not much to do in this case. Also,
- # catch OSError because the directory is then no longer empty.
- return
+
+ with TemporaryDirectoryWinProof(dir=temp_dir) as tmpdirname:
+ no_ccache = False
+ if isinstance(code, str):
+ srcname = os.path.join(tmpdirname,
+ 'testfile.' + self.default_suffix)
+ with open(srcname, 'w') as ofile:
+ ofile.write(code)
+ # ccache would result in a cache miss
+ no_ccache = True
+ contents = code
+ elif isinstance(code, mesonlib.File):
+ srcname = code.fname
+ with open(code.fname, 'r') as f:
+ contents = f.read()
+
+ # Construct the compiler command-line
+ commands = self.compiler_args()
+ commands.append(srcname)
+ # Preprocess mode outputs to stdout, so no output args
+ if mode != 'preprocess':
+ output = self._get_compile_output(tmpdirname, mode)
+ commands += self.get_output_args(output)
+ commands.extend(self.get_compiler_args_for_mode(CompileCheckMode(mode)))
+ # extra_args must be last because it could contain '/link' to
+ # pass args to VisualStudio's linker. In that case everything
+ # in the command line after '/link' is given to the linker.
+ commands += extra_args
+ # Generate full command-line with the exelist
+ command_list = self.get_exelist() + commands.to_native()
+ mlog.debug('Running compile:')
+ mlog.debug('Working directory: ', tmpdirname)
+ mlog.debug('Command line: ', ' '.join(command_list), '\n')
+ mlog.debug('Code:\n', contents)
+ os_env = os.environ.copy()
+ os_env['LC_ALL'] = 'C'
+ if no_ccache:
+ os_env['CCACHE_DISABLE'] = '1'
+ p, stdo, stde = Popen_safe(command_list, cwd=tmpdirname, env=os_env)
+ mlog.debug('Compiler stdout:\n', stdo)
+ mlog.debug('Compiler stderr:\n', stde)
+
+ result = CompileResult(stdo, stde, list(commands), p.returncode, p.pid, input_name=srcname)
+ if want_output:
+ result.output_name = output
+ yield result
@contextlib.contextmanager
def cached_compile(self, code: str, cdata: coredata.CoreData, *,
diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py
index bb6a748..d46dfca 100644
--- a/mesonbuild/mesonlib.py
+++ b/mesonbuild/mesonlib.py
@@ -22,6 +22,7 @@ import collections
from enum import IntEnum
from functools import lru_cache, wraps
from itertools import tee, filterfalse
+from tempfile import TemporaryDirectory
import typing as T
import uuid
import textwrap
@@ -1452,6 +1453,25 @@ def windows_proof_rm(fpath: str) -> None:
os.unlink(fpath)
+class TemporaryDirectoryWinProof(TemporaryDirectory):
+ """
+ Like TemporaryDirectory, but cleans things up using
+ windows_proof_rmtree()
+ """
+
+ def __exit__(self, exc: T.Any, value: T.Any, tb: T.Any) -> None:
+ try:
+ super().__exit__(exc, value, tb)
+ except OSError:
+ windows_proof_rmtree(self.name)
+
+ def cleanup(self) -> None:
+ try:
+ super().cleanup()
+ except OSError:
+ windows_proof_rmtree(self.name)
+
+
def detect_subprojects(spdir_name: str, current_dir: str = '',
result: T.Optional[T.Dict[str, T.List[str]]] = None) -> T.Optional[T.Dict[str, T.List[str]]]:
if result is None: