config: Replace rust-ini
This cuts binary size by around 30KiB on my local release builds.
This commit is contained in:
8
Cargo.lock
generated
8
Cargo.lock
generated
@@ -85,6 +85,11 @@ dependencies = [
|
||||
"rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enquote"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "fakegreet"
|
||||
version = "0.5.0"
|
||||
@@ -137,12 +142,12 @@ name = "greetd"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"async-trait 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enquote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"greetd_ipc 0.5.1",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nix 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pam-sys 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rust-ini 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -611,6 +616,7 @@ dependencies = [
|
||||
"checksum const-random 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "2f1af9ac737b2dd2d577701e59fd09ba34822f6f2ebdb30a7647405d9e55e16a"
|
||||
"checksum const-random-macro 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "25e4c606eb459dd29f7c57b2e0879f2b6f14ee130918c2b78ccb58a9624e6c7a"
|
||||
"checksum dlv-list 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1b391911b9a786312a10cb9d2b3d0735adfd5a8113eb3648de26a75e91b0826c"
|
||||
"checksum enquote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ec878a5d2f3b6e9eaee72373dd23414cfc7d353104741471bec712ef241a66e"
|
||||
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
|
@@ -22,4 +22,4 @@ tokio = { version = "0.2", features = ["net", "sync", "macros", "signal", "rt-ut
|
||||
getopts = "0.2"
|
||||
thiserror = "1.0"
|
||||
async-trait = "0.1"
|
||||
rust-ini = "0.15"
|
||||
enquote = "1.0.3"
|
134
greetd/src/config/inish.rs
Normal file
134
greetd/src/config/inish.rs
Normal file
@@ -0,0 +1,134 @@
|
||||
use std::{collections::HashMap, error::Error};
|
||||
|
||||
fn parse_field<'a>(line: &'a str) -> Result<(&'a str, &'a str), Box<dyn Error>> {
|
||||
let split = match line.find('=') {
|
||||
Some(v) => v,
|
||||
None => return Err("expected equals sign on line, but found none".into()),
|
||||
};
|
||||
|
||||
let (key, value) = line.split_at(split);
|
||||
let (key, value) = (key.trim(), value.trim_matches('=').trim());
|
||||
|
||||
Ok((key, value))
|
||||
}
|
||||
|
||||
type InishSection<'a> = HashMap<&'a str, &'a str>;
|
||||
type Inish<'a> = HashMap<&'a str, InishSection<'a>>;
|
||||
|
||||
pub fn parse<'a>(s: &'a str) -> Result<Inish<'a>, Box<dyn Error>> {
|
||||
let mut sections: Inish<'a> = HashMap::new();
|
||||
let mut current_section = HashMap::new();
|
||||
let mut current_section_name = "";
|
||||
|
||||
for line in s.lines() {
|
||||
let line = line.trim();
|
||||
let mut chars = line.chars();
|
||||
let start = chars.next();
|
||||
let end = chars.last();
|
||||
match (start, end) {
|
||||
(Some('#'), _) => continue,
|
||||
(Some('['), Some(']')) => {
|
||||
sections.insert(current_section_name, current_section);
|
||||
current_section = HashMap::new();
|
||||
let len = line.bytes().count();
|
||||
current_section_name = &line[1..len - 1].trim();
|
||||
}
|
||||
(Some('['), v) => {
|
||||
return Err(format!(
|
||||
"expected Some(']') to terminate section name, but got {:?}",
|
||||
v
|
||||
)
|
||||
.into());
|
||||
}
|
||||
_ if line.is_empty() => continue,
|
||||
_ => {
|
||||
let (key, value) = parse_field(line)?;
|
||||
current_section.insert(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sections.insert(current_section_name, current_section);
|
||||
Ok(sections)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn sections() {
|
||||
let config = parse(
|
||||
"
|
||||
[section_a]
|
||||
[section_b]
|
||||
",
|
||||
)
|
||||
.expect("config didn't parse");
|
||||
|
||||
if !config.contains_key("section_a") {
|
||||
panic!("named section did not exist");
|
||||
}
|
||||
|
||||
if !config.contains_key("section_b") {
|
||||
panic!("named section did not exist");
|
||||
}
|
||||
|
||||
if !config.contains_key("") {
|
||||
panic!("unnamed section did not exist");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fields() {
|
||||
let config = parse(
|
||||
"
|
||||
field_outside = 'hello'
|
||||
[section_a]
|
||||
field_a = 1234
|
||||
",
|
||||
)
|
||||
.expect("config didn't parse");
|
||||
|
||||
let section_a = match config.get("section_a") {
|
||||
Some(v) => v,
|
||||
None => panic!("named section did not exist"),
|
||||
};
|
||||
|
||||
assert_eq!(section_a.get("field_a"), Some(&"1234"));
|
||||
|
||||
let section_unnamed = match config.get("") {
|
||||
Some(v) => v,
|
||||
None => panic!("unnamed section did not exist"),
|
||||
};
|
||||
|
||||
assert_eq!(section_unnamed.get("field_outside"), Some(&"'hello'"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn whitespaces() {
|
||||
let config = parse(
|
||||
"
|
||||
|
||||
field outside = 'hello'
|
||||
|
||||
[ section a ]
|
||||
field a = 1234 ",
|
||||
)
|
||||
.expect("config didn't parse");
|
||||
|
||||
let section_a = match config.get("section a") {
|
||||
Some(v) => v,
|
||||
None => panic!("named section did not exist"),
|
||||
};
|
||||
|
||||
assert_eq!(section_a.get("field a"), Some(&"1234"));
|
||||
|
||||
let section_unnamed = match config.get("") {
|
||||
Some(v) => v,
|
||||
None => panic!("unnamed section did not exist"),
|
||||
};
|
||||
|
||||
assert_eq!(section_unnamed.get("field outside"), Some(&"'hello'"));
|
||||
}
|
||||
}
|
@@ -1,9 +1,12 @@
|
||||
use std::{env, fs::read_to_string};
|
||||
use std::{collections::HashMap, env, fs::read_to_string};
|
||||
|
||||
use enquote::unquote;
|
||||
use getopts::Options;
|
||||
|
||||
use super::error::Error;
|
||||
|
||||
mod inish;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum VtSelection {
|
||||
Next,
|
||||
@@ -48,16 +51,28 @@ fn print_usage(program: &str, opts: Options) {
|
||||
println!("For more details, see greetd(1).");
|
||||
}
|
||||
|
||||
fn parse_old_config(config: &ini::Ini) -> Result<ConfigFile, Error> {
|
||||
let general = config.section(None::<String>).ok_or("no general section")?;
|
||||
let greeter = general
|
||||
fn maybe_unquote(s: &str) -> Result<String, Error> {
|
||||
Ok(match s.chars().next() {
|
||||
Some('"') | Some('\'') => unquote(s).map_err(|e| Error::ConfigError(format!("{}", e)))?,
|
||||
_ => s.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_old_config(config: &HashMap<&str, HashMap<&str, &str>>) -> Result<ConfigFile, Error> {
|
||||
let general = config.get("").ok_or("no general section")?;
|
||||
|
||||
let greeterstr = general
|
||||
.get("greeter")
|
||||
.ok_or("unable to parse configuration file: no greeter specified")?;
|
||||
let greeter_user = general.get("greeter_user").unwrap_or("greeter");
|
||||
let vt: VtSelection = match general
|
||||
let greeter = maybe_unquote(greeterstr)?;
|
||||
|
||||
let greeter_userstr = general.get("greeter_user").unwrap_or(&"greeter");
|
||||
let greeter_user = maybe_unquote(greeter_userstr)?;
|
||||
|
||||
let vtstr = general
|
||||
.get("vt")
|
||||
.ok_or("unable to parse configuration file: no VT specified")?
|
||||
{
|
||||
.ok_or("unable to parse configuration file: no VT specified")?;
|
||||
let vt: VtSelection = match maybe_unquote(vtstr)?.as_str() {
|
||||
"none" | "\"none\"" => VtSelection::None,
|
||||
"current" | "\"current\"" => VtSelection::Current,
|
||||
"next" | "\"next\"" => VtSelection::Next,
|
||||
@@ -70,42 +85,56 @@ fn parse_old_config(config: &ini::Ini) -> Result<ConfigFile, Error> {
|
||||
Ok(ConfigFile {
|
||||
terminal: ConfigTerminal { vt },
|
||||
default_session: ConfigSession {
|
||||
user: greeter_user.to_string(),
|
||||
command: greeter.to_string(),
|
||||
user: greeter_user,
|
||||
command: greeter,
|
||||
},
|
||||
initial_session: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_new_config(config: &ini::Ini) -> Result<ConfigFile, Error> {
|
||||
let default_session = match config.section(Some("default_session")) {
|
||||
Some(section) => Ok(ConfigSession {
|
||||
command: section
|
||||
fn parse_new_config(config: &HashMap<&str, HashMap<&str, &str>>) -> Result<ConfigFile, Error> {
|
||||
let default_session = match config.get("default_session") {
|
||||
Some(section) => {
|
||||
let commandstr = section
|
||||
.get("command")
|
||||
.ok_or("default_session contains no command")?
|
||||
.to_string(),
|
||||
user: section.get("user").unwrap_or("greeter").to_string(),
|
||||
}),
|
||||
.ok_or("default_session contains no command")?;
|
||||
let command = maybe_unquote(commandstr)
|
||||
.map_err(|e| format!("unable to read default_session.command: {}", e))?;
|
||||
|
||||
let userstr = section.get("user").unwrap_or(&"greeter");
|
||||
let user = maybe_unquote(userstr)
|
||||
.map_err(|e| format!("unable to read default_session.user: {}", e))?;
|
||||
|
||||
Ok(ConfigSession { command, user })
|
||||
}
|
||||
None => Err("no default_session specified"),
|
||||
}?;
|
||||
|
||||
let initial_session = match config.section(Some("initial_session")) {
|
||||
Some(section) => Some(ConfigSession {
|
||||
command: section
|
||||
let initial_session = match config.get("initial_session") {
|
||||
Some(section) => {
|
||||
let commandstr = section
|
||||
.get("command")
|
||||
.ok_or("initial_session contains no command")?
|
||||
.to_string(),
|
||||
user: section
|
||||
.ok_or("initial_session contains no command")?;
|
||||
let command = maybe_unquote(commandstr)
|
||||
.map_err(|e| format!("unable to read initial_session.command: {}", e))?;
|
||||
|
||||
let userstr = section
|
||||
.get("user")
|
||||
.ok_or("initial_session contains no user")?
|
||||
.to_string(),
|
||||
}),
|
||||
.ok_or("initial_session contains no user")?;
|
||||
let user = maybe_unquote(userstr)
|
||||
.map_err(|e| format!("unable to read initial_session.user: {}", e))?;
|
||||
|
||||
Some(ConfigSession { command, user })
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
let terminal = match config.section(Some("terminal")) {
|
||||
let terminal = match config.get("terminal") {
|
||||
Some(section) => Ok(ConfigTerminal {
|
||||
vt: match section.get("vt").ok_or("VT not specified")? {
|
||||
vt: match maybe_unquote(section.get("vt").ok_or("VT not specified")?)
|
||||
.map_err(|e| format!("unable to read terminal.vt: {}", e))?
|
||||
.as_str()
|
||||
{
|
||||
"none" | "\"none\"" => VtSelection::None,
|
||||
"current" | "\"current\"" => VtSelection::Current,
|
||||
"next" | "\"next\"" => VtSelection::Next,
|
||||
@@ -126,7 +155,7 @@ fn parse_new_config(config: &ini::Ini) -> Result<ConfigFile, Error> {
|
||||
}
|
||||
|
||||
fn parse_config(config_str: &str) -> Result<ConfigFile, Error> {
|
||||
let config_ini = ini::Ini::load_from_str(config_str)?;
|
||||
let config_ini = inish::parse(config_str)?;
|
||||
match parse_new_config(&config_ini) {
|
||||
Ok(v) => Ok(v),
|
||||
Err(e) => match parse_old_config(&config_ini) {
|
||||
|
@@ -78,9 +78,3 @@ impl From<std::ffi::NulError> for Error {
|
||||
Error::Error(error.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ini::ini::ParseError> for Error {
|
||||
fn from(error: ini::ini::ParseError) -> Self {
|
||||
Error::Error(error.to_string())
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user