Skip to content
Draft
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
5 changes: 3 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@ jobs:
- name: Install Rust (rustup)
run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }}
shell: bash
- run: cargo test --locked
- run: cargo test --features https,ssh
- run: cargo run -p systest
- run: cargo run -p systest --features unstable-sha256
- run: cargo test --locked
- run: cargo test --features https,ssh
- run: cargo test --features unstable-sha256
- run: cargo test -p git2-curl

rustfmt:
Expand Down
12 changes: 12 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ url = "2.5.4"

[features]
unstable = []
# Experimental SHA256 OID support,
# reflecting upstream libgit2's GIT_EXPERIMENTAL_SHA256.
#
# This is an ABI-breaking change.
# Future releases with this feature may introduce breakages without notice
# Use at your own risk.
#
# Library authors:
# DO NOT enable this feature by default in your dependencies.
# Due to Cargo's additive features,
# downstream users cannot deactivate it once enabled.
unstable-sha256 = ["libgit2-sys/unstable-sha256"]
default = []
ssh = ["libgit2-sys/ssh", "cred"]
https = ["libgit2-sys/https", "openssl-sys", "openssl-probe", "cred"]
Expand Down
8 changes: 7 additions & 1 deletion examples/diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,13 @@ fn tree_to_treeish<'a>(

fn resolve_blob<'a>(repo: &'a Repository, arg: Option<&String>) -> Result<Option<Blob<'a>>, Error> {
let arg = match arg {
Some(s) => Oid::from_str(s)?,
Some(s) => {
#[cfg(not(feature = "unstable-sha256"))]
let oid = Oid::from_str(s)?;
#[cfg(feature = "unstable-sha256")]
let oid = Oid::from_str(s, repo.object_format())?;
oid
}
None => return Ok(None),
};
repo.find_blob(arg).map(|b| Some(b))
Expand Down
20 changes: 20 additions & 0 deletions examples/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#![deny(warnings)]

use clap::Parser;
use git2::ObjectFormat;
use git2::{Error, Repository, RepositoryInitMode, RepositoryInitOptions};
use std::path::{Path, PathBuf};

Expand All @@ -40,6 +41,9 @@ struct Args {
#[structopt(name = "perms", long = "shared")]
/// permissions to create the repository with
flag_shared: Option<String>,
#[structopt(name = "object-format", long, value_parser = parse_object_format)]
/// object format to use (sha1 or sha256, requires unstable-sha256 feature)
flag_object_format: Option<ObjectFormat>,
}

