diff options
Diffstat (limited to 'src/git.rs')
| -rw-r--r-- | src/git.rs | 92 |
1 files changed, 77 insertions, 15 deletions
| @@ -32,10 +32,13 @@ impl Repo { | |||
| 32 | pub trait RepoActions { | 32 | pub trait RepoActions { |
| 33 | fn get_path(&self) -> Result<&Path>; | 33 | fn get_path(&self) -> Result<&Path>; |
| 34 | fn get_origin_url(&self) -> Result<String>; | 34 | fn get_origin_url(&self) -> Result<String>; |
| 35 | fn get_remote_branch_names(&self) -> Result<Vec<String>>; | ||
| 35 | fn get_local_branch_names(&self) -> Result<Vec<String>>; | 36 | fn get_local_branch_names(&self) -> Result<Vec<String>>; |
| 37 | fn get_origin_main_or_master_branch(&self) -> Result<(&str, Sha1Hash)>; | ||
| 38 | fn get_local_main_or_master_branch(&self) -> Result<(&str, Sha1Hash)>; | ||
| 36 | fn get_main_or_master_branch(&self) -> Result<(&str, Sha1Hash)>; | 39 | fn get_main_or_master_branch(&self) -> Result<(&str, Sha1Hash)>; |
| 37 | fn get_checked_out_branch_name(&self) -> Result<String>; | 40 | fn get_checked_out_branch_name(&self) -> Result<String>; |
| 38 | fn get_tip_of_local_branch(&self, branch_name: &str) -> Result<Sha1Hash>; | 41 | fn get_tip_of_branch(&self, branch_name: &str) -> Result<Sha1Hash>; |
| 39 | fn get_root_commit(&self) -> Result<Sha1Hash>; | 42 | fn get_root_commit(&self) -> Result<Sha1Hash>; |
| 40 | fn does_commit_exist(&self, commit: &str) -> Result<bool>; | 43 | fn does_commit_exist(&self, commit: &str) -> Result<bool>; |
| 41 | fn get_head_commit(&self) -> Result<Sha1Hash>; | 44 | fn get_head_commit(&self) -> Result<Sha1Hash>; |
| @@ -91,7 +94,30 @@ impl RepoActions for Repo { | |||
| 91 | .to_string()) | 94 | .to_string()) |
| 92 | } | 95 | } |
| 93 | 96 | ||
| 94 | fn get_main_or_master_branch(&self) -> Result<(&str, Sha1Hash)> { | 97 | fn get_origin_main_or_master_branch(&self) -> Result<(&str, Sha1Hash)> { |
| 98 | let main_branch_name = { | ||
| 99 | let remote_branches = self | ||
| 100 | .get_remote_branch_names() | ||
| 101 | .context("cannot find any local branches")?; | ||
| 102 | if remote_branches.contains(&"origin/main".to_string()) { | ||
| 103 | "origin/main" | ||
| 104 | } else if remote_branches.contains(&"origin/master".to_string()) { | ||
| 105 | "origin/master" | ||
| 106 | } else { | ||
| 107 | bail!("no main or master branch locally in this git repository to initiate from",) | ||
| 108 | } | ||
| 109 | }; | ||
| 110 | |||
| 111 | let tip = self | ||
| 112 | .get_tip_of_branch(main_branch_name) | ||
| 113 | .context(format!( | ||
| 114 | "branch {main_branch_name} was listed as a remote branch but cannot get its tip commit id", | ||
| 115 | ))?; | ||
| 116 | |||
| 117 | Ok((main_branch_name, tip)) | ||
| 118 | } | ||
| 119 | |||
| 120 | fn get_local_main_or_master_branch(&self) -> Result<(&str, Sha1Hash)> { | ||
| 95 | let main_branch_name = { | 121 | let main_branch_name = { |
| 96 | let local_branches = self | 122 | let local_branches = self |
| 97 | .get_local_branch_names() | 123 | .get_local_branch_names() |
| @@ -106,7 +132,7 @@ impl RepoActions for Repo { | |||
| 106 | }; | 132 | }; |
| 107 | 133 | ||
| 108 | let tip = self | 134 | let tip = self |
| 109 | .get_tip_of_local_branch(main_branch_name) | 135 | .get_tip_of_branch(main_branch_name) |
| 110 | .context(format!( | 136 | .context(format!( |
| 111 | "branch {main_branch_name} was listed as a local branch but cannot get its tip commit id", | 137 | "branch {main_branch_name} was listed as a local branch but cannot get its tip commit id", |
| 112 | ))?; | 138 | ))?; |
| @@ -114,6 +140,18 @@ impl RepoActions for Repo { | |||
| 114 | Ok((main_branch_name, tip)) | 140 | Ok((main_branch_name, tip)) |
| 115 | } | 141 | } |
| 116 | 142 | ||
| 143 | fn get_main_or_master_branch(&self) -> Result<(&str, Sha1Hash)> { | ||
| 144 | if let Ok(main_tuple) = self | ||
| 145 | .get_origin_main_or_master_branch() | ||
| 146 | .context("the default branches (main or master) do not exist") | ||
| 147 | { | ||
| 148 | Ok(main_tuple) | ||
| 149 | } else { | ||
| 150 | self.get_main_or_master_branch() | ||
| 151 | .context("the default branches (main or master) do not exist") | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 117 | fn get_local_branch_names(&self) -> Result<Vec<String>> { | 155 | fn get_local_branch_names(&self) -> Result<Vec<String>> { |
| 118 | let local_branches = self | 156 | let local_branches = self |
| 119 | .git_repo | 157 | .git_repo |
| @@ -131,6 +169,23 @@ impl RepoActions for Repo { | |||
| 131 | Ok(branch_names) | 169 | Ok(branch_names) |
| 132 | } | 170 | } |
| 133 | 171 | ||
| 172 | fn get_remote_branch_names(&self) -> Result<Vec<String>> { | ||
| 173 | let remote_branches = self | ||
| 174 | .git_repo | ||
| 175 | .branches(Some(git2::BranchType::Remote)) | ||
| 176 | .context("getting GitRepo branches should not error even for a blank repository")?; | ||
| 177 | |||
| 178 | let mut branch_names = vec![]; | ||
| 179 | |||
| 180 | for iter in remote_branches { | ||
| 181 | let branch = iter?.0; | ||
| 182 | if let Some(name) = branch.name()? { | ||
| 183 | branch_names.push(name.to_string()); | ||
| 184 | } | ||
| 185 | } | ||
| 186 | Ok(branch_names) | ||
| 187 | } | ||
| 188 | |||
| 134 | fn get_checked_out_branch_name(&self) -> Result<String> { | 189 | fn get_checked_out_branch_name(&self) -> Result<String> { |
| 135 | Ok(self | 190 | Ok(self |
| 136 | .git_repo | 191 | .git_repo |
| @@ -140,11 +195,18 @@ impl RepoActions for Repo { | |||
| 140 | .to_string()) | 195 | .to_string()) |
| 141 | } | 196 | } |
| 142 | 197 | ||
| 143 | fn get_tip_of_local_branch(&self, branch_name: &str) -> Result<Sha1Hash> { | 198 | fn get_tip_of_branch(&self, branch_name: &str) -> Result<Sha1Hash> { |
| 144 | let branch = self | 199 | let branch = if let Ok(branch) = self |
| 145 | .git_repo | 200 | .git_repo |
| 146 | .find_branch(branch_name, git2::BranchType::Local) | 201 | .find_branch(branch_name, git2::BranchType::Local) |
| 147 | .context(format!("cannot find branch {branch_name}"))?; | 202 | .context(format!("cannot find local branch {branch_name}")) |
| 203 | { | ||
| 204 | branch | ||
| 205 | } else { | ||
| 206 | self.git_repo | ||
| 207 | .find_branch(branch_name, git2::BranchType::Remote) | ||
| 208 | .context(format!("cannot find local or remote branch {branch_name}"))? | ||
| 209 | }; | ||
| 148 | Ok(oid_to_sha1(&branch.into_reference().peel_to_commit()?.id())) | 210 | Ok(oid_to_sha1(&branch.into_reference().peel_to_commit()?.id())) |
| 149 | } | 211 | } |
| 150 | 212 | ||
| @@ -407,7 +469,7 @@ impl RepoActions for Repo { | |||
| 407 | branch_name: &str, | 469 | branch_name: &str, |
| 408 | patch_and_ancestors: Vec<nostr::Event>, | 470 | patch_and_ancestors: Vec<nostr::Event>, |
| 409 | ) -> Result<Vec<nostr::Event>> { | 471 | ) -> Result<Vec<nostr::Event>> { |
| 410 | let branch_tip_result = self.get_tip_of_local_branch(branch_name); | 472 | let branch_tip_result = self.get_tip_of_branch(branch_name); |
| 411 | 473 | ||
| 412 | // filter out existing ancestors in branch | 474 | // filter out existing ancestors in branch |
| 413 | let mut patches_to_apply: Vec<nostr::Event> = patch_and_ancestors | 475 | let mut patches_to_apply: Vec<nostr::Event> = patch_and_ancestors |
| @@ -1663,7 +1725,7 @@ mod tests { | |||
| 1663 | let git_repo = Repo::from_path(&test_repo.dir)?; | 1725 | let git_repo = Repo::from_path(&test_repo.dir)?; |
| 1664 | git_repo.apply_patch_chain(BRANCH_NAME, patch_events)?; | 1726 | git_repo.apply_patch_chain(BRANCH_NAME, patch_events)?; |
| 1665 | assert_eq!( | 1727 | assert_eq!( |
| 1666 | git_repo.get_tip_of_local_branch(BRANCH_NAME)?, | 1728 | git_repo.get_tip_of_branch(BRANCH_NAME)?, |
| 1667 | oid_to_sha1(&original_repo.git_repo.head()?.peel_to_commit()?.id(),), | 1729 | oid_to_sha1(&original_repo.git_repo.head()?.peel_to_commit()?.id(),), |
| 1668 | ); | 1730 | ); |
| 1669 | Ok(()) | 1731 | Ok(()) |
| @@ -1677,11 +1739,11 @@ mod tests { | |||
| 1677 | let existing_branch = test_repo.get_checked_out_branch_name()?; | 1739 | let existing_branch = test_repo.get_checked_out_branch_name()?; |
| 1678 | let git_repo = Repo::from_path(&test_repo.dir)?; | 1740 | let git_repo = Repo::from_path(&test_repo.dir)?; |
| 1679 | let previous_tip_of_existing_branch = | 1741 | let previous_tip_of_existing_branch = |
| 1680 | git_repo.get_tip_of_local_branch(existing_branch.as_str())?; | 1742 | git_repo.get_tip_of_branch(existing_branch.as_str())?; |
| 1681 | git_repo.apply_patch_chain(BRANCH_NAME, patch_events)?; | 1743 | git_repo.apply_patch_chain(BRANCH_NAME, patch_events)?; |
| 1682 | assert_eq!( | 1744 | assert_eq!( |
| 1683 | previous_tip_of_existing_branch, | 1745 | previous_tip_of_existing_branch, |
| 1684 | git_repo.get_tip_of_local_branch(existing_branch.as_str())?, | 1746 | git_repo.get_tip_of_branch(existing_branch.as_str())?, |
| 1685 | ); | 1747 | ); |
| 1686 | Ok(()) | 1748 | Ok(()) |
| 1687 | } | 1749 | } |
| @@ -1744,7 +1806,7 @@ mod tests { | |||
| 1744 | let git_repo = Repo::from_path(&test_repo.dir)?; | 1806 | let git_repo = Repo::from_path(&test_repo.dir)?; |
| 1745 | git_repo.apply_patch_chain(BRANCH_NAME, patch_events)?; | 1807 | git_repo.apply_patch_chain(BRANCH_NAME, patch_events)?; |
| 1746 | assert_eq!( | 1808 | assert_eq!( |
| 1747 | git_repo.get_tip_of_local_branch(BRANCH_NAME)?, | 1809 | git_repo.get_tip_of_branch(BRANCH_NAME)?, |
| 1748 | oid_to_sha1(&original_repo.git_repo.head()?.peel_to_commit()?.id(),), | 1810 | oid_to_sha1(&original_repo.git_repo.head()?.peel_to_commit()?.id(),), |
| 1749 | ); | 1811 | ); |
| 1750 | Ok(()) | 1812 | Ok(()) |
| @@ -1760,11 +1822,11 @@ mod tests { | |||
| 1760 | let existing_branch = test_repo.get_checked_out_branch_name()?; | 1822 | let existing_branch = test_repo.get_checked_out_branch_name()?; |
| 1761 | let git_repo = Repo::from_path(&test_repo.dir)?; | 1823 | let git_repo = Repo::from_path(&test_repo.dir)?; |
| 1762 | let previous_tip_of_existing_branch = | 1824 | let previous_tip_of_existing_branch = |
| 1763 | git_repo.get_tip_of_local_branch(existing_branch.as_str())?; | 1825 | git_repo.get_tip_of_branch(existing_branch.as_str())?; |
| 1764 | git_repo.apply_patch_chain(BRANCH_NAME, patch_events)?; | 1826 | git_repo.apply_patch_chain(BRANCH_NAME, patch_events)?; |
| 1765 | assert_eq!( | 1827 | assert_eq!( |
| 1766 | previous_tip_of_existing_branch, | 1828 | previous_tip_of_existing_branch, |
| 1767 | git_repo.get_tip_of_local_branch(existing_branch.as_str())?, | 1829 | git_repo.get_tip_of_branch(existing_branch.as_str())?, |
| 1768 | ); | 1830 | ); |
| 1769 | Ok(()) | 1831 | Ok(()) |
| 1770 | } | 1832 | } |
| @@ -1800,7 +1862,7 @@ mod tests { | |||
| 1800 | git_repo.apply_patch_chain(BRANCH_NAME, patch_events)?; | 1862 | git_repo.apply_patch_chain(BRANCH_NAME, patch_events)?; |
| 1801 | 1863 | ||
| 1802 | assert_eq!( | 1864 | assert_eq!( |
| 1803 | git_repo.get_tip_of_local_branch(BRANCH_NAME)?, | 1865 | git_repo.get_tip_of_branch(BRANCH_NAME)?, |
| 1804 | oid_to_sha1(&original_repo.git_repo.head()?.peel_to_commit()?.id(),), | 1866 | oid_to_sha1(&original_repo.git_repo.head()?.peel_to_commit()?.id(),), |
| 1805 | ); | 1867 | ); |
| 1806 | Ok(()) | 1868 | Ok(()) |
| @@ -1832,7 +1894,7 @@ mod tests { | |||
| 1832 | git_repo.apply_patch_chain(BRANCH_NAME, patch_events)?; | 1894 | git_repo.apply_patch_chain(BRANCH_NAME, patch_events)?; |
| 1833 | 1895 | ||
| 1834 | assert_eq!( | 1896 | assert_eq!( |
| 1835 | git_repo.get_tip_of_local_branch(BRANCH_NAME)?, | 1897 | git_repo.get_tip_of_branch(BRANCH_NAME)?, |
| 1836 | oid_to_sha1(&original_repo.git_repo.head()?.peel_to_commit()?.id(),), | 1898 | oid_to_sha1(&original_repo.git_repo.head()?.peel_to_commit()?.id(),), |
| 1837 | ); | 1899 | ); |
| 1838 | Ok(()) | 1900 | Ok(()) |