milieux.cli.config

 1from dataclasses import dataclass, field
 2from pathlib import Path
 3from typing import Any, Union
 4
 5from fancy_dataclass import CLIDataclass
 6from rich.prompt import Confirm, Prompt
 7
 8from milieux import PROG, logger
 9from milieux.config import Config, PipConfig, get_config_path, user_default_base_dir
10from milieux.errors import ConfigNotFoundError
11
12
13@dataclass
14class ConfigNew(CLIDataclass, command_name='new'):
15    """Create a new config file."""
16    stdout: bool = field(
17        default=False,
18        metadata={'help': 'output config file to stdout'}
19    )
20
21    def run(self) -> None:
22        """Creates a new config file interactively."""
23        path = get_config_path()
24        write = True
25        if (not self.stdout) and path.exists():
26            prompt = f'Config file {path} already exists. Overwrite?'
27            write = Confirm.ask(prompt)
28        if not write:
29            return
30        default_base_dir = user_default_base_dir()
31        base_dir = Prompt.ask('Base directory for workspace', default=str(default_base_dir)).strip()
32        if not (p := Path(base_dir)).is_dir():
33            prompt = f'Directory {p} does not exist. Create it?'
34            create = Confirm.ask(prompt)
35            if create:
36                p.mkdir(parents=True)
37                logger.info(f'Created directory {p}')
38            else:
39                return
40        kwargs: dict[str, Any] = {'base_dir': base_dir}
41        default_env_dir = Config.__dataclass_fields__['env_dir'].default
42        assert isinstance(default_env_dir, str)
43        kwargs['env_dir'] = Prompt.ask('Directory for env_dir', default=default_env_dir).strip()
44        # TODO: access ~/.pip/pip.conf to retrieve index_url if it exists
45        index_url = Prompt.ask('PyPI index URL \\[optional]').strip() or None
46        kwargs['pip'] = PipConfig(index_url=index_url)
47        cfg = Config(**kwargs)
48        if self.stdout:
49            print('\n' + cfg.to_toml_string())
50        else:
51            cfg.save(path)
52            logger.info(f'Saved config file to {path}')
53
54
55@dataclass
56class ConfigPath(CLIDataclass, command_name='path'):
57    """Print out path to the configurations."""
58
59    def run(self) -> None:
60        """Displays the path to the user's config file."""
61        print(get_config_path())
62
63
64@dataclass
65class ConfigShow(CLIDataclass, command_name='show'):
66    """Show the configurations."""
67
68    def run(self) -> None:
69        """Displays the contents of the user's config file."""
70        if (path := get_config_path()).exists():
71            cfg = Config.load(path)
72            print(cfg.to_toml_string())
73        else:
74            raise ConfigNotFoundError(f"No config file found. Run '{PROG} config new' to create a new one.")
75
76
77@dataclass
78class ConfigCmd(CLIDataclass, command_name='config'):
79    """Manage configurations."""
80
81    subcommand: Union[
82        ConfigNew,
83        ConfigPath,
84        ConfigShow,
85    ] = field(metadata={'subcommand': True})
@dataclass
class ConfigNew(fancy_dataclass.cli.CLIDataclass):
14@dataclass
15class ConfigNew(CLIDataclass, command_name='new'):
16    """Create a new config file."""
17    stdout: bool = field(
18        default=False,
19        metadata={'help': 'output config file to stdout'}
20    )
21
22    def run(self) -> None:
23        """Creates a new config file interactively."""
24        path = get_config_path()
25        write = True
26        if (not self.stdout) and path.exists():
27            prompt = f'Config file {path} already exists. Overwrite?'
28            write = Confirm.ask(prompt)
29        if not write:
30            return
31        default_base_dir = user_default_base_dir()
32        base_dir = Prompt.ask('Base directory for workspace', default=str(default_base_dir)).strip()
33        if not (p := Path(base_dir)).is_dir():
34            prompt = f'Directory {p} does not exist. Create it?'
35            create = Confirm.ask(prompt)
36            if create:
37                p.mkdir(parents=True)
38                logger.info(f'Created directory {p}')
39            else:
40                return
41        kwargs: dict[str, Any] = {'base_dir': base_dir}
42        default_env_dir = Config.__dataclass_fields__['env_dir'].default
43        assert isinstance(default_env_dir, str)
44        kwargs['env_dir'] = Prompt.ask('Directory for env_dir', default=default_env_dir).strip()
45        # TODO: access ~/.pip/pip.conf to retrieve index_url if it exists
46        index_url = Prompt.ask('PyPI index URL \\[optional]').strip() or None
47        kwargs['pip'] = PipConfig(index_url=index_url)
48        cfg = Config(**kwargs)
49        if self.stdout:
50            print('\n' + cfg.to_toml_string())
51        else:
52            cfg.save(path)
53            logger.info(f'Saved config file to {path}')

