Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 97 additions & 76 deletions src/iproject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -463,113 +463,134 @@ export class IProject {

/**
* Run the project's build, build object, or compile command.
* Return type includes success, output, and error to ensure callers can handle failures properly (e.g., external tools)
*
* @param isBuild True for build command and false for compile command.
* @param fileUri The file uri to compile or `undefined` for builds.
* @param object The specific object to build.
*/
public async runBuildOrCompileCommand(isBuild: boolean, fileUri?: Uri, object?: string) {
public async runBuildOrCompileCommand(isBuild: boolean, fileUri?: Uri, object?: string): Promise<{ success: boolean, output: string[], error?: string } | undefined> {
const unresolvedState = await this.getUnresolvedState();

if (unresolvedState) {
let rawCommand: string | undefined;
let commandWithVariableSubstitution: string | undefined;
if (isBuild) {
if (object) {
rawCommand = unresolvedState.buildObjectCommand;
if (!unresolvedState) {
return { success: false, output: [], error: 'No iproj.json found' }; // Return error details for proper error reporting
}

// Handle special case for build object command where {object} should be replaced by object name
commandWithVariableSubstitution = rawCommand?.replace(new RegExp('{object}', `g`), object);
} else {
rawCommand = unresolvedState.buildCommand;
}
let rawCommand: string | undefined;
let commandWithVariableSubstitution: string | undefined;
if (isBuild) {
if (object) {
rawCommand = unresolvedState.buildObjectCommand;

// Handle special case for build object command where {object} should be replaced by object name
commandWithVariableSubstitution = rawCommand?.replace(new RegExp('{object}', `g`), object);
} else {
rawCommand = unresolvedState.compileCommand;
rawCommand = unresolvedState.buildCommand;
}
} else {
rawCommand = unresolvedState.compileCommand;
}

if (rawCommand) {
const directoryUris = ['.logs', '.evfevent'].map(dir => Uri.file(path.join(this.workspaceFolder.uri.fsPath, dir)));
for await (const uri of directoryUris) {
try {
await workspace.fs.stat(uri);

// Clear directory if it does exist
const files = await workspace.fs.readDirectory(uri);
for (const [fileName] of files) {
const fileUri = Uri.joinPath(uri, fileName);
await workspace.fs.delete(fileUri, { recursive: true });
}
} catch {
// Create directory if it does not exist
await workspace.fs.createDirectory(uri);
}
}
if (!rawCommand) {
const commandType = isBuild ? (object ? 'build object command' : 'build command') : 'compile command';
return { success: false, output: [], error: `${commandType} not set` }; // Return error details for proper error reporting
}

const action: Action = {
name: rawCommand,
command: commandWithVariableSubstitution || rawCommand,
environment: `pase`,
extensions: [`GLOBAL`],
deployFirst: true,
type: `file`,
postDownload: [
".logs",
".evfevent"
]
};
await commands.executeCommand(`code-for-ibmi.runAction`, { resourceUri: fileUri ? fileUri : this.workspaceFolder.uri }, undefined, action, this.deploymentMethod);
ProjectManager.fire({ type: isBuild ? 'build' : 'compile', iProject: this });
const directoryUris = ['.logs', '.evfevent'].map(dir => Uri.file(path.join(this.workspaceFolder.uri.fsPath, dir)));
for await (const uri of directoryUris) {
try {
await workspace.fs.stat(uri);

// Clear directory if it does exist
const files = await workspace.fs.readDirectory(uri);
for (const [fileName] of files) {
const fileUri = Uri.joinPath(uri, fileName);
await workspace.fs.delete(fileUri, { recursive: true });
}
} catch {
// Create directory if it does not exist
await workspace.fs.createDirectory(uri);
}
}

const action: Action = {
name: rawCommand,
command: commandWithVariableSubstitution || rawCommand,
environment: `pase`,
extensions: [`GLOBAL`],
deployFirst: true,
type: `file`,
postDownload: [
".logs",
".evfevent"
]
};
const result = await commands.executeCommand<{ success: boolean, output: string[], error?: string }>(`code-for-ibmi.runAction`, { resourceUri: fileUri ? fileUri : this.workspaceFolder.uri }, undefined, action, this.deploymentMethod);
ProjectManager.fire({ type: isBuild ? 'build' : 'compile', iProject: this });

if (!result) {
return { success: false, output: [], error: 'Action execution failed' }; // Return error details for proper error reporting
}

// Return structured result with success status, output, and error message for proper error handling
return {
success: result.success,
output: result.output,
error: result.success ? undefined : (result.error || `${isBuild ? 'Build' : 'Compile'} failed`)
};
}
/**
* Run the project's build, build object, or compile command. If no command
* is specified, prompt for it and then run the provided command.
* Return type includes success, output, and error to ensure callers can handle failures properly (e.g., external tools)
*
* @param isBuild True for build command and false for compile command.
* @param fileUri The file uri to compile or `undefined` for builds.
* @param object The specific object to build.
*/
public async runBuildOrCompileCommandWithPrompt(isBuild: boolean, fileUri?: Uri, object?: string) {
public async runBuildOrCompileCommandWithPrompt(isBuild: boolean, fileUri?: Uri, object?: string): Promise<{ success: boolean, output: string[], error?: string } | undefined> {
let unresolvedState = await this.getUnresolvedState();

if (unresolvedState) {
let command: string | undefined;
let unsetCommandParams: { errorMessage: string, option: string, setCommand: string };
if (isBuild) {
if (object) {
command = unresolvedState.buildObjectCommand;
unsetCommandParams = {
errorMessage: l10n.t('Project\'s build object command not set'),
option: l10n.t('Set Build Object Command'),
setCommand: `vscode-ibmi-projectexplorer.projectExplorer.setBuildObjectCommand`,
};
} else {
command = unresolvedState.buildCommand;
unsetCommandParams = {
errorMessage: l10n.t('Project\'s build command not set'),
option: l10n.t('Set Build Command'),
setCommand: `vscode-ibmi-projectexplorer.projectExplorer.setBuildCommand`
};
}
if (!unresolvedState) {
return { success: false, output: [], error: 'No iproj.json found' }; // Return error details for proper error reporting
}

let command: string | undefined;
let unsetCommandParams: { errorMessage: string, option: string, setCommand: string };
if (isBuild) {
if (object) {
command = unresolvedState.buildObjectCommand;
unsetCommandParams = {
errorMessage: l10n.t('Project\'s build object command not set'),
option: l10n.t('Set Build Object Command'),
setCommand: `vscode-ibmi-projectexplorer.projectExplorer.setBuildObjectCommand`,
};
} else {
command = unresolvedState.compileCommand;
command = unresolvedState.buildCommand;
unsetCommandParams = {
errorMessage: l10n.t('Project\'s compile command not set'),
option: l10n.t('Set Compile Command'),
setCommand: `vscode-ibmi-projectexplorer.projectExplorer.setCompileCommand`
errorMessage: l10n.t('Project\'s build command not set'),
option: l10n.t('Set Build Command'),
setCommand: `vscode-ibmi-projectexplorer.projectExplorer.setBuildCommand`
};
}
} else {
command = unresolvedState.compileCommand;
unsetCommandParams = {
errorMessage: l10n.t('Project\'s compile command not set'),
option: l10n.t('Set Compile Command'),
setCommand: `vscode-ibmi-projectexplorer.projectExplorer.setCompileCommand`
};
}

if (!command) {
const selection = await window.showErrorMessage(unsetCommandParams.errorMessage, unsetCommandParams.option);
if (selection === unsetCommandParams.option) {
await commands.executeCommand(unsetCommandParams.setCommand, this);
this.runBuildOrCompileCommand(isBuild, fileUri, object);
}
} else {
this.runBuildOrCompileCommand(isBuild, fileUri, object);
if (!command) {
const selection = await window.showErrorMessage(unsetCommandParams.errorMessage, unsetCommandParams.option);
if (selection === unsetCommandParams.option) {
await commands.executeCommand(unsetCommandParams.setCommand, this);
return await this.runBuildOrCompileCommand(isBuild, fileUri, object);
}
return { success: false, output: [], error: unsetCommandParams.errorMessage }; // Return error details for proper error reporting
} else {
return await this.runBuildOrCompileCommand(isBuild, fileUri, object);
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/views/projectExplorer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export default class ProjectExplorer implements TreeDataProvider<ProjectExplorer
}

if (iProject) {
iProject.runBuildOrCompileCommandWithPrompt(true);
return await iProject.runBuildOrCompileCommandWithPrompt(true);
} else {
window.showErrorMessage(l10n.t('Failed to retrieve project'));
}
Expand Down Expand Up @@ -153,7 +153,7 @@ export default class ProjectExplorer implements TreeDataProvider<ProjectExplorer
const iProject = element.workspaceFolder ? ProjectManager.get(element.workspaceFolder) : undefined;

if (iProject) {
iProject.runBuildOrCompileCommandWithPrompt(true, undefined, element.label?.toString());
return await iProject.runBuildOrCompileCommandWithPrompt(true, undefined, element.label?.toString());
} else {
window.showErrorMessage(l10n.t('Failed to retrieve project'));
}
Expand Down Expand Up @@ -212,7 +212,7 @@ export default class ProjectExplorer implements TreeDataProvider<ProjectExplorer
}

if (iProject) {
iProject.runBuildOrCompileCommandWithPrompt(false, element);
return await iProject.runBuildOrCompileCommandWithPrompt(false, element);
} else {
window.showErrorMessage(l10n.t('Failed to retrieve project'));
}
Expand Down