Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate binder source from module or service program #2485

Open
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

janfh
Copy link
Contributor

@janfh janfh commented Jan 25, 2025

Fixes #2484

Changes

  • New command and object browser option to generate binder source from module or service program
  • New functions in IBMiContent for retrieving module exports using DSPMOD *OUTFILE and service program exports using the PROGRAM_EXPORT_IMPORT_INFO view
  • Generates binder source in a new editor

How to test this PR

Examples:

  1. Locate a module and a service program in object browser
  2. Right click and select "Generate binder source"
  3. Verify binder source generated in editor

Checklist

  • have tested my change
  • have created one or more test cases
  • updated relevant documentation

@janfh janfh changed the title Feature/binder source Generate binder source from module or service program Jan 25, 2025
@worksofliam
Copy link
Contributor

Honestly I love the idea!

There is some overlap with the FS extension (look up vscode-ibmi-fs on our org), but since it hasn't been released yet and isn't anywhere near being released, I believe it could live here until then.

Thoughts @sebjulliand?

@worksofliam
Copy link
Contributor

@janfh What are the chances you can write new test cases for the new APIs you added? Perhaps against objects in QSYS2?

@janfh
Copy link
Contributor Author

janfh commented Jan 27, 2025

@janfh What are the chances you can write new test cases for the new APIs you added? Perhaps against objects in QSYS2?

Sure :) But I'm not sure if there is any *MODULE to to test "getModuleExport". Do you know of any?

@worksofliam
Copy link
Contributor

@janfh You're right, I don't know of many modules to test with in either QSYS, QSYS2, or SYSTOOLS. If you have to skip one API, that's ok. But if you're feeling adventurous, perhaps your test could create a module with a simple export.

@janfh
Copy link
Contributor Author

janfh commented Jan 27, 2025

@worksofliam : I have added a test for each of the two new methods in IBMiContent

Copy link
Contributor

@worksofliam worksofliam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall a nice change, but sadly I have a test case not passing and also am making a recommendation to the parameter type on your new method.

src/ui/views/objectBrowser.ts Show resolved Hide resolved
src/api/tests/suites/content.test.ts Outdated Show resolved Hide resolved
src/api/tests/suites/content.test.ts Outdated Show resolved Hide resolved
Copy link
Contributor

@worksofliam worksofliam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry - meant to press request changes.

@janfh
Copy link
Contributor Author

janfh commented Jan 28, 2025

Sorry - meant to press request changes.

Thanks for the feedback :)

@janfh janfh requested a review from worksofliam January 28, 2025 16:59
Copy link
Collaborator

@sebjulliand sebjulliand left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice feature, thanks @janfh !
I just have a few style/simplification suggestions related to the code. Thanks!

const config = connection.getConfig();
const tempLib = config!.tempLibrary;
const id: string = `${Tools.makeid().toUpperCase()}`;
const source: string = `/tmp/vscodetemp-${id}.clle`;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest to use connection.withTempDirectory here to handle the creation/cleanup of temporary IFS files (see above). You don't have to bother with DEL afterwards.

