Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify parsing of AMENT_PREFIX_PATH #489

Merged
merged 9 commits into from
May 1, 2024
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions libraries/extensions/ros2-bridge/msg-gen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ quote = "1.0"
regex = "1"
syn = "1.0"
thiserror = "1.0"
glob = "0.3.1"
tracing = "0.1.33"
8 changes: 7 additions & 1 deletion libraries/extensions/ros2-bridge/msg-gen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ where

#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct U16String {
chars: Vec<u16>,
pub chars: Vec<u16>,
}

#(#shared_type_defs)*
Expand All @@ -262,6 +262,12 @@ where
}
}

impl ffi::U16String {
fn from_str(arg: &str) -> Self {
Self { chars: crate::_core::widestring::U16String::from_str(arg).into_vec()}
}
}

#(#message_struct_impls)*

#cxx_bridge_impls
Expand Down
185 changes: 68 additions & 117 deletions libraries/extensions/ros2-bridge/msg-gen/src/parser/package.rs
Original file line number Diff line number Diff line change
@@ -1,94 +1,88 @@
use std::{
fs::{self, File},
io::{BufRead, BufReader},
path::Path,
};
use std::{collections::HashMap, path::Path};

use anyhow::Result;
use anyhow::{Context, Result};
use glob::glob;
use tracing::warn;

use super::{action::parse_action_file, message::parse_message_file, service::parse_service_file};
use crate::types::Package;

const ROSIDL_INTERFACES: &str = "share/ament_index/resource_index/rosidl_interfaces";
fn get_ros_msgs_each_package<P: AsRef<Path>>(root_dir: P) -> Result<Vec<Package>> {
let mut map: HashMap<String, Package> = HashMap::new();

const NAMESPACES: &[&str] = &["msg", "srv", "action"];
let ros_formats = vec!["msg", "srv", "action"];

fn parse_line(line: &str) -> Option<(&str, &str)> {
if !line.ends_with(".idl") {
return None;
}
for &namespace in NAMESPACES {
if line.starts_with(&format!("{}/", namespace)) {
let name = &line[namespace.len() + 1..line.len() - 4];
return Some((namespace, name));
}
// Return empty vector if root_dir is empty
if root_dir.as_ref() == Path::new("") {
let empty_vec: Vec<Package> = vec![];
warn!("AMENT_PREFIX_PATH pointed to ''");
return Ok(empty_vec);
}
println!("Unknown type: {:?}", line);
None
}

fn get_ros_msgs_each_package<P: AsRef<Path>>(root_dir: P) -> Result<Vec<Package>> {
let dir = root_dir.as_ref().join(ROSIDL_INTERFACES);

let mut packages = Vec::new();

let paths = match fs::read_dir(dir) {
Ok(paths) => paths,
Err(_) => {
return Ok(packages);
}
};
for ros_format in ros_formats {
let pattern = root_dir.as_ref().to_string_lossy().to_string()
+ "/**/"
+ ros_format
+ "/*."
+ ros_format;
let mut visited_files = vec![];
for entry in glob(&pattern).context("Failed to read glob pattern")? {
let path = entry.context("Could not glob given path")?;
let file_name = path
.clone()
.file_name()
.unwrap()
.to_str()
.unwrap()
.to_string();

let package = path
.parent()
.context("Should have a msg folder")?
.parent()
.context("should have a package folder")?
.file_name()
.context("folder name should exist")?
.to_string_lossy()
.to_string();

// Hack
if file_name == "libstatistics_collector" {
continue;
} else if visited_files.contains(&(package.clone(), file_name.clone())) {
warn!(
"found two versions of package: {:?}, message: {:?}. will skip the one in: {:#?}",
package, file_name, path
);
continue;
} else {
visited_files.push((package.clone(), file_name.clone()));
}

for path in paths {
let path = path?.path();
let file_name = path
.clone()
.file_name()
.unwrap()
.to_str()
.unwrap()
.to_string();
// Hack
if file_name == "libstatistics_collector" {
continue;
}
let p = map
.entry(package.clone())
.or_insert_with(|| Package::new(package.clone()));

let mut package = Package::new(file_name.clone());
for line in BufReader::new(File::open(path)?).lines() {
match parse_line(&line?) {
Some(("msg", v)) => {
let msg = parse_message_file(
&file_name,
root_dir
.as_ref()
.join(format!("share/{}/msg/{}.msg", file_name, v)),
)?;
package.messages.push(msg);
match ros_format {
"msg" => {
p.messages.push(parse_message_file(&package, path.clone())?);
}
Some(("srv", v)) => {
let srv = parse_service_file(
&file_name,
root_dir
.as_ref()
.join(format!("share/{}/srv/{}.srv", file_name, v)),
)?;
package.services.push(srv);
"srv" => {
p.services.push(parse_service_file(&package, path.clone())?);
}
Some(("action", v)) => {
let action = parse_action_file(
&file_name,
root_dir
.as_ref()
.join(format!("share/{}/action/{}.action", file_name, v)),
)?;
package.actions.push(action);
"action" => {
p.actions.push(parse_action_file(&package, path.clone())?);
}
Some(_) => unreachable!(),
None => {}
_ => todo!(),
}
}
packages.push(package);
}
debug_assert!(
!map.is_empty(),
"it seens that no package was generated from your AMENT_PREFIX_PATH directory"
);

let packages = map.into_values().collect();
Ok(packages)
}

Expand All @@ -110,46 +104,3 @@ where

Ok(packages)
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn parse_line_msg() {
let result = parse_line("msg/TestHoge.idl").unwrap();

assert_eq!(result.0, "msg");
assert_eq!(result.1, "TestHoge");
}

#[test]
fn parse_line_srv() {
let result = parse_line("srv/TestHoge.idl").unwrap();

assert_eq!(result.0, "srv");
assert_eq!(result.1, "TestHoge");
}

#[test]
fn parse_line_action() {
let result = parse_line("action/TestHoge.idl").unwrap();

assert_eq!(result.0, "action");
assert_eq!(result.1, "TestHoge");
}

#[test]
fn parse_line_wrong_namespace() {
assert!(parse_line("test/Test.msg").is_none());
assert!(parse_line("test/Test.srv").is_none());
assert!(parse_line("test/Test.action").is_none());
}

#[test]
fn parse_line_wrong_suffix() {
assert!(parse_line("msg/Test.test").is_none());
assert!(parse_line("srv/Test.test").is_none());
assert!(parse_line("action/Test.test").is_none());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ impl GenericString {
// TODO: Assertion
let value = Literal::string(value);
if self.is_wide() {
quote! { ::widestring::U16String::from_str(#value) }
quote! { ffi::U16String::from_str(#value) }
haixuanTao marked this conversation as resolved.
Show resolved Hide resolved
} else {
quote! { ::std::string::String::from(#value) }
}
Expand Down
Loading