diff --git a/.gitignore b/.gitignore index 79a9498..3a47d02 100644 --- a/.gitignore +++ b/.gitignore @@ -16,5 +16,4 @@ __pycache__ htmlcov # --- Odev plugins, loaded as submodules -odev/plugins/* tests/plugins/* diff --git a/README.md b/README.md index 6e33156..54bacbd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # ODEV - VSCode Editor -Configure VSCode for a database and open a repository in the editor. +Configure VSCode (or any editor derived from it, e.g. VSCodium or Antigravity) for a database and open a repository +in the editor. ## Installation @@ -12,3 +13,12 @@ Enable this plugin by running: ```bash odev plugin --enable odoo-odev/odev-plugin-editor-vscode ``` + +Using other editors sharing the same base (e.g. VSCodium) should work as well, at the cost of setting up a symlink +to the editor executable in your path. + +Antigravity example: + +```bash +ln -s $(which antigravity) /usr/local/bin/code +``` diff --git a/__manifest__.py b/__manifest__.py index bec5f51..032f27d 100644 --- a/__manifest__.py +++ b/__manifest__.py @@ -22,7 +22,7 @@ # or merged change. # ------------------------------------------------------------------------------ -__version__ = "2.0.0" +__version__ = "2.1.0" # --- Dependencies ------------------------------------------------------------- # List other odev plugins from which this current plugin depends. diff --git a/common/editor_vscode.py b/common/editor_vscode.py index dbff100..09712e8 100644 --- a/common/editor_vscode.py +++ b/common/editor_vscode.py @@ -4,10 +4,11 @@ from jinja2 import Environment, FileSystemLoader -from odev.common import progress, string +from odev.common import bash, progress, string from odev.common.databases import LocalDatabase from odev.common.errors import OdevError from odev.common.logging import logging +from odev.common.odoobin import OdoobinProcess from odev.common.python import PythonEnv from odev.plugins.odev_plugin_editor_base.common.editor import Editor @@ -22,9 +23,19 @@ class VSCodeEditor(Editor): _name = "code" _display_name = "VSCode" + @property + def display_name(self) -> str: + """Also handle other editors derived from VSCode/VSCodium (e.g. Antigravity).""" + name = bash.execute(f"{self._name} --help | head -n 1 | awk '{{print $1}}'") + + if name and name.stdout.strip(): + return name.stdout.strip().capitalize().decode() + + return self._display_name + @property def command(self) -> str: - if isinstance(self.database, LocalDatabase): + if isinstance(self.database, LocalDatabase) or self.version: return f"{self._name} {self.workspace_path}" raise OdevError("Database doesn't exist") @@ -37,12 +48,15 @@ def templates(self) -> Environment: @property def workspace_directory(self) -> Path: """The path to the workspace directory.""" - return self.path / ".vscode" + if isinstance(self.database, LocalDatabase): + return self.path / ".vscode" + return self.path @property def workspace_path(self) -> Path: """The path to the workspace file.""" - return self.workspace_directory / f"{self.database.name}.code-workspace" + name = self.database.name if isinstance(self.database, LocalDatabase) else str(self.version) + return self.workspace_directory / f"{name}.code-workspace" @property def launch_path(self) -> Path: @@ -55,29 +69,37 @@ def tasks_path(self) -> Path: return self.workspace_directory / "tasks.json" def configure(self): - """Configure VSCode to work with the database.""" - if not isinstance(self.database, LocalDatabase): - return logger.warning( - f"No local database associated with repository {self.git.name!r}, skipping VSCode configuration" - ) - - with progress.spinner(f"Configuring {self._display_name} for project {self.git.name!r}"): - self.workspace_directory.mkdir(parents=True, exist_ok=True) - - self._create_workspace() - self._create_launch() - self._create_tasks() - self._create_jsconfig() - - created_files = string.join_bullet( - [ - f"Workspace: {self.workspace_path}", - f"Launch: {self.launch_path}", - f"Tasks: {self.tasks_path}", - ], - ) - logger.info(f"Created VSCode config for project {self.git.name!r}\n{created_files}") - return None + """Configure VSCode to work with the database, or to browse a bare Odoo version.""" + if isinstance(self.database, LocalDatabase): + with progress.spinner(f"Configuring {self.display_name} for project {self.git.name!r}"): + self.workspace_directory.mkdir(parents=True, exist_ok=True) + + self._create_workspace() + self._create_launch() + self._create_tasks() + self._create_jsconfig() + + created_files = string.join_bullet( + [ + f"Workspace: {self.workspace_path}", + f"Launch: {self.launch_path}", + f"Tasks: {self.tasks_path}", + ], + ) + logger.info(f"Created {self.display_name} config for project {self.git.name!r}\n{created_files}") + return None + + if self.version: + with progress.spinner(f"Configuring {self.display_name} workspace for Odoo {self.version}"): + self.workspace_directory.mkdir(parents=True, exist_ok=True) + self._create_version_workspace() + logger.info(f"Created {self.display_name} workspace for Odoo {self.version}\n Workspace: {self.workspace_path}") + return None + + return logger.warning( + f"No local database associated with repository {self.git.name!r}, " + f"skipping {self.display_name} configuration" + ) def _get_rendered_template(self, template_name, **kwargs): template = self.templates.get_template(template_name) @@ -96,6 +118,18 @@ def _create_workspace(self): with open(self.workspace_path, "w", encoding="utf-8") as f: f.write(rendered_template) + def _create_version_workspace(self): + """Create a workspace listing the Odoo worktrees (odoo, enterprise, design-themes) for the version.""" + process = OdoobinProcess(self.database, version=self.version).with_edition("enterprise") + + worktrees = list(process.odoo_worktrees) + if len(worktrees) < len(list(process.odoo_repositories)): + process.update_worktrees() + worktrees = list(process.odoo_worktrees) + + folders = [{"path": worktree.path.as_posix(), "name": worktree.path.name} for worktree in worktrees] + self.workspace_path.write_text(json.dumps({"folders": folders}, indent=4)) + def _create_launch(self): """Create a launch file for the project.""" rendered_template = self._get_rendered_template("launch.jinja")