git.delta.rocks / jrsonnet / refs/commits / a69298f739ac

difftreelog

feat multiple trace formats

Лач2020-06-06parent: #e614efa.patch.diff
in: master

1 file changed

modifiedcmds/jsonnet/src/main.rsdiffbeforeafterboth
1use clap::Clap;1use clap::Clap;
2use jsonnet_evaluator::Val;2use jsonnet_evaluator::{EvaluationState, LocError, StackTrace, Val};
3use std::env::current_dir;
3use std::str::FromStr;4use std::str::FromStr;
45
5enum Format {6enum Format {
6 None,7 None,
7 Json,8 Json,
9 Yaml,
8}10}
911
10impl FromStr for Format {12impl FromStr for Format {
13 Ok(match s {15 Ok(match s {
14 "none" => Format::None,16 "none" => Format::None,
15 "json" => Format::Json,17 "json" => Format::Json,
18 "yaml" => Format::Yaml,
16 _ => return Err("no such format"),19 _ => return Err("no such format"),
17 })20 })
18 }21 }
19}22}
23
24#[derive(PartialEq)]
25enum TraceFormat {
26 CppJsonnet,
27 GoJsonnet,
28 Custom,
29}
30impl FromStr for TraceFormat {
31 type Err = &'static str;
32 fn from_str(s: &str) -> Result<Self, Self::Err> {
33 Ok(match s {
34 "cpp" => TraceFormat::CppJsonnet,
35 "go" => TraceFormat::GoJsonnet,
36 "default" => TraceFormat::Custom,
37 _ => return Err("no such format"),
38 })
39 }
40}
2041
21#[derive(Clap)]42#[derive(Clap)]
22#[clap(version = "0.1.0", author = "Lach <iam@lach.pw>")]43#[clap(version = "0.1.0", author = "Lach <iam@lach.pw>")]
31 tla_str: Option<Vec<String>>,52 tla_str: Option<Vec<String>>,
32 #[clap(long, about = "Add TLA from code")]53 #[clap(long, about = "Add TLA from code")]
33 tla_code: Option<Vec<String>>,54 tla_code: Option<Vec<String>>,
34 #[clap(long, short = "f", default_value = "json", possible_values = &["none", "json"])]55 #[clap(long, short = "f", default_value = "json", possible_values = &["none", "json", "yaml"], about = "Output format, wraps resulting value to corresponding std.manifest call")]
35 format: Format,56 format: Format,
57 #[clap(long, default_value = "default", possible_values = &["cpp", "go", "default"], about = "Emulated needed stacktrace display")]
58 trace_format: TraceFormat,
59
60 #[clap(
61 long,
62 short = "s",
63 default_value = "200",
64 about = "Number of allowed stack frames"
65 )]
66 max_stack: usize,
67 #[clap(
68 long,
69 short = "t",
70 default_value = "20",
71 about = "Max length of stack trace before cropping"
72 )]
73 max_trace: usize,
74
36 #[clap(about = "File to compile")]75 #[clap(about = "File to compile", index = 1)]
37 input: String,76 input: String,
38}77}
78
79fn main() {
80 let opts: Opts = Opts::parse();
81 let evaluator = jsonnet_evaluator::EvaluationState::default();
82 if !opts.no_stdlib {
83 evaluator.add_stdlib();
84 }
85 let mut input = current_dir().unwrap();
86 input.push(opts.input.clone());
87 evaluator
88 .add_file(
89 input.clone(),
90 String::from_utf8(std::fs::read(opts.input.clone()).unwrap()).unwrap(),
91 )
92 .unwrap();
93 let result = evaluator.evaluate_file(&input);
94 match result {
95 Ok(v) => {
96 let v = match opts.format {
97 Format::Json => {
98 if opts.no_stdlib {
99 evaluator.add_stdlib();
100 }
101 evaluator.add_global("__tmp__to_json__".to_owned(), v);
102 let v = evaluator
103 .parse_evaluate_raw("std.manifestJsonEx(__tmp__to_json__, \" \")");
104 match v {
105 Ok(v) => v,
106 Err(err) => {
107 print_error(&err, evaluator, &opts);
108 std::process::exit(2);
109 }
110 }
111 }
112 Format::Yaml => {
113 if opts.no_stdlib {
114 evaluator.add_stdlib();
115 }
116 evaluator.add_global("__tmp__to_yaml__".to_owned(), v);
117 let v = evaluator
118 .parse_evaluate_raw("std.manifestYamlDoc(__tmp__to_yaml__, \" \")");
119 match v {
120 Ok(v) => v,
121 Err(err) => {
122 print_error(&err, evaluator, &opts);
123 std::process::exit(2);
124 }
125 }
126 }
127 _ => v,
128 };
129 match v {
130 Val::Str(s) => println!("{}", s),
131 Val::Num(n) => println!("{}", n),
132 _v => eprintln!(
133 "jsonnet output is not a string.\nDid you forgot to set --format, or wrap your data with std.manifestJson?"
134 ),
135 }
136 }
137 Err(err) => {
138 print_error(&err, evaluator, &opts);
139 }
140 }
141}
142
143fn print_error(err: &LocError, evaluator: EvaluationState, opts: &Opts) {
144 println!("Error: {:?}", err.0);
145 print_trace(&(err.1), evaluator, &opts);
146}
147
148fn line_columns(file: &str, offsets: &[usize]) -> Vec<(usize, usize)> {
149 if offsets.is_empty() {
150 return vec![];
151 }
152 let mut line = 0;
153 let mut column = 0;
154 let max_offset = *offsets.iter().max().unwrap();
155
156 let mut offset_map = offsets
157 .iter()
158 .enumerate()
159 .map(|(pos, offset)| (*offset, pos))
160 .collect::<Vec<_>>();
161 offset_map.sort_by_key(|v| v.0);
162 offset_map.reverse();
163
164 let mut out = vec![(0usize, 0usize); offsets.len()];
165 for (pos, ch) in (0..max_offset + 1).zip(file.chars()) {
166 column += 1;
167 if offset_map.last().unwrap().0 == pos {
168 out[offset_map.last().unwrap().1] = (line, column);
169 offset_map.pop();
170 }
171 if ch == '\n' {
172 line += 1;
173 column = 0;
174 }
175 }
176
177 out
178}
39179
40fn main() {180fn print_trace(trace: &StackTrace, evaluator: EvaluationState, opts: &Opts) {
41 let opts: Opts = Opts::parse();
42 let evaluator = jsonnet_evaluator::EvaluationState::default();
43 if !opts.no_stdlib {
44 evaluator.add_stdlib();
45 }
46 evaluator
47 .add_file(
48 opts.input.clone(),
49 String::from_utf8(std::fs::read(opts.input.clone()).unwrap()).unwrap(),
50 )
51 .unwrap();
52 let result = evaluator.evaluate_file(&opts.input);
53 match result {
54 Ok(mut v) => {
55 if let Format::Json = opts.format {
56 if opts.no_stdlib {
57 evaluator.add_stdlib();
58 }
59 evaluator.add_global("__tmp__to_json__".to_owned(), v);
60 v = evaluator
61 .parse_evaluate_raw("std.manifestJsonEx(__tmp__to_json__, \" \")")
62 .expect("json serialization");
63 }
64 match v {
65 Val::Str(s) => println!("{}", s),
66 Val::Num(n) => println!("{}", n),
67 _v => eprintln!(
68 "jsonnet output is not a string.\nDid you forgot to set --format, or wrap your data with std.manifestJson?"
69 ),
70 }
71 }
72 Err(err) => {
73 println!("Error: {:?}", err.0);
74 use annotate_snippets::{181 use annotate_snippets::{
75 display_list::{DisplayList, FormatOptions},182 display_list::{DisplayList, FormatOptions},
76 snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation},183 snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation},
77 };184 };
78 for item in (err.1).0.iter() {185 for item in trace.0.iter() {
79 let desc = &item.1;186 let desc = &item.1;
80 if (item.0).1.is_none() {187 if (item.0).1.is_none() {
81 continue;188 continue;
82 }189 }
83 let source = (item.0).1.clone().unwrap();190 let source = (item.0).1.clone().unwrap();
84 let code = evaluator.get_source(&source.0);191 let code = evaluator.get_source(&source.0);
192 if code.is_none() {
193 continue;
194 }
195 let code = code.unwrap();
196 let start_end = line_columns(&code, &[source.1, source.2]);
197 if opts.trace_format == TraceFormat::Custom {
85 let snippet = Snippet {198 let snippet = Snippet {
86 opt: FormatOptions {199 opt: FormatOptions {
87 color: true,200 color: true,
96 slices: vec![Slice {209 slices: vec![Slice {
97 source: &code,210 source: &code,
98 line_start: 1,211 line_start: 1,
99 origin: Some(&source.0),212 origin: Some(&source.0.to_str().unwrap()),
100 fold: true,213 fold: false,
101 annotations: vec![SourceAnnotation {214 annotations: vec![SourceAnnotation {
102 label: desc,215 label: desc,
103 annotation_type: AnnotationType::Error,216 annotation_type: AnnotationType::Error,
108221
109 let dl = DisplayList::from(snippet);222 let dl = DisplayList::from(snippet);
110 println!("{}", dl);223 println!("{}", dl);
224 } else {
225 if opts.trace_format == TraceFormat::CppJsonnet {
226 print!(" ");
227 } else {
228 print!(" ");
229 }
230 print!("{}:", source.0.to_str().unwrap());
231 if start_end[0].0 == start_end[1].0 {
232 // IDK why, but this is the behavior original jsonnet shows
233 if start_end[0].1 == start_end[1].1
234 || opts.trace_format == TraceFormat::CppJsonnet
235 && start_end[0].1 + 1 == start_end[1].1
236 {
237 println!("{}:{}", start_end[0].0 + 1, start_end[0].1)
238 } else {
239 println!(
240 "{}:{}-{}",
241 start_end[0].0 + 1,
242 start_end[0].1,
243 start_end[1].1
244 );
245 }
246 } else {
247 println!(
248 "({}:{})-({}:{})",
249 start_end[0].0 + 1,
250 start_end[0].1,
251 start_end[1].0 + 1,
252 start_end[1].1
253 );
254 }
255 }
111 }256 }
112 }
113 }257}
114}
115258