i2c: Move to newer version of Clap

Lets not use beta release anymore, since we have a stable version
available now.

The newer version doesn't support Yamls anymore, but rather another
feature "derive", which is quite easy to use actually. Lets migrate to
it.

Some of the tests can't be done anymore, drop them.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
This commit is contained in:
Viresh Kumar 2022-01-20 10:30:20 +05:30
parent e5634eada4
commit 6f588d6809
3 changed files with 43 additions and 108 deletions

View File

@ -12,7 +12,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = { version = "=3.0.0-beta.2", features = ["yaml"] }
clap = { version = ">=3.0", features = ["derive"] }
env_logger = ">=0.9"
libc = ">=0.2.95"
log = ">=0.4.6"

View File

@ -1,37 +0,0 @@
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

View File

@ -14,7 +14,7 @@ use std::num::ParseIntError;
use std::sync::{Arc, RwLock};
use std::thread::spawn;
use clap::{load_yaml, App, ArgMatches};
use clap::Parser;
use thiserror::Error as ThisError;
use vhost::{vhost_user, vhost_user::Listener};
use vhost_user_backend::VhostUserDaemon;
@ -28,8 +28,6 @@ type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, PartialEq, ThisError)]
/// Errors related to low level i2c helpers
pub enum Error {
#[error("Invalid socket path")]
SocketPathInvalid,
#[error("Invalid socket count: {0}")]
SocketCountInvalid(usize),
#[error("Invalid device list")]
@ -48,6 +46,23 @@ pub enum Error {
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)]
struct DeviceConfig {
adapter_no: u32,
@ -140,39 +155,25 @@ struct I2cConfiguration {
devices: AdapterConfig,
}
impl TryFrom<ArgMatches> for I2cConfiguration {
impl TryFrom<I2cArgs> for I2cConfiguration {
type Error = Error;
fn try_from(cmd_args: ArgMatches) -> Result<Self> {
let socket_path = cmd_args
.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 {
fn try_from(args: I2cArgs) -> Result<Self> {
if args.socket_count == 0 {
return Err(Error::SocketCountInvalid(0));
}
let list = cmd_args
.value_of("devices")
.ok_or(Error::DeviceListInvalid)?;
let devices = AdapterConfig::try_from(list)?;
let devices = AdapterConfig::try_from(args.device_list.as_str())?;
Ok(I2cConfiguration {
socket_path,
socket_count,
socket_path: args.socket_path,
socket_count: args.socket_count,
devices,
})
}
}
fn start_backend<D: 'static + I2cDevice + Send + Sync>(cmd_args: ArgMatches) -> Result<()> {
let config = I2cConfiguration::try_from(cmd_args).unwrap();
fn start_backend<D: 'static + I2cDevice + Send + Sync>(args: I2cArgs) -> Result<()> {
let config = I2cConfiguration::try_from(args).unwrap();
// 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)?);
@ -237,10 +238,7 @@ fn start_backend<D: 'static + I2cDevice + Send + Sync>(cmd_args: ArgMatches) ->
fn main() -> Result<()> {
env_logger::init();
let yaml = load_yaml!("cli.yaml");
let cmd_args = App::from(yaml).get_matches();
start_backend::<PhysDevice>(cmd_args)
start_backend::<PhysDevice>(I2cArgs::parse())
}
#[cfg(test)]
@ -260,19 +258,12 @@ mod tests {
}
}
fn get_cmd_args(name: Option<&str>, devices: &str, count: Option<&str>) -> ArgMatches {
let mut args = vec!["prog", "-l", devices];
let yaml = load_yaml!("cli.yaml");
let app = App::from(yaml);
if let Some(name) = name {
args.extend_from_slice(&["-s", name]);
fn get_cmd_args(path: &str, devices: &str, count: usize) -> I2cArgs {
I2cArgs {
socket_path: path.to_string(),
socket_count: count,
device_list: devices.to_string(),
}
if let Some(count) = count {
args.extend_from_slice(&["-c", count]);
}
app.try_get_matches_from(args).unwrap()
}
#[test]
@ -296,45 +287,31 @@ mod tests {
#[test]
fn test_parse_failure() {
let socket_name = Some("vi2c.sock");
let socket_name = "vi2c.sock";
// 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!(
I2cConfiguration::try_from(cmd_args).unwrap_err(),
Error::ParseFailure("3d".parse::<u32>().unwrap_err())
);
// 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!(
I2cConfiguration::try_from(cmd_args).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
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!(
I2cConfiguration::try_from(cmd_args).unwrap_err(),
Error::SocketCountInvalid(0)
);
// 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!(
I2cConfiguration::try_from(cmd_args).unwrap_err(),
Error::ClientAddressDuplicate(4)
@ -343,14 +320,9 @@ mod tests {
#[test]
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 expected_devices = AdapterConfig::new_with(vec![
@ -361,7 +333,7 @@ mod tests {
let expected_config = I2cConfiguration {
socket_count: 5,
socket_path: String::from(socket_name.unwrap()),
socket_path: String::from(socket_name),
devices: expected_devices,
};
@ -387,8 +359,8 @@ mod tests {
#[test]
fn test_fail_listener() {
// This will fail the listeners and thread will panic.
let socket_name = Some("~/path/not/present/i2c");
let cmd_args = get_cmd_args(socket_name, "1:4,3:5", Some("5"));
let socket_name = "~/path/not/present/i2c";
let cmd_args = get_cmd_args(socket_name, "1:4,3:5", 5);
assert_eq!(
start_backend::<DummyDevice>(cmd_args).unwrap_err(),