PK!2ךsnakeless/__init__.pyimport sys from .cli_controller import SnakelessCli def main(argv=sys.argv[1:]): snakeless_cli = SnakelessCli() return snakeless_cli.run(argv) PK! <]]snakeless/__main__.pyimport sys from . import main if __name__ == '__main__': sys.exit(main(sys.argv[1:])) PK! jKKsnakeless/cli_controller.pyfrom cliff import help as cliff_help from cliff.app import App from cliff.commandmanager import CommandManager class SnakelessCli(App): def __init__(self): super().__init__( description="Snakeless CLI", version="0.3.0", command_manager=CommandManager("snakeless.cli"), deferred_help=True, ) def initialize_app(self, argv): if self.interactive_mode: # disable interactive mode action = cliff_help.HelpAction(None, None, default=self) action(self.parser, self.options, None, None) PK!Mccsnakeless/commands/__init__.pyfrom .check import Check # noqa from .deploy import Deploy # noqa from .init import Init # noqa PK!V))snakeless/commands/check.pyimport logging import fs from cliff.command import Command from schema import SchemaError from ..constants import CURRENT_DIR from ..helpers import ( check_config_existence, snakeless_spinner, parse_config ) from ..exceptions import CommandFailure class Check(Command): "A health-check of your snakeless setup" logger = logging.getLogger(__name__) def check_config_existence(self, root_fs): with snakeless_spinner( text="Checking the config existence.", spinner="dots" ) as spinner: config_file_exists = check_config_existence(root_fs) if not config_file_exists: raise CommandFailure("Config was not found.") else: spinner.succeed("Config was found.") def validate_config(self, root_fs): with snakeless_spinner( text="Validating the config file.", spinner="dots" ) as spinner: try: parse_config(root_fs) except fs.errors.ResourceNotFound: raise CommandFailure("Config does not anymore exist.") except SchemaError: raise CommandFailure("Config validation failed") else: spinner.succeed("Config is valid.") def take_action(self, parsed_args): with fs.open_fs(CURRENT_DIR) as root_fs: try: self.check_config_existence(root_fs) self.validate_config(root_fs) except Exception as exc: self.logger.exception(exc, exc_info=True) PK!1oQsnakeless/commands/deploy.pyimport logging import fs from cliff.command import Command from ..constants import CURRENT_DIR from ..mixins import ConfigLoaderMixin, DeployerMixin class Deploy(Command, DeployerMixin, ConfigLoaderMixin): "Deploy some functions or all of them" logger = logging.getLogger(__name__) def get_parser(self, prog_name): parser = super().get_parser(prog_name) parser.add_argument( "-f", "--functions", nargs="*", help="A list of functions' names" ) return parser def take_action(self, parsed_args): parsed_args = vars(parsed_args) functions_to_deploy = parsed_args.get("functions", []) with fs.open_fs(CURRENT_DIR) as root_fs: try: config = self.load_config(root_fs) if not functions_to_deploy: functions_to_deploy = config["functions"].keys() self.deploy_functions(config, functions_to_deploy) except Exception as exc: self.logger.exception(exc, exc_info=True) PK! snakeless/commands/init.pyimport logging import fs from cliff.command import Command from ..constants import BASE_CONFIG_EXAMPLE, CURRENT_DIR from ..exceptions import CommandFailure from ..helpers import (check_config_existence, get_config_example, get_providers, snakeless_spinner) class Init(Command): "Create initial snakeless.yml configuration" logger = logging.getLogger(__name__) def get_parser(self, prog_name): parser = super().get_parser(prog_name) parser.add_argument( "-f", "--force", action="store_true", help="Rewrite current config if it exists", ) available_providers = ["base"] + list(get_providers().keys()) parser.add_argument( "-p", "--provider", default="base", choices=available_providers, help="Which provider's example we should use", ) return parser def check_config_existence(self, root_fs): with snakeless_spinner( text="Checking the config existence.", spinner="dots" ) as spinner: config_file_exists = check_config_existence(root_fs) if config_file_exists: raise CommandFailure("Config was found. Ignore it with -f") else: spinner.succeed("Config was not found.") def create_configuration(self, root_fs, provider): with snakeless_spinner( text="Creating configuration", spinner="dots" ) as spinner: if provider == "base": config_example = BASE_CONFIG_EXAMPLE else: try: config_example = get_config_example(provider) except KeyError: raise CommandFailure("Plugin doesn't provide example config") root_fs.writetext("snakeless.yml", config_example) spinner.succeed("Config was created") def take_action(self, parsed_args): parsed_args = vars(parsed_args) ignore_config = parsed_args.get("force", False) provider = parsed_args.get("provider", "base") with fs.open_fs(CURRENT_DIR) as root_fs: try: if not ignore_config: self.check_config_existence(root_fs) self.create_configuration(root_fs, provider) except Exception as exc: self.logger.exception(exc, exc_info=True) PK!!Gu{{snakeless/constants.pyimport os CURRENT_DIR = os.getcwd() BASE_CONFIG_EXAMPLE = """project: name: your-name provider: your-provider """ PK!E**snakeless/exceptions.pyclass CommandFailure(Exception): pass PK!H r snakeless/helpers.pyfrom contextlib import contextmanager from functools import lru_cache from halo import Halo from pkg_resources import iter_entry_points from schema import And, Optional, Schema, Use from yaml import load from .exceptions import CommandFailure try: from yaml import CLoader as Loader except ImportError: from yaml import Loader @contextmanager def snakeless_spinner(*args, **kwargs): spinner = Halo(*args, **kwargs) spinner.start() try: yield spinner except CommandFailure as exc: spinner.fail(str(exc)) raise except Exception as exc: spinner.fail(spinner.text + "\n" + "Unexpected exception.") raise finally: spinner.stop() def check_config_existence(root_fs, file_name="snakeless.yml"): return root_fs.exists(file_name) @lru_cache() def get_providers(): providers = {} for entry_point in iter_entry_points("snakeless.providers"): providers[entry_point.name] = entry_point.load() return providers @lru_cache() def get_schemas(): schemas = {} for entry_point in iter_entry_points("snakeless.schemas"): schemas[entry_point.name] = entry_point.load() return schemas def get_provider(provider_name, config): providers = get_providers() return providers[provider_name](config) @lru_cache(maxsize=None) def get_schema(provider_name): providers = get_providers() supported_providers = providers.keys() base_schema = { "project": { "name": str, "provider": And( Use(str), lambda provider: provider in supported_providers, error="Unsupported provider", ), } } schemas = get_schemas() provider_schema = schemas[provider_name] return merge(base_schema, provider_schema) @lru_cache() def get_config_examples(): examples = {} for entry_point in iter_entry_points("snakeless.examples"): examples[entry_point.name] = entry_point.load() return examples def get_config_example(provider_name): config_examples = get_config_examples() return config_examples[provider_name] def parse_config(root_fs, file_name="snakeless.yml"): config_file_data = root_fs.readtext("snakeless.yml") raw_parsed_config = load(config_file_data, Loader=Loader) try: provider_name = raw_parsed_config["project"]["provider"] except KeyError: raise else: try: provider_schema = get_schema(provider_name) except KeyError: raise CommandFailure("Plugin for that provider is not available") validator = Schema(provider_schema, ignore_extra_keys=True) parse_config = validator.validate(raw_parsed_config) # TODO: validate a few more fields mannualy return parse_config def merge(source, destination): for key, value in source.items(): if isinstance(value, dict): node = destination.setdefault(key, {}) merge(value, node) else: destination[key] = value return destination PK!8x{``snakeless/mixins/__init__.pyfrom .deployer import DeployerMixin # noqa from .config_loader import ConfigLoaderMixin # noqaPK!Cx!snakeless/mixins/config_loader.pyimport fs from schema import SchemaError from ..helpers import snakeless_spinner, parse_config from ..exceptions import CommandFailure class ConfigLoaderMixin(object): def load_config(self, root_fs): with snakeless_spinner( text="Loading the config file...", spinner="dots" ) as spinner: try: config = parse_config(root_fs) except fs.errors.ResourceNotFound: raise CommandFailure("Config does not exist.") except SchemaError as exc: raise CommandFailure("Config validation failed.") else: spinner.succeed("The config file was loaded.") return config PK!5snakeless/mixins/deployer.pyfrom ..helpers import snakeless_spinner, get_provider class DeployerMixin(object): def deploy_functions(self, config, functions_to_deploy): with snakeless_spinner( text="Deploying functions...", spinner="dots" ) as spinner: provider_name = config["project"]["provider"] provider = get_provider(provider_name, config) for function_to_deploy in functions_to_deploy: spinner.text = ( f"Deploying the { function_to_deploy } function..." ) provider.deploy_function(function_to_deploy) spinner.succeed("All functions were deployed!") PK!snakeless/providers/__init__.pyPK!4ɛpK>X;baP>PK!H$H]"snakeless-0.3.0.dist-info/METADATAUn7}W>Dwe[A nPFRrkN( zwb%)w?/됫8[OZqeoIY3P"[5:n GBD #xPal'~-N6ppذ-ޗm7:72MU{11,{40YJc[lI')/Qyc,Qy?ӒHrNvukKo/V4o=S[|yM\QHƏSx>TZ {2z2~y!M<:?ɿG_Z=M?0Dՙt@?aW1\K̚&7Gr}bNpsZWk6%-JesjҔl[5)oz7xahvݲBB}Ѭ]x{{u@1R!,dX q7vPӶkX`_p{};-JbRlt\_:u;FF}*reUWjGS*t =}|ydCvUgɐ1Ewm83mc۝[݋J>3I>F;Yw(CQb,ut@FOIة5D/Fʠ*uDz&\5$JuK?nl Jcve0Q.yTI9Z>\x`MufM3P-%oEgZ rhX{xLS&] dVCf38X|} 9.Q[bK&_y= ˵mO,45cK'MB|! ~9Yȉy޵% 8LVX;EENI,Ko^}7<_o7PK!Hk_ snakeless-0.3.0.dist-info/RECORD}ɲH}= b`P@( "<}[Q(^˓'{ՠ}3M+X iX_fi6K$41/iPquؑنEIQHѯ67 Y+r2ajB {/dZDze]* 8T \օ*2I0Vf@=^ռ&rihZ =-؝6t#>+0wӒf#܆3Lzo즠;Ha*N|_W^^dN;T*~R漱x'nXr1:o1ey> ;Sќ@ ~A!Y@^0YN8!zt}cM{A9/rdhk>=mt}}/̤FS!$d[ BIB$'HK‡ykN\6dwvK >9hM(!B*PK!2ךsnakeless/__init__.pyPK! <]]snakeless/__main__.pyPK! jKK]snakeless/cli_controller.pyPK!Mccsnakeless/commands/__init__.pyPK!V))snakeless/commands/check.pyPK!1oQ snakeless/commands/deploy.pyPK! ;snakeless/commands/init.pyPK!!Gu{{snakeless/constants.pyPK!E**snakeless/exceptions.pyPK!H r 'snakeless/helpers.pyPK!8x{``e&snakeless/mixins/__init__.pyPK!Cx!&snakeless/mixins/config_loader.pyPK!5*snakeless/mixins/deployer.pyPK!,snakeless/providers/__init__.pyPK!snakeless-0.3.0.dist-info/RECORDPKHB