diff --git a/src/cook/fetch.rs b/src/cook/fetch.rs index 2d869bde..e5267fa7 100644 --- a/src/cook/fetch.rs +++ b/src/cook/fetch.rs @@ -253,19 +253,28 @@ pub fn fetch(recipe: &CookRecipe, check_source: bool, logger: &PtyOut) -> Result } } (None, false) => { - let (_, remote_branch, remote_name, remote_url) = - get_git_remote_tracking(&source_dir)?; - // TODO: how to get default branch and compare it here? - if let Some(branch) = branch - && branch != &remote_branch + let remote = get_git_remote_tracking(&source_dir)?; + if remote.local_branch != remote.tracking_branch { + false + } else if let Some(branch) = branch + && branch != &remote.tracking_branch { false - } else if remote_name != "origin" || &remote_url != chop_dot_git(git) { + } else if branch.is_none() && remote.remote_branch != remote.tracking_branch + { + false + } else if remote.remote_name != "origin" + || &remote.remote_url != chop_dot_git(git) + { false } else { git_run_fetch(logger, &source_dir, git)?; fetch_is_ran = true; - match get_git_fetch_rev(&source_dir, &remote_url, &remote_branch) { + match get_git_fetch_rev( + &source_dir, + &remote.remote_url, + &remote.remote_branch, + ) { Ok(fetch_rev) => fetch_rev == head_rev, Err(e) => { log_to_pty!(logger, "{}", e); diff --git a/src/cook/fs.rs b/src/cook/fs.rs index 87f9a344..c7fe1c0e 100644 --- a/src/cook/fs.rs +++ b/src/cook/fs.rs @@ -367,25 +367,45 @@ pub fn get_git_fetch_rev(dir: &PathBuf, remote_url: &str, remote_branch: &str) - )()) } -/// (local_branch_name, remote_branch, remote_name, remote_url) -/// -> ("fix_stuff", "master", "origin", "https://gitlab.redox-os.org/willnode/redox") -pub fn get_git_remote_tracking(dir: &PathBuf) -> Result<(String, String, String, String)> { - let git_head = dir.join(".git/HEAD"); - let git_config = dir.join(".git/config"); +#[derive(Default, Debug)] +pub struct GitRemoteTracking { + /// from .git/HEAD + pub local_branch: String, + /// from .git/config -> [branch ].merge + pub tracking_branch: String, + /// from .git/config -> [branch ].remote (usually "origin") + pub remote_name: String, + /// from refs/remotes//HEAD (the default branch on remote) + pub remote_branch: String, + /// from .git/config -> [remote ].url + pub remote_url: String, +} - let head_content = read_to_string(&git_head)?; - - if !head_content.starts_with("ref: ") { - let sha = head_content.trim_end().to_string(); - return Ok((sha, "".to_string(), "".to_string(), "".to_string())); +impl GitRemoteTracking { + pub fn detached(rev: String) -> Self { + Self { + local_branch: rev, + ..Default::default() + } } +} - let local_branch_path = head_content["ref: ".len()..].trim_end(); - let local_branch_name = get_git_branch_name(local_branch_path)?; +pub fn get_git_remote_tracking(dir: &PathBuf) -> Result { + let git_head = dir.join(".git/HEAD"); + let local_branch = { + let head_content = read_to_string(&git_head)?; + if !head_content.starts_with("ref: ") { + let rev = head_content.trim_end().to_string(); + return Ok(GitRemoteTracking::detached(rev)); + } + let path = &head_content["ref: ".len()..]; + get_git_branch_name(path.trim_end())? + }; + let git_config = dir.join(".git/config"); let config_content = read_to_string(&git_config)?; - let branch_section = format!("[branch \"{}\"]", local_branch_name); + let branch_section = format!("[branch \"{}\"]", local_branch); let mut remote_name: Option = None; let mut remote_branch: Option = None; let mut parsing_branch_section = false; @@ -413,13 +433,13 @@ pub fn get_git_remote_tracking(dir: &PathBuf) -> Result<(String, String, String, } } - let remote_name_str = remote_name.ok_or_else(wrap_other_err!( + let remote_name = remote_name.ok_or_else(wrap_other_err!( "Branch {:?} is not tracking a remote", - local_branch_name + local_branch ))?; - let remote_branch_str = remote_branch.unwrap_or("".into()); + let tracking_branch = remote_branch.unwrap_or("".into()); - let remote_section = format!("[remote \"{}\"]", remote_name_str); + let remote_section = format!("[remote \"{}\"]", remote_name); let mut remote_url: Option = None; let mut parsing_remote_section = false; @@ -445,17 +465,30 @@ pub fn get_git_remote_tracking(dir: &PathBuf) -> Result<(String, String, String, } } - let remote_url_str = remote_url.ok_or_else(wrap_other_err!( + let remote_url = remote_url.ok_or_else(wrap_other_err!( "Could not find URL for remote {:?} in .git/config.", - remote_name_str + remote_name ))?; - Ok(( - local_branch_name, - remote_branch_str, - remote_name_str, - remote_url_str, - )) + let remote_branch = { + let head_path = format!(".git/refs/remotes/{remote_name}/HEAD"); + let git_remote_head = dir.join(&head_path); + let head_content = read_to_string(&git_remote_head)?; + let path = head_content + .get("ref: ".len()..) + .ok_or_else(wrap_other_err!( + "Malformed content {:?} in {head_path}", + head_content + ))?; + get_git_branch_name(path.trim_end())? + }; + Ok(GitRemoteTracking { + local_branch, + tracking_branch, + remote_name, + remote_branch, + remote_url, + }) } pub(crate) fn chop_dot_git(url: &str) -> &str { @@ -465,14 +498,14 @@ pub(crate) fn chop_dot_git(url: &str) -> &str { url } -fn get_git_branch_name(local_branch_path: &str) -> Result { +fn get_git_branch_name(branch_path: &str) -> Result { // TODO: incorrectly handle branch with slashes - Ok(local_branch_path + Ok(branch_path .split('/') .last() .ok_or_else(wrap_other_err!( "Failed to parse branch name of {:?}", - local_branch_path + branch_path ))? .to_string()) }