pseek 3.1.1__tar.gz → 3.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pseek-3.1.1 → pseek-3.2.0}/PKG-INFO +66 -11
- {pseek-3.1.1 → pseek-3.2.0}/README.md +65 -10
- {pseek-3.1.1 → pseek-3.2.0}/pseek/archive.py +55 -34
- {pseek-3.1.1 → pseek-3.2.0}/pseek/cli.py +102 -39
- {pseek-3.1.1 → pseek-3.2.0}/pseek/parser.py +0 -2
- pseek-3.2.0/pseek/searcher.py +408 -0
- {pseek-3.1.1 → pseek-3.2.0}/pseek/structs.py +92 -46
- pseek-3.2.0/pseek/utils.py +44 -0
- {pseek-3.1.1 → pseek-3.2.0}/pseek.egg-info/PKG-INFO +66 -11
- {pseek-3.1.1 → pseek-3.2.0}/pyproject.toml +1 -1
- pseek-3.1.1/pseek/searcher.py +0 -304
- pseek-3.1.1/pseek/utils.py +0 -104
- {pseek-3.1.1 → pseek-3.2.0}/LICENSE +0 -0
- {pseek-3.1.1 → pseek-3.2.0}/pseek/__init__.py +0 -0
- {pseek-3.1.1 → pseek-3.2.0}/pseek/compound_extensions +0 -0
- {pseek-3.1.1 → pseek-3.2.0}/pseek.egg-info/SOURCES.txt +0 -0
- {pseek-3.1.1 → pseek-3.2.0}/pseek.egg-info/dependency_links.txt +0 -0
- {pseek-3.1.1 → pseek-3.2.0}/pseek.egg-info/entry_points.txt +0 -0
- {pseek-3.1.1 → pseek-3.2.0}/pseek.egg-info/requires.txt +0 -0
- {pseek-3.1.1 → pseek-3.2.0}/pseek.egg-info/top_level.txt +0 -0
- {pseek-3.1.1 → pseek-3.2.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pseek
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.0
|
|
4
4
|
Summary: Pseek is a Python CLI toolkit to search files, folders, and text
|
|
5
5
|
Author: Groot
|
|
6
6
|
License-Expression: MIT
|
|
@@ -112,12 +112,14 @@ psk -- --path
|
|
|
112
112
|
| `--re-include`, `--re-exclude` | Limit search results to specific directories or files with regex |
|
|
113
113
|
| `--word` | Match the whole word only (except when `--expr` is enabled, in which case you can make it match whole word by putting `w` before term: `w"foo"`) |
|
|
114
114
|
| `--expr` | Enable boolean query expressions. Example: `r"foo.*bar" and ("bar" or "baz") and not "qux"`. Prefixes: `r=regex`, `c=case-sensitive`, `w=whole-word`, `f=fuzzy` |
|
|
115
|
+
| `--context` | Show N context lines before and after matches, or use N:M to specify before:after |
|
|
116
|
+
| `--depth` | Limit directory traversal to given depth range. By default, there is no limit on search depth |
|
|
115
117
|
| `--timeout` | Stop the search after the specified number of seconds |
|
|
116
118
|
| `--fuzzy` | Enable fuzzy search (Highlighting and counting matches are disabled in this mode if `--word` is not enabled to prevent the program from slowing down). except when `--expr` is enabled, in which case you can make it fuzzy by putting `f` before term: `f"foo"` |
|
|
117
119
|
| `--fuzzy-level` | Fuzzy matching threshold (0-99). Higher values require closer matches (default: `80`) |
|
|
118
120
|
| `--size` | Limit results based on the size of files |
|
|
119
121
|
| `--archive` | Enable search within archive files (e.g. `zip`, `rar`, `7z`, `gz`, `bz2`, `xz`, `tar`, `tar.gz`, `tar.bz2`, `tar.xz`) |
|
|
120
|
-
| `--depth` |
|
|
122
|
+
| `--arc-depth` | Limit nested archive to given depth range. By default, there is no limit |
|
|
121
123
|
| `--arc-ext`, `--arc-exc-ext` | Filter by file extension inside archive files |
|
|
122
124
|
| `--arc-include`, `--arc-exclude` | Limit search results to specific set of directories or files inside archive files |
|
|
123
125
|
| `--arc-size` | Limit results based on the size of files in the archive |
|
|
@@ -176,7 +178,7 @@ Example:
|
|
|
176
178
|
psk "hello world"
|
|
177
179
|
```
|
|
178
180
|
|
|
179
|
-
**Note:** To use case-sensitive, whole-word matching, regular expression search, and fuzzy search when `--expr` is enabled, we can use [expression prefixes](#expression-prefixes).
|
|
181
|
+
> **Note:** To use case-sensitive, whole-word matching, regular expression search, and fuzzy search when `--expr` is enabled, we can use [expression prefixes](#expression-prefixes).
|
|
180
182
|
|
|
181
183
|
### Case Sensitive Search
|
|
182
184
|
|
|
@@ -364,7 +366,51 @@ simultaneously.
|
|
|
364
366
|
|
|
365
367
|
Allowed modes: `r`, `c`, `w`, `f`, `rc`, `cr`, `cw`, `wc`, `cf`, `fc`, `wf`, `fw`, `cwf`, `cfw`, `wcf`, `wfc`, `fcw`, `fwc`
|
|
366
368
|
|
|
367
|
-
**Note:** Whole word matching and regex matching cannot be used at the same time, because we can use `\b` in regex to enable whole word matching: `r"\btext\b"`
|
|
369
|
+
> **Note:** Whole word matching and regex matching cannot be used at the same time, because we can use `\b` in regex to enable whole word matching: `r"\btext\b"`
|
|
370
|
+
|
|
371
|
+
## Context
|
|
372
|
+
|
|
373
|
+
Show context lines around each match. The value is specified as `BEFORE:AFTER`:
|
|
374
|
+
|
|
375
|
+
```bash
|
|
376
|
+
--context 2 # 2 lines before and after
|
|
377
|
+
--context 2:0 # 2 lines before, none after
|
|
378
|
+
--context 0:2 # none before, 2 lines after
|
|
379
|
+
--context 2:5 # 2 lines before, 5 lines after
|
|
380
|
+
--context 2: # 2 lines before, none after
|
|
381
|
+
--context :2 # none before, 2 lines after
|
|
382
|
+
--context 0 # matching lines only
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Nearby matches whose context ranges overlap or directly touch are combined into a single group.
|
|
386
|
+
|
|
387
|
+
## Depth
|
|
388
|
+
|
|
389
|
+
Controls how deep the search goes inside directories.
|
|
390
|
+
|
|
391
|
+
A depth of `0` means that only base path's immediate contents are searched; subdirectories are not entered.
|
|
392
|
+
|
|
393
|
+
```text
|
|
394
|
+
project/ ← base directory
|
|
395
|
+
├── file.txt ← depth 0
|
|
396
|
+
├── folder1/ ← depth 0
|
|
397
|
+
│ ├── file.txt ← depth 1
|
|
398
|
+
│ └── folder2/ ← depth 1
|
|
399
|
+
│ └── file.txt ← depth 2
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
`--depth` can be specified multiple times to search non-contiguous depth ranges:
|
|
403
|
+
|
|
404
|
+
```bash
|
|
405
|
+
--depth 0 # Direct contents only
|
|
406
|
+
--depth 1 # One level inside
|
|
407
|
+
--depth 2:4 # Depths 2 through 4
|
|
408
|
+
--depth 2 --depth 5:7 # Depths 2 and 5 through 7
|
|
409
|
+
--depth :2 # Depths 0 through 2
|
|
410
|
+
--depth 3: # Depth 3 and deeper
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
If `--depth` is not specified, the search has no depth limit.
|
|
368
414
|
|
|
369
415
|
## Extension Filters
|
|
370
416
|
|
|
@@ -402,7 +448,7 @@ psk TODO \
|
|
|
402
448
|
|
|
403
449
|
Skip those paths.
|
|
404
450
|
|
|
405
|
-
**Note:** The include and exclude paths will be combined with path argument.
|
|
451
|
+
> **Note:** The include and exclude paths will be combined with path argument.
|
|
406
452
|
|
|
407
453
|
## Regex Path Filters
|
|
408
454
|
|
|
@@ -455,7 +501,7 @@ psk config \
|
|
|
455
501
|
|
|
456
502
|
Files between `1 MiB` and `10 MiB` will not match.
|
|
457
503
|
|
|
458
|
-
**Note:** Directory sizes are not calculated recursively. When `--size` is used, directories are automatically excluded from the search results.
|
|
504
|
+
> **Note:** Directory sizes are not calculated recursively. When `--size` is used, directories are automatically excluded from the search results.
|
|
459
505
|
|
|
460
506
|
## Archive Search
|
|
461
507
|
|
|
@@ -487,15 +533,24 @@ backup.zip::source.7z::notes.txt
|
|
|
487
533
|
|
|
488
534
|
### Archive Depth
|
|
489
535
|
|
|
490
|
-
|
|
536
|
+
The concept of depth in archive is different from `--depth`. Depth in archive is calculated based on nested archives. Each archive that is inside another archive counts as one level of depth.
|
|
537
|
+
|
|
538
|
+
| Syntax | Meaning |
|
|
539
|
+
| ------ | -------------------------------------------------------- |
|
|
540
|
+
| `2` | exactly `2nd` depth |
|
|
541
|
+
| `:2` | `2nd` depth or lower |
|
|
542
|
+
| `2:` | `2nd` depth or higher |
|
|
543
|
+
| `2:4` | between `2` and `4` (Both range boundaries are included) |
|
|
544
|
+
|
|
545
|
+
`--arc-depth` can be specified multiple times:
|
|
491
546
|
|
|
492
547
|
```bash
|
|
493
|
-
psk TODO --archive --depth 2
|
|
548
|
+
psk TODO --archive --arc-depth :2 --arc-depth 5:
|
|
494
549
|
```
|
|
495
550
|
|
|
496
|
-
Meaning `archive level
|
|
551
|
+
Meaning `archive level 3` and `archive level 4` won't be searched.
|
|
497
552
|
|
|
498
|
-
**Note:** `--depth 0` means perform the search only within this current archive and don't enter nested archives.
|
|
553
|
+
> **Note:** `--arc-depth 0` means perform the search only within this current archive and don't enter nested archives.
|
|
499
554
|
|
|
500
555
|
## Archive Filters
|
|
501
556
|
|
|
@@ -535,7 +590,7 @@ This works exactly like the [--size](#size-filtering) option.
|
|
|
535
590
|
psk TODO --archive --arc-size 10m:40m
|
|
536
591
|
```
|
|
537
592
|
|
|
538
|
-
**Note:** Archive directory sizes are usually reported as zero by archive formats, so directory search is disabled if this filter is enabled to avoid incorrect results.
|
|
593
|
+
> **Note:** Archive directory sizes are usually reported as zero by archive formats, so directory search is disabled if this filter is enabled to avoid incorrect results.
|
|
539
594
|
|
|
540
595
|
## RAR Backend
|
|
541
596
|
|
|
@@ -83,12 +83,14 @@ psk -- --path
|
|
|
83
83
|
| `--re-include`, `--re-exclude` | Limit search results to specific directories or files with regex |
|
|
84
84
|
| `--word` | Match the whole word only (except when `--expr` is enabled, in which case you can make it match whole word by putting `w` before term: `w"foo"`) |
|
|
85
85
|
| `--expr` | Enable boolean query expressions. Example: `r"foo.*bar" and ("bar" or "baz") and not "qux"`. Prefixes: `r=regex`, `c=case-sensitive`, `w=whole-word`, `f=fuzzy` |
|
|
86
|
+
| `--context` | Show N context lines before and after matches, or use N:M to specify before:after |
|
|
87
|
+
| `--depth` | Limit directory traversal to given depth range. By default, there is no limit on search depth |
|
|
86
88
|
| `--timeout` | Stop the search after the specified number of seconds |
|
|
87
89
|
| `--fuzzy` | Enable fuzzy search (Highlighting and counting matches are disabled in this mode if `--word` is not enabled to prevent the program from slowing down). except when `--expr` is enabled, in which case you can make it fuzzy by putting `f` before term: `f"foo"` |
|
|
88
90
|
| `--fuzzy-level` | Fuzzy matching threshold (0-99). Higher values require closer matches (default: `80`) |
|
|
89
91
|
| `--size` | Limit results based on the size of files |
|
|
90
92
|
| `--archive` | Enable search within archive files (e.g. `zip`, `rar`, `7z`, `gz`, `bz2`, `xz`, `tar`, `tar.gz`, `tar.bz2`, `tar.xz`) |
|
|
91
|
-
| `--depth` |
|
|
93
|
+
| `--arc-depth` | Limit nested archive to given depth range. By default, there is no limit |
|
|
92
94
|
| `--arc-ext`, `--arc-exc-ext` | Filter by file extension inside archive files |
|
|
93
95
|
| `--arc-include`, `--arc-exclude` | Limit search results to specific set of directories or files inside archive files |
|
|
94
96
|
| `--arc-size` | Limit results based on the size of files in the archive |
|
|
@@ -147,7 +149,7 @@ Example:
|
|
|
147
149
|
psk "hello world"
|
|
148
150
|
```
|
|
149
151
|
|
|
150
|
-
**Note:** To use case-sensitive, whole-word matching, regular expression search, and fuzzy search when `--expr` is enabled, we can use [expression prefixes](#expression-prefixes).
|
|
152
|
+
> **Note:** To use case-sensitive, whole-word matching, regular expression search, and fuzzy search when `--expr` is enabled, we can use [expression prefixes](#expression-prefixes).
|
|
151
153
|
|
|
152
154
|
### Case Sensitive Search
|
|
153
155
|
|
|
@@ -335,7 +337,51 @@ simultaneously.
|
|
|
335
337
|
|
|
336
338
|
Allowed modes: `r`, `c`, `w`, `f`, `rc`, `cr`, `cw`, `wc`, `cf`, `fc`, `wf`, `fw`, `cwf`, `cfw`, `wcf`, `wfc`, `fcw`, `fwc`
|
|
337
339
|
|
|
338
|
-
**Note:** Whole word matching and regex matching cannot be used at the same time, because we can use `\b` in regex to enable whole word matching: `r"\btext\b"`
|
|
340
|
+
> **Note:** Whole word matching and regex matching cannot be used at the same time, because we can use `\b` in regex to enable whole word matching: `r"\btext\b"`
|
|
341
|
+
|
|
342
|
+
## Context
|
|
343
|
+
|
|
344
|
+
Show context lines around each match. The value is specified as `BEFORE:AFTER`:
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
--context 2 # 2 lines before and after
|
|
348
|
+
--context 2:0 # 2 lines before, none after
|
|
349
|
+
--context 0:2 # none before, 2 lines after
|
|
350
|
+
--context 2:5 # 2 lines before, 5 lines after
|
|
351
|
+
--context 2: # 2 lines before, none after
|
|
352
|
+
--context :2 # none before, 2 lines after
|
|
353
|
+
--context 0 # matching lines only
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
Nearby matches whose context ranges overlap or directly touch are combined into a single group.
|
|
357
|
+
|
|
358
|
+
## Depth
|
|
359
|
+
|
|
360
|
+
Controls how deep the search goes inside directories.
|
|
361
|
+
|
|
362
|
+
A depth of `0` means that only base path's immediate contents are searched; subdirectories are not entered.
|
|
363
|
+
|
|
364
|
+
```text
|
|
365
|
+
project/ ← base directory
|
|
366
|
+
├── file.txt ← depth 0
|
|
367
|
+
├── folder1/ ← depth 0
|
|
368
|
+
│ ├── file.txt ← depth 1
|
|
369
|
+
│ └── folder2/ ← depth 1
|
|
370
|
+
│ └── file.txt ← depth 2
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
`--depth` can be specified multiple times to search non-contiguous depth ranges:
|
|
374
|
+
|
|
375
|
+
```bash
|
|
376
|
+
--depth 0 # Direct contents only
|
|
377
|
+
--depth 1 # One level inside
|
|
378
|
+
--depth 2:4 # Depths 2 through 4
|
|
379
|
+
--depth 2 --depth 5:7 # Depths 2 and 5 through 7
|
|
380
|
+
--depth :2 # Depths 0 through 2
|
|
381
|
+
--depth 3: # Depth 3 and deeper
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
If `--depth` is not specified, the search has no depth limit.
|
|
339
385
|
|
|
340
386
|
## Extension Filters
|
|
341
387
|
|
|
@@ -373,7 +419,7 @@ psk TODO \
|
|
|
373
419
|
|
|
374
420
|
Skip those paths.
|
|
375
421
|
|
|
376
|
-
**Note:** The include and exclude paths will be combined with path argument.
|
|
422
|
+
> **Note:** The include and exclude paths will be combined with path argument.
|
|
377
423
|
|
|
378
424
|
## Regex Path Filters
|
|
379
425
|
|
|
@@ -426,7 +472,7 @@ psk config \
|
|
|
426
472
|
|
|
427
473
|
Files between `1 MiB` and `10 MiB` will not match.
|
|
428
474
|
|
|
429
|
-
**Note:** Directory sizes are not calculated recursively. When `--size` is used, directories are automatically excluded from the search results.
|
|
475
|
+
> **Note:** Directory sizes are not calculated recursively. When `--size` is used, directories are automatically excluded from the search results.
|
|
430
476
|
|
|
431
477
|
## Archive Search
|
|
432
478
|
|
|
@@ -458,15 +504,24 @@ backup.zip::source.7z::notes.txt
|
|
|
458
504
|
|
|
459
505
|
### Archive Depth
|
|
460
506
|
|
|
461
|
-
|
|
507
|
+
The concept of depth in archive is different from `--depth`. Depth in archive is calculated based on nested archives. Each archive that is inside another archive counts as one level of depth.
|
|
508
|
+
|
|
509
|
+
| Syntax | Meaning |
|
|
510
|
+
| ------ | -------------------------------------------------------- |
|
|
511
|
+
| `2` | exactly `2nd` depth |
|
|
512
|
+
| `:2` | `2nd` depth or lower |
|
|
513
|
+
| `2:` | `2nd` depth or higher |
|
|
514
|
+
| `2:4` | between `2` and `4` (Both range boundaries are included) |
|
|
515
|
+
|
|
516
|
+
`--arc-depth` can be specified multiple times:
|
|
462
517
|
|
|
463
518
|
```bash
|
|
464
|
-
psk TODO --archive --depth 2
|
|
519
|
+
psk TODO --archive --arc-depth :2 --arc-depth 5:
|
|
465
520
|
```
|
|
466
521
|
|
|
467
|
-
Meaning `archive level
|
|
522
|
+
Meaning `archive level 3` and `archive level 4` won't be searched.
|
|
468
523
|
|
|
469
|
-
**Note:** `--depth 0` means perform the search only within this current archive and don't enter nested archives.
|
|
524
|
+
> **Note:** `--arc-depth 0` means perform the search only within this current archive and don't enter nested archives.
|
|
470
525
|
|
|
471
526
|
## Archive Filters
|
|
472
527
|
|
|
@@ -506,7 +561,7 @@ This works exactly like the [--size](#size-filtering) option.
|
|
|
506
561
|
psk TODO --archive --arc-size 10m:40m
|
|
507
562
|
```
|
|
508
563
|
|
|
509
|
-
**Note:** Archive directory sizes are usually reported as zero by archive formats, so directory search is disabled if this filter is enabled to avoid incorrect results.
|
|
564
|
+
> **Note:** Archive directory sizes are usually reported as zero by archive formats, so directory search is disabled if this filter is enabled to avoid incorrect results.
|
|
510
565
|
|
|
511
566
|
## RAR Backend
|
|
512
567
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import io
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
from .utils import get_path_suffix,
|
|
3
|
+
from .utils import get_path_suffix, is_binary
|
|
4
4
|
# Archive modules
|
|
5
5
|
import zipfile, py7zr, tarfile, gzip, bz2, lzma, rarfile
|
|
6
6
|
|
|
@@ -39,7 +39,7 @@ def archive_should_skip(path_info: Path, config, p_size: float, file_ext, is_dir
|
|
|
39
39
|
return False
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
def extract_names_from_archive(file_path: Path, config, depth: int
|
|
42
|
+
def extract_names_from_archive(file_path: Path, config, depth: int = -1,
|
|
43
43
|
file_bytes: bytes | None = None, parent_label: list[str] | None = None):
|
|
44
44
|
"""
|
|
45
45
|
Recursively extract files and directories name from archive files.
|
|
@@ -57,8 +57,7 @@ def extract_names_from_archive(file_path: Path, config, depth: int | None = None
|
|
|
57
57
|
|
|
58
58
|
file_ext = get_path_suffix(file_path)
|
|
59
59
|
label_prefix = [*parent_label, str(file_path)] if parent_label is not None else []
|
|
60
|
-
|
|
61
|
-
depth = config.depth
|
|
60
|
+
new_depth = depth + 1
|
|
62
61
|
|
|
63
62
|
try:
|
|
64
63
|
# Decide the stream source: from disk or memory
|
|
@@ -72,8 +71,6 @@ def extract_names_from_archive(file_path: Path, config, depth: int | None = None
|
|
|
72
71
|
name = Path(info.filename)
|
|
73
72
|
new_path_ext = get_path_suffix(name)
|
|
74
73
|
is_dir = info.is_dir()
|
|
75
|
-
# At each recursion, subtract 1 from depth if it's set
|
|
76
|
-
new_depth = None if depth is None else depth - 1
|
|
77
74
|
|
|
78
75
|
if not archive_should_skip(
|
|
79
76
|
name,
|
|
@@ -82,10 +79,11 @@ def extract_names_from_archive(file_path: Path, config, depth: int | None = None
|
|
|
82
79
|
new_path_ext,
|
|
83
80
|
is_dir
|
|
84
81
|
):
|
|
85
|
-
|
|
82
|
+
if any(mi <= new_depth <= ma for mi, ma in config.arc_depth):
|
|
83
|
+
yield label_prefix, name, is_dir
|
|
86
84
|
|
|
87
85
|
# Check if this is a nested archive
|
|
88
|
-
if new_path_ext in ARCHIVE_EXTS[:-3] and (new_depth
|
|
86
|
+
if new_path_ext in ARCHIVE_EXTS[:-3] and any(new_depth < d[1] for d in config.arc_depth):
|
|
89
87
|
yield from extract_names_from_archive(
|
|
90
88
|
name,
|
|
91
89
|
config,
|
|
@@ -100,7 +98,6 @@ def extract_names_from_archive(file_path: Path, config, depth: int | None = None
|
|
|
100
98
|
name = Path(info.filename)
|
|
101
99
|
new_path_ext = get_path_suffix(name)
|
|
102
100
|
is_dir = info.is_directory
|
|
103
|
-
new_depth = None if depth is None else depth - 1
|
|
104
101
|
|
|
105
102
|
if not archive_should_skip(
|
|
106
103
|
name,
|
|
@@ -109,9 +106,10 @@ def extract_names_from_archive(file_path: Path, config, depth: int | None = None
|
|
|
109
106
|
new_path_ext,
|
|
110
107
|
is_dir
|
|
111
108
|
):
|
|
112
|
-
|
|
109
|
+
if any(mi <= new_depth <= ma for mi, ma in config.arc_depth):
|
|
110
|
+
yield label_prefix, name, is_dir
|
|
113
111
|
|
|
114
|
-
if new_path_ext in ARCHIVE_EXTS[:-3] and (new_depth
|
|
112
|
+
if new_path_ext in ARCHIVE_EXTS[:-3] and any(new_depth < d[1] for d in config.arc_depth):
|
|
115
113
|
file_data = z.read([info.filename]).get(info.filename)
|
|
116
114
|
if file_data is None:
|
|
117
115
|
continue
|
|
@@ -138,7 +136,6 @@ def extract_names_from_archive(file_path: Path, config, depth: int | None = None
|
|
|
138
136
|
name = Path(member.name)
|
|
139
137
|
new_path_ext = get_path_suffix(name)
|
|
140
138
|
is_dir = member.isdir()
|
|
141
|
-
new_depth = None if depth is None else depth - 1
|
|
142
139
|
|
|
143
140
|
if not archive_should_skip(
|
|
144
141
|
name,
|
|
@@ -147,9 +144,10 @@ def extract_names_from_archive(file_path: Path, config, depth: int | None = None
|
|
|
147
144
|
new_path_ext,
|
|
148
145
|
is_dir
|
|
149
146
|
):
|
|
150
|
-
|
|
147
|
+
if any(mi <= new_depth <= ma for mi, ma in config.arc_depth):
|
|
148
|
+
yield label_prefix, name, is_dir
|
|
151
149
|
|
|
152
|
-
if new_path_ext in ARCHIVE_EXTS[:-3] and (new_depth
|
|
150
|
+
if new_path_ext in ARCHIVE_EXTS[:-3] and any(new_depth < d[1] for d in config.arc_depth):
|
|
153
151
|
f = tf.extractfile(member)
|
|
154
152
|
if f is None:
|
|
155
153
|
continue
|
|
@@ -165,7 +163,7 @@ def extract_names_from_archive(file_path: Path, config, depth: int | None = None
|
|
|
165
163
|
return # silently skip invalid or unreadable archives
|
|
166
164
|
|
|
167
165
|
|
|
168
|
-
def extract_text_from_archive(file_path: Path, config, depth: int
|
|
166
|
+
def extract_text_from_archive(file_path: Path, config, depth: int = -1,
|
|
169
167
|
file_bytes: bytes | None = None, parent_label: list[str] | None = None):
|
|
170
168
|
"""
|
|
171
169
|
Recursively extract (path_label, text_content) from any archive file.
|
|
@@ -183,8 +181,7 @@ def extract_text_from_archive(file_path: Path, config, depth: int | None = None,
|
|
|
183
181
|
|
|
184
182
|
file_ext = get_path_suffix(file_path)
|
|
185
183
|
label_prefix = [*parent_label, str(file_path)] if parent_label is not None else []
|
|
186
|
-
|
|
187
|
-
depth = config.depth
|
|
184
|
+
new_depth = depth + 1
|
|
188
185
|
|
|
189
186
|
try:
|
|
190
187
|
# Decide the stream source: from disk or memory
|
|
@@ -195,10 +192,10 @@ def extract_text_from_archive(file_path: Path, config, depth: int | None = None,
|
|
|
195
192
|
opener = {'zip': zipfile.ZipFile, 'rar': rarfile.RarFile}[file_ext]
|
|
196
193
|
with opener(file_stream) as f:
|
|
197
194
|
for info in f.infolist():
|
|
195
|
+
if info.is_dir():
|
|
196
|
+
continue
|
|
197
|
+
|
|
198
198
|
file_name = Path(info.filename)
|
|
199
|
-
data = f.read(info)
|
|
200
|
-
# At each recursion, subtract 1 from depth if it's set
|
|
201
|
-
new_depth = None if depth is None else depth - 1
|
|
202
199
|
new_path_ext = get_path_suffix(file_name)
|
|
203
200
|
|
|
204
201
|
if archive_should_skip(
|
|
@@ -209,22 +206,33 @@ def extract_text_from_archive(file_path: Path, config, depth: int | None = None,
|
|
|
209
206
|
):
|
|
210
207
|
continue
|
|
211
208
|
|
|
209
|
+
with f.open(info) as entry:
|
|
210
|
+
head = entry.read(8192)
|
|
211
|
+
|
|
212
|
+
if is_binary(head) and new_path_ext not in ARCHIVE_EXTS:
|
|
213
|
+
continue
|
|
214
|
+
|
|
215
|
+
# 8 KiB has already been consumed from stream. If we use entry.read(), we will lose that 8 KiB
|
|
216
|
+
data = head + entry.read()
|
|
217
|
+
|
|
212
218
|
# Check if this is a nested archive
|
|
213
|
-
if new_path_ext in ARCHIVE_EXTS
|
|
214
|
-
|
|
215
|
-
|
|
219
|
+
if new_path_ext in ARCHIVE_EXTS:
|
|
220
|
+
if any(new_depth < d[1] for d in config.arc_depth):
|
|
221
|
+
yield from extract_text_from_archive(file_name, config, new_depth, data, label_prefix)
|
|
222
|
+
elif any(mi <= new_depth <= ma for mi, ma in config.arc_depth):
|
|
216
223
|
yield [*label_prefix, str(file_name)], data
|
|
217
224
|
# Handle 7Z archives
|
|
218
225
|
elif file_ext == '7z':
|
|
219
226
|
with py7zr.SevenZipFile(file_stream, mode='r') as archive:
|
|
220
227
|
for info in archive.list():
|
|
228
|
+
if info.is_directory:
|
|
229
|
+
continue
|
|
230
|
+
|
|
221
231
|
file_data = archive.read([info.filename]).get(info.filename)
|
|
222
232
|
if file_data is None:
|
|
223
233
|
continue
|
|
224
234
|
|
|
225
235
|
file_name = Path(info.filename)
|
|
226
|
-
data = file_data.read()
|
|
227
|
-
new_depth = None if depth is None else depth - 1
|
|
228
236
|
new_path_ext = get_path_suffix(file_name)
|
|
229
237
|
|
|
230
238
|
if archive_should_skip(
|
|
@@ -234,10 +242,16 @@ def extract_text_from_archive(file_path: Path, config, depth: int | None = None,
|
|
|
234
242
|
new_path_ext
|
|
235
243
|
):
|
|
236
244
|
continue
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
245
|
+
|
|
246
|
+
head = file_data.read(8192)
|
|
247
|
+
if is_binary(head) and new_path_ext not in ARCHIVE_EXTS:
|
|
248
|
+
continue
|
|
249
|
+
|
|
250
|
+
data = head + file_data.read()
|
|
251
|
+
if new_path_ext in ARCHIVE_EXTS:
|
|
252
|
+
if any(new_depth < d[1] for d in config.arc_depth):
|
|
253
|
+
yield from extract_text_from_archive(file_name, config, new_depth, data, label_prefix)
|
|
254
|
+
elif any(mi <= new_depth <= ma for mi, ma in config.arc_depth):
|
|
241
255
|
yield [*label_prefix, str(file_name)], data
|
|
242
256
|
# Handle TAR and compressed TAR formats
|
|
243
257
|
elif file_ext in ('tar', 'tar.gz', 'tar.bz2', 'tar.xz'):
|
|
@@ -250,13 +264,14 @@ def extract_text_from_archive(file_path: Path, config, depth: int | None = None,
|
|
|
250
264
|
|
|
251
265
|
with tarfile.open(fileobj=file_stream, mode=mode) as tf:
|
|
252
266
|
for member in tf.getmembers():
|
|
267
|
+
if member.isdir():
|
|
268
|
+
continue
|
|
269
|
+
|
|
253
270
|
f = tf.extractfile(member)
|
|
254
271
|
if f is None:
|
|
255
272
|
continue
|
|
256
273
|
|
|
257
274
|
file_name = Path(member.name)
|
|
258
|
-
data = f.read()
|
|
259
|
-
new_depth = None if depth is None else depth - 1
|
|
260
275
|
new_path_ext = get_path_suffix(file_name)
|
|
261
276
|
|
|
262
277
|
if archive_should_skip(
|
|
@@ -266,10 +281,16 @@ def extract_text_from_archive(file_path: Path, config, depth: int | None = None,
|
|
|
266
281
|
new_path_ext
|
|
267
282
|
):
|
|
268
283
|
continue
|
|
284
|
+
|
|
285
|
+
head = f.read(8192)
|
|
286
|
+
if is_binary(head) and new_path_ext not in ARCHIVE_EXTS:
|
|
287
|
+
continue
|
|
269
288
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
289
|
+
data = head + f.read()
|
|
290
|
+
if new_path_ext in ARCHIVE_EXTS:
|
|
291
|
+
if any(new_depth < d[1] for d in config.arc_depth):
|
|
292
|
+
yield from extract_text_from_archive(file_name, config, new_depth, data, label_prefix)
|
|
293
|
+
elif any(mi <= new_depth <= ma for mi, ma in config.arc_depth):
|
|
273
294
|
yield [*label_prefix, str(file_name)], data
|
|
274
295
|
# Handle single compressed files like .gz, .bz2, .xz
|
|
275
296
|
elif file_ext in ARCHIVE_EXTS[-3:]:
|