Skip to content

Commit 99947af

Browse files
authored
fix: ensure that PbxGroups are not duplicated (#17)
1 parent 77267e7 commit 99947af

File tree

5 files changed

+165
-2
lines changed

5 files changed

+165
-2
lines changed

Diff for: .gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ node_modules/*
22
.DS_Store
33
npm-debug.log
44
package-lock.json
5-
5+
.ns-build-pbxgroup-data.json
66
*.tgz

Diff for: lib/guidMapper.js

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
const fs = require('fs');
2+
const path = require('path');
3+
4+
function guidMapper(filePath) {
5+
this.filePath = filePath;
6+
this.data = this.loadFromFile();
7+
}
8+
9+
guidMapper.prototype.loadFromFile = function () {
10+
try {
11+
const rawData = fs.readFileSync(this.filePath, 'utf8');
12+
return JSON.parse(rawData);
13+
} catch (error) {
14+
// If file doesn't exist or there's an error parsing it, initialize with an empty object.
15+
return {};
16+
}
17+
};
18+
19+
guidMapper.prototype.writeFileSync = function () {
20+
const jsonData = JSON.stringify(this.data, null, 2);
21+
fs.writeFileSync(this.filePath, jsonData, 'utf8');
22+
};
23+
24+
guidMapper.prototype.addEntry = function (guid, path, name) {
25+
if(!!guid && !! path && !!name){
26+
this.data[guid] = { path: path, name: name };
27+
}
28+
};
29+
30+
guidMapper.prototype.removeEntry = function (guid) {
31+
if (this.data[guid]) {
32+
delete this.data[guid];
33+
}
34+
};
35+
36+
guidMapper.prototype.getEntries = function () {
37+
return this.data;
38+
};
39+
40+
guidMapper.prototype.findEntryGuid = function (name, path) {
41+
for (const guid in this.data) {
42+
if (this.data.hasOwnProperty(guid)) {
43+
const entry = this.data[guid];
44+
if (entry.path === path && entry.name === name) {
45+
return guid;
46+
}
47+
}
48+
}
49+
return null;
50+
};
51+
52+
module.exports = guidMapper;

Diff for: lib/pbxProject.js

+26-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ var util = require('util'),
3535
isEntitlementFileType = constants.isEntitlementFileType,
3636
isAssetFileType = constants.isAssetFileType,
3737
isPlistFileType = constants.isPlistFileType,
38-
isModuleMapFileType = constants.isModuleMapFileType;
38+
isModuleMapFileType = constants.isModuleMapFileType,
39+
guidMapper = require('./guidMapper');
3940

4041
function pbxProject(filename) {
4142
if (!(this instanceof pbxProject))
@@ -74,6 +75,10 @@ pbxProject.prototype.parseSync = function() {
7475
}
7576

7677
pbxProject.prototype.writeSync = function(options) {
78+
if(this.pbxGroupTracker){
79+
this.pbxGroupTracker.writeFileSync();
80+
}
81+
7782
this.writer = new pbxWriter(this.hash, options);
7883
return this.writer.writeSync();
7984
}
@@ -538,10 +543,27 @@ pbxProject.prototype.findMainPbxGroup = function () {
538543

539544
return null;
540545
}
546+
pbxProject.prototype.getPbxGroupTracker = function (path) {
547+
548+
if(!this.pbxGroupTracker){
549+
this.pbxGroupTracker = new guidMapper($path.join(path, '.ns-build-pbxgroup-data.json'));
550+
}
551+
552+
return this.pbxGroupTracker;
553+
}
541554

542555
pbxProject.prototype.addPbxGroup = function (filePathsArray, name, path, sourceTree, opt) {
543556
opt = opt || {};
544557
var srcRootPath = $path.dirname($path.dirname(this.filepath));
558+
559+
var existingGroupId = this.getPbxGroupTracker(srcRootPath).findEntryGuid(name, path);
560+
if(existingGroupId){
561+
if(this.getPBXGroupByKey(existingGroupId)){
562+
this.removePbxGroupByKey(existingGroupId, path);
563+
}
564+
this.pbxGroupTracker.removeEntry(existingGroupId);
565+
}
566+
545567
var groups = this.hash.project.objects['PBXGroup'],
546568
pbxGroupUuid = opt.uuid || this.generateUuid(),
547569
commentKey = f("%s_comment", pbxGroupUuid),
@@ -560,6 +582,9 @@ pbxProject.prototype.addPbxGroup = function (filePathsArray, name, path, sourceT
560582
pbxGroup.path = path;
561583
}
562584

585+
// save to group to the tracker
586+
this.pbxGroupTracker.addEntry(pbxGroupUuid, path, name);
587+
563588
for (var key in fileReferenceSection) {
564589
// only look for comments
565590
if (!COMMENT_KEY.test(key)) continue;

Diff for: test/guidMapper.js

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
var guidMapper = require('../lib/guidMapper');
2+
const fs = require('fs');
3+
const $uuid = require('uuid');
4+
const TEST_FILE_NAME = 'test/.ns-build-pbxgroup-data.json';
5+
const goodGUID = $uuid.v4();
6+
const goodName = "goodName";
7+
const badName = 'badName';
8+
const goodPath = "goodPath";
9+
const badPath = "badPath";
10+
exports.setUp = function(callback) {
11+
if(fs.existsSync(TEST_FILE_NAME)){
12+
fs.rmSync(TEST_FILE_NAME);
13+
}
14+
callback();
15+
}
16+
exports.tearDown = function(callback) {
17+
if(fs.existsSync(TEST_FILE_NAME)){
18+
fs.rmSync(TEST_FILE_NAME);
19+
}
20+
callback();
21+
}
22+
function addTestData(){
23+
var mapper = new guidMapper(TEST_FILE_NAME);
24+
mapper.addEntry(goodGUID, goodPath, goodName);
25+
mapper.writeFileSync();
26+
}
27+
exports.operations = {
28+
'should be able to add to map': function(test) {
29+
var mapper = new guidMapper(TEST_FILE_NAME);
30+
mapper.addEntry(goodGUID, goodPath, goodName);
31+
mapper.writeFileSync();
32+
mapper = new guidMapper(TEST_FILE_NAME);
33+
const result = mapper.findEntryGuid(goodName, goodPath);
34+
35+
test.ok(result === goodGUID)
36+
test.done();
37+
},
38+
'should not match only on name': function(test) {
39+
addTestData();
40+
var mapper = new guidMapper(TEST_FILE_NAME);
41+
42+
const result = mapper.findEntryGuid(goodName, badPath);
43+
44+
test.ok(result === null)
45+
test.done();
46+
},
47+
'should not match only on path': function(test) {
48+
addTestData();
49+
var mapper = new guidMapper(TEST_FILE_NAME);
50+
51+
const result = mapper.findEntryGuid(badName, goodPath);
52+
53+
test.ok(result === null)
54+
test.done();
55+
},
56+
'can remove': function(test) {
57+
addTestData();
58+
var mapper = new guidMapper(TEST_FILE_NAME);
59+
mapper.removeEntry(goodGUID);
60+
var result = mapper.findEntryGuid(goodName, goodPath);
61+
62+
test.ok(result === null);
63+
mapper.writeFileSync();
64+
result = mapper.findEntryGuid(goodName, goodPath);
65+
test.ok(result === null)
66+
67+
test.done();
68+
}
69+
}

Diff for: test/pbxProject.js

+17
Original file line numberDiff line numberDiff line change
@@ -433,3 +433,20 @@ exports['addToPbxFileReferenceSection'] = {
433433
}
434434
}
435435

436+
437+
exports['addPbxGroup'] = {
438+
'should not add the same group twice': function (test) {
439+
var newProj = new pbx('test/parser/projects/group.pbxproj');
440+
newProj.parse(function (err, hash) {
441+
this.hash.project.objects['PBXVariantGroup']={};
442+
var group1 = newProj.addPbxGroup(['test/somefile'], "TestGroup", "test/somepath", null, null);
443+
var group2 = newProj.addPbxGroup(['test/somefile'], "TestGroup", "test/somepath", null, null);
444+
test.equal(newProj.getPBXGroupByKey(group1.uuid), null);
445+
test.equal(newProj.getPBXGroupByKey(group2.uuid).name, "TestGroup");
446+
test.equal(newProj.getPbxGroupTracker().getEntries().hasOwnProperty(group1.uuid), false);
447+
test.equal(newProj.getPbxGroupTracker().getEntries().hasOwnProperty(group2.uuid), true);
448+
449+
test.done();
450+
});
451+
}
452+
}

0 commit comments

Comments
 (0)