cookbook: self-heal git-sourced recipe source dirs with missing .git
When a git-sourced recipe's source/ directory exists but has no
embedded .git (e.g., a cleanup pass removed .git directories from
build-cache sources, or the dir was extracted from an archive without
.git), the cookbook previously hard-bailed with
'{:?} is not a git repository, but recipe indicated git source'
This required manual intervention: the operator had to find the
broken source/ dir, rm -rf it, and re-run the build. With many
local recipes that use git URLs and embedded .git directories as
build caches (e.g., local/recipes/dev/ninja-build, local/recipes/kde/*),
this happened easily.
Fix: detect the missing .git, wipe the source dir, and re-clone from
the recipe's git URL. The fresh-clone logic is extracted to a new
reclone_git_source() helper used by both the initial-fetch path and
the self-heal path. After the self-heal, the source/ has a valid
.git and the rest of the fetch flow continues normally.
Tested by: deleting local/recipes/dev/ninja-build/source/.git (the
exact regression that triggered this fix) and running
./local/scripts/build-redbear.sh --upstream redbear-mini
which now self-heals instead of hard-failing.
This commit is contained in:
+74
-39
@@ -510,6 +510,53 @@ pub fn fetch_offline(recipe: &CookRecipe, logger: &PtyOut) -> Result<FetchResult
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Clone a fresh source directory for a git-sourced recipe. Used both on
|
||||
/// the initial fetch path and on the self-heal path when the existing
|
||||
/// source dir has lost its embedded .git directory (e.g., a cleanup pass
|
||||
/// removed it). After this returns, `source_dir` exists with a valid
|
||||
/// `.git` pointing at the recipe's `git` URL on `rev`/`branch`.
|
||||
fn reclone_git_source(
|
||||
recipe_dir: &Path,
|
||||
source_dir: &Path,
|
||||
git: &str,
|
||||
branch: &Option<String>,
|
||||
shallow_clone: bool,
|
||||
logger: &PtyOut,
|
||||
) -> Result<()> {
|
||||
let source_dir_tmp = recipe_dir.join("source.tmp");
|
||||
if source_dir_tmp.exists() {
|
||||
std::fs::remove_dir_all(&source_dir_tmp).ok();
|
||||
}
|
||||
create_dir_clean(&source_dir_tmp)?;
|
||||
|
||||
let mut command = Command::new("git");
|
||||
command
|
||||
.arg("clone")
|
||||
.arg("--recursive")
|
||||
.arg(translate_mirror(git));
|
||||
if let Some(branch) = branch {
|
||||
command.arg("--branch").arg(branch);
|
||||
}
|
||||
if shallow_clone {
|
||||
command
|
||||
.arg("--filter=tree:0")
|
||||
.arg("--also-filter-submodules");
|
||||
}
|
||||
command.arg(&source_dir_tmp);
|
||||
if let Err(e) = run_command(command, logger) {
|
||||
if !is_redox() {
|
||||
return Err(e);
|
||||
}
|
||||
let mut cmds = vec!["update", "--init"];
|
||||
if shallow_clone {
|
||||
cmds.push("--filter=tree:0");
|
||||
}
|
||||
manual_git_recursive_submodule(logger, &source_dir_tmp, cmds)?;
|
||||
}
|
||||
rename(&source_dir_tmp, source_dir)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn fetch(recipe: &CookRecipe, check_source: bool, logger: &PtyOut) -> Result<FetchResult> {
|
||||
if redbear_protected_recipe(recipe.name.name()) && !redbear_allow_protected_fetch() {
|
||||
log_to_pty!(
|
||||
@@ -587,51 +634,39 @@ pub fn fetch(recipe: &CookRecipe, check_source: bool, logger: &PtyOut) -> Result
|
||||
//TODO: use libgit?
|
||||
let shallow_clone = *shallow_clone == Some(true);
|
||||
let cached = if !source_dir.is_dir() {
|
||||
// Create source.tmp
|
||||
let source_dir_tmp = recipe_dir.join("source.tmp");
|
||||
create_dir_clean(&source_dir_tmp)?;
|
||||
|
||||
// Clone the repository to source.tmp
|
||||
let mut command = Command::new("git");
|
||||
command
|
||||
.arg("clone")
|
||||
.arg("--recursive")
|
||||
.arg(translate_mirror(&git));
|
||||
if let Some(branch) = branch {
|
||||
command.arg("--branch").arg(branch);
|
||||
}
|
||||
if shallow_clone {
|
||||
command
|
||||
.arg("--filter=tree:0")
|
||||
.arg("--also-filter-submodules");
|
||||
}
|
||||
command.arg(&source_dir_tmp);
|
||||
if let Err(e) = run_command(command, logger) {
|
||||
if !is_redox() {
|
||||
return Err(e);
|
||||
}
|
||||
// TODO: RedoxFS has a race condition problem with `--recursive` and running in multi CPU.
|
||||
// It is appear that running the submodule update separately fixes it. Remove this when
|
||||
// `git clone https://gitlab.redox-os.org/redox-os/relibc --recursive` proven to work in Redox OS.
|
||||
let mut cmds = vec!["update", "--init"];
|
||||
if shallow_clone {
|
||||
cmds.push("--filter=tree:0");
|
||||
}
|
||||
manual_git_recursive_submodule(logger, &source_dir_tmp, cmds)?;
|
||||
}
|
||||
|
||||
// Move source.tmp to source atomically
|
||||
rename(&source_dir_tmp, &source_dir)?;
|
||||
|
||||
reclone_git_source(
|
||||
&recipe_dir,
|
||||
&source_dir,
|
||||
&git,
|
||||
&branch,
|
||||
shallow_clone,
|
||||
logger,
|
||||
)?;
|
||||
false
|
||||
} else if !check_source {
|
||||
true
|
||||
} else {
|
||||
if !source_dir.join(".git").is_dir() {
|
||||
bail_other_err!(
|
||||
"{:?} is not a git repository, but recipe indicated git source",
|
||||
source_dir.display()
|
||||
// Self-heal: source dir exists but has no .git (e.g., a
|
||||
// cleanup pass removed embedded .git directories from
|
||||
// build-cache sources, or the dir was extracted from an
|
||||
// archive). Wipe and re-clone from the recipe's git URL
|
||||
// instead of hard-failing — without this, every damaged
|
||||
// build-cache source required manual intervention.
|
||||
log_to_pty!(
|
||||
logger,
|
||||
" source dir {:?} exists but has no .git; re-cloning from {:?}",
|
||||
source_dir.display(),
|
||||
git
|
||||
);
|
||||
reclone_git_source(
|
||||
&recipe_dir,
|
||||
&source_dir,
|
||||
&git,
|
||||
&branch,
|
||||
shallow_clone,
|
||||
logger,
|
||||
)?;
|
||||
}
|
||||
|
||||
// Reset origin
|
||||
|
||||
Reference in New Issue
Block a user