buildkit.extractors: Refactoring and formatting

This commit is contained in:
Eloston
2018-03-20 22:09:26 +00:00
parent a3cfc7621b
commit 2cd39da2cb
5 changed files with 212 additions and 113 deletions

View File

@@ -25,8 +25,8 @@ from . import source_retrieval
from . import domain_substitution
from .common import (
CONFIG_BUNDLES_DIR, BUILDSPACE_DOWNLOADS, BUILDSPACE_TREE,
BUILDSPACE_TREE_PACKAGING, BUILDSPACE_USER_BUNDLE,
BuildkitAbort, get_resources_dir, get_logger)
BUILDSPACE_TREE_PACKAGING, BUILDSPACE_USER_BUNDLE, SEVENZIP_USE_REGISTRY,
BuildkitAbort, ExtractorEnum, get_resources_dir, get_logger)
from .config import ConfigBundle
# Classes
@@ -136,14 +136,14 @@ def _add_getsrc(subparsers):
"""Downloads, checks, and unpacks the necessary files into the buildspace tree"""
def _callback(args):
try:
user_binaries = {}
if args.tar_path is not None:
user_binaries['tar'] = args.tar_path
if args.sevenz_path is not None:
user_binaries['7z'] = args.sevenz_path
extractors = {
ExtractorEnum.SEVENZIP: args.sevenz_path,
ExtractorEnum.TAR: args.tar_path,
}
source_retrieval.retrieve_and_extract(
args.bundle, args.downloads, args.tree, prune_binaries=args.prune_binaries,
show_progress=args.show_progress, user_binaries=user_binaries)
config_bundle=args.bundle, buildspace_downloads=args.downloads,
buildspace_tree=args.tree, prune_binaries=args.prune_binaries,
show_progress=args.show_progress, extractors=extractors)
except FileExistsError as exc:
get_logger().error('Directory is not empty: %s', exc)
raise _CLIError()
@@ -185,9 +185,14 @@ def _add_getsrc(subparsers):
'--hide-progress-bar', action='store_false', dest='show_progress',
help='Hide the download progress.')
parser.add_argument(
'--tar-path', help='Path to the tar binary.')
'--tar-path', default='tar',
help=('(Linux and macOS only) Command or path to the BSD or GNU tar '
'binary for extraction. Default: %(default)s'))
parser.add_argument(
'--7z-path', help='Path to the 7z.exe binary.', dest='sevenz_path')
'--7z-path', dest='sevenz_path', default=SEVENZIP_USE_REGISTRY,
help=('(Windows only) Command or path to the 7-Zip 7z.exe binary. If '
'"_use_registry" is specified, determine the path from the registry. '
'Default: %(default)s'))
parser.set_defaults(callback=_callback)
def _add_prubin(subparsers):

View File

