11var util = require ( 'util' ) ,
22 f = util . format ,
33 EventEmitter = require ( 'events' ) . EventEmitter ,
4- path = require ( 'path' ) ,
4+ $ path = require ( 'path' ) ,
55 uuid = require ( 'node-uuid' ) ,
66 fork = require ( 'child_process' ) . fork ,
77 pbxWriter = require ( './pbxWriter' ) ,
8- pbxFile = require ( './pbxFile' ) ,
8+ pbxFile = require ( './pbxFile' ) . pbxFile ,
9+ pbxFileTypes = require ( './pbxFile' ) . fileTypes ,
910 fs = require ( 'fs' ) ,
1011 parser = require ( './parser/pbxproj' ) ,
1112 COMMENT_KEY = / _ c o m m e n t $ / ,
12- NO_SPECIAL_SYMBOLS = / ^ [ a - z A - Z 0 - 9 _ \. \$ ] + \. [ a - z A - Z ] + $ / ;
13+ NO_SPECIAL_SYMBOLS = / ^ [ a - z A - Z 0 - 9 _ \. \$ ] + \. [ a - z A - Z ] + $ / ,
14+ HEADER_FILE_TYPE_SUFFIX = ".h" ,
15+ SOURCE_CODE_FILE_TYPE_PREFIX = "sourcecode." ;
1316
1417function pbxProject ( filename ) {
1518 if ( ! ( this instanceof pbxProject ) )
1619 return new pbxProject ( filename ) ;
1720
18- this . filepath = path . resolve ( filename )
21+ this . filepath = $ path. resolve ( filename )
1922}
2023
2124util . inherits ( pbxProject , EventEmitter )
@@ -286,31 +289,52 @@ pbxProject.prototype.removeFromPbxBuildFileSection = function (file) {
286289 }
287290}
288291
289- pbxProject . prototype . addPbxGroup = function ( filePathsArray , name , path , sourceTree ) {
292+ pbxProject . prototype . findMainPbxGroup = function ( ) {
293+ var groups = this . hash . project . objects [ 'PBXGroup' ] ;
294+ var candidates = [ ] ;
295+ for ( var key in groups ) {
296+ if ( ! groups [ key ] . path && ! groups [ key ] . name && groups [ key ] . isa ) {
297+ candidates . push ( groups [ key ] ) ;
298+ }
299+ }
300+ if ( candidates . length == 1 ) {
301+ return candidates [ 0 ] ;
302+ }
303+
304+ return null ;
305+ }
306+
307+ pbxProject . prototype . addPbxGroup = function ( filePathsArray , name , path , sourceTree , opt ) {
308+
309+ var oldGroup = this . pbxGroupByName ( name ) ;
310+ if ( oldGroup ) {
311+ this . removePbxGroup ( name , path ) ;
312+ }
313+
290314 var groups = this . hash . project . objects [ 'PBXGroup' ] ,
291- pbxGroupUuid = this . generateUuid ( ) ,
315+ pbxGroupUuid = opt . uuid || this . generateUuid ( ) ,
292316 commentKey = f ( "%s_comment" , pbxGroupUuid ) ,
293317 pbxGroup = {
294318 isa : 'PBXGroup' ,
295319 children : [ ] ,
296320 name : name ,
297- path : path ,
298321 sourceTree : sourceTree ? sourceTree : '"<group>"'
299- } ,
322+ } , //path is mandatory only for the main group
300323 fileReferenceSection = this . pbxFileReferenceSection ( ) ,
301324 filePathToReference = { } ;
302-
325+
303326 for ( var key in fileReferenceSection ) {
304327 // only look for comments
305328 if ( ! COMMENT_KEY . test ( key ) ) continue ;
306-
329+
307330 var fileReferenceKey = key . split ( COMMENT_KEY ) [ 0 ] ,
308331 fileReference = fileReferenceSection [ fileReferenceKey ] ;
309-
332+
310333 filePathToReference [ fileReference . path ] = { fileRef : fileReferenceKey , basename : fileReferenceSection [ key ] } ;
311334 }
312335
313336 for ( var index = 0 ; index < filePathsArray . length ; index ++ ) {
337+
314338 var filePath = filePathsArray [ index ] ,
315339 filePathQuoted = "\"" + filePath + "\"" ;
316340 if ( filePathToReference [ filePath ] ) {
@@ -320,23 +344,80 @@ pbxProject.prototype.addPbxGroup = function (filePathsArray, name, path, sourceT
320344 pbxGroup . children . push ( pbxGroupChild ( filePathToReference [ filePathQuoted ] ) ) ;
321345 continue ;
322346 }
323-
324- var file = new pbxFile ( filePath ) ;
325- file . uuid = this . generateUuid ( ) ;
326- file . fileRef = this . generateUuid ( ) ;
327- this . addToPbxFileReferenceSection ( file ) ; // PBXFileReference
328- this . addToPbxBuildFileSection ( file ) ; // PBXBuildFile
329- pbxGroup . children . push ( pbxGroupChild ( file ) ) ;
347+
348+ var srcRootPath = $path . dirname ( $path . dirname ( this . filepath ) ) ;
349+ var file = new pbxFile ( $path . relative ( srcRootPath , filePath ) ) ;
350+ if ( fs . lstatSync ( filePath ) . isDirectory ( ) ) {
351+ file . uuid = this . generateUuid ( ) ;
352+ file . fileRef = file . uuid ;
353+ this . addToPbxFileReferenceSection ( file ) ; // PBXFileReference
354+ this . addToPbxBuildFileSection ( file ) ;
355+ pbxGroup . children . push ( pbxGroupChild ( file ) ) ;
356+ var files = fs . readdirSync ( filePath ) . map ( p => $path . join ( filePath , p ) ) ;
357+ this . addPbxGroup ( files , $path . basename ( filePath ) , filePath , null , { uuid : file . uuid } ) ;
358+ } else if ( file . lastType . startsWith ( SOURCE_CODE_FILE_TYPE_PREFIX ) ) {
359+ file . uuid = this . generateUuid ( ) ;
360+ file . fileRef = this . generateUuid ( ) ;
361+ this . addToPbxFileReferenceSection ( file ) ; // PBXFileReference
362+ this . addToPbxBuildFileSection ( file ) ; // PBXBuildFile
363+ if ( ! file . lastType . endsWith ( HEADER_FILE_TYPE_SUFFIX ) ) {
364+ this . addToPbxSourcesBuildPhase ( file ) ;
365+ }
366+ pbxGroup . children . push ( pbxGroupChild ( file ) ) ;
367+ }
368+
330369 }
331-
370+
332371 if ( groups ) {
333372 groups [ pbxGroupUuid ] = pbxGroup ;
334373 groups [ commentKey ] = name ;
335374 }
336-
375+
376+ if ( opt . isMain ) {
377+ let mainGroup = this . findMainPbxGroup ( ) ;
378+ if ( mainGroup ) {
379+ var file = new pbxFile ( $path . relative ( this . filepath , path ) ) ;
380+ file . fileRef = pbxGroupUuid ;
381+ mainGroup . children . push ( pbxGroupChild ( file ) ) ;
382+ }
383+ }
384+
337385 return { uuid : pbxGroupUuid , pbxGroup : pbxGroup } ;
338386}
339387
388+ pbxProject . prototype . removePbxGroup = function ( name , path ) {
389+ var group = this . pbxGroupByName ( name ) ;
390+ if ( ! group ) {
391+ return ;
392+ }
393+
394+ var children = group . children ;
395+
396+ for ( i in children ) {
397+ var file = new pbxFile ( $path . join ( path , children [ i ] . comment ) ) ;
398+ file . fileRef = children [ i ] . value ;
399+ file . uuid = file . fileRef ;
400+ this . removePbxGroup ( children [ i ] . comment , $path . join ( path , children [ i ] . comment ) ) ;
401+ this . removeFromPbxFileReferenceSection ( file ) ;
402+ this . removeFromPbxBuildFileSection ( file ) ;
403+ this . removeFromPbxSourcesBuildPhase ( file ) ;
404+ }
405+
406+ //copied from https://github.com/alunny/node-xcode/blob/master/lib/pbxProject.js#L527
407+ var section = this . hash . project . objects [ 'PBXGroup' ] ,
408+ key , itemKey ;
409+
410+ for ( key in section ) {
411+ // only look for comments
412+ if ( ! COMMENT_KEY . test ( key ) ) continue ;
413+
414+ if ( section [ key ] == name ) {
415+ itemKey = key . split ( COMMENT_KEY ) [ 0 ] ;
416+ delete section [ itemKey ] ;
417+ }
418+ }
419+ }
420+
340421pbxProject . prototype . addToPbxFileReferenceSection = function ( file ) {
341422 var commentKey = f ( "%s_comment" , file . fileRef ) ;
342423
@@ -852,7 +933,7 @@ pbxProject.prototype.removeFromHeaderSearchPaths = function (file) {
852933 INHERITED = '"$(inherited)"' ,
853934 SEARCH_PATHS = 'HEADER_SEARCH_PATHS' ,
854935 config , buildSettings , searchPaths ;
855- var new_path = searchPathForFile ( file , this ) ;
936+ var new_path = typeof file === 'string' ? file : searchPathForFile ( file , this ) ;
856937
857938 for ( config in configurations ) {
858939 buildSettings = configurations [ config ] . buildSettings ;
@@ -1048,7 +1129,7 @@ function searchPathForFile(file, proj) {
10481129
10491130 var plugins = proj . pbxGroupByName ( 'Plugins' ) ,
10501131 pluginsPath = plugins ? plugins . path : null ,
1051- fileDir = path . dirname ( file . path ) ;
1132+ fileDir = $ path. dirname ( file . path ) ;
10521133
10531134 if ( fileDir == '.' ) {
10541135 fileDir = '' ;
0 commit comments