Skip to content

Commit 0160728

Browse files
edrioukCopilotbrondani
authored
* Update only layer files relevant for context * Fix the problem, add tests and correct tests * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Update test-data/solutions/simple/project.cproject.yml Co-authored-by: Daniel Brondani <daniel.brondani@arm.com> --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Daniel Brondani <daniel.brondani@arm.com>
1 parent 5d54514 commit 0160728

17 files changed

Lines changed: 388 additions & 63 deletions

src/solutions/csolution.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ describe('CSolution', () => {
7777
loadResult = await csolution.load(fileName);
7878
expect(loadResult).toEqual(ETextFileResult.Unchanged);
7979
expect(csolution.solutionPath).toEqual(fileName);
80-
expect(csolution.cbuildIdxYmlRoot?.getChild()).toEqual(undefined);
81-
expect(csolution.cbuildYmlRoot.size).toEqual(0);
80+
expect(csolution.cbuildIdxYmlRoot?.getChild()).toBeDefined();
81+
expect(csolution.cbuildYmlRoot.size).toEqual(1);
8282

8383
const content = csolution.csolutionYml.text.trim(); // avoid whitespace noise
8484
expect(content).toContain('projects');

src/solutions/csolution.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,12 @@ export class CSolution {
449449
return this.clayerYmlRoot.get(absPath);
450450
}
451451

452+
public getClayersForContext(context?: string): CTreeItem[] {
453+
const cbuild = this.getCbuildTop(context);
454+
return (cbuild?.getRoot().getProperty('clayers') as CTreeItem[] | undefined) ?? [];
455+
}
456+
457+
452458
/**
453459
* Returns first child of cproject.yml file for specified cbuild item
454460
* @param cbuild cbuild item (first child of cbuild.yml file)

src/solutions/edit/project-file-updater.test.ts

Lines changed: 131 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,28 @@ describe('ProjectFileUpdaterImpl', () => {
3030
let testProject: string;
3131
let testSolution: string;
3232
let testLayer: string;
33+
let testProject1: string;
34+
let testProject2: string;
35+
let testLayer1: string;
36+
let testLayer2: string;
37+
let csolution: CSolution;
3338
let usedItems: UsedItems;
3439
const solutionManager: MockSolutionManager = solutionManagerFactory();
3540
const testDataHandler = new TestDataHandler();
3641
let tmpSolutionDir: string;
42+
const contextDebug = 'project.Debug+TEST_TARGET';
43+
const contextDebug1 = 'project1.Debug+TEST_TARGET';
44+
const contextRelease = 'project.Release+TEST_TARGET';
3745

3846
beforeAll(() => {
3947
tmpSolutionDir = testDataHandler.copyTestDataToTmp('solutions');
4048
testSolution = path.join(tmpSolutionDir, 'simple', 'test.csolution.yml');
4149
testProject = path.join(tmpSolutionDir, 'simple', 'project.cproject.yml');
4250
testLayer = path.join(tmpSolutionDir, 'simple', 'Board.clayer.yml');
51+
testProject1 = path.join(tmpSolutionDir, 'multi-project', 'project1', 'project1.cproject.yml');
52+
testProject2 = path.join(tmpSolutionDir, 'multi-project', 'project2', 'project2.cproject.yml');
53+
testLayer1 = path.join(tmpSolutionDir, 'multi-project', 'project1', 'Board.clayer.yml');
54+
testLayer2 = path.join(tmpSolutionDir, 'multi-project', 'project2', 'Board.clayer.yml');
4355
});
4456

4557
afterAll(async () => {
@@ -48,8 +60,7 @@ describe('ProjectFileUpdaterImpl', () => {
4860

4961

5062
beforeEach(() => {
51-
const MockCSolution = CSolution as jest.MockedClass<typeof CSolution>;
52-
const csolution = new MockCSolution();
63+
csolution = new CSolution();
5364
solutionManager.getCsolution.mockReturnValue(csolution as CSolution);
5465
csolution.clayerYmlRoot = new Map();
5566

@@ -88,7 +99,7 @@ describe('ProjectFileUpdaterImpl', () => {
8899
};
89100

90101
const updater = new ProjectFileUpdaterImpl(solutionManager);
91-
let result = await updater.updateUsedItems('Debug', testProject, usedItems);
102+
let result = await updater.updateUsedItems(contextDebug, testProject, usedItems);
92103
expect(result).toBe(true);
93104

94105
// Reload and check file content
@@ -126,7 +137,7 @@ describe('ProjectFileUpdaterImpl', () => {
126137
]
127138
};
128139

129-
result = await updater.updateUsedItems('Debug', testProject, usedItems);
140+
result = await updater.updateUsedItems(contextDebug, testProject, usedItems);
130141
expect(result).toBe(true);
131142

132143
await ymlFile.load(testProject);
@@ -147,17 +158,17 @@ describe('ProjectFileUpdaterImpl', () => {
147158
expect(pack).toBeDefined();
148159

149160
// modify component to be context specific and save the file
150-
c!.setValue('for-context', 'Release');
161+
c!.setValue('for-context', contextRelease);
151162
c!.setValue('instances', '2');
152-
pack?.setValue('not-for-context', 'Debug');
163+
pack?.setValue('not-for-context', contextDebug);
153164
const saveResult = await ymlFile.save();
154165
expect(saveResult).toEqual(ETextFileResult.Success);
155166

156167
// update again to see if component and pack is added
157168
usedItems.components[0].options = { explicitVersion: '@>=10.4.0' };
158169
usedItems.packs[0].pack = 'Keil::CMSIS-FreeRTOS@^10.4.7';
159170

160-
result = await updater.updateUsedItems('Debug', testProject, usedItems);
171+
result = await updater.updateUsedItems(contextDebug, testProject, usedItems);
161172
expect(result).toBe(true);
162173
await ymlFile.load(testProject);
163174
top = ymlFile.topItem;
@@ -171,7 +182,7 @@ describe('ProjectFileUpdaterImpl', () => {
171182
c = components?.getChildByValue('component', 'ARM::CMSIS:RTOS2:FreeRTOS@>=10.4.0');
172183
expect(components?.indexOfChild(c)).toBe(1);
173184
expect(c?.getValue('instances')).toBe('3');
174-
expect(c?.getValue('for-context')).toEqual('Debug');
185+
expect(c?.getValue('for-context')).toEqual(contextDebug);
175186

176187
packs = top?.getChild('packs');
177188
expect(packs).toBeDefined();
@@ -186,7 +197,7 @@ describe('ProjectFileUpdaterImpl', () => {
186197
// clear all debug
187198
usedItems = { success: true, components: [], packs: [] };
188199

189-
result = await updater.updateUsedItems('Debug', testProject, usedItems);
200+
result = await updater.updateUsedItems(contextDebug, testProject, usedItems);
190201
expect(result).toBe(true);
191202
await ymlFile.load(testProject);
192203
top = ymlFile.topItem;
@@ -220,7 +231,7 @@ describe('ProjectFileUpdaterImpl', () => {
220231
{ pack: 'Keil::CMSIS-FreeRTOS', origin: testProject, selected: true }
221232
]
222233
};
223-
result = await updater.updateUsedItems('Release', testProject, usedItems);
234+
result = await updater.updateUsedItems(contextRelease, testProject, usedItems);
224235
expect(result).toBe(true);
225236
await ymlFile.load(testProject);
226237
top = ymlFile.topItem;
@@ -233,7 +244,7 @@ describe('ProjectFileUpdaterImpl', () => {
233244

234245
// try to use explicit version without @ prefix
235246
usedItems.components[0].options = { explicitVersion: '^10.4.0' };
236-
result = await updater.updateUsedItems('Release', testProject, usedItems);
247+
result = await updater.updateUsedItems(contextRelease, testProject, usedItems);
237248
expect(result).toBe(true);
238249
await ymlFile.load(testProject);
239250
top = ymlFile.topItem;
@@ -244,7 +255,7 @@ describe('ProjectFileUpdaterImpl', () => {
244255

245256
// clear all Release
246257
usedItems = { success: true, components: [], packs: [] };
247-
result = await updater.updateUsedItems('Release', testProject, usedItems);
258+
result = await updater.updateUsedItems(contextRelease, testProject, usedItems);
248259
expect(result).toBe(true);
249260
await ymlFile.load(testProject);
250261
top = ymlFile.topItem;
@@ -270,31 +281,23 @@ describe('ProjectFileUpdaterImpl', () => {
270281
]
271282
};
272283

273-
const ymlFile = new CTreeItemYamlFile();
274-
await ymlFile.load(testSolution);
275-
let top = ymlFile.topItem;
284+
// load solution
285+
await csolution.load(testSolution);
286+
287+
let top = csolution.csolutionYml.topItem;
276288
expect(top).toBeDefined();
277289
let packs = top!.getChild('packs');
278290
expect(packs).toBeDefined();
279291
expect(packs?.getChildren().length).toBe(1); // packs are written to all files
280292
let pack = packs?.getChildByValue('pack', 'ARM::RteTest_DFP');
281293
expect(pack).toBeDefined();
282294

283-
284-
// add layer information
285-
const csolution = solutionManager.getCsolution();
286-
csolution!.solutionPath = testSolution;
287-
csolution!.solutionDir = path.dirname(testSolution);
288-
csolution!.clayerYmlRoot = new Map([
289-
[testLayer, new CTreeItem()],
290-
['dummy.cgen.yml', new CTreeItem()]
291-
]);
292-
293295
const updater = new ProjectFileUpdaterImpl(solutionManager);
294-
let result = await updater.updateUsedItems('Debug', testProject, usedItems);
296+
let result = await updater.updateUsedItems(contextDebug, testProject, usedItems);
295297
expect(result).toBe(true);
296298

297299
// Reload and check file content
300+
const ymlFile = new CTreeItemYamlFile();
298301
await ymlFile.load(testSolution);
299302
top = ymlFile.topItem;
300303
expect(top).toBeDefined();
@@ -327,7 +330,7 @@ describe('ProjectFileUpdaterImpl', () => {
327330
// Modify usedItems, now add component to project
328331
usedItems.components.push({ id: 'CMSIS:CORE', selectedCount: 1 });
329332

330-
result = await updater.updateUsedItems('Debug', testProject, usedItems);
333+
result = await updater.updateUsedItems(contextDebug, testProject, usedItems);
331334
expect(result).toBe(true);
332335

333336
await ymlFile.load(testProject);
@@ -363,7 +366,7 @@ describe('ProjectFileUpdaterImpl', () => {
363366
// move component to a layer
364367
usedItems.components[2].options = { layer: testLayer };
365368
usedItems.packs[2].origin = testLayer;
366-
result = await updater.updateUsedItems('Debug', testProject, usedItems);
369+
result = await updater.updateUsedItems(contextDebug, testProject, usedItems);
367370
expect(result).toBe(true);
368371
await ymlFile.load(testProject);
369372
top = ymlFile.topItem;
@@ -396,9 +399,10 @@ describe('ProjectFileUpdaterImpl', () => {
396399
expect(pack).toBeDefined();
397400

398401

399-
// clear all Release: no context specific components => project, solution and layer are cleared
402+
// clear all Debug: no context specific components => project, solution and layer are cleared
400403
usedItems = { success: true, components: [], packs: [] };
401-
result = await updater.updateUsedItems('Release', testProject, usedItems);
404+
405+
result = await updater.updateUsedItems(contextDebug, testProject, usedItems);
402406
expect(result).toBe(true);
403407
await ymlFile.load(testProject);
404408
top = ymlFile.topItem;
@@ -420,6 +424,103 @@ describe('ProjectFileUpdaterImpl', () => {
420424
expect(packs).toBeUndefined();
421425
});
422426

427+
it('updates first project and its layer in multi-project solution', async () => {
428+
const multiProjectDir = path.join(tmpSolutionDir, 'multi-project');
429+
const multiSolution = path.join(multiProjectDir, 'test.csolution.yml');
430+
const project2File = new CTreeItemYamlFile(testProject2);
431+
const layer2File = new CTreeItemYamlFile(testLayer2);
432+
let unchangedResult = await project2File.load();
433+
expect(unchangedResult).toBe(ETextFileResult.Success);
434+
unchangedResult = await layer2File.load();
435+
expect(unchangedResult).toBe(ETextFileResult.Success);
436+
437+
await csolution.load(multiSolution);
438+
csolution.clayerYmlRoot = new Map([
439+
[testLayer1, new CTreeItem()],
440+
[testLayer2, new CTreeItem()],
441+
]);
442+
443+
usedItems = {
444+
success: true,
445+
components: [
446+
{ id: 'CMSIS:CORE', selectedCount: 1 },
447+
{ id: 'ARM::CMSIS-Compiler:CORE', selectedCount: 2, options: { layer: testLayer1, explicitVendor: true } },
448+
],
449+
packs: [
450+
{ pack: 'ARM::RteTest_DFP', origin: multiSolution, selected: true },
451+
{ pack: 'MY::DummyPack', origin: multiSolution, selected: true, path: './my/dummy/pack' },
452+
{ pack: 'Keil::CMSIS-FreeRTOS@>=10.4.6', origin: testProject1, selected: true },
453+
{ pack: 'ARM::CMSIS-Compiler@2.0.0', origin: testLayer1, selected: true },
454+
]
455+
};
456+
457+
const updater = new ProjectFileUpdaterImpl(solutionManager);
458+
const result = await updater.updateUsedItems(contextDebug1, testProject1, usedItems);
459+
expect(result).toBe(true);
460+
461+
const ymlFile = new CTreeItemYamlFile();
462+
await ymlFile.load(multiSolution);
463+
let top = ymlFile.topItem;
464+
expect(top).toBeDefined();
465+
466+
let packs = top!.getChild('packs');
467+
expect(packs).toBeDefined();
468+
expect(packs!.getChildren().length).toBe(2);
469+
expect(packs!.getChildByValue('pack', 'ARM::RteTest_DFP')).toBeDefined();
470+
expect(packs!.getChildByValue('pack', 'MY::DummyPack')?.getValue('path')).toEqual('my/dummy/pack');
471+
472+
await ymlFile.load(testProject1);
473+
top = ymlFile.topItem;
474+
expect(top).toBeDefined();
475+
let components = top!.getChild('components');
476+
expect(components).toBeDefined();
477+
expect(components!.getChildren().length).toBe(1);
478+
expect(components!.getChildByValue('component', 'CMSIS:CORE')).toBeDefined();
479+
packs = top!.getChild('packs');
480+
expect(packs).toBeDefined();
481+
expect(packs!.getChildren().length).toBe(1);
482+
expect(packs!.getChildByValue('pack', 'Keil::CMSIS-FreeRTOS@>=10.4.6')).toBeDefined();
483+
484+
await ymlFile.load(testLayer1);
485+
top = ymlFile.topItem;
486+
expect(top).toBeDefined();
487+
components = top!.getChild('components');
488+
expect(components).toBeDefined();
489+
expect(components!.getChildren().length).toBe(1);
490+
expect(components!.getChildByValue('component', 'ARM::CMSIS-Compiler:CORE')).toBeDefined();
491+
packs = top!.getChild('packs');
492+
expect(packs).toBeDefined();
493+
expect(packs!.getChildren().length).toBe(1);
494+
expect(packs!.getChildByValue('pack', 'ARM::CMSIS-Compiler@2.0.0')).toBeDefined();
495+
496+
unchangedResult = await project2File.load();
497+
expect(unchangedResult).toBe(ETextFileResult.Unchanged);
498+
unchangedResult = await layer2File.load();
499+
expect(unchangedResult).toBe(ETextFileResult.Unchanged);
500+
501+
await ymlFile.load(testProject2);
502+
top = ymlFile.topItem;
503+
expect(top).toBeDefined();
504+
components = top!.getChild('components');
505+
expect(components).toBeDefined();
506+
expect(components!.getChildren().length).toBe(1);
507+
expect(components!.getChildByValue('component', 'CORE')).toBeDefined();
508+
packs = top!.getChild('packs');
509+
expect(packs).toBeUndefined();
510+
511+
await ymlFile.load(testLayer2);
512+
top = ymlFile.topItem;
513+
expect(top).toBeDefined();
514+
components = top!.getChild('components');
515+
expect(components).toBeDefined();
516+
expect(components!.getChildren().length).toBe(1);
517+
expect(components!.getChildByValue('component', 'CMSIS:RTOS2:FreeRTOS')).toBeDefined();
518+
packs = top!.getChild('packs');
519+
expect(packs).toBeDefined();
520+
expect(packs!.getChildren().length).toBe(1);
521+
expect(packs!.getChildByValue('pack', 'Keil::CMSIS-FreeRTOS@>=10.4.0')).toBeDefined();
522+
});
523+
423524

424525
it('returns false if save fails', async () => {
425526
// Patch CTreeItemYamlFile.save to simulate failure

0 commit comments

Comments
 (0)