pub struct GitSource { /* private fields */ }Expand description
A file in a git repository, as a configuration source.
Built with GitSource::builder. Not Clone: the working directory is
claimed by one source, and two clones fetching into it would interleave
their ref updates. Wrap it in an Arc if two places need one.
Implementations§
Source§impl GitSource
impl GitSource
Sourcepub fn builder(url: impl Into<String>) -> Builder
pub fn builder(url: impl Into<String>) -> Builder
A source reading from the repository at url.
url is anything git understands: https://…, ssh://…,
git@host:org/repo.git, or a local path.
Sourcepub fn watch<F>(
&self,
watching: &Watching,
interval: Duration,
on_change: F,
) -> Result<(), Error>
pub fn watch<F>( &self, watching: &Watching, interval: Duration, on_change: F, ) -> Result<(), Error>
Calls on_change when the ref moves, checking every interval.
Polling, because git offers nothing better — and advertisement polling, because transferring a commit every tick to discover it has not changed would be a poor thing to do to a git host. Each tick is one handshake and one ref advertisement; only a ref that moved costs a transfer.
The current value is not delivered at startup, for the same reason a file watcher does not report an edit when it starts. Fetch first if the starting value matters, which it usually does:
sink.apply(source.fetch()?)?;
source.watch(&watching, Duration::from_secs(60), move |document| sink.apply(document))A host that is away, a ref that has been deleted, a document that does
not parse — none of those end the watch. It waits out the interval and
tries again. stop is noticed within a quarter second regardless of how
long interval is.
§A source reading several files can be watched
It is the only one in this family that can. Every other store refuses a watch on a set, and the reason is written down: waking on a change to one key and then re-reading key by key collects the new value of that key and whatever the others happen to be halfway through a deployment — a document that never existed at any instant, installed and then served until the next change.
Neither half of that applies here. What moves is a ref, and what a ref names is a commit — so the watch does not wake on one file, it wakes on the repository, and the re-read that follows takes every file out of that one commit’s tree. A deployment that writes four files in one commit is delivered as one document; a deployment that writes them in four commits is delivered as up to four documents, each of which is a state the repository really was in. There is no interleaving to be had.
The cost is the other direction, and it is the same cost a single-file
watch has always had: a commit that touches nothing this source reads
still moves the ref, so on_change is called with a document identical
to the last one. A spurious delivery, never a torn one — dynamic-config
diffs it and reports no changes.
§Errors
If the host refuses a credential that cannot be replaced — a token
handed in as a constant is the same token next tick, so retrying it
forever would be a hot loop against a host that may well start locking
the account. A credential that came from a closure is refreshed and
retried instead, and only ends the watch if the fresh one is refused
too. Or if on_change returns an error, which ends the watch — so a
caller that wants to survive a bad document should log it and return
Ok.
Trait Implementations§
Source§impl RemoteSource for GitSource
impl RemoteSource for GitSource
Source§fn watch_capability(&self) -> WatchCapability
fn watch_capability(&self) -> WatchCapability
Conditional: a ref advertisement says where the branch points without fetching the objects behind it.