Comment on lines +670 to +673
await connection!.runCommand({
command: `DLTMOD MODULE(${tempLib}/${id})`,
environment: 'ile'
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be put in a try/finally{} block, to make sure objects are cleaned up unconditionally.

Comment on lines +706 to +713
await connection!.runCommand({
command: `DLTSRVPGM SRVPGM(${tempLib}/${id})`,
environment: 'ile'
});
await connection!.runCommand({
command: `DLTMOD MODULE(${tempLib}/${id})`,
environment: 'ile'
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be put in a try/finally{} block, to make sure objects are cleaned up unconditionally.

const config = connection.getConfig();
const tempLib = config!.tempLibrary;
const id: string = `${Tools.makeid().toUpperCase()}`;
const source: string = `/tmp/vscodetemp-${id}.clle`;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, try using connection.withTempDirectory for this.

},
{
"command": "code-for-ibmi.generateBinderSource",
"when": "view == objectBrowser && viewItem =~ /^object.(module|srvpgm).*/",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may want to escape the dot here, since you'll be looking at an actual dot (and not any character).

Suggested change
"when": "view == objectBrowser && viewItem =~ /^object.(module|srvpgm).*/",
"when": "view == objectBrowser && viewItem =~ /^object\.(module|srvpgm).*/",

Comment on lines +652 to +664
if (results.length) {
return results.map(result => ({
program_library: result.PROGRAM_LIBRARY,
program_name: result.PROGRAM_NAME,
object_type: result.OBJECT_TYPE,
symbol_name: result.SYMBOL_NAME,
symbol_usage: result.SYMBOL_USAGE,
argument_optimization: result.ARGUMENT_OPTIMIZATION,
data_item_size: result.DATA_ITEM_SIZE
} as ProgramExportImportInfo));
} else {
return [];
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to check the array's length. Directly return the map operation. Map on an empty array is an empty array, so you'll be good anyway.

Suggested change
if (results.length) {
return results.map(result => ({
program_library: result.PROGRAM_LIBRARY,
program_name: result.PROGRAM_NAME,
object_type: result.OBJECT_TYPE,
symbol_name: result.SYMBOL_NAME,
symbol_usage: result.SYMBOL_USAGE,
argument_optimization: result.ARGUMENT_OPTIMIZATION,
data_item_size: result.DATA_ITEM_SIZE
} as ProgramExportImportInfo));
} else {
return [];
}
return results.map(result => ({
program_library: result.PROGRAM_LIBRARY,
program_name: result.PROGRAM_NAME,
object_type: result.OBJECT_TYPE,
symbol_name: result.SYMBOL_NAME,
symbol_usage: result.SYMBOL_USAGE,
argument_optimization: result.ARGUMENT_OPTIMIZATION,
data_item_size: result.DATA_ITEM_SIZE
} as ProgramExportImportInfo));

Comment on lines +681 to +691
if (results.length) {
return results.map(result => ({
module_library: result.MODULE_LIBRARY,
module_name: result.MODULE_NAME,
module_attr: result.MODULE_ATTR,
symbol_name: result.SYMBOL_NAME,
symbol_type: result.SYMBOL_TYPE,
argument_optimization: result.ARGUMENT_OPTIMIZATION
} as ModuleExport));
}
return [];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, return the map directly. Runnin map on an empty array won't hurt.

Comment on lines +185 to +202
export interface ProgramExportImportInfo {
program_library: string,
program_name: string,
object_type: string,
symbol_name: string,
symbol_usage: string,
argument_optimization: string,
data_item_size: number
}

export interface ModuleExport {
module_library: string,
module_name: string,
module_attr: string,
symbol_name: string,
symbol_type: string,
argument_optimization: string,
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer camel case for variable names, to keep it consistent with the others.

Suggested change
export interface ProgramExportImportInfo {
program_library: string,
program_name: string,
object_type: string,
symbol_name: string,
symbol_usage: string,
argument_optimization: string,
data_item_size: number
}
export interface ModuleExport {
module_library: string,
module_name: string,
module_attr: string,
symbol_name: string,
symbol_type: string,
argument_optimization: string,
}
export interface ProgramExportImportInfo {
programLibrary: string
programName: string
objectType: string
symbolName: string
symbolUsage: string
argumentOptimization: string
dataItemSize: number
}
export interface ModuleExport {
moduleLibrary: string
moduleName: string
moduleAttr: string
symbolName: string
symbolType: string
argumentOptimization: string
}

@sebjulliand
Copy link
Collaborator

Honestly I love the idea!

There is some overlap with the FS extension (look up vscode-ibmi-fs on our org), but since it hasn't been released yet and isn't anywhere near being released, I believe it could live here until then.

Thoughts @sebjulliand?

We'll definitely have to keep in mind to move it to FS in due time, since it's really an action targeted at objects 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Generate binder source from module
3 participants