Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ default = ["max"]
##
## When used in conjunction with `http-client-curl-rustls`, the `openssl` crates will still be compiled, but won't be used. To bypass this, disable
## default dependencies and specify the features yourself.
max = ["hashes", "max-control", "fast", "gitoxide-core-tools-query", "gitoxide-core-tools-corpus", "gitoxide-core-blocking-client", "http-client-curl-openssl"]
max = ["hashes", "max-control", "fast", "gitoxide-core-tools-query", "gitoxide-core-tools-corpus", "gitoxide-core-blocking-client", "http-client-curl-openssl", "experimental"]

## Like `max`, but only Rust is allowed.
##
Expand All @@ -53,7 +53,7 @@ max = ["hashes", "max-control", "fast", "gitoxide-core-tools-query", "gitoxide-c
## This uses Rust's HTTP implementation.
##
## As fast as possible, with TUI progress, progress line rendering with auto-configuration, all transports available but less mature pure Rust HTTP implementation, all `ein` tools, CLI colors and local-time support, JSON output, regex support for rev-specs.
max-pure = ["hashes", "max-control", "http-client-reqwest", "gitoxide-core-blocking-client"]
max-pure = ["hashes", "max-control", "http-client-reqwest", "gitoxide-core-blocking-client", "experimental"]

## Like `max`, but with more control for configuration. See the *Package Maintainers* headline for more information.
## Needs to chose its own hash(es).
Expand Down Expand Up @@ -82,6 +82,10 @@ small = ["hashes", "pretty-cli", "prodash-render-line", "is-terminal"]
## It uses, however, a fully asynchronous networking implementation which can serve a real-world example on how to implement custom async transports.
lean-async = ["hashes", "fast", "tracing", "pretty-cli", "tix", "gitoxide-core-tools", "gitoxide-core-tools-query", "gitoxide-core-tools-corpus", "gitoxide-core-async-client", "prodash-render-line"]

## Enable experimental features in gix for development builds.
## Currently gates the built-in upload-pack for file:// transports.
experimental = ["gix/experimental", "gitoxide-core/experimental"]

#! ### Package Maintainers
#! `*-control` features leave it to you to configure C libraries, involving choices for HTTP transport implementation.
#!
Expand Down
7 changes: 7 additions & 0 deletions crate-status.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,14 @@ The top-level crate that acts as hub to all functionality provided by the `gix-*
* [ ] include-tags when shallow is used (needs separate fetch)
* [ ] prune non-existing shallow commits
* [ ] [bundles](https://git-scm.com/docs/git-bundle)
* [x] in-process `file://` via built-in upload-pack (experimental feature gate, no external process)
* [x] fetch
* [x] shallow (remains shallow, options to adjust shallow boundary)
* [ ] a way to auto-explode small packs to avoid them to pile up
* [x] 'ref-in-want'
* [ ] 'wanted-ref'
* [x] standard negotiation algorithms `consecutive`, `skipping` and `noop`.
* [x] in-process `file://` via built-in upload-pack (experimental feature gate, no external process)
* [ ] push
* [x] ls-refs
* [x] ls-refs with ref-spec filter
Expand Down Expand Up @@ -559,6 +561,11 @@ Provide a native SSH transport and authentication backend so `gix` users can shi
* [ ] report-status, sideband, delete-refs, push-options and atomic pushes
* [ ] object-format negotiation
* [ ] upload-pack / receive-pack server plumbing for in-process transports
* [x] upload-pack V2 request/response plumbing for blocking in-process servers (command parsing, `ls-refs` response encoding, `fetch` section encoding, sideband pack streaming)
* [x] async upload-pack V2 bridge for async transport streams (`futures_lite::io::BlockOn` adapter wrapping blocking plumbing)
* [x] repository-backed upload-pack fetch negotiation wiring (`want`/`have` resolution, `ACK`/`NAK` generation, `want-ref` ref-store resolution)
* [x] upload-pack pack construction wiring
* [x] receive-pack V1/V2 server plumbing for blocking in-process servers (V1 command/capability/push-options parsing, V2 command/section parsing, report-status response encoding, async per-client bridge)
* [ ] bundle-uri protocol integration
* [ ] remote helper protocol and integration
* [x] API documentation
Expand Down
3 changes: 3 additions & 0 deletions gitoxide-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ test = true
[features]
default = []

## Enable experimental features, currently the built-in upload-pack transport for `file://` URLs.
experimental = ["gix/experimental", "gix/parallel"]

#! ### Tools
## Discover all git repositories within a directory. Particularly useful with [skim](https://github.com/lotabout/skim).
organize = ["dep:dua-core", "dep:gix-url", "dep:parking_lot"]
Expand Down
48 changes: 48 additions & 0 deletions gitoxide-core/src/repository/clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ pub struct Options {
pub shallow: gix::remote::fetch::Shallow,
pub ref_name: Option<gix::refs::PartialName>,
pub revision: Option<gix::bstr::BString>,
/// Use the built-in in-process upload-pack instead of spawning git-upload-pack.
pub builtin_upload_pack: bool,
}

pub const PROGRESS_RANGE: std::ops::RangeInclusive<u8> = 1..=3;
Expand Down Expand Up @@ -36,6 +38,7 @@ pub(crate) mod function {
ref_name,
revision,
shallow,
builtin_upload_pack,
}: Options,
) -> anyhow::Result<()>
where
Expand Down Expand Up @@ -77,6 +80,9 @@ pub(crate) mod function {
if no_tags {
prepare = prepare.configure_remote(|r| Ok(r.with_fetch_tags(gix::remote::fetch::Tags::None)));
}
if builtin_upload_pack {
prepare = prepare.configure_connection(configure_builtin_transport);
}
let (mut checkout, fetch_outcome) = prepare
.with_shallow(shallow)
.with_ref_name(ref_name.as_ref())?
Expand Down Expand Up @@ -145,4 +151,46 @@ pub(crate) mod function {
}
Ok(())
}

/// Configure the connection to use the built-in upload-pack transport for `file://` URLs.
///
/// When the remote URL uses the `file://` scheme, this replaces the standard
/// `SpawnProcessOnDemand` transport with an in-process `BuiltinUploadPack`.
/// For non-file schemes the connection is left unchanged.
#[cfg(feature = "experimental")]
fn configure_builtin_transport(
connection: &mut gix::remote::Connection<
'_,
'_,
'_,
Box<dyn gix::protocol::transport::client::blocking_io::Transport + Send>,
>,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let url = connection
.remote()
.url(gix::remote::Direction::Fetch)
.expect("remote always has a fetch URL during clone/fetch");
if url.scheme == gix::url::Scheme::File {
let path = url.path.clone();
let transport = gix::transport::builtin_upload_pack::BuiltinUploadPack::new(
path,
gix::protocol::transport::Protocol::V2,
false,
);
*connection.transport_mut() = Box::new(transport);
}
Ok(())
}

#[cfg(not(feature = "experimental"))]
fn configure_builtin_transport(
_connection: &mut gix::remote::Connection<
'_,
'_,
'_,
Box<dyn gix::protocol::transport::client::blocking_io::Transport + Send>,
>,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
Err("--builtin-upload-pack requires the 'experimental' feature (build with --features experimental)".into())
}
}
53 changes: 51 additions & 2 deletions gitoxide-core/src/repository/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ pub struct Options {
pub handshake_info: bool,
pub negotiation_info: bool,
pub open_negotiation_graph: Option<std::path::PathBuf>,
/// Use the built-in in-process upload-pack instead of spawning git-upload-pack.
pub builtin_upload_pack: bool,
}

pub const PROGRESS_RANGE: std::ops::RangeInclusive<u8> = 1..=3;
Expand Down Expand Up @@ -46,6 +48,7 @@ pub(crate) mod function {
open_negotiation_graph,
shallow,
ref_specs,
builtin_upload_pack,
}: Options,
) -> anyhow::Result<()>
where
Expand All @@ -61,8 +64,12 @@ pub(crate) mod function {
remote.replace_refspecs(ref_specs.iter(), gix::remote::Direction::Fetch)?;
remote = remote.with_fetch_tags(gix::remote::fetch::Tags::None);
}
let res: gix::remote::fetch::Outcome = remote
.connect(gix::remote::Direction::Fetch)?
let mut connection = remote.connect(gix::remote::Direction::Fetch)?;
if builtin_upload_pack {
configure_builtin_transport(&mut connection)
.map_err(|err| anyhow::anyhow!("{err}"))?;
}
let res: gix::remote::fetch::Outcome = connection
.prepare_fetch(&mut progress, Default::default())?
.with_dry_run(dry_run)
.with_shallow(shallow)
Expand Down Expand Up @@ -331,4 +338,46 @@ pub(crate) mod function {
}
Ok(())
}

/// Configure the connection to use the built-in upload-pack transport for `file://` URLs.
///
/// When the remote URL uses the `file://` scheme, this replaces the standard
/// `SpawnProcessOnDemand` transport with an in-process `BuiltinUploadPack`.
/// For non-file schemes the connection is left unchanged.
#[cfg(feature = "experimental")]
fn configure_builtin_transport(
connection: &mut gix::remote::Connection<
'_,
'_,
'_,
Box<dyn gix::protocol::transport::client::blocking_io::Transport + Send>,
>,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let url = connection
.remote()
.url(gix::remote::Direction::Fetch)
.expect("remote always has a fetch URL during fetch");
if url.scheme == gix::url::Scheme::File {
let path = url.path.clone();
let transport = gix::transport::builtin_upload_pack::BuiltinUploadPack::new(
path,
gix::protocol::transport::Protocol::V2,
false,
);
*connection.transport_mut() = Box::new(transport);
}
Ok(())
}

#[cfg(not(feature = "experimental"))]
fn configure_builtin_transport(
_connection: &mut gix::remote::Connection<
'_,
'_,
'_,
Box<dyn gix::protocol::transport::client::blocking_io::Transport + Send>,
>,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
Err("--builtin-upload-pack requires the 'experimental' feature (build with --features experimental)".into())
}
}
Loading