Skip to content
This repository was archived by the owner on Oct 23, 2025. It is now read-only.

Commit 3946991

Browse files
authored
Merge pull request killercup#18 from killercup/fearless-syncing-in-la-salida
WIP: Make this work in a concurrent setting
2 parents 3a5b3a8 + 275f628 commit 3946991

File tree

10 files changed

+451
-63
lines changed

10 files changed

+451
-63
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@ serde_json = "1.0.31"
1919
failure_derive = "0.1.2"
2020
failure = "0.1.2"
2121
serde_derive = "1.0.79"
22+
crossbeam-channel = "0.2.6"
2223

2324
[dev-dependencies]
2425
proptest = "0.8.7"
2526
assert_fs = "0.9.0"
2627
predicates = "0.9.0"
2728
output_derive = { version = "0.1", path = "output_derive" }
29+
rand = "0.5.5"

examples/concurrent.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
extern crate failure;
2+
extern crate output;
3+
extern crate rand;
4+
5+
use output::{human, json};
6+
use rand::distributions::Distribution;
7+
use rand::distributions::Range;
8+
use rand::thread_rng;
9+
use std::thread;
10+
use std::time::Duration;
11+
12+
fn main() -> Result<(), failure::Error> {
13+
let out = output::new()
14+
.add_target(json::file("target/foo.log")?)
15+
.add_target(human::stdout()?);
16+
17+
let mut threads = vec![];
18+
for i in 0..100 {
19+
let mut out = out.clone();
20+
let t = thread::spawn(move || {
21+
let dur = Duration::from_millis({
22+
let mut rng = thread_rng();
23+
let range = Range::new(0u64, 1);
24+
range.sample(&mut rng)
25+
});
26+
thread::sleep(dur);
27+
out.print(&format!("thread {} says hello", i))
28+
});
29+
threads.push(t);
30+
}
31+
32+
threads.into_iter().for_each(|t| {
33+
t.join().unwrap().unwrap();
34+
});
35+
36+
Ok(())
37+
}

output_derive/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
//! code: 42,
2222
//! message: String::from("Derive works"),
2323
//! })?;
24+
//! # out.flush()?;
2425
//! # assert_eq!(test_target.to_string(), "code: 42\nmessage: Derive works\n\n");
2526
//! # Ok(()) }
2627
//! ```

output_derive/tests/structs.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ fn struct_with_named_fields_of_primitive_types() -> Result<(), output::Error> {
2424
name: String::from("info"),
2525
message: String::from("Derive works"),
2626
})?;
27+
out.flush()?;
2728

