Unified · Split
| @@ -5,6 +5,7 @@ pub struct Options { · 4 unmodified lines | ||
| 5 | 5 | pub bare: bool, |
| 6 | 6 | pub handshake_info: bool, |
| 7 | 7 | pub no_tags: bool, |
| 8 | + pub shallow: gix::remote::fetch::Shallow, | |
| 8 | 9 | } |
| 9 | 10 | |
| 10 | 11 | pub const PROGRESS_RANGE: std::ops::RangeInclusive<u8> = 1..=3; |
| @@ -30,6 +31,7 @@ pub(crate) mod function { · 19 unmodified lines | ||
| 30 | 31 | handshake_info, |
| 31 | 32 | bare, |
| 32 | 33 | no_tags, |
| 34 | + shallow, | |
| 33 | 35 | }: Options, |
| 34 | 36 | ) -> anyhow::Result<()> |
| 35 | 37 | where |
| @@ -66,8 +68,9 @@ pub(crate) mod function { · 30 unmodified lines | ||
| 66 | 68 | if no_tags { |
| 67 | 69 | prepare = prepare.configure_remote(|r| Ok(r.with_fetch_tags(gix::remote::fetch::Tags::None))); |
| 68 | 70 | } |
| 69 | − let (mut checkout, fetch_outcome) = | |
| 70 | − prepare.fetch_then_checkout(&mut progress, &gix::interrupt::IS_INTERRUPTED)?; | |
| 71 | + let (mut checkout, fetch_outcome) = prepare | |
| 72 | + .with_shallow(shallow) | |
| 73 | + .fetch_then_checkout(&mut progress, &gix::interrupt::IS_INTERRUPTED)?; | |
| 71 | 74 | |
| 72 | 75 | let (repo, outcome) = if bare { |
| 73 | 76 | (checkout.persist(), None) |
| @@ -8,6 +8,7 @@ pub struct Options { · 7 unmodified lines | ||
| 8 | 8 | pub remote: Option<String>, |
| 9 | 9 | /// If non-empty, override all ref-specs otherwise configured in the remote |
| 10 | 10 | pub ref_specs: Vec<BString>, |
| 11 | + pub shallow: gix::remote::fetch::Shallow, | |
| 11 | 12 | pub handshake_info: bool, |
| 12 | 13 | } |
| 13 | 14 | |
| @@ -30,6 +31,7 @@ pub(crate) mod function { · 16 unmodified lines | ||
| 30 | 31 | dry_run, |
| 31 | 32 | remote, |
| 32 | 33 | handshake_info, |
| 34 | + shallow, | |
| 33 | 35 | ref_specs, |
| 34 | 36 | }: Options, |
| 35 | 37 | ) -> anyhow::Result<()> |
| @@ -50,6 +52,7 @@ pub(crate) mod function { · 14 unmodified lines | ||
| 50 | 52 | .connect(gix::remote::Direction::Fetch, progress)? |
| 51 | 53 | .prepare_fetch(Default::default())? |
| 52 | 54 | .with_dry_run(dry_run) |
| 55 | + .with_shallow(shallow) | |
| 53 | 56 | .receive(&gix::interrupt::IS_INTERRUPTED)?; |
| 54 | 57 | |
| 55 | 58 | if handshake_info { |
| @@ -130,6 +130,7 @@ pub fn main() -> Result<()> { · 129 unmodified lines | ||
| 130 | 130 | bare, |
| 131 | 131 | no_tags, |
| 132 | 132 | remote, |
| 133 | + shallow, | |
| 133 | 134 | directory, |
| 134 | 135 | }) => { |
| 135 | 136 | let opts = core::repository::clone::Options { |
| @@ -137,6 +138,7 @@ pub fn main() -> Result<()> { · 1 unmodified line | ||
| 137 | 138 | bare, |
| 138 | 139 | handshake_info, |
| 139 | 140 | no_tags, |
| 141 | + shallow: shallow.into(), | |
| 140 | 142 | }; |
| 141 | 143 | prepare_and_run( |
| 142 | 144 | "clone", |
| @@ -152,6 +154,7 @@ pub fn main() -> Result<()> { · 9 unmodified lines | ||
| 152 | 154 | dry_run, |
| 153 | 155 | handshake_info, |
| 154 | 156 | remote, |
| 157 | + shallow, | |
| 155 | 158 | ref_spec, |
| 156 | 159 | }) => { |
| 157 | 160 | let opts = core::repository::fetch::Options { |
| @@ -159,6 +162,7 @@ pub fn main() -> Result<()> { · 1 unmodified line | ||
| 159 | 162 | dry_run, |
| 160 | 163 | remote, |
| 161 | 164 | handshake_info, |
| 165 | + shallow: shallow.into(), | |
| 162 | 166 | ref_specs: ref_spec, |
| 163 | 167 | }; |
| 164 | 168 | prepare_and_run( |
| @@ -135,6 +135,9 @@ pub mod config { · 134 unmodified lines | ||
| 135 | 135 | |
| 136 | 136 | #[cfg(feature = "gitoxide-core-blocking-client")] |
| 137 | 137 | pub mod fetch { |
| 138 | + use gix::remote::fetch::Shallow; | |
| 139 | + use std::num::NonZeroU32; | |
| 140 | + | |
| 138 | 141 | #[derive(Debug, clap::Parser)] |
| 139 | 142 | pub struct Platform { |
| 140 | 143 | /// Don't change the local repository, but otherwise try to be as accurate as possible. |
| @@ -145,6 +148,9 @@ pub mod fetch { · 4 unmodified lines | ||
| 145 | 148 | #[clap(long, short = 'H')] |
| 146 | 149 | pub handshake_info: bool, |
| 147 | 150 | |
| 151 | + #[clap(flatten)] | |
| 152 | + pub shallow: ShallowOptions, | |
| 153 | + | |
| 148 | 154 | /// The name of the remote to connect to, or the url of the remote to connect to directly. |
| 149 | 155 | /// |
| 150 | 156 | /// If unset, the current branch will determine the remote. |
| @@ -155,10 +161,56 @@ pub mod fetch { · 4 unmodified lines | ||
| 155 | 161 | #[clap(value_parser = crate::shared::AsBString)] |
| 156 | 162 | pub ref_spec: Vec<gix::bstr::BString>, |
| 157 | 163 | } |
| 164 | + | |
| 165 | + #[derive(Debug, clap::Parser)] | |
| 166 | + pub struct ShallowOptions { | |
| 167 | + /// Fetch with the history truncated to the given number of commits as seen from the remote. | |
| 168 | + #[clap(long, conflicts_with_all = ["shallow_since", "shallow_exclude", "deepen", "unshallow"])] | |
| 169 | + pub depth: Option<NonZeroU32>, | |
| 170 | + | |
| 171 | + /// Extend the current shallow boundary by the given amount of commits, with 0 meaning no change. | |
| 172 | + #[clap(long, value_name = "DEPTH", conflicts_with_all = ["depth", "shallow_since", "shallow_exclude", "unshallow"])] | |
| 173 | + pub deepen: Option<u32>, | |
| 174 | + | |
| 175 | + /// Cutoff all history past the given date. Can be combined with shallow-exclude. | |
| 176 | + #[clap(long, value_parser = crate::shared::AsTime, value_name = "DATE", conflicts_with_all = ["depth", "deepen", "unshallow"])] | |
| 177 | + pub shallow_since: Option<gix::date::Time>, | |
| 178 | + | |
| 179 | + /// Cutoff all history past the tag-name or ref-name. Can be combined with shallow-since. | |
| 180 | + #[clap(long, value_parser = crate::shared::AsPartialRefName, value_name = "REF_NAME", conflicts_with_all = ["depth", "deepen", "unshallow"])] | |
| 181 | + pub shallow_exclude: Vec<gix::refs::PartialName>, | |
| 182 | + | |
| 183 | + /// Remove the shallow boundary and fetch the entire history available on the remote. | |
| 184 | + #[clap(long, conflicts_with_all = ["shallow_since", "shallow_exclude", "depth", "deepen", "unshallow"])] | |
| 185 | + pub unshallow: bool, | |
| 186 | + } | |
| 187 | + | |
| 188 | + impl From<ShallowOptions> for Shallow { | |
| 189 | + fn from(opts: ShallowOptions) -> Self { | |
| 190 | + if let Some(depth) = opts.depth { | |
| 191 | + Shallow::DepthAtRemote(depth) | |
| 192 | + } else if !opts.shallow_exclude.is_empty() { | |
| 193 | + Shallow::Exclude { | |
| 194 | + remote_refs: opts.shallow_exclude, | |
| 195 | + since_cutoff: opts.shallow_since, | |
| 196 | + } | |
| 197 | + } else if let Some(cutoff) = opts.shallow_since { | |
| 198 | + Shallow::Since { cutoff } | |
| 199 | + } else if let Some(depth) = opts.deepen { | |
| 200 | + Shallow::Deepen(depth) | |
| 201 | + } else if opts.unshallow { | |
| 202 | + Shallow::undo() | |
| 203 | + } else { | |
| 204 | + Shallow::default() | |
| 205 | + } | |
| 206 | + } | |
| 207 | + } | |
| 158 | 208 | } |
| 159 | 209 | |
| 160 | 210 | #[cfg(feature = "gitoxide-core-blocking-client")] |
| 161 | 211 | pub mod clone { |
| 212 | + use gix::remote::fetch::Shallow; | |
| 213 | + use std::num::NonZeroU32; | |
| 162 | 214 | use std::{ffi::OsString, path::PathBuf}; |
| 163 | 215 | |
| 164 | 216 | #[derive(Debug, clap::Parser)] |
| @@ -175,12 +227,47 @@ pub mod clone { · 10 unmodified lines | ||
| 175 | 227 | #[clap(long)] |
| 176 | 228 | pub no_tags: bool, |
| 177 | 229 | |
| 230 | + #[clap(flatten)] | |
| 231 | + pub shallow: ShallowOptions, | |
| 232 | + | |
| 178 | 233 | /// The url of the remote to connect to, like `https://github.com/byron/gitoxide`. |
| 179 | 234 | pub remote: OsString, |
| 180 | 235 | |
| 181 | 236 | /// The directory to initialize with the new repository and to which all data should be written. |
| 182 | 237 | pub directory: Option<PathBuf>, |
| 183 | 238 | } |
| 239 | + | |
| 240 | + #[derive(Debug, clap::Parser)] | |
| 241 | + pub struct ShallowOptions { | |
| 242 | + /// Create a shallow clone with the history truncated to the given number of commits. | |
| 243 | + #[clap(long, conflicts_with_all = ["shallow_since", "shallow_exclude"])] | |
| 244 | + pub depth: Option<NonZeroU32>, | |
| 245 | + | |
| 246 | + /// Cutoff all history past the given date. Can be combined with shallow-exclude. | |
| 247 | + #[clap(long, value_parser = crate::shared::AsTime, value_name = "DATE")] | |
| 248 | + pub shallow_since: Option<gix::date::Time>, | |
| 249 | + | |
| 250 | + /// Cutoff all history past the tag-name or ref-name. Can be combined with shallow-since. | |
| 251 | + #[clap(long, value_parser = crate::shared::AsPartialRefName, value_name = "REF_NAME")] | |
| 252 | + pub shallow_exclude: Vec<gix::refs::PartialName>, | |
| 253 | + } | |
| 254 | + | |
| 255 | + impl From<ShallowOptions> for Shallow { | |
| 256 | + fn from(opts: ShallowOptions) -> Self { | |
| 257 | + if let Some(depth) = opts.depth { | |
| 258 | + Shallow::DepthAtRemote(depth) | |
| 259 | + } else if !opts.shallow_exclude.is_empty() { | |
| 260 | + Shallow::Exclude { | |
| 261 | + remote_refs: opts.shallow_exclude, | |
| 262 | + since_cutoff: opts.shallow_since, | |
| 263 | + } | |
| 264 | + } else if let Some(cutoff) = opts.shallow_since { | |
| 265 | + Shallow::Since { cutoff } | |
| 266 | + } else { | |
| 267 | + Shallow::default() | |
| 268 | + } | |
| 269 | + } | |
| 270 | + } | |
| 184 | 271 | } |
| 185 | 272 | |
| 186 | 273 | #[cfg(any(feature = "gitoxide-core-async-client", feature = "gitoxide-core-blocking-client"))] |
| @@ -214,8 +214,14 @@ static GIT_CONFIG: &[Record] = &[ · 213 unmodified lines | ||
| 214 | 214 | }, |
| 215 | 215 | Record { |
| 216 | 216 | config: "clone.rejectShallow", |
| 217 | + usage: Planned { | |
| 218 | + note: Some("probably trivial to implement once there is protocol support for shallow clones"), | |
| 219 | + }, | |
| 220 | + }, | |
| 221 | + Record { | |
| 222 | + config: "receive.shallowUpdate", | |
| 217 | 223 | usage: NotPlanned { |
| 218 | − reason: "it's not a use-case we consider important now, but once that changes it can be implemented", | |
| 224 | + reason: "it looks like a server-only setting that allows boundaries to change if refs are pushed that are outside of the boundary.", | |
| 219 | 225 | }, |
| 220 | 226 | }, |
| 221 | 227 | Record { |
| @@ -292,7 +292,7 @@ mod clap { · 291 unmodified lines | ||
| 292 | 292 | } |
| 293 | 293 | } |
| 294 | 294 | |
| 295 | − use clap::builder::{OsStringValueParser, TypedValueParser}; | |
| 295 | + use clap::builder::{OsStringValueParser, StringValueParser, TypedValueParser}; | |
| 296 | 296 | |
| 297 | 297 | #[derive(Clone)] |
| 298 | 298 | pub struct AsPathSpec; |
| @@ -306,5 +306,31 @@ mod clap { · 7 unmodified lines | ||
| 306 | 306 | .parse_ref(cmd, arg, value) |
| 307 | 307 | } |
| 308 | 308 | } |
| 309 | + | |
| 310 | + #[derive(Clone)] | |
| 311 | + pub struct AsTime; | |
| 312 | + | |
| 313 | + impl TypedValueParser for AsTime { | |
| 314 | + type Value = gix::date::Time; | |
| 315 | + | |
| 316 | + fn parse_ref(&self, cmd: &Command, arg: Option<&Arg>, value: &OsStr) -> Result<Self::Value, Error> { | |
| 317 | + StringValueParser::new() | |
| 318 | + .try_map(|arg| gix::date::parse(&arg, Some(std::time::SystemTime::now()))) | |
| 319 | + .parse_ref(cmd, arg, value) | |
| 320 | + } | |
| 321 | + } | |
| 322 | + | |
| 323 | + #[derive(Clone)] | |
| 324 | + pub struct AsPartialRefName; | |
| 325 | + | |
| 326 | + impl TypedValueParser for AsPartialRefName { | |
| 327 | + type Value = gix::refs::PartialName; | |
| 328 | + | |
| 329 | + fn parse_ref(&self, cmd: &Command, arg: Option<&Arg>, value: &OsStr) -> Result<Self::Value, Error> { | |
| 330 | + AsBString | |
| 331 | + .try_map(gix::refs::PartialName::try_from) | |
| 332 | + .parse_ref(cmd, arg, value) | |
| 333 | + } | |
| 334 | + } | |
| 309 | 335 | } |
| 310 | −pub use self::clap::{AsBString, AsHashKind, AsOutputFormat, AsPathSpec}; | |
| 336 | +pub use self::clap::{AsBString, AsHashKind, AsOutputFormat, AsPartialRefName, AsPathSpec, AsTime}; | |