Skip to content

Commit ab986a3

Browse files
authored
Add git_submodule_set_* bindings (#676)
* feat: SubmoduleUpdate <-> git_submodule_update_t * feat: convert from raw for SubmoduleUpdate & SubmoduleIgnore * feat: add git_submodule_update_strategy & git_submodule_ignore * feat: add git_submodule_set_* bindings
1 parent 7b63635 commit ab986a3

File tree

5 files changed

+189
-4
lines changed

5 files changed

+189
-4
lines changed

Diff for: libgit2-sys/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2409,6 +2409,7 @@ extern "C" {
24092409
) -> c_int;
24102410
pub fn git_submodule_free(submodule: *mut git_submodule);
24112411
pub fn git_submodule_head_id(submodule: *mut git_submodule) -> *const git_oid;
2412+
pub fn git_submodule_ignore(submodule: *mut git_submodule) -> git_submodule_ignore_t;
24122413
pub fn git_submodule_index_id(submodule: *mut git_submodule) -> *const git_oid;
24132414
pub fn git_submodule_init(submodule: *mut git_submodule, overwrite: c_int) -> c_int;
24142415
pub fn git_submodule_location(status: *mut c_uint, submodule: *mut git_submodule) -> c_int;

Diff for: src/call.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ mod impls {
5858

5959
use crate::call::Convert;
6060
use crate::{raw, BranchType, ConfigLevel, Direction, ObjectType, ResetType};
61-
use crate::{AutotagOption, DiffFormat, FetchPrune, FileFavor, SubmoduleIgnore};
61+
use crate::{
62+
AutotagOption, DiffFormat, FetchPrune, FileFavor, SubmoduleIgnore, SubmoduleUpdate,
63+
};
6264

6365
impl<T: Copy> Convert<T> for T {
6466
fn convert(&self) -> T {
@@ -209,6 +211,18 @@ mod impls {
209211
}
210212
}
211213

214+
impl Convert<raw::git_submodule_update_t> for SubmoduleUpdate {
215+
fn convert(&self) -> raw::git_submodule_update_t {
216+
match *self {
217+
SubmoduleUpdate::Checkout => raw::GIT_SUBMODULE_UPDATE_CHECKOUT,
218+
SubmoduleUpdate::Rebase => raw::GIT_SUBMODULE_UPDATE_REBASE,
219+
SubmoduleUpdate::Merge => raw::GIT_SUBMODULE_UPDATE_MERGE,
220+
SubmoduleUpdate::None => raw::GIT_SUBMODULE_UPDATE_NONE,
221+
SubmoduleUpdate::Default => raw::GIT_SUBMODULE_UPDATE_DEFAULT,
222+
}
223+
}
224+
}
225+
212226
impl Convert<raw::git_remote_autotag_option_t> for AutotagOption {
213227
fn convert(&self) -> raw::git_remote_autotag_option_t {
214228
match *self {

Diff for: src/lib.rs

+54
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,34 @@ impl ConfigLevel {
931931
}
932932
}
933933

934+
impl SubmoduleIgnore {
935+
/// Converts a [`raw::git_submodule_ignore_t`] to a [`SubmoduleIgnore`]
936+
pub fn from_raw(raw: raw::git_submodule_ignore_t) -> Self {
937+
match raw {
938+
raw::GIT_SUBMODULE_IGNORE_UNSPECIFIED => SubmoduleIgnore::Unspecified,
939+
raw::GIT_SUBMODULE_IGNORE_NONE => SubmoduleIgnore::None,
940+
raw::GIT_SUBMODULE_IGNORE_UNTRACKED => SubmoduleIgnore::Untracked,
941+
raw::GIT_SUBMODULE_IGNORE_DIRTY => SubmoduleIgnore::Dirty,
942+
raw::GIT_SUBMODULE_IGNORE_ALL => SubmoduleIgnore::All,
943+
n => panic!("unknown submodule ignore rule: {}", n),
944+
}
945+
}
946+
}
947+
948+
impl SubmoduleUpdate {
949+
/// Converts a [`raw::git_submodule_update_t`] to a [`SubmoduleUpdate`]
950+
pub fn from_raw(raw: raw::git_submodule_update_t) -> Self {
951+
match raw {
952+
raw::GIT_SUBMODULE_UPDATE_CHECKOUT => SubmoduleUpdate::Checkout,
953+
raw::GIT_SUBMODULE_UPDATE_REBASE => SubmoduleUpdate::Rebase,
954+
raw::GIT_SUBMODULE_UPDATE_MERGE => SubmoduleUpdate::Merge,
955+
raw::GIT_SUBMODULE_UPDATE_NONE => SubmoduleUpdate::None,
956+
raw::GIT_SUBMODULE_UPDATE_DEFAULT => SubmoduleUpdate::Default,
957+
n => panic!("unknown submodule update strategy: {}", n),
958+
}
959+
}
960+
}
961+
934962
bitflags! {
935963
/// Status flags for a single file
936964
///
@@ -1173,6 +1201,7 @@ impl SubmoduleStatus {
11731201
/// These values represent settings for the `submodule.$name.ignore`
11741202
/// configuration value which says how deeply to look at the working
11751203
/// directory when getting the submodule status.
1204+
#[derive(Debug)]
11761205
pub enum SubmoduleIgnore {
11771206
/// Use the submodule's configuration
11781207
Unspecified,
@@ -1186,6 +1215,31 @@ pub enum SubmoduleIgnore {
11861215
All,
11871216
}
11881217

1218+
/// Submodule update values
1219+
///
1220+
/// These values represent settings for the `submodule.$name.update`
1221+
/// configuration value which says how to handle `git submodule update`
1222+
/// for this submodule. The value is usually set in the ".gitmodules"
1223+
/// file and copied to ".git/config" when the submodule is initialized.
1224+
#[derive(Debug)]
1225+
pub enum SubmoduleUpdate {
1226+
/// The default; when a submodule is updated, checkout the new detached
1227+
/// HEAD to the submodule directory.
1228+
Checkout,
1229+
/// Update by rebasing the current checked out branch onto the commit from
1230+
/// the superproject.
1231+
Rebase,
1232+
/// Update by merging the commit in the superproject into the current
1233+
/// checkout out branch of the submodule.
1234+
Merge,
1235+
/// Do not update this submodule even when the commit in the superproject
1236+
/// is updated.
1237+
None,
1238+
/// Not used except as static initializer when we don't want any particular
1239+
/// update rule to be specified.
1240+
Default,
1241+
}
1242+
11891243
bitflags! {
11901244
/// ...
11911245
pub struct PathspecFlags: u32 {

Diff for: src/repo.rs

+108-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ use crate::{
2424
StashFlags,
2525
};
2626
use crate::{
27-
AnnotatedCommit, MergeAnalysis, MergeOptions, MergePreference, SubmoduleIgnore, SubmoduleStatus,
27+
AnnotatedCommit, MergeAnalysis, MergeOptions, MergePreference, SubmoduleIgnore,
28+
SubmoduleStatus, SubmoduleUpdate,
2829
};
2930
use crate::{ApplyLocation, ApplyOptions, Rebase, RebaseOptions};
3031
use crate::{Blame, BlameOptions, Reference, References, ResetType, Signature, Submodule};
@@ -1635,6 +1636,62 @@ impl Repository {
16351636
Ok(SubmoduleStatus::from_bits_truncate(ret as u32))
16361637
}
16371638

1639+
/// Set the ignore rule for the submodule in the configuration
1640+
///
1641+
/// This does not affect any currently-loaded instances.
1642+
pub fn submodule_set_ignore(
1643+
&mut self,
1644+
name: &str,
1645+
ignore: SubmoduleIgnore,
1646+
) -> Result<(), Error> {
1647+
let name = CString::new(name)?;
1648+
unsafe {
1649+
try_call!(raw::git_submodule_set_ignore(self.raw(), name, ignore));
1650+
}
1651+
Ok(())
1652+
}
1653+
1654+
/// Set the update rule for the submodule in the configuration
1655+
///
1656+
/// This setting won't affect any existing instances.
1657+
pub fn submodule_set_update(
1658+
&mut self,
1659+
name: &str,
1660+
update: SubmoduleUpdate,
1661+
) -> Result<(), Error> {
1662+
let name = CString::new(name)?;
1663+
unsafe {
1664+
try_call!(raw::git_submodule_set_update(self.raw(), name, update));
1665+
}
1666+
Ok(())
1667+
}
1668+
1669+
/// Set the URL for the submodule in the configuration
1670+
///
1671+
/// After calling this, you may wish to call [`Submodule::sync`] to write
1672+
/// the changes to the checked out submodule repository.
1673+
pub fn submodule_set_url(&mut self, name: &str, url: &str) -> Result<(), Error> {
1674+
let name = CString::new(name)?;
1675+
let url = CString::new(url)?;
1676+
unsafe {
1677+
try_call!(raw::git_submodule_set_url(self.raw(), name, url));
1678+
}
1679+
Ok(())
1680+
}
1681+
1682+
/// Set the branch for the submodule in the configuration
1683+
///
1684+
/// After calling this, you may wish to call [`Submodule::sync`] to write
1685+
/// the changes to the checked out submodule repository.
1686+
pub fn submodule_set_branch(&mut self, name: &str, branch_name: &str) -> Result<(), Error> {
1687+
let name = CString::new(name)?;
1688+
let branch_name = CString::new(branch_name)?;
1689+
unsafe {
1690+
try_call!(raw::git_submodule_set_branch(self.raw(), name, branch_name));
1691+
}
1692+
Ok(())
1693+
}
1694+
16381695
/// Lookup a reference to one of the objects in a repository.
16391696
pub fn find_tree(&self, oid: Oid) -> Result<Tree<'_>, Error> {
16401697
let mut raw = ptr::null_mut();
@@ -3078,7 +3135,7 @@ impl RepositoryInitOptions {
30783135
mod tests {
30793136
use crate::build::CheckoutBuilder;
30803137
use crate::CherrypickOptions;
3081-
use crate::{ObjectType, Oid, Repository, ResetType};
3138+
use crate::{ObjectType, Oid, Repository, ResetType, SubmoduleIgnore, SubmoduleUpdate};
30823139
use std::ffi::OsStr;
30833140
use std::fs;
30843141
use std::path::Path;
@@ -3721,4 +3778,53 @@ mod tests {
37213778

37223779
Ok(())
37233780
}
3781+
3782+
#[test]
3783+
fn smoke_submodule_set() -> Result<(), crate::Error> {
3784+
let (td1, _repo) = crate::test::repo_init();
3785+
let (td2, mut repo2) = crate::test::repo_init();
3786+
let url = crate::test::path2url(td1.path());
3787+
let name = "bar";
3788+
{
3789+
let mut s = repo2.submodule(&url, Path::new(name), true)?;
3790+
fs::remove_dir_all(td2.path().join("bar")).unwrap();
3791+
Repository::clone(&url, td2.path().join("bar"))?;
3792+
s.add_to_index(false)?;
3793+
s.add_finalize()?;
3794+
}
3795+
3796+
// update strategy
3797+
repo2.submodule_set_update(name, SubmoduleUpdate::None)?;
3798+
assert!(matches!(
3799+
repo2.find_submodule(name)?.update_strategy(),
3800+
SubmoduleUpdate::None
3801+
));
3802+
repo2.submodule_set_update(name, SubmoduleUpdate::Rebase)?;
3803+
assert!(matches!(
3804+
repo2.find_submodule(name)?.update_strategy(),
3805+
SubmoduleUpdate::Rebase
3806+
));
3807+
3808+
// ignore rule
3809+
repo2.submodule_set_ignore(name, SubmoduleIgnore::Untracked)?;
3810+
assert!(matches!(
3811+
repo2.find_submodule(name)?.ignore_rule(),
3812+
SubmoduleIgnore::Untracked
3813+
));
3814+
repo2.submodule_set_ignore(name, SubmoduleIgnore::Dirty)?;
3815+
assert!(matches!(
3816+
repo2.find_submodule(name)?.ignore_rule(),
3817+
SubmoduleIgnore::Dirty
3818+
));
3819+
3820+
// url
3821+
repo2.submodule_set_url(name, "fake-url")?;
3822+
assert_eq!(repo2.find_submodule(name)?.url(), Some("fake-url"));
3823+
3824+
// branch
3825+
repo2.submodule_set_branch(name, "fake-branch")?;
3826+
assert_eq!(repo2.find_submodule(name)?.branch(), Some("fake-branch"));
3827+
3828+
Ok(())
3829+
}
37243830
}

Diff for: src/submodule.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use std::path::Path;
55
use std::ptr;
66
use std::str;
77

8-
use crate::build::CheckoutBuilder;
98
use crate::util::{self, Binding};
9+
use crate::{build::CheckoutBuilder, SubmoduleIgnore, SubmoduleUpdate};
1010
use crate::{raw, Error, FetchOptions, Oid, Repository};
1111

1212
/// A structure to represent a git [submodule][1]
@@ -113,6 +113,16 @@ impl<'repo> Submodule<'repo> {
113113
unsafe { Binding::from_raw_opt(raw::git_submodule_wd_id(self.raw)) }
114114
}
115115

116+
/// Get the ignore rule that will be used for the submodule.
117+
pub fn ignore_rule(&self) -> SubmoduleIgnore {
118+
SubmoduleIgnore::from_raw(unsafe { raw::git_submodule_ignore(self.raw) })
119+
}
120+
121+
/// Get the update rule that will be used for the submodule.
122+
pub fn update_strategy(&self) -> SubmoduleUpdate {
123+
SubmoduleUpdate::from_raw(unsafe { raw::git_submodule_update_strategy(self.raw) })
124+
}
125+
116126
/// Copy submodule info into ".git/config" file.
117127
///
118128
/// Just like "git submodule init", this copies information about the

0 commit comments

Comments
 (0)