idmtools-cli 0.0.0.dev0__py3-none-any.whl → 0.0.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- idmtools_cli/__init__.py +12 -8
- idmtools_cli/cli/__init__.py +1 -0
- idmtools_cli/cli/common_project_templates.json +19 -0
- idmtools_cli/cli/config_file.py +199 -0
- idmtools_cli/cli/entrypoint.py +45 -0
- idmtools_cli/cli/gitrepo.py +393 -0
- idmtools_cli/cli/init.py +113 -0
- idmtools_cli/cli/package.py +106 -0
- idmtools_cli/cli/system_info.py +158 -0
- idmtools_cli/cli/utils.py +49 -0
- idmtools_cli/iplatform_cli.py +141 -0
- idmtools_cli/main.py +52 -0
- idmtools_cli/utils/__init__.py +1 -0
- idmtools_cli/utils/cols.py +135 -0
- idmtools_cli/utils/formatters.py +105 -0
- idmtools_cli/utils/utils.py +63 -0
- idmtools_cli-0.0.3.dist-info/METADATA +208 -0
- idmtools_cli-0.0.3.dist-info/RECORD +22 -0
- idmtools_cli-0.0.3.dist-info/entry_points.txt +2 -0
- idmtools_cli-0.0.3.dist-info/licenses/LICENSE.TXT +3 -0
- idmtools_cli-0.0.0.dev0.dist-info/METADATA +0 -41
- idmtools_cli-0.0.0.dev0.dist-info/RECORD +0 -5
- {idmtools_cli-0.0.0.dev0.dist-info → idmtools_cli-0.0.3.dist-info}/WHEEL +0 -0
- {idmtools_cli-0.0.0.dev0.dist-info → idmtools_cli-0.0.3.dist-info}/top_level.txt +0 -0
idmtools_cli/cli/init.py
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""Defines the init(templates) cli command."""
|
|
2
|
+
import itertools
|
|
3
|
+
import json
|
|
4
|
+
import logging
|
|
5
|
+
import os
|
|
6
|
+
import urllib.request
|
|
7
|
+
from logging import getLogger
|
|
8
|
+
from typing import Dict, List
|
|
9
|
+
from idmtools.config import IdmConfigParser
|
|
10
|
+
from idmtools.registry.plugin_specification import ProjectTemplate
|
|
11
|
+
from idmtools_cli.cli.entrypoint import cli
|
|
12
|
+
|
|
13
|
+
logger = getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@cli.group(help="Commands to help start or extend projects through templating.")
|
|
17
|
+
def init():
|
|
18
|
+
"""Base init group command."""
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@cli.command(help="Export list of project templates.")
|
|
23
|
+
def init_export():
|
|
24
|
+
"""Export project templates."""
|
|
25
|
+
with open('templates.json', 'w') as o:
|
|
26
|
+
import dataclasses
|
|
27
|
+
result = get_project_list()
|
|
28
|
+
result = {x: dataclasses.asdict(v) for x, v in result.items()}
|
|
29
|
+
json.dump(result, o)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def define_cookiecutter_project_command(project_details: ProjectTemplate):
|
|
33
|
+
"""
|
|
34
|
+
Defines the specific project cookie cutter command.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
project_details:
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
Define a dynamic cookie cutter command around a template
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
@init.command(name=project_details.name, help=project_details.description)
|
|
44
|
+
def run_project():
|
|
45
|
+
from cookiecutter.main import cookiecutter
|
|
46
|
+
if not isinstance(project_details.url, list):
|
|
47
|
+
project_details.url = [project_details.url]
|
|
48
|
+
for url in project_details.url:
|
|
49
|
+
cookiecutter(url)
|
|
50
|
+
|
|
51
|
+
return run_project
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def get_project_list() -> Dict[str, ProjectTemplate]:
|
|
55
|
+
"""
|
|
56
|
+
Build a list of cookie cutter options for menu.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
Return list of project templates
|
|
60
|
+
"""
|
|
61
|
+
from idmtools.registry.experiment_specification import ExperimentPlugins
|
|
62
|
+
from idmtools.registry.platform_specification import PlatformPlugins
|
|
63
|
+
|
|
64
|
+
# fetch
|
|
65
|
+
items = list()
|
|
66
|
+
f_dir = os.path.dirname(__file__)
|
|
67
|
+
with open(os.path.join(f_dir, 'common_project_templates.json'), 'rb') as fin:
|
|
68
|
+
items.extend(ProjectTemplate.read_templates_from_json_stream(fin))
|
|
69
|
+
|
|
70
|
+
for pm in [ExperimentPlugins().get_plugins(), PlatformPlugins().get_plugins()]:
|
|
71
|
+
items.extend(list(itertools.chain(*map(lambda pl: pl.get_project_templates(), pm))))
|
|
72
|
+
|
|
73
|
+
# check for values in config
|
|
74
|
+
url = IdmConfigParser.get_option('Templating', 'url')
|
|
75
|
+
if url:
|
|
76
|
+
logger.debug(f'Loading templates from url: {url}')
|
|
77
|
+
with urllib.request.urlopen(url) as s:
|
|
78
|
+
items.extend(ProjectTemplate.read_templates_from_json_stream(s))
|
|
79
|
+
result = {x.name: x for x in items}
|
|
80
|
+
|
|
81
|
+
if logger.isEnabledFor(logging.DEBUG):
|
|
82
|
+
logger.debug(f'Cookie cutter project list: {result}')
|
|
83
|
+
|
|
84
|
+
return result
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def build_project_commands():
|
|
88
|
+
"""
|
|
89
|
+
Builds the cookie cutter cli commands.
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
None
|
|
93
|
+
"""
|
|
94
|
+
result = get_project_list()
|
|
95
|
+
# Now define all the cookie cutter projects
|
|
96
|
+
for _name, details in result.items():
|
|
97
|
+
define_cookiecutter_project_command(details)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def read_templates_from_json_stream(items: List[ProjectTemplate], s):
|
|
101
|
+
"""
|
|
102
|
+
Read Project Template from stream onto the list.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
items: List to append data to
|
|
106
|
+
s: Stream where json data resides
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
None
|
|
110
|
+
"""
|
|
111
|
+
data = json.loads(s.read().decode())
|
|
112
|
+
for item in data:
|
|
113
|
+
items.append(ProjectTemplate(**item))
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""Define our package group CLI command."""
|
|
2
|
+
import os
|
|
3
|
+
from logging import getLogger
|
|
4
|
+
import click
|
|
5
|
+
from typing import Optional, List
|
|
6
|
+
from idmtools_cli.cli.entrypoint import cli
|
|
7
|
+
|
|
8
|
+
user_logger = getLogger('user')
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@cli.group(short_help="Contains commands related to package versions.")
|
|
12
|
+
def package():
|
|
13
|
+
"""Package group cli command."""
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@package.command()
|
|
18
|
+
@click.option('--name', required=True, type=str, help="package name")
|
|
19
|
+
def latest_version(name: Optional[str]):
|
|
20
|
+
"""
|
|
21
|
+
Display the latest version of a package.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
name: package name
|
|
25
|
+
"""
|
|
26
|
+
from idmtools_platform_comps.utils.package_version import get_latest_version
|
|
27
|
+
v = get_latest_version(name)
|
|
28
|
+
print(v)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@package.command()
|
|
32
|
+
@click.option('--name', required=True, type=str, help="package name")
|
|
33
|
+
@click.option('--base_version', required=True, default=None, type=str, help="package version")
|
|
34
|
+
def compatible_version(name: Optional[str], base_version: Optional[str]):
|
|
35
|
+
"""
|
|
36
|
+
Display the latest compatible version of a package.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
name: package name
|
|
40
|
+
base_version: package version
|
|
41
|
+
"""
|
|
42
|
+
from idmtools_platform_comps.utils.package_version import get_latest_compatible_version
|
|
43
|
+
v = get_latest_compatible_version(name, base_version)
|
|
44
|
+
print(v)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@package.command()
|
|
48
|
+
@click.option('--name', required=True, type=str, help="package name")
|
|
49
|
+
@click.option('--all/--no-all', type=bool, default=False, help="package version")
|
|
50
|
+
def list_versions(name: Optional[str], all: Optional[bool]):
|
|
51
|
+
"""
|
|
52
|
+
Display all package versions.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
name: package name
|
|
56
|
+
all: True/False - return all or only released versions
|
|
57
|
+
"""
|
|
58
|
+
from idmtools_platform_comps.utils.package_version import fetch_package_versions
|
|
59
|
+
versions = fetch_package_versions(name, not all)
|
|
60
|
+
print(versions)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@package.command()
|
|
64
|
+
@click.argument('requirement', type=click.Path(exists=True), required=False)
|
|
65
|
+
@click.option('--pkg', multiple=True, help="Package for override. Format: 'key==value'")
|
|
66
|
+
@click.option('--wheel', multiple=True, help="Local wheel file")
|
|
67
|
+
def updated_requirements(requirement: str = None, pkg: Optional[List[str]] = None, wheel: Optional[List[str]] = None):
|
|
68
|
+
"""
|
|
69
|
+
Build Updated_Requirements from requirement file.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
requirement: Path to requirement file
|
|
73
|
+
pkg: package name (along with version)
|
|
74
|
+
wheel: package wheel file
|
|
75
|
+
"""
|
|
76
|
+
from idmtools_platform_comps.utils.python_requirements_ac.requirements_to_asset_collection import \
|
|
77
|
+
RequirementsToAssetCollection
|
|
78
|
+
|
|
79
|
+
pkg_list = list(pkg)
|
|
80
|
+
wheel_list = [os.path.abspath(w) for w in wheel]
|
|
81
|
+
pl = RequirementsToAssetCollection(None, requirements_path=requirement, pkg_list=pkg_list, local_wheels=wheel_list)
|
|
82
|
+
pl.save_updated_requirements()
|
|
83
|
+
req = open('requirements_updated.txt').read()
|
|
84
|
+
print(req)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@package.command()
|
|
88
|
+
@click.argument('requirement', type=click.Path(exists=True), required=False)
|
|
89
|
+
@click.option('--pkg', multiple=True, help="Package for override. Format: 'key==value'")
|
|
90
|
+
@click.option('--wheel', multiple=True, help="Local wheel file")
|
|
91
|
+
def checksum(requirement: str = None, pkg: Optional[List[str]] = None, wheel: Optional[List[str]] = None):
|
|
92
|
+
"""
|
|
93
|
+
Construct checksum from requirement file.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
requirement: path to requirement file
|
|
97
|
+
pkg: package name (along with version)
|
|
98
|
+
wheel: package wheel file
|
|
99
|
+
"""
|
|
100
|
+
from idmtools_platform_comps.utils.python_requirements_ac.requirements_to_asset_collection import \
|
|
101
|
+
RequirementsToAssetCollection
|
|
102
|
+
|
|
103
|
+
pkg_list = list(pkg)
|
|
104
|
+
wheel_list = [os.path.abspath(w) for w in wheel]
|
|
105
|
+
pl = RequirementsToAssetCollection(None, requirements_path=requirement, pkg_list=pkg_list, local_wheels=wheel_list)
|
|
106
|
+
print(pl.checksum)
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Defines the info group cli command and version command as well.
|
|
3
|
+
"""
|
|
4
|
+
from collections import defaultdict
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
from logging import getLogger, DEBUG
|
|
8
|
+
import stat
|
|
9
|
+
import click
|
|
10
|
+
import pyperclip
|
|
11
|
+
|
|
12
|
+
from idmtools.registry.master_plugin_registry import MasterPluginRegistry
|
|
13
|
+
from idmtools.registry.task_specification import TaskPlugins
|
|
14
|
+
from tabulate import tabulate
|
|
15
|
+
from idmtools.core.system_information import get_system_information
|
|
16
|
+
from idmtools.registry.platform_specification import PlatformPlugins
|
|
17
|
+
from idmtools_cli.cli.entrypoint import cli
|
|
18
|
+
from idmtools_cli.cli.utils import supported_platforms
|
|
19
|
+
from idmtools_cli.utils.cols import columns
|
|
20
|
+
|
|
21
|
+
logger = getLogger(__name__)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@cli.command(help="List version info about idmtools and plugins.")
|
|
25
|
+
@click.option('--no-plugins/--plugins', default=False, help="Control whether we display plugins with modules")
|
|
26
|
+
def version(no_plugins: bool):
|
|
27
|
+
"""Returns version of all idmtools components."""
|
|
28
|
+
from idmtools import __version__
|
|
29
|
+
from idmtools_cli import __version__ as cli_version
|
|
30
|
+
plugin_map = MasterPluginRegistry().get_plugin_map()
|
|
31
|
+
module_map = defaultdict(dict)
|
|
32
|
+
for name in sorted(plugin_map.keys()):
|
|
33
|
+
try:
|
|
34
|
+
spec = plugin_map[name]
|
|
35
|
+
module_name = str(spec.get_type().__module__)
|
|
36
|
+
if module_name:
|
|
37
|
+
module_name = module_name.split(".")[0]
|
|
38
|
+
except Exception as e:
|
|
39
|
+
if logger.isEnabledFor(DEBUG):
|
|
40
|
+
logger.exception(e)
|
|
41
|
+
module_name = 'Unknown Module'
|
|
42
|
+
if plugin_map[name].get_version():
|
|
43
|
+
module_map[module_name][name] = plugin_map[name].get_version()
|
|
44
|
+
|
|
45
|
+
if not module_map['idmtools']:
|
|
46
|
+
module_map['idmtools'] = __version__
|
|
47
|
+
|
|
48
|
+
if not module_map['idmtools-cli']:
|
|
49
|
+
module_map['idmtools-cli'] = cli_version
|
|
50
|
+
|
|
51
|
+
for module in sorted(module_map.keys()):
|
|
52
|
+
if isinstance(module_map[module], dict):
|
|
53
|
+
mod_version = list(module_map[module].values())[0]
|
|
54
|
+
click.echo(click.style(columns((module.replace("_", "-"), 36), (f'Version: {mod_version}', 40)), fg='green'))
|
|
55
|
+
if not no_plugins:
|
|
56
|
+
click.echo(click.style(' Plugins:', fg='yellow'))
|
|
57
|
+
for plugin_name in sorted(module_map[module].keys()):
|
|
58
|
+
click.echo(click.style(columns(('', 3), (f'{plugin_name}', 25)), fg='blue'))
|
|
59
|
+
else:
|
|
60
|
+
click.echo(click.style(columns((module.replace("_", "-"), 36), (f'Version: {module_map[module]}', 40)), fg='green'))
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@cli.group(help="Troubleshooting and debugging information.")
|
|
64
|
+
def info():
|
|
65
|
+
"""Info cli subcommand."""
|
|
66
|
+
pass
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@info.command(help="Provide an output with details about your current execution platform and IDM-Tools install")
|
|
70
|
+
@click.option('--copy-to-clipboard/--no-copy-to-clipboard', default=False, help="Copy output to clipboard")
|
|
71
|
+
@click.option('--no-format-for-gh/--format-for-gh', default=False, help="When copying to clipboard, do we want to "
|
|
72
|
+
"formatted for Github")
|
|
73
|
+
@click.option('--issue/--no-issue', default=False, help="Copy data and format for github alias")
|
|
74
|
+
@click.option('--output-filename', default=None, help="Output filename")
|
|
75
|
+
def system(copy_to_clipboard, no_format_for_gh, issue, output_filename):
|
|
76
|
+
"""Provide info about your current install of idmtools."""
|
|
77
|
+
logger.debug("Building system info")
|
|
78
|
+
system_info = get_system_information()
|
|
79
|
+
logger.debug("Building system info output")
|
|
80
|
+
lines = [f'System Information\n{"=" * 20}']
|
|
81
|
+
ordered_fields = sorted(system_info.__dict__.keys())
|
|
82
|
+
[lines.append(f'{k}: {system_info.__dict__[k]}') for k in ordered_fields]
|
|
83
|
+
if os.name != 'nt':
|
|
84
|
+
logger.debug("Building windows info")
|
|
85
|
+
for f in ['workers', 'redis-data']:
|
|
86
|
+
fname = os.path.join(system_info.data_directory, f)
|
|
87
|
+
if os.path.exists(fname):
|
|
88
|
+
from pwd import getpwuid
|
|
89
|
+
s = os.stat(fname)
|
|
90
|
+
owned_by = f'{getpwuid(s.st_uid).pw_name} UID {s.st_uid}:{s.st_gid}'
|
|
91
|
+
lines.append(f'{fname} has permissions of {oct(stat.S_IMODE(os.lstat(fname).st_mode))} '
|
|
92
|
+
f'and is owned by {owned_by}')
|
|
93
|
+
logger.debug("Windows info done")
|
|
94
|
+
try:
|
|
95
|
+
import docker
|
|
96
|
+
logger.debug("Building docker info")
|
|
97
|
+
lines.append(f'\nDocker Information\n{"=" * 20}')
|
|
98
|
+
client = docker.from_env()
|
|
99
|
+
lines.append(f'Version: {client.version()}')
|
|
100
|
+
docker_info = client.info()
|
|
101
|
+
ordered_fields = sorted(docker_info.keys())
|
|
102
|
+
[lines.append(f'{k}: {docker_info[k]}') for k in ordered_fields]
|
|
103
|
+
logger.debug("docker info done")
|
|
104
|
+
except ImportError:
|
|
105
|
+
pass
|
|
106
|
+
except Exception as e:
|
|
107
|
+
logger.error(e)
|
|
108
|
+
raise e
|
|
109
|
+
if copy_to_clipboard:
|
|
110
|
+
logger.debug("Copying to clipboard")
|
|
111
|
+
output = '\n'.join(lines)
|
|
112
|
+
if not no_format_for_gh or issue:
|
|
113
|
+
logger.debug('Formatting for github')
|
|
114
|
+
# let's remove system information here by rebuilding without it
|
|
115
|
+
output = '\n'.join(lines[0:])
|
|
116
|
+
output = f'```### System Information\n{output}````'
|
|
117
|
+
pyperclip.copy(output)
|
|
118
|
+
if output_filename is not None:
|
|
119
|
+
with open(output_filename, 'w') as log_out:
|
|
120
|
+
log_out.writelines(lines)
|
|
121
|
+
else:
|
|
122
|
+
logger.debug("Writing output")
|
|
123
|
+
for line in lines:
|
|
124
|
+
click.echo(line)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@info.group(help="Commands to get information about installed IDM-Tools plugins")
|
|
128
|
+
def plugins():
|
|
129
|
+
"""Info about plugins installed."""
|
|
130
|
+
pass
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@plugins.command(help="List CLI plugins")
|
|
134
|
+
def cli():
|
|
135
|
+
"""List CLI plugins."""
|
|
136
|
+
items = list(supported_platforms.keys())
|
|
137
|
+
print(tabulate([[x] for x in items], headers=['CLI Plugins'], tablefmt='psql'))
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
@plugins.command(help="List Platform plugins configuration aliases")
|
|
141
|
+
def platform_aliases():
|
|
142
|
+
"""List platform aliases."""
|
|
143
|
+
aliases = PlatformPlugins().get_aliases()
|
|
144
|
+
print(tabulate([[name, details[1]] for name, details in aliases.items()], headers=['Platform Plugin Aliases', "Configuration Options"], tablefmt='psql'))
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
@plugins.command(help="List Platform plugins")
|
|
148
|
+
def platform():
|
|
149
|
+
"""List platform plugins."""
|
|
150
|
+
platforms = PlatformPlugins().get_plugin_map().keys()
|
|
151
|
+
print(tabulate([[x] for x in platforms], headers=['Platform Plugins'], tablefmt='psql'))
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
@plugins.command(help="List Task plugins")
|
|
155
|
+
def task():
|
|
156
|
+
"""List task plugins."""
|
|
157
|
+
tasks = TaskPlugins().get_plugin_map().keys()
|
|
158
|
+
print(tabulate([[x] for x in tasks], headers=['Task Plugins'], tablefmt='psql'))
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Defines utilities used with the cli commands."""
|
|
2
|
+
import sys
|
|
3
|
+
from typing import NoReturn, Union
|
|
4
|
+
import requests
|
|
5
|
+
from click import UsageError
|
|
6
|
+
from colorama import Fore
|
|
7
|
+
from idmtools.core.platform_factory import Platform
|
|
8
|
+
from idmtools_cli.iplatform_cli import PlatformCLIPlugins
|
|
9
|
+
|
|
10
|
+
supported_platforms = PlatformCLIPlugins().get_plugin_map()
|
|
11
|
+
|
|
12
|
+
tags_help = "Tag to filter by. This should be in the form name value. For example, if you have a tag type=PythonTask " \
|
|
13
|
+
"you would use --tags type PythonTask. In addition, you can provide multiple tags, ie --tags a 1 " \
|
|
14
|
+
"--tags b 2. This will perform an AND based query on the tags meaning only jobs contains ALL the tags " \
|
|
15
|
+
"specified will be displayed"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def show_error(message: Union[str, requests.Response]) -> NoReturn:
|
|
19
|
+
"""
|
|
20
|
+
Display an error response from API on the command line.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
message (Union[str, requests.Response]): message to display
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
Nothing
|
|
27
|
+
"""
|
|
28
|
+
print(f'{Fore.RED}Error{Fore.RESET}: {message}')
|
|
29
|
+
sys.exit(-1)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def get_platform_from_config_or_name(config_block, platform):
|
|
33
|
+
"""
|
|
34
|
+
Attempt to find the config block or crete platform obj from name.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
config_block: Config block
|
|
38
|
+
platform: Platform type
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
Platform object
|
|
42
|
+
"""
|
|
43
|
+
if platform is None and config_block is None:
|
|
44
|
+
raise UsageError("You must specify a platform or a configuration block")
|
|
45
|
+
if config_block:
|
|
46
|
+
platform_obj = Platform(config_block)
|
|
47
|
+
else:
|
|
48
|
+
platform_obj = supported_platforms[platform].get({})
|
|
49
|
+
return platform_obj
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"""Define our platform specific specifications.
|
|
2
|
+
|
|
3
|
+
This is a specific specification to illuminate a command CLI between platforms for interacting with
|
|
4
|
+
experiment/simulations.
|
|
5
|
+
"""
|
|
6
|
+
#
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
8
|
+
from typing import NoReturn, Dict, Set, cast, Optional, List, Tuple
|
|
9
|
+
import pluggy
|
|
10
|
+
from idmtools.registry.plugin_specification import PLUGIN_REFERENCE_NAME, PluginSpecification
|
|
11
|
+
from idmtools.registry.utils import load_plugin_map
|
|
12
|
+
|
|
13
|
+
get_platform_cli_spec = pluggy.HookspecMarker(PLUGIN_REFERENCE_NAME)
|
|
14
|
+
get_additional_commands_spec = pluggy.HookspecMarker(PLUGIN_REFERENCE_NAME)
|
|
15
|
+
get_platform_cli_impl = pluggy.HookimplMarker(PLUGIN_REFERENCE_NAME)
|
|
16
|
+
get_additional_commands_impl = pluggy.HookimplMarker(PLUGIN_REFERENCE_NAME)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class IPlatformCLI(ABC):
|
|
20
|
+
"""The Base PLatformCLI definition. It is mostly abstract classes around fetching info from a platform."""
|
|
21
|
+
|
|
22
|
+
@abstractmethod
|
|
23
|
+
def get_experiment_status(self, id: Optional[str], tags: Optional[List[Tuple[str, str]]]) -> NoReturn:
|
|
24
|
+
"""
|
|
25
|
+
Get experiment status from a platform.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
id: Optional ID to search for
|
|
29
|
+
tags: Optional tags to filter for as well
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
None
|
|
33
|
+
"""
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
@abstractmethod
|
|
37
|
+
def get_simulation_status(self, id: Optional[str], experiment_id: Optional[str], status: Optional[str],
|
|
38
|
+
tags: Optional[List[Tuple[str, str]]]) -> NoReturn:
|
|
39
|
+
"""
|
|
40
|
+
Get simulation status.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
id: Optional simulation id
|
|
44
|
+
experiment_id: Optional experiment id
|
|
45
|
+
status: Status to filter for
|
|
46
|
+
tags: Tags to filter for
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
None
|
|
50
|
+
"""
|
|
51
|
+
pass
|
|
52
|
+
|
|
53
|
+
@abstractmethod
|
|
54
|
+
def get_platform_information(self) -> dict:
|
|
55
|
+
"""
|
|
56
|
+
Get any platform relevant information.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
Str containing platform info
|
|
60
|
+
"""
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class PlatformCLISpecification(PluginSpecification, ABC):
|
|
65
|
+
"""Defines the Platform CLI Plugin Base."""
|
|
66
|
+
@classmethod
|
|
67
|
+
def get_name(cls, strip_all: bool = True) -> str:
|
|
68
|
+
"""
|
|
69
|
+
Get name of plugin. By default we remove the CLISpecification portion.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
strip_all: When true, CLISpecification is stripped from name. When false only Specification is Stripped
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
None
|
|
76
|
+
"""
|
|
77
|
+
if strip_all:
|
|
78
|
+
ret = cls.__name__.replace("CLISpecification", '')
|
|
79
|
+
else:
|
|
80
|
+
ret = cls.__name__.replace('Specification', '')
|
|
81
|
+
return ret
|
|
82
|
+
|
|
83
|
+
@get_platform_cli_spec
|
|
84
|
+
def get(self, configuration: dict) -> IPlatformCLI:
|
|
85
|
+
"""
|
|
86
|
+
Factor that should return a new platform using the passed-in configuration.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
configuration:
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
None
|
|
93
|
+
|
|
94
|
+
Raises:
|
|
95
|
+
NotImplementedError
|
|
96
|
+
"""
|
|
97
|
+
raise NotImplementedError("Plugin did not implement get")
|
|
98
|
+
|
|
99
|
+
@get_additional_commands_spec
|
|
100
|
+
def get_additional_commands(self) -> NoReturn:
|
|
101
|
+
"""
|
|
102
|
+
Get any additional commands defined by the platform CLI.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
None
|
|
106
|
+
|
|
107
|
+
Raises:
|
|
108
|
+
NotImplementedError
|
|
109
|
+
"""
|
|
110
|
+
raise NotImplementedError("Plugin did not implement get_additional_commands")
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class PlatformCLIPlugins:
|
|
114
|
+
"""Platform CLI Plugin Manager. Loads all the plugins."""
|
|
115
|
+
def __init__(self, strip_all: bool = True) -> None:
|
|
116
|
+
"""
|
|
117
|
+
Creates our plugin index.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
strip_all: Formatting option for plugin names in registry
|
|
121
|
+
"""
|
|
122
|
+
self._plugins = cast(Dict[str, PlatformCLISpecification],
|
|
123
|
+
load_plugin_map('idmtools_platform_cli', PlatformCLISpecification, strip_all))
|
|
124
|
+
|
|
125
|
+
def get_plugins(self) -> Set[PlatformCLISpecification]:
|
|
126
|
+
"""
|
|
127
|
+
Get plugins in the manager.
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
List of plugin specs
|
|
131
|
+
"""
|
|
132
|
+
return set(self._plugins.values())
|
|
133
|
+
|
|
134
|
+
def get_plugin_map(self) -> Dict[str, PlatformCLISpecification]:
|
|
135
|
+
"""
|
|
136
|
+
Get the plugin map.
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
Plugin Dict with name of plugin -> plugin cli spec
|
|
140
|
+
"""
|
|
141
|
+
return self._plugins
|
idmtools_cli/main.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Entrypoint for idmtools cli."""
|
|
2
|
+
import os
|
|
3
|
+
from typing import NoReturn
|
|
4
|
+
from colorama import init as color_init
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def main() -> NoReturn:
|
|
8
|
+
"""
|
|
9
|
+
This is our main run function for the CLI.
|
|
10
|
+
|
|
11
|
+
It basically calls start(load cli including the plugins) and then run the cli.
|
|
12
|
+
|
|
13
|
+
Returns:
|
|
14
|
+
None
|
|
15
|
+
"""
|
|
16
|
+
os.environ['IDMTOOLS_NO_CONFIG_WARNING'] = '1'
|
|
17
|
+
from idmtools_cli.cli.entrypoint import cli
|
|
18
|
+
start()
|
|
19
|
+
cli(auto_envvar_prefix='IDMTOOLS_CLI')
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def start() -> NoReturn:
|
|
23
|
+
"""
|
|
24
|
+
Loads the different components of the CLI.
|
|
25
|
+
|
|
26
|
+
Currently this involves
|
|
27
|
+
|
|
28
|
+
1) Initializing colorama
|
|
29
|
+
2) Loading built-in commands
|
|
30
|
+
3) Loading Platform CLI items
|
|
31
|
+
4) Loading custom CLI from platform plugins
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
None
|
|
35
|
+
"""
|
|
36
|
+
from idmtools_cli.iplatform_cli import PlatformCLIPlugins
|
|
37
|
+
color_init()
|
|
38
|
+
import idmtools_cli.cli.init # noqa: F401
|
|
39
|
+
import idmtools_cli.cli.config_file # noqa: F401
|
|
40
|
+
import idmtools_cli.cli.system_info # noqa: F401
|
|
41
|
+
import idmtools_cli.cli.gitrepo # noqa: F401
|
|
42
|
+
import idmtools_cli.cli.package # noqa: F401
|
|
43
|
+
platform_plugins = PlatformCLIPlugins()
|
|
44
|
+
from idmtools_cli.cli.init import build_project_commands
|
|
45
|
+
build_project_commands()
|
|
46
|
+
# Trigger the loading of additional cli from platforms
|
|
47
|
+
[p.get_additional_commands() for p in platform_plugins.get_plugins()]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# our entrypoint for our cli
|
|
51
|
+
if __name__ == '__main__':
|
|
52
|
+
main()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Module for cli utils."""
|