2829
assert_eq!(
2930
human.to_string(),
@@ -34,7 +35,7 @@ fn struct_with_named_fields_of_primitive_types() -> Result<(), output::Error> {
3435

3536
assert_eq!(
3637
json.to_string(),
37-
"{\"code\":42,\"name\":\"info\",\"message\":\"Derive works\"}\n\n"
38+
"{\"code\":42,\"name\":\"info\",\"message\":\"Derive works\"}\n"
3839
);
3940

4041
Ok(())
@@ -52,10 +53,11 @@ fn tuple_struct_of_primitive_types() -> Result<(), output::Error> {
5253
.add_target(json.target());
5354

5455
out.print(&ErrorMessage(42, String::from("Derive works")))?;
56+
out.flush()?;
5557

5658
assert_eq!(human.to_string(), "(42, Derive works)\n");
5759

58-
assert_eq!(json.to_string(), "[42,\"Derive works\"]\n\n");
60+
assert_eq!(json.to_string(), "[42,\"Derive works\"]\n");
5961

6062
Ok(())
6163
}

src/components/span.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use termcolor::{ColorSpec, WriteColor};
1+
use termcolor::ColorSpec;
22
use {human, json, Error, Render};
33

44
/// Construct a new, empty span
@@ -96,7 +96,7 @@ impl Span {
9696

9797
impl Render for Span {
9898
fn render_for_humans(&self, fmt: &mut human::Formatter) -> Result<(), Error> {
99-
fmt.writer.set_color(
99+
fmt.set_color(
100100
ColorSpec::new()
101101
.set_fg(self.fg)
102102
.set_bg(self.bg)
@@ -107,13 +107,17 @@ impl Render for Span {
107107
for item in &self.items {
108108
item.render_for_humans(fmt)?;
109109
}
110-
fmt.writer.reset()?;
110+
fmt.reset()?;
111111
Ok(())
112112
}
113113

114114
fn render_json(&self, fmt: &mut json::Formatter) -> Result<(), Error> {
115-
for item in &self.items {
116-
item.render_json(fmt)?;
115+
let len = self.items.len();
116+
for i in 0..len {
117+
self.items[i].render_json(fmt)?;
118+
if i < len - 1 {
119+
fmt.write_separator()?;
120+
}
117121
}
118122
Ok(())
119123
}
@@ -138,15 +142,18 @@ mod test {
138142

139143
let json = json::test();
140144
item.render_json(&mut json.formatter())?;
141-
assert_eq!(json.to_string(), "\"one\"\n\"two\"\n\"three\"\n");
145+
assert_eq!(json.to_string(), "\"one\"\n\"two\"\n\"three\"");
142146
Ok(())
143147
}
144148

145149
#[test]
146150
fn test_colored_output() -> Result<(), Error> {
147151
let test_target = human::test_with_color();
148152
let mut out = ::new().add_target(test_target.target());
153+
149154
out.print(span().add_item("hello").fg("green")?.bg("blue")?)?;
155+
out.flush()?;
156+
150157
assert_eq!(
151158
test_target.to_string(),
152159
"\u{1b}[0m\u{1b}[32m\u{1b}[44mhello\u{1b}[0m\n"
@@ -158,7 +165,10 @@ mod test {
158165
fn test_bold_output() -> Result<(), Error> {
159166
let test_target = human::test_with_color();
160167
let mut out = ::new().add_target(test_target.target());
168+
161169
out.print(span().add_item("hello").bold(true)?)?;
170+
out.flush()?;
171+
162172
assert_eq!(
163173
test_target.to_string(),
164174
"\u{1b}[0m\u{1b}[1mhello\u{1b}[0m\n"
@@ -170,7 +180,10 @@ mod test {
170180
fn test_intense_output() -> Result<(), Error> {
171181
let test_target = human::test_with_color();
172182
let mut out = ::new().add_target(test_target.target());
183+
173184
out.print(span().add_item("hello").fg("green")?.intense(true)?)?;
185+
out.flush()?;
186+
174187
assert_eq!(
175188
test_target.to_string(),
176189
"\u{1b}[0m\u{1b}[38;5;10mhello\u{1b}[0m\n"
@@ -182,7 +195,10 @@ mod test {
182195
fn test_underline_output() -> Result<(), Error> {
183196
let test_target = human::test_with_color();
184197
let mut out = ::new().add_target(test_target.target());
198+
185199
out.print(span().add_item("hello").underline(true)?)?;
200+
out.flush()?;
201+
186202
assert_eq!(
187203
test_target.to_string(),
188204
"\u{1b}[0m\u{1b}[4mhello\u{1b}[0m\n"

src/components/text.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use std::io::Write;
21
use {human, json, Error, Render};
32

43
/// Render some text
@@ -18,7 +17,7 @@ pub struct Text(String);
1817

1918
impl Render for Text {
2019
fn render_for_humans(&self, fmt: &mut human::Formatter) -> Result<(), Error> {
21-
fmt.writer.write_all(self.0.as_bytes())?;
20+
fmt.write(self.0.as_bytes())?;
2221
Ok(())
2322
}
2423

@@ -44,7 +43,7 @@ mod test {
4443

4544
let json = json::test();
4645
item.render_json(&mut json.formatter()).unwrap();
47-
prop_assert_eq!(json.to_string(), json!(s).to_string() + "\n");
46+
prop_assert_eq!(json.to_string(), json!(s).to_string());
4847
}
4948
}
5049
}

src/error.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ pub enum Error {
1414
/// Error dealing with JSON
1515
#[fail(display = "{}", _0)]
1616
Json(JsonError),
17+
/// Error in formatting worker
18+
#[fail(display = "{}", _0)]
19+
WorkerError(String),
20+
/// Error syncing output
21+
#[fail(display = "Error syncing output")]
22+
SyncError,
1723
}
1824

1925
impl From<io::Error> for Error {

0 commit comments

Comments
 (0)