dirpluck 0.1.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.
- dirpluck-0.1.0/CHANGELOG.md +26 -0
- dirpluck-0.1.0/CONFIGURATION.md +409 -0
- dirpluck-0.1.0/GLOSSARY.md +43 -0
- dirpluck-0.1.0/LICENSE +21 -0
- dirpluck-0.1.0/MANIFEST.in +13 -0
- dirpluck-0.1.0/PKG-INFO +236 -0
- dirpluck-0.1.0/README.md +214 -0
- dirpluck-0.1.0/SPECIFICATION.md +290 -0
- dirpluck-0.1.0/pyproject.toml +44 -0
- dirpluck-0.1.0/setup.cfg +4 -0
- dirpluck-0.1.0/src/dirpluck/__init__.py +3 -0
- dirpluck-0.1.0/src/dirpluck/builder.py +750 -0
- dirpluck-0.1.0/src/dirpluck/cli.py +133 -0
- dirpluck-0.1.0/src/dirpluck/config.py +565 -0
- dirpluck-0.1.0/src/dirpluck/docs/CONFIGURATION.md +409 -0
- dirpluck-0.1.0/src/dirpluck/docs/GLOSSARY.md +43 -0
- dirpluck-0.1.0/src/dirpluck/docs/README.md +214 -0
- dirpluck-0.1.0/src/dirpluck/docs/SPECIFICATION.md +290 -0
- dirpluck-0.1.0/src/dirpluck/errors.py +13 -0
- dirpluck-0.1.0/src/dirpluck.egg-info/PKG-INFO +236 -0
- dirpluck-0.1.0/src/dirpluck.egg-info/SOURCES.txt +26 -0
- dirpluck-0.1.0/src/dirpluck.egg-info/dependency_links.txt +1 -0
- dirpluck-0.1.0/src/dirpluck.egg-info/entry_points.txt +2 -0
- dirpluck-0.1.0/src/dirpluck.egg-info/top_level.txt +1 -0
- dirpluck-0.1.0/tests/test_builder.py +900 -0
- dirpluck-0.1.0/tests/test_cli.py +592 -0
- dirpluck-0.1.0/tests/test_config.py +729 -0
- dirpluck-0.1.0/tests/test_public_interface.py +26 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# dirpluck CHANGELOG
|
|
2
|
+
|
|
3
|
+
Release-by-release changes for dirpluck.
|
|
4
|
+
|
|
5
|
+
## 0.1.0
|
|
6
|
+
|
|
7
|
+
First public release.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Rework `README.md` around concrete use cases and the value of repeatable file sets, move TOML authoring guidance into `CONFIGURATION.md`, and keep exact operational semantics in `SPECIFICATION.md`.
|
|
12
|
+
- Keep the Archive-root `README.md` as a purpose-neutral index: fixed wording does not identify the generating tool or prescribe downstream use, while Target and Companion `description` values carry concrete purpose.
|
|
13
|
+
- Add fixed and generated Output forms. Generated Output uses `directory`, `timestamp = true`, optional `prefix` / `suffix`, and optional CLI `--sequence N` to produce `[prefix-]YYYYMMDD-HHMMSS[-N][-suffix].zip`; existing destinations are rejected during normal execution, with no auto-numbering, auto-renaming, or overwrite mode. Asynchronous and parallel invocations are not coordinated, so callers must avoid concurrent writes to the same output path.
|
|
14
|
+
- Clarify in `README.md` and `CONFIGURATION.md` that selecting a directory recursively collects its contents and that dirpluck does not infer or automatically exclude secret-like files such as `.env`, private keys, or `.git`; broad selections require explicit exclusions appropriate to the workspace.
|
|
15
|
+
- Define the CLI as the supported public interface; package-internal Python modules and functions are not yet a compatibility-guaranteed public API.
|
|
16
|
+
- Treat one Configuration file as one extraction intent, producing a ZIP Archive from an optional runtime-bound Target definition and/or one or more fixed Companions, plus one required Output definition. When a Target is defined, one or more CLI directory arguments may instantiate that same Target rule in one run; TOML still defines only one Target rule. A Configuration with no Target runs without positional directories, while supplying any to such a Configuration is an error.
|
|
17
|
+
- Generalize Case as one flat, Configuration-wide selection variation. Target and Companion Case selections are complete alternatives with no inheritance or merge. When a Target exists it must define the selected Case; Companions with the same Case use it and other Companions fall back to base. Without a Target, a Case is valid when at least one Companion defines it. Cases cannot be combined or nested, and they never change source membership, Companion paths, or Output policy.
|
|
18
|
+
- Select fixed-depth relative paths with `include` and `include_if_exists`, allowing at most one `*` per path element. `include` requires at least one match per pattern, while `include_if_exists` permits zero matches. Recursive-anywhere `**` search is not provided.
|
|
19
|
+
- Filter selected file or directory names with `exclude` using limited exact, prefix, suffix, and contains matching.
|
|
20
|
+
- Default `if_empty` to `error`, while allowing optional-only Target or Companion selections to use `if_empty = "allow"`. Allowed empty selections can be preserved as explicit empty directories in the Archive.
|
|
21
|
+
- Preview planned Archive contents with `--dry-run`. Missing required includes are shown as `[missing]`, optional misses as `[optional missing]`, and empty-result policy is reported without creating a ZIP.
|
|
22
|
+
- Restrict processing to the current working directory, reject symbolic-link escapes, and allow the Target to be the cwd itself while still preserving the cwd's actual directory name in the Archive.
|
|
23
|
+
- Require `description` on every Target or Companion selection, including named Cases, and generate an Archive-root README. When multiple purposes resolve to the same actual directory, files are unioned by real path and the README records each declared purpose.
|
|
24
|
+
- Support Python 3.11 and later, distribute dirpluck under the MIT License, and keep runtime third-party dependencies at zero.
|
|
25
|
+
- Define PyPI distribution boundaries explicitly: the wheel ships executable code plus the public `README.md` / `CONFIGURATION.md` / `GLOSSARY.md` / `SPECIFICATION.md`, while the sdist additionally includes tests and public source documents. `_internal/` and `.github/` remain repository-only development infrastructure.
|
|
26
|
+
- Simplify the normal CLI form to `dirpluck DIRECTORY [DIRECTORY ...]` and remove the `build` subcommand. Discover Configurations only from the cwd and `./dirpluck/`: the default searches for `dirpluck.toml`, while `--config NAME` searches for the same named TOML in both locations. Multiple matches are rejected as ambiguous, and `--configs` lists discoverable candidates and conflicts.
|
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
# dirpluck Configuration
|
|
2
|
+
|
|
3
|
+
A dirpluck Configuration is a TOML file that describes one extraction intent. This document is the authoring guide: it explains how to choose Target and Companion sources, write selections, define Cases, and set Output policy.
|
|
4
|
+
|
|
5
|
+
For an overview of where this model is useful, start with [README.md](README.md). For exact parser, matching, filesystem, Archive, and error semantics, use [SPECIFICATION.md](SPECIFICATION.md).
|
|
6
|
+
|
|
7
|
+
## Start with one extraction intent
|
|
8
|
+
|
|
9
|
+
Use one Configuration for one package you want to be able to reproduce. A Configuration may describe a changing runtime subject, fixed material from several directories, or both.
|
|
10
|
+
|
|
11
|
+
If two workflows need different source membership, different Companion paths, or different Output policy, write two Configurations. Cases are for coordinated selection variations inside one intent, not for turning one Configuration into a stack of profiles.
|
|
12
|
+
|
|
13
|
+
Every Configuration contains:
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
Configuration
|
|
17
|
+
├── target optional, runtime-bound
|
|
18
|
+
├── companion.<name> zero or more, configuration-bound
|
|
19
|
+
└── output exactly one
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
At least one Target or Companion is required.
|
|
23
|
+
|
|
24
|
+
## Target
|
|
25
|
+
|
|
26
|
+
Use a Target when one or more source directories of the same role should be supplied at invocation time. The Configuration contains one `[target]` definition that declares how files are selected, but it does not store those runtime directory paths. When several directories are supplied, the same Target selection is applied independently to each one.
|
|
27
|
+
|
|
28
|
+
```toml
|
|
29
|
+
[target]
|
|
30
|
+
description = "The submission currently being reviewed."
|
|
31
|
+
include = [
|
|
32
|
+
"documents",
|
|
33
|
+
"metadata.json",
|
|
34
|
+
]
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
A Configuration that defines a Target requires at least one `DIRECTORY` on the CLI:
|
|
38
|
+
|
|
39
|
+
```console
|
|
40
|
+
dirpluck submissions/acme
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The same Target definition may be applied to several runtime directories in one run:
|
|
44
|
+
|
|
45
|
+
```console
|
|
46
|
+
dirpluck submissions/acme submissions/contoso submissions/globex
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
TOML still contains only one Target definition; the CLI list does not create separately configured Targets. Runtime Target directories must resolve to distinct directories. If the Configuration does not define a Target, supplying any positional `DIRECTORY` is an error. This keeps runtime input aligned with what the Configuration actually declares.
|
|
50
|
+
|
|
51
|
+
A Target may define a default selection, named Cases, or both. If it has Cases but no default `[target]` selection, the Configuration must be invoked with `--case`.
|
|
52
|
+
|
|
53
|
+
## Companions
|
|
54
|
+
|
|
55
|
+
Use a Companion for a source directory that belongs to the extraction intent itself and therefore has a fixed path in TOML.
|
|
56
|
+
|
|
57
|
+
```toml
|
|
58
|
+
[companion.guidelines]
|
|
59
|
+
path = "review-guidelines"
|
|
60
|
+
description = "Guidelines used for every review."
|
|
61
|
+
include = ["*.md"]
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The Companion name (`guidelines` above) identifies that source inside the Configuration. `path` is relative to the current working directory and names one concrete directory.
|
|
65
|
+
|
|
66
|
+
Companions do not require a Target. A Configuration may be made entirely of fixed Companions:
|
|
67
|
+
|
|
68
|
+
```toml
|
|
69
|
+
[companion.contracts]
|
|
70
|
+
path = "records/contracts"
|
|
71
|
+
description = "Contracts included in the project snapshot."
|
|
72
|
+
include = ["*.pdf"]
|
|
73
|
+
|
|
74
|
+
[companion.minutes]
|
|
75
|
+
path = "records/meetings"
|
|
76
|
+
description = "Meeting records included in the project snapshot."
|
|
77
|
+
include = ["*.md"]
|
|
78
|
+
|
|
79
|
+
[output]
|
|
80
|
+
directory = "artifacts/snapshots"
|
|
81
|
+
prefix = "project"
|
|
82
|
+
timestamp = true
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Run it without a positional directory:
|
|
86
|
+
|
|
87
|
+
```console
|
|
88
|
+
dirpluck --config project-snapshot
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Selection fields
|
|
92
|
+
|
|
93
|
+
Every Target selection, Companion base selection, and Case selection has its own `description` and file-selection fields.
|
|
94
|
+
|
|
95
|
+
### `description`
|
|
96
|
+
|
|
97
|
+
`description` is required and must be non-empty. Write the role of that source or selection in the extraction intent rather than merely repeating its directory name.
|
|
98
|
+
|
|
99
|
+
```toml
|
|
100
|
+
description = "Reference material used to evaluate the submission."
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The generated Archive index carries these descriptions forward, so purpose-specific meaning should be stated here rather than inferred later from filenames.
|
|
104
|
+
|
|
105
|
+
### `include`
|
|
106
|
+
|
|
107
|
+
Use `include` for entries that must be present. Every pattern must match during a normal build.
|
|
108
|
+
|
|
109
|
+
```toml
|
|
110
|
+
include = [
|
|
111
|
+
"report.pdf",
|
|
112
|
+
"data/*.csv",
|
|
113
|
+
]
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
A missing required pattern is an error. Use this when absence means the resulting package would no longer represent the declared intent.
|
|
117
|
+
|
|
118
|
+
### `include_if_exists`
|
|
119
|
+
|
|
120
|
+
Use `include_if_exists` for known candidates whose absence is acceptable.
|
|
121
|
+
|
|
122
|
+
```toml
|
|
123
|
+
include_if_exists = [
|
|
124
|
+
"generated/*.pdf",
|
|
125
|
+
"coverage.xml",
|
|
126
|
+
]
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
This is useful for generated outputs, optional attachments, or files that exist only in some runs.
|
|
130
|
+
|
|
131
|
+
A selection may use both `include` and `include_if_exists` when it has a required core plus optional additions.
|
|
132
|
+
|
|
133
|
+
### `exclude`
|
|
134
|
+
|
|
135
|
+
Use `exclude` to filter names only inside areas already selected by `include` or `include_if_exists`.
|
|
136
|
+
|
|
137
|
+
```toml
|
|
138
|
+
exclude = [
|
|
139
|
+
".git/",
|
|
140
|
+
"__pycache__/",
|
|
141
|
+
".env*",
|
|
142
|
+
"*.pem",
|
|
143
|
+
"*.key",
|
|
144
|
+
".DS_Store",
|
|
145
|
+
"*.pyc",
|
|
146
|
+
]
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Selecting a directory with `include` or `include_if_exists` recursively collects files below it. dirpluck does not automatically recognize hidden files or secret-like names, so broad selections should add `exclude` rules appropriate to the workspace. The list above is illustrative, not an exhaustive secret filter.
|
|
150
|
+
|
|
151
|
+
`exclude` is not another include language and does not select files by itself. Exact supported pattern forms are defined in [SPECIFICATION.md](SPECIFICATION.md).
|
|
152
|
+
|
|
153
|
+
### `if_empty`
|
|
154
|
+
|
|
155
|
+
The default is:
|
|
156
|
+
|
|
157
|
+
```toml
|
|
158
|
+
if_empty = "error"
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
For a selection that contains only `include_if_exists`, you may explicitly allow a zero-file result:
|
|
162
|
+
|
|
163
|
+
```toml
|
|
164
|
+
include_if_exists = ["generated/*.pdf"]
|
|
165
|
+
if_empty = "allow"
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
`if_empty = "allow"` cannot be combined with required `include` patterns.
|
|
169
|
+
|
|
170
|
+
## Cases
|
|
171
|
+
|
|
172
|
+
A Case is one flat, named selection variation shared by the Configuration. At most one Case name can be active in a run.
|
|
173
|
+
|
|
174
|
+
Cases replace a source's selection as a whole. They do not inherit from or merge with the base selection.
|
|
175
|
+
|
|
176
|
+
### Target Case
|
|
177
|
+
|
|
178
|
+
```toml
|
|
179
|
+
[target]
|
|
180
|
+
description = "The current project for normal development work."
|
|
181
|
+
include = ["src", "pyproject.toml"]
|
|
182
|
+
|
|
183
|
+
[target.case.review]
|
|
184
|
+
description = "The current project with review material included."
|
|
185
|
+
include = ["src", "tests", "pyproject.toml"]
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
```console
|
|
189
|
+
dirpluck project-a project-b --case review
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
When a Target exists, it defines the valid Case namespace. Selecting `review` requires `[target.case.review]` to exist, and that same Case selection is applied to every runtime Target directory supplied in the command.
|
|
193
|
+
|
|
194
|
+
### Companion Case and fallback
|
|
195
|
+
|
|
196
|
+
A Companion may define the same Case name when its own selection should change with that Configuration-wide Case:
|
|
197
|
+
|
|
198
|
+
```toml
|
|
199
|
+
[companion.framework]
|
|
200
|
+
path = "framework"
|
|
201
|
+
description = "The framework used by the project."
|
|
202
|
+
include = ["dist/framework-*.whl"]
|
|
203
|
+
|
|
204
|
+
[companion.framework.case.review]
|
|
205
|
+
description = "The framework distribution and source used during review."
|
|
206
|
+
include = ["dist/framework-*.whl", "src"]
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
If `--case review` is active, this Companion uses its `review` selection. A Companion without `[companion.<name>.case.review]` remains present and falls back to its base selection.
|
|
210
|
+
|
|
211
|
+
### Cases without a Target
|
|
212
|
+
|
|
213
|
+
Companion-only Configurations may also use Cases:
|
|
214
|
+
|
|
215
|
+
```toml
|
|
216
|
+
[companion.documents]
|
|
217
|
+
path = "documents"
|
|
218
|
+
description = "Current documents in the snapshot."
|
|
219
|
+
include = ["current/*.md"]
|
|
220
|
+
|
|
221
|
+
[companion.documents.case.archive]
|
|
222
|
+
description = "Current and historical documents in the archival snapshot."
|
|
223
|
+
include = ["current/*.md", "history/*.md"]
|
|
224
|
+
|
|
225
|
+
[companion.assets]
|
|
226
|
+
path = "assets"
|
|
227
|
+
description = "Assets included in every snapshot."
|
|
228
|
+
include = ["*.png"]
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
```console
|
|
232
|
+
dirpluck --config snapshot --case archive
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Here `documents` uses its `archive` Case while `assets` falls back to base. Without a Target, a selected Case must be defined by at least one Companion.
|
|
236
|
+
|
|
237
|
+
Case names are flat. Do not combine Cases, repeat `--case`, or create nested forms such as `case.review.case.security`.
|
|
238
|
+
|
|
239
|
+
Cases change selections only. If a variation needs a different Companion set, Companion path, or Output policy, use another Configuration.
|
|
240
|
+
|
|
241
|
+
## Output
|
|
242
|
+
|
|
243
|
+
Every Configuration has one `[output]` table. It uses exactly one of two forms: **fixed output**, which updates one known path, or **generated output**, which creates a new timestamped name for each run. The two forms cannot be mixed.
|
|
244
|
+
|
|
245
|
+
### Fixed output
|
|
246
|
+
|
|
247
|
+
```toml
|
|
248
|
+
[output]
|
|
249
|
+
path = "artifacts/review.zip"
|
|
250
|
+
if_exists = "overwrite"
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
`path` is a concrete path below the current working directory. `if_exists` is required:
|
|
254
|
+
|
|
255
|
+
- `error` refuses to replace an existing output.
|
|
256
|
+
- `overwrite` replaces it only after a new Archive has been written successfully.
|
|
257
|
+
|
|
258
|
+
Use fixed output when the workflow intentionally maintains one known artifact. Only fixed output can permit replacement.
|
|
259
|
+
|
|
260
|
+
### Generated output
|
|
261
|
+
|
|
262
|
+
Use generated output when runs are meant to accumulate, such as snapshots or recurring packages:
|
|
263
|
+
|
|
264
|
+
```toml
|
|
265
|
+
[output]
|
|
266
|
+
directory = "artifacts/snapshots"
|
|
267
|
+
prefix = "project"
|
|
268
|
+
timestamp = true
|
|
269
|
+
suffix = "review"
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
The filename has one fixed layout:
|
|
273
|
+
|
|
274
|
+
```text
|
|
275
|
+
[prefix-]YYYYMMDD-HHMMSS[-N][-suffix].zip
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
The example above produces a name such as:
|
|
279
|
+
|
|
280
|
+
```text
|
|
281
|
+
project-20260916-011623-review.zip
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
`prefix` and `suffix` are optional. `timestamp = true` is required. The local process time is captured once at the start of the build; custom timestamp formats and general naming templates are not supported.
|
|
285
|
+
|
|
286
|
+
If a script deliberately starts more than one run in the same second, the caller can supply one positive integer:
|
|
287
|
+
|
|
288
|
+
```console
|
|
289
|
+
dirpluck --config project-snapshot --sequence 3
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
The sequence is placed immediately after the timestamp:
|
|
293
|
+
|
|
294
|
+
```text
|
|
295
|
+
project-20260916-011623-3-review.zip
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
`--sequence` is not automatic numbering. dirpluck never inspects existing outputs to infer the next number, and the number segment is omitted when it is not supplied. `--sequence` is invalid with fixed output.
|
|
299
|
+
|
|
300
|
+
Generated output does not accept `if_exists`. If the generated name already exists when the run checks its destination, the run fails. dirpluck neither auto-numbers nor auto-renames it. dirpluck does not coordinate concurrent writes to the same output path, so overlapping invocations must be given distinct names by the caller.
|
|
301
|
+
|
|
302
|
+
The CLI does not temporarily replace the Output form. If two workflows need different output behavior, represent them as different Configurations. `--sequence` only fills the runtime number slot provided by generated naming; it does not replace the naming rule.
|
|
303
|
+
|
|
304
|
+
## Complete example: changing Target with fixed references
|
|
305
|
+
|
|
306
|
+
```toml
|
|
307
|
+
[target]
|
|
308
|
+
description = "The submission currently being reviewed."
|
|
309
|
+
include = [
|
|
310
|
+
"documents",
|
|
311
|
+
"metadata.json",
|
|
312
|
+
]
|
|
313
|
+
include_if_exists = ["attachments"]
|
|
314
|
+
|
|
315
|
+
[target.case.audit]
|
|
316
|
+
description = "The submission with additional records required for audit."
|
|
317
|
+
include = [
|
|
318
|
+
"documents",
|
|
319
|
+
"metadata.json",
|
|
320
|
+
"records",
|
|
321
|
+
]
|
|
322
|
+
include_if_exists = ["attachments"]
|
|
323
|
+
|
|
324
|
+
[companion.guidelines]
|
|
325
|
+
path = "review-guidelines"
|
|
326
|
+
description = "Guidelines used for every review."
|
|
327
|
+
include = ["*.md"]
|
|
328
|
+
|
|
329
|
+
[companion.guidelines.case.audit]
|
|
330
|
+
description = "Guidelines and audit checklist used for an audit review."
|
|
331
|
+
include = ["*.md", "audit-checklist.pdf"]
|
|
332
|
+
|
|
333
|
+
[companion.reference]
|
|
334
|
+
path = "reference-data"
|
|
335
|
+
description = "Reference data used by every review type."
|
|
336
|
+
include = ["*.csv"]
|
|
337
|
+
|
|
338
|
+
[output]
|
|
339
|
+
path = "artifacts/review.zip"
|
|
340
|
+
if_exists = "overwrite"
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Normal review, with one or more runtime Targets:
|
|
344
|
+
|
|
345
|
+
```console
|
|
346
|
+
dirpluck submissions/acme submissions/contoso
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
Audit variation:
|
|
350
|
+
|
|
351
|
+
```console
|
|
352
|
+
dirpluck submissions/acme submissions/contoso --case audit
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
The same Target selection is applied to both runtime directories. Under `audit`, every runtime Target and `guidelines` switch to the `audit` selection; `reference` has no `audit` Case and therefore uses its base selection.
|
|
356
|
+
|
|
357
|
+
## Complete example: fixed-source snapshot
|
|
358
|
+
|
|
359
|
+
```toml
|
|
360
|
+
[companion.documents]
|
|
361
|
+
path = "records/documents"
|
|
362
|
+
description = "Documents that define the current project state."
|
|
363
|
+
include = ["*.pdf", "*.md"]
|
|
364
|
+
|
|
365
|
+
[companion.decisions]
|
|
366
|
+
path = "records/decisions"
|
|
367
|
+
description = "Recorded decisions that explain the current project state."
|
|
368
|
+
include = ["*.md"]
|
|
369
|
+
|
|
370
|
+
[companion.generated]
|
|
371
|
+
path = "generated"
|
|
372
|
+
description = "Generated material available at snapshot time."
|
|
373
|
+
include_if_exists = ["*.pdf", "*.zip"]
|
|
374
|
+
if_empty = "allow"
|
|
375
|
+
|
|
376
|
+
[output]
|
|
377
|
+
directory = "artifacts/snapshots"
|
|
378
|
+
prefix = "project"
|
|
379
|
+
timestamp = true
|
|
380
|
+
suffix = "snapshot"
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
```console
|
|
384
|
+
dirpluck --config project-snapshot
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
This Configuration is complete without a Target because all of its sources are fixed Companions. Each run adds a name such as `project-YYYYMMDD-HHMMSS-snapshot.zip`; a script that intentionally launches multiple runs in the same second can supply `--sequence N`.
|
|
388
|
+
|
|
389
|
+
## Configuration discovery
|
|
390
|
+
|
|
391
|
+
By default, dirpluck looks for `dirpluck.toml`. With `--config NAME`, the `.toml` suffix may be omitted:
|
|
392
|
+
|
|
393
|
+
```console
|
|
394
|
+
dirpluck DIRECTORY [DIRECTORY ...] --config review
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
Configuration discovery is limited to the current working directory and `./dirpluck/`. A name found in both places is ambiguous and is rejected rather than resolved by precedence.
|
|
398
|
+
|
|
399
|
+
Use:
|
|
400
|
+
|
|
401
|
+
```console
|
|
402
|
+
dirpluck --configs
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
to list discoverable Configurations.
|
|
406
|
+
|
|
407
|
+
## Exact syntax and execution rules
|
|
408
|
+
|
|
409
|
+
This guide is intentionally about writing and structuring Configurations. [SPECIFICATION.md](SPECIFICATION.md) is the authority for exact include and exclude pattern grammar, case-sensitive matching, symbolic-link boundaries, Archive path behavior, dry-run semantics, and validation errors.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# dirpluck Glossary
|
|
2
|
+
|
|
3
|
+
Terms used with a common meaning in the design, implementation, and use of dirpluck.
|
|
4
|
+
|
|
5
|
+
## dirpluck
|
|
6
|
+
|
|
7
|
+
The name of this library. It follows one extraction intent described in a Configuration file, applies one optional runtime-bound Target definition to one or more CLI-supplied directories and/or selects from fixed Companions, and creates a ZIP Archive.
|
|
8
|
+
|
|
9
|
+
## Configuration file
|
|
10
|
+
|
|
11
|
+
A TOML file describing one extraction intent for one dirpluck invocation. It contains zero or one Target definition, zero or more Companions, at least one source in total, and one Output definition. A Configuration may use one flat named Case to vary source selections without changing source membership, Companion paths, or Output policy. Configuration discovery is limited to the cwd and `./dirpluck/`; if the same filename exists in both places, it is ambiguous and rejected.
|
|
12
|
+
|
|
13
|
+
## Target
|
|
14
|
+
|
|
15
|
+
An optional runtime-bound source definition applied to one or more directories supplied from the CLI. Its default extraction settings may be written directly in `[target]`, with independent named alternatives under `[target.case.<name>]`. A Target never has a fixed `path` in the Configuration, and TOML still defines at most one Target rule. If a Configuration defines a Target, at least one `DIRECTORY` is required and the same selected rule is applied to every supplied directory; otherwise no `DIRECTORY` may be supplied.
|
|
16
|
+
|
|
17
|
+
## Case
|
|
18
|
+
|
|
19
|
+
One flat named selection variation shared by a Configuration's sources and selected with `--case <name>`. At most one Case may be active. When a Target exists, it must define the selected Case. A Companion may define the same Case or fall back to its base selection. Without a Target, a Case is valid when at least one Companion defines it. Case selections are complete alternatives rather than inherited differences, and Cases do not change source membership, Companion paths, or Output.
|
|
20
|
+
|
|
21
|
+
## Companion
|
|
22
|
+
|
|
23
|
+
A configuration-bound source with a fixed cwd-relative `path`. It belongs to the Configuration's extraction intent whether or not a Target exists. `[companion.<name>]` contains its base `description` and selection rules. Optional `[companion.<name>.case.<case-name>]` tables provide complete alternative selections for named Cases; when the active Case is absent, the Companion uses its base selection.
|
|
24
|
+
|
|
25
|
+
## Source directory
|
|
26
|
+
|
|
27
|
+
An actual directory from which extraction is performed. One or more Target directories may come from the CLI and all use the same Target definition, while a Companion directory comes from its configured fixed `path`. Every used source directory must exist and resolve within the current working directory. Symbolic-link escapes are rejected. A Target may be the cwd itself, in which case its actual directory name is still preserved in the Archive.
|
|
28
|
+
|
|
29
|
+
## Extraction
|
|
30
|
+
|
|
31
|
+
The process of determining which files from a Target or Companion belong in the Archive. `include` lists required relative paths, `include_if_exists` lists optional candidates that are added only when present, and `exclude` applies limited name filters inside selected areas. At least one of `include` or `include_if_exists` is required. `if_empty = "allow"` is valid only when there are no required `include` patterns.
|
|
32
|
+
|
|
33
|
+
## Archive
|
|
34
|
+
|
|
35
|
+
The ZIP output generated by dirpluck. Selected files keep their actual cwd-relative filesystem paths, and a generated `README.md` is written at the Archive root. If multiple sources resolve to the same actual directory, their selected files are unioned by real archive path and are not duplicated.
|
|
36
|
+
|
|
37
|
+
## Output definition
|
|
38
|
+
|
|
39
|
+
The required `[output]` settings. Fixed output declares a cwd-relative `path` plus `if_exists = "error" | "overwrite"`. Generated output declares `directory`, `timestamp = true`, and optional `prefix` / `suffix`; it creates a timestamped ZIP name, rejects an already-existing destination during normal execution, and may accept an explicit CLI `--sequence N` after the timestamp. dirpluck does not auto-number generated outputs, coordinate concurrent writes to the same path, or temporarily override the Output form from the CLI.
|
|
40
|
+
|
|
41
|
+
## Archive README
|
|
42
|
+
|
|
43
|
+
The purpose-neutral index document generated as the Archive-root `README.md`. It records the active Case, included directories, Target or Companion descriptions, selected Configuration locations, directory sources, selected-file counts, and empty-result policies when relevant. Its fixed wording does not name the generating tool or prescribe a downstream use; concrete purpose comes from the configured descriptions. If multiple roles resolve to the same actual directory, that directory is indexed once and each role is recorded separately.
|
dirpluck-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 minoru_jp
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
include README.md
|
|
2
|
+
include CONFIGURATION.md
|
|
3
|
+
include GLOSSARY.md
|
|
4
|
+
include SPECIFICATION.md
|
|
5
|
+
include CHANGELOG.md
|
|
6
|
+
include LICENSE
|
|
7
|
+
include pyproject.toml
|
|
8
|
+
recursive-include src *.py *.md
|
|
9
|
+
recursive-include tests *.py
|
|
10
|
+
prune _internal
|
|
11
|
+
prune .github
|
|
12
|
+
exclude .gitignore
|
|
13
|
+
global-exclude __pycache__ *.py[cod] .DS_Store
|