1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
//! # Neverest
//!
//! A CLI synchronizing PIM collections between backends, and the crate
//! architecture (header-001): the behavioural contract lives in cairn/spec/,
//! the history in cairn/log/, the shared conventions in the [Pimalaya
//! ARCHITECTURE][pimalaya]. Where header and code disagree, the code wins.
//!
//! [pimalaya]: https://github.com/pimalaya/.github/blob/master/ARCHITECTURE.md
//!
//! ## Place in the stack
//!
//! An application, the top of the stack: it writes no protocol and no
//! storage logic of its own, orchestrating the layers below and rendering
//! what they return.
//!
//! The reconcile and the local replica are both [io-pimdir]'s: the engine
//! owns the three-way merge, the checkpoints, the push outcomes, the object
//! dedup and the multi-source hub, and the store is a SQLite index beside a
//! content-addressed blob directory servicing the engine's storage seam.
//!
//! The protocols are io-imap, io-webdav and io-msgraph, behind the lean
//! adapters in [`imap`], [`dav`] and [`msgraph`]. Around them, pimalaya-cli,
//! pimalaya-config and pimalaya-stream supply the CLI, the TOML loading and
//! the blocking runtime; the wizard discovers through [io-pim-discovery].
//!
//! ## The topology mismatch
//!
//! The load-bearing design point. The engine is local-replica-centric: one
//! local replica against one remote, merged three ways against a
//! per-placement base, its sync verb tying one collection to one remote's
//! enumerate. neverest is peer-to-peer, several sources reaching each other.
//!
//! So calling sync twice cannot replicate both ways. The resolution is the
//! multi-source hub: an account's sources are the sources of one shared
//! collection in one pimdir store, and a load projects the shared item
//! against that source's own base.
//!
//! A change one source folds in therefore reads as locally dirty for the
//! others, whose ordinary reconcile pushes it. Cross-source propagation of
//! items, flags and deletions falls out of the per-source merge, leaving
//! neverest to sequence the coroutines until quiescent.
//!
//! ## Namespaces
//!
//! An account is one hub but not one collection space: a hub collection id
//! is `<namespace>/<name>`, and the namespace is the source's own name, so
//! mail and contacts under one account, or two providers cached side by
//! side, never meet. It is derived, never configured.
//!
//! Which endpoints meet is the account's arity: a pairing binds both into
//! the source's namespace, and an item there with no binding for the other
//! is pushed to it. What the store keeps is `retain`, and a crossing between
//! two streamable endpoints is streamed rather than staged.
//!
//! ## The kind seam
//!
//! Everything above [`client`] is kind-neutral, speaking collections and
//! items rather than mailboxes and messages, so a contacts or calendar
//! backend implements the same surface while each adapter keeps its own
//! nouns behind it: an IMAP mailbox stays a mailbox inside [`imap`].
//!
//! What varies per media type lives in [`kind`]: an item's link id, its
//! typed summary and sort key, which io-pimdir derives, and the three-way
//! merge a content conflict is resolved by, which is here so the engine
//! keeps knowing nothing about merging formats.
//!
//! The kind a source syncs comes from its backend's media type and is
//! recorded on the pimdir collection, so one store may hold several.
//!
//! ## Layout
//!
//! [`cli`] holds the clap parser, one module per subcommand, and the outcome
//! a command exits with: a run that reconciled everything and still left a
//! parked conflict or a refused write is neither a success nor a failure, so
//! it carries a code of its own back to `main`.
//!
//! [`config`] is the TOML schema and [`account`] its runtime counterpart,
//! the endpoints with every secret already resolved, which [`client`], the
//! kind-neutral backend seam, opens a connection from. [`item`] is the
//! vocabulary above that seam, [`kind`] the per-media-type derivations.
//!
//! [`conflict`] is the other end of that merge: the divergences it could not
//! settle, the decision a person makes about one, and the guard refusing a
//! decision the store moved out from under. Deciding is a command and never
//! a run, so nothing there is reachable from a sync.
//!
//! [`offline`] is the sync engine: `mod` maps sources onto pimdir source
//! ids, `state` records what the last run derived, `storage` projects and
//! hydrates one source, `remote` implements io-pimdir's remote seam,
//! `submit` holds the queued send, and `driver` builds the report.
//!
//! [`sync`] keeps the output types alone, the engine having moved to
//! [`offline`], and [`wizard`] discovers an account from one prompt.
//!
//! What becomes of that account belongs to `cli::configure`, which generates
//! and never edits: it appends the rendered table rather than re-serializing
//! the document, so a hand-written configuration keeps its comments.
//!
//! [`json_schema`] is the registry behind `neverest json-schema`: one entry
//! per data command, mapping its invocation path to the schema of what it
//! prints under `--json`.
//!
//! [io-pimdir]: https://github.com/pimalaya/io-pimdir
//! [io-pim-discovery]: https://github.com/pimalaya/io-pim-discovery
use ;
use Result;
use ;
use ;
use TomlConfig;
use crate::;
/// Meets a bare `neverest`, which is where a newcomer lands.
///
/// A missing configuration raises the offer; anything else gets the help.
/// A broken file counts as a configuration, so the offer never writes over
/// one, and `--account` alone is a half-typed command, not a first run.