Skip to content

Commit

Permalink
[IMP] vscode: allow Odoo extension to work standalone and with vscode…
Browse files Browse the repository at this point in the history
… python extension

Changes:
- check if python extension is ready and save it in global
- display python path in config when relevant
- check and prepare the environment without python extension
  • Loading branch information
Louciole committed Dec 18, 2023
1 parent becfd7d commit f687c6d
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 15 deletions.
1 change: 0 additions & 1 deletion server/core/odoo.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,6 @@ def reload_database(ls):
Odoo.get().reset(ls)
FileMgr.files = {}
ls.show_message_log("Building new database", MessageType.Log)
ls.show_message("Reloading Odoo database", MessageType.Info)
ls.launch_thread(target=Odoo.initialize, args=(ls,))


Expand Down
2 changes: 1 addition & 1 deletion vscode/client/common/python.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export interface IInterpreterDetails {
resource?: Uri;
}

const onDidChangePythonInterpreterEvent = new EventEmitter<IInterpreterDetails>();
export const onDidChangePythonInterpreterEvent = new EventEmitter<IInterpreterDetails>();
export const onDidChangePythonInterpreter: Event<IInterpreterDetails> = onDidChangePythonInterpreterEvent.event;

let _api: PythonExtension | undefined;
Expand Down
96 changes: 87 additions & 9 deletions vscode/client/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,16 @@ import {
ConfigurationsChange,
clientStopped
} from './common/events'
import { IInterpreterDetails, getInterpreterDetails, initializePython, onDidChangePythonInterpreter } from "./common/python";
import {
IInterpreterDetails,
getInterpreterDetails,
initializePython,
onDidChangePythonInterpreter,
onDidChangePythonInterpreterEvent
} from "./common/python";
import { getCurrentConfig } from "./common/utils";
import { getConfigurationStructure, stateInit } from "./common/validation";
import { execSync } from "child_process";


