wpt_interop/
results_cache.rs

1use crate::{Error, Result, Results};
2use git2;
3use serde_json;
4use std::collections::{BTreeMap, BTreeSet};
5use std::path::Path;
6use urlencoding;
7
8pub struct ResultsCache {
9    repo: git2::Repository,
10}
11
12impl ResultsCache {
13    pub fn new(path: &Path) -> Result<ResultsCache> {
14        Ok(ResultsCache {
15            repo: git2::Repository::open(path)?,
16        })
17    }
18
19    fn tag(run_id: u64) -> String {
20        format!("refs/tags/run/{}/results", run_id)
21    }
22
23    pub fn results(
24        &self,
25        run_id: u64,
26        include_tests: Option<&BTreeSet<String>>,
27    ) -> Result<BTreeMap<String, Results>> {
28        let mut results_data = BTreeMap::new();
29        let run_ref = self.repo.find_reference(&ResultsCache::tag(run_id))?;
30        if !run_ref.is_tag() {
31            return Err(Error::String(format!(
32                "{} is not a tag",
33                ResultsCache::tag(run_id)
34            )));
35        }
36        let root = run_ref.peel_to_tree()?;
37        let mut stack: Vec<(git2::Tree, String)> = vec![(root, "".to_string())];
38        while let Some((tree, path)) = stack.pop() {
39            for tree_entry in tree.iter() {
40                match tree_entry.kind() {
41                    Some(git2::ObjectType::Tree) => {
42                        let name = tree_entry.name().ok_or_else(|| {
43                            Error::String(format!("Tree has non-utf8 name {:?}", tree_entry.name()))
44                        })?;
45                        stack.push((
46                            tree_entry.to_object(&self.repo)?.peel_to_tree()?,
47                            format!("{}/{}", path, name),
48                        ));
49                    }
50                    Some(git2::ObjectType::Blob) => {
51                        let name = tree_entry.name().ok_or_else(|| {
52                            Error::String(format!("Tree has non-utf8 name {:?}", tree_entry.name()))
53                        })?;
54                        let test_name = match name.rsplit_once('.') {
55                            Some((test_name, "json")) => urlencoding::decode(test_name),
56                            Some((_, _)) | None => {
57                                return Err(Error::String(format!(
58                                    "Expected a name ending .json(), got {}",
59                                    name
60                                )));
61                            }
62                        }
63                        .expect("Test name is valid utf8");
64                        let path = format!("{}/{}", path, test_name);
65                        if let Some(include) = include_tests {
66                            if !include.contains(&path) {
67                                continue;
68                            }
69                        }
70                        let blob = tree_entry.to_object(&self.repo)?.peel_to_blob()?;
71                        let results: Results = serde_json::from_slice(blob.content())?;
72                        results_data.insert(path, results);
73                    }
74                    _ => {
75                        return Err(Error::String(format!(
76                            "Unexpected object while walking tree {}",
77                            tree_entry.id()
78                        )));
79                    }
80                }
81            }
82        }
83        Ok(results_data)
84    }
85}