Improved path handling

This commit fixes a bunch of issues at the same time, as they are all
related to path handling:

- `pathlib.Path.resolve()` or `.absolute()` are replaced by
  `bpathlib.make_absolute()`. The latter does NOT follow symlinks and does
  NOT network mounts from a drive letter to UNC notation. This also has
  advantages on non-Windows sytems, as it allows BAT-packing a directory
  structure with symlinked files (such as a Shaman checkout).
- Better handling of drive letters, and of paths that cross drive
  boundaries.
- Better testing of Windows-specific cases when running the tests on
  Windows, and of POSIX-specific cases on other platforms.

Thanks to @wisaac for starting this patch in D6676.

Thanks to @jbakker for pointing out the drive letter issue. This fixes
T70655.
This commit is contained in:
Sybren A. Stüvel
2020-03-17 17:15:19 +01:00
parent 3fa4389658
commit e4bf2e8e35
12 changed files with 367 additions and 67 deletions
+5 -5
View File
@@ -82,7 +82,7 @@ class BlockIterator:
yield from self._visit_linked_blocks(blocks_per_lib)
def _visit_blocks(self, bfile, limit_to):
bpath = bfile.filepath.absolute().resolve()
bpath = bpathlib.make_absolute(bfile.filepath)
root_dir = bpathlib.BlendPath(bpath.parent)
# Mapping from library path to data blocks to expand.
@@ -123,10 +123,10 @@ class BlockIterator:
# We've gone through all the blocks in this file, now open the libraries
# and iterate over the blocks referred there.
for lib_bpath, idblocks in blocks_per_lib.items():
lib_path = pathlib.Path(lib_bpath.to_path())
try:
lib_path = lib_path.resolve()
except FileNotFoundError:
lib_path = bpathlib.make_absolute(lib_bpath.to_path())
assert lib_path.exists()
if not lib_path.exists():
log.warning('Library %s does not exist', lib_path)
continue
+9 -10
View File
@@ -107,8 +107,8 @@ class BlockUsage:
def __repr__(self):
if self.path_full_field is None:
field_name = self.path_dir_field.name.name_full.decode() + \
'/' + \
self.path_base_field.name.name_full.decode()
'/' + \
self.path_base_field.name.name_full.decode()
else:
field_name = self.path_full_field.name.name_full.decode()
return '<BlockUsage name=%r type=%r field=%r asset=%r%s>' % (
@@ -141,20 +141,19 @@ class BlockUsage:
log.warning('Path %s does not exist for %s', path, self)
def __fspath__(self) -> pathlib.Path:
"""Determine the absolute path of the asset on the filesystem.
The path is resolved (see pathlib.Path.resolve()) if it exists on the
filesystem.
"""
"""Determine the absolute path of the asset on the filesystem."""
if self._abspath is None:
bpath = self.block.bfile.abspath(self.asset_path)
log.info('Resolved %s rel to %s -> %s',
self.asset_path, self.block.bfile.filepath, bpath)
as_path = pathlib.Path(bpath.to_path())
# Windows cannot resolve() a path that has a glob pattern in it.
# Windows cannot make a path that has a glob pattern in it absolute.
# Since globs are generally only on the filename part, we take that off,
# resolve() the parent directory, then put the filename back.
# make the parent directory absolute, then put the filename back.
try:
abs_parent = as_path.parent.resolve()
abs_parent = bpathlib.make_absolute(as_path.parent)
except FileNotFoundError:
self._abspath = as_path
else: