Skip to content

Commit f8b1f55

Browse files
committed
Merge branch 'fixes-and-improvements'
2 parents 7611fa4 + d1f9c63 commit f8b1f55

File tree

33 files changed

+1091
-235
lines changed

33 files changed

+1091
-235
lines changed

cargo-smart-release/Cargo.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cargo-smart-release/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ gix = { version = "^0.50.0", default-features = false, features = ["max-performa
2828
anyhow = "1.0.42"
2929
clap = { version = "4.1.0", features = ["derive", "cargo"] }
3030
env_logger = { version = "0.10.0", default-features = false, features = ["humantime", "auto-color"] }
31-
cargo_metadata = "0.15.0"
31+
cargo_metadata = "0.17.0"
3232
log = "0.4.14"
3333
toml_edit = "0.19.1"
3434
semver = "1.0.4"
35-
crates-index = { version = "2.0.0", default-features = false, features = ["git-performance", "git-https"] }
35+
crates-index = { version = "2.1.0", default-features = false, features = ["git-performance", "git-https"] }
3636
cargo_toml = "0.15.1"
3737
winnow = "0.5.1"
3838
git-conventional = "0.12.0"
Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,12 @@
1-
use std::path::PathBuf;
2-
31
pub struct Index {
42
inner: Option<crates_index::GitIndex>,
53
}
64

75
impl Index {
86
/// Like the original one, but doesn't create it if it doesn't exist
97
pub fn new_cargo_default() -> Result<Index, crates_index::Error> {
10-
let path = default_path();
118
Ok(Index {
12-
inner: if path.is_dir() {
13-
crates_index::GitIndex::new_cargo_default()?.into()
14-
} else {
15-
None
16-
},
9+
inner: crates_index::GitIndex::try_new_cargo_default()?,
1710
})
1811
}
1912

@@ -29,9 +22,3 @@ impl Index {
2922
self.inner.as_ref().and_then(|idx| idx.crate_(name))
3023
}
3124
}
32-
33-
fn default_path() -> PathBuf {
34-
crates_index::local_path_and_canonical_url(crates_index::git::URL, None)
35-
.expect("defaults are well-known")
36-
.0
37-
}

gitoxide-core/src/repository/fetch.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub const PROGRESS_RANGE: std::ops::RangeInclusive<u8> = 1..=3;
1818

1919
pub(crate) mod function {
2020
use anyhow::bail;
21+
use gix::remote::fetch::refs::update::TypeChange;
2122
use gix::{prelude::ObjectIdExt, refspec::match_group::validate::Fix, remote::fetch::Status};
2223
use layout::{
2324
backends::svg::SVGWriter,
@@ -261,11 +262,28 @@ pub(crate) mod function {
261262
crate::repository::remote::refs::print_ref(&mut out, r)?;
262263
}
263264
};
265+
let mode_and_type = update.type_change.map_or_else(
266+
|| format!("{}", update.mode),
267+
|type_change| {
268+
format!(
269+
"{} ({})",
270+
update.mode,
271+
match type_change {
272+
TypeChange::DirectToSymbolic => {
273+
"direct ref overwrites symbolic"
274+
}
275+
TypeChange::SymbolicToDirect => {
276+
"symbolic ref overwrites direct"
277+
}
278+
}
279+
)
280+
},
281+
);
264282
match edit {
265283
Some(edit) => {
266-
writeln!(out, " -> {} [{}]", edit.name, update.mode)
284+
writeln!(out, " -> {} [{mode_and_type}]", edit.name)
267285
}
268-
None => writeln!(out, " [{}]", update.mode),
286+
None => writeln!(out, " [{mode_and_type}]"),
269287
}?;
270288
}
271289
consume_skipped_tags(&mut skipped_due_to_implicit_tag, &mut out)?;

gitoxide-core/src/repository/remote.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,8 @@ mod refs_impl {
244244
},
245245
Symbolic {
246246
path: String,
247+
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
248+
tag: Option<String>,
247249
target: String,
248250
object: String,
249251
},
@@ -265,10 +267,12 @@ mod refs_impl {
265267
},
266268
handshake::Ref::Symbolic {
267269
full_ref_name: path,
270+
tag,
268271
target,
269272
object,
270273
} => JsonRef::Symbolic {
271274
path: path.to_string(),
275+
tag: tag.map(|t| t.to_string()),
272276
target: target.to_string(),
273277
object: object.to_string(),
274278
},
@@ -298,9 +302,15 @@ mod refs_impl {
298302
} => write!(&mut out, "{tag} {path} object:{object}").map(|_| tag.as_ref()),
299303
handshake::Ref::Symbolic {
300304
full_ref_name: path,
305+
tag,
301306
target,
302307
object,
303-
} => write!(&mut out, "{object} {path} symref-target:{target}").map(|_| object.as_ref()),
308+
} => match tag {
309+
Some(tag) => {
310+
write!(&mut out, "{tag} {path} symref-target:{target} peeled:{object}").map(|_| tag.as_ref())
311+
}
312+
None => write!(&mut out, "{object} {path} symref-target:{target}").map(|_| object.as_ref()),
313+
},
304314
handshake::Ref::Unborn { full_ref_name, target } => {
305315
static NULL: gix::hash::ObjectId = gix::hash::ObjectId::null(gix::hash::Kind::Sha1);
306316
write!(&mut out, "unborn {full_ref_name} symref-target:{target}").map(|_| NULL.as_ref())

gix-actor/src/signature/decode.rs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ pub(crate) mod function {
22
use bstr::ByteSlice;
33
use btoi::btoi;
44
use gix_date::{time::Sign, OffsetInSeconds, SecondsSinceUnixEpoch, Time};
5+
use nom::multi::many1_count;
56
use nom::{
67
branch::alt,
78
bytes::complete::{tag, take, take_until, take_while_m_n},
@@ -10,6 +11,7 @@ pub(crate) mod function {
1011
sequence::{terminated, tuple},
1112
IResult,
1213
};
14+
use std::cell::RefCell;
1315

1416
use crate::{IdentityRef, SignatureRef};
1517

@@ -19,7 +21,9 @@ pub(crate) mod function {
1921
pub fn decode<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
2022
i: &'a [u8],
2123
) -> IResult<&'a [u8], SignatureRef<'a>, E> {
22-
let (i, (identity, _, time, tzsign, hours, minutes)) = context(
24+
use nom::Parser;
25+
let tzsign = RefCell::new(b'-'); // TODO: there should be no need for this.
26+
let (i, (identity, _, time, _tzsign_count, hours, minutes)) = context(
2327
"<name> <<email>> <timestamp> <+|-><HHMM>",
2428
tuple((
2529
identity,
@@ -31,7 +35,13 @@ pub(crate) mod function {
3135
.map_err(|_| nom::Err::Error(E::from_error_kind(i, nom::error::ErrorKind::MapRes)))
3236
})
3337
}),
34-
context("+|-", alt((tag(b"-"), tag(b"+")))),
38+
context(
39+
"+|-",
40+
alt((
41+
many1_count(tag(b"-")).map(|_| *tzsign.borrow_mut() = b'-'), // TODO: this should be a non-allocating consumer of consecutive tags
42+
many1_count(tag(b"+")).map(|_| *tzsign.borrow_mut() = b'+'),
43+
)),
44+
),
3545
context("HH", |i| {
3646
take_while_m_n(2usize, 2, is_digit)(i).and_then(|(i, v)| {
3747
btoi::<OffsetInSeconds>(v)
@@ -40,7 +50,7 @@ pub(crate) mod function {
4050
})
4151
}),
4252
context("MM", |i| {
43-
take_while_m_n(2usize, 2, is_digit)(i).and_then(|(i, v)| {
53+
take_while_m_n(1usize, 2, is_digit)(i).and_then(|(i, v)| {
4454
btoi::<OffsetInSeconds>(v)
4555
.map(|v| (i, v))
4656
.map_err(|_| nom::Err::Error(E::from_error_kind(i, nom::error::ErrorKind::MapRes)))
@@ -49,8 +59,9 @@ pub(crate) mod function {
4959
)),
5060
)(i)?;
5161

52-
debug_assert!(tzsign[0] == b'-' || tzsign[0] == b'+', "parser assure it's +|- only");
53-
let sign = if tzsign[0] == b'-' { Sign::Minus } else { Sign::Plus }; //
62+
let tzsign = tzsign.into_inner();
63+
debug_assert!(tzsign == b'-' || tzsign == b'+', "parser assure it's +|- only");
64+
let sign = if tzsign == b'-' { Sign::Minus } else { Sign::Plus }; //
5465
let offset = (hours * 3600 + minutes * 60) * if sign == Sign::Minus { -1 } else { 1 };
5566

5667
Ok((
@@ -148,6 +159,16 @@ mod tests {
148159
);
149160
}
150161

162+
#[test]
163+
fn negative_offset_double_dash() {
164+
assert_eq!(
165+
decode(b"name <[email protected]> 1288373970 --700")
166+
.expect("parse to work")
167+
.1,
168+
signature("name", "[email protected]", 1288373970, Sign::Minus, -252000)
169+
);
170+
}
171+
151172
#[test]
152173
fn empty_name_and_email() {
153174
assert_eq!(

gix-object/tests/commit/from_bytes.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,32 @@ fn pre_epoch() -> crate::Result {
160160
Ok(())
161161
}
162162

163+
#[test]
164+
fn double_dash_special_time_offset() -> crate::Result {
165+
let signature = || SignatureRef {
166+
name: "name".into(),
167+
email: "[email protected]".into(),
168+
time: Time {
169+
seconds: 1288373970,
170+
offset: -252000,
171+
sign: Sign::Minus,
172+
},
173+
};
174+
assert_eq!(
175+
CommitRef::from_bytes(&fixture_name("commit", "double-dash-date-offset.txt"))?,
176+
CommitRef {
177+
tree: b"0a851d7a2a66084ab10516c406a405d147e974ad".as_bstr(),
178+
parents: SmallVec::from(vec![b"31350f4f0f459485eff2131517e3450cf251f6fa".as_bstr()]),
179+
author: signature(),
180+
committer: signature(),
181+
encoding: None,
182+
message: "msg\n".into(),
183+
extra_headers: vec![]
184+
}
185+
);
186+
Ok(())
187+
}
188+
163189
#[test]
164190
fn with_trailer() -> crate::Result {
165191
let kim = SignatureRef {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
tree 0a851d7a2a66084ab10516c406a405d147e974ad
2+
parent 31350f4f0f459485eff2131517e3450cf251f6fa
3+
author name <[email protected]> 1288373970 --700
4+
committer name <[email protected]> 1288373970 --700
5+
6+
msg

gix-odb/src/store_impls/dynamic/load_index.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,11 @@ impl super::Store {
493493
// Unlike libgit2, do not sort by modification date, but by size and put the biggest indices first. That way
494494
// the chance to hit an object should be higher. We leave it to the handle to sort by LRU.
495495
// Git itself doesn't change the order which may safe time, but we want it to be stable which also helps some tests.
496+
// NOTE: this will work well for well-packed repos or those using geometric repacking, but force us to open a lot
497+
// of files when dealing with new objects, as there is no notion of recency here as would be with unmaintained
498+
// repositories. Different algorithms should be provided, like newest packs first, and possibly a mix of both
499+
// with big packs first, then sorting by recency for smaller packs.
500+
// We also want to implement `fetch.unpackLimit` to alleviate this issue a little.
496501
indices_by_modification_time.sort_by(|l, r| l.2.cmp(&r.2).reverse());
497502
Ok(indices_by_modification_time)
498503
}

gix-protocol/src/fetch/arguments/blocking_io.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,7 @@ impl Arguments {
4545
}
4646
transport.invoke(
4747
Command::Fetch.as_str(),
48-
self.features
49-
.iter()
50-
.filter_map(|(k, v)| v.as_ref().map(|v| (*k, Some(v.as_ref())))),
48+
self.features.iter().filter(|(_, v)| v.is_some()).cloned(),
5149
Some(std::mem::replace(&mut self.args, retained_state).into_iter()),
5250
)
5351
}

gix-protocol/src/fetch/arguments/mod.rs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -165,20 +165,30 @@ impl Arguments {
165165
pub fn use_include_tag(&mut self) {
166166
debug_assert!(self.supports_include_tag, "'include-tag' feature required");
167167
if self.supports_include_tag {
168-
match self.version {
169-
gix_transport::Protocol::V0 | gix_transport::Protocol::V1 => {
170-
let features = self
171-
.features_for_first_want
172-
.as_mut()
173-
.expect("call use_include_tag before want()");
174-
features.push("include-tag".into())
175-
}
176-
gix_transport::Protocol::V2 => {
177-
self.args.push("include-tag".into());
178-
}
168+
self.add_feature("include-tag");
169+
}
170+
}
171+
172+
/// Add the given `feature`, unconditionally.
173+
///
174+
/// Note that sending an unknown or unsupported feature may cause the remote to terminate
175+
/// the connection. Use this method if you know what you are doing *and* there is no specialized
176+
/// method for this, e.g. [`Self::use_include_tag()`].
177+
pub fn add_feature(&mut self, feature: &str) {
178+
match self.version {
179+
gix_transport::Protocol::V0 | gix_transport::Protocol::V1 => {
180+
let features = self
181+
.features_for_first_want
182+
.as_mut()
183+
.expect("call add_feature before first want()");
184+
features.push(feature.into())
185+
}
186+
gix_transport::Protocol::V2 => {
187+
self.args.push(feature.into());
179188
}
180189
}
181190
}
191+
182192
fn prefixed(&mut self, prefix: &str, value: impl fmt::Display) {
183193
self.args.push(format!("{prefix}{value}").into());
184194
}

gix-protocol/src/fetch/tests.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@ mod arguments {
319319
assert!(arguments.is_stateless(true), "V2 is stateless…");
320320
assert!(arguments.is_stateless(false), "…in all cases");
321321

322+
arguments.add_feature("no-progress");
322323
arguments.deepen(1);
323324
arguments.deepen_relative();
324325
arguments.want(id("7b333369de1221f9bfbbe03a3a13e9a09bc1c907"));
@@ -329,6 +330,7 @@ mod arguments {
329330
b"0012command=fetch
330331
0001000ethin-pack
331332
000eofs-delta
333+
0010no-progress
332334
000ddeepen 1
333335
0014deepen-relative
334336
0032want 7b333369de1221f9bfbbe03a3a13e9a09bc1c907
@@ -347,6 +349,7 @@ mod arguments {
347349
let mut t = transport(&mut out, *is_stateful);
348350
let mut arguments = arguments_v2(Some("shallow"));
349351

352+
arguments.add_feature("no-progress");
350353
arguments.deepen(1);
351354
arguments.deepen_since(12345);
352355
arguments.shallow(id("7b333369de1221f9bfbbe03a3a13e9a09bc1c9ff"));
@@ -362,6 +365,7 @@ mod arguments {
362365
b"0012command=fetch
363366
0001000ethin-pack
364367
000eofs-delta
368+
0010no-progress
365369
000ddeepen 1
366370
0017deepen-since 12345
367371
0035shallow 7b333369de1221f9bfbbe03a3a13e9a09bc1c9ff
@@ -371,6 +375,7 @@ mod arguments {
371375
00000012command=fetch
372376
0001000ethin-pack
373377
000eofs-delta
378+
0010no-progress
374379
000ddeepen 1
375380
0017deepen-since 12345
376381
0035shallow 7b333369de1221f9bfbbe03a3a13e9a09bc1c9ff

gix-protocol/src/handshake/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub enum Ref {
2121
/// The hash of the object the ref points to.
2222
object: gix_hash::ObjectId,
2323
},
24-
/// A symbolic ref pointing to `target` ref, which in turn points to an `object`
24+
/// A symbolic ref pointing to `target` ref, which in turn, ultimately after possibly following `tag`, points to an `object`
2525
Symbolic {
2626
/// The name at which the symbolic ref is located, like `HEAD`.
2727
full_ref_name: BString,
@@ -31,7 +31,11 @@ pub enum Ref {
3131
///
3232
/// [#205]: https://github.com/Byron/gitoxide/issues/205
3333
target: BString,
34-
/// The hash of the object the `target` ref points to.
34+
/// The hash of the annotated tag the ref points to, if present.
35+
///
36+
/// Note that this field is also `None` if `full_ref_name` is a lightweight tag.
37+
tag: Option<gix_hash::ObjectId>,
38+
/// The hash of the object the `target` ref ultimately points to.
3539
object: gix_hash::ObjectId,
3640
},
3741
/// A ref is unborn on the remote and just points to the initial, unborn branch, as is the case in a newly initialized repository

0 commit comments

Comments
 (0)