reups_lib/db/
table.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
4 * Copyright Nate Lust 2018*/
5
6use fnv::FnvHashMap;
7use lazy_static;
8use regex::Regex;
9use std::fs::File;
10use std::io;
11use std::io::prelude::*;
12use std::path;
13
14/**!
15 A Table object is the in memory representation of a products table file.
16*/
17
18lazy_static::lazy_static! {
19    // Regexes to capture information out of the text of a table file
20    // captures exact dependency trees
21    static ref EXACT: Regex = Regex::new(r"[^#]\b(?P<type>setup(Optional|Required))[(](?P<product>[[:word:]]+?\b)\s+[-]j\s(?P<version>\S+?\b)[)]").unwrap();
22    // captures inexact dependency trees
23    static ref INEXACT: Regex = Regex::new(r"[^#]\b(?P<type>setup(Optional|Required))[(](?P<product>[[:word:]]+?\b)(?:\s(?P<version>\S+?\b)\s\[)?").unwrap();
24
25
26    // Finds variables to be prepended to an environment variable
27    static ref ENV_PREPEND: Regex = Regex::new(r"(envPrepend|pathPrepend)[(](?P<var>.+?)[,]\s(?P<target>.+?)[)]").unwrap();
28    // Finds variables to be appended to an environment variable
29    static ref ENV_APPEND: Regex = Regex::new(r"(envAppend|pathAppend)[(](?P<var>.+?)[,]\s(?P<target>.+?)[)]").unwrap();
30}
31
32/// VersionType is an enum that differentiates between dependency trees that have
33/// explicit exact versions sepecified, or if specific versions will be determined
34/// with tags.
35#[derive(Clone)]
36pub enum VersionType {
37    Exact,
38    Inexact,
39}
40
41/// Enum to describ the action of an environment variable, prepend or append to the
42/// env var.
43#[derive(Debug, Clone)]
44pub enum EnvActionType {
45    Prepend,
46    Append,
47}
48
49/// Deps describes if a product is a required or optional dependency. Required
50/// dependencies will cause the application to abort if they are not present
51#[derive(Debug, Clone)]
52pub struct Deps {
53    pub required: FnvHashMap<String, String>,
54    pub optional: FnvHashMap<String, String>,
55}
56
57/// Structure containing all the information about an on disk table file
58#[derive(Debug, Clone)]
59pub struct Table {
60    pub name: String,
61    pub path: path::PathBuf,
62    pub product_dir: path::PathBuf,
63    pub exact: Option<Deps>,
64    pub inexact: Option<Deps>,
65    pub env_var: FnvHashMap<String, (EnvActionType, String)>,
66}
67
68impl Table {
69    /// Creates a new Table object given the product name to assign, the path to the
70    /// table file, and the directory the product is located in
71    pub fn new(
72        name: String,
73        path: path::PathBuf,
74        prod_dir: path::PathBuf,
75    ) -> Result<Table, io::Error> {
76        let mut f = File::open(path.clone())?;
77        let mut contents = String::new();
78        f.read_to_string(&mut contents)?;
79        // Get the exact mapping
80        // Dereferencing and taking a reference is nesseary to cause the
81        // lazy static object defined at the top to be evaluated and turned into
82        // a proper static, this only happens at first dereference. These are
83        // defined as statics because they will remain between different tables
84        // being created
85        let exact = Table::extract_setup(contents.as_str(), &*EXACT);
86        // Get the inexact mapping
87        let inexact = Table::extract_setup(contents.as_str(), &*INEXACT);
88        let mut env_var = FnvHashMap::default();
89        let env_re_vec: Vec<&Regex> = vec![&*ENV_PREPEND, &*ENV_APPEND];
90        for (re, action) in env_re_vec
91            .iter()
92            .zip([EnvActionType::Prepend, EnvActionType::Append].iter())
93        {
94            for cap in re.captures_iter(contents.as_str()) {
95                let var = String::from(&cap["var"]);
96                let target = String::from(&cap["target"]);
97                let final_target = target.replace("${PRODUCT_DIR}", prod_dir.to_str().unwrap());
98                env_var.insert(var, (action.clone(), final_target));
99            }
100        }
101        Ok(Table {
102            name: name,
103            path: path,
104            product_dir: prod_dir,
105            exact: exact,
106            inexact: inexact,
107            env_var: env_var,
108        })
109    }
110
111    /// Extracts the part of the table file that is related to the dependencies of the
112    /// table file
113    fn extract_setup(input: &str, re: &Regex) -> Option<Deps> {
114        let temp_string = input;
115        let mut required_map = FnvHashMap::default();
116        let mut optional_map = FnvHashMap::default();
117        for dep_cap in re.captures_iter(temp_string) {
118            let option_type = &dep_cap["type"];
119            let prod = &dep_cap["product"];
120            let vers = match dep_cap.name("version") {
121                Some(ver) => ver.as_str(),
122                None => "",
123            };
124            if option_type == "setupRequired" {
125                required_map.insert(String::from(prod), String::from(vers));
126            }
127            if option_type == "setupOptional" {
128                optional_map.insert(String::from(prod), String::from(vers));
129            }
130        }
131        Some(Deps {
132            required: required_map,
133            optional: optional_map,
134        })
135    }
136}