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
+8 -15
View File
@@ -230,13 +230,13 @@ class Packer:
# The blendfile that we pack is generally not its own dependency, so
# we have to explicitly add it to the _packed_paths.
bfile_path = self.blendfile.absolute()
bfile_path = bpathlib.make_absolute(self.blendfile)
# Both paths have to be resolved first, because this also translates
# network shares mapped to Windows drive letters back to their UNC
# notation. Only resolving one but not the other (which can happen
# with the abosolute() call above) can cause errors.
bfile_pp = self._target_path / bfile_path.resolve().relative_to(self.project.resolve())
bfile_pp = self._target_path / bfile_path.relative_to(bpathlib.make_absolute(self.project))
self._output_path = bfile_pp
self._progress_cb.pack_start()
@@ -330,15 +330,8 @@ class Packer:
act = self._actions[path]
assert isinstance(act, AssetAction)
# Remove the base of the path, effectively removing the 'absoluteness'.
# On POSIX this turns '/path/file.txt' into 'path/file.txt'.
# On Windows this turns 'X:/path/file.txt' into 'X/path/file.txt'.
if path.drive:
path_parts = (path.drive[0], *path.parts[1:])
else:
path_parts = path.parts[1:]
act.new_path = pathlib.Path(self._target_path, '_outside_project', *path_parts)
relpath = bpathlib.strip_root(path)
act.new_path = pathlib.Path(self._target_path, '_outside_project', relpath)
def _group_rewrites(self) -> None:
"""For each blend file, collect which fields need rewriting.
@@ -358,7 +351,7 @@ class Packer:
continue
for usage in action.usages:
bfile_path = usage.block.bfile.filepath.absolute().resolve()
bfile_path = bpathlib.make_absolute(usage.block.bfile.filepath)
insert_new_action = bfile_path not in self._actions
self._actions[bfile_path].rewrites.append(usage)
@@ -367,10 +360,10 @@ class Packer:
actions.add(self._actions[bfile_path])
def _path_in_project(self, path: pathlib.Path) -> bool:
abs_path = bpathlib.make_absolute(path)
abs_project = bpathlib.make_absolute(self.project)
try:
# MUST use resolve(), otherwise /path/to/proj/../../asset.png
# will return True (relative_to will return ../../asset.png).
path.resolve().relative_to(self.project)
abs_path.relative_to(abs_project)
except ValueError:
return False
return True
+5 -1
View File
@@ -26,6 +26,7 @@ import typing
import requests
import blender_asset_tracer.pack.transfer as bat_transfer
from blender_asset_tracer import bpathlib
MAX_DEFERRED_PATHS = 8
MAX_FAILED_PATHS = 8
@@ -83,6 +84,9 @@ class ShamanTransferrer(bat_transfer.FileTransferer):
self.log.info('Created checkout definition file of %d KiB',
len(definition_file) // 1024)
self.log.info('Feeding %d files to the Shaman', len(self._file_info))
if self.log.isEnabledFor(logging.INFO):
for path in self._file_info:
self.log.info(' - %s', path)
# Try to upload all the files.
failed_paths = set() # type: typing.Set[str]
@@ -151,7 +155,7 @@ class ShamanTransferrer(bat_transfer.FileTransferer):
checksum = cache.compute_cached_checksum(src)
filesize = src.stat().st_size
# relpath = dst.relative_to(self.project_root)
relpath = str(dst)[1:]
relpath = bpathlib.strip_root(dst).as_posix()
self._file_info[relpath] = FileInfo(
checksum=checksum,