diff --git a/README.md b/README.md index e830d08..157bea9 100644 --- a/README.md +++ b/README.md @@ -87,11 +87,7 @@ versions = ["16.0", "17.0", "18.0"] [tools] uv = ["odoo-venv", "odoo-addons-path", "pre-commit"] npm = ["prettier", "eslint"] -system_packages = ["git", "postgresql", "pnpm"] - -[[tools.script]] -url = "https://astral.sh/uv/install.sh" -name = "uv installer" +system_packages = ["git", "postgresql"] [repos] odoo = ["odoo", "enterprise"] diff --git a/bootstrap.sh b/bootstrap.sh index a45acf5..05a9ff7 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -9,6 +9,13 @@ export PATH="$HOME/.local/bin:$PATH" echo "=== Bootstrap trobz_local ===" +# Check not running as root +if [ "$(id -u)" -eq 0 ]; then + echo "Error: Do not run this script as root." + echo "Please run as a regular user with sudo access." + exit 1 +fi + # Check if user can sudo check_sudo() { if ! sudo -v &>/dev/null; then diff --git a/docs/codebase-summary.md b/docs/codebase-summary.md index 3955101..c9707f0 100644 --- a/docs/codebase-summary.md +++ b/docs/codebase-summary.md @@ -52,7 +52,7 @@ Technical overview of the `trobz_local` codebase structure, implementation patte 1. **PostgreSQL Repository Setup**: Idempotent APT repo configuration with GPG verification (Debian/Ubuntu) 2. **Scripts**: Download via wget/curl, execute with /bin/sh 3. **System Packages**: OS-aware (apt-get, pacman, brew) with platform defaults -4. **NPM Packages**: Global via pnpm install -g +4. **NPM Packages**: Global via npm install -g 5. **UV Tools**: Global via uv tool install **Key Functions**: diff --git a/docs/project-overview-pdr.md b/docs/project-overview-pdr.md index c81387e..9432841 100644 --- a/docs/project-overview-pdr.md +++ b/docs/project-overview-pdr.md @@ -67,7 +67,7 @@ Five-stage installation pipeline: 1. **PostgreSQL Repository** (Debian/Ubuntu only): Setup PGDG APT repository with GPG verification (idempotent) 2. **Shell Scripts**: Download and execute scripts (e.g., uv installer) 3. **System Packages**: OS-aware installation via apt/pacman/brew (runs after PostgreSQL repo setup on Debian/Ubuntu) -4. **NPM Packages**: Global packages via pnpm +4. **NPM Packages**: Global packages via npm 5. **UV Tools**: Python tools via uv tool install ### 4. Virtual Environment Management (`create-venvs`) @@ -138,11 +138,7 @@ versions = ["16.0", "17.0", "18.0"] [tools] uv = ["odoo-venv", "odoo-addons-path", "pre-commit"] npm = ["prettier", "eslint"] -system_packages = ["git", "postgresql", "pnpm"] - -[[tools.script]] -url = "https://astral.sh/uv/install.sh" -name = "uv installer" +system_packages = ["git", "postgresql"] [repos] odoo = ["odoo", "enterprise"] @@ -166,7 +162,7 @@ UV tools to install globally via `uv tool install` - **Examples**: `["odoo-venv", "pre-commit", "black[d]>=24.0"]` #### `tools.npm` (Optional) -NPM packages to install globally via pnpm +NPM packages to install globally via npm - **Type**: List of strings - **Pattern**: `^(@[a-z0-9-~][a-z0-9-._~]*/)?[a-z0-9-~][a-z0-9-._~]*$` - **Supports**: Scoped (@org/package) and unscoped packages @@ -181,8 +177,8 @@ Shell scripts to download and execute - **Example**: ```toml [[tools.script]] - url = "https://astral.sh/uv/install.sh" - name = "uv installer" + url = "https://example.com/install.sh" + name = "my installer" ``` #### `tools.system_packages` (Optional) @@ -310,7 +306,7 @@ Install tools from five sources in order: PostgreSQL repo, scripts, system packa 1. **PostgreSQL Repository** (Debian/Ubuntu): Setup PGDG APT repository with GPG verification 2. **Scripts**: Download and execute via `wget` or `curl`, then `sh` 3. **System Packages**: OS-aware installation (apt/pacman/brew) - runs after PostgreSQL repo on Debian/Ubuntu -4. **NPM Packages**: Global installation via `pnpm install -g` +4. **NPM Packages**: Global installation via `npm install -g` 5. **UV Tools**: Global installation via `uv tool install` **Behavior**: diff --git a/docs/system-architecture.md b/docs/system-architecture.md index a524f61..2713bcc 100644 --- a/docs/system-architecture.md +++ b/docs/system-architecture.md @@ -186,8 +186,8 @@ install-tools command │ └─ Return success/failure boolean │ │ 4. install_npm_packages() - │ ├─ Check if pnpm exists - │ └─ Parallel: run_tasks() with pnpm install -g + │ ├─ Check if npm exists + │ └─ Parallel: run_tasks() with npm install -g │ │ 5. install_uv_tools() │ └─ Parallel: run_tasks() with uv tool install @@ -354,9 +354,9 @@ install_tools request │ └─ Execute with sudo │ ├─ NPM Packages - │ ├─ Check: which pnpm + │ ├─ Check: which npm │ ├─ For each package: - │ │ └─ pnpm install -g {package} + │ │ └─ npm install -g {package} │ └─ Parallel via run_tasks() │ └─ UV Tools diff --git a/tests/test_install_tools.py b/tests/test_install_tools.py index 93367de..d3929a5 100644 --- a/tests/test_install_tools.py +++ b/tests/test_install_tools.py @@ -24,10 +24,11 @@ def mock_typer_confirm(): @patch("trobz_local.main.setup_postgresql_repo", return_value=True) +@patch("trobz_local.main.install_system_packages", return_value=True) @patch("trobz_local.installers.shutil.which") @patch("trobz_local.main.get_config") @patch("trobz_local.installers.subprocess.run") -def test_install_uv_tools(mock_subprocess, mock_get_config, mock_which, _mock_pg): +def test_install_uv_tools(mock_subprocess, mock_get_config, mock_which, _mock_sys_pkgs, _mock_pg): mock_which.return_value = "/usr/bin/uv" mock_get_config.return_value = { "tools": { @@ -133,10 +134,11 @@ def test_install_npm_packages_npm_missing(mock_subprocess, mock_get_config, mock @patch("trobz_local.main.setup_postgresql_repo", return_value=True) +@patch("trobz_local.main.install_system_packages", return_value=True) @patch("trobz_local.installers.shutil.which") @patch("trobz_local.main.get_config") @patch("trobz_local.installers.subprocess.run") -def test_install_npm_packages_success(mock_subprocess, mock_get_config, mock_which, _mock_pg): +def test_install_npm_packages_success(mock_subprocess, mock_get_config, mock_which, _mock_sys_pkgs, _mock_pg): mock_which.return_value = "/usr/bin/npm" mock_get_config.return_value = { "tools": { @@ -171,7 +173,7 @@ def test_install_system_packages_arch(mock_subprocess, mock_get_config, mock_whi "uv": [], "npm": [], "script": [], - "system_packages": ["pnpm"], + "system_packages": ["git"], } } @@ -182,7 +184,7 @@ def test_install_system_packages_arch(mock_subprocess, mock_get_config, mock_whi mock_subprocess.assert_called_once() call_args = mock_subprocess.call_args[0][0] assert "pacman" in call_args - assert "pnpm" in call_args + assert "git" in call_args @patch("trobz_local.installers.get_os_info") diff --git a/trobz_local/assets/odoo_dev.toml b/trobz_local/assets/odoo_dev.toml new file mode 100644 index 0000000..d63807e --- /dev/null +++ b/trobz_local/assets/odoo_dev.toml @@ -0,0 +1,33 @@ +versions = ["14.0", "15.0", "16.0", "17.0", "18.0"] + +[tools] +uv = [ + "odoo-venv", + "odoo-addons-path", + "pre-commit", +] + +npm = [ + "prettier", +] + +[[tools.script]] +name = "uv" +url = "https://astral.sh/uv/install.sh" + +[[tools.script]] +name = "nvm" +url = "https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh" + +system_packages = [] + +[repos] +odoo = [ + "odoo", + "enterprise", +] + +oca = [ + "server-tools", + "server-ux", +] diff --git a/trobz_local/installers.py b/trobz_local/installers.py index 26dd68a..cce5efe 100644 --- a/trobz_local/installers.py +++ b/trobz_local/installers.py @@ -156,10 +156,7 @@ def _run_package_install(cmd: list[str], packages: list[str]) -> bool: return True -def install_system_packages(packages: list[str], dry_run: bool = False) -> bool: - if not packages: - return True - +def install_system_packages(packages: list[str], dry_run: bool = False, install_defaults: bool = True) -> bool: os_info = get_os_info() system = os_info["system"] distro = os_info["distro"] @@ -177,8 +174,9 @@ def install_system_packages(packages: list[str], dry_run: bool = False) -> bool: cmd, default_packages = config - # Merge user packages with default packages - all_packages = list(dict.fromkeys(default_packages + packages)) + all_packages = list(dict.fromkeys((default_packages if install_defaults else []) + packages)) + if not all_packages: + return True if dry_run: typer.echo(f"\n[System packages - would be installed via {cmd[0]}]") diff --git a/trobz_local/main.py b/trobz_local/main.py index fbf31d0..41ccaef 100644 --- a/trobz_local/main.py +++ b/trobz_local/main.py @@ -47,12 +47,18 @@ def main( help="Enable newcomer mode with confirmations and help.", envvar="NEWCOMER_MODE", ), + yes: bool = typer.Option( + False, + "--yes", + "-y", + help="Skip all confirmations (non-interactive mode).", + ), ): """ Hi, I'm a CLI to help you setup and manage your local environment for Odoo development. """ ctx.ensure_object(dict) - ctx.obj["newcomer"] = newcomer + ctx.obj["newcomer"] = newcomer and not yes if ctx.invoked_subcommand is None: _run_init(ctx) @@ -281,7 +287,9 @@ def _build_install_message(tools_config: dict) -> str: return msg -def _run_installers(tools_config: dict, dry_run: bool) -> tuple[list, bool]: +def _run_installers( + tools_config: dict, dry_run: bool, install_default_system_packages: bool = True +) -> tuple[list, bool]: all_results = [] any_failed = False @@ -303,14 +311,12 @@ def _run_installers(tools_config: dict, dry_run: bool) -> tuple[list, bool]: if not dry_run: setup_postgresql_repo() - if tools_config.get("system_packages"): - success = install_system_packages(tools_config["system_packages"], dry_run) - if not success: - any_failed = True - - all_results.append( - TaskResult(name="system-packages", success=False, message="System package installation failed") - ) + success = install_system_packages(tools_config.get("system_packages", []), dry_run, install_default_system_packages) + if not success: + any_failed = True + all_results.append( + TaskResult(name="system-packages", success=False, message="System package installation failed") + ) if tools_config.get("npm"): results = install_npm_packages(tools_config["npm"], dry_run) @@ -331,6 +337,7 @@ def _run_installers(tools_config: dict, dry_run: bool) -> tuple[list, bool]: def install_tools( ctx: typer.Context, dry_run: bool = typer.Option(False, "--dry-run", help="Show what would be installed without executing."), + install_default_system_packages: bool = typer.Option(True, help="Install default OS system packages."), ): """ Install tools using uv tool based on config. @@ -353,7 +360,7 @@ def install_tools( msg = _build_install_message(tools_config) confirm_step(ctx, msg, "install-tools") - all_results, any_failed = _run_installers(tools_config, dry_run) + all_results, any_failed = _run_installers(tools_config, dry_run, install_default_system_packages) if not dry_run: if any_failed: diff --git a/trobz_local/utils.py b/trobz_local/utils.py index 4603cd4..3e251fa 100644 --- a/trobz_local/utils.py +++ b/trobz_local/utils.py @@ -2,6 +2,7 @@ import platform import re import shutil +from importlib.resources import files from pathlib import Path import git @@ -162,40 +163,7 @@ def get_uv_path(): def show_config_instructions(): - content = """versions = ["14.0", "15.0", "16.0", "17.0", "18.0"] - -[tools] -uv = [ - "odoo-venv", - "odoo-addons-path", - "pre-commit", -] - -npm = [ - "prettier", -] - -[[tools.script]] -name = "uv" -url = "https://astral.sh/uv/install.sh" - -[[tools.script]] -name = "nvm" -url = "https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh" - -system_packages = [] - -[repos] -odoo = [ - "odoo", - "enterprise", -] - -oca = [ - "server-tools", - "server-ux", -] -""" + content = files("trobz_local").joinpath("assets/odoo_dev.toml").read_text() typer.secho("Config file not found.", fg=typer.colors.YELLOW) code_root = get_code_root() typer.echo(f"Please create {code_root}/config.toml with content like this:")