record_query/
proto_index.rs1use 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}