cpl new use venv & install deps on creation
Some checks failed
Test before pr merge / test-lint (pull_request) Failing after 7s
Some checks failed
Test before pr merge / test-lint (pull_request) Failing after 7s
This commit is contained in:
@@ -3,8 +3,8 @@ from datetime import datetime
|
||||
|
||||
from cpl.core.console import Console
|
||||
from cpl.core.time.cron import Cron
|
||||
from cpl.dependency.hosted.cronjob import CronjobABC
|
||||
from cpl.dependency.hosted.hosted_service import HostedService
|
||||
from cpl.core.service.cronjob import CronjobABC
|
||||
from cpl.core.service.hosted_service import HostedService
|
||||
|
||||
|
||||
class Hosted(HostedService):
|
||||
|
||||
9
src/cli/cpl/cli/.cpl/generate/cron_job.py.schematic
Normal file
9
src/cli/cpl/cli/.cpl/generate/cron_job.py.schematic
Normal file
@@ -0,0 +1,9 @@
|
||||
from cpl.core.console import Console
|
||||
from cpl.core.service import CronjobABC
|
||||
|
||||
class CronJob(CronjobABC):
|
||||
def __init__(self):
|
||||
CronjobABC.__init__(self, Cron("*/1 * * * *"))
|
||||
|
||||
async def loop(self):
|
||||
Console.write_line(f"[{datetime.now()}] Hello, World!")
|
||||
13
src/cli/cpl/cli/.cpl/generate/hosted_service.py.schematic
Normal file
13
src/cli/cpl/cli/.cpl/generate/hosted_service.py.schematic
Normal file
@@ -0,0 +1,13 @@
|
||||
from cpl.core.console import Console
|
||||
from cpl.core.service import HostedService
|
||||
|
||||
|
||||
class <Name>(HostedService):
|
||||
def __init__(self):
|
||||
HostedService.__init__(self)
|
||||
|
||||
async def start(self):
|
||||
Console.write_line("Hello, World!")
|
||||
|
||||
async def stop(self):
|
||||
Console.write_line("Goodbye, World!")
|
||||
@@ -1,8 +1,11 @@
|
||||
import os
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
import click
|
||||
|
||||
from cpl.cli.cli import cli
|
||||
from cpl.cli.const import PIP_URL
|
||||
from cpl.cli.utils.pip import Pip
|
||||
from cpl.cli.utils.structure import Structure
|
||||
from cpl.core.console import Console
|
||||
@@ -20,10 +23,10 @@ def install(package: str, project: str, dev: bool, verbose: bool):
|
||||
Console.write_line(f"Installing {package} to '{project.name}':")
|
||||
try:
|
||||
Pip.command(
|
||||
"install --extra-index-url https://git.sh-edraft.de/api/packages/sh-edraft.de/pypi/simple/",
|
||||
f"install --extra-index-url {PIP_URL}",
|
||||
package,
|
||||
verbose=verbose,
|
||||
path=project.path,
|
||||
path=Path(project.path).parent,
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
Console.error(f"Failed to install {package}: exit code {e.returncode}")
|
||||
|
||||
@@ -3,6 +3,7 @@ import subprocess
|
||||
import click
|
||||
|
||||
from cpl.cli.cli import cli
|
||||
from cpl.cli.const import PIP_URL
|
||||
from cpl.cli.utils.pip import Pip
|
||||
from cpl.cli.utils.structure import Structure
|
||||
from cpl.core.console import Console
|
||||
@@ -30,8 +31,7 @@ def update(package: str, project: str, dev: bool, verbose: bool):
|
||||
Console.write_line(f"Updating {package} to '{project.name}':")
|
||||
try:
|
||||
Pip.command(
|
||||
"install --upgrade --extra-index-url https://git.sh-edraft.de/api/packages/sh-edraft.de/pypi/simple/",
|
||||
f"{Pip.normalize_dep(package, old_spec)}",
|
||||
f"install --upgrade --extra-index-url {PIP_URL}" f"{Pip.normalize_dep(package, old_spec)}",
|
||||
verbose=verbose,
|
||||
path=project.path,
|
||||
)
|
||||
|
||||
@@ -3,8 +3,9 @@ from pathlib import Path
|
||||
import click
|
||||
|
||||
from cpl.cli.const import PROJECT_TYPES, PROJECT_TYPES_SHORT
|
||||
from cpl.cli.utils.prompt import SmartChoice
|
||||
from cpl.cli.utils.prompt import ProjectType
|
||||
from cpl.cli.utils.structure import Structure
|
||||
from cpl.cli.utils.venv import ensure_venv
|
||||
from cpl.core.console import Console
|
||||
|
||||
|
||||
@@ -12,11 +13,14 @@ from cpl.core.console import Console
|
||||
@click.argument("target", required=False)
|
||||
@click.argument("name", required=False)
|
||||
def init(target: str, name: str):
|
||||
workspace = None
|
||||
project = None
|
||||
|
||||
if target is None:
|
||||
Console.write_line("CPL Init Wizard")
|
||||
target = click.prompt(
|
||||
"What do you want to initialize?",
|
||||
type=SmartChoice(["workspace"] + PROJECT_TYPES, {"workspace": "ws"}),
|
||||
type=ProjectType,
|
||||
show_choices=True,
|
||||
)
|
||||
|
||||
@@ -24,10 +28,14 @@ def init(target: str, name: str):
|
||||
target = [pt for pt in PROJECT_TYPES if pt.startswith(target)][0]
|
||||
|
||||
if target in ["workspace", "ws"]:
|
||||
Structure.init_workspace("./", name or click.prompt("Workspace name", default="my-workspace"))
|
||||
workspace = Structure.init_workspace("./", name or click.prompt("Workspace name", default="my-workspace"))
|
||||
elif target in PROJECT_TYPES:
|
||||
workspace = Structure.find_workspace_in_path(Path(name).parent)
|
||||
Structure.init_project("./", name or click.prompt("Project name", default=f"my-{target}"), target, workspace)
|
||||
project = Structure.init_project(
|
||||
"./", name or click.prompt("Project name", default=f"my-{target}"), target, workspace
|
||||
)
|
||||
else:
|
||||
Console.error(f"Unknown target '{target}'")
|
||||
raise SystemExit(1)
|
||||
|
||||
ensure_venv(Path((workspace or project).path).parent)
|
||||
|
||||
@@ -2,16 +2,19 @@ import os
|
||||
from pathlib import Path
|
||||
|
||||
import click
|
||||
|
||||
from cpl.cli import cli as clim
|
||||
from cpl.cli.cli import cli
|
||||
from cpl.cli.const import PROJECT_TYPES, PROJECT_TYPES_SHORT
|
||||
from cpl.cli.model.workspace import Workspace
|
||||
from cpl.cli.utils.prompt import ProjectType
|
||||
from cpl.cli.utils.structure import Structure
|
||||
from cpl.cli.utils.venv import ensure_venv
|
||||
from cpl.core.console import Console
|
||||
|
||||
|
||||
@cli.command("new", aliases=["n"])
|
||||
@click.argument("type", type=click.STRING, required=True)
|
||||
@click.argument("type", type=ProjectType, required=True)
|
||||
@click.argument("name", type=click.STRING, required=True)
|
||||
@click.option("--name", "in_name", type=click.STRING, help="Name of the workspace or project to create.")
|
||||
@click.option(
|
||||
@@ -23,16 +26,17 @@ from cpl.core.console import Console
|
||||
)
|
||||
@click.option("--verbose", "-v", is_flag=True, help="Enable verbose output")
|
||||
def new(type: str, name: str, in_name: str | None, project: list[str] | None, verbose: bool) -> None:
|
||||
workspace_created = False
|
||||
path = Path(name).parent
|
||||
project_name = in_name or Path(name).stem
|
||||
|
||||
if type in ["workspace", "ws"]:
|
||||
Structure.init_workspace(name, project_name)
|
||||
workspace = Workspace.from_file(Path(name) / "cpl.workspace.json")
|
||||
workspace_created = True
|
||||
ensure_venv(Path(name))
|
||||
|
||||
if project is None or len(project) != 2:
|
||||
return
|
||||
|
||||
if len(project) == 2:
|
||||
type = project[0]
|
||||
if type not in PROJECT_TYPES + PROJECT_TYPES_SHORT:
|
||||
raise ValueError(f"Unknown project type '{type}'")
|
||||
@@ -40,7 +44,7 @@ def new(type: str, name: str, in_name: str | None, project: list[str] | None, ve
|
||||
path = Path(workspace.path).parent / Path(project[1]).parent
|
||||
project_name = Path(project[1]).stem
|
||||
|
||||
workspace = Structure.find_workspace_in_path(path)
|
||||
workspace = Structure.find_workspace_in_path(path, with_parents=False)
|
||||
if workspace is None:
|
||||
Console.error("No workspace found. Please run 'cpl init workspace' first.")
|
||||
raise SystemExit(1)
|
||||
@@ -59,6 +63,8 @@ def new(type: str, name: str, in_name: str | None, project: list[str] | None, ve
|
||||
raise ValueError(f"Unsupported project type '{type}'")
|
||||
|
||||
Structure.create_project(path, type, project_name, workspace, verbose)
|
||||
if workspace_created:
|
||||
|
||||
ensure_venv(Path((workspace or project).path).parent)
|
||||
if workspace.default_project is None:
|
||||
workspace.default_project = project_name
|
||||
workspace.save()
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
PROJECT_TYPES = ["console", "web", "library", "service"]
|
||||
PROJECT_TYPES = ["console", "web", "graphql", "library", "service"]
|
||||
PROJECT_TYPES_SHORT = [x[0] for x in PROJECT_TYPES]
|
||||
|
||||
PIP_URL = "https://git.sh-edraft.de/api/packages/sh-edraft.de/pypi/simple/"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from cpl.cli.cli import cli
|
||||
@@ -17,6 +16,7 @@ from cpl.cli.command.version import version
|
||||
from cpl.cli.model.workspace import Workspace
|
||||
from cpl.cli.utils.custom_command import script_command
|
||||
from cpl.core.configuration import Configuration
|
||||
from cpl.core.console import Console
|
||||
|
||||
|
||||
def _load_workspace(path: str) -> Workspace | None:
|
||||
@@ -74,12 +74,16 @@ def configure():
|
||||
def main():
|
||||
prepare()
|
||||
configure()
|
||||
try:
|
||||
cli()
|
||||
finally:
|
||||
Console.write_line()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
|
||||
# ((
|
||||
# ( `)
|
||||
# ; / ,
|
||||
|
||||
@@ -52,7 +52,7 @@ class Workspace(CPLStructureModel):
|
||||
|
||||
@property
|
||||
def project_names(self) -> List[str]:
|
||||
return [Project.from_file(p).name for p in self._projects if "name" in p]
|
||||
return [Project.from_file(p).name for p in self._projects]
|
||||
|
||||
@property
|
||||
def default_project(self) -> Optional[str]:
|
||||
|
||||
@@ -97,13 +97,12 @@ class Pip:
|
||||
return spec.replace(package_name, "").strip() or None
|
||||
|
||||
@staticmethod
|
||||
def command(command: str, *args, verbose: bool = False, path: str = None):
|
||||
if path is not None and Path(path).is_file():
|
||||
def command(command: str, *args, verbose: bool = False, path: Path = None):
|
||||
if path is not None and path.is_file():
|
||||
path = os.path.dirname(path)
|
||||
|
||||
venv_path = ensure_venv(Path(path or "./"))
|
||||
venv_path = ensure_venv(Path(os.getcwd()) / Path(path or "./"))
|
||||
pip = get_venv_pip(venv_path)
|
||||
|
||||
if verbose:
|
||||
Console.write_line()
|
||||
Console.write_line(f"Running: {pip} {command} {''.join(args)}")
|
||||
@@ -111,6 +110,7 @@ class Pip:
|
||||
subprocess.run(
|
||||
[*pip.split(), *command.split(), *args],
|
||||
check=True,
|
||||
cwd=path,
|
||||
stdin=subprocess.DEVNULL if not verbose else None,
|
||||
stdout=subprocess.DEVNULL if not verbose else None,
|
||||
stderr=subprocess.DEVNULL if not verbose else None,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import click
|
||||
|
||||
from cpl.cli.const import PROJECT_TYPES
|
||||
|
||||
|
||||
class SmartChoice(click.Choice):
|
||||
|
||||
@@ -18,3 +20,8 @@ class SmartChoice(click.Choice):
|
||||
if val_lower in self._aliases.values():
|
||||
value = [k for k, v in self._aliases.items() if v == val_lower][0]
|
||||
return super().convert(value, param, ctx)
|
||||
|
||||
def get_metavar(self, param, ctx):
|
||||
return "|".join([f"({a}){option}" for option,a in self._aliases.items()])
|
||||
|
||||
ProjectType = SmartChoice(["workspace"] + PROJECT_TYPES, {"workspace": "ws"})
|
||||
@@ -5,7 +5,7 @@ from pathlib import Path
|
||||
|
||||
import click
|
||||
|
||||
import cpl.cli as cli
|
||||
from cpl import cli
|
||||
from cpl.cli.model.project import Project
|
||||
from cpl.cli.model.workspace import Workspace
|
||||
from cpl.cli.utils.template_renderer import TemplateRenderer
|
||||
@@ -13,17 +13,35 @@ from cpl.core.console import Console
|
||||
|
||||
|
||||
class Structure:
|
||||
@staticmethod
|
||||
def find_workspace_in_path(path: Path) -> Workspace | None:
|
||||
current_path = path.resolve()
|
||||
_dependency_map = {
|
||||
"console": [
|
||||
"cpl-core",
|
||||
],
|
||||
"web": [
|
||||
"cpl-api",
|
||||
],
|
||||
"graphql": [
|
||||
"cpl-graphql",
|
||||
],
|
||||
"library": [
|
||||
"cpl-core",
|
||||
],
|
||||
"service": [
|
||||
"cpl-core",
|
||||
]
|
||||
}
|
||||
|
||||
Console.write_line(*([current_path] + list(current_path.parents)))
|
||||
for parent in [current_path] + list(current_path.parents):
|
||||
@staticmethod
|
||||
def find_workspace_in_path(path: Path, with_parents=False) -> Workspace | None:
|
||||
current_path = path.resolve()
|
||||
paths = [current_path]
|
||||
if with_parents:
|
||||
paths.extend(current_path.parents)
|
||||
|
||||
for parent in paths:
|
||||
workspace_file = parent / "cpl.workspace.json"
|
||||
Console.write_line(workspace_file)
|
||||
if workspace_file.exists() and workspace_file.is_file():
|
||||
ws = Workspace.from_file(workspace_file)
|
||||
Console.error(ws.name)
|
||||
return ws
|
||||
|
||||
return None
|
||||
@@ -95,6 +113,7 @@ class Structure:
|
||||
workspace.save()
|
||||
|
||||
Console.write_line(f"Created workspace '{name}'")
|
||||
return workspace
|
||||
|
||||
@staticmethod
|
||||
def init_project(rel_path: str, name: str, project_type: str, workspace: Workspace | None, verbose=False):
|
||||
@@ -103,8 +122,8 @@ class Structure:
|
||||
|
||||
path = Path(rel_path) / Path("cpl.project.json")
|
||||
if path.exists():
|
||||
Console.write_line("cpl.project.json already exists.")
|
||||
return
|
||||
Console.error("cpl.project.json already exists.")
|
||||
raise SystemExit(1)
|
||||
|
||||
project = Project.new(str(path), name, project_type)
|
||||
|
||||
@@ -120,6 +139,16 @@ class Structure:
|
||||
|
||||
project.save()
|
||||
|
||||
from cpl.cli.command.package.install import install
|
||||
old_cwd = os.getcwd()
|
||||
os.chdir(Path(workspace.path).parent)
|
||||
install.callback(f"cpl-cli>={cli.__version__}", project.name, dev=True, verbose=verbose)
|
||||
if project_type in Structure._dependency_map:
|
||||
for package in Structure._dependency_map[project_type]:
|
||||
install.callback(package, project.name, dev=False, verbose=verbose)
|
||||
|
||||
os.chdir(old_cwd)
|
||||
|
||||
if workspace is not None:
|
||||
rel_path = str(path.resolve().absolute().relative_to(Path(workspace.path).parent))
|
||||
if rel_path not in workspace.projects:
|
||||
@@ -130,6 +159,7 @@ class Structure:
|
||||
Console.write_line(f"Registered '{name}' in workspace.json")
|
||||
|
||||
Console.write_line(f"Created {project_type} project '{name}'")
|
||||
return project
|
||||
|
||||
@staticmethod
|
||||
def create_project(path: Path, project_type: str, name: str, workspace: Workspace | None, verbose=False):
|
||||
|
||||
@@ -9,7 +9,8 @@ from cpl.core.console import Console
|
||||
|
||||
def ensure_venv(start_path: Path | None = None) -> Path:
|
||||
start_path = start_path or Path.cwd()
|
||||
workspace = Configuration.get("workspace")
|
||||
from cpl.cli.utils.structure import Structure
|
||||
workspace = Structure.find_workspace_in_path(start_path)
|
||||
|
||||
if workspace is not None:
|
||||
workspace = Path(os.path.dirname(workspace.path))
|
||||
@@ -28,7 +29,7 @@ def ensure_venv(start_path: Path | None = None) -> Path:
|
||||
else:
|
||||
venv_path = start_path / ".venv"
|
||||
|
||||
Console.write_line(f"Creating virtual environment at {venv_path.absolute()}...")
|
||||
Console.write_line(f"Creating virtual environment at {venv_path.resolve().absolute()}...")
|
||||
venv.EnvBuilder(with_pip=True).create(venv_path)
|
||||
return venv_path
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@ keywords = ["cpl", "cli", "backend", "shared", "library"]
|
||||
|
||||
dynamic = ["dependencies", "optional-dependencies"]
|
||||
|
||||
[project.scripts]
|
||||
cpl = "cpl.cli.main:main"
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://www.sh-edraft.de"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user