Skip to content

Commit 0c4b28f

Browse files
Fix race condition in FileSystemPackageRepository directory creation, modernize usage of os.makedirs (#1913)
* Fix race condition in `FileSystemPackageRepository` directory creation Signed-off-by: Nathan Rusch <[email protected]> * Replace `safe_makedirs` helper with `os.makedirs(..., exist_ok=True)` Signed-off-by: Nathan Rusch <[email protected]> * Update remaining uses of `os.makedirs` to include `exist_ok=True` Signed-off-by: Nathan Rusch <[email protected]> --------- Signed-off-by: Nathan Rusch <[email protected]> Co-authored-by: Jean-Christophe Morin <[email protected]>
1 parent d152c9a commit 0c4b28f

File tree

11 files changed

+34
-66
lines changed

11 files changed

+34
-66
lines changed

src/rez/bind/_utils.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ def log(msg):
2626

2727
def make_dirs(*dirs):
2828
path = os.path.join(*dirs)
29-
if not os.path.exists(path):
30-
os.makedirs(path)
29+
os.makedirs(path, exist_ok=True)
3130
return path
3231

3332

src/rez/package_cache.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@
2424
from rez.exceptions import PackageCacheError
2525
from rez.vendor.lockfile import LockFile, NotLocked
2626
from rez.vendor.progress.spinner import PixelSpinner
27-
from rez.utils.filesystem import safe_listdir, safe_makedirs, safe_remove, \
28-
forceful_rmtree
27+
from rez.utils.filesystem import forceful_rmtree, safe_listdir, safe_remove
2928
from rez.utils.colorize import ColorizedStreamHandler
3029
from rez.utils.logging_ import print_warning
3130
from rez.packages import get_variant
@@ -100,9 +99,9 @@ def __init__(self, path):
10099
self.path = path
101100

102101
# make dirs for internal use
103-
safe_makedirs(self._log_dir)
104-
safe_makedirs(self._pending_dir)
105-
safe_makedirs(self._remove_dir)
102+
os.makedirs(self._log_dir, exist_ok=True)
103+
os.makedirs(self._pending_dir, exist_ok=True)
104+
os.makedirs(self._remove_dir, exist_ok=True)
106105

107106
def get_cached_root(self, variant):
108107
"""Get location of variant payload copy.
@@ -172,7 +171,6 @@ def add_variant(self, variant, force=False, wait_for_copying=False, logger=None)
172171
- int: One of VARIANT_FOUND, VARIANT_CREATED, VARIANT_COPYING, VARIANT_COPY_STALLED
173172
"""
174173
from rez.utils.base26 import get_next_base26
175-
from rez.utils.filesystem import safe_makedirs
176174

177175
# do some sanity checking on variant to cache
178176
package = variant.parent
@@ -263,7 +261,7 @@ def add_variant(self, variant, force=False, wait_for_copying=False, logger=None)
263261

264262
# 1.
265263
path = self._get_hash_path(variant)
266-
safe_makedirs(path)
264+
os.makedirs(path, exist_ok=True)
267265

268266
# construct data to store to json file
269267
data = {

src/rez/package_copy.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from rez.utils.sourcecode import IncludeModuleManager
1818
from rez.utils.logging_ import print_info, print_warning
1919
from rez.utils.filesystem import replacing_symlink, replacing_copy, \
20-
safe_makedirs, additive_copytree, make_path_writable, get_existing_path
20+
additive_copytree, make_path_writable, get_existing_path
2121

2222

2323
def copy_package(package, dest_repository, variants=None, shallow=False,
@@ -287,7 +287,7 @@ def _copy_variant_payload(src_variant, dest_pkg_repo, shallow=False,
287287

288288
# copy the variant payload
289289
with ctxt:
290-
safe_makedirs(variant_install_path)
290+
os.makedirs(variant_install_path, exist_ok=True)
291291

292292
# determine files not to copy
293293
skip_files = []
@@ -362,7 +362,7 @@ def _copy_variant_payload(src_variant, dest_pkg_repo, shallow=False,
362362
src_package.config.variant_shortlinks_dirname
363363
)
364364

365-
safe_makedirs(base_shortlinks_path)
365+
os.makedirs(base_shortlinks_path, exist_ok=True)
366366

367367
# shortlink
368368
rel_variant_path = os.path.relpath(
@@ -425,5 +425,5 @@ def _copy_package_include_modules(src_package, dest_pkg_repo, overrides=None):
425425
ctxt = with_noop()
426426

427427
with ctxt:
428-
safe_makedirs(dest_include_modules_path)
428+
os.makedirs(dest_include_modules_path, exist_ok=True)
429429
additive_copytree(src_include_modules_path, dest_include_modules_path)

src/rez/package_maker.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -220,15 +220,13 @@ def make_package(name, path, make_base=None, make_root=None, skip_existing=True,
220220

221221
base = variant_.base
222222
if make_base and base:
223-
if not os.path.exists(base):
224-
os.makedirs(base)
223+
os.makedirs(base, exist_ok=True)
225224
os.chdir(base)
226225
make_base(variant_, base)
227226

228227
root = variant_.root
229228
if make_root and root:
230-
if not os.path.exists(root):
231-
os.makedirs(root)
229+
os.makedirs(root, exist_ok=True)
232230
os.chdir(root)
233231
make_root(variant_, root)
234232

src/rez/pip.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -386,8 +386,7 @@ def make_root(variant, path):
386386
src = os.path.join(targetpath, rel_src)
387387
dest = os.path.join(path, rel_dest)
388388

389-
if not os.path.exists(os.path.dirname(dest)):
390-
os.makedirs(os.path.dirname(dest))
389+
os.makedirs(os.path.dirname(dest), exist_ok=True)
391390

392391
shutil.copyfile(src, dest)
393392

src/rez/suite.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ def save(self, path, verbose=False):
441441
raise SuiteError("Cannot save, path exists: %r" % path)
442442

443443
contexts_path = os.path.join(path, "contexts")
444-
os.makedirs(contexts_path)
444+
os.makedirs(contexts_path, exist_ok=True)
445445

446446
# write suite data
447447
data = self.to_dict()
@@ -460,7 +460,7 @@ def save(self, path, verbose=False):
460460

461461
# create alias wrappers
462462
tools_path = os.path.join(path, "bin")
463-
os.makedirs(tools_path)
463+
os.makedirs(tools_path, exist_ok=True)
464464
if verbose:
465465
print("creating alias wrappers in %r..." % tools_path)
466466

src/rez/tests/test_packages.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,8 +347,7 @@ def test_variant_iteration(self):
347347
def test_variant_install(self):
348348
"""test variant installation."""
349349
repo_path = os.path.join(self.root, "packages")
350-
if not os.path.exists(repo_path):
351-
os.makedirs(repo_path)
350+
os.makedirs(repo_path, exist_ok=True)
352351

353352
def _data(obj):
354353
d = obj.validated_data()

src/rez/utils/filesystem.py

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -173,19 +173,6 @@ def safe_listdir(path):
173173
raise
174174

175175

176-
def safe_makedirs(path):
177-
"""Safe makedirs.
178-
179-
Works in a multithreaded scenario.
180-
"""
181-
if not os.path.exists(path):
182-
try:
183-
os.makedirs(path)
184-
except OSError:
185-
if not os.path.exists(path):
186-
raise
187-
188-
189176
def safe_remove(path):
190177
"""Safely remove the given file or directory.
191178
@@ -303,8 +290,7 @@ def replace_file_or_dir(dest, source):
303290
def additive_copytree(src, dst, symlinks=False, ignore=None):
304291
"""Version of `copytree` that merges into an existing directory.
305292
"""
306-
if not os.path.exists(dst):
307-
os.makedirs(dst)
293+
os.makedirs(dst, exist_ok=True)
308294

309295
for item in os.listdir(src):
310296
s = os.path.join(src, item)
@@ -437,8 +423,7 @@ def copy(srcname, dstname):
437423
else:
438424
copy = shutil.copy2
439425

440-
if not os.path.isdir(dst):
441-
os.makedirs(dst)
426+
os.makedirs(dst, exist_ok=True)
442427

443428
errors = []
444429
for name in names:

src/rez/utils/py_dist.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@
1616

1717
def _mkdirs(*dirs):
1818
path = os.path.join(*dirs)
19-
if not os.path.exists(path):
20-
os.makedirs(path)
19+
os.makedirs(path, exist_ok=True)
2120
return path
2221

2322

src/rezplugins/build_process/local.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
from rez.utils.logging_ import print_warning
1515
from rez.utils.base26 import create_unique_base26_symlink
1616
from rez.utils.colorize import Printer, warning
17-
from rez.utils.filesystem import safe_makedirs, copy_or_replace, \
18-
make_path_writable, get_existing_path, forceful_rmtree
17+
from rez.utils.filesystem import copy_or_replace, get_existing_path, \
18+
forceful_rmtree, make_path_writable
1919
from rez.utils.sourcecode import IncludeModuleManager
2020
from rez.utils.filesystem import TempDirs
2121
from rez.package_test import PackageTestRunner, PackageTestResults
@@ -148,7 +148,7 @@ def _build_variant_base(self, variant, build_type, install_path=None,
148148
if clean and os.path.exists(variant_build_path):
149149
self._rmtree(variant_build_path)
150150

151-
safe_makedirs(variant_build_path)
151+
os.makedirs(variant_build_path, exist_ok=True)
152152

153153
# find last dir of installation path that exists, and possibly make it
154154
# writable during variant installation
@@ -167,8 +167,7 @@ def _build_variant_base(self, variant, build_type, install_path=None,
167167
pkg_repo = package_repository_manager.get_repository(install_path)
168168
pkg_repo.pre_variant_install(variant.resource)
169169

170-
if not os.path.exists(variant_install_path):
171-
safe_makedirs(variant_install_path)
170+
os.makedirs(variant_install_path, exist_ok=True)
172171

173172
# if hashed variants are enabled, create the variant shortlink
174173
if variant.parent.hashed_variants:
@@ -179,7 +178,7 @@ def _build_variant_base(self, variant, build_type, install_path=None,
179178
variant.parent.config.variant_shortlinks_dirname
180179
)
181180

182-
safe_makedirs(base_shortlinks_path)
181+
os.makedirs(base_shortlinks_path, exist_ok=True)
183182

184183
# create the shortlink
185184
rel_variant_path = os.path.relpath(
@@ -293,7 +292,7 @@ def _install_include_modules(self, install_path):
293292
base_path = self.get_package_install_path(install_path)
294293

295294
path = os.path.join(base_path, IncludeModuleManager.include_modules_subpath)
296-
safe_makedirs(path)
295+
os.makedirs(path, exist_ok=True)
297296

298297
definition_python_path = self.package.config.package_definition_python_path
299298

0 commit comments

Comments
 (0)