Create a new config file.

ConfigNew(stdout: bool = False)
stdout: bool = False
def run(self) -> None:
22    def run(self) -> None:
23        """Creates a new config file interactively."""
24        path = get_config_path()
25        write = True
26        if (not self.stdout) and path.exists():
27            prompt = f'Config file {path} already exists. Overwrite?'
28            write = Confirm.ask(prompt)
29        if not write:
30            return
31        default_base_dir = user_default_base_dir()
32        base_dir = Prompt.ask('Base directory for workspace', default=str(default_base_dir)).strip()
33        if not (p := Path(base_dir)).is_dir():
34            prompt = f'Directory {p} does not exist. Create it?'
35            create = Confirm.ask(prompt)
36            if create:
37                p.mkdir(parents=True)
38                logger.info(f'Created directory {p}')
39            else:
40                return
41        kwargs: dict[str, Any] = {'base_dir': base_dir}
42        default_env_dir = Config.__dataclass_fields__['env_dir'].default
43        assert isinstance(default_env_dir, str)
44        kwargs['env_dir'] = Prompt.ask('Directory for env_dir', default=default_env_dir).strip()
45        # TODO: access ~/.pip/pip.conf to retrieve index_url if it exists
46        index_url = Prompt.ask('PyPI index URL \\[optional]').strip() or None
47        kwargs['pip'] = PipConfig(index_url=index_url)
48        cfg = Config(**kwargs)
49        if self.stdout:
50            print('\n' + cfg.to_toml_string())
51        else:
52            cfg.save(path)
53            logger.info(f'Saved config file to {path}')

Creates a new config file interactively.

subcommand_field_name: ClassVar[Optional[str]] = None
subcommand_dest_name: ClassVar[str] = '_subcommand_ConfigNew'
@dataclass
class ConfigPath(fancy_dataclass.cli.CLIDataclass):
56@dataclass
57class ConfigPath(CLIDataclass, command_name='path'):
58    """Print out path to the configurations."""
59
60    def run(self) -> None:
61        """Displays the path to the user's config file."""
62        print(get_config_path())

Print out path to the configurations.

def run(self) -> None:
60    def run(self) -> None:
61        """Displays the path to the user's config file."""
62        print(get_config_path())

Displays the path to the user's config file.

subcommand_field_name: ClassVar[Optional[str]] = None
subcommand_dest_name: ClassVar[str] = '_subcommand_ConfigPath'
@dataclass
class ConfigShow(fancy_dataclass.cli.CLIDataclass):
65@dataclass
66class ConfigShow(CLIDataclass, command_name='show'):
67    """Show the configurations."""
68
69    def run(self) -> None:
70        """Displays the contents of the user's config file."""
71        if (path := get_config_path()).exists():
72            cfg = Config.load(path)
73            print(cfg.to_toml_string())
74        else:
75            raise ConfigNotFoundError(f"No config file found. Run '{PROG} config new' to create a new one.")

Show the configurations.

def run(self) -> None:
69    def run(self) -> None:
70        """Displays the contents of the user's config file."""
71        if (path := get_config_path()).exists():
72            cfg = Config.load(path)
73            print(cfg.to_toml_string())
74        else:
75            raise ConfigNotFoundError(f"No config file found. Run '{PROG} config new' to create a new one.")

Displays the contents of the user's config file.

subcommand_field_name: ClassVar[Optional[str]] = None
subcommand_dest_name: ClassVar[str] = '_subcommand_ConfigShow'
@dataclass
class ConfigCmd(fancy_dataclass.cli.CLIDataclass):
78@dataclass
79class ConfigCmd(CLIDataclass, command_name='config'):
80    """Manage configurations."""
81
82    subcommand: Union[
83        ConfigNew,
84        ConfigPath,
85        ConfigShow,
86    ] = field(metadata={'subcommand': True})

Manage configurations.

ConfigCmd( subcommand: Union[ConfigNew, ConfigPath, ConfigShow])
subcommand: Union[ConfigNew, ConfigPath, ConfigShow]
subcommand_field_name: ClassVar[Optional[str]] = 'subcommand'
subcommand_dest_name: ClassVar[str] = '_subcommand_ConfigCmd'