Skip to content
Open
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
67 changes: 61 additions & 6 deletions asyncgit/src/sync/branch/merge_commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
use super::BranchType;
use crate::{
error::{Error, Result},
sync::{merge_msg, repository::repo, CommitId, RepoPath},
sync::{
commit::signature_allow_undefined_name, merge_msg,
repository::repo, sign::SignBuilder, CommitId, RepoPath,
},
};
use git2::Commit;
use scopetime::scope_time;
Expand Down Expand Up @@ -66,8 +69,20 @@ pub(crate) fn commit_merge_with_head(
commits: &[Commit],
msg: &str,
) -> Result<CommitId> {
let signature =
crate::sync::commit::signature_allow_undefined_name(repo)?;
commit_merge_with_head_with_sign(repo, commits, msg, None)
}

pub(crate) fn commit_merge_with_head_with_sign(
repo: &git2::Repository,
commits: &[Commit],
msg: &str,
sign_override: Option<bool>,
) -> Result<CommitId> {
let config = repo.config()?;
let should_sign = sign_override.unwrap_or_else(|| {
config.get_bool("commit.gpgsign").unwrap_or(false)
});
let signature = signature_allow_undefined_name(repo)?;
let mut index = repo.index()?;
let tree_id = index.write_tree()?;
let tree = repo.find_tree(tree_id)?;
Expand All @@ -78,16 +93,56 @@ pub(crate) fn commit_merge_with_head(
let mut parents = vec![&head_commit];
parents.extend(commits);

let commit_id = repo
.commit(
let commit_id = if should_sign {
let buffer = repo.commit_create_buffer(
&signature,
&signature,
msg,
&tree,
parents.as_slice(),
)?;

let commit = std::str::from_utf8(&buffer).map_err(|_e| {
crate::sync::sign::SignError::Shellout(
"utf8 conversion error".to_string(),
)
})?;

let signer = SignBuilder::from_gitconfig(repo, &config)?;
let (signature, signature_field) = signer.sign(&buffer)?;
let commit_id = repo.commit_signed(
commit,
&signature,
signature_field.as_deref(),
)?;

if let Ok(mut head) = repo.head() {
head.set_target(commit_id, msg)?;
} else {
let default_branch_name = config
.get_str("init.defaultBranch")
.unwrap_or("master");
repo.reference(
&format!("refs/heads/{default_branch_name}"),
commit_id,
true,
msg,
)?;
}

CommitId::new(commit_id)
} else {
repo.commit(
Some("HEAD"),
&signature,
&signature,
msg,
&tree,
parents.as_slice(),
)?
.into();
.into()
};

repo.cleanup_state()?;
Ok(commit_id)
}
Expand Down
43 changes: 37 additions & 6 deletions asyncgit/src/sync/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,55 @@ use git2::{
};
use scopetime::scope_time;

fn gpgsign_enabled(
config: &git2::Config,
sign_override: Option<bool>,
) -> bool {
sign_override.unwrap_or_else(|| {
config.get_bool("commit.gpgsign").unwrap_or(false)
})
}

///
pub fn amend(
repo_path: &RepoPath,
id: CommitId,
msg: &str,
) -> Result<CommitId> {
amend_with_sign(repo_path, id, msg, None)
}

///
pub fn amend_with_sign(
repo_path: &RepoPath,
id: CommitId,
msg: &str,
sign_override: Option<bool>,
) -> Result<CommitId> {
scope_time!("amend");

let repo = repo(repo_path)?;
let config = repo.config()?;
let should_sign = gpgsign_enabled(&config, sign_override);

let commit = repo.find_commit(id.into())?;

let mut index = repo.index()?;
let tree_id = index.write_tree()?;
let tree = repo.find_tree(tree_id)?;

if config.get_bool("commit.gpgsign").unwrap_or(false) {
if should_sign {
// HACK: we undo the last commit and create a new one
use crate::sync::utils::undo_last_commit;

let head = get_head_repo(&repo)?;
if head == commit.id().into() {
undo_last_commit(repo_path)?;
return self::commit(repo_path, msg);
return self::commit_with_sign(
repo_path,
msg,
Some(true),
);
}

return Err(Error::SignAmendNonLastCommit);
Expand Down Expand Up @@ -82,10 +106,20 @@ pub(crate) fn signature_allow_undefined_name(

/// this does not run any git hooks, git-hooks have to be executed manually, checkout `hooks_commit_msg` for example
pub fn commit(repo_path: &RepoPath, msg: &str) -> Result<CommitId> {
commit_with_sign(repo_path, msg, None)
}

/// this does not run any git hooks, git-hooks have to be executed manually, checkout `hooks_commit_msg` for example
pub fn commit_with_sign(
repo_path: &RepoPath,
msg: &str,
sign_override: Option<bool>,
) -> Result<CommitId> {
scope_time!("commit");

let repo = repo(repo_path)?;
let config = repo.config()?;
let should_sign = gpgsign_enabled(&config, sign_override);
let signature = signature_allow_undefined_name(&repo)?;
let mut index = repo.index()?;
let tree_id = index.write_tree()?;
Expand All @@ -99,10 +133,7 @@ pub fn commit(repo_path: &RepoPath, msg: &str) -> Result<CommitId> {

let parents = parents.iter().collect::<Vec<_>>();

let commit_id = if config
.get_bool("commit.gpgsign")
.unwrap_or(false)
{
let commit_id = if should_sign {
let buffer = repo.commit_create_buffer(
&signature,
&signature,
Expand Down
12 changes: 11 additions & 1 deletion asyncgit/src/sync/commit_revert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,20 @@ pub fn revert_head(repo_path: &RepoPath) -> Result<CommitId> {
pub fn commit_revert(
repo_path: &RepoPath,
msg: &str,
) -> Result<CommitId> {
commit_revert_with_sign(repo_path, msg, None)
}

///
pub fn commit_revert_with_sign(
repo_path: &RepoPath,
msg: &str,
sign_override: Option<bool>,
) -> Result<CommitId> {
scope_time!("commit_revert");

let id = crate::sync::commit(repo_path, msg)?;
let id =
crate::sync::commit_with_sign(repo_path, msg, sign_override)?;

repo(repo_path)?.cleanup_state()?;

Expand Down
25 changes: 23 additions & 2 deletions asyncgit/src/sync/merge.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use crate::{
error::{Error, Result},
sync::{
branch::merge_commit::commit_merge_with_head,
branch::merge_commit::{
commit_merge_with_head, commit_merge_with_head_with_sign,
},
rebase::{
abort_rebase, continue_rebase, get_rebase_progress,
},
Expand Down Expand Up @@ -135,6 +137,16 @@ pub fn merge_commit(
repo_path: &RepoPath,
msg: &str,
ids: &[CommitId],
) -> Result<CommitId> {
merge_commit_with_sign(repo_path, msg, ids, None)
}

///
pub fn merge_commit_with_sign(
repo_path: &RepoPath,
msg: &str,
ids: &[CommitId],
sign_override: Option<bool>,
) -> Result<CommitId> {
scope_time!("merge_commit");

Expand All @@ -146,7 +158,16 @@ pub fn merge_commit(
commits.push(repo.find_commit((*id).into())?);
}

let id = commit_merge_with_head(&repo, &commits, msg)?;
let id = if sign_override.is_some() {
commit_merge_with_head_with_sign(
&repo,
&commits,
msg,
sign_override,
)?
} else {
commit_merge_with_head(&repo, &commits, msg)?
};

Ok(id)
}
Expand Down
16 changes: 11 additions & 5 deletions asyncgit/src/sync/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ pub use branch::{
merge_rebase::merge_upstream_rebase, rename::rename_branch,
validate_branch_name, BranchCompare, BranchDetails, BranchInfo,
};
pub use commit::{amend, commit, tag_commit};
pub use commit::{
amend, amend_with_sign, commit, commit_with_sign, tag_commit,
};
pub use commit_details::{
get_commit_details, CommitDetails, CommitMessage, CommitSignature,
};
Expand All @@ -55,7 +57,10 @@ pub use commit_filter::{
LogFilterSearchOptions, SearchFields, SearchOptions,
SharedCommitFilterFn,
};
pub use commit_revert::{commit_revert, revert_commit, revert_head};
pub use commit_revert::{
commit_revert, commit_revert_with_sign, revert_commit,
revert_head,
};
pub use commits_info::{
get_commit_info, get_commits_info, CommitId, CommitInfo,
};
Expand All @@ -75,8 +80,9 @@ pub use ignore::add_to_ignore;
pub use logwalker::{LogWalker, LogWalkerWithoutFilter};
pub use merge::{
abort_pending_rebase, abort_pending_state,
continue_pending_rebase, merge_branch, merge_commit, merge_msg,
mergehead_ids, rebase_progress,
continue_pending_rebase, merge_branch, merge_commit,
merge_commit_with_sign, merge_msg, mergehead_ids,
rebase_progress,
};
pub use rebase::rebase_branch;
pub use remotes::{
Expand All @@ -88,7 +94,7 @@ pub use remotes::{
pub(crate) use repository::{gix_repo, repo};
pub use repository::{RepoPath, RepoPathRef};
pub use reset::{reset_repo, reset_stage, reset_workdir};
pub use reword::reword;
pub use reword::{reword, reword_with_sign};
pub use staging::{discard_lines, stage_lines};
pub use stash::{
get_stashes, stash_apply, stash_drop, stash_pop, stash_save,
Expand Down
21 changes: 19 additions & 2 deletions asyncgit/src/sync/reword.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,24 @@ pub fn reword(
repo_path: &RepoPath,
commit: CommitId,
message: &str,
) -> Result<CommitId> {
reword_with_sign(repo_path, commit, message, None)
}

/// This is the same as reword, but allows overriding signing behavior for this operation
pub fn reword_with_sign(
repo_path: &RepoPath,
commit: CommitId,
message: &str,
sign_override: Option<bool>,
) -> Result<CommitId> {
let repo = repo(repo_path)?;
let config = repo.config()?;
let should_sign = sign_override.unwrap_or_else(|| {
config.get_bool("commit.gpgsign").unwrap_or(false)
});

if config.get_bool("commit.gpgsign").unwrap_or(false) {
if should_sign {
// HACK: we undo the last commit and create a new one
use crate::sync::utils::undo_last_commit;

Expand All @@ -32,7 +45,11 @@ pub fn reword(
.len() == 0
{
undo_last_commit(repo_path)?;
return super::commit(repo_path, message);
return super::commit_with_sign(
repo_path,
message,
Some(true),
);
}

return Err(Error::SignRewordLastCommitStaged);
Expand Down
16 changes: 15 additions & 1 deletion src/components/textinput.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ pub struct TextInputComponent {
theme: SharedTheme,
key_config: SharedKeyConfig,
input_type: InputType,
multiline_popup_height: u16,
current_area: Cell<Rect>,
embed: bool,
textarea: Option<TextAreaComponent>,
Expand All @@ -72,6 +73,7 @@ impl TextInputComponent {
default_msg: default_msg.to_string(),
selected: None,
input_type: InputType::Multiline,
multiline_popup_height: 20,
current_area: Cell::new(Rect::default()),
embed: false,
textarea: None,
Expand All @@ -88,6 +90,14 @@ impl TextInputComponent {
self
}

pub const fn with_multiline_popup_height(
mut self,
height: u16,
) -> Self {
self.multiline_popup_height = height;
self
}

///
pub fn set_input_type(&mut self, input_type: InputType) {
self.clear();
Expand Down Expand Up @@ -623,7 +633,11 @@ impl DrawableComponent for TextInputComponent {
let area = if self.embed {
rect
} else if self.input_type == InputType::Multiline {
let area = ui::centered_rect(60, 20, f.area());
let area = ui::centered_rect(
60,
self.multiline_popup_height,
f.area(),
);
ui::rect_inside(
Size::new(10, 3),
f.area().into(),
Expand Down
2 changes: 2 additions & 0 deletions src/keys/key_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ pub struct KeysList {
pub find_commit_sha: GituiKeyEvent,
pub commit_amend: GituiKeyEvent,
pub toggle_signoff: GituiKeyEvent,
pub toggle_gpgsign: GituiKeyEvent,
pub toggle_verify: GituiKeyEvent,
pub copy: GituiKeyEvent,
pub create_branch: GituiKeyEvent,
Expand Down Expand Up @@ -189,6 +190,7 @@ impl Default for KeysList {
find_commit_sha: GituiKeyEvent::new(KeyCode::Char('j'), KeyModifiers::CONTROL),
commit_amend: GituiKeyEvent::new(KeyCode::Char('a'), KeyModifiers::CONTROL),
toggle_signoff: GituiKeyEvent::new(KeyCode::Char('s'), KeyModifiers::CONTROL),
toggle_gpgsign: GituiKeyEvent::new(KeyCode::Char('g'), KeyModifiers::CONTROL),
toggle_verify: GituiKeyEvent::new(KeyCode::Char('f'), KeyModifiers::CONTROL),
copy: GituiKeyEvent::new(KeyCode::Char('y'), KeyModifiers::empty()),
create_branch: GituiKeyEvent::new(KeyCode::Char('c'), KeyModifiers::empty()),
Expand Down
Loading