difftreelog
feat multiple trace formats
in: master
1 file changed
cmds/jsonnet/src/main.rsdiffbeforeafterboth1use 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;455enum Format {6enum Format {6 None,7 None,7 Json,8 Json,9 Yaml,8}10}91110impl 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}2324#[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}204121#[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,5960 #[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,7436 #[clap(about = "File to compile")]75 #[clap(about = "File to compile", index = 1)]37 input: String,76 input: String,38}77}7879fn 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 evaluator88 .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 = evaluator103 .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 = evaluator118 .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}142143fn print_error(err: &LocError, evaluator: EvaluationState, opts: &Opts) {144 println!("Error: {:?}", err.0);145 print_trace(&(err.1), evaluator, &opts);146}147148fn 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();155156 let mut offset_map = offsets157 .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();163164 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 }176177 out178}3917940fn 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 evaluator47 .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 = evaluator61 .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,108221109 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 shows233 if start_end[0].1 == start_end[1].1234 || opts.trace_format == TraceFormat::CppJsonnet235 && start_end[0].1 + 1 == start_end[1].1236 {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].1244 );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].1253 );254 }255 }111 }256 }112 }113 }257}114}115258