Skip to content

Commit

Permalink
Migrate version reporting to the orchestrator
Browse files Browse the repository at this point in the history
  • Loading branch information
shepmaster committed Nov 30, 2023
1 parent 9f4880c commit 235ffe9
Show file tree
Hide file tree
Showing 6 changed files with 351 additions and 158 deletions.
230 changes: 230 additions & 0 deletions compiler/base/orchestrator/src/coordinator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,134 @@ use crate::{
DropErrorDetailsExt,
};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Versions {
pub stable: ChannelVersions,
pub beta: ChannelVersions,
pub nightly: ChannelVersions,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ChannelVersions {
pub rustc: Version,
pub rustfmt: Version,
pub clippy: Version,
pub miri: Option<Version>,
}

/// Parsing this struct is very lenient — we'd rather return some
/// partial data instead of absolutely nothing.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Version {
pub release: String,
pub commit_hash: String,
pub commit_date: String,
}

impl Version {
fn parse_rustc_version_verbose(rustc_version: &str) -> Self {
let mut release = "";
let mut commit_hash = "";
let mut commit_date = "";

let fields = rustc_version.lines().skip(1).filter_map(|line| {
let mut pieces = line.splitn(2, ':');
let key = pieces.next()?.trim();
let value = pieces.next()?.trim();
Some((key, value))
});

for (k, v) in fields {
match k {
"release" => release = v,
"commit-hash" => commit_hash = v,
"commit-date" => commit_date = v,
_ => {}
}
}

Self {
release: release.into(),
commit_hash: commit_hash.into(),
commit_date: commit_date.into(),
}
}

// Parses versions of the shape `toolname 0.0.0 (0000000 0000-00-00)`
fn parse_tool_version(tool_version: &str) -> Self {
let mut parts = tool_version.split_whitespace().fuse().skip(1);

let release = parts.next().unwrap_or("").into();
let commit_hash = parts.next().unwrap_or("").trim_start_matches('(').into();
let commit_date = parts.next().unwrap_or("").trim_end_matches(')').into();

Self {
release,
commit_hash,
commit_date,
}
}
}

#[derive(Debug, Snafu)]
#[snafu(module)]
pub enum VersionsError {
#[snafu(display("Unable to determine versions for the stable channel"))]
Stable { source: VersionsChannelError },

#[snafu(display("Unable to determine versions for the beta channel"))]
Beta { source: VersionsChannelError },

#[snafu(display("Unable to determine versions for the nightly channel"))]
Nightly { source: VersionsChannelError },
}

#[derive(Debug, Snafu)]
pub enum VersionsChannelError {
#[snafu(context(false))] // transparent
Channel { source: Error },

#[snafu(context(false))] // transparent
Versions { source: ContainerVersionsError },
}

#[derive(Debug, Snafu)]
#[snafu(module)]
pub enum ContainerVersionsError {
#[snafu(display("Failed to get `rustc` version"))]
Rustc { source: VersionError },

#[snafu(display("`rustc` not executable"))]
RustcMissing,

#[snafu(display("Failed to get `rustfmt` version"))]
Rustfmt { source: VersionError },

#[snafu(display("`cargo fmt` not executable"))]
RustfmtMissing,

#[snafu(display("Failed to get clippy version"))]
Clippy { source: VersionError },

#[snafu(display("`cargo clippy` not executable"))]
ClippyMissing,

#[snafu(display("Failed to get miri version"))]
Miri { source: VersionError },
}

#[derive(Debug, Snafu)]
#[snafu(module)]
pub enum VersionError {
#[snafu(display("Could not start the process"))]
#[snafu(context(false))]
SpawnProcess { source: SpawnCargoError },

#[snafu(display("The task panicked"))]
#[snafu(context(false))]
TaskPanic { source: tokio::task::JoinError },
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum AssemblyFlavor {
Att,
Expand Down Expand Up @@ -639,6 +767,28 @@ where
}
}

pub async fn versions(&self) -> Result<Versions, VersionsError> {
use versions_error::*;

let [stable, beta, nightly] =
[Channel::Stable, Channel::Beta, Channel::Nightly].map(|c| async move {
let c = self.select_channel(c).await?;
c.versions().await.map_err(VersionsChannelError::from)
});

let (stable, beta, nightly) = join!(stable, beta, nightly);

let stable = stable.context(StableSnafu)?;
let beta = beta.context(BetaSnafu)?;
let nightly = nightly.context(NightlySnafu)?;

Ok(Versions {
stable,
beta,
nightly,
})
}

pub async fn execute(
&self,
request: ExecuteRequest,
Expand Down Expand Up @@ -904,6 +1054,72 @@ impl Container {
})
}

