shellfoundry 1.2.25__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.
- shellfoundry/__init__.py +8 -0
- shellfoundry/__main__.py +7 -0
- shellfoundry/bootstrap.py +169 -0
- shellfoundry/commands/__init__.py +0 -0
- shellfoundry/commands/config_command.py +87 -0
- shellfoundry/commands/delete_command.py +24 -0
- shellfoundry/commands/dist_command.py +34 -0
- shellfoundry/commands/extend_command.py +182 -0
- shellfoundry/commands/generate_command.py +44 -0
- shellfoundry/commands/get_templates_command.py +151 -0
- shellfoundry/commands/install_command.py +81 -0
- shellfoundry/commands/list_command.py +110 -0
- shellfoundry/commands/new_command.py +393 -0
- shellfoundry/commands/pack_command.py +45 -0
- shellfoundry/commands/show_command.py +55 -0
- shellfoundry/data/standards.json +44 -0
- shellfoundry/data/templates.yml +117 -0
- shellfoundry/decorators/__init__.py +1 -0
- shellfoundry/decorators/standards.py +20 -0
- shellfoundry/decorators/version_check.py +52 -0
- shellfoundry/exceptions.py +52 -0
- shellfoundry/models/__init__.py +0 -0
- shellfoundry/models/install_config.py +82 -0
- shellfoundry/models/shell_template.py +22 -0
- shellfoundry/models/shellfoundry_settings.py +13 -0
- shellfoundry/utilities/__init__.py +114 -0
- shellfoundry/utilities/archive_creator.py +35 -0
- shellfoundry/utilities/cloudshell_api/__init__.py +1 -0
- shellfoundry/utilities/cloudshell_api/client_wrapper.py +71 -0
- shellfoundry/utilities/config/__init__.py +0 -0
- shellfoundry/utilities/config/config_context.py +44 -0
- shellfoundry/utilities/config/config_file_creation.py +32 -0
- shellfoundry/utilities/config/config_providers.py +50 -0
- shellfoundry/utilities/config/config_record.py +24 -0
- shellfoundry/utilities/config_reader.py +154 -0
- shellfoundry/utilities/constants.py +37 -0
- shellfoundry/utilities/cookiecutter_integration.py +67 -0
- shellfoundry/utilities/driver_generator.py +121 -0
- shellfoundry/utilities/filters.py +45 -0
- shellfoundry/utilities/installer.py +44 -0
- shellfoundry/utilities/modifiers/__init__.py +0 -0
- shellfoundry/utilities/modifiers/configuration/__init__.py +0 -0
- shellfoundry/utilities/modifiers/configuration/aggregated_modifiers.py +26 -0
- shellfoundry/utilities/modifiers/configuration/password_modification.py +48 -0
- shellfoundry/utilities/modifiers/definition/__init__.py +0 -0
- shellfoundry/utilities/modifiers/definition/definition_modification.py +205 -0
- shellfoundry/utilities/package_builder.py +152 -0
- shellfoundry/utilities/python_dependencies_packager.py +53 -0
- shellfoundry/utilities/repository_downloader.py +76 -0
- shellfoundry/utilities/shell_config_reader.py +59 -0
- shellfoundry/utilities/shell_datamodel_merger.py +44 -0
- shellfoundry/utilities/shell_package.py +59 -0
- shellfoundry/utilities/shell_package_builder.py +149 -0
- shellfoundry/utilities/shell_package_installer.py +231 -0
- shellfoundry/utilities/standards/__init__.py +3 -0
- shellfoundry/utilities/standards/consts.py +2 -0
- shellfoundry/utilities/standards/standards_retriever.py +32 -0
- shellfoundry/utilities/standards/standards_versions.py +34 -0
- shellfoundry/utilities/temp_dir_context.py +17 -0
- shellfoundry/utilities/template_retriever.py +309 -0
- shellfoundry/utilities/template_url.py +38 -0
- shellfoundry/utilities/template_versions.py +47 -0
- shellfoundry/utilities/validations/__init__.py +2 -0
- shellfoundry/utilities/validations/shell_generation_validation.py +29 -0
- shellfoundry/utilities/validations/shell_name_validations.py +10 -0
- shellfoundry/utilities/version_utilities.py +19 -0
- shellfoundry-1.2.25.dist-info/LICENSE +201 -0
- shellfoundry-1.2.25.dist-info/METADATA +417 -0
- shellfoundry-1.2.25.dist-info/RECORD +72 -0
- shellfoundry-1.2.25.dist-info/WHEEL +5 -0
- shellfoundry-1.2.25.dist-info/entry_points.txt +2 -0
- shellfoundry-1.2.25.dist-info/top_level.txt +1 -0
shellfoundry/__init__.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
from os.path import dirname, join
|
|
2
|
+
|
|
3
|
+
ALTERNATIVE_TEMPLATES_PATH = join(dirname(__file__), "data", "templates.yml")
|
|
4
|
+
ALTERNATIVE_STANDARDS_PATH = join(dirname(__file__), "data", "standards.json")
|
|
5
|
+
|
|
6
|
+
MASTER_BRANCH_NAME = "master"
|
|
7
|
+
|
|
8
|
+
PACKAGE_NAME = __package__.split(".")[0]
|
shellfoundry/__main__.py
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
import click
|
|
5
|
+
import pkg_resources
|
|
6
|
+
|
|
7
|
+
from shellfoundry.commands.config_command import ConfigCommandExecutor
|
|
8
|
+
from shellfoundry.commands.delete_command import DeleteCommandExecutor
|
|
9
|
+
from shellfoundry.commands.dist_command import DistCommandExecutor
|
|
10
|
+
from shellfoundry.commands.extend_command import ExtendCommandExecutor
|
|
11
|
+
from shellfoundry.commands.generate_command import GenerateCommandExecutor
|
|
12
|
+
from shellfoundry.commands.get_templates_command import GetTemplatesCommandExecutor
|
|
13
|
+
from shellfoundry.commands.install_command import InstallCommandExecutor
|
|
14
|
+
from shellfoundry.commands.list_command import ListCommandExecutor
|
|
15
|
+
from shellfoundry.commands.new_command import NewCommandExecutor
|
|
16
|
+
from shellfoundry.commands.pack_command import PackCommandExecutor
|
|
17
|
+
from shellfoundry.commands.show_command import ShowCommandExecutor
|
|
18
|
+
from shellfoundry.decorators import shellfoundry_version_check
|
|
19
|
+
from shellfoundry.utilities import GEN_ONE, GEN_TWO, LAYER_ONE, NO_FILTER
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@click.group()
|
|
23
|
+
def cli():
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@cli.command()
|
|
28
|
+
def version():
|
|
29
|
+
"""Displays the shellfoundry version."""
|
|
30
|
+
click.echo(
|
|
31
|
+
"shellfoundry version " + pkg_resources.get_distribution("shellfoundry").version
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@cli.command() # noqa: A001
|
|
36
|
+
@click.option(
|
|
37
|
+
"--gen2",
|
|
38
|
+
"default_view",
|
|
39
|
+
flag_value=GEN_TWO,
|
|
40
|
+
help="Show 2nd generation shell templates",
|
|
41
|
+
)
|
|
42
|
+
@click.option(
|
|
43
|
+
"--gen1",
|
|
44
|
+
"default_view",
|
|
45
|
+
flag_value=GEN_ONE,
|
|
46
|
+
help="Show 1st generation shell templates",
|
|
47
|
+
)
|
|
48
|
+
@click.option(
|
|
49
|
+
"--layer1", "default_view", flag_value=LAYER_ONE, help="Show layer1 shell templates"
|
|
50
|
+
)
|
|
51
|
+
@click.option("--all", "default_view", flag_value=NO_FILTER, help="Show all templates")
|
|
52
|
+
@shellfoundry_version_check(abort_if_major=True)
|
|
53
|
+
def list(default_view): # noqa: A001
|
|
54
|
+
"""Lists the available shell templates."""
|
|
55
|
+
ListCommandExecutor(default_view).list()
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@cli.command()
|
|
59
|
+
@click.argument("name")
|
|
60
|
+
@click.option(
|
|
61
|
+
"--template",
|
|
62
|
+
default="gen2/resource",
|
|
63
|
+
help="Specify a Shell template. Use 'shellfoundry list' to see the list of available templates. " # noqa: E501
|
|
64
|
+
"You can use 'local://<folder>' to specify a locally saved template",
|
|
65
|
+
)
|
|
66
|
+
@click.option("--version", default=None)
|
|
67
|
+
@click.option(
|
|
68
|
+
"--python",
|
|
69
|
+
type=click.Choice(["2", "3"]),
|
|
70
|
+
default="3",
|
|
71
|
+
required=False,
|
|
72
|
+
help="Specify Python version which will be used",
|
|
73
|
+
)
|
|
74
|
+
@shellfoundry_version_check(abort_if_major=True)
|
|
75
|
+
def new(name, template, version, python):
|
|
76
|
+
"""Creates a new shell based on a template."""
|
|
77
|
+
NewCommandExecutor().new(name, template, version, python)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@cli.command()
|
|
81
|
+
def pack():
|
|
82
|
+
"""Creates a shell package."""
|
|
83
|
+
PackCommandExecutor().pack()
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@cli.command()
|
|
87
|
+
def install():
|
|
88
|
+
"""Installs the shell package into CloudShell."""
|
|
89
|
+
PackCommandExecutor().pack()
|
|
90
|
+
InstallCommandExecutor().install()
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@cli.command()
|
|
94
|
+
@click.option(
|
|
95
|
+
"--enable_cs_repo",
|
|
96
|
+
is_flag=True,
|
|
97
|
+
help="Includes shell dependencies " "that are stored in the local pypi repository",
|
|
98
|
+
)
|
|
99
|
+
def dist(enable_cs_repo):
|
|
100
|
+
"""Creates a deployable Shell which can be distributed to a production environment.""" # noqa: E501
|
|
101
|
+
PackCommandExecutor().pack()
|
|
102
|
+
DistCommandExecutor().dist(enable_cs_repo)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@cli.command()
|
|
106
|
+
def generate():
|
|
107
|
+
"""Generates Python driver data model to be used in driver code."""
|
|
108
|
+
PackCommandExecutor().pack()
|
|
109
|
+
GenerateCommandExecutor().generate()
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@cli.command()
|
|
113
|
+
@click.argument("kv", type=(str, str), default=(None, None), required=False)
|
|
114
|
+
@click.option("--global/--local", "global_cfg", default=True)
|
|
115
|
+
@click.option("--remove", "key_to_remove", default=None)
|
|
116
|
+
def config(kv, global_cfg, key_to_remove):
|
|
117
|
+
"""Configures global/local config values used by shellfoundry."""
|
|
118
|
+
ConfigCommandExecutor(global_cfg).config(kv, key_to_remove)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@cli.command()
|
|
122
|
+
@click.argument("template_name")
|
|
123
|
+
def show(template_name):
|
|
124
|
+
"""Shows all versions of TEMPLATE NAME."""
|
|
125
|
+
ShowCommandExecutor().show(template_name)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@cli.command()
|
|
129
|
+
@click.argument("source")
|
|
130
|
+
@click.option(
|
|
131
|
+
"--attribute",
|
|
132
|
+
"add_attribute",
|
|
133
|
+
multiple=True,
|
|
134
|
+
default=None,
|
|
135
|
+
help="Creates a commented out attribute in the shell definition",
|
|
136
|
+
)
|
|
137
|
+
def extend(source, add_attribute):
|
|
138
|
+
r"""Creates a new shell based on an existing shell.
|
|
139
|
+
|
|
140
|
+
SOURCE - Specify the original Shell location.\n
|
|
141
|
+
\tYou can use 'local://<folder>' to specify a locally saved Shell folder
|
|
142
|
+
"""
|
|
143
|
+
ExtendCommandExecutor().extend(source, add_attribute)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@cli.command()
|
|
147
|
+
@click.argument("cs_version")
|
|
148
|
+
@click.option(
|
|
149
|
+
"--output_dir",
|
|
150
|
+
"output_dir",
|
|
151
|
+
default=None,
|
|
152
|
+
help="Folder where templates will be saved",
|
|
153
|
+
)
|
|
154
|
+
def get_templates(cs_version, output_dir):
|
|
155
|
+
"""Download all templates which are compatible with provided CloudShell Version.
|
|
156
|
+
|
|
157
|
+
CS_VERSION - CloudShell Version
|
|
158
|
+
"""
|
|
159
|
+
GetTemplatesCommandExecutor().get_templates(cs_version, output_dir)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
@cli.command()
|
|
163
|
+
@click.argument("name")
|
|
164
|
+
def delete(name):
|
|
165
|
+
"""Deletes the shell from CloudShell.
|
|
166
|
+
|
|
167
|
+
NAME - Shell name installed on CloudShell
|
|
168
|
+
"""
|
|
169
|
+
DeleteCommandExecutor().delete(name)
|
|
File without changes
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
import click
|
|
5
|
+
|
|
6
|
+
from shellfoundry.utilities.config.config_context import ConfigContext
|
|
7
|
+
from shellfoundry.utilities.config.config_file_creation import ConfigFileCreation
|
|
8
|
+
from shellfoundry.utilities.config.config_providers import (
|
|
9
|
+
GlobalConfigProvider,
|
|
10
|
+
LocalConfigProvider,
|
|
11
|
+
)
|
|
12
|
+
from shellfoundry.utilities.config.config_record import ConfigRecord
|
|
13
|
+
from shellfoundry.utilities.config_reader import INSTALL, Configuration
|
|
14
|
+
|
|
15
|
+
DEFAULTS_CHAR = "*"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ConfigCommandExecutor(object):
|
|
19
|
+
def __init__(self, global_cfg, cfg_creation=None):
|
|
20
|
+
self.global_cfg = global_cfg
|
|
21
|
+
self.cfg_creation = cfg_creation or ConfigFileCreation()
|
|
22
|
+
|
|
23
|
+
def config(self, kv=(None, None), key_to_remove=None):
|
|
24
|
+
config_file_path = self._get_config_file_path(self.global_cfg)
|
|
25
|
+
if self._should_remove_key(key_to_remove):
|
|
26
|
+
context = ConfigContext(config_file_path)
|
|
27
|
+
ConfigRecord(key_to_remove).delete(context)
|
|
28
|
+
elif self._should_append_key(kv):
|
|
29
|
+
field, name = kv
|
|
30
|
+
if not name:
|
|
31
|
+
raise click.BadArgumentUsage(
|
|
32
|
+
"Field '{}' can not be empty".format(field)
|
|
33
|
+
)
|
|
34
|
+
else:
|
|
35
|
+
self.cfg_creation.create(config_file_path)
|
|
36
|
+
context = ConfigContext(config_file_path)
|
|
37
|
+
ConfigRecord(*kv).save(context)
|
|
38
|
+
else:
|
|
39
|
+
self._echo_config(config_file_path)
|
|
40
|
+
|
|
41
|
+
def _should_append_key(self, kv):
|
|
42
|
+
return None not in kv
|
|
43
|
+
|
|
44
|
+
def _should_remove_key(self, key_to_remove):
|
|
45
|
+
return key_to_remove is not None
|
|
46
|
+
|
|
47
|
+
def _echo_config(self, config_file_path):
|
|
48
|
+
|
|
49
|
+
config_data = Configuration.readall(
|
|
50
|
+
config_file_path, mark_defaults=DEFAULTS_CHAR
|
|
51
|
+
)
|
|
52
|
+
table = self._format_config_as_table(config_data, DEFAULTS_CHAR)
|
|
53
|
+
click.echo(table)
|
|
54
|
+
click.echo("")
|
|
55
|
+
click.echo(
|
|
56
|
+
"* Value marked with '{}' is actually the default value and has not been override by the user.".format( # noqa: E501
|
|
57
|
+
DEFAULTS_CHAR
|
|
58
|
+
)
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
def _format_config_as_table(self, config_data, defaults_char):
|
|
62
|
+
from shellfoundry.utilities.modifiers.configuration.password_modification import ( # noqa: E501
|
|
63
|
+
PasswordModification,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
table_data = [["Key", "Value", ""]]
|
|
67
|
+
for key, value in config_data[INSTALL].items():
|
|
68
|
+
default_val = ""
|
|
69
|
+
if defaults_char in value:
|
|
70
|
+
default_val = defaults_char
|
|
71
|
+
value = value.strip(defaults_char).lstrip()
|
|
72
|
+
if key in PasswordModification.HANDLING_KEYS:
|
|
73
|
+
value = "[encrypted]"
|
|
74
|
+
table_data.append([key, value, default_val])
|
|
75
|
+
import terminaltables
|
|
76
|
+
|
|
77
|
+
table = terminaltables.AsciiTable(table_data)
|
|
78
|
+
table.outer_border = False
|
|
79
|
+
table.inner_column_border = False
|
|
80
|
+
return table.table
|
|
81
|
+
|
|
82
|
+
@staticmethod
|
|
83
|
+
def _get_config_file_path(is_global_flag):
|
|
84
|
+
if is_global_flag:
|
|
85
|
+
cfg_provider = GlobalConfigProvider()
|
|
86
|
+
return cfg_provider.get_config_path()
|
|
87
|
+
return LocalConfigProvider().get_config_path()
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# !/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
import click
|
|
5
|
+
|
|
6
|
+
from shellfoundry.exceptions import FatalError
|
|
7
|
+
from shellfoundry.utilities.shell_package_installer import ShellPackageInstaller
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class DeleteCommandExecutor(object):
|
|
11
|
+
def __init__(self, shell_package_installer=None):
|
|
12
|
+
self.shell_package_installer = (
|
|
13
|
+
shell_package_installer or ShellPackageInstaller()
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
def delete(self, shell_name):
|
|
17
|
+
try:
|
|
18
|
+
self.shell_package_installer.delete(shell_name=shell_name)
|
|
19
|
+
except FatalError as err:
|
|
20
|
+
|
|
21
|
+
msg = err.message if hasattr(err, "message") else err.args[0]
|
|
22
|
+
click.ClickException(msg)
|
|
23
|
+
|
|
24
|
+
click.secho("Successfully deleted shell", fg="green")
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
from shellfoundry.utilities.config_reader import CloudShellConfigReader, Configuration
|
|
7
|
+
from shellfoundry.utilities.python_dependencies_packager import (
|
|
8
|
+
PythonDependenciesPackager,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class DistCommandExecutor(object):
|
|
13
|
+
def __init__(self, cloudshell_config_reader=None, dependencies_packager=None):
|
|
14
|
+
self.cloudshell_config_reader = cloudshell_config_reader or Configuration(
|
|
15
|
+
CloudShellConfigReader()
|
|
16
|
+
)
|
|
17
|
+
self.dependencies_packager = (
|
|
18
|
+
dependencies_packager or PythonDependenciesPackager()
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
def dist(self, enable_cs_repo):
|
|
22
|
+
"""Creates offline dependencies archive."""
|
|
23
|
+
current_path = os.getcwd()
|
|
24
|
+
requirements_path = os.path.join(current_path, "src", "requirements.txt")
|
|
25
|
+
dest_path = os.path.join(current_path, "dist", "offline_requirements")
|
|
26
|
+
|
|
27
|
+
if enable_cs_repo:
|
|
28
|
+
cs_server_address = self.cloudshell_config_reader.read().host
|
|
29
|
+
else:
|
|
30
|
+
cs_server_address = None
|
|
31
|
+
|
|
32
|
+
self.dependencies_packager.save_offline_dependencies(
|
|
33
|
+
requirements_path, dest_path, cs_server_address
|
|
34
|
+
)
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
import re
|
|
6
|
+
import shutil
|
|
7
|
+
|
|
8
|
+
import click
|
|
9
|
+
|
|
10
|
+
from shellfoundry.exceptions import VersionRequestException
|
|
11
|
+
from shellfoundry.utilities.config_reader import CloudShellConfigReader, Configuration
|
|
12
|
+
from shellfoundry.utilities.constants import (
|
|
13
|
+
METADATA_AUTHOR_FIELD,
|
|
14
|
+
TEMPLATE_AUTHOR_FIELD,
|
|
15
|
+
TEMPLATE_BASED_ON,
|
|
16
|
+
)
|
|
17
|
+
from shellfoundry.utilities.modifiers.definition.definition_modification import (
|
|
18
|
+
DefinitionModification,
|
|
19
|
+
)
|
|
20
|
+
from shellfoundry.utilities.repository_downloader import RepositoryDownloader
|
|
21
|
+
from shellfoundry.utilities.temp_dir_context import TempDirContext
|
|
22
|
+
from shellfoundry.utilities.validations import (
|
|
23
|
+
ShellGenerationValidations,
|
|
24
|
+
ShellNameValidations,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ExtendCommandExecutor(object):
|
|
29
|
+
LOCAL_TEMPLATE_URL_PREFIX = "local:"
|
|
30
|
+
SIGN_FILENAME = "signed"
|
|
31
|
+
ARTIFACTS = {"driver": "src", "deployment": "deployments"}
|
|
32
|
+
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
repository_downloader=None,
|
|
36
|
+
shell_name_validations=None,
|
|
37
|
+
shell_gen_validations=None,
|
|
38
|
+
):
|
|
39
|
+
"""Creates a new shell based on an already existing shell.
|
|
40
|
+
|
|
41
|
+
:param RepositoryDownloader repository_downloader:
|
|
42
|
+
:param ShellNameValidations shell_name_validations:
|
|
43
|
+
"""
|
|
44
|
+
self.repository_downloader = repository_downloader or RepositoryDownloader()
|
|
45
|
+
self.shell_name_validations = shell_name_validations or ShellNameValidations()
|
|
46
|
+
self.shell_gen_validations = (
|
|
47
|
+
shell_gen_validations or ShellGenerationValidations()
|
|
48
|
+
)
|
|
49
|
+
self.cloudshell_config_reader = Configuration(CloudShellConfigReader())
|
|
50
|
+
|
|
51
|
+
def extend(self, source, attribute_names):
|
|
52
|
+
"""Create a new shell based on an already existing shell.
|
|
53
|
+
|
|
54
|
+
:param str source: The path to the existing shell. Can be a url or local path
|
|
55
|
+
:param tuple attribute_names: Sequence of attribute names that should be added
|
|
56
|
+
"""
|
|
57
|
+
with TempDirContext("Extended_Shell_Temp_Dir") as temp_dir:
|
|
58
|
+
try:
|
|
59
|
+
if self._is_local(source):
|
|
60
|
+
temp_shell_path = self._copy_local_shell(
|
|
61
|
+
self._remove_prefix(
|
|
62
|
+
source, ExtendCommandExecutor.LOCAL_TEMPLATE_URL_PREFIX
|
|
63
|
+
),
|
|
64
|
+
temp_dir,
|
|
65
|
+
)
|
|
66
|
+
else:
|
|
67
|
+
temp_shell_path = self._copy_online_shell(source, temp_dir)
|
|
68
|
+
except VersionRequestException as err:
|
|
69
|
+
raise click.ClickException(str(err))
|
|
70
|
+
except Exception:
|
|
71
|
+
raise click.BadParameter("Check correctness of entered attributes")
|
|
72
|
+
|
|
73
|
+
# Remove shell version from folder name
|
|
74
|
+
shell_path = re.sub(r"-\d+(\.\d+)*/?$", "", temp_shell_path)
|
|
75
|
+
os.rename(temp_shell_path, shell_path)
|
|
76
|
+
|
|
77
|
+
if not self.shell_gen_validations.validate_2nd_gen(shell_path):
|
|
78
|
+
raise click.ClickException("Invalid second generation Shell.")
|
|
79
|
+
|
|
80
|
+
modificator = DefinitionModification(shell_path)
|
|
81
|
+
self._unpack_driver_archive(shell_path, modificator)
|
|
82
|
+
self._remove_quali_signature(shell_path)
|
|
83
|
+
self._change_author(shell_path, modificator)
|
|
84
|
+
self._add_based_on(shell_path, modificator)
|
|
85
|
+
self._add_attributes(shell_path, attribute_names)
|
|
86
|
+
|
|
87
|
+
try:
|
|
88
|
+
shutil.move(shell_path, os.path.curdir)
|
|
89
|
+
except shutil.Error as err:
|
|
90
|
+
raise click.BadParameter(str(err))
|
|
91
|
+
|
|
92
|
+
click.echo("Created shell based on source {}".format(source))
|
|
93
|
+
|
|
94
|
+
def _copy_local_shell(self, source, destination):
|
|
95
|
+
"""Copy shell and extract if needed."""
|
|
96
|
+
if os.path.isdir(source):
|
|
97
|
+
source = source.rstrip(os.sep)
|
|
98
|
+
name = os.path.basename(source)
|
|
99
|
+
ext_shell_path = os.path.join(destination, name)
|
|
100
|
+
shutil.copytree(source, ext_shell_path)
|
|
101
|
+
else:
|
|
102
|
+
raise
|
|
103
|
+
|
|
104
|
+
return ext_shell_path
|
|
105
|
+
|
|
106
|
+
def _copy_online_shell(self, source, destination):
|
|
107
|
+
"""Download shell and extract it."""
|
|
108
|
+
archive_path = None
|
|
109
|
+
try:
|
|
110
|
+
archive_path = self.repository_downloader.download_file(source, destination)
|
|
111
|
+
ext_shell_path = (
|
|
112
|
+
self.repository_downloader.repo_extractor.extract_to_folder(
|
|
113
|
+
archive_path, destination
|
|
114
|
+
)
|
|
115
|
+
)
|
|
116
|
+
ext_shell_path = ext_shell_path[0]
|
|
117
|
+
finally:
|
|
118
|
+
if archive_path and os.path.exists(archive_path):
|
|
119
|
+
os.remove(archive_path)
|
|
120
|
+
|
|
121
|
+
return os.path.join(destination, ext_shell_path)
|
|
122
|
+
|
|
123
|
+
@staticmethod
|
|
124
|
+
def _is_local(source):
|
|
125
|
+
return source.startswith(ExtendCommandExecutor.LOCAL_TEMPLATE_URL_PREFIX)
|
|
126
|
+
|
|
127
|
+
@staticmethod
|
|
128
|
+
def _remove_prefix(string, prefix):
|
|
129
|
+
return string.rpartition(prefix)[-1]
|
|
130
|
+
|
|
131
|
+
def _unpack_driver_archive(self, shell_path, modificator=None):
|
|
132
|
+
"""Unpack driver files from ZIP-archive."""
|
|
133
|
+
if not modificator:
|
|
134
|
+
modificator = DefinitionModification(shell_path)
|
|
135
|
+
|
|
136
|
+
artifacts = modificator.get_artifacts_files(
|
|
137
|
+
artifact_name_list=list(self.ARTIFACTS.keys())
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
for artifact_name, artifact_path in artifacts.items():
|
|
141
|
+
|
|
142
|
+
artifact_path = os.path.join(shell_path, artifact_path)
|
|
143
|
+
|
|
144
|
+
if os.path.exists(artifact_path):
|
|
145
|
+
self.repository_downloader.repo_extractor.extract_to_folder(
|
|
146
|
+
artifact_path,
|
|
147
|
+
os.path.join(shell_path, self.ARTIFACTS[artifact_name]),
|
|
148
|
+
)
|
|
149
|
+
os.remove(artifact_path)
|
|
150
|
+
|
|
151
|
+
@staticmethod
|
|
152
|
+
def _remove_quali_signature(shell_path):
|
|
153
|
+
"""Remove Quali signature from shell."""
|
|
154
|
+
signature_file_path = os.path.join(
|
|
155
|
+
shell_path, ExtendCommandExecutor.SIGN_FILENAME
|
|
156
|
+
)
|
|
157
|
+
if os.path.exists(signature_file_path):
|
|
158
|
+
os.remove(signature_file_path)
|
|
159
|
+
|
|
160
|
+
def _change_author(self, shell_path, modificator=None):
|
|
161
|
+
"""Change shell authoring."""
|
|
162
|
+
author = self.cloudshell_config_reader.read().author
|
|
163
|
+
|
|
164
|
+
if not modificator:
|
|
165
|
+
modificator = DefinitionModification(shell_path)
|
|
166
|
+
|
|
167
|
+
modificator.edit_definition(field=TEMPLATE_AUTHOR_FIELD, value=author)
|
|
168
|
+
modificator.edit_tosca_meta(field=METADATA_AUTHOR_FIELD, value=author)
|
|
169
|
+
|
|
170
|
+
def _add_based_on(self, shell_path, modificator=None):
|
|
171
|
+
"""Add Based_ON field to shell-definition.yaml file."""
|
|
172
|
+
if not modificator:
|
|
173
|
+
modificator = DefinitionModification(shell_path)
|
|
174
|
+
|
|
175
|
+
modificator.add_field_to_definition(field=TEMPLATE_BASED_ON)
|
|
176
|
+
|
|
177
|
+
def _add_attributes(self, shell_path, attribute_names, modificator=None):
|
|
178
|
+
"""Add a commented out attributes to the shell definition."""
|
|
179
|
+
if not modificator:
|
|
180
|
+
modificator = DefinitionModification(shell_path)
|
|
181
|
+
|
|
182
|
+
modificator.add_properties(attribute_names=attribute_names)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
from os import path
|
|
6
|
+
|
|
7
|
+
import click
|
|
8
|
+
|
|
9
|
+
from shellfoundry.utilities.config_reader import CloudShellConfigReader, Configuration
|
|
10
|
+
from shellfoundry.utilities.driver_generator import DriverGenerator
|
|
11
|
+
from shellfoundry.utilities.shell_package import ShellPackage
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class GenerateCommandExecutor(object):
|
|
15
|
+
def __init__(self, cloudshell_config_reader=None, driver_generator=None):
|
|
16
|
+
self.cloudshell_config_reader = cloudshell_config_reader or Configuration(
|
|
17
|
+
CloudShellConfigReader()
|
|
18
|
+
)
|
|
19
|
+
self.driver_generator = driver_generator or DriverGenerator()
|
|
20
|
+
|
|
21
|
+
def generate(self):
|
|
22
|
+
"""Generates Python driver by connecting to CloudShell server."""
|
|
23
|
+
current_path = os.getcwd()
|
|
24
|
+
shell_package = ShellPackage(current_path)
|
|
25
|
+
if not shell_package.is_tosca():
|
|
26
|
+
click.echo("Code generation supported in TOSCA based shells only", err=True)
|
|
27
|
+
return
|
|
28
|
+
|
|
29
|
+
shell_name = shell_package.get_name_from_definition()
|
|
30
|
+
shell_filename = shell_name + ".zip"
|
|
31
|
+
package_full_path = path.join(current_path, "dist", shell_filename)
|
|
32
|
+
destination_path = path.join(current_path, "src")
|
|
33
|
+
|
|
34
|
+
cloudshell_config = self.cloudshell_config_reader.read()
|
|
35
|
+
|
|
36
|
+
click.echo("Connecting to Cloudshell server ...")
|
|
37
|
+
|
|
38
|
+
self.driver_generator.generate_driver(
|
|
39
|
+
cloudshell_config=cloudshell_config,
|
|
40
|
+
destination_path=destination_path,
|
|
41
|
+
package_full_path=package_full_path,
|
|
42
|
+
shell_filename=shell_filename,
|
|
43
|
+
shell_name=shell_name,
|
|
44
|
+
)
|