Coverage for src/irorun/helpers.py: 100%
65 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-03-02 16:47 -0500
« prev ^ index » next coverage.py v7.6.12, created at 2025-03-02 16:47 -0500
1# Copyright 2025 Faith O. Oyedemi
2# SPDX-License-Identifier: Apache-2.0
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16# For more details, see the full text of the Apache License at:
17# http://www.apache.org/licenses/LICENSE-2.0
19import os
20import subprocess
21from collections.abc import Iterable
22from contextlib import contextmanager
23from enum import Enum
24from pathlib import Path
25from typing import Optional
27import typer
30class EnvManager(Enum):
31 POETRY = 'poetry'
32 UV = 'uv'
33 VIRTUALENV = 'virtualenv'
36@contextmanager
37def change_dir(new_dir: str):
38 """Context manager for changing the current working directory."""
39 previous_dir = os.getcwd()
40 os.chdir(new_dir)
41 try:
42 yield
43 finally:
44 os.chdir(previous_dir)
47def run_command(cmd: list[str], cwd: Optional[str] = None) -> None:
48 """Wrapper for subprocess.run to execute a command and handle errors."""
49 try:
50 subprocess.run(cmd, check=True, cwd=cwd)
51 except subprocess.CalledProcessError as e:
52 typer.echo(f'Error running command {cmd}: {e}', err=True)
53 raise typer.Exit(1) from e
56def add_dependencies(package_manager: EnvManager, dependencies: list[str]) -> None:
57 """
58 Adds dependencies using the specified package manager.
59 Only supports POETRY and UV.
60 """
61 if package_manager not in (EnvManager.POETRY, EnvManager.UV):
62 typer.echo('Invalid package manager', err=True)
63 raise typer.Exit(1)
64 run_command([package_manager.value, 'add'] + dependencies)
65 typer.echo(f'Added dependencies: {dependencies}')
68def create_poetry_project(
69 project_dir: str, dependencies: Optional[list[str]] = None
70) -> None:
71 """
72 Creates a new Poetry project and optionally installs dependencies.
73 """
74 run_command(['poetry', 'new', project_dir])
75 typer.echo(f'Created new Poetry project in {project_dir}')
76 with change_dir(project_dir):
77 if dependencies:
78 typer.echo(f'Installing dependencies: {dependencies}')
79 add_dependencies(EnvManager.POETRY, dependencies)
82def create_uv_project(
83 project_dir: str, venv_name: str, dependencies: Optional[list[str]] = None
84) -> None:
85 """
86 Creates a new project with a virtual environment using uv.
87 """
88 run_command(['uv', 'init', project_dir])
89 with change_dir(project_dir):
90 run_command(['uv', 'venv', venv_name])
91 typer.echo(f'Created virtual environment "{venv_name}" in {project_dir}')
92 if dependencies:
93 typer.echo(f'Installing dependencies: {dependencies}')
94 add_dependencies(EnvManager.UV, dependencies)
97def create_virtualenv_project(
98 project_dir: str, venv_name: str, dependencies: Optional[list[str]] = None
99) -> None:
100 """
101 Creates a new project directory and virtual environment using virtualenv.
102 """
103 Path(project_dir).mkdir(parents=True, exist_ok=True)
104 with change_dir(project_dir):
105 run_command(['virtualenv', venv_name])
107 # Determine the correct path for the pip executable in the virtual environment.
108 venv_path = Path(venv_name)
109 bin_dir = 'Scripts' if os.name == 'nt' else 'bin'
110 pip_executable = str(venv_path / bin_dir / 'pip')
112 run_command([pip_executable, 'install', '-U', 'pip'])
113 if dependencies:
114 typer.echo(f'Installing dependencies: {dependencies}')
115 run_command([pip_executable, 'install'] + dependencies)
116 typer.echo('Dependencies installed successfully.')
117 typer.echo(f'Created virtual environment project in {project_dir}')
120def create_subdirectories(project_dir: str, subdirectories: Iterable[str]) -> None:
121 """
122 Creates subdirectories within a project directory.
124 Parameters:
125 project_dir: The base project directory.
126 subdirectories: An iterable of subdirectory names to create under project_dir.
127 """
128 base = Path(project_dir)
129 for subdir in subdirectories:
130 sub_path = base / subdir
131 sub_path.mkdir(parents=True, exist_ok=True)
132 typer.echo(f'Created subdirectory: {sub_path}')