async fn versions(&self) -> Result<ChannelVersions, ContainerVersionsError> {
use container_versions_error::*;

let token = CancellationToken::new();

let rustc = self.rustc_version(token.clone());
let rustfmt = self.tool_version(token.clone(), "fmt");
let clippy = self.tool_version(token.clone(), "clippy");
let miri = self.tool_version(token, "miri");

let (rustc, rustfmt, clippy, miri) = join!(rustc, rustfmt, clippy, miri);

let rustc = rustc.context(RustcSnafu)?.context(RustcMissingSnafu)?;
let rustfmt = rustfmt
.context(RustfmtSnafu)?
.context(RustfmtMissingSnafu)?;
let clippy = clippy.context(ClippySnafu)?.context(ClippyMissingSnafu)?;
let miri = miri.context(MiriSnafu)?;

Ok(ChannelVersions {
rustc,
rustfmt,
clippy,
miri,
})
}

async fn rustc_version(
&self,
token: CancellationToken,
) -> Result<Option<Version>, VersionError> {
let rustc_cmd = ExecuteCommandRequest::simple("rustc", ["--version", "--verbose"]);
let output = self.version_output(token, rustc_cmd).await?;

Ok(output.map(|o| Version::parse_rustc_version_verbose(&o)))
}

async fn tool_version(
&self,
token: CancellationToken,
subcommand_name: &str,
) -> Result<Option<Version>, VersionError> {
let tool_cmd = ExecuteCommandRequest::simple("cargo", [subcommand_name, "--version"]);
let output = self.version_output(token, tool_cmd).await?;

Ok(output.map(|o| Version::parse_tool_version(&o)))
}

async fn version_output(
&self,
token: CancellationToken,
cmd: ExecuteCommandRequest,
) -> Result<Option<String>, VersionError> {
let v = self.spawn_cargo_task(token.clone(), cmd).await?;
let SpawnCargo {
task,
stdin_tx,
stdout_rx,
stderr_rx,
} = v;
drop(stdin_tx);
let task = async { task.await?.map_err(VersionError::from) };
let o = WithOutput::try_absorb(task, stdout_rx, stderr_rx).await?;
Ok(if o.success { Some(o.stdout) } else { None })
}

async fn execute(
&self,
request: ExecuteRequest,
Expand Down Expand Up @@ -2416,6 +2632,20 @@ mod tests {
}
}

#[tokio::test]
#[snafu::report]
async fn versions() -> Result<()> {
let coordinator = new_coordinator().await;

let versions = coordinator.versions().with_timeout().await.unwrap();

assert_starts_with!(versions.stable.rustc.release, "1.");

coordinator.shutdown().await?;

Ok(())
}

const ARBITRARY_EXECUTE_REQUEST: ExecuteRequest = ExecuteRequest {
channel: Channel::Stable,
mode: Mode::Debug,
Expand Down
14 changes: 14 additions & 0 deletions compiler/base/orchestrator/src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,20 @@ pub struct ExecuteCommandRequest {
pub cwd: Option<String>, // None means in project direcotry.
}

impl ExecuteCommandRequest {
pub fn simple(
cmd: impl Into<String>,
args: impl IntoIterator<Item = impl Into<String>>,
) -> Self {
Self {
cmd: cmd.into(),
args: args.into_iter().map(Into::into).collect(),
envs: Default::default(),
cwd: None,
}
}
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ExecuteCommandResponse {
pub success: bool,
Expand Down
18 changes: 8 additions & 10 deletions ui/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,14 @@ enum Error {
#[snafu(display("The WebSocket worker panicked: {}", text))]
WebSocketTaskPanic { text: String },

#[snafu(display("Unable to find the available versions"))]
Versions {
source: orchestrator::coordinator::VersionsError,
},

#[snafu(display("The Miri version was missing"))]
MiriVersion,

#[snafu(display("Unable to shutdown the coordinator"))]
ShutdownCoordinator {
source: orchestrator::coordinator::Error,
Expand Down Expand Up @@ -471,16 +479,6 @@ impl From<Vec<sandbox::CrateInformation>> for MetaCratesResponse {
}
}

impl From<sandbox::Version> for MetaVersionResponse {
fn from(me: sandbox::Version) -> Self {
MetaVersionResponse {
version: me.release.into(),
hash: me.commit_hash.into(),
date: me.commit_date.into(),
}
}
}

impl From<gist::Gist> for MetaGistResponse {
fn from(me: gist::Gist) -> Self {
MetaGistResponse {
Expand Down
6 changes: 0 additions & 6 deletions ui/src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,12 +227,6 @@ impl SuccessDetails for Vec<sandbox::CrateInformation> {
}
}

impl SuccessDetails for sandbox::Version {
fn success_details(&self) -> Outcome {
Outcome::Success
}
}

pub(crate) async fn track_metric_no_request_async<B, Fut, Resp>(
endpoint: Endpoint,
body: B,
Expand Down
Loading

0 comments on commit 235ffe9

Please sign in to comment.