Skip to content

Commit

Permalink
internal: structural error handling for git commands
Browse files Browse the repository at this point in the history
  • Loading branch information
lijunchen committed Sep 10, 2024
1 parent 0a5e0dc commit 7cbce27
Show file tree
Hide file tree
Showing 3 changed files with 266 additions and 89 deletions.
4 changes: 2 additions & 2 deletions crates/moonbuild/src/new.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,8 @@ fn common(
) -> anyhow::Result<i32> {
std::fs::create_dir_all(target_dir).context("failed to create target directory")?;

if !is_in_git_repo(target_dir) {
git_init_repo(target_dir);
if !is_in_git_repo(target_dir)? {
git_init_repo(target_dir)?;
}

{
Expand Down
233 changes: 170 additions & 63 deletions crates/mooncake/src/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,97 +18,204 @@

use std::path::Path;

use anyhow::bail;
use colored::Colorize;
use moonutil::mooncakes::RegistryConfig;
use moonutil::{
git::{GitCommandError, Stdios},
mooncakes::RegistryConfig,
};

#[derive(Debug, thiserror::Error)]
#[error("failed to clone registry index")]
struct CloneRegistryIndexError {
#[source]
source: CloneRegistryIndexErrorKind,
}

#[derive(Debug, thiserror::Error)]
enum CloneRegistryIndexErrorKind {
#[error(transparent)]
GitCommandError(#[from] GitCommandError),

#[error(transparent)]
IO(#[from] std::io::Error),

#[error("non-zero exit code: {0}")]
NonZeroExitCode(std::process::ExitStatus),
}

fn clone_registry_index(
registry_config: &RegistryConfig,
target_dir: &Path,
) -> anyhow::Result<i32> {
let output = std::process::Command::new("git")
.arg("clone")
.arg(&registry_config.index)
.arg(target_dir)
.spawn()?
.wait();
match output {
Ok(status) => {
if !status.success() {
bail!("Failed to clone registry index");
}
Ok(0)
}
Err(e) => {
eprintln!("Failed to clone registry index: {}", e);
bail!("Failed to clone registry index");
}
) -> Result<(), CloneRegistryIndexError> {
let mut child = moonutil::git::git_command(
&[
"clone",
&registry_config.index,
target_dir.to_str().unwrap(),
],
Stdios::npp(),
)
.map_err(|e| CloneRegistryIndexError {
source: CloneRegistryIndexErrorKind::GitCommandError(e),
})?;

let status = child.wait().map_err(|e| CloneRegistryIndexError {
source: CloneRegistryIndexErrorKind::IO(e),
})?;
if !status.success() {
return Err(CloneRegistryIndexError {
source: CloneRegistryIndexErrorKind::NonZeroExitCode(status),
});
}
Ok(())
}

#[derive(Debug, thiserror::Error)]
#[error("failed to pull latest registry index")]
struct PullLatestRegistryIndexError {
#[source]
source: PullLatestRegistryIndexErrorKind,
}

#[derive(Debug, thiserror::Error)]
enum PullLatestRegistryIndexErrorKind {
#[error(transparent)]
GitCommandError(GitCommandError),

#[error(transparent)]
IO(#[from] std::io::Error),

#[error("non-zero exit code: {0}")]
NonZeroExitCode(std::process::ExitStatus),
}

fn pull_latest_registry_index(
_registry_config: &RegistryConfig,
target_dir: &Path,
) -> anyhow::Result<i32> {
let output = std::process::Command::new("git")
.arg("pull")
.arg("origin")
.arg("main")
.current_dir(target_dir)
.spawn()?
.wait()?;

match output.code() {
Some(code) => {
if code != 0 {
bail!("Failed to pull registry index");
}
Ok(0)
}
None => {
eprintln!("Failed to pull registry index");
bail!("Failed to pull registry index");
}
) -> Result<(), PullLatestRegistryIndexError> {
let mut child = moonutil::git::git_command(
&["-C", target_dir.to_str().unwrap(), "pull", "origin", "main"],
Stdios::npp(),
)
.map_err(|e| PullLatestRegistryIndexError {
source: PullLatestRegistryIndexErrorKind::GitCommandError(e),
})?;
let status = child.wait().map_err(|e| PullLatestRegistryIndexError {
source: PullLatestRegistryIndexErrorKind::IO(e),
})?;
if !status.success() {
return Err(PullLatestRegistryIndexError {
source: PullLatestRegistryIndexErrorKind::NonZeroExitCode(status),
});
}
Ok(())
}

#[derive(Debug, thiserror::Error)]
#[error("update failed")]
struct UpdateError {
#[source]
source: UpdateErrorKind,
}

#[derive(Debug, thiserror::Error)]
enum UpdateErrorKind {
#[error(transparent)]
CloneRegistryIndexError(#[from] CloneRegistryIndexError),

#[error(transparent)]
PullLatestRegistryIndexError(#[from] PullLatestRegistryIndexError),

#[error(transparent)]
GetRemoteUrlError(#[from] GetRemoteUrlError),

#[error(transparent)]
IO(#[from] std::io::Error),
}

#[derive(Debug, thiserror::Error)]
#[error("failed to get remote url")]
struct GetRemoteUrlError {
#[source]
source: GetRemoteUrlErrorKind,
}

#[derive(Debug, thiserror::Error)]
enum GetRemoteUrlErrorKind {
#[error(transparent)]
GitCommandError(#[from] GitCommandError),

#[error(transparent)]
IO(#[from] std::io::Error),
}

fn get_remote_url(target_dir: &Path) -> Result<String, GetRemoteUrlError> {
let output = moonutil::git::git_command(
&[
"-C",
target_dir.to_str().unwrap(),
"remote",
"get-url",
"origin",
],
Stdios::npp(),
)
.map_err(|e| GetRemoteUrlError {
source: GetRemoteUrlErrorKind::GitCommandError(e),
})?
.wait_with_output()
.map_err(|e| GetRemoteUrlError {
source: GetRemoteUrlErrorKind::IO(e),
})?;
let url = String::from_utf8_lossy(&output.stdout).trim().to_string();
Ok(url)
}

pub fn update(target_dir: &Path, registry_config: &RegistryConfig) -> anyhow::Result<i32> {
if target_dir.exists() {
let output = std::process::Command::new("git")
.arg("remote")
.arg("get-url")
.arg("origin")
.current_dir(target_dir)
.output()?;

let url = String::from_utf8_lossy(&output.stdout).trim().to_string();
let url = get_remote_url(target_dir).map_err(|e| UpdateError {
source: UpdateErrorKind::GetRemoteUrlError(e),
})?;
if url == registry_config.index {
let result = pull_latest_registry_index(registry_config, target_dir);
if result.is_err() {
eprintln!(
"Failed to update registry, {}",
"re-cloning".bold().yellow()
);
std::fs::remove_dir_all(target_dir)?;
clone_registry_index(registry_config, target_dir)?;
eprintln!("{}", "Registry index re-cloned successfully".bold().green());
Ok(0)
} else {
eprintln!("{}", "Registry index updated successfully".bold().green());
Ok(0)
match result {
Err(_) => {
eprintln!(
"failed to update registry, {}",
"re-cloning".bold().yellow()
);
std::fs::remove_dir_all(target_dir).map_err(|e| UpdateError {
source: UpdateErrorKind::IO(e),
})?;
clone_registry_index(registry_config, target_dir).map_err(|e| UpdateError {
source: UpdateErrorKind::CloneRegistryIndexError(e),
})?;
eprintln!("{}", "Registry index re-cloned successfully".bold().green());
Ok(0)
}
Ok(()) => {
eprintln!("{}", "Registry index updated successfully".bold().green());
Ok(0)
}
}
} else {
eprintln!(
"Registry index is not cloned from the same URL, {}",
"re-cloning".yellow().bold()
);
std::fs::remove_dir_all(target_dir)?;
clone_registry_index(registry_config, target_dir)?;
std::fs::remove_dir_all(target_dir).map_err(|e| UpdateError {
source: UpdateErrorKind::IO(e),
})?;
clone_registry_index(registry_config, target_dir).map_err(|e| UpdateError {
source: UpdateErrorKind::CloneRegistryIndexError(e),
})?;
eprintln!("{}", "Registry index re-cloned successfully".bold().green());
Ok(0)
}
} else {
clone_registry_index(registry_config, target_dir)?;
clone_registry_index(registry_config, target_dir).map_err(|e| UpdateError {
source: UpdateErrorKind::CloneRegistryIndexError(e),
})?;
eprintln!("{}", "Registry index cloned successfully".bold().green());
Ok(0)
}
Expand Down
Loading

0 comments on commit 7cbce27

Please sign in to comment.