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

Custom filter for omitting ROS2 interfaces from the message-generation process #891

Merged
merged 1 commit into from
Feb 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/windows-build-and-test-compatibility.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
strategy:
fail-fast: false
matrix:
node-version: [10.X, 12.X, 14.X, 16.11.X, 17.X, 18.X, 19.X]
node-version: [10.X, 12.X, 14.X, 16.11.X, 17.X, 18.12.X, 19.X]
ros_distribution:
# - foxy
- galactic
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/windows-build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
strategy:
fail-fast: false
matrix:
node-version: [10.X, 12.X, 14.X, 16.11.X, 17.X, 18.X, 19.X]
node-version: [10.X, 12.X, 14.X, 16.11.X, 17.X, 18.12.0, 19.X]
steps:
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
Expand Down
5 changes: 5 additions & 0 deletions rosidl_gen/blocklist.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[
{
"pkgName": "rosbag2_storage_mcap_testdata"
}
]
104 changes: 104 additions & 0 deletions rosidl_gen/filter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
const fs = require('fs');
const path = require('path');
const os = require('os');

// blocklist.json format
// [
// {
// pkgName: RegExString,
// interfaceName: RegExString,
// os: RegExString
// },
// ...
// ]
//
// examples
// [
// {
// "pkgName": "action*"
// },
// {
// "pkgName": "std_msgs",
// },
// {
// "pkgName": "std_msgs",
// "interfaceName": "String"
// },
// {
// "os": "Linux"
// },
// ]

const RosPackageFilters = {
filters: [],
_loaded: false,

addFilter: function (pkgName, interfaceName, os) {
this.filters.push({
pkgName: pkgName,
interfaceName: interfaceName,
os: os,
});
},

_matches: function (filter, pkgInfo) {
if (filter.os && filter.os.test(os.type())) {
return true;
}

if (filter.pkgName) {
if (filter.pkgName.test(pkgInfo.pkgName)) {
if (!filter.interfaceName) {
return true;
}
} else {
return false;
}
}

if (
filter.interfaceName &&
filter.interfaceName.test(pkgInfo.interfaceName)
) {
return true;
}

return false;
},

load: function (
blocklistPath = path.join(__dirname, '../rosidl_gen/blocklist.json')
) {
this._loaded = true;

if (!fs.existsSync(blocklistPath)) return;

// eslint-disable-next-line
let blocklistData = JSON.parse(fs.readFileSync(blocklistPath, 'utf8'));

let filters = blocklistData.map((pkgFilterData) => {
let filter = {};
if (pkgFilterData['pkgName']) {
filter.pkgName = new RegExp(pkgFilterData.pkgName);
}
if (pkgFilterData['interfaceName']) {
filter.interfaceName = new RegExp(pkgFilterData.interfaceName);
}
if (pkgFilterData['os']) {
filter.os = new RegExp(pkgFilterData.os);
}
return filter;
});

this.filters = filters.filter(
(filter) => !filter.os || filter.os.test(os.type())
);
},

matchesAny: function (pkgInfo) {
if (!this._loaded) this.load();
return this.filters.some((filter) => this._matches(filter, pkgInfo));
},
};

