mirror of
https://github.com/github/codeql.git
synced 2026-04-30 19:26:02 +02:00
Python: Copy Python extractor to codeql repo
This commit is contained in:
102
python/extractor/tests/buildtools/helper.py
Normal file
102
python/extractor/tests/buildtools/helper.py
Normal file
@@ -0,0 +1,102 @@
|
||||
import os
|
||||
import stat
|
||||
import tempfile
|
||||
import shutil
|
||||
import time
|
||||
import sys
|
||||
import subprocess
|
||||
from contextlib import contextmanager
|
||||
from functools import wraps
|
||||
|
||||
|
||||
# Would have liked to use a decorator, but for Python 2 the functools.wraps is not good enough for
|
||||
# signature preservation that pytest can figure out what is going on. It would be possible to use
|
||||
# the decorator package, but that seemed like a bit too much of a hassle.
|
||||
@contextmanager
|
||||
def in_fresh_temp_dir():
|
||||
old_cwd = os.getcwd()
|
||||
with managed_temp_dir('extractor-python-buildtools-test-') as tmp:
|
||||
os.chdir(tmp)
|
||||
try:
|
||||
yield tmp
|
||||
finally:
|
||||
os.chdir(old_cwd)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def managed_temp_dir(prefix=None):
|
||||
dir = tempfile.mkdtemp(prefix=prefix)
|
||||
try:
|
||||
yield dir
|
||||
finally:
|
||||
rmtree_robust(dir)
|
||||
|
||||
|
||||
def rmtree_robust(dir):
|
||||
if is_windows():
|
||||
# It's important that the path is a Unicode path on Windows, so
|
||||
# that the right system calls get used.
|
||||
dir = u'' + dir
|
||||
if not dir.startswith("\\\\?\\"):
|
||||
dir = "\\\\?\\" + os.path.abspath(dir)
|
||||
|
||||
# Emulate Python 3 "nonlocal" keyword
|
||||
class state: pass
|
||||
state.last_failed_delete = None
|
||||
|
||||
|
||||
def _rmtree(path):
|
||||
"""wrapper of shutil.rmtree to handle Python 3.12 rename (onerror => onexc)"""
|
||||
if sys.version_info >= (3, 12):
|
||||
shutil.rmtree(path, onexc=remove_error)
|
||||
else:
|
||||
shutil.rmtree(path, onerror=remove_error)
|
||||
|
||||
def remove_error(func, path, excinfo):
|
||||
# If we get an error twice in a row for the same path then just give up.
|
||||
if state.last_failed_delete == path:
|
||||
return
|
||||
state.last_failed_delete = path
|
||||
|
||||
# The problem could be one of permissions, so setting path writable
|
||||
# might fix it.
|
||||
os.chmod(path, stat.S_IWRITE)
|
||||
|
||||
# On Windows, we sometimes get errors about directories not being
|
||||
# empty, but immediately afterwards they are empty. Waiting a bit
|
||||
# might therefore be sufficient.
|
||||
t = 0.1
|
||||
while (True):
|
||||
try:
|
||||
if os.path.isdir(path):
|
||||
_rmtree(path)
|
||||
else:
|
||||
os.remove(path)
|
||||
except OSError:
|
||||
if (t > 1):
|
||||
return # Give up
|
||||
time.sleep(t)
|
||||
t *= 2
|
||||
_rmtree(dir)
|
||||
# On Windows, attempting to write immediately after deletion may result in
|
||||
# an 'access denied' exception, so wait a bit.
|
||||
if is_windows():
|
||||
time.sleep(0.5)
|
||||
|
||||
|
||||
def is_windows():
|
||||
return os.name == 'nt'
|
||||
|
||||
|
||||
@contextmanager
|
||||
def copy_repo_dir(repo_dir_in):
|
||||
with managed_temp_dir(prefix="extractor-python-buildtools-test-") as tmp:
|
||||
repo_dir = os.path.join(tmp, 'repo')
|
||||
print('copying', repo_dir_in, 'to', repo_dir)
|
||||
shutil.copytree(repo_dir_in, repo_dir, symlinks=True)
|
||||
yield repo_dir
|
||||
|
||||
################################################################################
|
||||
|
||||
|
||||
DEVNULL = subprocess.DEVNULL
|
||||
Reference in New Issue
Block a user