Unified · Split
| @@ -5,6 +5,7 @@ pub struct Options { · 4 unmodified lines | |||
| 5 | pub bare: bool, | 5 | pub bare: bool, |
| 6 | pub handshake_info: bool, | 6 | pub handshake_info: bool, |
| 7 | pub no_tags: bool, | 7 | pub no_tags: bool, |
| 8 | pub shallow: gix::remote::fetch::Shallow, | ||
| 8 | } | 9 | } |
| 9 | 10 | ||
| 10 | pub const PROGRESS_RANGE: std::ops::RangeInclusive<u8> = 1..=3; | 11 | pub const PROGRESS_RANGE: std::ops::RangeInclusive<u8> = 1..=3; |
| @@ -30,6 +31,7 @@ pub(crate) mod function { · 19 unmodified lines | |||
| 30 | handshake_info, | 31 | handshake_info, |
| 31 | bare, | 32 | bare, |
| 32 | no_tags, | 33 | no_tags, |
| 34 | shallow, | ||
| 33 | }: Options, | 35 | }: Options, |
| 34 | ) -> anyhow::Result<()> | 36 | ) -> anyhow::Result<()> |
| 35 | where | 37 | where |
| @@ -66,8 +68,9 @@ pub(crate) mod function { · 30 unmodified lines | |||
| 66 | if no_tags { | 68 | if no_tags { |
| 67 | prepare = prepare.configure_remote(|r| Ok(r.with_fetch_tags(gix::remote::fetch::Tags::None))); | 69 | prepare = prepare.configure_remote(|r| Ok(r.with_fetch_tags(gix::remote::fetch::Tags::None))); |
| 68 | } | 70 | } |
| 69 | let (mut checkout, fetch_outcome) = | 71 | let (mut checkout, fetch_outcome) = prepare |
| 70 | prepare.fetch_then_checkout(&mut progress, &gix::interrupt::IS_INTERRUPTED)?; | 72 | .with_shallow(shallow) |
| 73 | .fetch_then_checkout(&mut progress, &gix::interrupt::IS_INTERRUPTED)?; | ||
| 71 | 74 | ||
| 72 | let (repo, outcome) = if bare { | 75 | let (repo, outcome) = if bare { |
| 73 | (checkout.persist(), None) | 76 | (checkout.persist(), None) |
| @@ -8,6 +8,7 @@ pub struct Options { · 7 unmodified lines | |||
| 8 | pub remote: Option<String>, | 8 | pub remote: Option<String>, |
| 9 | /// If non-empty, override all ref-specs otherwise configured in the remote | 9 | /// If non-empty, override all ref-specs otherwise configured in the remote |
| 10 | pub ref_specs: Vec<BString>, | 10 | pub ref_specs: Vec<BString>, |
| 11 | pub shallow: gix::remote::fetch::Shallow, | ||
| 11 | pub handshake_info: bool, | 12 | pub handshake_info: bool, |
| 12 | } | 13 | } |
| 13 | 14 | ||
| @@ -30,6 +31,7 @@ pub(crate) mod function { · 16 unmodified lines | |||
| 30 | dry_run, | 31 | dry_run, |
| 31 | remote, | 32 | remote, |
| 32 | handshake_info, | 33 | handshake_info, |
| 34 | shallow, | ||
| 33 | ref_specs, | 35 | ref_specs, |
| 34 | }: Options, | 36 | }: Options, |
| 35 | ) -> anyhow::Result<()> | 37 | ) -> anyhow::Result<()> |
| @@ -50,6 +52,7 @@ pub(crate) mod function { · 14 unmodified lines | |||
| 50 | .connect(gix::remote::Direction::Fetch, progress)? | 52 | .connect(gix::remote::Direction::Fetch, progress)? |
| 51 | .prepare_fetch(Default::default())? | 53 | .prepare_fetch(Default::default())? |
| 52 | .with_dry_run(dry_run) | 54 | .with_dry_run(dry_run) |
| 55 | .with_shallow(shallow) | ||
| 53 | .receive(&gix::interrupt::IS_INTERRUPTED)?; | 56 | .receive(&gix::interrupt::IS_INTERRUPTED)?; |
| 54 | 57 | ||
| 55 | if handshake_info { | 58 | if handshake_info { |
| @@ -130,6 +130,7 @@ pub fn main() -> Result<()> { · 129 unmodified lines | |||
| 130 | bare, | 130 | bare, |
| 131 | no_tags, | 131 | no_tags, |
| 132 | remote, | 132 | remote, |
| 133 | shallow, | ||
| 133 | directory, | 134 | directory, |
| 134 | }) => { | 135 | }) => { |
| 135 | let opts = core::repository::clone::Options { | 136 | let opts = core::repository::clone::Options { |
| @@ -137,6 +138,7 @@ pub fn main() -> Result<()> { · 1 unmodified line | |||
| 137 | bare, | 138 | bare, |
| 138 | handshake_info, | 139 | handshake_info, |
| 139 | no_tags, | 140 | no_tags, |
| 141 | shallow: shallow.into(), | ||
| 140 | }; | 142 | }; |
| 141 | prepare_and_run( | 143 | prepare_and_run( |
| 142 | "clone", | 144 | "clone", |
| @@ -152,6 +154,7 @@ pub fn main() -> Result<()> { · 9 unmodified lines | |||
| 152 | dry_run, | 154 | dry_run, |
| 153 | handshake_info, | 155 | handshake_info, |
| 154 | remote, | 156 | remote, |
| 157 | shallow, | ||
| 155 | ref_spec, | 158 | ref_spec, |
| 156 | }) => { | 159 | }) => { |
| 157 | let opts = core::repository::fetch::Options { | 160 | let opts = core::repository::fetch::Options { |
| @@ -159,6 +162,7 @@ pub fn main() -> Result<()> { · 1 unmodified line | |||
| 159 | dry_run, | 162 | dry_run, |
| 160 | remote, | 163 | remote, |
| 161 | handshake_info, | 164 | handshake_info, |
| 165 | shallow: shallow.into(), | ||
| 162 | ref_specs: ref_spec, | 166 | ref_specs: ref_spec, |
| 163 | }; | 167 | }; |
| 164 | prepare_and_run( | 168 | prepare_and_run( |
| @@ -135,6 +135,9 @@ pub mod config { · 134 unmodified lines | |||
| 135 | 135 | ||
| 136 | #[cfg(feature = "gitoxide-core-blocking-client")] | 136 | #[cfg(feature = "gitoxide-core-blocking-client")] |
| 137 | pub mod fetch { | 137 | pub mod fetch { |
| 138 | use gix::remote::fetch::Shallow; | ||
| 139 | use std::num::NonZeroU32; | ||
| 140 | |||
| 138 | #[derive(Debug, clap::Parser)] | 141 | #[derive(Debug, clap::Parser)] |
| 139 | pub struct Platform { | 142 | pub struct Platform { |
| 140 | /// Don't change the local repository, but otherwise try to be as accurate as possible. | 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 | #[clap(long, short = 'H')] | 148 | #[clap(long, short = 'H')] |
| 146 | pub handshake_info: bool, | 149 | pub handshake_info: bool, |
| 147 | 150 | ||
| 151 | #[clap(flatten)] | ||
| 152 | pub shallow: ShallowOptions, | ||
| 153 | |||
| 148 | /// The name of the remote to connect to, or the url of the remote to connect to directly. | 154 | /// The name of the remote to connect to, or the url of the remote to connect to directly. |
| 149 | /// | 155 | /// |
| 150 | /// If unset, the current branch will determine the remote. | 156 | /// If unset, the current branch will determine the remote. |
| @@ -155,10 +161,56 @@ pub mod fetch { · 4 unmodified lines | |||
| 155 | #[clap(value_parser = crate::shared::AsBString)] | 161 | #[clap(value_parser = crate::shared::AsBString)] |
| 156 | pub ref_spec: Vec<gix::bstr::BString>, | 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 | #[cfg(feature = "gitoxide-core-blocking-client")] | 210 | #[cfg(feature = "gitoxide-core-blocking-client")] |
| 161 | pub mod clone { | 211 | pub mod clone { |
| 212 | use gix::remote::fetch::Shallow; | ||
| 213 | use std::num::NonZeroU32; | ||
| 162 | use std::{ffi::OsString, path::PathBuf}; | 214 | use std::{ffi::OsString, path::PathBuf}; |
| 163 | 215 | ||
| 164 | #[derive(Debug, clap::Parser)] | 216 | #[derive(Debug, clap::Parser)] |
| @@ -175,12 +227,47 @@ pub mod clone { · 10 unmodified lines | |||
| 175 | #[clap(long)] | 227 | #[clap(long)] |
| 176 | pub no_tags: bool, | 228 | pub no_tags: bool, |
| 177 | 229 | ||
| 230 | #[clap(flatten)] | ||
| 231 | pub shallow: ShallowOptions, | ||
| 232 | |||
| 178 | /// The url of the remote to connect to, like `https://github.com/byron/gitoxide`. | 233 | /// The url of the remote to connect to, like `https://github.com/byron/gitoxide`. |
| 179 | pub remote: OsString, | 234 | pub remote: OsString, |
| 180 | 235 | ||
| 181 | /// The directory to initialize with the new repository and to which all data should be written. | 236 | /// The directory to initialize with the new repository and to which all data should be written. |
| 182 | pub directory: Option<PathBuf>, | 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 | #[cfg(any(feature = "gitoxide-core-async-client", feature = "gitoxide-core-blocking-client"))] | 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 | Record { | 215 | Record { |
| 216 | config: "clone.rejectShallow", | 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 | usage: NotPlanned { | 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 | Record { | 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 | #[derive(Clone)] | 297 | #[derive(Clone)] |
| 298 | pub struct AsPathSpec; | 298 | pub struct AsPathSpec; |
| @@ -306,5 +306,31 @@ mod clap { · 7 unmodified lines | |||
| 306 | .parse_ref(cmd, arg, value) | 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}; |