Skip to content

Commit

Permalink
Merge pull request #1695 from codefori/feature/autoBashrc
Browse files Browse the repository at this point in the history
Add /QOpenSys/pkgs/bin to .bashrc if needed
  • Loading branch information
sebjulliand authored Dec 12, 2023
2 parents f1b4f05 + 60a29c0 commit 92c91f7
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 37 deletions.
143 changes: 107 additions & 36 deletions src/api/IBMi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ export default class IBMi {
progress.report({
message: `Connecting via SSH.`
});
const delayedOperations: Function[] = [];

await this.client.connect(connectionObject as node_ssh.Config);

Expand Down Expand Up @@ -239,17 +240,17 @@ export default class IBMi {
// But, remember, but we only got here if 'cd $HOME' failed.
// Let's try to figure out why....
if (0 !== (await this.sendCommand({ command: `test -d ${actualHomeDir}` })).code) {
await vscode.window.showWarningMessage(`Your home directory (${actualHomeDir}) is not a directory! Code for IBM i may not function correctly. Please contact your system administrator`, { modal: !reconnecting });
await vscode.window.showWarningMessage(`Your home directory (${actualHomeDir}) is not a directory! Code for IBM i may not function correctly. Please contact your system administrator.`, { modal: !reconnecting });
}
else if (0 !== (await this.sendCommand({ command: `test -w ${actualHomeDir}` })).code) {
await vscode.window.showWarningMessage(`Your home directory (${actualHomeDir}) is not writable! Code for IBM i may not function correctly. Please contact your system administrator`, { modal: !reconnecting });
await vscode.window.showWarningMessage(`Your home directory (${actualHomeDir}) is not writable! Code for IBM i may not function correctly. Please contact your system administrator.`, { modal: !reconnecting });
}
else if (0 !== (await this.sendCommand({ command: `test -x ${actualHomeDir}` })).code) {
await vscode.window.showWarningMessage(`Your home directory (${actualHomeDir}) is not usable due to permissions! Code for IBM i may not function correctly. Please contact your system administrator`, { modal: !reconnecting });
await vscode.window.showWarningMessage(`Your home directory (${actualHomeDir}) is not usable due to permissions! Code for IBM i may not function correctly. Please contact your system administrator.`, { modal: !reconnecting });
}
else {
// not sure, but get your sys admin involved
await vscode.window.showWarningMessage(`Your home directory (${actualHomeDir}) exists but is unusable. Code for IBM i may not function correctly. Please contact your system administrator`, { modal: !reconnecting });
await vscode.window.showWarningMessage(`Your home directory (${actualHomeDir}) exists but is unusable. Code for IBM i may not function correctly. Please contact your system administrator.`, { modal: !reconnecting });
}
}
else if (reconnecting) {
Expand All @@ -259,7 +260,7 @@ export default class IBMi {
modal: true,
detail: `Your home directory (${actualHomeDir}) does not exist, so Code for IBM i may not function correctly. Would you like to create this directory now?`,
}, `Yes`)) {
console.log(`creating home directory ${actualHomeDir}`);
this.appendOutput(`creating home directory ${actualHomeDir}`);
let mkHomeCmd = `mkdir -p ${actualHomeDir} && chown ${connectionObject.username.toLowerCase()} ${actualHomeDir} && chmod 0755 ${actualHomeDir}`;
let mkHomeResult = await this.sendCommand({ command: mkHomeCmd, directory: `.` });
if (0 === mkHomeResult.code) {
Expand All @@ -268,7 +269,7 @@ export default class IBMi {
let mkHomeErrs = mkHomeResult.stderr;
// We still get 'Could not chdir to home directory' in stderr so we need to hackily gut that out, as well as the bashisms that are a side effect of our API
mkHomeErrs = mkHomeErrs.substring(1 + mkHomeErrs.indexOf(`\n`)).replace(`bash: line 1: `, ``);
await vscode.window.showWarningMessage(`Error creating home directory (${actualHomeDir}):\n${mkHomeErrs}.\n\n Code for IBM i may not function correctly. Please contact your system administrator`, { modal: true });
await vscode.window.showWarningMessage(`Error creating home directory (${actualHomeDir}):\n${mkHomeErrs}.\n\n Code for IBM i may not function correctly. Please contact your system administrator.`, { modal: true });
}
}
}
Expand Down Expand Up @@ -692,47 +693,115 @@ export default class IBMi {
}
}

