record_query/
proto_index.rs

1use crate::config;
2use crate::error;
3
4use protobuf;
5use std::cmp;
6use std::fs;
7use std::path;
8use std::process;
9
10pub fn add_file(
11    paths: &config::Paths,
12    relative_to: &path::Path,
13    file: &path::Path,
14) -> error::Result<()> {
15    let rel_file = file
16        .strip_prefix(relative_to)
17        .unwrap_or_else(|_| file.file_name().map_or(file, path::Path::new));
18    let target = paths.preferred_data("proto").join(rel_file);
19
20    if let Some(parent) = target.parent() {
21        trace!("Creating directory {:?}", parent);
22        fs::create_dir_all(parent)?;
23    }
24
25    fs::copy(file, &target)?;
26    info!("Added proto file as {:?}", target);
27    Ok(())
28}
29
30pub fn compile_descriptor_set(
31    paths: &config::Paths,
32) -> error::Result<protobuf::descriptor::FileDescriptorSet> {
33    let proto_includes = paths.find_data("proto")?;
34    let proto_files = paths.find_data("proto/**/*.proto")?;
35    let cache = paths.preferred_cache("descriptor-cache.pb");
36
37    debug!("Proto includes: {:?}", proto_includes);
38    debug!("Proto files: {:?}", proto_files);
39    debug!("Proto cache location: {:?}", cache);
40
41    if is_cache_stale(&cache, &proto_files)? {
42        info!("Proto descriptor cache is stale; recomputing");
43
44        if let Some(parent) = cache.parent() {
45            trace!("Creating directory {:?}", parent);
46            fs::create_dir_all(parent)?;
47        }
48
49        let include_args = proto_includes
50            .into_iter()
51            .map(|p| format!("-I{}", p.to_string_lossy()))
52            .collect::<Vec<_>>();
53
54        let status = process::Command::new("protoc")
55            .arg("-o")
56            .arg(&cache)
57            .args(&include_args)
58            .args(&proto_files)
59            .status()?;
60        if !status.success() {
61            panic!("protoc descriptor compilation failed");
62        }
63
64        trace!("Proto descriptor cache regenerated");
65    }
66
67    let mut cache_file = fs::File::open(&cache)?;
68    let descriptor_set = protobuf::Message::parse_from_reader(&mut cache_file)?;
69
70    trace!("Successfully parsed descriptor set from cache");
71
72    Ok(descriptor_set)
73}
74
75fn is_cache_stale<P>(cache: &path::Path, proto_files: &[P]) -> error::Result<bool>
76where
77    P: AsRef<path::Path>,
78{
79    if cache.exists() {
80        let cache_metadata = fs::metadata(&cache)?;
81        let cache_mtime = cache_metadata.modified()?;
82        let mut max_proto_mtime = std::time::SystemTime::UNIX_EPOCH;
83
84        for proto_file in proto_files.iter() {
85            let proto_metadata = fs::metadata(&proto_file)?;
86            let proto_mtime = proto_metadata.modified()?;
87            max_proto_mtime = cmp::max(max_proto_mtime, proto_mtime);
88        }
89
90        Ok(cache_mtime < max_proto_mtime)
91    } else {
92        Ok(true)
93    }
94}