Skip to content

Commit

Permalink
Integrate with Sapling or Git if they exist (#4691)
Browse files Browse the repository at this point in the history
Summary:
There is some basic code here that is AFAICT only used in Meta's private version of the compiler. We can take that code, spruce it up a bit, and integrate it into the public version of the compiler!

Pull Request resolved: #4691

Test Plan: I built the compiler locally and tested against a local Sapling repo. It worked as expected. I didn't have a chance to try it on a git repo though :/

Reviewed By: captbaritone

Differential Revision: D56963384

Pulled By: bigfootjon

fbshipit-source-id: d9a59ca2a6f3e6d91abea93ff873d966e3492b87
  • Loading branch information
bigfootjon authored and facebook-github-bot committed May 9, 2024
1 parent d048828 commit 9cf21af
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 24 deletions.
2 changes: 1 addition & 1 deletion compiler/crates/relay-compiler/src/build_project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ use rustc_hash::FxHashSet;
use schema::SDLSchema;
use schema_diff::check::IncrementalBuildSchemaChange;
use schema_diff::check::SchemaChangeSafety;
pub use source_control::add_to_mercurial;
pub use source_control::source_control_for_root;
pub use validate::validate;
pub use validate::AdditionalValidations;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use serde::Serializer;
use sha1::Digest;
use sha1::Sha1;

use crate::build_project::source_control::SourceControl;
use crate::errors::BuildProjectError;
use crate::errors::Error;

Expand All @@ -40,22 +41,23 @@ pub trait ArtifactWriter {
fn finalize(&self) -> crate::errors::Result<()>;
}

type SourceControlFn =
fn(&PathBuf, &Mutex<Vec<PathBuf>>, &Mutex<Vec<PathBuf>>) -> crate::errors::Result<()>;
#[derive(Default)]
pub struct ArtifactFileWriter {
added: Mutex<Vec<PathBuf>>,
removed: Mutex<Vec<PathBuf>>,
source_control_fn: Option<SourceControlFn>,
source_control: Option<Box<dyn SourceControl + Send + Sync>>,
root_dir: PathBuf,
}

impl ArtifactFileWriter {
pub fn new(source_control_fn: Option<SourceControlFn>, root_dir: PathBuf) -> Self {
pub fn new(
source_control: Option<Box<dyn SourceControl + Send + Sync>>,
root_dir: PathBuf,
) -> Self {
Self {
added: Default::default(),
removed: Default::default(),
source_control_fn,
source_control,
root_dir,
}
}
Expand Down Expand Up @@ -112,8 +114,9 @@ impl ArtifactWriter for ArtifactFileWriter {
}

fn finalize(&self) -> crate::errors::Result<()> {
if let Some(source_control_fn) = self.source_control_fn {
(source_control_fn)(&self.root_dir, &self.added, &self.removed)
if let Some(source_control) = &self.source_control {
source_control.add_files(&self.root_dir, &self.added)?;
source_control.remove_files(&self.root_dir, &self.removed)
} else {
Ok(())
}
Expand Down
130 changes: 116 additions & 14 deletions compiler/crates/relay-compiler/src/build_project/source_control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,57 +5,159 @@
* LICENSE file in the root directory of this source tree.
*/

use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use std::process::Stdio;
use std::sync::Mutex;

use log::debug;
use log::info;

pub fn add_to_mercurial(
root_dir: &PathBuf,
added: &Mutex<Vec<PathBuf>>,
removed: &Mutex<Vec<PathBuf>>,
) -> crate::errors::Result<()> {
{
pub trait SourceControl {
fn add_files(&self, root_dir: &Path, added: &Mutex<Vec<PathBuf>>) -> crate::errors::Result<()>;

fn remove_files(
&self,
root_dir: &Path,
removed: &Mutex<Vec<PathBuf>>,
) -> crate::errors::Result<()>;
}

trait SourceControlStartAndStopCommands {
fn start_tracking_command() -> Command;

fn stop_tracking_command() -> Command;
}

impl<T> SourceControl for T
where
T: SourceControlStartAndStopCommands,
{
fn add_files(&self, root_dir: &Path, added: &Mutex<Vec<PathBuf>>) -> crate::errors::Result<()> {
let mut added = added.lock().unwrap();
if !added.is_empty() {
for added_files in added.chunks(100) {
if Command::new("hg")
if Self::start_tracking_command()
.current_dir(root_dir)
.arg("add")
.args(added_files)
.stdout(Stdio::null())
.stderr(Stdio::null())
.stdin(Stdio::null())
.spawn()
.is_err()
{
info!("Failed to run `hg add`.");
info!("Failed to run source control 'add' operation.");
}
}
added.clear();
}
Ok(())
}
{

fn remove_files(
&self,
root_dir: &Path,
removed: &Mutex<Vec<PathBuf>>,
) -> crate::errors::Result<()> {
let mut removed = removed.lock().unwrap();
if !removed.is_empty() {
for removed_files in removed.chunks(100) {
if Command::new("hg")
if Self::stop_tracking_command()
.current_dir(root_dir)
.arg("forget")
.args(removed_files)
.stdout(Stdio::null())
.stderr(Stdio::null())
.stdin(Stdio::null())
.spawn()
.is_err()
{
info!("Failed to run `hg forget`.");
info!("Failed to run source control 'remove' operation.");
}
}
removed.clear();
}
Ok(())
}
}

/// Sapling is Meta's fork of Mercurial.
/// Inside Meta, it is available as both
/// `sl`, and `hg`.
struct Sapling;

impl SourceControlStartAndStopCommands for Sapling {
fn start_tracking_command() -> Command {
let mut command = Command::new("sl");
command.arg("add");
command
}

fn stop_tracking_command() -> Command {
let mut command = Command::new("sl");
command.arg("forget");
command
}
}

struct Git;

impl SourceControlStartAndStopCommands for Git {
fn start_tracking_command() -> Command {
let mut command = Command::new("git");
command.arg("add");
command
}
Ok(())

fn stop_tracking_command() -> Command {
let mut command = Command::new("git");
command.arg("rm").arg("--cached");
command
}
}

pub fn source_control_for_root(root_dir: &PathBuf) -> Option<Box<dyn SourceControl + Send + Sync>> {
let check_git = Command::new("git")
.arg("status")
.current_dir(root_dir)
.output();

if let Ok(check_git) = check_git {
if check_git.status.success() {
debug!("Enabling git source control integration");
return Some(Box::new(Git));
}
}

// Warning: `sl` can support git repos, so it's important that we
// check the native `git` command first due to differences in
// staging behavior between the two.
let check_sapling = Command::new("sl")
.arg("root")
.current_dir(root_dir)
.output();

if let Ok(check_sapling) = check_sapling {
if check_sapling.status.success() {
let possible_steam_locomotive_check = Command::new("sl").arg("--version").output();

// The "Steam Locomotive" command also uses `sl` and doesn't have an easy way to detect
// if it is actually the `sl` command (it exits with code 0 if run as `sl root`), so we
// need to do some additional checking to make sure we can enable Sapling integration:
if let Ok(output) = possible_steam_locomotive_check {
if output.status.success()
&& String::from_utf8_lossy(&output.stdout).contains("Sapling")
{
debug!("Enabling Sapling source control integration");
return Some(Box::new(Sapling));
} else {
debug!(
"The `sl` command is not Sapling, so Sapling source control integration is disabled"
);
}
}
}
}

None
}
6 changes: 5 additions & 1 deletion compiler/crates/relay-compiler/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ use crate::errors::ConfigValidationError;
use crate::errors::Error;
use crate::errors::Result;
use crate::saved_state::SavedStateLoader;
use crate::source_control_for_root;
use crate::status_reporter::ConsoleStatusReporter;
use crate::status_reporter::StatusReporter;

Expand Down Expand Up @@ -418,7 +419,10 @@ impl Config {

let config = Self {
name: config_file.name,
artifact_writer: Box::new(ArtifactFileWriter::new(None, root_dir.clone())),
artifact_writer: Box::new(ArtifactFileWriter::new(
source_control_for_root(&root_dir),
root_dir.clone(),
)),
status_reporter: Box::new(ConsoleStatusReporter::new(
root_dir.clone(),
is_multi_project,
Expand Down
2 changes: 1 addition & 1 deletion compiler/crates/relay-compiler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ pub mod status_reporter;
mod utils;

pub use artifact_map::ArtifactSourceKey;
pub use build_project::add_to_mercurial;
pub use build_project::artifact_writer::ArtifactDifferenceShardedWriter;
pub use build_project::artifact_writer::ArtifactDifferenceWriter;
pub use build_project::artifact_writer::ArtifactFileWriter;
Expand All @@ -40,6 +39,7 @@ pub use build_project::find_duplicates;
pub use build_project::generate_artifacts;
pub use build_project::generate_extra_artifacts::GenerateExtraArtifactsFn;
pub use build_project::get_artifacts_file_hash_map::GetArtifactsFileHashMapFn;
pub use build_project::source_control_for_root;
pub use build_project::transform_program;
pub use build_project::validate;
pub use build_project::validate_program;
Expand Down

0 comments on commit 9cf21af

Please sign in to comment.