Skip to content

Commit 73acee2

Browse files
authored
Merge pull request #115 from IBM/fix/binder_bob
Improved support for binding directory
2 parents 43b20c9 + 449c62e commit 73acee2

31 files changed

+1238
-23
lines changed

cli/src/builders/bob.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ export class BobProject {
2626
}
2727
}
2828

29+
if (targets.binderRequired()) {
30+
if (target.deps.some(d => d.type === `SRVPGM`)) {
31+
target.deps = target.deps.filter(d => d.type !== `SRVPGM`);
32+
target.deps.push(targets.getBinderTarget());
33+
}
34+
}
35+
2936
if (dirname) {
3037
if (list[dirname] === undefined) list[dirname] = [];
3138

@@ -44,6 +51,20 @@ export class BobProject {
4451

4552
output[`Rules.mk`] = `SUBDIRS = ${subdirs.join(` `)}`;
4653

54+
let bnddirRulesDir: string|undefined = undefined;
55+
56+
if (this.targets.binderRequired()) {
57+
const servicePrograms = this.targets.getResolvedObjects(`SRVPGM`);
58+
const relativePaths = servicePrograms.map(sp => path.dirname(sp.relativePath));
59+
60+
if (relativePaths.length === 1) {
61+
// We know the rules
62+
bnddirRulesDir = relativePaths[0];
63+
} else if (relativePaths.length > 1) {
64+
throw new Error(`All service programs must be in the same directory.`);
65+
}
66+
}
67+
4768
for (const subdir in this.dirTargets) {
4869
const targets = this.dirTargets[subdir];
4970
const currentRulesFile = path.join(subdir, `Rules.mk`);
@@ -60,6 +81,13 @@ export class BobProject {
6081
rulesFile.applyRule(target);
6182
}
6283

84+
if (subdir === bnddirRulesDir) {
85+
rulesFile.applyRule({
86+
...this.targets.getBinderTarget(),
87+
deps: this.targets.getResolvedObjects(`SRVPGM`),
88+
});
89+
}
90+
6391
output[currentRulesFile] = rulesFile.getContent();
6492
}
6593

cli/src/builders/environment.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ export function getObjectType(ext: string): ObjectType {
8484
case `sqlprc`:
8585
case `sqltrg`:
8686
return `PGM`;
87+
88+
case `bnddir`:
89+
return `BNDDIR`;
8790
}
8891

8992
return undefined;

cli/src/builders/make/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ export class MakeProject {
8282
}
8383

8484
public generateHeader(): string[] {
85+
const bindingDirectory = this.targets.getBinderTarget();
86+
8587
let baseBinders = [
8688
...(this.targets.binderRequired() ? [`($(BIN_LIB)/$(APP_BNDDIR))`] : []),
8789
...this.settings.binders.map(b => `(${b})`)
@@ -91,7 +93,7 @@ export class MakeProject {
9193

9294
return [
9395
`BIN_LIB=DEV`,
94-
`APP_BNDDIR=APP`,
96+
`APP_BNDDIR=${this.targets.binderRequired() ? bindingDirectory.systemName : ``}`,
9597
`LIBL=$(BIN_LIB)`,
9698
``,
9799
`INCDIR="${this.settings.includePaths ? this.settings.includePaths.join(`:`) : `.`}"`,
@@ -284,6 +286,10 @@ export class MakeProject {
284286
delete data.parameters.memberCcsid;
285287
}
286288

289+
if (!data.command) {
290+
return [];
291+
}
292+
287293
const resolvedCommand = resolve(toCl(data.command, data.parameters));
288294

289295
lines.push(

cli/src/extensions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export const ddsExtension = [`pf`, `lf`, `dspf`, `prtf`];
55
export const sqlExtensions = [`sql`, `table`, `view`, `index`, `alias`, `sqlprc`, `sqludf`, `sqludt`, `sqltrg`, `sqlalias`, `sqlseq`];
66
export const srvPgmExtensions = [`binder`, `bnd`];
77
export const cmdExtensions = [`cmd`];
8-
export const objectExtensions = [`dtaara`, `mnucmd`, `msgf`, `dtaq`];
8+
export const objectExtensions = [`dtaara`, `mnucmd`, `msgf`, `dtaq`, `bnddir`];
99

1010
export const allExtensions = [...rpgExtensions, ...clExtensions, ...ddsExtension, ...sqlExtensions, ...srvPgmExtensions, ...cmdExtensions, ...objectExtensions];
1111
export const scanGlob = `**/*.{${allExtensions.join(`,`)},${allExtensions.map(e => e.toUpperCase()).join(`,`)}}`;

cli/src/targets.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const sqlTypeExtension = {
3030
'SEQUENCE': `sqlseq`
3131
};
3232

33-
const bindingDirectoryTarget: ILEObject = { systemName: `$(APP_BNDDIR)`, type: `BNDDIR` };
33+
const DEFAULT_BINDER_TARGET: ILEObject = { systemName: `$(APP_BNDDIR)`, type: `BNDDIR` };
3434

3535
const TextRegex = /\%TEXT.*(?=\n|\*)/gm
3636

@@ -102,7 +102,9 @@ export class Targets {
102102
private resolvedObjects: { [localPath: string]: ILEObject } = {};
103103
private resolvedExports: { [name: string]: ILEObject } = {};
104104
private targets: { [name: string]: ILEObjectTarget } = {};
105+
105106
private needsBinder = false;
107+
private projectBindingDirectory = DEFAULT_BINDER_TARGET;
106108

107109
private suggestions: TargetSuggestions = {};
108110

@@ -126,7 +128,7 @@ export class Targets {
126128
}
127129

128130
public getBinderTarget() {
129-
return bindingDirectoryTarget;
131+
return this.projectBindingDirectory;
130132
}
131133

132134
public getRelative(fullPath: string) {
@@ -180,6 +182,10 @@ export class Targets {
180182
}
181183
}
182184

185+
if (type === `BNDDIR`) {
186+
this.projectBindingDirectory = theObject;
187+
}
188+
183189
// This allows us to override the .objrefs if the source actually exists.
184190
if (this.isReferenceObject(theObject, true)) {
185191
this.logger.fileLog(relativePath, {
@@ -1384,7 +1390,7 @@ export class Targets {
13841390

13851391
if (target.deps.length > 0) {
13861392
// Add this new service program to the project binding directory
1387-
this.createOrAppend(bindingDirectoryTarget, target);
1393+
this.createOrAppend(this.projectBindingDirectory, target);
13881394

13891395
// Make sure we can resolve to this service program
13901396
for (const e of target.exports) {

cli/src/utils.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,16 @@ import { CommandParameters } from "./builders/environment";
1010
import { ReadFileSystem } from "./readFileSystem";
1111

1212
export function getSystemNameFromPath(inputName: string) {
13+
const isTest = inputName.toUpperCase().endsWith(`.TEST`);
1314
let baseName = inputName.includes(`-`) ? inputName.split(`-`)[0] : inputName;
1415

16+
if (isTest) {
17+
// Remove the .TEST part
18+
baseName = baseName.substring(0, baseName.length - 5);
19+
}
20+
1521
// If the name is of valid length, return it
16-
if (baseName.length <= 10) {
22+
if (baseName.length <= 10 && !isTest) {
1723
return baseName.toUpperCase();
1824
}
1925

@@ -27,8 +33,9 @@ export function getSystemNameFromPath(inputName: string) {
2733
name = parts[1];
2834
}
2935

30-
if (baseName.toUpperCase().endsWith(`.TEST`)) {
31-
name = name.substring(0, name.length - 5);
36+
if (isTest) {
37+
prefix = `T`;
38+
name = name.toUpperCase();
3239
}
3340

3441
// We start the system name with the suppliedPrefix

cli/test/cs_srvpgm.test.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { MakeProject } from '../src/builders/make';
55
import { setupFixture } from './fixtures/projects';
66
import { ReadFileSystem } from '../src/readFileSystem';
77
import { BobProject } from '../src/builders/bob';
8+
import path from 'path';
89

910
describe(`pseudo tests`, () => {
1011
const project = setupFixture(`cs_srvpgm`);
@@ -25,14 +26,15 @@ describe(`pseudo tests`, () => {
2526

2627
test(`That test files are understood`, () => {
2728
expect(targets).toBeDefined();
29+
expect(targets.binderRequired()).toBeFalsy();
2830

29-
const testModule = targets.getTarget({systemName: `EMPTEST`, type: `MODULE`});
31+
const testModule = targets.getTarget({systemName: `TEMPTEST`, type: `MODULE`});
3032
expect(testModule).toBeDefined();
3133

3234
expect(testModule.deps.length).toBe(3);
3335
expect(testModule.deps.find(f => f.systemName === `EMPLOYEE`)).toBeDefined();
3436
expect(testModule.deps.find(f => f.systemName === `DEPARTMENT`)).toBeDefined();
35-
expect(testModule.deps.find(f => f.systemName === `EMPDET`)).toBeDefined();
37+
expect(testModule.deps.find(f => f.systemName === `EMPDET` && f.type === `MODULE`)).toBeDefined();
3638
});
3739

3840
test('Deps are picked up for the module', () => {
@@ -61,11 +63,11 @@ describe(`pseudo tests`, () => {
6163
expect(files[`Rules.mk`]).toBeDefined();
6264
expect(files[`Rules.mk`]).toBe(`SUBDIRS = qddssrc qrpglesrc qtestsrc`);
6365

64-
expect(files[`qtestsrc/Rules.mk`]).toBe(`EMPTEST.MODULE: emptest.test.sqlrpgle qrpgleref/empdet.rpgleinc EMPLOYEE.FILE DEPARTMENT.FILE EMPDET.MODULE`)
65-
66-
console.log(files[`qrpglesrc/Rules.mk`]);
67-
expect(files[`qrpglesrc/Rules.mk`]).toContain(`EMPLOYEES.MODULE: employees.pgm.sqlrpgle qrpgleref/constants.rpgleinc qrpgleref/empdet.rpgleinc`);
68-
expect(files[`qrpglesrc/Rules.mk`]).toContain(`EMPLOYEES.PGM: EMPLOYEE.FILE EMPS.FILE EMPDET.MODULE EMPLOYEES.MODULE`);
66+
expect(files[path.join(`qtestsrc`, `Rules.mk`)]).toBe(`TEMPTEST.MODULE: emptest.test.sqlrpgle qrpgleref/empdet.rpgleinc EMPLOYEE.FILE DEPARTMENT.FILE EMPDET.MODULE`)
67+
68+
expect(files[path.join(`qrpglesrc`, `Rules.mk`)]).toContain(`EMPLOYEES.MODULE: employees.pgm.sqlrpgle qrpgleref/constants.rpgleinc qrpgleref/empdet.rpgleinc`);
69+
expect(files[path.join(`qrpglesrc`, `Rules.mk`)]).toContain(`EMPLOYEES.PGM: EMPLOYEE.FILE EMPS.FILE EMPDET.MODULE EMPLOYEES.MODULE`);
70+
expect(files[path.join(`qrpglesrc`, `Rules.mk`)]).not.toContain(`EMPDET.SRVPGM`); // Ensure no service program is created
6971
});
7072

7173
test('makefile', () => {
@@ -75,5 +77,8 @@ describe(`pseudo tests`, () => {
7577

7678
expect(contents).toContain(`$(PREPATH)/EMPLOYEES.PGM:`);
7779
expect(contents).toContain(`system "CRTPGM PGM($(BIN_LIB)/EMPLOYEES) ENTMOD(EMPLOYEES) MODULE(EMPDET EMPLOYEES) TGTRLS(*CURRENT) BNDDIR($(BNDDIR)) ACTGRP(*NEW)" > .logs/employees.splf`);
80+
81+
expect(contents).not.toContain(`EMPDET.SRVPGM`); // Ensure no service program is created
82+
expect(contents).toContain(`EMPDET.MODULE`);
7883
});
7984
});

cli/test/cs_with_bnddir.test.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { beforeAll, describe, expect, test } from 'vitest';
2+
3+
import { Targets } from '../src/targets'
4+
import { MakeProject } from '../src/builders/make';
5+
import { setupFixture } from './fixtures/projects';
6+
import { ReadFileSystem } from '../src/readFileSystem';
7+
import { BobProject } from '../src/builders/bob';
8+
import path from 'path';
9+
10+
describe(`pseudo tests`, () => {
11+
const project = setupFixture(`cs_with_bnddir`);
12+
13+
const fs = new ReadFileSystem();
14+
const targets = new Targets(project.cwd, fs);
15+
let make: MakeProject;
16+
17+
beforeAll(async () => {
18+
project.setup();
19+
await targets.loadProject();
20+
21+
expect(targets.getTargets().length).toBeGreaterThan(0);
22+
targets.resolveBinder();
23+
24+
make = new MakeProject(project.cwd, targets);
25+
});
26+
27+
test(`That test files are understood`, () => {
28+
expect(targets).toBeDefined();
29+
expect(targets.binderRequired()).toBeTruthy();
30+
31+
const testModule = targets.getTarget({systemName: `TEMPDETT`, type: `MODULE`});
32+
expect(testModule).toBeDefined();
33+
34+
expect(testModule.deps.length).toBe(3);
35+
expect(testModule.deps.find(f => f.systemName === `EMPLOYEE`)).toBeDefined();
36+
expect(testModule.deps.find(f => f.systemName === `DEPARTMENT`)).toBeDefined();
37+
expect(testModule.deps.find(f => f.systemName === `EMPDET` && f.type === `SRVPGM`)).toBeDefined();
38+
});
39+
40+
test('Deps are picked up for the module', () => {
41+
const empdet = targets.getTarget({systemName: `EMPDET`, type: `MODULE`});
42+
expect(empdet).toBeDefined();
43+
44+
expect(empdet.deps.length).toBe(2);
45+
expect(empdet.deps.find(f => f.systemName === `EMPLOYEE`)).toBeDefined();
46+
expect(empdet.deps.find(f => f.systemName === `DEPARTMENT`)).toBeDefined();
47+
48+
const employees = targets.getTarget({systemName: `EMPLOYEES`, type: `PGM`});
49+
expect(employees).toBeDefined();
50+
51+
expect(employees.deps.length).toBe(3);
52+
expect(employees.deps.find(f => f.systemName === `EMPDET` && f.type === `SRVPGM`)).toBeDefined();
53+
expect(employees.deps.find(f => f.systemName === `EMPS` && f.type === `FILE`)).toBeDefined();
54+
expect(employees.deps.find(f => f.systemName === `EMPLOYEE` && f.type === `FILE`)).toBeDefined();
55+
});
56+
57+
test('makefile', () => {
58+
const makefile = new MakeProject(targets.getCwd(), targets);
59+
60+
const contents = makefile.getMakefile().join(`\n`);
61+
62+
expect(contents).toContain(`APP_BNDDIR=APP\n`);
63+
expect(contents).toContain(`BNDDIR=($(BIN_LIB)/$(APP_BNDDIR))\n`);
64+
65+
expect(contents).toContain(`$(PREPATH)/EMPLOYEES.PGM: $(PREPATH)/EMPLOYEE.FILE $(PREPATH)/EMPS.FILE $(PREPATH)/EMPDET.SRVPGM`);
66+
expect(contents).toContain(`system "CRTSQLRPGI OBJ($(BIN_LIB)/EMPLOYEES) SRCSTMF('qrpglesrc/employees.pgm.sqlrpgle') COMMIT(*NONE) DBGVIEW(*SOURCE) OPTION(*EVENTF) RPGPPOPT(*LVL2) COMPILEOPT('TGTCCSID(*JOB) BNDDIR($(BNDDIR)) DFTACTGRP(*no)')"`);
67+
68+
expect(contents).toContain(`$(PREPATH)/APP.BNDDIR: $(PREPATH)/EMPDET.SRVPGM`);
69+
expect(contents).toContain(`$(PREPATH)/EMPDET.SRVPGM: $(PREPATH)/EMPDET.MODULE`);
70+
});
71+
72+
test('ibmi-bob rules', () => {
73+
const bobProject = new BobProject(targets);
74+
75+
const files = bobProject.createRules();
76+
77+
expect(files[`Rules.mk`]).toBeDefined();
78+
expect(files[`Rules.mk`]).toBe(`SUBDIRS = qddssrc qrpglesrc qsqlsrc qtestsrc`);
79+
80+
expect(files[path.join(`qtestsrc`,`Rules.mk`)]).toBe(`TEMPDETT.MODULE: empdett.test.sqlrpgle qrpgleref/empdet.rpgleinc EMPLOYEE.FILE DEPARTMENT.FILE APP.BNDDIR`)
81+
82+
expect(files[path.join(`qrpglesrc`,`Rules.mk`)]).toContain(`EMPDET.MODULE: empdet.sqlrpgle qrpgleref/empdet.rpgleinc EMPLOYEE.FILE DEPARTMENT.FILE`);
83+
expect(files[path.join(`qrpglesrc`,`Rules.mk`)]).toContain(`EMPDET.SRVPGM: empdet.bnd EMPDET.MODULE`);
84+
expect(files[path.join(`qrpglesrc`,`Rules.mk`)]).toContain(`EMPLOYEES.PGM: employees.pgm.sqlrpgle qrpgleref/constants.rpgleinc qrpgleref/empdet.rpgleinc EMPLOYEE.FILE EMPS.FILE APP.BNDDIR`);
85+
expect(files[path.join(`qrpglesrc`,`Rules.mk`)]).toContain(`APP.BNDDIR: app.bnddir EMPDET.SRVPGM`);
86+
});
87+
});

cli/test/fixtures/cs_srvpgm/qrpglesrc/app.bnddir

Lines changed: 0 additions & 2 deletions
This file was deleted.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
DEPTS.FILE: depts.dspf
2+
EMPS.FILE: emps.dspf
3+
NEMP.FILE: nemp.dspf

0 commit comments

Comments
 (0)