@@ -6,6 +6,7 @@
"""Common code and constants"""
import enum
import os
import logging
import platform
@@ -24,6 +25,8 @@ BUILDSPACE_TREE = 'buildspace/tree'
BUILDSPACE_TREE_PACKAGING = 'buildspace/tree/ungoogled_packaging'
BUILDSPACE_USER_BUNDLE = 'buildspace/user_bundle'
SEVENZIP_USE_REGISTRY = '_use_registry'
_ENV_FORMAT = "BUILDKIT_{}"
# Public classes
@@ -38,6 +41,16 @@ class BuildkitAbort(BuildkitError):
It should only be caught by the user of buildkit's library interface.
"""
class PlatformEnum(enum.Enum):
"""Enum for platforms that need distinction for certain functionality"""
UNIX = 'unix' # Currently covers anything that isn't Windows
WINDOWS = 'windows'
class ExtractorEnum: #pylint: disable=too-few-public-methods
"""Enum for extraction binaries"""
SEVENZIP = '7z'
TAR = 'tar'
# Public methods
def get_logger(name=__package__, initial_level=logging.DEBUG):
@@ -107,11 +120,16 @@ def ensure_empty_dir(path, parents=False):
if not dir_empty(path):
raise exc
def is_windows_platform():
def get_running_platform():
"""
Returns True if we are running on a Windows platform, either natively or
inside WSL/MSYS2
Returns a PlatformEnum value indicating the platform that buildkit is running on.
NOTE: Platform detection should only be used when no cross-platform alternative is available.
"""
uname = platform.uname()
# detect native python and WSL
return uname.system == 'Windows' or 'Microsoft' in uname.release
if uname.system == 'Windows' or 'Microsoft' in uname.release:
return PlatformEnum.WINDOWS
else:
# Only Windows and UNIX-based platforms need to be distinguished right now.
return PlatformEnum.UNIX

View File

@@ -18,7 +18,7 @@ import shutil
from pathlib import Path
from .common import (
ENCODING, CONFIG_BUNDLES_DIR, BuildkitAbort,
ENCODING, CONFIG_BUNDLES_DIR, BuildkitAbort, ExtractorEnum,
get_logger, get_resources_dir, ensure_empty_dir)
from .third_party import schema
@@ -619,13 +619,14 @@ class ExtraDepsIni(IniConfigFile):
_hashes = ('md5', 'sha1', 'sha256', 'sha512')
_required_keys = ('version', 'url', 'download_name')
_optional_keys = ('strip_leading_dirs','extractor')
_passthrough_properties = (*_required_keys, *_optional_keys)
_optional_keys = ('strip_leading_dirs')
_passthrough_properties = (*_required_keys, *_optional_keys, 'extractor')
_schema = schema.Schema(schema_inisections({
schema.Optional(schema.And(str, len)): schema_dictcast({
**{x: schema.And(str, len) for x in _required_keys},
**{schema.Optional(x): schema.And(str, len) for x in _optional_keys},
schema.Optional('extractor'): schema.Or(ExtractorEnum.TAR, ExtractorEnum.SEVENZIP),
schema.Or(*_hashes): schema.And(str, len),
})
}))

View File

@@ -14,7 +14,22 @@ import subprocess
import tarfile
from pathlib import Path, PurePosixPath
from .common import ENCODING, BuildkitAbort, get_logger, ensure_empty_dir, is_windows_platform
from .common import (
SEVENZIP_USE_REGISTRY, BuildkitAbort, PlatformEnum, ExtractorEnum, get_logger,
get_running_platform)
DEFAULT_EXTRACTORS = {
ExtractorEnum.SEVENZIP: SEVENZIP_USE_REGISTRY,
ExtractorEnum.TAR: 'tar',
}
def _find_extractor_binary(extractor_cmd):
"""Returns a string path to the binary; None if it couldn't be found"""
if not extractor_cmd:
return None
if Path(extractor_cmd).is_file():
return extractor_cmd
return shutil.which(extractor_cmd)
def _process_relative_to(unpack_root, relative_to):
"""
@@ -23,7 +38,9 @@ def _process_relative_to(unpack_root, relative_to):
"""
relative_root = unpack_root / relative_to
if not relative_root.is_dir():
raise Exception('Could not find relative_to directory in extracted files: {}', relative_to)
get_logger().error(
'Could not find relative_to directory in extracted files: %s', relative_to)
raise BuildkitAbort()
for src_path in relative_root.iterdir():
dest_path = unpack_root / src_path.name
src_path.rename(dest_path)
@@ -33,56 +50,65 @@ def _prune_tree(unpack_root, ignore_files):
"""
Run through the list of pruned files, delete them, and remove them from the set
"""
deleted_files = []
deleted_files = set()
for relative_file in ignore_files:
file = unpack_root / relative_file
if not file.is_file():
file_path = unpack_root / relative_file
if not file_path.is_file():
continue
file.unlink()
deleted_files.append((Path(relative_file).as_posix()))
for d in deleted_files:
ignore_files.remove(d)
file_path.unlink()
deleted_files.add(Path(relative_file).as_posix())
for deleted_path in deleted_files:
ignore_files.remove(deleted_path)
def _extract_tar_file_7z(binary, tar_path, buildspace_tree, unpack_dir, ignore_files, relative_to):
def _extract_tar_with_7z(binary, archive_path, buildspace_tree, unpack_dir, ignore_files, #pylint: disable=too-many-arguments
relative_to):
get_logger().debug('Using 7-zip extractor')
out_dir = buildspace_tree / unpack_dir
cmd1 = [binary, 'x', str(tar_path), '-so']
cmd2 = [binary, 'x', '-si', '-aoa', '-ttar', '-o{}'.format(str(out_dir))]
cmdline = '{} | {}'.format(' '.join(cmd1), ' '.join(cmd2))
get_logger().debug("7z command line: {}".format(cmdline))
if not relative_to is None and (out_dir / relative_to).exists():
get_logger().error(
'Temporary unpacking directory already exists: %s', out_dir / relative_to)
raise BuildkitAbort()
cmd1 = (binary, 'x', str(archive_path), '-so')
cmd2 = (binary, 'x', '-si', '-aoa', '-ttar', '-o{}'.format(str(out_dir)))
get_logger().debug('7z command line: %s | %s',
' '.join(cmd1), ' '.join(cmd2))
p1 = subprocess.Popen(cmd1, stdout=subprocess.PIPE)
p2 = subprocess.Popen(cmd2, stdin=p1.stdout, stdout=subprocess.PIPE)
p1.stdout.close()
(stdout_data, stderr_data) = p2.communicate()
if p2.returncode != 0:
get_logger().debug('stdout: {}'.format(stdout_data))
get_logger().debug('stderr: {}'.format(stderr_data))
raise Exception('7z commands returned non-zero status: {}'.format(p2.returncode))
proc1 = subprocess.Popen(cmd1, stdout=subprocess.PIPE)
proc2 = subprocess.Popen(cmd2, stdin=proc1.stdout, stdout=subprocess.PIPE)
proc1.stdout.close()
(stdout_data, stderr_data) = proc2.communicate()
if proc2.returncode != 0:
get_logger().error('7z commands returned non-zero status: %s', proc2.returncode)
get_logger().debug('stdout: %s', stdout_data)
get_logger().debug('stderr: %s', stderr_data)
raise BuildkitAbort()
if relative_to is not None:
if not relative_to is None:
_process_relative_to(out_dir, relative_to)
_prune_tree(out_dir, ignore_files)
def _extract_tar_file_tar(binary, tar_path, buildspace_tree, unpack_dir, ignore_files, relative_to):
def _extract_tar_with_tar(binary, archive_path, buildspace_tree, unpack_dir, #pylint: disable=too-many-arguments
ignore_files, relative_to):
get_logger().debug('Using BSD or GNU tar extractor')
out_dir = buildspace_tree / unpack_dir
out_dir.mkdir(exist_ok=True)
cmd = [binary, '-xf', str(tar_path), '-C', str(out_dir)]
cmdline = ' '.join(cmd)
get_logger().debug("tar command line: {}".format(cmdline))
cmd = (binary, '-xf', str(archive_path), '-C', str(out_dir))
get_logger().debug('tar command line: %s', ' '.join(cmd))
result = subprocess.run(cmd)
if result.returncode != 0:
raise Exception('tar command returned {}'.format(result.returncode))
get_logger().error('tar command returned %s', result.returncode)
raise BuildkitAbort()
# for gnu tar, the --transform option could be used. but to keep compatibility with
# bsdtar on macos, we just do this ourselves
if relative_to is not None:
if not relative_to is None:
_process_relative_to(out_dir, relative_to)
_prune_tree(out_dir, ignore_files)
def _extract_tar_file_python(tar_path, buildspace_tree, unpack_dir, ignore_files, relative_to):
def _extract_tar_with_python(archive_path, buildspace_tree, unpack_dir, ignore_files, relative_to):
get_logger().debug('Using pure Python tar extractor')
class NoAppendList(list):
"""Hack to workaround memory issues with large tar files"""
def append(self, obj):
@@ -103,7 +129,7 @@ def _extract_tar_file_python(tar_path, buildspace_tree, unpack_dir, ignore_files
get_logger().exception('Unexpected exception during symlink support check.')
raise BuildkitAbort()
with tarfile.open(str(tar_path)) as tar_file_obj:
with tarfile.open(str(archive_path)) as tar_file_obj:
tar_file_obj.members = NoAppendList()
for tarinfo in tar_file_obj:
try:
@@ -134,11 +160,12 @@ def _extract_tar_file_python(tar_path, buildspace_tree, unpack_dir, ignore_files
get_logger().exception('Exception thrown for tar member: %s', tarinfo.name)
raise BuildkitAbort()
def extract_tar_file(tar_path, buildspace_tree, unpack_dir, ignore_files, relative_to, user_binaries):
def extract_tar_file(archive_path, buildspace_tree, unpack_dir, ignore_files, relative_to, #pylint: disable=too-many-arguments
extractors=None):
"""
One-time tar extraction function
Extract regular or compressed tar archive into the buildspace tree.
tar_path is the pathlib.Path to the archive to unpack
archive_path is the pathlib.Path to the archive to unpack
buildspace_tree is a pathlib.Path to the buildspace tree.
unpack_dir is a pathlib.Path relative to buildspace_tree to unpack the archive.
It must already exist.
@@ -147,56 +174,90 @@ def extract_tar_file(tar_path, buildspace_tree, unpack_dir, ignore_files, relati
Files that have been ignored are removed from the set.
relative_to is a pathlib.Path for directories that should be stripped relative to the
root of the archive.
user_binaries is a dict of user-provided utility binaries, if available
extractors is a dictionary of PlatformEnum to a command or path to the
extractor binary. Defaults to 'tar' for tar, and '_use_registry' for 7-Zip.
Raises BuildkitAbort if unexpected issues arise during unpacking.
"""
def lookup_binary(name):
return user_binaries.get(name) or shutil.which(name)
tar_bin = lookup_binary('tar')
sevenz_bin = lookup_binary('7z')
resolved_tree = buildspace_tree.resolve()
common_args = [tar_path, resolved_tree, unpack_dir, ignore_files, relative_to]
if extractors is None:
extractors = DEFAULT_EXTRACTORS
if is_windows_platform():
if sevenz_bin is not None:
_extract_tar_file_7z(sevenz_bin, *common_args)
else:
get_logger().info('7z.exe not found. Using built-in Python extractor')
_extract_tar_file_python(*common_args)
current_platform = get_running_platform()
if current_platform == PlatformEnum.WINDOWS:
# TODO: Add option to get 7z.exe path from registry at path
# "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\7zFM.exe"
sevenzip_cmd = extractors.get(ExtractorEnum.SEVENZIP)
if sevenzip_cmd == SEVENZIP_USE_REGISTRY:
raise NotImplementedError()
sevenzip_bin = _find_extractor_binary(sevenzip_cmd)
if not sevenzip_bin is None:
_extract_tar_with_7z(
binary=sevenzip_bin, archive_path=archive_path, buildspace_tree=resolved_tree,
unpack_dir=unpack_dir, ignore_files=ignore_files, relative_to=relative_to)
return
elif current_platform == PlatformEnum.UNIX:
# NOTE: 7-zip isn't an option because it doesn't preserve file permissions
tar_bin = _find_extractor_binary(extractors.get(ExtractorEnum.TAR))
if not tar_bin is None:
_extract_tar_with_tar(
binary=tar_bin, archive_path=archive_path, buildspace_tree=resolved_tree,
unpack_dir=unpack_dir, ignore_files=ignore_files, relative_to=relative_to)
return
else:
if tar_bin is not None:
_extract_tar_file_tar(tar_bin, *common_args)
else:
# we dont try 7z on unix because it doesnt preserve file permissions
get_logger().info('tar command not found. Using built-in Python extractor')
_extract_tar_file_python(*common_args)
def extract_7z_file(tar_path, buildspace_tree, unpack_dir, ignore_files, relative_to, user_binaries):
# This is not a normal code path, so make it clear.
raise NotImplementedError(current_platform)
# Fallback to Python-based extractor on all platforms
_extract_tar_with_python(
archive_path=archive_path, buildspace_tree=resolved_tree, unpack_dir=unpack_dir,
ignore_files=ignore_files, relative_to=relative_to)
def extract_with_7z(archive_path, buildspace_tree, unpack_dir, ignore_files, relative_to, #pylint: disable=too-many-arguments
extractors=None):
"""
One-time 7zip extraction function
(Windows only) Extract archives with 7-zip into the buildspace tree.
Only supports archives with one layer of unpacking, unlike compressed tar archives.
Same arguments as extract_tar_file
archive_path is the pathlib.Path to the archive to unpack
buildspace_tree is a pathlib.Path to the buildspace tree.
unpack_dir is a pathlib.Path relative to buildspace_tree to unpack the archive.
It must already exist.
ignore_files is a set of paths as strings that should not be extracted from the archive.
Files that have been ignored are removed from the set.
relative_to is a pathlib.Path for directories that should be stripped relative to the
root of the archive.
extractors is a dictionary of PlatformEnum to a command or path to the
extractor binary. Defaults to 'tar' for tar, and '_use_registry' for 7-Zip.
Raises BuildkitAbort if unexpected issues arise during unpacking.
"""
sevenz_bin = user_binaries.get('7z') or shutil.which('7z')
if sevenz_bin is None:
raise Exception('Unable to locate 7z binary')
# TODO: Add option to get 7z.exe path from registry at path
# "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\7zFM.exe"
# TODO: It would be nice to extend this to support arbitrary standard IO chaining of 7z
# instances, so _extract_tar_with_7z and other future formats could use this.
if extractors is None:
extractors = DEFAULT_EXTRACTORS
sevenzip_cmd = extractors.get(ExtractorEnum.SEVENZIP)
if sevenzip_cmd == SEVENZIP_USE_REGISTRY:
raise NotImplementedError()
sevenzip_bin = _find_extractor_binary(sevenzip_cmd)
resolved_tree = buildspace_tree.resolve()
common_args = [tar_path, resolved_tree, unpack_dir, ignore_files, relative_to]
out_dir = resolved_tree / unpack_dir
cmd = [sevenz_bin, 'x', str(tar_path), '-aoa', '-o{}'.format(str(out_dir))]
cmdline = ' '.join(cmd)
get_logger().debug("7z command line: {}".format(cmdline))
if not relative_to is None and (out_dir / relative_to).exists():
get_logger().error(
'Temporary unpacking directory already exists: %s', out_dir / relative_to)
raise BuildkitAbort()
cmd = (sevenzip_bin, 'x', str(archive_path), '-aoa', '-o{}'.format(str(out_dir)))
get_logger().debug('7z command line: %s', ' '.join(cmd))
result = subprocess.run(cmd)
if result.returncode != 0:
raise Exception('7z command returned {}'.format(result.returncode))
get_logger().error('7z command returned %s', result.returncode)
raise BuildkitAbort()
if relative_to is not None:
if not relative_to is None:
_process_relative_to(out_dir, relative_to)
_prune_tree(out_dir, ignore_files)

View File

@@ -8,14 +8,13 @@
Module for the downloading, checking, and unpacking of necessary files into the buildspace tree
"""
import os
import tarfile
import urllib.request
import hashlib
from pathlib import Path, PurePosixPath
from pathlib import Path
from .common import ENCODING, BuildkitAbort, get_logger, ensure_empty_dir
from .extractors import extract_tar_file, extract_7z_file
from .common import (
ENCODING, ExtractorEnum, get_logger, ensure_empty_dir)
from .extractors import extract_tar_file, extract_with_7z
# Constants
@@ -83,14 +82,16 @@ def _chromium_hashes_generator(hashes_path):
else:
get_logger().warning('Skipping unknown hash algorithm: %s', hash_name)
def _setup_chromium_source(config_bundle, buildspace_downloads, buildspace_tree,
show_progress, pruning_set, user_binaries):
def _setup_chromium_source(config_bundle, buildspace_downloads, buildspace_tree, #pylint: disable=too-many-arguments
show_progress, pruning_set, extractors=None):
"""
Download, check, and extract the Chromium source code into the buildspace tree.
Arguments of the same name are shared with retreive_and_extract().
pruning_set is a set of files to be pruned. Only the files that are ignored during
extraction are removed from the set.
extractors is a dictionary of PlatformEnum to a command or path to the
extractor binary. Defaults to 'tar' for tar, and '_use_registry' for 7-Zip.
Raises source_retrieval.HashMismatchError when the computed and expected hashes do not match.
Raises source_retrieval.NotAFileError when the archive name exists but is not a file.
@@ -123,18 +124,22 @@ def _setup_chromium_source(config_bundle, buildspace_downloads, buildspace_tree,
if not hasher.hexdigest().lower() == hash_hex.lower():
raise HashMismatchError(source_archive)
get_logger().info('Extracting archive...')
extract_tar_file(source_archive, buildspace_tree, Path(), pruning_set,
Path('chromium-{}'.format(config_bundle.version.chromium_version)),
user_binaries)
extract_tar_file(
archive_path=source_archive, buildspace_tree=buildspace_tree, unpack_dir=Path(),
ignore_files=pruning_set,
relative_to=Path('chromium-{}'.format(config_bundle.version.chromium_version)),
extractors=extractors)
def _setup_extra_deps(config_bundle, buildspace_downloads, buildspace_tree, show_progress,
pruning_set, user_binaries):
def _setup_extra_deps(config_bundle, buildspace_downloads, buildspace_tree, show_progress, #pylint: disable=too-many-arguments,too-many-locals
pruning_set, extractors=None):
"""
Download, check, and extract extra dependencies into the buildspace tree.
Arguments of the same name are shared with retreive_and_extract().
pruning_set is a set of files to be pruned. Only the files that are ignored during
extraction are removed from the set.
extractors is a dictionary of PlatformEnum to a command or path to the
extractor binary. Defaults to 'tar' for tar, and '_use_registry' for 7-Zip.
Raises source_retrieval.HashMismatchError when the computed and expected hashes do not match.
Raises source_retrieval.NotAFileError when the archive name exists but is not a file.
@@ -154,30 +159,35 @@ def _setup_extra_deps(config_bundle, buildspace_downloads, buildspace_tree, show
if not hasher.hexdigest().lower() == hash_hex.lower():
raise HashMismatchError(dep_archive)
get_logger().info('Extracting archive...')
extractors = {'7z': extract_7z_file, 'tar': extract_tar_file}
extractor_name = dep_properties.extractor or 'tar'
extractor_fn = extractors.get(extractor_name)
if extractor_fn is None:
raise Exception('Unknown extractor: {}. Supported values: {}'
.format(extractor_name, [k for k in extractors.keys()]))
extractor_name = dep_properties.extractor or ExtractorEnum.TAR
if extractor_name == ExtractorEnum.SEVENZIP:
extractor_func = extract_with_7z
elif extractor_name == ExtractorEnum.TAR:
extractor_func = extract_tar_file
else:
# This is not a normal code path
raise NotImplementedError(extractor_name)
if dep_properties.strip_leading_dirs is None:
strip_leading_dirs_path = None
else:
strip_leading_dirs_path = Path(dep_properties.strip_leading_dirs)
extractor_fn(dep_archive, buildspace_tree, Path(dep_name), pruning_set,
strip_leading_dirs_path, user_binaries)
extractor_func(
archive_path=dep_archive, buildspace_tree=buildspace_tree,
unpack_dir=Path(dep_name), ignore_files=pruning_set,
relative_to=strip_leading_dirs_path, extractors=extractors)
def retrieve_and_extract(config_bundle, buildspace_downloads, buildspace_tree,
prune_binaries=True, show_progress=True, user_binaries={}):
def retrieve_and_extract(config_bundle, buildspace_downloads, buildspace_tree, #pylint: disable=too-many-arguments
prune_binaries=True, show_progress=True, extractors=None):
"""
Downloads, checks, and unpacks the Chromium source code and extra dependencies
defined in the config bundle into the buildspace tree.
Currently for extra dependencies, only compressed tar files are supported.
buildspace_downloads is the path to the buildspace downloads directory, and
buildspace_tree is the path to the buildspace tree.
extractors is a dictionary of PlatformEnum to a command or path to the
extractor binary. Defaults to 'tar' for tar, and '_use_registry' for 7-Zip.
Raises FileExistsError when the buildspace tree already exists and is not empty
Raises FileNotFoundError when buildspace/downloads does not exist or through
@@ -197,10 +207,14 @@ def retrieve_and_extract(config_bundle, buildspace_downloads, buildspace_tree,
remaining_files = set(config_bundle.pruning)
else:
remaining_files = set()
_setup_chromium_source(config_bundle, buildspace_downloads, buildspace_tree, show_progress,
remaining_files, user_binaries)
_setup_extra_deps(config_bundle, buildspace_downloads, buildspace_tree, show_progress,
remaining_files, user_binaries)
_setup_chromium_source(
config_bundle=config_bundle, buildspace_downloads=buildspace_downloads,
buildspace_tree=buildspace_tree, show_progress=show_progress,
pruning_set=remaining_files, extractors=extractors)
_setup_extra_deps(
config_bundle=config_bundle, buildspace_downloads=buildspace_downloads,
buildspace_tree=buildspace_tree, show_progress=show_progress,
pruning_set=remaining_files, extractors=extractors)
if remaining_files:
logger = get_logger()
for path in remaining_files: