Added support for toml and yaml configurations.
This commit is contained in:
parent
a63dbb5422
commit
c749146d5c
6 changed files with 274 additions and 77 deletions
|
@ -7,10 +7,10 @@ sudo: false
|
|||
script:
|
||||
- chmod +x mktestconfig.sh
|
||||
- ./mktestconfig.sh
|
||||
- cargo build --verbose --features "toml yaml"
|
||||
- cargo test --verbose --features "toml yaml"
|
||||
- cargo build --verbose --no-default-features
|
||||
- cargo build --verbose
|
||||
- cargo test --verbose --no-default-features
|
||||
- cargo test --verbose
|
||||
notifications:
|
||||
email: false
|
||||
irc:
|
||||
|
|
12
Cargo.toml
12
Cargo.toml
|
@ -11,9 +11,11 @@ repository = "https://github.com/aatxe/irc"
|
|||
readme = "README.md"
|
||||
|
||||
[features]
|
||||
default = ["ctcp"]
|
||||
default = ["ctcp", "json"]
|
||||
ctcp = []
|
||||
nochanlists = []
|
||||
json = ["serde_json"]
|
||||
yaml = ["serde_yaml"]
|
||||
|
||||
[dependencies]
|
||||
bufstream = "0.1"
|
||||
|
@ -25,9 +27,15 @@ futures = "0.1"
|
|||
native-tls = "0.1"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0"
|
||||
serde_json = { version = "1.0", optional = true }
|
||||
serde_yaml = { version = "0.7", optional = true }
|
||||
tokio-core = "0.1"
|
||||
tokio-io = "0.1"
|
||||
tokio-mockstream = "1.1"
|
||||
tokio-timer = "0.1"
|
||||
tokio-tls = "0.1"
|
||||
toml = { version = "0.4", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
args = "2.0"
|
||||
getopts = "0.2"
|
||||
|
|
62
examples/convertconf.rs
Normal file
62
examples/convertconf.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
extern crate args;
|
||||
extern crate getopts;
|
||||
extern crate irc;
|
||||
|
||||
use std::env;
|
||||
use std::process::exit;
|
||||
|
||||
use args::{Args, ArgsError};
|
||||
use getopts::Occur;
|
||||
use irc::client::data::Config;
|
||||
|
||||
const PROGRAM_DESC: &'static str = "Use this program to convert configs between {JSON, TOML, YAML}.";
|
||||
const PROGRAM_NAME: &'static str = "convertconf";
|
||||
|
||||
fn main() {
|
||||
let args: Vec<_> = env::args().collect();
|
||||
match parse(&args) {
|
||||
Ok(Some((ref input, ref output))) => {
|
||||
let cfg = Config::load(input).unwrap();
|
||||
cfg.save(output).unwrap();
|
||||
println!("Converted {} to {}.", input, output);
|
||||
}
|
||||
Ok(None) => {
|
||||
println!("Failed to provide required arguments.");
|
||||
exit(1);
|
||||
}
|
||||
Err(err) => {
|
||||
println!("{}", err);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse(input: &Vec<String>) -> Result<Option<(String, String)>, ArgsError> {
|
||||
let mut args = Args::new(PROGRAM_NAME, PROGRAM_DESC);
|
||||
args.flag("h", "help", "Print the usage menu");
|
||||
args.option("i",
|
||||
"input",
|
||||
"The path to the input config",
|
||||
"FILE",
|
||||
Occur::Req,
|
||||
None);
|
||||
args.option("o",
|
||||
"output",
|
||||
"The path to output the new config to",
|
||||
"FILE",
|
||||
Occur::Req,
|
||||
None);
|
||||
|
||||
args.parse(input)?;
|
||||
|
||||
let help = args.value_of("help")?;
|
||||
if help {
|
||||
args.full_usage();
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
Ok(Some((
|
||||
args.value_of("input")?,
|
||||
args.value_of("output")?,
|
||||
)))
|
||||
}
|
|
@ -1 +1,3 @@
|
|||
echo "{\"owners\": [\"test\"],\"nickname\": \"test\",\"username\": \"test\",\"realname\": \"test\",\"password\": \"\",\"server\": \"irc.test.net\",\"port\": 6667,\"use_ssl\": false,\"encoding\": \"UTF-8\",\"channels\": [\"#test\", \"#test2\"],\"umodes\": \"+BR\",\"options\": {}}" > client_config.json
|
||||
cargo run --example convertconf --features "toml yaml" -- -i client_config.json -o client_config.toml
|
||||
cargo run --example convertconf --features "toml yaml" -- -i client_config.json -o client_config.yaml
|
||||
|
|
|
@ -7,7 +7,12 @@ use std::io::{Error, ErrorKind};
|
|||
use std::net::{SocketAddr, ToSocketAddrs};
|
||||
use std::path::Path;
|
||||
|
||||
#[cfg(feature = "json")]
|
||||
use serde_json;
|
||||
#[cfg(feature = "yaml")]
|
||||
use serde_yaml;
|
||||
#[cfg(feature = "toml")]
|
||||
use toml;
|
||||
|
||||
use error::Result;
|
||||
|
||||
|
@ -80,30 +85,157 @@ pub struct Config {
|
|||
}
|
||||
|
||||
impl Config {
|
||||
/// Loads a JSON configuration from the desired path.
|
||||
/// Loads a configuration from the desired path. This will use the file extension to detect
|
||||
/// which format to parse the file as (json, toml, or yaml). Using each format requires having
|
||||
/// its respective crate feature enabled. Only json is available by default.
|
||||
pub fn load<P: AsRef<Path>>(path: P) -> Result<Config> {
|
||||
let mut file = File::open(path)?;
|
||||
let mut file = File::open(&path)?;
|
||||
let mut data = String::new();
|
||||
file.read_to_string(&mut data)?;
|
||||
|
||||
match path.as_ref().extension().and_then(|s| s.to_str()) {
|
||||
Some("json") => Config::load_json(&data),
|
||||
Some("toml") => Config::load_toml(&data),
|
||||
Some("yaml") | Some("yml") => Config::load_yaml(&data),
|
||||
Some(ext) => return Err(Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
format!("Failed to decode configuration of unknown format {}", ext),
|
||||
).into()),
|
||||
None => return Err(Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
"Failed to decode configuration of missing or non-unicode format.",
|
||||
).into()),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "json")]
|
||||
fn load_json(data: &str) -> Result<Config> {
|
||||
serde_json::from_str(&data[..]).map_err(|_| {
|
||||
Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
"Failed to decode configuration file.",
|
||||
"Failed to decode JSON configuration file.",
|
||||
).into()
|
||||
})
|
||||
}
|
||||
|
||||
/// Saves a JSON configuration to the desired path.
|
||||
#[cfg(not(feature = "json"))]
|
||||
fn load_json(_: &str) -> Result<Config> {
|
||||
Err(Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
"JSON file decoding is disabled.",
|
||||
).into())
|
||||
}
|
||||
|
||||
#[cfg(feature = "toml")]
|
||||
fn load_toml(data: &str) -> Result<Config> {
|
||||
toml::from_str(&data[..]).map_err(|_| {
|
||||
Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
"Failed to decode TOML configuration file.",
|
||||
).into()
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "toml"))]
|
||||
fn load_toml(_: &str) -> Result<Config> {
|
||||
Err(Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
"TOML file decoding is disabled.",
|
||||
).into())
|
||||
}
|
||||
|
||||
#[cfg(feature = "yaml")]
|
||||
fn load_yaml(data: &str) -> Result<Config> {
|
||||
serde_yaml::from_str(&data[..]).map_err(|_| {
|
||||
Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
"Failed to decode YAML configuration file.",
|
||||
).into()
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "yaml"))]
|
||||
fn load_yaml(_: &str) -> Result<Config> {
|
||||
Err(Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
"YAML file decoding is disabled.",
|
||||
).into())
|
||||
}
|
||||
|
||||
/// Saves a configuration to the desired path. This will use the file extension to detect
|
||||
/// which format to parse the file as (json, toml, or yaml). Using each format requires having
|
||||
/// its respective crate feature enabled. Only json is available by default.
|
||||
pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<()> {
|
||||
let mut file = File::create(path)?;
|
||||
file.write_all(
|
||||
serde_json::to_string(self).map_err(|_| {
|
||||
Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
"Failed to encode configuration file.",
|
||||
)
|
||||
})?.as_bytes(),
|
||||
).map_err(|e| e.into())
|
||||
let mut file = File::create(&path)?;
|
||||
let data = match path.as_ref().extension().and_then(|s| s.to_str()) {
|
||||
Some("json") => self.save_json()?,
|
||||
Some("toml") => self.save_toml()?,
|
||||
Some("yaml") | Some("yml") => self.save_yaml()?,
|
||||
Some(ext) => return Err(Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
format!("Failed to encode configuration of unknown format {}", ext),
|
||||
).into()),
|
||||
None => return Err(Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
"Failed to encode configuration of missing or non-unicode format.",
|
||||
).into()),
|
||||
};
|
||||
file.write_all(data.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "json")]
|
||||
fn save_json(&self) -> Result<String> {
|
||||
serde_json::to_string(self).map_err(|_| {
|
||||
Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
"Failed to encode JSON configuration file.",
|
||||
).into()
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "json"))]
|
||||
fn save_json(&self) -> Result<String> {
|
||||
Err(Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
"JSON file encoding is disabled.",
|
||||
).into())
|
||||
}
|
||||
|
||||
#[cfg(feature = "toml")]
|
||||
fn save_toml(&self) -> Result<String> {
|
||||
toml::to_string(self).map_err(|_| {
|
||||
Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
"Failed to encode TOML configuration file.",
|
||||
).into()
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "toml"))]
|
||||
fn save_toml(&self) -> Result<String> {
|
||||
Err(Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
"TOML file encoding is disabled.",
|
||||
).into())
|
||||
}
|
||||
|
||||
#[cfg(feature = "yaml")]
|
||||
fn save_yaml(&self) -> Result<String> {
|
||||
serde_yaml::to_string(self).map_err(|_| {
|
||||
Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
"Failed to encode YAML configuration file.",
|
||||
).into()
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "yaml"))]
|
||||
fn save_yaml(&self) -> Result<String> {
|
||||
Err(Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
"YAML file encoding is disabled.",
|
||||
).into())
|
||||
}
|
||||
|
||||
/// Determines whether or not the nickname provided is the owner of the bot.
|
||||
|
@ -308,78 +440,66 @@ impl Config {
|
|||
mod test {
|
||||
use std::collections::HashMap;
|
||||
use std::default::Default;
|
||||
#[cfg(feature = "json")]
|
||||
use std::path::Path;
|
||||
|
||||
use super::Config;
|
||||
|
||||
fn test_config() -> Config {
|
||||
Config {
|
||||
owners: Some(vec![format!("test")]),
|
||||
nickname: Some(format!("test")),
|
||||
nick_password: None,
|
||||
alt_nicks: None,
|
||||
username: Some(format!("test")),
|
||||
realname: Some(format!("test")),
|
||||
password: Some(String::new()),
|
||||
umodes: Some(format!("+BR")),
|
||||
server: Some(format!("irc.test.net")),
|
||||
port: Some(6667),
|
||||
use_ssl: Some(false),
|
||||
cert_path: None,
|
||||
encoding: Some(format!("UTF-8")),
|
||||
channels: Some(vec![format!("#test"), format!("#test2")]),
|
||||
channel_keys: None,
|
||||
user_info: None,
|
||||
version: None,
|
||||
source: None,
|
||||
ping_time: None,
|
||||
ping_timeout: None,
|
||||
burst_window_length: None,
|
||||
max_messages_in_burst: None,
|
||||
should_ghost: None,
|
||||
ghost_sequence: None,
|
||||
options: Some(HashMap::new()),
|
||||
use_mock_connection: None,
|
||||
mock_initial_value: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "json")]
|
||||
fn load() {
|
||||
let cfg = Config {
|
||||
owners: Some(vec![format!("test")]),
|
||||
nickname: Some(format!("test")),
|
||||
nick_password: None,
|
||||
alt_nicks: None,
|
||||
username: Some(format!("test")),
|
||||
realname: Some(format!("test")),
|
||||
password: Some(String::new()),
|
||||
umodes: Some(format!("+BR")),
|
||||
server: Some(format!("irc.test.net")),
|
||||
port: Some(6667),
|
||||
use_ssl: Some(false),
|
||||
cert_path: None,
|
||||
encoding: Some(format!("UTF-8")),
|
||||
channels: Some(vec![format!("#test"), format!("#test2")]),
|
||||
channel_keys: None,
|
||||
user_info: None,
|
||||
version: None,
|
||||
source: None,
|
||||
ping_time: None,
|
||||
ping_timeout: None,
|
||||
burst_window_length: None,
|
||||
max_messages_in_burst: None,
|
||||
should_ghost: None,
|
||||
ghost_sequence: None,
|
||||
options: Some(HashMap::new()),
|
||||
use_mock_connection: None,
|
||||
mock_initial_value: None,
|
||||
};
|
||||
assert_eq!(Config::load(Path::new("client_config.json")).unwrap(), cfg);
|
||||
assert_eq!(Config::load(Path::new("client_config.json")).unwrap(), test_config());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "json")]
|
||||
fn load_from_str() {
|
||||
let cfg = Config {
|
||||
owners: Some(vec![format!("test")]),
|
||||
nickname: Some(format!("test")),
|
||||
nick_password: None,
|
||||
alt_nicks: None,
|
||||
username: Some(format!("test")),
|
||||
realname: Some(format!("test")),
|
||||
umodes: Some(format!("+BR")),
|
||||
password: Some(String::new()),
|
||||
server: Some(format!("irc.test.net")),
|
||||
port: Some(6667),
|
||||
use_ssl: Some(false),
|
||||
cert_path: None,
|
||||
encoding: Some(format!("UTF-8")),
|
||||
channels: Some(vec![format!("#test"), format!("#test2")]),
|
||||
channel_keys: None,
|
||||
user_info: None,
|
||||
version: None,
|
||||
source: None,
|
||||
ping_time: None,
|
||||
ping_timeout: None,
|
||||
burst_window_length: None,
|
||||
max_messages_in_burst: None,
|
||||
should_ghost: None,
|
||||
ghost_sequence: None,
|
||||
options: Some(HashMap::new()),
|
||||
use_mock_connection: None,
|
||||
mock_initial_value: None,
|
||||
};
|
||||
assert_eq!(Config::load("client_config.json").unwrap(), cfg);
|
||||
assert_eq!(Config::load("client_config.json").unwrap(), test_config());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "toml")]
|
||||
fn load_from_toml() {
|
||||
assert_eq!(Config::load("client_config.toml").unwrap(), test_config());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "yaml")]
|
||||
fn load_from_yaml() {
|
||||
assert_eq!(Config::load("client_config.yaml").unwrap(), test_config());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_owner() {
|
||||
|
|
|
@ -15,12 +15,17 @@ extern crate native_tls;
|
|||
extern crate serde;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
#[cfg(feature = "json")]
|
||||
extern crate serde_json;
|
||||
#[cfg(feature = "yaml")]
|
||||
extern crate serde_yaml;
|
||||
extern crate tokio_core;
|
||||
extern crate tokio_io;
|
||||
extern crate tokio_mockstream;
|
||||
extern crate tokio_timer;
|
||||
extern crate tokio_tls;
|
||||
#[cfg(feature = "toml")]
|
||||
extern crate toml;
|
||||
|
||||
pub mod client;
|
||||
pub mod error;
|
||||
|
|
Loading…
Reference in a new issue