1919
2020let fs = require ( 'fs' ) ;
2121let path = require ( 'path' ) ;
22+ let utils = require ( 'util' ) ;
2223let log = require ( './logger.js' ) . createLogger ( ) ;
2324
2425// When sourcing your workspace, CMAKE_PREFIX_PATH is AUTOMATICALLY
2526// prepended with the devel directory of your workspace. Workspace
2627// chaining works by continuing this path prepending.
2728let cmakePath = process . env . CMAKE_PREFIX_PATH ;
2829let cmakePaths = cmakePath . split ( ':' ) ;
29- let jsMsgPath = 'share/ node_js/ ros' ;
30+ let jsMsgPath = path . join ( 'share' , ' node_js' , ' ros') ;
3031
3132let messagePackageMap = { } ;
3233let messagePackagePathMap = { } ;
@@ -41,6 +42,51 @@ let messagePackagePathMap = {};
4142// in the cache and require it if found.
4243//-----------------------------------------------------------------------
4344
45+ function createDirectory ( directory ) {
46+ let curPath = '/' ;
47+ const paths = directory . split ( path . sep ) ;
48+ paths . forEach ( ( part , index ) => {
49+ if ( ! part ) {
50+ return ;
51+ }
52+ curPath = path . join ( curPath , part ) ;
53+ const thisPath = curPath ;
54+
55+ try {
56+ fs . mkdirSync ( thisPath ) ;
57+ }
58+ catch ( err ) {
59+ if ( err . code !== 'EEXIST' ) {
60+ throw err ;
61+ }
62+ }
63+ } ) ;
64+ }
65+
66+ function copyFile ( from , to , replaceCallback ) {
67+ return new Promise ( ( resolve , reject ) => {
68+ const readStream = fs . createReadStream ( from ) ;
69+ let fileData = '' ;
70+ readStream . on ( 'data' , ( data ) => {
71+ fileData += data ;
72+ } ) ;
73+
74+ readStream . on ( 'end' , ( ) => {
75+ if ( typeof replaceCallback === 'function' ) {
76+ fileData = replaceCallback ( fileData ) ;
77+ }
78+
79+ // open the output file for writing
80+ const writeStream = fs . createWriteStream ( to ) ;
81+ writeStream . on ( 'open' , ( ) => {
82+ writeStream . write ( fileData ) ;
83+ writeStream . end ( ) ;
84+ resolve ( ) ;
85+ } ) ;
86+ } ) ;
87+ } ) ;
88+ }
89+
4490let MessageUtils = {
4591 findMessageFiles ( ) {
4692 if ( Object . keys ( messagePackagePathMap ) . length > 0 ) {
@@ -62,6 +108,78 @@ let MessageUtils = {
62108 } ) ;
63109 } ,
64110
111+ flatten ( outputDir ) {
112+ const finderDeclRegex = / ^ l e t _ f i n d e r = r e q u i r e \( ' \. \. \/ \. \. \/ \. \. \/ f i n d \. j s ' \) ; / m;
113+ const finderCallRegex = / ^ l e t ( \w + ) = _ f i n d e r \( \' \1\' \) ; / gm;
114+
115+ const flatten_local = ( packageName , startPath , localPath , outputDir ) => {
116+ const flattenPath = path . join ( startPath , localPath ) ;
117+ fs . readdir ( flattenPath , ( err , files ) => {
118+ if ( err ) {
119+ // if the path doesn't exist, it just means the package currently
120+ // being flattened doesn't have either msgs or srvs
121+ if ( err . code !== 'ENOENT' ) {
122+ throw new Error ( 'Error while flattening generated messages ' + err ) ;
123+ }
124+ return ;
125+ }
126+ // else
127+ const outputPath = path . join ( outputDir , packageName , localPath ) ;
128+ createDirectory ( outputPath )
129+
130+ files . forEach ( ( file ) => {
131+ const filePath = path . join ( flattenPath , file ) ;
132+ const outputFilePath = path . join ( outputDir , packageName , localPath , file ) ;
133+ let callback ;
134+ if ( file !== '_index.js' ) {
135+ callback = ( fileData ) => {
136+ fileData = fileData . replace ( finderDeclRegex , '' ) ;
137+ let matchData ;
138+ while ( ( matchData = finderCallRegex . exec ( fileData ) ) !== null ) {
139+ const matchStr = matchData [ 0 ] ;
140+ const msgPackage = matchData [ 1 ] ;
141+ const replaceStr = utils . format ( 'let %s = require(\'../../%s/_index.js\');' , msgPackage , msgPackage ) ;
142+ fileData = fileData . replace ( matchStr , replaceStr ) ;
143+ }
144+ return fileData ;
145+ } ;
146+ }
147+ copyFile ( filePath , outputFilePath , callback ) ;
148+ } ) ;
149+ } ) ;
150+ } ;
151+
152+ outputDir = path . resolve ( outputDir ) ;
153+ const messageDirectory = path . join ( outputDir , 'ros' ) ;
154+ createDirectory ( messageDirectory ) ;
155+
156+ // find relevant genjs base files and copy to output directory
157+ const filesToCopy = [ 'base_deserialize.js' , 'base_serialize.js' ] ;
158+ cmakePaths . some ( ( cmakePath ) => {
159+ const checkPath = path . join ( cmakePath , 'share' , 'node_js' ) ;
160+ let files = fs . readdirSync ( checkPath ) ;
161+ if ( ! files ) {
162+ return false ;
163+ }
164+ files . forEach ( ( fileName ) => {
165+ if ( filesToCopy . indexOf ( fileName ) !== - 1 ) {
166+ copyFile ( path . join ( checkPath , fileName ) , path . join ( outputDir , fileName ) ) ;
167+ }
168+ } ) ;
169+ return true ;
170+ } ) ;
171+
172+ Object . keys ( messagePackagePathMap ) . forEach ( ( packageName ) => {
173+ const messagePackagePath = messagePackagePathMap [ packageName ] ;
174+ const dir = path . dirname ( messagePackagePath )
175+
176+ flatten_local ( packageName , dir , 'msg' , messageDirectory ) ;
177+ flatten_local ( packageName , dir , 'srv' , messageDirectory ) ;
178+ // copy the index
179+ copyFile ( messagePackagePath , path . join ( messageDirectory , packageName , '_index.js' ) ) ;
180+ } ) ;
181+ } ,
182+
65183 loadMessagePackage ( msgPackage ) {
66184 const indexPath = messagePackagePathMap [ msgPackage ] ;
67185 if ( indexPath === undefined ) {
0 commit comments