mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 21:35:00 +00:00
96 lines
3 KiB
Rust
96 lines
3 KiB
Rust
use std::io::Write;
|
|
use std::path::{Path, PathBuf};
|
|
use std::process::{Command, Stdio};
|
|
|
|
use serde::Deserialize;
|
|
use uv_git::GIT;
|
|
|
|
#[derive(Debug, traversable_error::TraversableError, thiserror::Error)]
|
|
pub enum VersionControlError {
|
|
#[error("Attempted to initialize a Git repository, but `git` was not found in PATH")]
|
|
GitNotInstalled,
|
|
#[error("Failed to initialize Git repository at `{0}`\nstdout: {1}\nstderr: {2}")]
|
|
GitInit(PathBuf, String, String),
|
|
#[error("`git` command failed")]
|
|
GitCommand(#[source] std::io::Error),
|
|
#[error(transparent)]
|
|
Io(#[from] std::io::Error),
|
|
}
|
|
|
|
/// The version control system to use.
|
|
#[derive(Clone, Copy, Debug, PartialEq, Default, Deserialize)]
|
|
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
|
|
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
|
|
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
|
pub enum VersionControlSystem {
|
|
/// Use Git for version control.
|
|
#[default]
|
|
Git,
|
|
/// Do not use any version control system.
|
|
None,
|
|
}
|
|
|
|
impl VersionControlSystem {
|
|
/// Initializes the VCS system based on the provided path.
|
|
pub fn init(&self, path: &Path) -> Result<(), VersionControlError> {
|
|
match self {
|
|
Self::Git => {
|
|
let Ok(git) = GIT.as_ref() else {
|
|
return Err(VersionControlError::GitNotInstalled);
|
|
};
|
|
|
|
let output = Command::new(git)
|
|
.arg("init")
|
|
.current_dir(path)
|
|
.stdout(Stdio::piped())
|
|
.stderr(Stdio::piped())
|
|
.output()
|
|
.map_err(VersionControlError::GitCommand)?;
|
|
if !output.status.success() {
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
return Err(VersionControlError::GitInit(
|
|
path.to_path_buf(),
|
|
stdout.to_string(),
|
|
stderr.to_string(),
|
|
));
|
|
}
|
|
|
|
// Create the `.gitignore`, if it doesn't exist.
|
|
match fs_err::OpenOptions::new()
|
|
.write(true)
|
|
.create_new(true)
|
|
.open(path.join(".gitignore"))
|
|
{
|
|
Ok(mut file) => file.write_all(GITIGNORE.as_bytes())?,
|
|
Err(err) if err.kind() == std::io::ErrorKind::AlreadyExists => (),
|
|
Err(err) => return Err(err.into()),
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
Self::None => Ok(()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for VersionControlSystem {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
Self::Git => write!(f, "git"),
|
|
Self::None => write!(f, "none"),
|
|
}
|
|
}
|
|
}
|
|
|
|
const GITIGNORE: &str = "# Python-generated files
|
|
__pycache__/
|
|
*.py[oc]
|
|
build/
|
|
dist/
|
|
wheels/
|
|
*.egg-info
|
|
|
|
# Virtual environments
|
|
.venv
|
|
";
|