fn run(args: &Args) -> Result<(), Error> {
Expand All @@ -48,6 +52,7 @@ fn run(args: &Args) -> Result<(), Error> {
&& args.flag_template.is_none()
&& args.flag_shared.is_none()
&& args.flag_separate_git_dir.is_none()
&& args.flag_object_format.is_none()
{
Repository::init(&path)?
} else {
Expand All @@ -68,6 +73,12 @@ fn run(args: &Args) -> Result<(), Error> {
if let Some(ref s) = args.flag_shared {
opts.mode(parse_shared(s)?);
}

#[cfg(feature = "unstable-sha256")]
if let Some(format) = args.flag_object_format {
opts.object_format(format);
}

Repository::init_opts(&path, &opts)?
};

Expand Down Expand Up @@ -136,6 +147,15 @@ fn parse_shared(shared: &str) -> Result<RepositoryInitMode, Error> {
}
}

fn parse_object_format(format: &str) -> Result<ObjectFormat, Error> {
match format {
"sha1" => Ok(ObjectFormat::Sha1),
#[cfg(feature = "unstable-sha256")]
"sha256" => Ok(ObjectFormat::Sha256),
_ => Err(Error::from_str("object format must be 'sha1' or 'sha256'")),
}
}

fn main() {
let args = Args::parse();
match run(&args) {
Expand Down
8 changes: 4 additions & 4 deletions libgit2-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,19 +254,19 @@ The build is now aborting. To disable, unset the variable or use `LIBGIT2_NO_VEN
features.push_str("#define GIT_HTTPS 1\n");

if windows {
features.push_str("#define GIT_WINHTTP 1\n");
features.push_str("#define GIT_HTTPS_WINHTTP 1\n");
} else if target.contains("apple") {
features.push_str("#define GIT_SECURE_TRANSPORT 1\n");
features.push_str("#define GIT_HTTPS_SECURETRANSPORT 1\n");
} else {
features.push_str("#define GIT_OPENSSL 1\n");
features.push_str("#define GIT_HTTPS_OPENSSL 1\n");
if let Some(path) = env::var_os("DEP_OPENSSL_INCLUDE") {
cfg.include(path);
}
}
}

// Use the CollisionDetection SHA1 implementation.
features.push_str("#define GIT_SHA1_COLLISIONDETECT 1\n");
features.push_str("#define GIT_SHA1_BUILTIN 1\n");
cfg.define("SHA1DC_NO_STANDARD_INCLUDES", "1");
cfg.define("SHA1DC_CUSTOM_INCLUDE_SHA1_C", "\"common.h\"");
cfg.define("SHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C", "\"common.h\"");
Expand Down
54 changes: 30 additions & 24 deletions libgit2-sys/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@
extern crate libz_sys as libz;

use libc::{c_char, c_int, c_uchar, c_uint, c_ushort, c_void, size_t};

// libc does not expose mode_t on Windows; use a local alias instead.
// libgit2 add shims for that, see <libgit2-sys/libgit2/src/util/win32/msvc-compat.h>
#[cfg(unix)]
use libc::mode_t;
#[cfg(not(unix))]
#[allow(non_camel_case_types)]
type mode_t = c_uint;
#[cfg(feature = "ssh")]
use libssh2_sys as libssh2;
use std::ffi::CStr;
Expand Down Expand Up @@ -839,8 +847,6 @@ git_enum! {
GIT_OBJECT_TREE = 2,
GIT_OBJECT_BLOB = 3,
GIT_OBJECT_TAG = 4,
GIT_OBJECT_OFS_DELTA = 6,
GIT_OBJECT_REF_DELTA = 7,
}
}

Expand Down Expand Up @@ -1164,6 +1170,7 @@ pub struct git_repository_init_options {
pub origin_url: *const c_char,
#[cfg(feature = "unstable-sha256")]
pub oid_type: git_oid_t,
pub refdb_type: git_refdb_t,
}

pub const GIT_REPOSITORY_INIT_OPTIONS_VERSION: c_uint = 1;
Expand Down Expand Up @@ -1236,10 +1243,10 @@ git_enum! {
pub enum git_repository_init_flag_t {
GIT_REPOSITORY_INIT_BARE = 1 << 0,
GIT_REPOSITORY_INIT_NO_REINIT = 1 << 1,
GIT_REPOSITORY_INIT_NO_DOTGIT_DIR = 1 << 2,
GIT_REPOSITORY_INIT_MKDIR = 1 << 3,
GIT_REPOSITORY_INIT_MKPATH = 1 << 4,
GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE = 1 << 5,
GIT_REPOSITORY_INIT_RELATIVE_GITLINK = 1 << 6,
}
}

Expand Down Expand Up @@ -1375,6 +1382,12 @@ git_enum! {
}
}

git_enum! {
pub enum git_refdb_t {
GIT_REFDB_FILES = 1,
}
}

git_enum! {
pub enum git_diff_format_t {
GIT_DIFF_FORMAT_PATCH = 1,
Expand Down Expand Up @@ -1816,6 +1829,7 @@ pub struct git_odb_writepack {
#[repr(C)]
pub struct git_refdb_backend {
pub version: c_uint,
pub init: Option<extern "C" fn(*mut git_refdb_backend, *const c_char, mode_t, u32) -> c_int>,
pub exists: Option<extern "C" fn(*mut c_int, *mut git_refdb_backend, *const c_char) -> c_int>,
pub lookup: Option<
extern "C" fn(*mut *mut git_reference, *mut git_refdb_backend, *const c_char) -> c_int,
Expand Down Expand Up @@ -2320,10 +2334,9 @@ extern "C" {
pub fn git_libgit2_shutdown() -> c_int;

// repository
#[cfg(not(feature = "unstable-sha256"))]
pub fn git_repository_new(out: *mut *mut git_repository) -> c_int;
#[cfg(feature = "unstable-sha256")]
pub fn git_repository_new(
pub fn git_repository_new_ext(
out: *mut *mut git_repository,
opts: *mut git_repository_new_options,
) -> c_int;
Expand Down Expand Up @@ -2495,28 +2508,25 @@ extern "C" {
pub fn git_object_typeisloose(kind: git_object_t) -> c_int;

// oid
#[cfg(not(feature = "unstable-sha256"))]
// These always parse as SHA1
pub fn git_oid_fromraw(out: *mut git_oid, raw: *const c_uchar) -> c_int;
#[cfg(not(feature = "unstable-sha256"))]
pub fn git_oid_fromstrn(out: *mut git_oid, str: *const c_char, len: size_t) -> c_int;
#[cfg(not(feature = "unstable-sha256"))]
pub fn git_oid_fromstr(out: *mut git_oid, str: *const c_char) -> c_int;
#[cfg(not(feature = "unstable-sha256"))]
pub fn git_oid_fromstrp(out: *mut git_oid, str: *const c_char) -> c_int;

// These take an explicit OID type (SHA1 or SHA256)
#[cfg(feature = "unstable-sha256")]
pub fn git_oid_fromraw(out: *mut git_oid, raw: *const c_uchar, oid_type: git_oid_t) -> c_int;
pub fn git_oid_from_raw(out: *mut git_oid, raw: *const c_uchar, oid_type: git_oid_t) -> c_int;
#[cfg(feature = "unstable-sha256")]
pub fn git_oid_fromstrn(
pub fn git_oid_from_prefix(
out: *mut git_oid,
str: *const c_char,
len: size_t,
oid_type: git_oid_t,
) -> c_int;
#[cfg(feature = "unstable-sha256")]
pub fn git_oid_fromstr(out: *mut git_oid, str: *const c_char, oid_type: git_oid_t) -> c_int;
#[cfg(feature = "unstable-sha256")]
pub fn git_oid_fromstrp(out: *mut git_oid, str: *const c_char, oid_type: git_oid_t) -> c_int;
pub fn git_oid_from_string(out: *mut git_oid, str: *const c_char, oid_type: git_oid_t)
-> c_int;

pub fn git_oid_tostr(out: *mut c_char, n: size_t, id: *const git_oid) -> *mut c_char;
pub fn git_oid_cmp(a: *const git_oid, b: *const git_oid) -> c_int;
Expand Down Expand Up @@ -2642,6 +2652,7 @@ extern "C" {
size: *mut size_t,
remote: *mut git_remote,
) -> c_int;
pub fn git_remote_oid_type(out: *mut git_oid_t, remote: *mut git_remote) -> c_int;
pub fn git_remote_set_autotag(
repo: *mut git_repository,
remote: *const c_char,
Expand Down Expand Up @@ -3344,14 +3355,12 @@ extern "C" {
stage: c_int,
) -> *const git_index_entry;
pub fn git_index_has_conflicts(index: *const git_index) -> c_int;
#[cfg(not(feature = "unstable-sha256"))]
pub fn git_index_new(index: *mut *mut git_index) -> c_int;
#[cfg(feature = "unstable-sha256")]
pub fn git_index_new(index: *mut *mut git_index, opts: *const git_index_options) -> c_int;
#[cfg(not(feature = "unstable-sha256"))]
pub fn git_index_new_ext(index: *mut *mut git_index, opts: *const git_index_options) -> c_int;
pub fn git_index_open(index: *mut *mut git_index, index_path: *const c_char) -> c_int;
#[cfg(feature = "unstable-sha256")]
pub fn git_index_open(
pub fn git_index_open_ext(
index: *mut *mut git_index,
index_path: *const c_char,
opts: *const git_index_options,
Expand Down Expand Up @@ -3923,14 +3932,13 @@ extern "C" {
line_cb: git_diff_line_cb,
payload: *mut c_void,
) -> c_int;
#[cfg(not(feature = "unstable-sha256"))]
pub fn git_diff_from_buffer(
diff: *mut *mut git_diff,
content: *const c_char,
content_len: size_t,
) -> c_int;
#[cfg(feature = "unstable-sha256")]
pub fn git_diff_from_buffer(
pub fn git_diff_from_buffer_ext(
diff: *mut *mut git_diff,
content: *const c_char,
content_len: size_t,
Expand Down Expand Up @@ -4266,14 +4274,12 @@ extern "C" {

// odb
pub fn git_repository_odb(out: *mut *mut git_odb, repo: *mut git_repository) -> c_int;
#[cfg(not(feature = "unstable-sha256"))]
pub fn git_odb_new(db: *mut *mut git_odb) -> c_int;
#[cfg(feature = "unstable-sha256")]
pub fn git_odb_new(db: *mut *mut git_odb, opts: *const git_odb_options) -> c_int;
#[cfg(not(feature = "unstable-sha256"))]
pub fn git_odb_new_ext(db: *mut *mut git_odb, opts: *const git_odb_options) -> c_int;
pub fn git_odb_open(out: *mut *mut git_odb, objects_dir: *const c_char) -> c_int;
#[cfg(feature = "unstable-sha256")]
pub fn git_odb_open(
pub fn git_odb_open_ext(
out: *mut *mut git_odb,
objects_dir: *const c_char,
opts: *const git_odb_options,
Expand Down
2 changes: 1 addition & 1 deletion libgit2-sys/libgit2
Submodule libgit2 updated 419 files
54 changes: 50 additions & 4 deletions src/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,10 +437,15 @@ mod tests {
assert_eq!(commit.parents().count(), 0);

let tree_header_bytes = commit.header_field_bytes("tree").unwrap();
assert_eq!(
crate::Oid::from_str(tree_header_bytes.as_str().unwrap()).unwrap(),
commit.tree_id()
);
let tree_oid = {
let str = tree_header_bytes.as_str().unwrap();
#[cfg(not(feature = "unstable-sha256"))]
let oid = crate::Oid::from_str(str).unwrap();
#[cfg(feature = "unstable-sha256")]
let oid = crate::Oid::from_str(str, repo.object_format()).unwrap();
oid
};
assert_eq!(tree_oid, commit.tree_id());
assert_eq!(commit.author().name(), Some("name"));
assert_eq!(commit.author().email(), Some("email"));
assert_eq!(commit.committer().name(), Some("name"));
Expand All @@ -467,4 +472,45 @@ mod tests {
.ok()
.unwrap();
}

#[test]
#[cfg(feature = "unstable-sha256")]
fn smoke_sha256() {
let (_td, repo) = crate::test::repo_init_sha256();
let head = repo.head().unwrap();
let target = head.target().unwrap();
let commit = repo.find_commit(target).unwrap();

// Verify SHA256 OID (32 bytes)
assert_eq!(commit.id().as_bytes().len(), 32);
assert_eq!(commit.tree_id().as_bytes().len(), 32);

assert_eq!(commit.message(), Some("initial\n\nbody"));
assert_eq!(commit.body(), Some("body"));
assert_eq!(commit.id(), target);
commit.summary().unwrap();
commit.tree().unwrap();
assert_eq!(commit.parents().count(), 0);

let tree_header_bytes = commit.header_field_bytes("tree").unwrap();
let tree_oid = {
let str = tree_header_bytes.as_str().unwrap();
let oid = crate::Oid::from_str(str, repo.object_format()).unwrap();
oid
};
assert_eq!(tree_oid, commit.tree_id());

// Create child commit with parent
let sig = repo.signature().unwrap();
let tree = repo.find_tree(commit.tree_id()).unwrap();
let id = repo
.commit(Some("HEAD"), &sig, &sig, "bar", &tree, &[&commit])
.unwrap();
let head = repo.find_commit(id).unwrap();

// Verify child commit ID is also SHA256
assert_eq!(head.id().as_bytes().len(), 32);
assert_eq!(head.parent_count(), 1);
assert_eq!(head.parent_id(0).unwrap(), commit.id());
}
}
Loading