pub struct Builder { /* private fields */ }Expand description
Collects what a GitSource needs, and refuses what it cannot use.
Everything that can be wrong about a source — a path that escapes the
repository, a format nothing can infer, a commit id that is not one, a
working directory another source already holds — is decided here, at
build, rather than at the first fetch. A configuration
mistake should fail where it was made.
Implementations§
Source§impl Builder
impl Builder
Sourcepub fn branch(self, name: impl Into<String>) -> Self
pub fn branch(self, name: impl Into<String>) -> Self
Reads from a branch, by short name. main unless this is called.
Sourcepub fn commit(self, sha: impl Into<String>) -> Self
pub fn commit(self, sha: impl Into<String>) -> Self
Reads from one commit, by full hexadecimal object id.
Reproducible, and static: nothing will ever move, so a watch on a pinned commit will never fire.
Sourcepub fn path(self, path: impl Into<Keys>) -> Self
pub fn path(self, path: impl Into<Keys>) -> Self
What to read: a file, or a Keys for several of them.
A path is /-separated and relative to the repository root. Required.
// One file — what a bare string has always meant.
GitSource::builder("https://github.com/acme/config.git")
.path("services/api/config.yaml")
.build()?;
// Several, merged in this order: `local` wins where they overlap.
GitSource::builder("https://github.com/acme/config.git")
.path(Keys::several([
"services/api/base.yaml",
"services/api/local.yaml",
]))
.build()?;
// A directory of disjoint sections, where an overlap is a mistake.
GitSource::builder("https://github.com/acme/config.git")
.path(Keys::prefix("services/api"))
.format(dynamic_config::Format::Yaml)
.build()?;Sourcepub fn format(self, format: Format) -> Self
pub fn format(self, format: Format) -> Self
The format to parse the files as.
Inferred from the extension when this is not called, so config.yaml
needs nothing. Call it for a file whose name does not say — .config,
or no extension at all — for a Keys::Several whose members name two
different formats, and always for Keys::Prefix, because a directory
has no extension to read.
One source reads one format. A caller who wants a JSON file and a TOML file has two sources, which already works.
Sourcepub fn credential(self, credential: Credential) -> Self
pub fn credential(self, credential: Credential) -> Self
How to authenticate. Anonymous — a public repository — by default.
See Credential; the short version is that anything that expires
should come from Credential::expiring rather than be pasted in as a
string.
Sourcepub fn tls(self, tls: TlsConfig) -> Self
pub fn tls(self, tls: TlsConfig) -> Self
How to trust an https:// host this machine does not already trust,
and how to prove who is asking.
For an enterprise GitLab behind a private certificate authority, and for a host that wants a client certificate before it will say hello. The platform’s own trust store still applies, so one source configuration reaches both a private host and github.com.
GitSource::builder("https://gitlab.internal/acme/config.git")
.path("services/api/config.yaml")
.tls(
TlsConfig::new()
.with_ca_certificate_file("/etc/ssl/certs/acme-root.pem")
.with_client_certificate_files("/etc/ssl/app.crt", "/etc/ssl/app.key"),
)
.build()?;This is the https:// knob and only that one. An ssh:// remote
authenticates its host through known_hosts and its client through a
key, which is Credential::ssh_agent, Credential::ssh_key or
Credential::ssh_command; asking for both is refused at
build rather than half-applied.
There is no way to turn verification off, and tls argues
why at length — the short version being that a fetch presents its
credential before it has received anything, so an unverified connection
is one that hands a token to whoever is on the path.
Configuring this replaces gix’s HTTP transport with one this crate
builds, because gix’s ignores every TLS option it is given; see
tls for what was measured. Leaving it alone changes
nothing.
Sourcepub fn cache_dir(self, path: impl Into<PathBuf>) -> Self
pub fn cache_dir(self, path: impl Into<PathBuf>) -> Self
Keeps the object database here, instead of in a temporary directory.
It survives restarts, so a restarted process transfers almost nothing.
In exchange the caller owns its size; see working.
Sourcepub fn with_timeout(self, timeout: Duration) -> Self
pub fn with_timeout(self, timeout: Duration) -> Self
How long one fetch may take before it is given up on. Thirty seconds by default.
The deadline for one fetch attempt, excluding retries the underlying client performs — the same sentence every store in this family answers to. What it reaches depends on which transport the source uses, and this crate owes the reader the table rather than the sentence:
| Phase | With tls — this crate’s transport | Without — gix’s own |
|---|---|---|
| connecting | this number | twenty seconds, gix’s, not configurable |
| the handshake and the ref advertisement | this number, per read | unbounded |
| negotiation and the pack | this number, per read | this number |
gix takes an interrupt flag and checks it between packets, which is a
real deadline for the part that transfers data and no deadline at all
for a host that accepts the connection and then sends nothing — there
are no packets for the check to be between. Its reqwest transport
reads none of the timeouts its own options type carries, so that column
is not this crate’s to fix from outside; tls records what
was measured and what closing it would have cost everybody else.
Sourcepub fn max_bytes(self, bytes: u64) -> Self
pub fn max_bytes(self, bytes: u64) -> Self
The largest single file this source will read, in bytes. A megabyte by default.
Checked against the object header before any of the file is loaded, so
a repository offering a two-gigabyte blob costs an error rather than the
memory. Per file rather than per document: a Keys::Prefix read is
bounded by this and by the five-hundred-and-twelve-file budget together.
Sourcepub fn compact_after(self, transfers: u32) -> Self
pub fn compact_after(self, transfers: u32) -> Self
How many transfers a working directory may accumulate before it is
emptied and refilled by the next fetch. Thirty-two by default; 0
turns it off.
A shallow fetch of a moving branch adds a pack every time the branch moves and removes nothing, so a watcher left running grows without bound. Compaction is how that is answered, and it is a visible trigger on purpose: a store that deletes things should be a store the caller can see deleting them, and can stop.
Only ever a directory this crate created. A cache_dir
pointing at a repository that already existed is never touched,
whatever this is set to — see working for the rule.
Turn it off for a deployment that would rather run git gc --prune=now on its own cadence.
Sourcepub fn build(self) -> Result<GitSource, Error>
pub fn build(self) -> Result<GitSource, Error>
Builds the source.
§Errors
If no path was given, or a Keys::Several with nothing in it; if any
path is not a path inside the repository — absolute, or with a . or
.. component, or with an empty one; if the format was neither given
nor inferable, or if two paths name two different formats; if a commit
was named that is not a hexadecimal object id; or if the named working
directory already belongs to another source in this program.