Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

compile_rustfmt rewrite #6275

Merged
merged 42 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
68492c2
refactor cliInputs
benluiwj Aug 12, 2024
7a0e5dc
add compile_rustfmt skeleton
benluiwj Aug 12, 2024
e80001f
refactor git commands
benluiwj Aug 12, 2024
4fbb6de
refactor git commands
benluiwj Aug 13, 2024
273eb9b
improve git error handling
benluiwj Aug 13, 2024
bf82485
change access modifiers
benluiwj Aug 13, 2024
51a743e
add ld lib path functionality
benluiwj Aug 13, 2024
f7775df
fix ci
benluiwj Aug 13, 2024
c2a0447
revert refactors
benluiwj Aug 14, 2024
28775aa
revert test refactor
benluiwj Aug 14, 2024
8295dd7
fix ci
benluiwj Aug 14, 2024
5b93dc7
implement checkdiff error
benluiwj Aug 14, 2024
e7aec13
add check diff error
benluiwj Aug 14, 2024
f8c8953
add more functionality
benluiwj Aug 17, 2024
94cc2e0
fix build errors
benluiwj Aug 18, 2024
02908e4
cleanup git errors
benluiwj Aug 19, 2024
6af17e4
minor refactor
benluiwj Aug 19, 2024
abe74b7
implement initial rewrite
benluiwj Aug 19, 2024
31943e2
fix build errors
benluiwj Aug 19, 2024
9f76de2
fix formatting issues
benluiwj Aug 19, 2024
769285f
update paths
benluiwj Aug 23, 2024
0b38c47
implement rustfmt runner
benluiwj Aug 23, 2024
5fb2424
update return types
benluiwj Aug 23, 2024
66a2bbf
remove unused lines
benluiwj Aug 23, 2024
08281e1
update return type
benluiwj Aug 23, 2024
d639b80
update access modifiers
benluiwj Sep 13, 2024
611aa07
update struct names
benluiwj Sep 13, 2024
b366ad7
fix build errors
benluiwj Sep 14, 2024
7c99610
add allow of dead code
benluiwj Sep 14, 2024
4c90697
add comments
benluiwj Sep 14, 2024
1cda209
remove unused var
benluiwj Sep 14, 2024
7094a00
minor refactor
benluiwj Sep 21, 2024
25aa30d
improve error handling
benluiwj Sep 21, 2024
9c9403b
improve errors
benluiwj Sep 21, 2024
163b618
update error handling
benluiwj Sep 22, 2024
a00203d
fix git switch function
benluiwj Sep 29, 2024
4597a07
update logs
benluiwj Sep 29, 2024
8dff7be
remove env when compiling binaries
benluiwj Sep 29, 2024
66396f8
refactor get_binary_version
benluiwj Sep 29, 2024
831d34f
update errors
benluiwj Sep 29, 2024
1b3f053
update logs
benluiwj Sep 29, 2024
4c1328c
fix git switch
benluiwj Oct 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion check_diff/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,4 @@ edition = "2021"
clap = { version = "4.4.2", features = ["derive"] }
tracing = "0.1.37"
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
[dev-dependencies]
tempfile = "3"
216 changes: 215 additions & 1 deletion check_diff/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,49 @@
use std::env;
use std::io;
use std::path::Path;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str::Utf8Error;
use tracing::info;

pub enum CheckDiffError {
/// Git related errors
FailedGit(GitError),
/// Error for generic commands
FailedCommand(&'static str),
/// UTF8 related errors
FailedUtf8(Utf8Error),
/// Error for building rustfmt from source
FailedSourceBuild(&'static str),
/// Error when obtaining binary version
FailedBinaryVersioning(PathBuf),
/// Error when obtaining cargo version
FailedCargoVersion(&'static str),
IO(std::io::Error),
}

impl From<io::Error> for CheckDiffError {
fn from(error: io::Error) -> Self {
CheckDiffError::IO(error)
}
}
benluiwj marked this conversation as resolved.
Show resolved Hide resolved

impl From<GitError> for CheckDiffError {
fn from(error: GitError) -> Self {
CheckDiffError::FailedGit(error)
}
}

impl From<Utf8Error> for CheckDiffError {
fn from(error: Utf8Error) -> Self {
CheckDiffError::FailedUtf8(error)
}
}

pub enum GitError {
FailedClone { stdout: Vec<u8>, stderr: Vec<u8> },
FailedRemoteAdd { stdout: Vec<u8>, stderr: Vec<u8> },
FailedFetch { stdout: Vec<u8>, stderr: Vec<u8> },
FailedSwitch { stdout: Vec<u8>, stderr: Vec<u8> },
IO(std::io::Error),
}

Expand All @@ -15,6 +53,35 @@ impl From<io::Error> for GitError {
}
}

// will be used in future PRs, just added to make the compiler happy
#[allow(dead_code)]
pub struct CheckDiffRunners {
feature_runner: RustfmtRunner,
src_runner: RustfmtRunner,
}

pub struct RustfmtRunner {
ld_library_path: String,
binary_path: PathBuf,
}

impl RustfmtRunner {
fn get_binary_version(&self) -> Result<String, CheckDiffError> {
let Ok(command) = Command::new(&self.binary_path)
.env("LD_LIBRARY_PATH", &self.ld_library_path)
.args(["--version"])
.output()
else {
return Err(CheckDiffError::FailedBinaryVersioning(
self.binary_path.clone(),
));
};

let binary_version = std::str::from_utf8(&command.stdout)?.trim();
return Ok(binary_version.to_string());
}
}

/// Clone a git repository
///
/// Parameters:
Expand Down Expand Up @@ -47,6 +114,62 @@ pub fn clone_git_repo(url: &str, dest: &Path) -> Result<(), GitError> {
return Ok(());
}

pub fn git_remote_add(url: &str) -> Result<(), GitError> {
let git_cmd = Command::new("git")
.args(["remote", "add", "feature", url])
.output()?;

// if the git command does not return successfully,
// any command on the repo will fail. So fail fast.
if !git_cmd.status.success() {
let error = GitError::FailedRemoteAdd {
stdout: git_cmd.stdout,
stderr: git_cmd.stderr,
};
return Err(error);
}

info!("Successfully added remote: {url}");
return Ok(());
}

pub fn git_fetch(branch_name: &str) -> Result<(), GitError> {
let git_cmd = Command::new("git")
.args(["fetch", "feature", branch_name])
.output()?;

// if the git command does not return successfully,
// any command on the repo will fail. So fail fast.
if !git_cmd.status.success() {
let error = GitError::FailedFetch {
stdout: git_cmd.stdout,
stderr: git_cmd.stderr,
};
return Err(error);
}

info!("Successfully fetched: {branch_name}");
return Ok(());
}

pub fn git_switch(git_ref: &str, should_detach: bool) -> Result<(), GitError> {
let detach_arg = if should_detach { "--detach" } else { "" };
let args = ["switch", git_ref, detach_arg];
let output = Command::new("git")
.args(args.iter().filter(|arg| !arg.is_empty()))
.output()?;
if !output.status.success() {
tracing::error!("Git switch failed: {output:?}");
let error = GitError::FailedSwitch {
stdout: output.stdout,
stderr: output.stderr,
};
return Err(error);
}
info!("Successfully switched to {git_ref}");
return Ok(());
}

pub fn change_directory_to_path(dest: &Path) -> io::Result<()> {
let dest_path = Path::new(&dest);
env::set_current_dir(&dest_path)?;
Expand All @@ -56,3 +179,94 @@ pub fn change_directory_to_path(dest: &Path) -> io::Result<()> {
);
return Ok(());
}

pub fn get_ld_library_path() -> Result<String, CheckDiffError> {
let Ok(command) = Command::new("rustc").args(["--print", "sysroot"]).output() else {
return Err(CheckDiffError::FailedCommand("Error getting sysroot"));
};
let sysroot = std::str::from_utf8(&command.stdout)?.trim_end();
let ld_lib_path = format!("{}/lib", sysroot);
return Ok(ld_lib_path);
}

pub fn get_cargo_version() -> Result<String, CheckDiffError> {
let Ok(command) = Command::new("cargo").args(["--version"]).output() else {
return Err(CheckDiffError::FailedCargoVersion(
"Failed to obtain cargo version",
));
};

let cargo_version = std::str::from_utf8(&command.stdout)?.trim_end();
return Ok(cargo_version.to_string());
}

/// Obtains the ld_lib path and then builds rustfmt from source
/// If that operation succeeds, the source is then copied to the output path specified
pub fn build_rustfmt_from_src(binary_path: PathBuf) -> Result<RustfmtRunner, CheckDiffError> {
//Because we're building standalone binaries we need to set `LD_LIBRARY_PATH` so each
// binary can find it's runtime dependencies.
// See https://github.com/rust-lang/rustfmt/issues/5675
// This will prepend the `LD_LIBRARY_PATH` for the master rustfmt binary
let ld_lib_path = get_ld_library_path()?;

info!("Building rustfmt from source");
let Ok(_) = Command::new("cargo")
benluiwj marked this conversation as resolved.
Show resolved Hide resolved
.args(["build", "-q", "--release", "--bin", "rustfmt"])
.output()
else {
return Err(CheckDiffError::FailedSourceBuild(
"Error building rustfmt from source",
));
};

std::fs::copy("target/release/rustfmt", &binary_path)?;

return Ok(RustfmtRunner {
ld_library_path: ld_lib_path,
binary_path,
});
}

// Compiles and produces two rustfmt binaries.
// One for the current master, and another for the feature branch
// Parameters:
// dest: Directory where rustfmt will be cloned
pub fn compile_rustfmt(
dest: &Path,
remote_repo_url: String,
feature_branch: String,
commit_hash: Option<String>,
) -> Result<CheckDiffRunners, CheckDiffError> {
const RUSTFMT_REPO: &str = "https://github.com/rust-lang/rustfmt.git";

clone_git_repo(RUSTFMT_REPO, dest)?;
benluiwj marked this conversation as resolved.
Show resolved Hide resolved
change_directory_to_path(dest)?;
git_remote_add(remote_repo_url.as_str())?;
git_fetch(feature_branch.as_str())?;

let cargo_version = get_cargo_version()?;
info!("Compiling with {}", cargo_version);
let src_runner = build_rustfmt_from_src(dest.join("src_rustfmt"))?;
let should_detach = commit_hash.is_some();
git_switch(
commit_hash.unwrap_or(feature_branch).as_str(),
should_detach,
)?;

let feature_runner = build_rustfmt_from_src(dest.join("feature_rustfmt"))?;
info!("RUSFMT_BIN {}", src_runner.get_binary_version()?);
info!(
"Runtime dependencies for (src) rustfmt -- LD_LIBRARY_PATH: {}",
src_runner.ld_library_path
);
info!("FEATURE_BIN {}", feature_runner.get_binary_version()?);
info!(
"Runtime dependencies for (feature) rustfmt -- LD_LIBRARY_PATH: {}",
feature_runner.ld_library_path
);

return Ok(CheckDiffRunners {
src_runner,
feature_runner,
});
}
16 changes: 15 additions & 1 deletion check_diff/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use check_diff::compile_rustfmt;
use clap::Parser;
use tempfile::Builder;
use tracing::info;

/// Inputs for the check_diff script
#[derive(Parser)]
Expand All @@ -17,5 +20,16 @@ struct CliInputs {
}

fn main() {
let _args = CliInputs::parse();
tracing_subscriber::fmt()
.with_env_filter(tracing_subscriber::EnvFilter::from_env("CHECK_DIFF_LOG"))
.init();
let args = CliInputs::parse();
let tmp_dir = Builder::new().tempdir_in("").unwrap();
info!("Created tmp_dir {:?}", tmp_dir);
let _ = compile_rustfmt(
tmp_dir.path(),
args.remote_repo_url,
args.feature_branch,
args.commit_hash,
);
}
Loading