Source code for conda_project.cli.commands
# -*- coding: utf-8 -*-
# Copyright (C) 2022-2024 Anaconda, Inc
# SPDX-License-Identifier: BSD-3-Clause
# Copyright (C) 2022 Anaconda, Inc
# SPDX-License-Identifier: BSD-3-Clause
import logging
import sys
from argparse import Namespace
from functools import wraps
from typing import Any, Callable, NoReturn
from ..exceptions import CommandNotFoundError, CondaProjectError
from ..project import Command, CondaProject
logger = logging.getLogger(__name__)
def _load_project(args: Namespace):
if args.project_archive is not None:
_storage_options = (
[]
if args.archive_storage_options is None
else args.archive_storage_options.split(",")
)
storage_options = {}
for option in _storage_options:
k, v = option.split("=")
storage_options[k] = v
project = CondaProject.from_archive(
args.project_archive,
storage_options=storage_options,
output_directory=args.directory,
)
else:
project = CondaProject(args.directory)
return project
[docs]
def handle_errors(func: Callable[[Namespace], Any]) -> Callable[[Namespace], int]:
"""Wrap a subcommand function to catch exceptions and return an appropriate error code."""
@wraps(func)
def wrapper(args: Namespace) -> int:
try:
ret = func(args)
if ret:
return 0
else:
return 1
except CondaProjectError as e:
print(f"{e.__class__.__name__}: {e}", file=sys.stderr)
return 1
return wrapper
[docs]
@handle_errors
def init(args: Namespace) -> bool:
project = CondaProject.init(
directory=args.directory,
name=args.name,
dependencies=args.dependencies,
channels=args.channel,
platforms=args.platforms.split(","),
conda_configs=(
[] if args.conda_configs is None else args.conda_configs.split(",")
),
lock_dependencies=args.lock,
from_environment=args.from_environment,
verbose=True,
)
if args.install:
project.default_environment.install(verbose=True)
return True
[docs]
def create(args: Namespace) -> int:
logger.warning(
"The 'create' subcommand is an alias for 'init' and may be removed in a future version."
)
return init(args)
[docs]
@handle_errors
def lock(args: Namespace) -> bool:
project = _load_project(args)
if args.environment:
to_lock = [project.environments[args.environment]]
else:
to_lock = project.environments.values()
for env in to_lock:
env.lock(force=args.force, verbose=True)
return True
[docs]
@handle_errors
def check(args: Namespace) -> bool:
project = _load_project(args)
return project.check(verbose=True)
[docs]
@handle_errors
def install(args: Namespace) -> bool:
project = _load_project(args)
if args.all:
for _, env in project.environments:
env.install(force=args.force, verbose=True)
else:
env = (
project.environments[args.environment]
if args.environment
else project.default_environment
)
env.install(force=args.force, as_platform=args.as_platform, verbose=True)
return True
[docs]
def prepare(args: Namespace) -> int:
logger.warning(
"The 'prepare' subcommand is an alias for 'install' and may be removed in a future version."
)
return install(args)
[docs]
@handle_errors
def add(args: Namespace) -> bool:
project = _load_project(args)
env = (
project.environments[args.environment]
if args.environment
else project.default_environment
)
env.add(args.dependencies, args.channel, verbose=True)
return True
[docs]
@handle_errors
def remove(args: Namespace) -> bool:
project = _load_project(args)
env = (
project.environments[args.environment]
if args.environment
else project.default_environment
)
env.remove(args.dependencies, verbose=True)
return True
[docs]
@handle_errors
def clean(args: Namespace) -> bool:
project = CondaProject(args.directory)
if args.all:
for env in project.environments.values():
env.clean(verbose=True)
else:
env = (
project.environments[args.environment]
if args.environment
else project.default_environment
)
env.clean(verbose=True)
return True
[docs]
@handle_errors
def run(args: Namespace) -> NoReturn:
project = _load_project(args)
if args.command:
try:
to_run = project.commands[args.command]
except CommandNotFoundError:
to_run = Command(
name=str(args.command),
cmd=args.command,
environment=project.default_environment,
project=project,
)
else:
to_run = project.default_command
to_run.run(
environment=args.environment,
external_environment=args.external_environment,
extra_args=args.extra_args,
verbose=True,
)
[docs]
@handle_errors
def activate(args: Namespace) -> bool:
project = _load_project(args)
if args.environment:
env = project.environments[args.environment]
else:
env = project.default_environment
env.activate(verbose=True)
return True