Merge pull request #93 from vireshk/i2c/clap

i2c: Move to newer version of Clap
This commit is contained in:
Viresh Kumar 2022-01-25 13:53:25 +05:30 committed by GitHub
commit f7bb411129
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 57 additions and 161 deletions

65
Cargo.lock generated
View File

@ -48,9 +48,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "3.0.0-beta.2"
version = "3.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bd1061998a501ee7d4b6d449020df3266ca3124b941ec56cf2005c3779ca142"
checksum = "7a30c3bf9ff12dfe5dae53f0a96e0febcd18420d1c0e7fad77796d9d5c4b5375"
dependencies = [
"atty",
"bitflags",
@ -61,16 +61,13 @@ dependencies = [
"strsim",
"termcolor",
"textwrap",
"unicode-width",
"vec_map",
"yaml-rust",
]
[[package]]
name = "clap_derive"
version = "3.0.0-beta.5"
version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b15c6b4f786ffb6192ffe65a36855bc1fc2444bcd0945ae16748dcd6ed7d0d3"
checksum = "517358c28fcef6607bf6f76108e02afad7e82297d132a6b846dcc1fc3efcd153"
dependencies = [
"heck",
"proc-macro-error",
@ -100,12 +97,9 @@ checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "heck"
version = "0.3.3"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
dependencies = [
"unicode-segmentation",
]
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]]
name = "hermit-abi"
@ -144,12 +138,6 @@ version = "0.2.112"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
[[package]]
name = "linked-hash-map"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]]
name = "log"
version = "0.4.14"
@ -167,9 +155,12 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "os_str_bytes"
version = "2.4.0"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afb2e1c3ee07430c2cf76151675e583e0f19985fa6efae47d6848a3e2c824f85"
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
dependencies = [
"memchr",
]
[[package]]
name = "proc-macro-error"
@ -258,12 +249,9 @@ dependencies = [
[[package]]
name = "textwrap"
version = "0.12.1"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "203008d98caf094106cfaba70acfed15e18ed3ddb7d94e49baec153a2b462789"
dependencies = [
"unicode-width",
]
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
[[package]]
name = "thiserror"
@ -285,30 +273,12 @@ dependencies = [
"syn",
]
[[package]]
name = "unicode-segmentation"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
[[package]]
name = "unicode-width"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version_check"
version = "0.9.4"
@ -427,12 +397,3 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "yaml-rust"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]

View File

@ -1,5 +1,5 @@
{
"coverage_score": 87.2,
"coverage_score": 85.7,
"exclude_path": "",
"crate_features": ""
}

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(),