Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Zsh style *** #225

Merged
merged 6 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/src/dictionary/en-custom.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ preprocessing
preprocessors
prerelease
prereleases
recurse
recursing
regex
sharepoint
Expand Down
6 changes: 5 additions & 1 deletion docs/src/markdown/about/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@

## 10.0

- **NEW**: Added `GLOBSTARLONG` which adds support for the Zsh style `***` which acts like `**` with `GLOBSTAR` but
but traverses symlinks.
- **NEW**: `pathlib.match` will respect symlinks (when the `REALPATH` flag is given) and hidden file rules (enable
`DOTALL` to match hidden files).
- **NEW**: Symlinks should not be traversed when `GLOBSTAR` is enabled unless `FOLLOW` is also enabled, but they
should still be matched. Prior to this change, symlinks were not traversed _and_ they were ignored from matching
which contradicts how Bash works, which is are general target.
which contradicts how Bash works and could be confusing to users.
- **FIX**: Fix some inconsistencies with `globmatch` and symlink handling when `REALPATH` is enabled.

## 9.0
Expand Down
23 changes: 22 additions & 1 deletion docs/src/markdown/glob.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ character `#!py3 r'\?'`. If you want to represent a literal backslash, you must
Pattern | Meaning
----------------- | -------
`*` | Matches everything except slashes. On Windows it will avoid matching backslashes as well as slashes.
`**` | Matches zero or more directories, but will never match the directories `.` and `..`. Requires the [`GLOBSTAR`](#globstar) flag.
`**` | Matches zero or more directories, but will never match the directories ` . ` and `..`. Requires the [`GLOBSTAR`](#globstar) flag.
`***` | Like `**` but will also recurse symlinks. Requires the [`GLOBSTARLONG`](#globstarlong) flag.
`?` | Matches any single character.
`[seq]` | Matches any character in seq.
`[!seq]` | Matches any character not in seq. Will also accept character exclusions in the form of `[^seq]`.
Expand Down Expand Up @@ -766,10 +767,27 @@ When `MINUSNEGATE` is used with [`NEGATE`](#negate), exclusion patterns are reco

`GLOBSTAR` enables the feature where `**` matches zero or more directories.

#### `glob.GLOBSTARLONG, glob.GL` {: #globstarlong}

/// new | New 10.0
///

When `GLOBSTARLONG` is enabled `***` will act like `**`, but will cause symlinks to be traversed as well.

Enabling `GLOBSTARLONG` automatically enables [`GLOBSTAR`](#globstar).

[`FOLLOW`](#follow) will be ignored and `***` will be required to traverse a symlink. But it should be noted that when
using [`MATCHBASE`](#matchbase) and [`FOLLOW`](#follow) with `GLOBSTARLONG`, that [`FOLLOW`](#follow) will cause the
implicit leading `**` that [`MATCHBASE`](#matchbase) applies to act as an implicit `***`.

#### `glob.FOLLOW, glob.L` {: #follow}

`FOLLOW` will cause [`GLOBSTAR`](#globstar) patterns (`**`) to traverse symlink directories.

`FOLLOW` will have no affect if using [`GLOBSTARLONG`](#globstarlong) and an explicit `***` will be required to traverse
a symlink. `FOLLOW` will have an affect if enabled with [`GLOBSTARLONG`](#globstarlong) and [`MATCHBASE`](#matchbase)
and will cause the implicit leading `**` that `MATCHBASE` applies to act as an implicit `***`.

#### `glob.REALPATH, glob.P` {: #realpath}

In the past, only [`glob`](#glob) and [`iglob`](#iglob) operated on the filesystem, but with `REALPATH`, other
Expand All @@ -786,6 +804,9 @@ logic so that the path must meet the following in order to match:
- Path must exist.
- Directories that are symlinks will not be traversed by [`GLOBSTAR`](#globstar) patterns (`**`) unless the
[`FOLLOW`](#follow) flag is enabled.
- If [`GLOBSTARLONG`](#globstarlong) is enabled, `***` will traverse symlinks, [`FOLLOW`](#follow) will be ignored
except if [`MATCHBASE`](#matchbase) is also enabled, in that case, the implicit leading `**` added by
[`MATCHBASE`](#matchbase) will act as `***`.
- When presented with a pattern where the match must be a directory, but the file path being compared doesn't indicate
the file is a directory with a trailing slash, the command will look at the filesystem to determine if it is a
directory.
Expand Down
54 changes: 39 additions & 15 deletions docs/src/markdown/pathlib.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,22 +252,12 @@ pattern(s).

`match` mimics Python's `pathlib` version of `match`. Python's `match` uses a right to left evaluation. Wildcard Match
emulates this behavior as well. What this means is that when provided with a path `some/path/name`, the patterns `name`,
`path/name` and `some/path/name` will all match.

Because the path is evaluated right to left, dot files may not prevent matches when `DOTGLOB` is disabled.

```pycon3
>>> from wcmatch import pathlib
>>> pathlib.PurePath('.dotfile/file').match('file')
True
>>> pathlib.PurePath('../.dotfile/file').match('file')
True
```
`path/name` and `some/path/name` will all match. Essentially, it matches what [`rglob`](#rglob) returns.

`match` does not access the filesystem, but you can force the path to access the filesystem if you give it the
[`REALPATH`](#realpath) flag. We do not restrict this, but we do not enable it by default.
[`REALPATH`](#realpath) simply forces the match to check the filesystem to see if the file exists and is a
directory or not.
[`REALPATH`](#realpath) simply forces the match to check the filesystem to see if the file exists, if it is a
directory or not, and whether it is a symlink.

Since [`Path`](#path) is derived from [`PurePath`](#purepath), this method is also available in
[`Path`](#path) objects.
Expand Down Expand Up @@ -302,8 +292,8 @@ a list of patterns. It will return a boolean indicating whether the objects file

`globmatch` does not access the filesystem, but you can force the path to access the filesystem if you give it the
[`REALPATH`](#realpath) flag. We do not restrict this, but we do not enable it by default.
[`REALPATH`](#realpath) simply forces the match to check the filesystem to see if the file exists and is a
directory or not.
[`REALPATH`](#realpath) simply forces the match to check the filesystem to see if the file exists, if it is a
directory or not, and whether it is a symlink.

Since [`Path`](#path) is derived from [`PurePath`](#purepath), this method is also available in
[`Path`](#path) objects.
Expand All @@ -323,6 +313,19 @@ True
`exclude` parameter was added.
///

#### `PurePath.full_match` {: #full_match}

/// new | new 10.0
///

```py3
def full_match(self, patterns, *, flags=0, limit=1000, exclude=None):
```

Python 3.13 added the new `full_match` method to `PurePath` objects. Essentially, this does for normal `pathlib`
what our existing `PurePath.globmatch` has been doing prior to Python 3.13. We've added an alias for
`PurePath.full_match` that redirects to [`PurePath.globmatch`](#globmatch) for completeness.

#### `Path.glob` {: #glob}

```py3
Expand Down Expand Up @@ -446,10 +449,27 @@ When `MINUSNEGATE` is used with [`NEGATE`](#negate), exclusion patterns are reco

`GLOBSTAR` enables the feature where `**` matches zero or more directories.

#### `glob.GLOBSTARLONG, glob.GL` {: #globstarlong}

/// new | New 10.0
///

When `GLOBSTARLONG` is enabled `***` will act like `**`, but will cause symlinks to be traversed as well.

Enabling `GLOBSTARLONG` automatically enables [`GLOBSTAR`](#globstar).

[`FOLLOW`](#follow) will be ignored and `***` will be required to traverse a symlink. But it should be noted that when
using [`MATCHBASE`](#matchbase) and [`FOLLOW`](#follow) with `GLOBSTARLONG`, that [`FOLLOW`](#follow) will cause the
implicit leading `**` that [`MATCHBASE`](#matchbase) applies to act as an implicit `***`.

#### `pathlib.FOLLOW, pathlib.L` {: #follow}

`FOLLOW` will cause `GLOBSTAR` patterns (`**`) to match and traverse symlink directories.

`FOLLOW` will have no affect if using [`GLOBSTARLONG`](#globstarlong) and an explicit `***` will be required to traverse
a symlink. `FOLLOW` will have an affect if enabled with [`GLOBSTARLONG`](#globstarlong) and [`MATCHBASE`](#matchbase)
and will cause the implicit leading `**` that `MATCHBASE` applies to act as an implicit `***`.

#### `pathlib.REALPATH, pathlib.P` {: #realpath}

In the past, only `glob` and `iglob` operated on the filesystem, but with `REALPATH`, other functions will now operate
Expand All @@ -466,6 +486,10 @@ that the path must meet the following in order to match:
- Path must exist.
- Directories that are symlinks will not be matched by [`GLOBSTAR`](#globstar) patterns (`**`) unless the
[`FOLLOW`](#follow) flag is enabled.
- If [`GLOBSTARLONG`](#globstarlong) is enabled, `***` will traverse symlinks, [`FOLLOW`](#follow) will be ignored
except if [`MATCHBASE`](#matchbase) is also enabled, in that case, the implicit leading `**` added by
[`MATCHBASE`](#matchbase) will act as `***`. This also affects the implicit leading `**` adding by
[`rglob`](#rglob).
- When presented with a pattern where the match must be a directory, but the file path being compared doesn't indicate
the file is a directory with a trailing slash, the command will look at the filesystem to determine if it is a
directory.
Expand Down
Loading
Loading