Unverified Commit c60cd2db authored by mathieupoirier's avatar mathieupoirier Committed by GitHub

Merge branch 'main' into dependabot/cargo/clap_derive-3.0.12

parents 54075c5b 9e54e290
{ {
"coverage_score": 87.2, "coverage_score": 85.5,
"exclude_path": "", "exclude_path": "",
"crate_features": "" "crate_features": ""
} }
...@@ -12,7 +12,7 @@ edition = "2018" ...@@ -12,7 +12,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
clap = { version = "=3.0.0-beta.2", features = ["yaml"] } clap = { version = ">=3.0", features = ["derive"] }
env_logger = ">=0.9" env_logger = ">=0.9"
libc = ">=0.2.95" libc = ">=0.2.95"
log = ">=0.4.6" log = ">=0.4.6"
......
name: vhost-device-i2c
version: "0.1.0"
author: "Viresh Kumar <viresh.kumar@linaro.org>"
about: Virtio I2C backend daemon.
settings:
- ArgRequiredElseHelp
args:
# Connection to sockets
- socket_path:
short: s
long: socket-path
value_name: FILE
takes_value: true
about: Location of vhost-user Unix domain socket. This is suffixed by 0,1,2..socket_count-1.
- socket_count:
short: c
long: socket-count
value_name: INT
takes_value: true
about: Number of guests (sockets) to connect to. Default = 1.
# I2C device list on host
- devices:
short: l
long: device-list
value_name: PATH
takes_value: true
about: List of I2C bus and clients in format <bus>:<client_addr>[:<client_addr>][,<bus>:<client_addr>[:<client_addr>]]
groups:
- required_args:
args:
- socket_path
args:
- devices
required: true
...@@ -14,7 +14,7 @@ use std::num::ParseIntError; ...@@ -14,7 +14,7 @@ use std::num::ParseIntError;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use std::thread::spawn; use std::thread::spawn;
use clap::{load_yaml, App, ArgMatches}; use clap::Parser;
use thiserror::Error as ThisError; use thiserror::Error as ThisError;
use vhost::{vhost_user, vhost_user::Listener}; use vhost::{vhost_user, vhost_user::Listener};
use vhost_user_backend::VhostUserDaemon; use vhost_user_backend::VhostUserDaemon;
...@@ -28,8 +28,6 @@ type Result<T> = std::result::Result<T, Error>; ...@@ -28,8 +28,6 @@ type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, PartialEq, ThisError)] #[derive(Debug, PartialEq, ThisError)]
/// Errors related to low level i2c helpers /// Errors related to low level i2c helpers
pub enum Error { pub enum Error {
#[error("Invalid socket path")]
SocketPathInvalid,
#[error("Invalid socket count: {0}")] #[error("Invalid socket count: {0}")]
SocketCountInvalid(usize), SocketCountInvalid(usize),
#[error("Invalid device list")] #[error("Invalid device list")]
...@@ -48,6 +46,23 @@ pub enum Error { ...@@ -48,6 +46,23 @@ pub enum Error {
FailedJoiningThreads, FailedJoiningThreads,
} }
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct I2cArgs {
/// Location of vhost-user Unix domain socket. This is suffixed by 0,1,2..socket_count-1.
#[clap(short, long)]
socket_path: String,
/// Number of guests (sockets) to connect to.
#[clap(short = 'c', long, default_value_t = 1)]
socket_count: usize,
/// List of I2C bus and clients in format
/// <bus>:<client_addr>[:<client_addr>][,<bus>:<client_addr>[:<client_addr>]].
#[clap(short = 'l', long)]
device_list: String,
}
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
struct DeviceConfig { struct DeviceConfig {
adapter_no: u32, adapter_no: u32,
...@@ -140,39 +155,25 @@ struct I2cConfiguration { ...@@ -140,39 +155,25 @@ struct I2cConfiguration {
devices: AdapterConfig, devices: AdapterConfig,
} }
impl TryFrom<ArgMatches> for I2cConfiguration { impl TryFrom<I2cArgs> for I2cConfiguration {
type Error = Error; type Error = Error;
fn try_from(cmd_args: ArgMatches) -> Result<Self> { fn try_from(args: I2cArgs) -> Result<Self> {
let socket_path = cmd_args if args.socket_count == 0 {
.value_of("socket_path")
.ok_or(Error::SocketPathInvalid)?
.to_string();
let socket_count = cmd_args
.value_of("socket_count")
.unwrap_or("1")
.parse::<usize>()
.map_err(Error::ParseFailure)?;
if socket_count == 0 {
return Err(Error::SocketCountInvalid(0)); return Err(Error::SocketCountInvalid(0));
} }
let list = cmd_args let devices = AdapterConfig::try_from(args.device_list.as_str())?;
.value_of("devices")
.ok_or(Error::DeviceListInvalid)?;
let devices = AdapterConfig::try_from(list)?;
Ok(I2cConfiguration { Ok(I2cConfiguration {
socket_path, socket_path: args.socket_path,
socket_count, socket_count: args.socket_count,
devices, devices,
}) })
} }
} }
fn start_backend<D: 'static + I2cDevice + Send + Sync>(cmd_args: ArgMatches) -> Result<()> { fn start_backend<D: 'static + I2cDevice + Send + Sync>(args: I2cArgs) -> Result<()> {
let config = I2cConfiguration::try_from(cmd_args).unwrap(); let config = I2cConfiguration::try_from(args).unwrap();
// The same i2c_map structure instance is shared between all the guests // The same i2c_map structure instance is shared between all the guests
let i2c_map = Arc::new(I2cMap::<D>::new(&config.devices).map_err(Error::I2cFailure)?); let i2c_map = Arc::new(I2cMap::<D>::new(&config.devices).map_err(Error::I2cFailure)?);
...@@ -237,10 +238,7 @@ fn start_backend<D: 'static + I2cDevice + Send + Sync>(cmd_args: ArgMatches) -> ...@@ -237,10 +238,7 @@ fn start_backend<D: 'static + I2cDevice + Send + Sync>(cmd_args: ArgMatches) ->
fn main() -> Result<()> { fn main() -> Result<()> {
env_logger::init(); env_logger::init();
let yaml = load_yaml!("cli.yaml"); start_backend::<PhysDevice>(I2cArgs::parse())
let cmd_args = App::from(yaml).get_matches();
start_backend::<PhysDevice>(cmd_args)
} }
#[cfg(test)] #[cfg(test)]
...@@ -260,19 +258,12 @@ mod tests { ...@@ -260,19 +258,12 @@ mod tests {
} }
} }
fn get_cmd_args(name: Option<&str>, devices: &str, count: Option<&str>) -> ArgMatches { fn get_cmd_args(path: &str, devices: &str, count: usize) -> I2cArgs {
let mut args = vec!["prog", "-l", devices]; I2cArgs {
let yaml = load_yaml!("cli.yaml"); socket_path: path.to_string(),
let app = App::from(yaml); socket_count: count,
device_list: devices.to_string(),
if let Some(name) = name {
args.extend_from_slice(&["-s", name]);
}
if let Some(count) = count {
args.extend_from_slice(&["-c", count]);
} }
app.try_get_matches_from(args).unwrap()
} }
#[test] #[test]
...@@ -296,45 +287,31 @@ mod tests { ...@@ -296,45 +287,31 @@ mod tests {
#[test] #[test]
fn test_parse_failure() { fn test_parse_failure() {
let socket_name = Some("vi2c.sock"); let socket_name = "vi2c.sock";
// Invalid bus_addr // Invalid bus_addr
let cmd_args = get_cmd_args(socket_name, "1:4,3d:5", Some("5")); let cmd_args = get_cmd_args(socket_name, "1:4,3d:5", 5);
assert_eq!( assert_eq!(
I2cConfiguration::try_from(cmd_args).unwrap_err(), I2cConfiguration::try_from(cmd_args).unwrap_err(),
Error::ParseFailure("3d".parse::<u32>().unwrap_err()) Error::ParseFailure("3d".parse::<u32>().unwrap_err())
); );
// Invalid client address // Invalid client address
let cmd_args = get_cmd_args(socket_name, "1:4d", Some("5")); let cmd_args = get_cmd_args(socket_name, "1:4d", 5);
assert_eq!( assert_eq!(
I2cConfiguration::try_from(cmd_args).unwrap_err(), I2cConfiguration::try_from(cmd_args).unwrap_err(),
Error::ParseFailure("4d".parse::<u16>().unwrap_err()) Error::ParseFailure("4d".parse::<u16>().unwrap_err())
); );
// Invalid socket path
let cmd_args = get_cmd_args(None, "1:4d", Some("5"));
assert_eq!(
I2cConfiguration::try_from(cmd_args).unwrap_err(),
Error::SocketPathInvalid
);
// Invalid socket count
let cmd_args = get_cmd_args(socket_name, "1:4", Some("1d"));
assert_eq!(
I2cConfiguration::try_from(cmd_args).unwrap_err(),
Error::ParseFailure("1d".parse::<u16>().unwrap_err())
);
// Zero socket count // Zero socket count
let cmd_args = get_cmd_args(socket_name, "1:4", Some("0")); let cmd_args = get_cmd_args(socket_name, "1:4", 0);
assert_eq!( assert_eq!(
I2cConfiguration::try_from(cmd_args).unwrap_err(), I2cConfiguration::try_from(cmd_args).unwrap_err(),
Error::SocketCountInvalid(0) Error::SocketCountInvalid(0)
); );
// Duplicate client address: 4 // Duplicate client address: 4
let cmd_args = get_cmd_args(socket_name, "1:4,2:32:21,5:4:23", Some("5")); let cmd_args = get_cmd_args(socket_name, "1:4,2:32:21,5:4:23", 5);
assert_eq!( assert_eq!(
I2cConfiguration::try_from(cmd_args).unwrap_err(), I2cConfiguration::try_from(cmd_args).unwrap_err(),
Error::ClientAddressDuplicate(4) Error::ClientAddressDuplicate(4)
...@@ -343,14 +320,9 @@ mod tests { ...@@ -343,14 +320,9 @@ mod tests {
#[test] #[test]
fn test_parse_successful() { fn test_parse_successful() {
let socket_name = Some("vi2c.sock"); let socket_name = "vi2c.sock";
// Missing socket count, default (1) should be used.
let cmd_args = get_cmd_args(socket_name, "1:4,2:32:21,5:5:23", None);
let config = I2cConfiguration::try_from(cmd_args).unwrap();
assert_eq!(config.socket_count, 1);
let cmd_args = get_cmd_args(socket_name, "1:4,2:32:21,5:5:23", Some("5")); let cmd_args = get_cmd_args(socket_name, "1:4,2:32:21,5:5:23", 5);
let config = I2cConfiguration::try_from(cmd_args).unwrap(); let config = I2cConfiguration::try_from(cmd_args).unwrap();
let expected_devices = AdapterConfig::new_with(vec![ let expected_devices = AdapterConfig::new_with(vec![
...@@ -361,7 +333,7 @@ mod tests { ...@@ -361,7 +333,7 @@ mod tests {
let expected_config = I2cConfiguration { let expected_config = I2cConfiguration {
socket_count: 5, socket_count: 5,
socket_path: String::from(socket_name.unwrap()), socket_path: String::from(socket_name),
devices: expected_devices, devices: expected_devices,
}; };
...@@ -387,8 +359,8 @@ mod tests { ...@@ -387,8 +359,8 @@ mod tests {
#[test] #[test]
fn test_fail_listener() { fn test_fail_listener() {
// This will fail the listeners and thread will panic. // This will fail the listeners and thread will panic.
let socket_name = Some("~/path/not/present/i2c"); let socket_name = "~/path/not/present/i2c";
let cmd_args = get_cmd_args(socket_name, "1:4,3:5", Some("5")); let cmd_args = get_cmd_args(socket_name, "1:4,3:5", 5);
assert_eq!( assert_eq!(
start_backend::<DummyDevice>(cmd_args).unwrap_err(), start_backend::<DummyDevice>(cmd_args).unwrap_err(),
......
Subproject commit d023262164ef8766ac2b0be33de13ef52b8706a1 Subproject commit d216a46879096a4f1e83af3a7b6c90c26e1a688d
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment