@@ -53,6 +53,8 @@ var OPTS = processCmdLineArgs();
5353var AUTHORS_FILE = OPTS . authorsFile || 'AUTHORS' ;
5454var MAILMAP_FILE = OPTS . mailmapFile || '.mailmap' ;
5555
56+ var PLATFORM_AGNOSTIC_EOL = / \r | \n | \r \n / ;
57+
5658var authorsMailMap = { } ;
5759
5860function usage ( ) {
@@ -92,12 +94,13 @@ function addAuthorToEmailMap(authorName, authorEmail) {
9294
9395 debug ( 'ADDING AUTHOR [' + authorName + '] [' + authorEmail + ']' ) ;
9496
95- if ( authorsMailMap [ authorName ] ) {
96- if ( authorsMailMap [ authorName ] . indexOf ( authorEmail ) === - 1 ) {
97- authorsMailMap [ authorName ] . push ( authorEmail ) ;
97+ var authorEntry = authorsMailMap [ authorName ] ;
98+ if ( authorEntry && authorEntry . emails ) {
99+ if ( authorEntry . emails . indexOf ( authorEmail ) === - 1 ) {
100+ authorEntry . emails . push ( authorEmail ) ;
98101 }
99102 } else {
100- authorsMailMap [ authorName ] = [ authorEmail ] ;
103+ authorsMailMap [ authorName ] = { emails : [ authorEmail ] } ;
101104 }
102105}
103106
@@ -126,7 +129,7 @@ function generateAuthorsMailMapFile(authorsMailMap, mailmapFilepath, cb) {
126129 assert ( Array . isArray ( authorsNames ) , 'authorsNames must be an array' ) ;
127130
128131 var authorName = authorsNames . splice ( 0 , 1 ) ;
129- var authorEmails = authorsMailMap [ authorName ] ;
132+ var authorEntry = authorsMailMap [ authorName ] ;
130133
131134 function writeNextAuthorOrDone ( ) {
132135 process . nextTick ( function onNextTick ( ) {
@@ -136,16 +139,19 @@ function generateAuthorsMailMapFile(authorsMailMap, mailmapFilepath, cb) {
136139 return cb ( ) ;
137140 } ) ;
138141 }
139- // Authors with no more than one email address don't need to be added
142+ // Unless the entry was already present in the original .mailmap file,
143+ // authors with no more than one email address don't need to be added
140144 // to the .mailmap file, since its purpose is to handle authors with
141145 // more than one email address.
142- if ( ! authorEmails || authorEmails . length < 2 ) {
146+ if ( ! authorEntry || ! authorEntry . emails ||
147+ ( authorEntry . emails . length < 2 && ! authorEntry . loadedFromExisting ) ) {
143148 debug ( 'Skipping mailmap entry for author [' + authorName + ']' ) ;
144149 return writeNextAuthorOrDone ( ) ;
145150 }
146151
147152 debug ( 'Writing mailmap entry for author [' + authorName + ']' ) ;
148153
154+ var authorEmails = authorEntry . emails ;
149155 authorEmails = authorEmails . map ( emailFormatter ) ;
150156
151157 var mapAuthorEntry = authorName + ' ' + authorEmails . join ( ' ' ) ;
@@ -182,7 +188,7 @@ var latestAuthorsLineChunk = '';
182188function addAuthors ( authors ) {
183189 assert ( typeof authors === 'string' , 'authors must be a string' ) ;
184190
185- var authors = ( latestAuthorsLineChunk + authors ) . split ( os . EOL ) ;
191+ var authors = ( latestAuthorsLineChunk + authors ) . split ( PLATFORM_AGNOSTIC_EOL ) ;
186192 latestAuthorsLineChunk = '' ;
187193 authors . forEach ( function eachAuthor ( author ) {
188194 if ( author && author . length > 0 ) {
@@ -202,38 +208,98 @@ function addAuthors(authors) {
202208 } ) ;
203209}
204210
205- var gitLog = child_process . spawn ( 'git' , GIT_LOG_COMMAND_ARGS ) ;
211+ function loadAdditionalAuthorsFromGitLog ( cb ) {
212+ var gitLog = child_process . spawn ( 'git' , GIT_LOG_COMMAND_ARGS ) ;
206213
207- gitLog . on ( 'close' , function onGitLogClose ( exitCode , signal ) {
208- if ( exitCode === 0 && signal === null ) {
214+ gitLog . on ( 'close' , function onGitLogClose ( exitCode , signal ) {
215+ if ( exitCode === 0 && signal === null ) {
209216
210- debug ( 'NB AUTHORS:' + Object . keys ( authorsMailMap ) . length ) ;
217+ debug ( 'NB AUTHORS:' + Object . keys ( authorsMailMap ) . length ) ;
211218
212- generateAuthorsFile ( AUTHORS_FILE , function onAuthorsFileGenerated ( err ) {
213- if ( err ) {
214- console . error ( 'Error when generating authors file:' , err ) ;
215- } else {
216- console . log ( 'Authors file generated successfully!' ) ;
217- }
218- } ) ;
219+ generateAuthorsFile ( AUTHORS_FILE , function onAuthorsFileGenerated ( err ) {
220+ if ( err ) {
221+ return cb ( new Error ( 'Error when generating authors file:' , err ) ) ;
222+ } else {
223+ console . log ( 'Authors file generated successfully!' ) ;
224+ }
225+ } ) ;
219226
220- generateAuthorsMailMapFile ( authorsMailMap ,
221- MAILMAP_FILE ,
222- function onMailmapFileGenerated ( err ) {
223- if ( err ) {
224- console . error ( 'Error when generating mailmap file:' , err ) ;
225- } else {
226- console . log ( 'mailmap file generated successfully!' ) ;
227- }
227+ generateAuthorsMailMapFile ( authorsMailMap ,
228+ MAILMAP_FILE ,
229+ function onMailmapFileGenerated ( err ) {
230+ if ( err ) {
231+ return cb ( new Error ( 'Error when generating mailmap file:' , err ) ) ;
232+ } else {
233+ console . log ( 'mailmap file generated successfully!' ) ;
234+ }
235+ } ) ;
236+ }
237+ } ) ;
238+
239+ gitLog . on ( 'error' , function onGitLogError ( err ) {
240+ var errorMsg = util . format ( 'Error when executing command %s: %s' , GIT_LOG_COMMAND , err ) ;
241+ return cb ( new Error ( errorMsg ) ) ;
242+ } ) ;
243+
244+ gitLog . stdout . on ( 'data' , function onGitLogData ( data ) {
245+ addAuthors ( data . toString ( ) ) ;
246+ } ) ;
247+ }
248+
249+ function addExistingMailmapEntries ( mailmapEntries , cb ) {
250+ assert ( typeof mailmapEntries === 'string' ,
251+ 'mailmapEntries must be a string' ) ;
252+ assert ( typeof cb === 'function' , 'cb must be a function' ) ;
253+
254+ var mailmapLines = mailmapEntries . split ( PLATFORM_AGNOSTIC_EOL ) ;
255+ mailmapLines . forEach ( function ( mailmapLine ) {
256+ debug ( 'Processing existing mailmap line:' ) ;
257+ debug ( mailmapLine ) ;
258+
259+ var indexFirstEmail = mailmapLine . indexOf ( '<' ) ;
260+ var authorName = mailmapLine . substr ( 0 , indexFirstEmail ) . trim ( ) ;
261+ debug ( 'author name: ' + authorName ) ;
262+
263+ var authorEmails = [ ] ;
264+
265+ var nextEmailIndex = indexFirstEmail ;
266+ for ( var idx = nextEmailIndex ;
267+ nextEmailIndex !== - 1 ;
268+ idx += mailmapLine . indexOf ( '<' , nextEmailIndex + 1 ) ) {
269+ var indexOfEmailEnd = mailmapLine . indexOf ( '>' , nextEmailIndex )
270+ var authorEmail = mailmapLine . substr ( nextEmailIndex + 1 ,
271+ indexOfEmailEnd - ( nextEmailIndex + 1 ) )
272+ debug ( 'author email: ' + authorEmail ) ;
273+ authorEmails . push ( authorEmail ) ;
274+
275+ nextEmailIndex = mailmapLine . indexOf ( '<' , indexOfEmailEnd ) ;
276+ }
277+
278+ if ( authorEmails . length > 0 ) {
279+ authorsMailMap [ authorName ] = {
280+ loadedFromExisting : true , emails : authorEmails
281+ } ;
282+ }
283+ } ) ;
284+
285+ return cb ( ) ;
286+ }
287+
288+ function loadExistingMailmapFile ( cb ) {
289+ debug ( 'Loading existing mailmap file' ) ;
290+
291+ fs . readFile ( MAILMAP_FILE , function onMailmapFileRead ( err , data ) {
292+ addExistingMailmapEntries ( data . toString ( ) , cb ) ;
293+ } ) ;
294+ }
295+
296+ loadExistingMailmapFile ( function onMailmapFileLoaded ( err ) {
297+ if ( err ) {
298+ console . error ( 'Error when loading existing mailmap file:' , err ) ;
299+ } else {
300+ return loadAdditionalAuthorsFromGitLog ( function onGitLoneDone ( err ) {
301+ console . error ( 'Error when loading git log data:' , err ) ;
228302 } ) ;
229303 }
230304} ) ;
231305
232- gitLog . on ( 'error' , function onGitLogError ( err ) {
233- console . error ( 'Error when executing command %s: %s' , GIT_LOG_COMMAND , err ) ;
234- process . exit ( 1 ) ;
235- } ) ;
236-
237- gitLog . stdout . on ( 'data' , function onGitLogData ( data ) {
238- addAuthors ( data . toString ( ) ) ;
239- } ) ;
0 commit comments