module.exports = RosPackageFilters;
3 changes: 3 additions & 0 deletions rosidl_gen/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ const installedPackagePaths = process.env.AMENT_PREFIX_PATH.split(

async function generateInPath(path) {
const pkgs = await packages.findPackagesInDirectory(path);

const pkgsInfo = Array.from(pkgs.values());

await Promise.all(
pkgsInfo.map((pkgInfo) => generateJSStructFromIDL(pkgInfo, generatedRoot))
);
Expand All @@ -42,6 +44,7 @@ async function generateAll(forcedGenerating) {
path.join(__dirname, 'generator.json'),
path.join(generatedRoot, 'generator.json')
);

await Promise.all(
installedPackagePaths.map((path) => generateInPath(path))
);
Expand Down
78 changes: 39 additions & 39 deletions rosidl_gen/packages.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const path = require('path');
const walk = require('walk');
const os = require('os');
const flat = require('array.prototype.flat');
const pkgFilters = require('../rosidl_gen/filter.js');

const fsp = fs.promises;

Expand Down Expand Up @@ -140,28 +141,30 @@ async function findAmentPackagesInDirectory(dir) {
pkgs.map((pkg) => getPackageDefinitionsFiles(pkg, dir))
);

// Support flat() methond for nodejs < 11.
// Support flat() method for nodejs < 11.
const rosFiles = Array.prototype.flat ? files.flat() : flat(files);

const pkgMap = new Map();
return new Promise((resolve, reject) => {
rosFiles.forEach((filePath) => {
if (path.extname(filePath) === '.msg') {
// Some .msg files were generated prior to 0.3.2 for .action files,
// which has been disabled. So these files should be ignored here.
if (path.dirname(dir).split(path.sep).pop() !== 'action') {
addInterfaceInfo(
grabInterfaceInfo(filePath, true),
'messages',
pkgMap
);
}
} else if (path.extname(filePath) === '.srv') {
addInterfaceInfo(grabInterfaceInfo(filePath, true), 'services', pkgMap);
} else if (path.extname(filePath) === '.action') {
addInterfaceInfo(grabInterfaceInfo(filePath, true), 'actions', pkgMap);
const interfaceInfo = grabInterfaceInfo(filePath, true);
const ignore = pkgFilters.matchesAny(interfaceInfo);
if (ignore) {
console.log('Omitting filtered interface: ', interfaceInfo);
} else {
// we ignore all other files
if (path.extname(filePath) === '.msg') {
// Some .msg files were generated prior to 0.3.2 for .action files,
// which has been disabled. So these files should be ignored here.
if (path.dirname(dir).split(path.sep).pop() !== 'action') {
addInterfaceInfo(interfaceInfo, 'messages', pkgMap);
}
} else if (path.extname(filePath) === '.srv') {
addInterfaceInfo(interfaceInfo, 'services', pkgMap);
} else if (path.extname(filePath) === '.action') {
addInterfaceInfo(interfaceInfo, 'actions', pkgMap);
} else {
// we ignore all other files
}
}
});
resolve(pkgMap);
Expand Down Expand Up @@ -191,30 +194,27 @@ async function findPackagesInDirectory(dir) {
let walker = walk.walk(dir, { followLinks: true });
let pkgMap = new Map();
walker.on('file', (root, file, next) => {
if (path.extname(file.name) === '.msg') {
// Some .msg files were generated prior to 0.3.2 for .action files,
// which has been disabled. So these files should be ignored here.
if (path.dirname(root).split(path.sep).pop() !== 'action') {
addInterfaceInfo(
grabInterfaceInfo(path.join(root, file.name), amentExecuted),
'messages',
pkgMap
);
}
} else if (path.extname(file.name) === '.srv') {
addInterfaceInfo(
grabInterfaceInfo(path.join(root, file.name), amentExecuted),
'services',
pkgMap
);
} else if (path.extname(file.name) === '.action') {
addInterfaceInfo(
grabInterfaceInfo(path.join(root, file.name), amentExecuted),
'actions',
pkgMap
);
const interfaceInfo = grabInterfaceInfo(
path.join(root, file.name),
amentExecuted
);
const ignore = pkgFilters.matchesAny(interfaceInfo);
if (ignore) {
console.log('Omitting filtered interface: ', interfaceInfo);
} else {
// we ignore all other files
if (path.extname(file.name) === '.msg') {
// Some .msg files were generated prior to 0.3.2 for .action files,
// which has been disabled. So these files should be ignored here.
if (path.dirname(root).split(path.sep).pop() !== 'action') {
addInterfaceInfo(interfaceInfo, 'messages', pkgMap);
}
} else if (path.extname(file.name) === '.srv') {
addInterfaceInfo(interfaceInfo, 'services', pkgMap);
} else if (path.extname(file.name) === '.action') {
addInterfaceInfo(interfaceInfo, 'actions', pkgMap);
} else {
// we ignore all other files
}
}
next();
});
Expand Down
10 changes: 9 additions & 1 deletion rostsd_gen/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ declare module "rclnodejs" {
const path = require('path');
const fs = require('fs');
const loader = require('../lib/interface_loader.js');
const pkgFilters = require('../rosidl_gen/filter.js');

async function generateAll() {
// load pkg and interface info (msgs and srvs)
Expand Down Expand Up @@ -63,7 +64,14 @@ function getPkgInfos(rootDir) {

for (let filename of files) {
const typeClass = fileName2Typeclass(filename);
if (!typeClass.type) continue;
if (
!typeClass.type ||
pkgFilters.matchesAny({
pkgName: typeClass.package,
interfaceName: typeClass.name,
})
)
continue;

const rosInterface = loader.loadInterface(typeClass);

Expand Down