fileroute 0.1.2__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.
- fileroute-0.1.2/PKG-INFO +493 -0
- fileroute-0.1.2/README.md +472 -0
- fileroute-0.1.2/fileroute/__init__.py +13 -0
- fileroute-0.1.2/fileroute/auth/__init__.py +17 -0
- fileroute-0.1.2/fileroute/auth/google.py +178 -0
- fileroute-0.1.2/fileroute/auth/microsoft.py +126 -0
- fileroute-0.1.2/fileroute/auth/settings.py +220 -0
- fileroute-0.1.2/fileroute/auth/token_store.py +24 -0
- fileroute-0.1.2/fileroute/cli.py +40 -0
- fileroute-0.1.2/fileroute/clients/__init__.py +24 -0
- fileroute-0.1.2/fileroute/clients/base.py +59 -0
- fileroute-0.1.2/fileroute/clients/googledrive.py +963 -0
- fileroute-0.1.2/fileroute/clients/s3.py +301 -0
- fileroute-0.1.2/fileroute/clients/sharepoint.py +792 -0
- fileroute-0.1.2/fileroute/commands/__init__.py +9 -0
- fileroute-0.1.2/fileroute/commands/auth.py +156 -0
- fileroute-0.1.2/fileroute/commands/config.py +38 -0
- fileroute-0.1.2/fileroute/commands/descriptor.py +445 -0
- fileroute-0.1.2/fileroute/commands/diagram.py +63 -0
- fileroute-0.1.2/fileroute/commands/toolkit.py +134 -0
- fileroute-0.1.2/fileroute/descriptor.py +286 -0
- fileroute-0.1.2/fileroute/diagram.py +335 -0
- fileroute-0.1.2/fileroute/diagram_reports.py +258 -0
- fileroute-0.1.2/fileroute/exceptions.py +65 -0
- fileroute-0.1.2/fileroute/item.py +332 -0
- fileroute-0.1.2/fileroute/migration.py +157 -0
- fileroute-0.1.2/fileroute/models.py +179 -0
- fileroute-0.1.2/fileroute/transfer.py +262 -0
- fileroute-0.1.2/fileroute.egg-info/PKG-INFO +493 -0
- fileroute-0.1.2/fileroute.egg-info/SOURCES.txt +56 -0
- fileroute-0.1.2/fileroute.egg-info/dependency_links.txt +1 -0
- fileroute-0.1.2/fileroute.egg-info/entry_points.txt +2 -0
- fileroute-0.1.2/fileroute.egg-info/requires.txt +15 -0
- fileroute-0.1.2/fileroute.egg-info/top_level.txt +1 -0
- fileroute-0.1.2/pyproject.toml +154 -0
- fileroute-0.1.2/setup.cfg +4 -0
- fileroute-0.1.2/tests/test_activate.py +27 -0
- fileroute-0.1.2/tests/test_add.py +141 -0
- fileroute-0.1.2/tests/test_clients.py +44 -0
- fileroute-0.1.2/tests/test_clone.py +163 -0
- fileroute-0.1.2/tests/test_descriptor.py +120 -0
- fileroute-0.1.2/tests/test_diagram.py +102 -0
- fileroute-0.1.2/tests/test_diagram_reports.py +195 -0
- fileroute-0.1.2/tests/test_google_auth.py +173 -0
- fileroute-0.1.2/tests/test_google_auth_settings.py +102 -0
- fileroute-0.1.2/tests/test_googledrive_client.py +374 -0
- fileroute-0.1.2/tests/test_item.py +387 -0
- fileroute-0.1.2/tests/test_migration.py +107 -0
- fileroute-0.1.2/tests/test_models.py +33 -0
- fileroute-0.1.2/tests/test_release.py +177 -0
- fileroute-0.1.2/tests/test_resolution.py +145 -0
- fileroute-0.1.2/tests/test_s3_client.py +260 -0
- fileroute-0.1.2/tests/test_sharepoint_auth.py +80 -0
- fileroute-0.1.2/tests/test_sharepoint_auth_settings.py +114 -0
- fileroute-0.1.2/tests/test_sharepoint_client.py +465 -0
- fileroute-0.1.2/tests/test_transfers.py +345 -0
- fileroute-0.1.2/tests/test_update.py +268 -0
- fileroute-0.1.2/tests/test_yaml_roundtrip.py +72 -0
fileroute-0.1.2/PKG-INFO
ADDED
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fileroute
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Convenient connectors to make interoperating and collaborating across multiple content management systems easier
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: pydantic>=2.10.6
|
|
8
|
+
Requires-Dist: pydantic-settings>=2.7.0
|
|
9
|
+
Requires-Dist: ruamel.yaml<0.20,>=0.19.1
|
|
10
|
+
Requires-Dist: requests>=2.32.3
|
|
11
|
+
Requires-Dist: python-dotenv>=1.0.1
|
|
12
|
+
Requires-Dist: typer>=0.24.1
|
|
13
|
+
Requires-Dist: boto3>=1.42.55
|
|
14
|
+
Requires-Dist: google-auth-oauthlib>=1.2.1
|
|
15
|
+
Requires-Dist: google-auth>=2.0
|
|
16
|
+
Requires-Dist: rich>=13.0
|
|
17
|
+
Requires-Dist: msal>=1.33.0
|
|
18
|
+
Provides-Extra: docs
|
|
19
|
+
Requires-Dist: mkdocs>=1.6.1; extra == "docs"
|
|
20
|
+
Requires-Dist: mkdocs-material>=9.7.1; extra == "docs"
|
|
21
|
+
|
|
22
|
+
# fileroute
|
|
23
|
+
|
|
24
|
+
Fileroute describes where project artifacts come from, where they live locally,
|
|
25
|
+
and where they should be published. A small YAML or JSON catalog connects local
|
|
26
|
+
files with SharePoint, Google Drive, and S3 URLs, so a document or data export
|
|
27
|
+
can keep its provenance and multiple destinations in one place. The CLI can
|
|
28
|
+
preview changes without credentials, visualize descriptor workflows as SVG, HTML,
|
|
29
|
+
or Markdown, pull remote inputs, and push supported outputs; the same descriptor, graph, and
|
|
30
|
+
transfer APIs are available from Python. Use it inside a project for repeatable,
|
|
31
|
+
versioned workflows, or run it as a standalone tool to inspect and retrieve
|
|
32
|
+
individual files. Python 3.11 or newer is required.
|
|
33
|
+
|
|
34
|
+
## Choose how to run it
|
|
35
|
+
|
|
36
|
+
**Within a project:** add Fileroute to that project's dependencies, commit its
|
|
37
|
+
`uv.lock` and descriptor, and run commands from the project root. `uv run` uses
|
|
38
|
+
the project's environment and resolves its declared dependencies before running
|
|
39
|
+
the command. This is the better fit for automation and Python API imports.
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
uv add git+https://github.com/mbkranz/fileroute.git@dev
|
|
43
|
+
uv run fileroute diagram config/fileroute.yaml
|
|
44
|
+
uv run fileroute pull config/fileroute.yaml --dry-run
|
|
45
|
+
uv run fileroute push config/fileroute.yaml --dry-run
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Use a commit SHA instead of `dev` in the Git dependency for a fixed revision,
|
|
49
|
+
or `uv add ./path/to/fileroute` when developing against a local checkout. See
|
|
50
|
+
uv's [project command guide](https://docs.astral.sh/uv/concepts/projects/run/)
|
|
51
|
+
and [dependency guide](https://docs.astral.sh/uv/concepts/projects/dependencies/).
|
|
52
|
+
|
|
53
|
+
**As a standalone tool:** `uvx` (an alias for `uv tool run`) runs Fileroute in
|
|
54
|
+
its own cached, disposable environment, separate from any project environment.
|
|
55
|
+
It reads descriptor paths and files from your current working directory, but it
|
|
56
|
+
does not add Fileroute to the project's dependencies or make it importable by
|
|
57
|
+
that project's Python code. Use this for ad hoc CLI operations:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
uvx --from git+https://github.com/mbkranz/fileroute.git@dev fileroute list config/fileroute.yaml
|
|
61
|
+
uvx --from git+https://github.com/mbkranz/fileroute.git@dev fileroute diagram config/fileroute.yaml
|
|
62
|
+
uvx --from git+https://github.com/mbkranz/fileroute.git@dev fileroute pull config/fileroute.yaml --dry-run
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Once the intended Fileroute distribution is available from your package index,
|
|
66
|
+
the shorter forms include `uvx fileroute diagram config/fileroute.yaml` and
|
|
67
|
+
`uvx fileroute list config/fileroute.yaml` (or `uvx fileroute --help`). For a
|
|
68
|
+
fixed tool version, pin the package version or Git commit. See uv's
|
|
69
|
+
[tool guide](https://docs.astral.sh/uv/concepts/tools/).
|
|
70
|
+
|
|
71
|
+
To develop this repository itself:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
uv sync
|
|
75
|
+
uv run fileroute --help
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Configure credentials using `.env-sample`. SharePoint uses the `AZURE_*` and
|
|
79
|
+
`SHAREPOINT_*` settings; Google supports ADC, service accounts, and user OAuth;
|
|
80
|
+
S3 uses the standard AWS credential chain. Descriptor loading, diagramming, and
|
|
81
|
+
dry runs do not authenticate.
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
fileroute auth login gdrive
|
|
85
|
+
fileroute auth login microsoft --auth-mode delegated
|
|
86
|
+
fileroute auth login sharepoint --auth-mode delegated
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
See [descriptor diagrams](docs/diagram.md),
|
|
90
|
+
[Google authentication](docs/google-auth.md), and the generated
|
|
91
|
+
[CLI](docs/cli.md) and [Python API](docs/api.md) references.
|
|
92
|
+
|
|
93
|
+
## Descriptor model
|
|
94
|
+
|
|
95
|
+
Four models define the public descriptor API: `Catalog`, `Resource`, `Location`,
|
|
96
|
+
and `CatalogReference`. A catalog groups resources and nested catalogs. A
|
|
97
|
+
resource describes one artifact. Sources and targets are lists of locations.
|
|
98
|
+
|
|
99
|
+
| Field | Meaning |
|
|
100
|
+
| --- | --- |
|
|
101
|
+
| `path` | Artifact location; a local file/directory for transfers |
|
|
102
|
+
| `sources` | Upstream inputs or provenance, including local authoring files |
|
|
103
|
+
| `targets` | Downstream publication destinations |
|
|
104
|
+
| `serviceType` | Optional location provider: `GoogleDrive`, `SharePoint`, or `S3` |
|
|
105
|
+
| `serviceId` | Optional provider-native identifier on a location |
|
|
106
|
+
| `$ref` | Another local catalog document, resolved beside its containing document |
|
|
107
|
+
|
|
108
|
+
For example, a rendered Word document can identify its Quarto source without
|
|
109
|
+
making that source a publication destination:
|
|
110
|
+
|
|
111
|
+
```yaml
|
|
112
|
+
$schema: fileroute-catalog
|
|
113
|
+
catalogs:
|
|
114
|
+
- name: documentation
|
|
115
|
+
path: docs/_output
|
|
116
|
+
targets:
|
|
117
|
+
- path: https://contoso.sharepoint.com/sites/dev/Shared%20Documents/Docs
|
|
118
|
+
serviceType: SharePoint
|
|
119
|
+
resources:
|
|
120
|
+
- name: guide
|
|
121
|
+
path: docs/_output/guide.docx
|
|
122
|
+
sources:
|
|
123
|
+
- path: docs/guide.qmd
|
|
124
|
+
- name: internal
|
|
125
|
+
path: docs/_output/internal.docx
|
|
126
|
+
targets: []
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
A retrieval descriptor explicitly identifies its remote source:
|
|
130
|
+
|
|
131
|
+
```yaml
|
|
132
|
+
resources:
|
|
133
|
+
- name: source-export
|
|
134
|
+
path: downloads/source.csv
|
|
135
|
+
sources:
|
|
136
|
+
- path: s3://my-bucket/exports/source.csv
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
All artifact paths are relative to the **working directory**, even when the
|
|
140
|
+
descriptor is in `config/` or references another descriptor. The Python planners
|
|
141
|
+
also accept an explicit `root`. Paths are preserved when loading and saving.
|
|
142
|
+
Transfers reject paths outside that root and symbolic links.
|
|
143
|
+
|
|
144
|
+
Reference paths are the exception: `$ref` is relative to the containing
|
|
145
|
+
**descriptor's directory**. References stay references on normal load/save. Transfer planning explicitly
|
|
146
|
+
expands them once; they cannot escape the containing directory. Cycles raise an error.
|
|
147
|
+
|
|
148
|
+
```yaml
|
|
149
|
+
catalogs:
|
|
150
|
+
- name: research
|
|
151
|
+
$ref: catalogs/research.yaml
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Unrecognized metadata fields survive model round trips. Existing YAML descriptors
|
|
155
|
+
are round-trip edited where practical, retaining comments and authored styles.
|
|
156
|
+
This is a Fileroute format inspired by Data Package
|
|
157
|
+
and DCAT, not a full implementation of either standard. `$schema` is an optional
|
|
158
|
+
profile label; loading does not fetch a schema from the network.
|
|
159
|
+
|
|
160
|
+
## Common use cases
|
|
161
|
+
|
|
162
|
+
Each resource has one local artifact `path`. Its `sources` record where the
|
|
163
|
+
artifact came from; its `targets` list every intended publication destination.
|
|
164
|
+
One resource can have multiple targets. `pull` downloads **one remote source**
|
|
165
|
+
to `path`, and `push` uploads the file at `path` to **all targets**. Run them as
|
|
166
|
+
separate steps; Fileroute does not stream directly between cloud providers or
|
|
167
|
+
convert source formats. These examples can be saved as `config/fileroute.yaml`.
|
|
168
|
+
|
|
169
|
+
### One SharePoint source and two SharePoint targets
|
|
170
|
+
|
|
171
|
+
Retrieve a report to the project, then publish copies to two SharePoint sites:
|
|
172
|
+
|
|
173
|
+
```yaml
|
|
174
|
+
resources:
|
|
175
|
+
- name: monthly-report
|
|
176
|
+
path: artifacts/monthly-report.csv
|
|
177
|
+
sources:
|
|
178
|
+
- path: https://contoso.sharepoint.com/sites/data/Shared%20Documents/monthly-report.csv
|
|
179
|
+
targets:
|
|
180
|
+
- path: https://contoso.sharepoint.com/sites/reports/Shared%20Documents/monthly-report.csv
|
|
181
|
+
- path: https://contoso.sharepoint.com/sites/archive/Shared%20Documents/monthly-report.csv
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
For this supported combination, run `fileroute pull config/fileroute.yaml`
|
|
185
|
+
and then `fileroute push config/fileroute.yaml`, with `--dry-run` on either
|
|
186
|
+
command to inspect its plan first. Each SharePoint site needs working access.
|
|
187
|
+
|
|
188
|
+
### SharePoint source and Google Drive target
|
|
189
|
+
|
|
190
|
+
Describe retrieval from SharePoint and intended publication to Google Drive:
|
|
191
|
+
|
|
192
|
+
```yaml
|
|
193
|
+
resources:
|
|
194
|
+
- name: partner-report
|
|
195
|
+
path: artifacts/partner-report.csv
|
|
196
|
+
sources:
|
|
197
|
+
- path: https://contoso.sharepoint.com/sites/data/Shared%20Documents/partner-report.csv
|
|
198
|
+
targets:
|
|
199
|
+
- path: https://drive.google.com/file/d/GOOGLE_FILE_ID/view
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### SharePoint source, SharePoint and Google Drive targets
|
|
203
|
+
|
|
204
|
+
Use the same local copy for a supported SharePoint publication and a planned
|
|
205
|
+
Google Drive publication:
|
|
206
|
+
|
|
207
|
+
```yaml
|
|
208
|
+
resources:
|
|
209
|
+
- name: partner-report
|
|
210
|
+
path: artifacts/partner-report.csv
|
|
211
|
+
sources:
|
|
212
|
+
- path: https://contoso.sharepoint.com/sites/data/Shared%20Documents/partner-report.csv
|
|
213
|
+
targets:
|
|
214
|
+
- path: https://contoso.sharepoint.com/sites/reports/Shared%20Documents/partner-report.csv
|
|
215
|
+
- path: https://drive.google.com/file/d/GOOGLE_FILE_ID/view
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Local authoring source with SharePoint, Google Drive, and S3 targets
|
|
219
|
+
|
|
220
|
+
Keep the input document as provenance while publishing its rendered output:
|
|
221
|
+
|
|
222
|
+
```yaml
|
|
223
|
+
resources:
|
|
224
|
+
- name: guide
|
|
225
|
+
path: docs/_output/guide.docx
|
|
226
|
+
sources:
|
|
227
|
+
- path: docs/guide.qmd
|
|
228
|
+
targets:
|
|
229
|
+
- path: https://contoso.sharepoint.com/sites/docs/Shared%20Documents/guide.docx
|
|
230
|
+
- path: https://drive.google.com/file/d/GOOGLE_FILE_ID/view
|
|
231
|
+
- path: s3://example-docs/guide.docx
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Render `docs/guide.qmd` to `docs/_output/guide.docx` with Quarto before
|
|
235
|
+
publishing. A local source is provenance; `pull` does not render or copy it.
|
|
236
|
+
|
|
237
|
+
**Current transfer support:** SharePoint, Google Drive, and S3 remote sources
|
|
238
|
+
can be pulled; only SharePoint targets can be pushed. A descriptor with a Google
|
|
239
|
+
Drive or S3 target is valid metadata, but `push` **and `push --dry-run` fail at
|
|
240
|
+
planning** until upload support is implemented. If you need the SharePoint
|
|
241
|
+
destination now, put it in a separate descriptor (or remove the unsupported
|
|
242
|
+
targets) for that run. `resolve` and `diagram` can still resolve those providers
|
|
243
|
+
and inspect the descriptor without authentication. Source and target URLs above
|
|
244
|
+
are examples; replace them with your own accessible files and sites.
|
|
245
|
+
|
|
246
|
+
## Visualize file workflows
|
|
247
|
+
|
|
248
|
+
`diagram` renders descriptor intent rather than executing a transfer. It expands
|
|
249
|
+
local `$ref` catalogs, resolves known provider URLs in memory, applies catalog
|
|
250
|
+
target inheritance, and draws sources → artifacts → targets as a standalone SVG.
|
|
251
|
+
It does not require Graphviz or another rendering dependency.
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
fileroute diagram config/fileroute.yaml
|
|
255
|
+
fileroute diagram config/fileroute.yaml --output docs/fileroute-workflow.svg
|
|
256
|
+
fileroute diagram config/fileroute.yaml --output docs/fileroute-workflow.html
|
|
257
|
+
fileroute diagram config/fileroute.yaml --output docs/fileroute-workflow.md --detail full
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
HTML provides a searchable offline file dictionary linked to diagram nodes; Markdown
|
|
261
|
+
writes an anchored dictionary and companion SVG. `--detail summary` exports curated
|
|
262
|
+
metadata; `--detail full` includes custom fields and service IDs. Inherited targets
|
|
263
|
+
identify their declaring catalog. Reports link to HTTP(S) locations but do not
|
|
264
|
+
preview file contents or authenticate. See the diagram guide for anchor stability
|
|
265
|
+
and duplicate-identity behavior.
|
|
266
|
+
|
|
267
|
+
The descriptor argument follows the same saved/default selection behavior as
|
|
268
|
+
`pull`, `push`, and `resolve`, so after `fileroute activate` you can simply run
|
|
269
|
+
`fileroute diagram`. The default output is `fileroute-diagram.svg` in the
|
|
270
|
+
current working directory. See [Descriptor diagrams](docs/diagram.md) for the
|
|
271
|
+
Python `DescriptorGraph` API and repository-integration guidance.
|
|
272
|
+
|
|
273
|
+
## Commands
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
fileroute add export --path downloads/source.csv --source s3://my-bucket/source.csv
|
|
277
|
+
fileroute add documentation --catalog --path docs/_output --target https://contoso.sharepoint.com/sites/dev/Docs
|
|
278
|
+
fileroute list config/fileroute.yaml --format json
|
|
279
|
+
fileroute activate config/fileroute.yaml
|
|
280
|
+
fileroute update --name documentation --title "Published documentation"
|
|
281
|
+
fileroute resolve config/fileroute.yaml
|
|
282
|
+
fileroute resolve config/fileroute.yaml --write
|
|
283
|
+
fileroute diagram config/fileroute.yaml
|
|
284
|
+
fileroute migrate old.yaml new.yaml --direction push
|
|
285
|
+
fileroute pull config/fileroute.yaml --dry-run
|
|
286
|
+
fileroute push config/fileroute.yaml --dry-run
|
|
287
|
+
fileroute push config/fileroute.yaml
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
`activate` saves the active descriptor in `.fileroute/descriptor`.
|
|
291
|
+
The optional descriptor argument also accepts an explicit override. `update`
|
|
292
|
+
selects an exact name or dot-path and reports ambiguous names; `clone descriptor`
|
|
293
|
+
copies a single authored document. For a resource with one source,
|
|
294
|
+
`update --name export --service-type S3` edits that source's provider.
|
|
295
|
+
Edit `sources`/`targets` in YAML for more involved changes, or supply a JSON array
|
|
296
|
+
using `--sources`/`--targets`.
|
|
297
|
+
|
|
298
|
+
### Resolve URLs
|
|
299
|
+
|
|
300
|
+
`resolve` previews canonical JSON without authenticating or contacting a remote
|
|
301
|
+
service. `resolve --write` saves the result to the selected YAML/JSON descriptor.
|
|
302
|
+
It infers `serviceType` from `s3://` URLs, `drive.google.com` / `docs.google.com`,
|
|
303
|
+
and SharePoint hosts, while preserving the original URL exactly as a clickable
|
|
304
|
+
link. For example:
|
|
305
|
+
|
|
306
|
+
```yaml
|
|
307
|
+
path: https://contoso.sharepoint.com/sites/dev/Docs/guide.docx
|
|
308
|
+
serviceType: SharePoint
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
A conflicting explicit provider is an error. Unrecognized target URLs require
|
|
312
|
+
an explicit `serviceType`; local files and general web citations remain valid
|
|
313
|
+
provider-less sources. Pull requires a supported remote source. Resolution
|
|
314
|
+
does not follow redirects, fetch remote IDs, or check remote permissions.
|
|
315
|
+
|
|
316
|
+
Write-back updates only the selected document and preserves `$ref` entries;
|
|
317
|
+
resolve referenced descriptors separately to persist their inferred metadata.
|
|
318
|
+
Repeated resolution is idempotent. Existing YAML comments and styles are retained
|
|
319
|
+
where practical; byte-for-byte whitespace preservation is not guaranteed.
|
|
320
|
+
Transfers expand references and resolve the relevant sources or targets in
|
|
321
|
+
memory, so write-back is optional. `push --dry-run` and `pull --dry-run` provide
|
|
322
|
+
concrete transfer plans; there is no separate `plan` command or stored lockfile.
|
|
323
|
+
|
|
324
|
+
### Push
|
|
325
|
+
|
|
326
|
+
`push` publishes `path` to `targets`.
|
|
327
|
+
Sources are never treated as targets. Only SharePoint uploads are currently
|
|
328
|
+
implemented. Other providers fail during planning, before authentication.
|
|
329
|
+
|
|
330
|
+
- Catalog targets denote existing remote folders. Children inherit those
|
|
331
|
+
targets using paths relative to the declaring catalog's `path` (or the working
|
|
332
|
+
root when no catalog path is given).
|
|
333
|
+
- A child's explicit `targets` replace inherited targets. `targets: []` disables
|
|
334
|
+
publication for that child and its descendants unless a descendant declares
|
|
335
|
+
its own targets.
|
|
336
|
+
- A catalog with children publishes only its declared children. A leaf catalog
|
|
337
|
+
with a path publishes all files in that directory tree.
|
|
338
|
+
- Explicit resource targets are exact file URLs, allowing renaming. Set a
|
|
339
|
+
target's `entityType: Directory` to append the local filename to a folder URL.
|
|
340
|
+
- Multiple targets publish multiple copies. Conflicting files aimed at the same
|
|
341
|
+
destination fail before any transfer.
|
|
342
|
+
|
|
343
|
+
The planner checks all inputs before authentication. SharePoint transfers
|
|
344
|
+
create missing child folders and create/replace files; they never delete remote
|
|
345
|
+
files. Files above Microsoft Graph's 250 MB single-request limit fail planning.
|
|
346
|
+
Dry runs show the proposed destinations without contacting the remote service;
|
|
347
|
+
they cannot verify remote permissions or folder existence.
|
|
348
|
+
|
|
349
|
+
### Pull
|
|
350
|
+
|
|
351
|
+
`pull` materializes one remote `sources` entry into each artifact's `path`.
|
|
352
|
+
A leaf catalog can retrieve a whole remote directory. A catalog with children
|
|
353
|
+
retrieves only those children. Targets never affect retrieval.
|
|
354
|
+
|
|
355
|
+
Multiple sources may represent a transformation, so pull refuses to choose one.
|
|
356
|
+
Local provenance such as `.qmd` inputs is not a download operation: build those
|
|
357
|
+
artifacts with their authoring tool, then push them. Use separate catalogs for
|
|
358
|
+
retrieval and publication when their source semantics differ. Dry runs plan
|
|
359
|
+
remote directories as units; execution enumerates and checks remote file paths
|
|
360
|
+
before writing any files. Pull replaces existing local files at planned paths.
|
|
361
|
+
|
|
362
|
+
## Python API and architecture
|
|
363
|
+
|
|
364
|
+
```python
|
|
365
|
+
from pathlib import Path
|
|
366
|
+
from fileroute import Catalog, Resource, Location
|
|
367
|
+
from fileroute.descriptor import save
|
|
368
|
+
from fileroute.diagram import load_graph, render_svg
|
|
369
|
+
from fileroute.transfer import plan_push, push
|
|
370
|
+
|
|
371
|
+
catalog = Catalog(resources=[Resource(
|
|
372
|
+
name="guide", path="docs/guide.docx",
|
|
373
|
+
sources=[Location(path="docs/guide.qmd")],
|
|
374
|
+
targets=[Location(path="https://contoso.sharepoint.com/sites/dev/Docs/guide.docx")],
|
|
375
|
+
)])
|
|
376
|
+
save(catalog, "config/fileroute.yaml")
|
|
377
|
+
graph = load_graph("config/fileroute.yaml")
|
|
378
|
+
render_svg(graph, "fileroute-diagram.svg")
|
|
379
|
+
plan = plan_push(Path("config/fileroute.yaml"), root=Path.cwd())
|
|
380
|
+
# Inspect plan before transfer.
|
|
381
|
+
push(plan)
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
The core has one module per responsibility:
|
|
385
|
+
|
|
386
|
+
- `models.py`: declarative `Catalog`, `Resource`, `Location`, `CatalogReference`
|
|
387
|
+
and `ServiceType` validation.
|
|
388
|
+
- `descriptor.py`: `load`, `save`, `walk`, `find`, and offline `resolve`.
|
|
389
|
+
- `diagram.py`: semantic descriptor graphs and dependency-free SVG rendering.
|
|
390
|
+
- `diagram_reports.py`: offline HTML inspector and Markdown file dictionary.
|
|
391
|
+
- `migration.py`: explicit one-way conversion of legacy descriptors.
|
|
392
|
+
- `transfer.py`: `plan_pull` / `plan_push`, then `pull` / `push` execution.
|
|
393
|
+
- `item.py`: runtime `ServiceItem` hierarchy.
|
|
394
|
+
- `clients/sharepoint.py`, `clients/googledrive.py`, `clients/s3.py`: provider APIs.
|
|
395
|
+
- `auth/` and `commands/`: credential handling and CLI workflows.
|
|
396
|
+
|
|
397
|
+
After resolution, `location.service_type` is the authoritative `ServiceType`
|
|
398
|
+
enum used directly for provider dispatch. Pydantic accepts aliases such as
|
|
399
|
+
`gdrive` or `google_drive`; saved values are `GoogleDrive`, `SharePoint`, or `S3`.
|
|
400
|
+
Python attributes use `service_type`, `service_id`, and `entity_type`; descriptors
|
|
401
|
+
use `serviceType`, `serviceId`, and `entityType`. No provider-string conversion
|
|
402
|
+
layer or dynamic registry is needed.
|
|
403
|
+
|
|
404
|
+
`ServiceItem` and provider clients retain their runtime roles. Clients own
|
|
405
|
+
provider-specific authentication and HTTP behavior; runtime items expose
|
|
406
|
+
`refresh()`, `children`, `get_path()`, `iter_items()`, `iter_files()`, and
|
|
407
|
+
`download()`. `item.to_catalog()` emits canonical artifact paths and sources.
|
|
408
|
+
Runtime paths remain relative to the provider container. `get_path()` is
|
|
409
|
+
relative to the current item. Parent relationships and recursive traversal use
|
|
410
|
+
a snapshot until refresh or mutation invalidates it.
|
|
411
|
+
|
|
412
|
+
## Breaking API changes
|
|
413
|
+
|
|
414
|
+
Use the four models above and the functions in `descriptor`, `diagram`, and
|
|
415
|
+
`transfer`. Model I/O and traversal methods, `upload.py`, `download.py`,
|
|
416
|
+
`helpers.py`, and the provider registry have been removed. The CLI has no
|
|
417
|
+
`upload` alias or `set` command. Run `activate` again to select a descriptor
|
|
418
|
+
using the new single-path selection file; obsolete saved workflow defaults are
|
|
419
|
+
no longer read.
|
|
420
|
+
|
|
421
|
+
Legacy `Drive*` classes, packages, `_cache`, and artifact-level provider fields
|
|
422
|
+
are unsupported. Update authored descriptors to `path`, `sources`, `targets`,
|
|
423
|
+
`resources`, and `catalogs`; provider metadata belongs on a location. Normal loading has no compatibility shims or automatic legacy conversion. Use
|
|
424
|
+
`fileroute migrate OLD NEW --direction pull|push` for an explicit, one-way
|
|
425
|
+
conversion that preserves the input file.
|
|
426
|
+
|
|
427
|
+
## Development
|
|
428
|
+
|
|
429
|
+
```bash
|
|
430
|
+
poe check
|
|
431
|
+
poe docs-check
|
|
432
|
+
poe docs-update
|
|
433
|
+
poe docs-build
|
|
434
|
+
poe docs-serve
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
Install the task runner with `uv tool install poethepoet==0.48.0`, or use
|
|
438
|
+
`uvx --from poethepoet==0.48.0 poe <task>` for a one-off run. `poe docs-build`
|
|
439
|
+
installs the documentation extra through `uv run`.
|
|
440
|
+
|
|
441
|
+
Provider tests use mocks; they do not prove live tenant permissions or transfers.
|
|
442
|
+
|
|
443
|
+
Field naming references: [Data Resource](https://datapackage.org/standard/data-resource/),
|
|
444
|
+
[DCAT](https://www.w3.org/TR/vocab-dcat-3/), and
|
|
445
|
+
[OpenMetadata Drive Service](https://docs.open-metadata.org/latest/main-concepts/metadata-standard/schemas/entity/services/driveservice).
|
|
446
|
+
|
|
447
|
+
## Package releases
|
|
448
|
+
|
|
449
|
+
Install the repository task runner with `uv tool install poethepoet==0.48.0`,
|
|
450
|
+
then run `poe release-check` for validation and `poe build` for a local wheel
|
|
451
|
+
and source distribution. One-off usage is
|
|
452
|
+
`uvx --from poethepoet==0.48.0 poe release-check`.
|
|
453
|
+
|
|
454
|
+
The `publish-to-pypi.yaml` workflow has three jobs: **prepare**, **publish**, and
|
|
455
|
+
**release**. Pushes to `dev` start or increment a patch development version
|
|
456
|
+
(`1.0.0 → 1.0.1.dev1 → 1.0.1.dev2`). Pushes to `main` promote a prerelease to
|
|
457
|
+
stable, or increment the patch when the source already has a stable version.
|
|
458
|
+
After a stable tag exists, `dev` starts the next patch series. Normal releases
|
|
459
|
+
should not edit the version manually. Merge updated `main` back into `dev`
|
|
460
|
+
when needed to keep the branches' version baselines aligned.
|
|
461
|
+
|
|
462
|
+
`poe release --branch dev --source <full-commit-sha>` runs `scripts/release.py`
|
|
463
|
+
in a clean checkout of that source. It uses `uv version --no-sync` to update
|
|
464
|
+
`pyproject.toml` and `uv.lock`, invokes `poe build`, and creates a local release
|
|
465
|
+
commit and annotated tag. This is the CI preparation command: it changes the
|
|
466
|
+
local checkout but does not push or publish. The workflow first saves the built
|
|
467
|
+
distributions, then atomically pushes the release commit and tag. Both branches
|
|
468
|
+
share one release concurrency group; a stale run fails rather than overwriting
|
|
469
|
+
newer work. Rapid pushes may supersede pending runs; the latest source should
|
|
470
|
+
be released. Workflow pushes use `GITHUB_TOKEN` and do not recursively trigger
|
|
471
|
+
another push workflow.
|
|
472
|
+
|
|
473
|
+
PyPI publication uses Trusted Publishing bound to this repository and
|
|
474
|
+
**`publish-to-pypi.yaml`**. No long-lived PyPI token is needed, and the publish
|
|
475
|
+
job does not require a GitHub environment unless the PyPI publisher is configured
|
|
476
|
+
to expect one. Only stable `main` versions get a GitHub Release, after PyPI succeeds.
|
|
477
|
+
The branch rules must permit the workflow's version commit; rejected pushes
|
|
478
|
+
leave both remote refs unchanged.
|
|
479
|
+
|
|
480
|
+
For a failed publish, use **Re-run failed jobs** on the original Actions run.
|
|
481
|
+
The publish job downloads the saved wheel and source distribution without
|
|
482
|
+
rebuilding. Identical PyPI uploads can be retried, including a partially
|
|
483
|
+
completed upload. A full rerun recognizes the tagged source/branch before
|
|
484
|
+
calculating a version and finds its unexpired artifact in the original workflow
|
|
485
|
+
run by source commit. Existing GitHub Releases
|
|
486
|
+
are left intact. If preparation failed before the atomic push, a fresh attempt
|
|
487
|
+
can rebuild and replace that run's unpublished artifact. If the original
|
|
488
|
+
artifact has expired or been deleted after the push, stop and recover those
|
|
489
|
+
exact files; the workflow deliberately does not rebuild a published version.
|
|
490
|
+
|
|
491
|
+
`poe release-test` exercises the release helper with temporary local Git remotes
|
|
492
|
+
and real uv version changes; distribution builds are mocked. No test publishes
|
|
493
|
+
packages or contacts cloud providers.
|