Skip to content

Commit

Permalink
Use json output format in cargo if set in scarb_ui
Browse files Browse the repository at this point in the history
commit-id:fd15f5ab
  • Loading branch information
maciektr committed Feb 23, 2024
1 parent 642b1ee commit 649d230
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 5 deletions.
62 changes: 60 additions & 2 deletions scarb/src/compiler/plugin/proc_macro/compilation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ use crate::process::exec_piping;
use anyhow::Result;
use camino::Utf8PathBuf;
use libloading::library_filename;
use scarb_ui::{Message, OutputFormat};
use serde::{Serialize, Serializer};
use serde_json::value::RawValue;
use std::fmt::Display;
use std::process::Command;
use tracing::trace_span;

Expand Down Expand Up @@ -62,6 +66,7 @@ fn run_cargo(action: CargoAction, package: &Package, ws: &Workspace<'_>) -> Resu
let cmd = CargoCommand {
action,
current_dir: package.root().to_path_buf(),
output_format: ws.config().ui().output_format(),
target_dir: package
.target_path(ws.config())
.path_unchecked()
Expand All @@ -83,9 +88,33 @@ enum CargoAction {
struct CargoCommand {
current_dir: Utf8PathBuf,
target_dir: Utf8PathBuf,
output_format: OutputFormat,
action: CargoAction,
}

enum CargoOutputFormat {
Human,
Json,
}

impl Display for CargoOutputFormat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CargoOutputFormat::Human => write!(f, "human"),
CargoOutputFormat::Json => write!(f, "json"),
}
}
}

impl From<OutputFormat> for CargoOutputFormat {
fn from(format: OutputFormat) -> Self {
match format {
OutputFormat::Text => CargoOutputFormat::Human,
OutputFormat::Json => CargoOutputFormat::Json,
}
}
}

impl From<CargoCommand> for Command {
fn from(args: CargoCommand) -> Self {
let mut cmd = Command::new("cargo");
Expand All @@ -99,6 +128,9 @@ impl From<CargoCommand> for Command {
CargoAction::Fetch => (),
_ => {
cmd.arg("--release");
cmd.arg("--message-format");
let output_format: CargoOutputFormat = args.output_format.into();
cmd.arg(output_format.to_string());
cmd.arg("--target-dir");
cmd.arg(args.target_dir);
}
Expand All @@ -111,7 +143,33 @@ fn exec(cmd: &mut Command, config: &Config) -> Result<()> {
exec_piping(
cmd,
config,
|line: &str| config.ui().print(line),
|line: &str| config.ui().print(line),
|line: &str| config.ui().print(PipedText::new(line)),
|line: &str| config.ui().print(PipedText::new(line)),
)
}

/// This message can be used for piped text from subprocesses.
///
/// It accepts either a string or a JSON string.
/// If the input is a JSON string, it can be serialized as a structured message.
/// Otherwise, the structured message will be skipped.
pub struct PipedText(String);

impl PipedText {
pub fn new(text: impl Into<String>) -> Self {
Self(text.into())
}
}

impl Message for PipedText {
fn text(self) -> String {
self.0
}

fn structured<S: Serializer>(self, ser: S) -> Result<S::Ok, S::Error> {
match serde_json::from_str::<&RawValue>(self.0.as_str()) {
Ok(value) => value.serialize(ser),
Err(_e) => Self::skip_structured(ser),
}
}
}
34 changes: 34 additions & 0 deletions scarb/tests/build_cairo_plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,40 @@ fn resolve_fetched_plugins() {
assert!(t.child("Cargo.lock").exists())
}

#[test]
fn can_use_json_output() {
let t = TempDir::new().unwrap();
simple_project(&t);
let output = Scarb::quick_snapbox()
.arg("--json")
.arg("check")
// Disable colors in Cargo output.
.env("CARGO_TERM_COLOR", "never")
.current_dir(&t)
.output()
.unwrap();
assert!(
output.status.success(),
"{}",
String::from_utf8_lossy(&output.stderr)
);
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
let lines = stdout.lines().map(ToString::to_string).collect::<Vec<_>>();
let (first, lines) = lines.split_first().unwrap();
assert_matches(
r#"{"status":"checking","message":"hello v1.0.0 ([..]Scarb.toml)"}"#,
first,
);
let (last, lines) = lines.split_last().unwrap();
assert_matches(
r#"{"status":"finished","message":"checking release target(s) in [..]"}"#,
last,
);
// Line from Cargo.
let (last, _lines) = lines.split_last().unwrap();
assert_matches(r#"{"reason":"build-finished","success":true}"#, last);
}

#[test]
fn compile_cairo_plugin_with_lib_target() {
let t = TempDir::new().unwrap();
Expand Down
8 changes: 5 additions & 3 deletions utils/scarb-ui/src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,11 @@ pub trait Message {
where
Self: Sized,
{
// Silence unused warning without using underscore in variable name,
// so that it will not be populated by editors.
let _ = ser;
Self::skip_structured(ser)
}

#[doc(hidden)]
fn skip_structured<S: Serializer>(_ser: S) -> Result<S::Ok, S::Error> {
Err(serde::ser::Error::custom(JSON_SKIP_MESSAGE))
}

Expand Down

0 comments on commit 649d230

Please sign in to comment.