Skip to content

Commit 4d6e2a9

Browse files
committed
config: flesh out basics for loading from disk
The details of merging the config are not sorted at this time and testing has not been done as of yet, but the basics seem to be present. Signed-off-by: Paul Osborne <[email protected]>
1 parent 00de1f3 commit 4d6e2a9

File tree

4 files changed

+90
-13
lines changed

4 files changed

+90
-13
lines changed

Cargo.lock

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ clap = "2.2"
88
rustc-serialize = "0.3"
99
sysfs_gpio = "0.4"
1010
toml = "0.1"
11+
glob = "0.2"
1112

1213
[[bin]]
1314
name = "gpio"

src/config.rs

Lines changed: 82 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,33 @@
11
// Copyright (C) 2016, Paul Osborne <[email protected]>
22

3-
use toml;
3+
use glob::glob;
44
use rustc_serialize::{Decodable};
5+
use std::collections::{HashMap, BTreeSet};
6+
use std::fs::{self, File};
57
use std::io;
8+
use std::io::prelude::*;
69
use std::path::Path;
7-
use std::collections::HashMap;
810
use sysfs_gpio::Direction;
11+
use toml;
912

10-
#[derive(RustcDecodable, Debug)]
13+
#[derive(RustcDecodable, Clone, Debug)]
1114
pub struct PinConfig {
1215
num: u64,
1316
direction: Option<String>,
14-
aliases: Option<Vec<String>>,
17+
aliases: Option<BTreeSet<String>>,
1518
export: Option<bool>,
1619
active_low: Option<bool>,
1720
}
1821

19-
#[derive(RustcDecodable, Debug)]
22+
#[derive(RustcDecodable, Clone, Debug)]
2023
pub struct GpioConfig {
2124
pins: HashMap<String, PinConfig>,
2225
}
2326

2427
#[derive(Debug)]
2528
pub enum Error {
2629
IoError(io::Error),
27-
ParseError,
30+
ParserErrors(Vec<toml::ParserError>),
2831
NoConfigFound,
2932
}
3033

@@ -38,6 +41,18 @@ fn to_direction(dirstr: &str) -> Option<Direction> {
3841
}
3942
}
4043

44+
impl From<io::Error> for Error {
45+
fn from(e: io::Error) -> Self {
46+
Error::IoError(e)
47+
}
48+
}
49+
50+
impl From<Vec<toml::ParserError>> for Error {
51+
fn from(e: Vec<toml::ParserError>) -> Self {
52+
Error::ParserErrors(e)
53+
}
54+
}
55+
4156
impl GpioConfig {
4257

4358
/// Load a GPIO Config from the system
@@ -57,26 +72,69 @@ impl GpioConfig {
5772
/// Each config file found in these locations will be loaded and then they
5873
/// will be pulled together to form a unified configuration via the
5974
/// `combine` method.
60-
pub fn load(configs: Vec<String>) -> Result<GpioConfig, Error> {
61-
Err(Error::NoConfigFound)
75+
pub fn load(configs: &[&str]) -> Result<GpioConfig, Error> {
76+
let mut config_instances: Vec<GpioConfig> = Vec::new();
77+
78+
// check /etc/gpio.toml
79+
if fs::metadata("/etc/gpio.toml").is_ok() {
80+
config_instances.push(try!(Self::from_file("/etc/gpio.toml")));
81+
}
82+
83+
// /etc/gpio.d/*.toml
84+
for fragment in glob("/etc/gpio.d/*.toml").unwrap().filter_map(Result::ok) {
85+
config_instances.push(try!(Self::from_file("/etc/gpio.toml")));
86+
}
87+
88+
// additional from command-line
89+
for fragment in configs {
90+
config_instances.push(try!(Self::from_file(fragment)));
91+
}
92+
93+
if config_instances.len() == 0 {
94+
Err(Error::NoConfigFound)
95+
} else {
96+
Ok(config_instances[1..].iter().fold(config_instances[0].clone(), |a, b| {
97+
a.merge(b)
98+
}))
99+
}
62100
}
63101

64102
/// Load a GPIO configuration for the provided toml string
65103
pub fn from_str(config: &str) -> Result<GpioConfig, Error> {
66-
let root = toml::Parser::new(config).parse().unwrap();
104+
let mut parser = toml::Parser::new(config);
105+
let root = try!(parser.parse().ok_or(parser.errors));
67106
let mut d = toml::Decoder::new(toml::Value::Table(root));
68107
Ok(Decodable::decode(&mut d).unwrap())
69108
}
70109

71110
/// Load a GPIO config from the specified path
72111
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<GpioConfig, Error> {
73-
Err(Error::NoConfigFound)
112+
let mut contents = String::new();
113+
let mut f = try!(File::open(path));
114+
try!(f.read_to_string(&mut contents));
115+
GpioConfig::from_str(&contents[..])
116+
}
117+
118+
/// Merge this config with other yielding a new, merged version
119+
///
120+
/// If in conflict, the other GPIO config takes priority.
121+
pub fn merge(&self, other: &GpioConfig) -> GpioConfig {
122+
// TODO: This needs to actually resolve conflicts rather than
123+
// blindly writing over as it does now.
124+
let mut pins = HashMap::new();
125+
pins.extend(self.pins.clone());
126+
pins.extend(other.pins.clone());
127+
GpioConfig {
128+
pins: pins
129+
}
74130
}
75131
}
76132

77133
#[cfg(test)]
78134
mod test {
79135
use super::*;
136+
use std::iter::FromIterator;
137+
use std::collections::BTreeSet;
80138

81139
#[test]
82140
fn test_parse_basic() {
@@ -99,12 +157,23 @@ error_led = { num = 11, direction = "in", export = false}
99157
"#;
100158
let config = GpioConfig::from_str(configstr).unwrap();
101159
let status_led = config.pins.get("status_led").unwrap();
160+
let mut aliases = BTreeSet::from_iter(vec!(String::from("A27"), String::from("green_led")));
102161
assert_eq!(status_led.num, 37);
103-
assert_eq!(status_led.aliases,
104-
Some(vec!(String::from("A27"),
105-
String::from("green_led"))));
162+
assert_eq!(status_led.aliases, Some(aliases));
106163
assert_eq!(status_led.direction, Some(String::from("out")));
107164
assert_eq!(status_led.active_low, None);
108165
assert_eq!(status_led.export, None);
109166
}
167+
168+
#[test]
169+
fn test_parse_error_bad_toml() {
170+
// basically, just garbage data
171+
let configstr = r#"
172+
[] -*-..asdf=-=-@#$%^&*()
173+
"#;
174+
match GpioConfig::from_str(configstr) {
175+
Err(Error::ParserErrors(e)) => {},
176+
_ => panic!("Did not receive parse error when expected"),
177+
}
178+
}
110179
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
extern crate sysfs_gpio;
44
extern crate rustc_serialize;
55
extern crate toml;
6+
extern crate glob;
67

78
pub mod options;
89
pub mod config;

0 commit comments

Comments
 (0)