1616
1717const debug = require ( 'debug' ) ( 'rosidl_gen:packages' ) ;
1818const fs = require ( 'fs' ) ;
19+ const readline = require ( 'readline' ) ;
1920const path = require ( 'path' ) ;
2021const walk = require ( 'walk' ) ;
2122const os = require ( 'os' ) ;
2223
24+ const fsp = fs . promises ;
25+
2326const generatedRoot = path . join ( __dirname , '../generated/' ) ;
2427
2528function getPackageName ( filePath , amentExecuted ) {
@@ -70,6 +73,96 @@ function addInterfaceInfo(info, type, pkgMap) {
7073 pkg [ type ] . push ( info ) ;
7174}
7275
76+ /**
77+ * Gets all ament packages with ros messages in an ament index.
78+ * @param {string } rootDir Path to the ament root directory
79+ * @returns {string[] } array of package names
80+ */
81+ async function getAmentPackages ( rootDir ) {
82+ try {
83+ const files = await fsp . readdir (
84+ path . join (
85+ rootDir ,
86+ 'share' ,
87+ 'ament_index' ,
88+ 'resource_index' ,
89+ 'rosidl_interfaces'
90+ )
91+ ) ;
92+ return files ;
93+ } catch ( e ) {
94+ if ( ! e . code === 'ENOENT' ) {
95+ throw e ;
96+ }
97+ return [ ] ;
98+ }
99+ }
100+
101+ /**
102+ * Get paths to all rosidl resources in an ament package
103+ * @param {string } packageName name of the package
104+ * @param {string } amentRoot ament root directory
105+ * @returns {string[] } array of rosidl ament resources in a package
106+ */
107+ async function getPackageDefinitionsFiles ( packageName , amentRoot ) {
108+ const rosFiles = [ ] ;
109+ const rl = readline . createInterface (
110+ fs . createReadStream (
111+ path . join (
112+ amentRoot ,
113+ 'share' ,
114+ 'ament_index' ,
115+ 'resource_index' ,
116+ 'rosidl_interfaces' ,
117+ packageName
118+ ) ,
119+ { emitClose : true }
120+ )
121+ ) ;
122+ rl . on ( 'line' , ( line ) => {
123+ rosFiles . push ( path . join ( amentRoot , 'share' , packageName , line ) ) ;
124+ } ) ;
125+ await new Promise ( ( res ) => {
126+ rl . on ( 'close' , res ) ;
127+ } ) ;
128+ return rosFiles ;
129+ }
130+
131+ /**
132+ * Collects all packages in a directory by using the ament index.
133+ * @param {string } dir - the directory to search in
134+ * @return {Promise<Map<string, object>> } A mapping from the package name to some info about it.
135+ */
136+ async function findAmentPackagesInDirectory ( dir ) {
137+ const pkgs = await getAmentPackages ( dir ) ;
138+ const rosFiles = (
139+ await Promise . all ( pkgs . map ( ( pkg ) => getPackageDefinitionsFiles ( pkg , dir ) ) )
140+ ) . flat ( ) ;
141+ const pkgMap = new Map ( ) ;
142+ return new Promise ( ( resolve , reject ) => {
143+ rosFiles . forEach ( ( filePath ) => {
144+ if ( path . extname ( filePath ) === '.msg' ) {
145+ // Some .msg files were generated prior to 0.3.2 for .action files,
146+ // which has been disabled. So these files should be ignored here.
147+ if ( path . dirname ( dir ) . split ( path . sep ) . pop ( ) !== 'action' ) {
148+ addInterfaceInfo (
149+ grabInterfaceInfo ( filePath , true ) ,
150+ 'messages' ,
151+ pkgMap
152+ ) ;
153+ }
154+ } else if ( path . extname ( filePath ) === '.srv' ) {
155+ addInterfaceInfo ( grabInterfaceInfo ( filePath , true ) , 'services' , pkgMap ) ;
156+ } else if ( path . extname ( filePath ) === '.action' ) {
157+ addInterfaceInfo ( grabInterfaceInfo ( filePath , true ) , 'actions' , pkgMap ) ;
158+ } else {
159+ // we ignore all other files
160+ }
161+ } ) ;
162+ resolve ( pkgMap ) ;
163+ } ) ;
164+ }
165+
73166/**
74167 * Collects all packages in a directory.
75168 * @param {string } dir - the directory to search in
@@ -85,7 +178,10 @@ async function findPackagesInDirectory(dir) {
85178 if ( err ) {
86179 amentExecuted = false ;
87180 }
88- dir = amentExecuted ? path . join ( dir , 'share' ) : dir ;
181+
182+ if ( amentExecuted ) {
183+ return resolve ( findAmentPackagesInDirectory ( dir ) ) ;
184+ }
89185
90186 let walker = walk . walk ( dir , { followLinks : true } ) ;
91187 let pkgMap = new Map ( ) ;
0 commit comments