Skip to content

Commit 5725553

Browse files
authored
Cleanup Message Generation (#726)
This PR closes #732 improves upon #712 by handling other whitespaces besides normal spaces in a more robust way. Also cleans up parts of the message/etc. generation process (using async functions). Fix#732
1 parent a5a84bd commit 5725553

File tree

7 files changed

+78
-81
lines changed

7 files changed

+78
-81
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ Special thanks to the people who contribute.
249249
- [Alex Mikhalev](https://github.com/amikhalev)
250250
- [Wayne Parrott](https://github.com/wayneparrott)
251251
- [Matt Richard](https://github.com/mattrichard)
252+
- [Felix Divo](https://github.com/felixdivo)
252253

253254
## License
254255

rosidl_gen/idl_generator.js

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const dots = dot.process({
2626
path: path.join(__dirname, '../rosidl_gen/templates'),
2727
});
2828

29-
function removeExtraSpaceLines(str) {
29+
function removeEmptyLines(str) {
3030
return str.replace(/^\s*\n/gm, '');
3131
}
3232

@@ -44,7 +44,7 @@ function generateServiceJSStruct(serviceInfo, dir) {
4444
'__' +
4545
serviceInfo.interfaceName +
4646
'.js';
47-
const generatedCode = removeExtraSpaceLines(
47+
const generatedCode = removeEmptyLines(
4848
dots.service({ serviceInfo: serviceInfo })
4949
);
5050
return writeGeneratedCode(dir, fileName, generatedCode);
@@ -68,7 +68,7 @@ function generateMessageJSStructFromSpec(messageInfo, dir, spec) {
6868
spec.msgName +
6969
'.js';
7070

71-
const generatedCode = removeExtraSpaceLines(
71+
const generatedCode = removeEmptyLines(
7272
dots.message({
7373
messageInfo: messageInfo,
7474
spec: spec,
@@ -207,12 +207,13 @@ async function generateActionJSStruct(actionInfo, dir) {
207207
'__' +
208208
actionInfo.subFolder +
209209
'__' +
210-
actionInfo.interfaceName;
211-
const generatedCode = removeExtraSpaceLines(
210+
actionInfo.interfaceName +
211+
'.js';
212+
const generatedCode = removeEmptyLines(
212213
dots.action({ actionInfo: actionInfo })
213214
);
214-
dir = path.join(dir, `${actionInfo.pkgName}`);
215-
const action = writeGeneratedCode(dir, fileName + '.js', generatedCode);
215+
dir = path.join(dir, actionInfo.pkgName);
216+
const action = writeGeneratedCode(dir, fileName, generatedCode);
216217

217218
await Promise.all([
218219
goalMsg,
@@ -230,17 +231,15 @@ async function generateActionJSStruct(actionInfo, dir) {
230231
}
231232

232233
async function generateJSStructFromIDL(pkg, dir) {
233-
const results = [];
234-
pkg.messages.forEach(messageInfo => {
235-
results.push(generateMessageJSStruct(messageInfo, dir));
236-
});
237-
pkg.services.forEach(serviceInfo => {
238-
results.push(generateServiceJSStruct(serviceInfo, dir));
239-
});
240-
pkg.actions.forEach(actionInfo => {
241-
results.push(generateActionJSStruct(actionInfo, dir));
242-
});
243-
await Promise.all(results);
234+
await Promise.all([
235+
...pkg.messages.map((messageInfo) =>
236+
generateMessageJSStruct(messageInfo, dir)
237+
),
238+
...pkg.services.map((serviceInfo) =>
239+
generateServiceJSStruct(serviceInfo, dir)
240+
),
241+
...pkg.actions.map((actionInfo) => generateActionJSStruct(actionInfo, dir)),
242+
]);
244243
}
245244

246245
module.exports = generateJSStructFromIDL;

rosidl_gen/index.js

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,14 @@ const installedPackagePaths = process.env.AMENT_PREFIX_PATH.split(
2525
);
2626

2727
async function generateInPath(path) {
28-
const results = [];
2928
const pkgs = await packages.findPackagesInDirectory(path);
30-
pkgs.forEach(pkg => {
31-
results.push(generateJSStructFromIDL(pkg, generatedRoot));
32-
});
33-
await Promise.all(results);
29+
const pkgsInfo = Array.from(pkgs.values());
30+
await Promise.all(
31+
pkgsInfo.map((pkgInfo) => generateJSStructFromIDL(pkgInfo, generatedRoot))
32+
);
3433
}
3534

3635
async function generateAll(forcedGenerating) {
37-
const results = [];
38-
3936
// If we want to create the JavaScript files compulsively (|forcedGenerating| equals to true)
4037
// or the JavaScript files have not been created (|exist| equals to false),
4138
// all the JavaScript files will be created.
@@ -45,10 +42,9 @@ async function generateAll(forcedGenerating) {
4542
path.join(__dirname, 'generator.json'),
4643
path.join(generatedRoot, 'generator.json')
4744
);
48-
installedPackagePaths.forEach(path => {
49-
results.push(generateInPath(path));
50-
});
51-
await Promise.all(results);
45+
await Promise.all(
46+
installedPackagePaths.map((path) => generateInPath(path))
47+
);
5248
}
5349
}
5450

rosidl_gen/packages.js

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,18 @@ function addInterfaceInfo(info, type, pkgMap) {
7070
pkg[type].push(info);
7171
}
7272

73-
function findPackagesInDirectory(dir) {
73+
/**
74+
* Collects all packages in a directory.
75+
* @param {string} dir - the directory to search in
76+
* @return {Promise<Map<string, object>>} A mapping from the package name to some info about it.
77+
*/
78+
async function findPackagesInDirectory(dir) {
7479
return new Promise((resolve, reject) => {
7580
let amentExecuted = true;
7681

7782
// If there is a folder named 'share' under the root path, we consider that
7883
// the ament build tool has been executed and |amentExecuted| will be true.
79-
fs.access(path.join(dir, 'share'), err => {
84+
fs.access(path.join(dir, 'share'), (err) => {
8085
if (err) {
8186
amentExecuted = false;
8287
}
@@ -88,12 +93,7 @@ function findPackagesInDirectory(dir) {
8893
if (path.extname(file.name) === '.msg') {
8994
// Some .msg files were generated prior to 0.3.2 for .action files,
9095
// which has been disabled. So these files should be ignored here.
91-
if (
92-
path
93-
.dirname(root)
94-
.split(path.sep)
95-
.pop() !== 'action'
96-
) {
96+
if (path.dirname(root).split(path.sep).pop() !== 'action') {
9797
addInterfaceInfo(
9898
grabInterfaceInfo(path.join(root, file.name), amentExecuted),
9999
'messages',
@@ -112,6 +112,8 @@ function findPackagesInDirectory(dir) {
112112
'actions',
113113
pkgMap
114114
);
115+
} else {
116+
// we ignore all other files
115117
}
116118
next();
117119
});

rosidl_parser/parser.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def get_json_object_from_msg_spec_object(msg_spec_object):
4949

5050
if __name__ == '__main__':
5151
if len(sys.argv) < 3:
52-
print ('Wrong number of argments')
52+
print('Wrong number of argments')
5353
sys.exit(1)
5454
try:
5555
parser_method = getattr(parser, sys.argv[1])
@@ -69,9 +69,9 @@ def get_json_object_from_msg_spec_object(msg_spec_object):
6969
else:
7070
assert False, "unknown method '%s'" % sys.argv[1]
7171

72-
print (json.dumps(json_obj))
72+
print(json.dumps(json_obj))
7373
sys.exit(0)
7474

7575
except Exception as e:
76-
print (str(e), file=sys.stderr)
76+
print(str(e), file=sys.stderr)
7777
sys.exit(1)

rosidl_parser/py_utils.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@
1616

1717
const os = require('os');
1818

19-
let pyUtils = {
20-
getPython(py) {
19+
module.exports = {
20+
/**
21+
* Get the python executable on any platform suitable to be handed to *child_process.execFile*.
22+
* @param {string} py either "python2" or "python3"
23+
* @return {[string, string[]]} A command to execute directly and additional arguments as an array.
24+
*/
25+
getPythonExecutable(py) {
2126
if (os.type() === 'Windows_NT') {
22-
py = py === 'python' ? 'py -2' : 'py -3';
27+
return ['py', [py === 'python' ? '-2' : '-3']];
2328
}
24-
return py;
29+
return [py, []];
2530
},
2631
};
27-
28-
module.exports = pyUtils;

rosidl_parser/rosidl_parser.js

Lines changed: 31 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,56 +14,52 @@
1414

1515
'use strict';
1616

17-
const os = require('os');
18-
const exec = require('child_process').exec;
19-
const pyUtils = require('./py_utils');
17+
const path = require('path');
18+
const execFile = require('child_process').execFile;
2019

21-
const pythonExe = pyUtils.getPython('python3');
20+
const pythonExecutable = require('./py_utils').getPythonExecutable('python3');
2221

23-
let rosidlParser = {
22+
const rosidlParser = {
2423
parseMessageFile(packageName, filePath) {
25-
return this._parseFile(
26-
'parse_message_file',
27-
packageName,
28-
filePath.replace(/\s/g, '\\ ')
29-
);
24+
return this._parseFile('parse_message_file', packageName, filePath);
3025
},
3126

3227
parseServiceFile(packageName, filePath) {
33-
return this._parseFile(
34-
'parse_service_file',
35-
packageName,
36-
filePath.replace(/\s/g, '\\ ')
37-
);
28+
return this._parseFile('parse_service_file', packageName, filePath);
3829
},
3930

4031
parseActionFile(packageName, filePath) {
41-
return this._parseFile(
42-
'parse_action_file',
43-
packageName,
44-
filePath.replace(/\s/g, '\\ ')
45-
);
32+
return this._parseFile('parse_action_file', packageName, filePath);
4633
},
4734

48-
_parseFile(...args) {
35+
_parseFile(command, packageName, filePath) {
4936
return new Promise((resolve, reject) => {
50-
exec(this._assembleCommand(args), (err, stdout, stderr) => {
51-
if (err) {
52-
reject(new Error(stderr));
53-
} else {
54-
resolve(JSON.parse(stdout));
37+
const args = [
38+
path.join(__dirname, 'parser.py'),
39+
command,
40+
packageName,
41+
filePath,
42+
];
43+
const [pythonExecutableFile, pythonExecutableArgs] = pythonExecutable;
44+
execFile(
45+
pythonExecutableFile,
46+
pythonExecutableArgs.concat(args),
47+
(err, stdout, stderr) => {
48+
if (err) {
49+
reject(
50+
new Error(
51+
`There was an error executing python with arguments "${JSON.stringify(
52+
args
53+
)}": "${err}"; stderr was: ${stderr}`
54+
)
55+
);
56+
} else {
57+
resolve(JSON.parse(stdout));
58+
}
5559
}
56-
});
60+
);
5761
});
5862
},
59-
60-
_assembleCommand(args) {
61-
let command = `${pythonExe} ${__dirname}/parser.py`;
62-
args.forEach((arg) => {
63-
command += ' ' + arg;
64-
});
65-
return command;
66-
},
6763
};
6864

6965
module.exports = rosidlParser;

0 commit comments

Comments
 (0)