1use std::io::Write;
2
3use libflate::gzip::Encoder;
4use proc_macro::TokenStream;
5use syn::parse_macro_input;
6
7fn repo_tarball(filter: &[String]) -> Vec<u8> {
8 let toplevel = std::process::Command::new("git")
12 .arg("rev-parse")
13 .arg("--show-toplevel")
14 .output()
15 .expect("could not get top level directory");
16 let toplevel_dir = String::from_utf8(toplevel.stdout).unwrap();
17 let toplevel_dir = toplevel_dir.trim();
18 let mut archive = std::process::Command::new("git");
19 archive
20 .current_dir(toplevel_dir)
21 .arg("archive")
22 .arg("HEAD")
23 .arg("--");
24 for f in filter {
25 archive.arg(f);
26 }
27 let output = archive
28 .output()
29 .expect("could not run 'git archive HEAD' for repo_tarball");
30
31 if !output.status.success() {
32 panic!("[include-repo]: error running git-archive: Exit {}: {}", output.status, String::from_utf8_lossy(&output.stderr));
33 }
34 output.stdout
35}
36
37struct Filters {
38 filters: Vec<String>
39}
40
41impl syn::parse::Parse for Filters {
42 fn parse(input: syn::parse::ParseStream) -> syn::parse::Result<Self> {
43 let mut filters = Vec::new();
44
45 while input.peek(syn::Lit) {
46 let lit: syn::Lit = input.parse()?;
47 let s = match lit {
48 syn::Lit::Str(s) => s.value(),
49 syn::Lit::ByteStr(s) => String::from_utf8(s.value()).unwrap(),
50 _ => panic!("[include-repo]: error parsing filter argument. Must be a string, got {:?}", lit),
51 };
52 filters.push(s);
53 }
54 Ok(Filters{filters})
55 }
56}
57
58#[proc_macro]
59pub fn include_repo(args: TokenStream) -> TokenStream {
63 let f: Filters = parse_macro_input!(args as Filters);
64 let tar = repo_tarball(&f.filters);
65 format!("&[{}]", tar.iter().map(|b| b.to_string()).collect::<Vec<_>>().join(", ")).parse().unwrap()
66}
67
68#[proc_macro]
69pub fn include_repo_gz(args: TokenStream) -> TokenStream {
73 let f: Filters = parse_macro_input!(args as Filters);
74 let tar = repo_tarball(&f.filters);
75
76 let mut encoder = Encoder::new(Vec::new()).unwrap();
77 encoder.write_all(&tar).unwrap();
78 let targz = encoder.finish().into_result().unwrap();
79
80 format!("&[{}];", targz.iter().map(|b| b.to_string()).collect::<Vec<_>>().join(", ")).parse().unwrap()
81}