function getClientOptions(): LanguageClientOptions {
Expand Down Expand Up @@ -221,8 +228,9 @@ async function addNewConfiguration(context: ExtensionContext) {
}

async function changeSelectedConfig(context: ExtensionContext, configId: Number) {
const oldConfig = await getCurrentConfig(context)
await context.workspaceState.update("Odoo.selectedConfiguration", configId);
selectedConfigurationChange.fire(null);
selectedConfigurationChange.fire(oldConfig);
}

async function displayCrashMessage(context: ExtensionContext, crashInfo: string, command: string = null, outputChannel = global.LSCLIENT.outputChannel) {
Expand Down Expand Up @@ -253,8 +261,23 @@ async function displayCrashMessage(context: ExtensionContext, crashInfo: string,
async function initLanguageServerClient(context: ExtensionContext, outputChannel: OutputChannel, autoStart = false) {
let client = global.LSCLIENT;
try {
const interpreter = await getInterpreterDetails();
const pythonPath = interpreter.path[0];
let pythonPath: string;

try{
//trying to use the VScode python extension
const interpreter = await getInterpreterDetails();
pythonPath = interpreter.path[0];
global.IS_PYTHON_EXTENSION_READY = true;

}catch{
global.IS_PYTHON_EXTENSION_READY = false;
//python extension is not available switch to standalone mode
pythonPath = await getStandalonePythonPath(context);
await checkStandalonePythonVersion(context)
}
outputChannel.appendLine("[INFO] Python VS code extension is ".concat(global.IS_PYTHON_EXTENSION_READY ? "ready" : "not ready"));



if (context.extensionMode === ExtensionMode.Development) {
// Development - Run the server manually
Expand Down Expand Up @@ -394,14 +417,21 @@ async function initializeSubscriptions(context: ExtensionContext): Promise<void>

// Listen to changes to Configurations
context.subscriptions.push(
ConfigurationsChange.event(async (changes: Array<String> | null) => {
ConfigurationsChange.event(async (changes: Array<string> | null) => {
try {
let client = global.LSCLIENT;
await setStatusConfig(context);
if (changes && (changes.includes('odooPath') || changes.includes('addons'))) {
const RELOAD_ON_CHANGE = ["odooPath","addons","pythonPath"];
if (changes && (changes.some(r=> RELOAD_ON_CHANGE.includes(r)))) {
await checkOdooPath(context);
await checkAddons(context);
if (client.diagnostics) client.diagnostics.clear();

if (changes.includes('pythonPath')){
await checkStandalonePythonVersion(context);
onDidChangePythonInterpreterEvent.fire(changes["pythonPath"]);
return
}
await client.sendNotification("Odoo/configurationChanged");
}
}
Expand All @@ -414,7 +444,7 @@ async function initializeSubscriptions(context: ExtensionContext): Promise<void>

// Listen to changes to the selected Configuration
context.subscriptions.push(
selectedConfigurationChange.event(async () => {
selectedConfigurationChange.event(async (oldConfig) => {
try {
if (!global.CAN_QUEUE_CONFIG_CHANGE) return;

Expand All @@ -425,9 +455,18 @@ async function initializeSubscriptions(context: ExtensionContext): Promise<void>
}

let client = global.LSCLIENT;
if (await getCurrentConfig(context)) {
const config = await getCurrentConfig(context)
if (config) {
await checkOdooPath(context);
await checkAddons(context);
if (!global.IS_PYTHON_EXTENSION_READY){
await checkStandalonePythonVersion(context);
if (!oldConfig || config["pythonPath"] != oldConfig["pythonPath"]){
onDidChangePythonInterpreterEvent.fire(config["pythonPath"]);
await setStatusConfig(context);
return
}
}
if (!client) {
global.LSCLIENT = await initLanguageServerClient(context, global.OUTPUT_CHANNEL);
client = global.LSCLIENT;
Expand Down Expand Up @@ -606,6 +645,7 @@ async function initializeSubscriptions(context: ExtensionContext): Promise<void>
}
}


export async function activate(context: ExtensionContext): Promise<void> {
try {
global.CAN_QUEUE_CONFIG_CHANGE = true;
Expand All @@ -616,7 +656,9 @@ export async function activate(context: ExtensionContext): Promise<void> {
setMissingStateVariables(context);
validateState(context);

await initializePython(context.subscriptions);
if (global.IS_PYTHON_EXTENSION_READY){
await initializePython(context.subscriptions);
}
await initStatusBar(context);
await initializeSubscriptions(context);

Expand Down Expand Up @@ -681,3 +723,39 @@ export async function deactivate(): Promise<void> {
return global.LSCLIENT.dispose();
}
}

async function getStandalonePythonPath(context: ExtensionContext) {
const config = await getCurrentConfig(context);
const pythonPath = config && config["pythonPath"] ? config["pythonPath"] : "python3";
return pythonPath
}

async function checkStandalonePythonVersion(context: ExtensionContext): Promise<boolean>{
const currentConfig = await getCurrentConfig(context);
if (!currentConfig){
return
}

const pythonPath = currentConfig["pythonPath"]
if (!pythonPath) {
OUTPUT_CHANNEL.appendLine("[INFO] pythonPath is not set, defaulting to python3.");
}

const versionString = execSync(`${pythonPath} --version`).toString().replace("Python ", "")
const pythonVersion = semver.parse(versionString)
if (semver.lt(pythonVersion, "3.8.0")) {
window.showErrorMessage(
`You must use python 3.8 or newer. Would you like to change it?`,
"Update current configuration",
"Ignore"
).then(selection => {
switch (selection) {
case ("Update current configuration"):
ConfigurationWebView.render(context, currentConfig.id);
break
}
});
return false
}
return true
}
3 changes: 2 additions & 1 deletion vscode/client/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ declare global {
var DEBUG_FILE: string;
var CLIENT_IS_STOPPING: boolean;
var CAN_QUEUE_CONFIG_CHANGE: boolean;
}
var IS_PYTHON_EXTENSION_READY: boolean;
}
21 changes: 21 additions & 0 deletions vscode/client/views/configurations/configurationWebView.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,27 @@ <h1>Odoo Configuration</h1>
<% } %>
</vscode-form-helper>
</vscode-form-group>
<% if (!pythonExtensionMode) { %>
<vscode-form-group variant="vertical">
<vscode-label for="config-python-path-textfield">
Python path
</vscode-label>
<vscode-textfield id="config-python-path-textfield" value="<%= config.pythonPath %>" placeholder="Path to the python executable">
<vscode-icon
label="Open Python path"
title="Open Python path"
slot="content-after"
name="folder-opened"
id="config-python-path-button"
action-icon
>
</vscode-icon>
</vscode-textfield>
<vscode-form-helper id="config-path-helper">
<p>Path to the Python binary the Language Server will run on.</p>
</vscode-form-helper>
</vscode-form-group>
<% } %>
<vscode-form-group id="config-addons" variant="vertical">
<vscode-label for="addons-scrollable" side-aligned="end">Additional addons</vscode-label>
<vscode-scrollable id="addons-scrollable">
Expand Down
14 changes: 14 additions & 0 deletions vscode/client/views/configurations/configurationWebView.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ window.addEventListener("message", event => {
pathField.focus();
pathField.setAttribute("value", message.path);
break
case "update_python_path":
const pythonPathField = document.getElementById('config-python-path-textfield');
pythonPathField.focus();
pythonPathField.setAttribute("value", message.pythonPath);
break
case "update_config_folder_validity":
const pathHelper = document.getElementById('config-path-helper');
if (message.version) {
Expand All @@ -28,12 +33,14 @@ function main() {
const addFolderButton = document.getElementById('add-folder-button');
const pathTextfield = document.getElementById('config-path-textfield');
const pathButton = document.getElementById('config-path-button');
const pythonPathButton = document.getElementById('config-python-path-button');
const saveButton = document.getElementById('save-button');
const deleteButton = document.getElementById('delete-button');

addFolderButton.addEventListener("click", addFolderClick);
pathTextfield.addEventListener("vsc-change", updateVersion);
pathButton.addEventListener('vsc-click', openOdooFolder);
pythonPathButton.addEventListener('vsc-click', openPythonPath);
saveButton.addEventListener('click', saveConfig);
deleteButton.addEventListener('click', deleteConfig);

Expand All @@ -50,6 +57,13 @@ function saveConfig() {
name: document.getElementById("config-name-textfield").value,
odooPath: document.getElementById("config-path-textfield").value,
addons: getAddons(),
pythonPath: document.getElementById("config-python-path-textfield").value,
});
}

function openPythonPath() {
vscode.postMessage({
command: "open_python_path"
});
}

Expand Down
32 changes: 29 additions & 3 deletions vscode/client/views/configurations/configurationWebView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ export class ConfigurationWebView {
config: config,
cspSource: webview.cspSource,
nonce: nonce,
odooVersion: configsVersion ? configsVersion[`${this.configId}`] : null
odooVersion: configsVersion ? configsVersion[`${this.configId}`] : null,
pythonExtensionMode: global.IS_PYTHON_EXTENSION_READY,
};
return ejs.render(htmlFile, data);
}
Expand All @@ -138,7 +139,7 @@ export class ConfigurationWebView {
panel.title = `Odoo: ${title}`
}

private _saveConfig(configs: any, odooPath: string, name: string, addons: Array<String>): void {
private _saveConfig(configs: any, odooPath: string, name: string, addons: Array<String>, pythonPath: string = "python3"): void {
let changes = [];
let oldAddons = configs[this.configId]["addons"]

Expand All @@ -150,6 +151,10 @@ export class ConfigurationWebView {
changes.push("name");
}

if (configs[this.configId]["pythonPath"] != pythonPath) {
changes.push("pythonPath");
}

if (oldAddons.length != addons.length) {
changes.push("addons");
} else {
Expand All @@ -168,6 +173,7 @@ export class ConfigurationWebView {
"name": name,
"odooPath": untildify(odooPath),
"addons": addons,
"pythonPath": untildify(pythonPath),
};
this._context.globalState.update("Odoo.configurations", configs);
if (this._context.workspaceState.get("Odoo.selectedConfiguration") == this.configId) {
Expand Down Expand Up @@ -202,7 +208,8 @@ export class ConfigurationWebView {
const odooPath = message.odooPath;
const name = message.name;
const addons = message.addons;
this._saveConfig(configs, odooPath, name, addons);
const pythonPath = message.pythonPath;
this._saveConfig(configs, odooPath, name, addons, pythonPath);
break;
case "view_ready":
webview.postMessage({
Expand Down Expand Up @@ -257,6 +264,25 @@ export class ConfigurationWebView {
case "update_version":
this._getOdooVersion(message.odooPath, webview);
break;
case "open_python_path":
const pythonPathOptions: vscode.OpenDialogOptions = {
title: "Add Python path",
openLabel: 'Add path',
canSelectMany: false,
canSelectFiles: false,
canSelectFolders: false,
};
window.showOpenDialog(pythonPathOptions).then(fileUri => {
if (fileUri && fileUri[0]) {
let config = configs[this.configId];
const odooPythonPath = fileUri[0].fsPath;
webview.postMessage({
command: "update_python_path",
pythonPath: odooPythonPath
});
}
});
break;
}
},
undefined,
Expand Down

0 comments on commit f687c6d

Please sign in to comment.