Skip to content

Instantly share code, notes, and snippets.

@heaths
Last active February 4, 2023 01:24
Show Gist options
  • Save heaths/b2cb43db72a9de5e0b5c28127f4d263a to your computer and use it in GitHub Desktop.
Save heaths/b2cb43db72a9de5e0b5c28127f4d263a to your computer and use it in GitHub Desktop.
Deserialize an autorest readme.md file
use clap::Parser;
use markdown::{tokenize, Block, Span};
use serde::Deserialize;
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;
fn main() {
let args = Args::parse();
let mut f = File::open(args.file).expect("failed to open autorest config");
let mut content = String::new();
f.read_to_string(&mut content)
.expect("failed to read autorest config");
let mut tags: Vec<String> = vec![];
let tag = match args.tag {
Some(ref s) => Some(s.as_str()),
None => None,
};
for block in tokenize(&content) {
match block {
Block::Header(spans, 3) if spans.len() == 1 => {
if let Span::Text(header) = &spans[0] {
if header.starts_with("Tag:") {
let header = header
.strip_prefix("Tag:")
.and_then(|s| Some(s.trim()))
.unwrap_or_default();
tags.push(header.to_string());
}
}
}
Block::CodeBlock(Some(s), content)
if tag.is_some() && s.contains("yaml") && s.contains(tag.unwrap()) =>
{
let config: Config = serde_yaml::from_str(content.as_str())
.expect("failed to parse autorest config");
if let Some(files) = config.input_files {
for file in files.to_vec() {
println!("{}", file);
}
}
return;
}
_ => {
if args.debug {
eprintln!("{:?}", block);
}
}
}
}
match args.tag {
Some(tag) => {
eprintln!("{} not defined", tag);
std::process::exit(2);
}
None => {
tags.sort();
tags.reverse();
for tag in tags {
println!("{}", tag);
}
}
}
}
#[derive(Parser)]
#[command(version, about, long_about = None)]
struct Args {
/// The autorest.md file to parse.
file: PathBuf,
/// The tag to parse.
#[arg(short, long)]
tag: Option<String>,
/// Print debugging information.
#[arg(long)]
debug: bool,
}
#[derive(Deserialize)]
struct Config {
// Deserialize either a string (rare) or array of strings.
#[serde(rename = "input-file")]
input_files: Option<StringOrStringArray>,
}
#[derive(Deserialize)]
#[serde(untagged)]
enum StringOrStringArray {
Str(String),
StrArray(Vec<String>),
}
impl StringOrStringArray {
fn to_vec(self) -> Vec<String> {
match self {
Self::StrArray(arr) => arr,
Self::Str(s) => vec![s],
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment