1use super::super::private::config;
2use super::super::private::git;
3use super::super::private::paths;
4use super::super::private::utils;
5use super::super::public::fetch;
6use super::super::public::list;
7
8#[derive(Debug)]
9pub enum PullError {
10 RepositoryMissing,
11 GetHeadBranchNameFailed,
12 GetUpstreamBranchNameFailed,
13 RebaseFailed(utils::ExecuteError),
14 FetchFailed(fetch::FetchError),
15 GetRepoRootPathFailed(paths::PathsError),
16 PathNotUtf8,
17 GetConfigFailed(config::GetConfigError),
18 ListFailed(list::ListError),
19}
20
21impl std::fmt::Display for PullError {
22 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23 match self {
24 Self::RepositoryMissing => write!(f, "repository missing"),
25 Self::GetHeadBranchNameFailed => write!(f, "get head branch name failed"),
26 Self::GetUpstreamBranchNameFailed => write!(f, "get upstream branch name failed"),
27 Self::RebaseFailed(e) => write!(f, "rebase failed, {}", e),
28 Self::FetchFailed(e) => write!(f, "fetch failed, {}", e),
29 Self::GetRepoRootPathFailed(e) => write!(f, "get repository root path failed, {}", e),
30 Self::PathNotUtf8 => write!(f, "path not utf-8"),
31 Self::GetConfigFailed(e) => write!(f, "get config failed, {}", e),
32 Self::ListFailed(e) => write!(f, "get list failed, {}", e),
33 }
34 }
35}
36
37impl std::error::Error for PullError {
38 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
39 match self {
40 Self::RepositoryMissing => None,
41 Self::GetHeadBranchNameFailed => None,
42 Self::GetUpstreamBranchNameFailed => None,
43 Self::RebaseFailed(e) => Some(e),
44 Self::FetchFailed(e) => Some(e),
45 Self::GetRepoRootPathFailed(e) => Some(e),
46 Self::PathNotUtf8 => None,
47 Self::GetConfigFailed(e) => Some(e),
48 Self::ListFailed(e) => Some(e),
49 }
50 }
51}
52
53pub fn pull(color: bool) -> Result<(), PullError> {
54 let repo = git::create_cwd_repo().map_err(|_| PullError::RepositoryMissing)?;
55
56 let repo_root_path = paths::repo_root_path(&repo).map_err(PullError::GetRepoRootPathFailed)?;
57 let repo_root_str = repo_root_path.to_str().ok_or(PullError::PathNotUtf8)?;
58 let repo_gitdir_path = repo.path();
59 let repo_gitdir_str = repo_gitdir_path.to_str().ok_or(PullError::PathNotUtf8)?;
60 let config =
61 config::get_config(repo_root_str, repo_gitdir_str).map_err(PullError::GetConfigFailed)?;
62
63 let head_ref = repo
64 .head()
65 .map_err(|_| PullError::GetHeadBranchNameFailed)?;
66 let head_branch_shorthand = head_ref
67 .shorthand()
68 .ok_or(PullError::GetHeadBranchNameFailed)?;
69 let head_branch_name = head_ref.name().ok_or(PullError::GetHeadBranchNameFailed)?;
70
71 let upstream_branch_name = git::branch_upstream_name(&repo, head_branch_name)
72 .map_err(|_| PullError::GetUpstreamBranchNameFailed)?;
73
74 println!("Fetching upstream patches...");
75 fetch::fetch(color).map_err(PullError::FetchFailed)?;
76 println!();
77
78 println!("Rebasing...");
79 utils::execute(
80 "git",
81 &[
82 "rebase",
83 "--no-reapply-cherry-picks",
84 "--onto",
85 upstream_branch_name.as_str(),
86 upstream_branch_name.as_str(),
87 head_branch_shorthand,
88 ],
89 )
90 .map_err(PullError::RebaseFailed)?;
91 println!();
92
93 if config.pull.show_list_post_pull {
94 println!("Listing patch stack...");
95 list::list(color).map_err(PullError::ListFailed)?
96 }
97
98 Ok(())
99}