// Check users default shell.
// give user option to set bash as default shell.
try {
// make sure chsh and bash is installed
if (this.remoteFeatures[`chsh`] &&
this.remoteFeatures[`bash`]) {

// give user option to set bash as default shell.
if (this.remoteFeatures[`bash`]) {
try {
//check users default shell
const bashShellPath = '/QOpenSys/pkgs/bin/bash';
const commandShellResult = await this.sendCommand({
command: `echo $SHELL`
});

if (!commandShellResult.stderr) {
let userDefaultShell = commandShellResult.stdout.trim();
if (userDefaultShell !== bashShellPath) {

vscode.window.showInformationMessage(`IBM recommends using bash as your default shell.`, `Set shell to bash`, `Read More`,).then(async choice => {
switch (choice) {
case `Set shell to bash`:
const commandSetBashResult = await this.sendCommand({
command: `/QOpenSys/pkgs/bin/chsh -s /QOpenSys/pkgs/bin/bash`
});

if (!commandSetBashResult.stderr) {
vscode.window.showInformationMessage(`Shell is now bash! Reconnect for change to take effect.`);
} else {
vscode.window.showInformationMessage(`Default shell WAS NOT changed to bash.`);
}
break;
let usesBash = commandShellResult.stdout.trim() === bashShellPath;
if (!usesBash) {
// make sure chsh is installed
if (this.remoteFeatures[`chsh`]) {
vscode.window.showInformationMessage(`IBM recommends using bash as your default shell.`, `Set shell to bash`, `Read More`,).then(async choice => {
switch (choice) {
case `Set shell to bash`:
const commandSetBashResult = await this.sendCommand({
command: `/QOpenSys/pkgs/bin/chsh -s /QOpenSys/pkgs/bin/bash`
});

if (!commandSetBashResult.stderr) {
vscode.window.showInformationMessage(`Shell is now bash! Reconnect for change to take effect.`);
usesBash = true;
} else {
vscode.window.showInformationMessage(`Default shell WAS NOT changed to bash.`);
}
break;

case `Read More`:
vscode.env.openExternal(vscode.Uri.parse(`https://ibmi-oss-docs.readthedocs.io/en/latest/user_setup/README.html#step-4-change-your-default-shell-to-bash`));
break;
}
});
}
}

case `Read More`:
vscode.env.openExternal(vscode.Uri.parse(`https://ibmi-oss-docs.readthedocs.io/en/latest/user_setup/README.html#step-4-change-your-default-shell-to-bash`));
break;
}
if (usesBash) {
//Ensure /QOpenSys/pkgs/bin is found in $PATH
progress.report({
message: `Checking /QOpenSys/pkgs/bin in $PATH.`
});

if ((!quickConnect || !cachedServerSettings?.pathChecked)) {
const currentPaths = (await this.sendCommand({ command: "echo $PATH" })).stdout.split(":");
const bashrcFile = `${defaultHomeDir}/.bashrc`;
let bashrcExists = (await this.sendCommand({ command: `test -e ${bashrcFile}` })).code === 0;
let reason;
if(!currentPaths.includes("/QOpenSys/pkgs/bin")){
reason = "Your $PATH shell environment variable does not include /QOpenSys/pkgs/bin";
}
else if (currentPaths.indexOf("/QOpenSys/pkgs/bin") > currentPaths.indexOf("/usr/bin") || currentPaths.indexOf("/QOpenSys/pkgs/bin") > currentPaths.indexOf("/QOpenSys/usr/bin")){
reason = "/QOpenSys/pkgs/bin is not in the right position in your $PATH shell environment variable";
}
if (reason && await vscode.window.showWarningMessage(`/QOpenSys/pkgs/bin not found in $PATH`, {
modal: true,
detail: `${reason}, so Code for IBM i may not function correctly. Would you like to ${bashrcExists ? "update" : "create"} ${bashrcFile} to fix this now?`,
}, `Yes`)) {
delayedOperations.push(async () => {
this.appendOutput(`${bashrcExists ? "update" : "create"} ${bashrcFile}`);
if (!bashrcExists) {
const createBashrc = await this.sendCommand({ command: `echo "# Generated by Code for IBM i\nexport PATH=/QOpenSys/pkgs/bin:\\$PATH" >> ${bashrcFile} && chown ${connectionObject.username.toLowerCase()} ${bashrcFile} && chmod 755 ${bashrcFile}` });
if (createBashrc.code !== 0) {
await vscode.window.showWarningMessage(`Error creating ${bashrcFile}):\n${createBashrc.stderr}.\n\n Code for IBM i may not function correctly. Please contact your system administrator.`, { modal: true });
}
}
else {
try {
const content = instance.getContent();
if (content) {
const bashrcContent = (await content.downloadStreamfile(bashrcFile)).split("\n");
let replaced = false;
bashrcContent.forEach((line, index) => {
if (!replaced) {
const pathRegex = /^((?:export )?PATH=)(.*)(?:)$/.exec(line);
if (pathRegex) {
bashrcContent[index] = `${pathRegex[1]}/QOpenSys/pkgs/bin:${pathRegex[2]
.replace("/QOpenSys/pkgs/bin", "") //Removes /QOpenSys/pkgs/bin wherever it is
.replace("::", ":")}`; //Removes double : in case /QOpenSys/pkgs/bin wasn't at the end
replaced = true;
}
}
});

if (!replaced) {
bashrcContent.push(
"",
"# Generated by Code for IBM i",
"export PATH=/QOpenSys/pkgs/bin:$PATH"
);
}

await content.writeStreamfile(bashrcFile, bashrcContent.join("\n"));
}
}
catch (error) {
await vscode.window.showWarningMessage(`Error modifying PATH in ${bashrcFile}):\n${error}.\n\n Code for IBM i may not function correctly. Please contact your system administrator.`, { modal: true });
}
}
});
}
}
}
}
} catch (e) {
// Oh well...trying to set default shell is not worth stopping for.
console.log(e);
}
} catch (e) {
// Oh well...trying to set default shell is not worth stopping for.
console.log(e);
}

if (this.config.autoConvertIFSccsid) {
Expand Down Expand Up @@ -801,6 +870,7 @@ export default class IBMi {
if (!reconnecting) {
vscode.workspace.getConfiguration().update(`workbench.editor.enablePreview`, false, true);
await vscode.commands.executeCommand(`setContext`, `code-for-ibmi:connected`, true);
delayedOperations.forEach(func => func());
instance.fire("connected");
}

Expand All @@ -814,7 +884,8 @@ export default class IBMi {
local: this.variantChars.local,
},
badDataAreasChecked: true,
libraryListValidated: true
libraryListValidated: true,
pathChecked: true
});

return {
Expand Down
3 changes: 2 additions & 1 deletion src/api/Storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ export type CachedServerSettings = {
remoteFeaturesKeys: string | null;
variantChars: { american: string, local: string };
badDataAreasChecked: boolean | null,
libraryListValidated: boolean | null
libraryListValidated: boolean | null,
pathChecked?: boolean
} | undefined;

export class GlobalStorage extends Storage {
Expand Down

0 comments on commit 92c91f7

Please sign in to comment.