diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 020fa0b..20587fc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,6 +41,9 @@ jobs: - name: Create run: aiida-project create testproject + - name: Create with additional plugins + run: 'aiida-project create testproject2 --core-version=2.7 -p aiida-cp2k -p git+https://github.com/aiidateam/aiida-quantumespresso' + # NOTE: The cda bash function does not seem to work in GitHub runners so we execute it manually - name: cda run: | @@ -49,6 +52,11 @@ jobs: source "$aiida_venv_dir/testproject/bin/activate" cd "$aiida_project_dir/testproject" && pwd ls -lrt + uv pip list - name: Destroy - run: aiida-project destroy --force testproject + run: | + aiida-project destroy --force testproject + export $(grep -v '^#' ~/.aiida_project.env | xargs) + if [[ -d "$aiida_project_dir/testproject" ]]; then echo "Project destruction incomplete!"; exit 1; fi + if [[ -d "$aiida_venv_dir/testproject" ]]; then echo "Project venv not destroyed!"; exit 1; fi diff --git a/aiida_project/commands/main.py b/aiida_project/commands/main.py index 02cbe63..70ced35 100644 --- a/aiida_project/commands/main.py +++ b/aiida_project/commands/main.py @@ -3,6 +3,7 @@ import sys from datetime import datetime from pathlib import Path +from subprocess import CalledProcessError from typing import Annotated, Optional import typer @@ -83,7 +84,7 @@ def init(shell: Optional[ShellType] = None): @app.command() -def create( # noqa: PLR0912 +def create( name: str, engine: EngineType = EngineType.venv, core_version: str = "latest", @@ -152,22 +153,20 @@ def create( # noqa: PLR0912 project_dict.add_project(project) print("✅ [bold green]Success:[/bold green] Project created.") + aiida_spec = "aiida-core" if core_version != "latest": - typer.echo(f"💾 Installing AiiDA core module v{core_version}.") - project.install(f"aiida-core=={core_version}") - else: - typer.echo("💾 Installing the latest release of the AiiDA core module.") - project.install("aiida-core") - - for plugin in plugins: - if "github.com" in plugin: - clone_path = project.project_path / Path("git") / Path(plugin.split("/")[-1]).stem - typer.echo(f"⬇️ Cloning repo `{plugin}` from GitHub to `{clone_path.resolve()}`.") - project.clone_repo(plugin, clone_path) - typer.echo(f"💾 Installing local repo `{clone_path}` as editable install.") - else: - typer.echo(f"💾 Installing `{plugin}` from the PyPI.") - project.install(plugin) + aiida_spec += f"=={core_version}" + + packages = [aiida_spec, *plugins] + typer.echo(f"💾 Installing packages `{' '.join(packages)}`") + try: + project.install(packages) + except CalledProcessError as e: + print("[bold red]Error:[/bold red] Package installation failed!") + typer.echo(e) + typer.echo(e.stdout.decode()) + typer.echo(e.stderr.decode()) + sys.exit(1) @app.command() diff --git a/aiida_project/config.py b/aiida_project/config.py index 6155687..4b41cf3 100644 --- a/aiida_project/config.py +++ b/aiida_project/config.py @@ -12,7 +12,6 @@ "computer", "code", ], - "git": [], } diff --git a/aiida_project/project/base.py b/aiida_project/project/base.py index 466a83a..25af311 100644 --- a/aiida_project/project/base.py +++ b/aiida_project/project/base.py @@ -1,7 +1,6 @@ from __future__ import annotations import shutil -import subprocess from abc import ABC, abstractmethod from pathlib import Path @@ -32,7 +31,7 @@ def engine(self): return self._engine @abstractmethod - def create(self, python_path: Path): + def create(self, python_path: Path) -> None: """Create the project.""" Path(self.project_path, ".aiida").mkdir(parents=True, exist_ok=True) recursive_mkdir(self.project_path, self.dir_structure) @@ -51,14 +50,5 @@ def append_deactivate_text(self, text: str) -> None: """Append a text to the deactivate script.""" @abstractmethod - def install(self, package): - """Install a package from PyPI.""" - - @abstractmethod - def install_local(self, path): - """Install a package from a local directory.""" - - def clone_repo(self, repo, path): - """Clone a ``git`` repository from a remote source.""" - clone_command = ["git", "clone", "--single-branch", f"{repo}", f"{path.resolve()}"] - subprocess.run(clone_command, capture_output=True) + def install(self, packages: list[str]) -> None: + """Install a list of packages from the PyPI or a GitHub repository.""" diff --git a/aiida_project/project/venv.py b/aiida_project/project/venv.py index a69255f..9a33bbf 100644 --- a/aiida_project/project/venv.py +++ b/aiida_project/project/venv.py @@ -59,12 +59,6 @@ def append_deactivate_text(self, text): ) ) - def install(self, package): - install_command = [Path(self.venv_path, "bin", "pip").as_posix(), "install", package] - subprocess.run(install_command, capture_output=True) - - def install_local(self, path): - install_command = [] - install_command.append(Path(self.venv_path, "bin", "pip")).as_posix() - install_command.extend(["install", "-e", path.as_posix()]) - subprocess.run(install_command, cwd=self.project_path) + def install(self, packages: list[str]) -> None: + install_command = [Path(self.venv_path, "bin", "pip").as_posix(), "install", *packages] + subprocess.run(install_command, capture_output=True, check=True)