Skip to content

Commit

Permalink
Add skip-excluded-dirs build option
Browse files Browse the repository at this point in the history
  • Loading branch information
ofek committed May 15, 2022
1 parent 21d7b29 commit 699f50b
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 7 deletions.
21 changes: 21 additions & 0 deletions backend/src/hatchling/builders/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def __init__(self, builder, root, plugin_name, build_config, target_config):

# Common options
self.__directory = None
self.__skip_excluded_dirs = None
self.__ignore_vcs = None
self.__only_packages = None
self.__reproducible = None
Expand Down Expand Up @@ -270,6 +271,26 @@ def directory(self):

return self.__directory

@property
def skip_excluded_dirs(self):
if self.__skip_excluded_dirs is None:
if 'skip-excluded-dirs' in self.target_config:
skip_excluded_dirs = self.target_config['skip-excluded-dirs']
if not isinstance(skip_excluded_dirs, bool):
raise TypeError(
'Field `tool.hatch.build.targets.{}.skip-excluded-dirs` must be a boolean'.format(
self.plugin_name
)
)
else:
skip_excluded_dirs = self.build_config.get('skip-excluded-dirs', False)
if not isinstance(skip_excluded_dirs, bool):
raise TypeError('Field `tool.hatch.build.skip-excluded-dirs` must be a boolean')

self.__skip_excluded_dirs = skip_excluded_dirs

return self.__skip_excluded_dirs

@property
def ignore_vcs(self):
if self.__ignore_vcs is None:
Expand Down
17 changes: 10 additions & 7 deletions backend/src/hatchling/builders/plugin/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,14 +178,17 @@ def recurse_project_files(self):
if relative_path == '.':
relative_path = ''

dirs[:] = sorted(
d
for d in dirs
# The trailing slash is necessary so e.g. `bar/` matches `foo/bar`
if not self.config.path_is_excluded('{}/'.format(os.path.join(relative_path, d)))
)
if self.config.skip_excluded_dirs:
dirs[:] = sorted(
d
for d in dirs
# The trailing slash is necessary so e.g. `bar/` matches `foo/bar`
if not self.config.path_is_excluded('{}/'.format(os.path.join(relative_path, d)))
)
else:
dirs.sort()

files = sorted(files)
files.sort()
is_package = '__init__.py' in files
for f in files:
relative_file_path = os.path.join(relative_path, f)
Expand Down
21 changes: 21 additions & 0 deletions docs/config/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,27 @@ The [packages](#packages) option itself relies on sources. Defining `#!toml pack
sources = ["src"]
```

### Performance

All encountered directories are traversed by default. To skip non-[artifact](#artifacts) directories that are excluded, set `skip-excluded-dirs` to `true`:

=== ":octicons-file-code-16: pyproject.toml"

```toml
[tool.hatch.build]
skip-excluded-dirs = true
```

=== ":octicons-file-code-16: hatch.toml"

```toml
[build]
skip-excluded-dirs = true
```

!!! warning
This may result in not shipping desired files. For example, if you want to include the file `a/b/c.txt` but your [VCS ignores](#vcs) `a/b`, the file `c.txt` will not be seen because its parent directory will not be entered. In such cases you can use the [`force-include`](#explicit-selection) option.

## Reproducible builds

By default, [build targets](#build-targets) will build in a reproducible manner provided that they support that behavior. To disable this, set `reproducible` to `false`:
Expand Down
2 changes: 2 additions & 0 deletions docs/history.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,15 @@ This is the first stable release of Hatch v1, a complete rewrite. Enjoy!

***Added:***

- Add `skip-excluded-dirs` build option
- Allow build data to add additional project dependencies for `wheel` and `sdist` build targets
- Add `force_include_editable` build data for the `wheel` build target
- Update project metadata to reflect the adoption by PyPA

***Fixed:***

- Properly use underscores for the name of `force_include` build data
- No longer greedily skip excluded directories by default

### [0.24.0](https://github.com/pypa/hatch/releases/tag/hatchling-v0.24.0) - 2022-04-28 ### {: #hatchling-v0.24.0 }

Expand Down
6 changes: 6 additions & 0 deletions hatch.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ post-install-commands = [
full = "pytest -n auto --reruns 5 --reruns-delay 1 -r aR --cov-report=term-missing --cov-config=pyproject.toml --cov=src/hatch --cov=backend/src/hatchling --cov=tests {args:tests}"
dev = "pytest -p no:randomly --no-cov {args:tests}"

[envs.test.overrides]
env.HERMETIC_TESTS.type = [
{ value = "container", if = ["true"] },
"virtual",
]

[[envs.test.matrix]]
python = ["37", "38", "39", "310"]

Expand Down
50 changes: 50 additions & 0 deletions tests/backend/builders/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,56 @@ def test_absolute_path(self, isolation):
assert builder.config.directory == absolute_path


class TestSkipExcludedDirs:
def test_default(self, isolation):
builder = BuilderInterface(str(isolation))

assert builder.config.skip_excluded_dirs is builder.config.skip_excluded_dirs is False

def test_target(self, isolation):
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'skip-excluded-dirs': True}}}}}}
builder = BuilderInterface(str(isolation), config=config)
builder.PLUGIN_NAME = 'foo'

assert builder.config.skip_excluded_dirs is True

def test_target_not_boolean(self, isolation):
config = {'tool': {'hatch': {'build': {'targets': {'foo': {'skip-excluded-dirs': 9000}}}}}}
builder = BuilderInterface(str(isolation), config=config)
builder.PLUGIN_NAME = 'foo'

with pytest.raises(
TypeError, match='Field `tool.hatch.build.targets.foo.skip-excluded-dirs` must be a boolean'
):
_ = builder.config.skip_excluded_dirs

def test_global(self, isolation):
config = {'tool': {'hatch': {'build': {'skip-excluded-dirs': True}}}}
builder = BuilderInterface(str(isolation), config=config)
builder.PLUGIN_NAME = 'foo'

assert builder.config.skip_excluded_dirs is True

def test_global_not_boolean(self, isolation):
config = {'tool': {'hatch': {'build': {'skip-excluded-dirs': 9000}}}}
builder = BuilderInterface(str(isolation), config=config)
builder.PLUGIN_NAME = 'foo'

with pytest.raises(TypeError, match='Field `tool.hatch.build.skip-excluded-dirs` must be a boolean'):
_ = builder.config.skip_excluded_dirs

def test_target_overrides_global(self, isolation):
config = {
'tool': {
'hatch': {'build': {'skip-excluded-dirs': True, 'targets': {'foo': {'skip-excluded-dirs': False}}}}
}
}
builder = BuilderInterface(str(isolation), config=config)
builder.PLUGIN_NAME = 'foo'

assert builder.config.skip_excluded_dirs is False


class TestIgnoreVCS:
def test_default(self, isolation):
builder = BuilderInterface(str(isolation))
Expand Down

0 comments on commit 699f50b

Please sign in to comment.