Compare commits
	
		
			5 Commits 
		
	
	
		
			d0e6473d39
			...
			7a64eeff09
		
	
	| Author | SHA1 | Date | 
|---|---|---|
|  | 7a64eeff09 | 3 years ago | 
|  | 85f7d8f792 | 3 years ago | 
|  | 29f8670d61 | 3 years ago | 
|  | 525a866e2b | 3 years ago | 
|  | 59add82e4c | 3 years ago | 
				 65 changed files with 1059 additions and 4346 deletions
			
			
		| @ -0,0 +1 @@ | |||||||
|  | 7.0.0-a | ||||||
| @ -1 +1 @@ | |||||||
| 6.8.26 | 7.0.0 | ||||||
| @ -1,84 +0,0 @@ | |||||||
| # Imports |  | ||||||
| 
 |  | ||||||
| import logging |  | ||||||
| from importlib import import_module |  | ||||||
| from .constants import LOGGER_NAME |  | ||||||
| from .library.commands import ItemizedCommand |  | ||||||
| 
 |  | ||||||
| log = logging.getLogger(LOGGER_NAME) |  | ||||||
| 
 |  | ||||||
| # Exports |  | ||||||
| 
 |  | ||||||
| __all__ = ( |  | ||||||
|     "Factory", |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| # Classes |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Factory(object): |  | ||||||
|     """A command factory.""" |  | ||||||
| 
 |  | ||||||
|     def __init__(self, overlay): |  | ||||||
|         """Initialize the factory. |  | ||||||
| 
 |  | ||||||
|         :param overlay: The name of the overlay to use for generating commands. |  | ||||||
|         :type overlay: str |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         self.is_loaded = False |  | ||||||
|         self.overlay = None |  | ||||||
|         self._overlay = overlay |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         return "<%s %s>" % (self.__class__.__name__, self._overlay) |  | ||||||
| 
 |  | ||||||
|     def get_command(self, name, *args, **kwargs): |  | ||||||
|         """Get a command. |  | ||||||
| 
 |  | ||||||
|         :param name: The name of the command. |  | ||||||
|         :type name: str |  | ||||||
| 
 |  | ||||||
|         args and kwargs are passed to the initialize the command. |  | ||||||
| 
 |  | ||||||
|         :rtype: scripttease.library.commands.Command | scripttease.library.commands.ItemizedCommand |  | ||||||
| 
 |  | ||||||
|         :raise: RuntimeError |  | ||||||
|         :raises: ``RuntimeError`` if the factory has not yet been loaded. |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         if not self.is_loaded: |  | ||||||
|             raise RuntimeError("Factory has not been loaded, so no commands are available. Call load() method first!") |  | ||||||
| 
 |  | ||||||
|         if not self.overlay.command_exists(name): |  | ||||||
|             log.warning("Command does not exist in %s overlay: %s" % (self._overlay, name)) |  | ||||||
|             return None |  | ||||||
| 
 |  | ||||||
|         callback = self.overlay.MAPPINGS[name] |  | ||||||
| 
 |  | ||||||
|         try: |  | ||||||
|             items = kwargs.pop("items", None) |  | ||||||
|             if items is not None: |  | ||||||
|                 return ItemizedCommand(callback, items, *args, name=name, **kwargs) |  | ||||||
| 
 |  | ||||||
|             command = callback(*args, **kwargs) |  | ||||||
|             command.name = name |  | ||||||
|             return command |  | ||||||
|         except (KeyError, NameError, TypeError, ValueError) as e: |  | ||||||
|             log.critical("Failed to load %s command: %s" % (name, e)) |  | ||||||
|             return None |  | ||||||
| 
 |  | ||||||
|     def load(self): |  | ||||||
|         """Load the factory. |  | ||||||
| 
 |  | ||||||
|         :rtype: bool |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         try: |  | ||||||
|             self.overlay = import_module("scripttease.library.overlays.%s" % self._overlay) |  | ||||||
|             self.is_loaded = True |  | ||||||
|         except ImportError as e: |  | ||||||
|             log.error("The %s overlay could not be imported: %s" % (self._overlay, str(e))) |  | ||||||
|             pass |  | ||||||
| 
 |  | ||||||
|         return self.is_loaded |  | ||||||
| @ -1 +0,0 @@ | |||||||
| from .commands.posix import POSIX_MAPPINGS |  | ||||||
| @ -1,3 +0,0 @@ | |||||||
| from .base import Command, ItemizedCommand |  | ||||||
| from .templates import Template |  | ||||||
| # from .factory import command_factory |  | ||||||
| @ -1,309 +0,0 @@ | |||||||
| # Classes |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Command(object): |  | ||||||
|     """A command line statement.""" |  | ||||||
| 
 |  | ||||||
|     def __init__(self, statement, comment=None, condition=None, cd=None, environments=None, function=None, name=None, |  | ||||||
|                  prefix=None, register=None, shell=None, stop=False, sudo=None, tags=None, **kwargs): |  | ||||||
|         """Initialize a command. |  | ||||||
| 
 |  | ||||||
|         :param statement: The statement to be executed. |  | ||||||
|         :type statement: str |  | ||||||
| 
 |  | ||||||
|         :param comment: A comment regarding the statement. |  | ||||||
|         :type comment: str |  | ||||||
| 
 |  | ||||||
|         :param condition: A (system-specific) condition for the statement to be executed. |  | ||||||
|         :type condition: str |  | ||||||
| 
 |  | ||||||
|         :param cd: The direction from which the statement should be executed. |  | ||||||
|         :type cd: str |  | ||||||
| 
 |  | ||||||
|         :param environments: A list of target environments where the statement should be executed. |  | ||||||
|         :type environments: list[str] |  | ||||||
| 
 |  | ||||||
|         :param function: The name of the function in which the statement is executed. |  | ||||||
|         :type function: str |  | ||||||
| 
 |  | ||||||
|         :param name: The name of the command from the mapping. Not used and not required for programmatic use, but |  | ||||||
|                      automatically assigned during factory instantiation. |  | ||||||
|         :type name: str |  | ||||||
| 
 |  | ||||||
|         :param prefix: A statement to execute before the main statement is executed. |  | ||||||
|         :type prefix: str |  | ||||||
| 
 |  | ||||||
|         :param register: A variable name to use for capture the success for failure of the statement's execution. |  | ||||||
|         :type register: str |  | ||||||
| 
 |  | ||||||
|         :param shell: The shell execute through which the statement is executed. |  | ||||||
|         :type shell: str |  | ||||||
| 
 |  | ||||||
|         :param stop: Indicates process should stop if the statement fails to execute. |  | ||||||
|         :type stop: bool | None |  | ||||||
| 
 |  | ||||||
|         :param sudo: Indicates whether sudo should be invoked for the statement. Given as a bool or user name or |  | ||||||
|                      :py:class:`scripttease.library.commands.base.Sudo` instance. |  | ||||||
|         :type sudo: bool | str | Sudo |  | ||||||
| 
 |  | ||||||
|         :param tags: A list of tags describing the statement. |  | ||||||
|         :type tags: list[str] |  | ||||||
| 
 |  | ||||||
|         Additional kwargs are available as dynamic attributes of the Command instance. |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         self.comment = comment |  | ||||||
|         self.condition = condition |  | ||||||
|         self.cd = cd |  | ||||||
|         self.environments = environments or list() |  | ||||||
|         self.function = function |  | ||||||
|         self.name = name |  | ||||||
|         self.prefix = prefix |  | ||||||
|         self.register = register |  | ||||||
|         self.shell = shell |  | ||||||
|         self.statement = statement |  | ||||||
|         self.stop = stop |  | ||||||
|         self.tags = tags or list() |  | ||||||
| 
 |  | ||||||
|         if isinstance(sudo, Sudo): |  | ||||||
|             self.sudo = sudo |  | ||||||
|         elif type(sudo) is str: |  | ||||||
|             self.sudo = Sudo(enabled=True, user=sudo) |  | ||||||
|         elif sudo is True: |  | ||||||
|             self.sudo = Sudo(enabled=True) |  | ||||||
|         else: |  | ||||||
|             self.sudo = Sudo() |  | ||||||
| 
 |  | ||||||
|         self._attributes = kwargs |  | ||||||
| 
 |  | ||||||
|     def __getattr__(self, item): |  | ||||||
|         return self._attributes.get(item) |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         if self.comment is not None: |  | ||||||
|             return "<%s %s>" % (self.__class__.__name__, self.comment) |  | ||||||
| 
 |  | ||||||
|         return "<%s>" % self.__class__.__name__ |  | ||||||
| 
 |  | ||||||
|     def get_statement(self, cd=False, suppress_comment=False): |  | ||||||
|         """Get the full statement. |  | ||||||
| 
 |  | ||||||
|         :param cd: Include the directory change, if given. |  | ||||||
|         :type cd: bool |  | ||||||
| 
 |  | ||||||
|         :param suppress_comment: Don't include the comment. |  | ||||||
|         :type suppress_comment: bool |  | ||||||
| 
 |  | ||||||
|         :rtype: str |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         a = list() |  | ||||||
| 
 |  | ||||||
|         if cd and self.cd is not None: |  | ||||||
|             a.append("( cd %s &&" % self.cd) |  | ||||||
| 
 |  | ||||||
|         if self.prefix is not None: |  | ||||||
|             a.append("%s &&" % self.prefix) |  | ||||||
| 
 |  | ||||||
|         if self.sudo: |  | ||||||
|             statement = "%s %s" % (self.sudo, self._get_statement()) |  | ||||||
|         else: |  | ||||||
|             statement = self._get_statement() |  | ||||||
| 
 |  | ||||||
|         a.append("%s" % statement) |  | ||||||
| 
 |  | ||||||
|         if cd and self.cd is not None: |  | ||||||
|             a.append(")") |  | ||||||
| 
 |  | ||||||
|         b = list() |  | ||||||
|         if self.comment is not None and not suppress_comment: |  | ||||||
|             b.append("# %s" % self.comment) |  | ||||||
| 
 |  | ||||||
|         if self.condition is not None: |  | ||||||
|             b.append("if [[ %s ]]; then %s; fi;" % (self.condition, " ".join(a))) |  | ||||||
|         else: |  | ||||||
|             b.append(" ".join(a)) |  | ||||||
| 
 |  | ||||||
|         if self.register is not None: |  | ||||||
|             b.append("%s=$?;" % self.register) |  | ||||||
| 
 |  | ||||||
|             if self.stop: |  | ||||||
|                 b.append("if [[ $%s -gt 0 ]]; exit 1; fi;" % self.register) |  | ||||||
|         elif self.stop: |  | ||||||
|             b.append("if [[ $? -gt 0 ]]; exit 1; fi;") |  | ||||||
|         else: |  | ||||||
|             pass |  | ||||||
| 
 |  | ||||||
|         return "\n".join(b) |  | ||||||
| 
 |  | ||||||
|     def has_attribute(self, name): |  | ||||||
|         """Indicates whether the command has the named, dynamic attribute. |  | ||||||
| 
 |  | ||||||
|         :param name: The name of the attribute to be checked. |  | ||||||
|         :type name: str |  | ||||||
| 
 |  | ||||||
|         :rtype: bool |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         return name in self._attributes |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def is_itemized(self): |  | ||||||
|         """Always returns ``False``.""" |  | ||||||
|         return False |  | ||||||
| 
 |  | ||||||
|     def set_attribute(self, name, value): |  | ||||||
|         """Set the value of a dynamic attribute. |  | ||||||
| 
 |  | ||||||
|         :param name: The name of the attribute. |  | ||||||
|         :type name: str |  | ||||||
| 
 |  | ||||||
|         :param value: The value of the attribute. |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         self._attributes[name] = value |  | ||||||
| 
 |  | ||||||
|     def _get_statement(self): |  | ||||||
|         """By default, get the statement passed upon command initialization. |  | ||||||
| 
 |  | ||||||
|         :rtype: str |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         return self.statement |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class ItemizedCommand(object): |  | ||||||
|     """An itemized command represents multiple commands of with the same statement but different parameters.""" |  | ||||||
| 
 |  | ||||||
|     def __init__(self, callback, items, *args, name=None, **kwargs): |  | ||||||
|         """Initialize the command. |  | ||||||
| 
 |  | ||||||
|         :param callback: The function to be used to generate the command. |  | ||||||
| 
 |  | ||||||
|         :param items: The command arguments. |  | ||||||
|         :type items: list[str] |  | ||||||
| 
 |  | ||||||
|         :param name: The name of the command from the mapping. Not used and not required for programmatic use, but |  | ||||||
|                      automatically assigned during factory instantiation. |  | ||||||
|         :type name: str |  | ||||||
| 
 |  | ||||||
|         :param args: The itemized arguments. ``$item`` should be included. |  | ||||||
| 
 |  | ||||||
|         Keyword arguments are passed to the command class upon instantiation. |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         self.args = args |  | ||||||
|         self.callback = callback |  | ||||||
|         self.items = items |  | ||||||
|         self.kwargs = kwargs |  | ||||||
|         self.name = name |  | ||||||
| 
 |  | ||||||
|         # Set defaults for when ItemizedCommand is referenced directly before individual commands are instantiated. For |  | ||||||
|         # example, when command filtering occurs. |  | ||||||
|         self.kwargs.setdefault("environments", list()) |  | ||||||
|         self.kwargs.setdefault("tags", list()) |  | ||||||
| 
 |  | ||||||
|     def __getattr__(self, item): |  | ||||||
|         return self.kwargs.get(item) |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         return "<%s %s>" % (self.__class__.__name__, self.callback.__name__) |  | ||||||
| 
 |  | ||||||
|     def get_commands(self): |  | ||||||
|         """Get the commands to be executed. |  | ||||||
| 
 |  | ||||||
|         :rtype: list[BaseType(Command)] |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         kwargs = self.kwargs.copy() |  | ||||||
| 
 |  | ||||||
|         a = list() |  | ||||||
|         for item in self.items: |  | ||||||
|             args = list() |  | ||||||
|             for arg in self.args: |  | ||||||
|                 args.append(arg.replace("$item", item)) |  | ||||||
| 
 |  | ||||||
|             command = self.callback(*args, **kwargs) |  | ||||||
|             a.append(command) |  | ||||||
| 
 |  | ||||||
|         return a |  | ||||||
| 
 |  | ||||||
|     def get_statement(self, cd=False, suppress_comment=False): |  | ||||||
|         """Override to get multiple commands.""" |  | ||||||
|         kwargs = self.kwargs.copy() |  | ||||||
|         comment = kwargs.pop("comment", "execute multiple commands") |  | ||||||
| 
 |  | ||||||
|         a = list() |  | ||||||
|         # a.append("# %s" % comment) |  | ||||||
| 
 |  | ||||||
|         commands = self.get_commands() |  | ||||||
|         for c in commands: |  | ||||||
|             a.append(c.get_statement(cd=cd, suppress_comment=suppress_comment)) |  | ||||||
|             a.append("") |  | ||||||
| 
 |  | ||||||
|         # for item in self.items: |  | ||||||
|         #     args = list() |  | ||||||
|         #     for arg in self.args: |  | ||||||
|         #         args.append(arg.replace("$item", item)) |  | ||||||
|         # |  | ||||||
|         #     command = self.command_class(*args, **kwargs) |  | ||||||
|         #     a.append(command.preview(cwd=cwd)) |  | ||||||
|         #     a.append("") |  | ||||||
| 
 |  | ||||||
|         return "\n".join(a) |  | ||||||
| 
 |  | ||||||
|     def has_attribute(self, name): |  | ||||||
|         """Indicates whether the command has the named, dynamic attribute. |  | ||||||
| 
 |  | ||||||
|         :param name: The name of the attribute to be checked. |  | ||||||
|         :type name: str |  | ||||||
| 
 |  | ||||||
|         :rtype: bool |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         return name in self.kwargs |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def is_itemized(self): |  | ||||||
|         """Always returns ``True``.""" |  | ||||||
|         return True |  | ||||||
| 
 |  | ||||||
|     def set_attribute(self, name, value): |  | ||||||
|         """Set the value of a dynamic attribute. |  | ||||||
| 
 |  | ||||||
|         :param name: The name of the attribute. |  | ||||||
|         :type name: str |  | ||||||
| 
 |  | ||||||
|         :param value: The value of the attribute. |  | ||||||
| 
 |  | ||||||
|         .. note:: |  | ||||||
|             This is applied to all command in the itemized list. |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         self.kwargs[name] = value |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Sudo(object): |  | ||||||
|     """Helper class for defining sudo options.""" |  | ||||||
| 
 |  | ||||||
|     def __init__(self, enabled=False, user="root"): |  | ||||||
|         """Initialize the helper. |  | ||||||
| 
 |  | ||||||
|         :param enabled: Indicates sudo is enabled. |  | ||||||
|         :type enabled: bool |  | ||||||
| 
 |  | ||||||
|         :param user: The user to be invoked. |  | ||||||
|         :type user: str |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         self.enabled = enabled |  | ||||||
|         self.user = user |  | ||||||
| 
 |  | ||||||
|     def __bool__(self): |  | ||||||
|         return self.enabled |  | ||||||
| 
 |  | ||||||
|     def __str__(self): |  | ||||||
|         if self.enabled: |  | ||||||
|             return "sudo -u %s" % self.user |  | ||||||
| 
 |  | ||||||
|         return "" |  | ||||||
| @ -1,197 +0,0 @@ | |||||||
| # Imports |  | ||||||
| 
 |  | ||||||
| from commonkit import parse_jinja_template, read_file |  | ||||||
| from jinja2.exceptions import TemplateError, TemplateNotFound |  | ||||||
| import logging |  | ||||||
| import os |  | ||||||
| from ...constants import LOGGER_NAME |  | ||||||
| from .base import Command |  | ||||||
| 
 |  | ||||||
| log = logging.getLogger(LOGGER_NAME) |  | ||||||
| 
 |  | ||||||
| # Exports |  | ||||||
| 
 |  | ||||||
| __all__ = ( |  | ||||||
|     "Template", |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| # Classes |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Template(Command): |  | ||||||
|     """Parse a template.""" |  | ||||||
| 
 |  | ||||||
|     PARSER_JINJA = "jinja2" |  | ||||||
|     PARSER_SIMPLE = "simple" |  | ||||||
| 
 |  | ||||||
|     def __init__(self, source, target, backup=True, lines=False, parser=PARSER_JINJA, pythonic=False, **kwargs): |  | ||||||
|         """Initialize the command. |  | ||||||
| 
 |  | ||||||
|         :param source: The template source file. |  | ||||||
|         :type source: str |  | ||||||
| 
 |  | ||||||
|         :param target: The path to the output file. |  | ||||||
|         :type target: str |  | ||||||
| 
 |  | ||||||
|         :param backup: Indicates a copy of an existing file should be madee. |  | ||||||
|         :type backup: bool |  | ||||||
| 
 |  | ||||||
|         :param parser: The parser to use. |  | ||||||
|         :type parser: str |  | ||||||
| 
 |  | ||||||
|         :param pythonic: Use a Python one-liner to write the file. Requires Python installation, obviously. This is |  | ||||||
|                          useful when the content of the file cannot be handled with a cat command; for example, shell |  | ||||||
|                          script templates. |  | ||||||
|         :type pythonic: bool |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         # Base parameters need to be captured, because all others are assumed to be switches for the management command. |  | ||||||
|         self._kwargs = { |  | ||||||
|             'comment': kwargs.pop("comment", None), |  | ||||||
|             'cd': kwargs.pop("cd", None), |  | ||||||
|             'environments': kwargs.pop("environments", None), |  | ||||||
|             'function': kwargs.pop("function", None), |  | ||||||
|             # 'local': kwargs.pop("local", False), |  | ||||||
|             'name': "template", |  | ||||||
|             'prefix': kwargs.pop("prefix", None), |  | ||||||
|             'shell': kwargs.pop("shell", "/bin/bash"), |  | ||||||
|             'stop': kwargs.pop("stop", False), |  | ||||||
|             'sudo': kwargs.pop('sudo', False), |  | ||||||
|             'tags': kwargs.pop("tags", None), |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         self.backup_enabled = backup |  | ||||||
|         self.context = kwargs.pop("context", dict()) |  | ||||||
|         self.parser = parser or self.PARSER_JINJA |  | ||||||
|         self.pythonic = pythonic |  | ||||||
|         self.line_by_line = lines |  | ||||||
|         self.locations = kwargs.pop("locations", list()) |  | ||||||
|         self.source = os.path.expanduser(source) |  | ||||||
|         self.target = target |  | ||||||
| 
 |  | ||||||
|         # Remaining kwargs are added to the context. |  | ||||||
|         # print(_kwargs['comment'], kwargs) |  | ||||||
|         self.context.update(kwargs) |  | ||||||
| 
 |  | ||||||
|         super().__init__("# template: %s" % source, **self._kwargs) |  | ||||||
| 
 |  | ||||||
|     def get_content(self): |  | ||||||
|         """Parse the template. |  | ||||||
| 
 |  | ||||||
|         :rtype: str | None |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         template = self.get_template() |  | ||||||
| 
 |  | ||||||
|         if self.parser == self.PARSER_SIMPLE: |  | ||||||
|             content = read_file(template) |  | ||||||
|             for key, value in self.context.items(): |  | ||||||
|                 replace = "$%s$" % key |  | ||||||
|                 content = content.replace(replace, str(value)) |  | ||||||
| 
 |  | ||||||
|             return content |  | ||||||
| 
 |  | ||||||
|         try: |  | ||||||
|             return parse_jinja_template(template, self.context) |  | ||||||
|         except TemplateNotFound: |  | ||||||
|             log.error("Template not found: %s" % template) |  | ||||||
|             return None |  | ||||||
|         except TemplateError as e: |  | ||||||
|             log.error("Could not parse %s template: %s" % (template, e)) |  | ||||||
|             return None |  | ||||||
| 
 |  | ||||||
|     def get_statement(self, cd=False, suppress_comment=False): |  | ||||||
|         """Override to get the statement based on the parser.""" |  | ||||||
|         if self.parser == self.PARSER_JINJA: |  | ||||||
|             return self._get_jinja2_statement(cd=cd).statement |  | ||||||
|         elif self.parser == self.PARSER_SIMPLE: |  | ||||||
|             return self._get_simple_statement(cd=cd).statement |  | ||||||
|         else: |  | ||||||
|             log.error("Unknown or unsupported template parser: %s" % self.parser) |  | ||||||
|             return None |  | ||||||
| 
 |  | ||||||
|     def get_template(self): |  | ||||||
|         """Get the template path. |  | ||||||
| 
 |  | ||||||
|         :rtype: str |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         source = self.source |  | ||||||
|         for location in self.locations: |  | ||||||
|             _source = os.path.join(location, self.source) |  | ||||||
|             if os.path.exists(_source): |  | ||||||
|                 return _source |  | ||||||
| 
 |  | ||||||
|         return source |  | ||||||
| 
 |  | ||||||
|     def _get_command(self, content): |  | ||||||
|         """Get the cat command.""" |  | ||||||
|         output = list() |  | ||||||
| 
 |  | ||||||
|         # TODO: Template backup is not system safe, but is specific to bash. |  | ||||||
|         if self.backup_enabled: |  | ||||||
|             output.append('if [[ -f "%s" ]]; then mv %s %s.b; fi;' % (self.target, self.target, self.target)) |  | ||||||
| 
 |  | ||||||
|         if content.startswith("#!"): |  | ||||||
|             _content = content.split("\n") |  | ||||||
|             first_line = _content.pop(0) |  | ||||||
|             output.append('echo "%s" > %s' % (first_line, self.target)) |  | ||||||
|             output.append("cat >> %s << EOF" % self.target) |  | ||||||
|             output.append("\n".join(_content)) |  | ||||||
|             output.append("EOF") |  | ||||||
|         else: |  | ||||||
|             output.append("cat > %s << EOF" % self.target) |  | ||||||
|             output.append(content) |  | ||||||
|             output.append("EOF") |  | ||||||
| 
 |  | ||||||
|         statement = "\n".join(output) |  | ||||||
| 
 |  | ||||||
|         return Command(statement, **self._kwargs) |  | ||||||
| 
 |  | ||||||
|         # # BUG: This still does not seem to work, possibly because a shell script includes EOF? The work around is to use |  | ||||||
|         # # get_content(), self.target, and write the file manually. |  | ||||||
|         # if self.line_by_line: |  | ||||||
|         #     a = list() |  | ||||||
|         #     a.append('touch %s' % self.target) |  | ||||||
|         #     for i in content.split("\n"): |  | ||||||
|         #         i = i.replace('"', r'\"') |  | ||||||
|         #         a.append('echo "%s" >> %s' % (i, self.target)) |  | ||||||
|         # |  | ||||||
|         #     output.append("\n".join(a)) |  | ||||||
|         # elif self.pythonic: |  | ||||||
|         #     target_file = File(self.target) |  | ||||||
|         #     script_file = "write_%s_template.py" % target_file.name.replace("-", "_") |  | ||||||
|         # |  | ||||||
|         #     a = list() |  | ||||||
|         #     a.append('content = """%s' % content) |  | ||||||
|         #     a.append('"""') |  | ||||||
|         #     a.append("") |  | ||||||
|         #     a.append('with open("%s", "w") as f:' % self.target) |  | ||||||
|         #     a.append('    f.write(content)') |  | ||||||
|         #     a.append('    f.close()') |  | ||||||
|         #     a.append('') |  | ||||||
|         #     output.append('cat > %s <<EOF' % script_file) |  | ||||||
|         #     output.append("\n".join(a)) |  | ||||||
|         #     output.append('EOF') |  | ||||||
|         #     output.append("") |  | ||||||
|         #     output.append("rm %s" % script_file) |  | ||||||
|         # else: |  | ||||||
|         #     output.append("cat > %s << EOF" % self.target) |  | ||||||
|         #     output.append(content) |  | ||||||
|         #     output.append("EOF") |  | ||||||
|         # |  | ||||||
|         # statement = "\n".join(output) |  | ||||||
|         # return Command(statement, **self._kwargs) |  | ||||||
| 
 |  | ||||||
|     # noinspection PyUnusedLocal |  | ||||||
|     def _get_jinja2_statement(self, cd=False): |  | ||||||
|         """Parse a Jinja2 template.""" |  | ||||||
|         content = self.get_content() |  | ||||||
|         return self._get_command(content) |  | ||||||
| 
 |  | ||||||
|     # noinspection PyUnusedLocal |  | ||||||
|     def _get_simple_statement(self, cd=False): |  | ||||||
|         """Parse a "simple" template.""" |  | ||||||
|         content = self.get_content() |  | ||||||
| 
 |  | ||||||
|         return self._get_command(content) |  | ||||||
| @ -1,281 +0,0 @@ | |||||||
| # Imports |  | ||||||
| 
 |  | ||||||
| from commonkit import split_csv |  | ||||||
| from ..commands import Command, Template |  | ||||||
| from .common import COMMON_MAPPINGS |  | ||||||
| from .django import DJANGO_MAPPINGS |  | ||||||
| from .mysql import MYSQL_MAPPINGS |  | ||||||
| from .pgsql import PGSQL_MAPPINGS |  | ||||||
| from .posix import POSIX_MAPPINGS, Function |  | ||||||
| 
 |  | ||||||
| # Exports |  | ||||||
| 
 |  | ||||||
| __all__ = ( |  | ||||||
|     "MAPPINGS", |  | ||||||
|     "apache", |  | ||||||
|     "apache_reload", |  | ||||||
|     "apache_restart", |  | ||||||
|     "apache_start", |  | ||||||
|     "apache_stop", |  | ||||||
|     "apache_test", |  | ||||||
|     "command_exists", |  | ||||||
|     "service_reload", |  | ||||||
|     "service_restart", |  | ||||||
|     "service_start", |  | ||||||
|     "service_stop", |  | ||||||
|     "system", |  | ||||||
|     "system_install", |  | ||||||
|     "system_reboot", |  | ||||||
|     "system_update", |  | ||||||
|     "system_upgrade", |  | ||||||
|     "system_uninstall", |  | ||||||
|     "template", |  | ||||||
|     "user", |  | ||||||
|     "Function", |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def command_exists(name): |  | ||||||
|     """Indicates whether a given command exists in this overlay. |  | ||||||
| 
 |  | ||||||
|     :param name: The name of the command. |  | ||||||
|     :type name: str |  | ||||||
| 
 |  | ||||||
|     :rtype: bool |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     return name in MAPPINGS |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def apache(op, **kwargs): |  | ||||||
|     """Execute an Apache-related command. |  | ||||||
| 
 |  | ||||||
|     - op (str): The operation to perform; reload, restart, start, stop, test. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     if op == "reload": |  | ||||||
|         return apache_reload(**kwargs) |  | ||||||
|     elif op == "restart": |  | ||||||
|         return apache_restart(**kwargs) |  | ||||||
|     elif op == "start": |  | ||||||
|         return apache_start(**kwargs) |  | ||||||
|     elif op == "stop": |  | ||||||
|         return apache_stop(**kwargs) |  | ||||||
|     elif op == "test": |  | ||||||
|         return apache_test(**kwargs) |  | ||||||
|     else: |  | ||||||
|         raise NameError("Unrecognized or unsupported apache operation: %s" % op) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def apache_reload(**kwargs): |  | ||||||
|     kwargs.setdefault("comment", "reload apache") |  | ||||||
|     kwargs.setdefault("register", "apache_reloaded") |  | ||||||
| 
 |  | ||||||
|     return Command("apachectl –k reload", **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def apache_restart(**kwargs): |  | ||||||
|     kwargs.setdefault("comment", "restart apache") |  | ||||||
|     kwargs.setdefault("register", "apache_restarted") |  | ||||||
| 
 |  | ||||||
|     return Command("apachectl –k restart", **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def apache_start(**kwargs): |  | ||||||
|     kwargs.setdefault("comment", "start apache") |  | ||||||
|     kwargs.setdefault("register", "apache_started") |  | ||||||
| 
 |  | ||||||
|     return Command("apachectl –k start", **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def apache_stop(**kwargs): |  | ||||||
|     kwargs.setdefault("comment", "stop apache") |  | ||||||
| 
 |  | ||||||
|     return Command("apachectl –k stop", **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def apache_test(**kwargs): |  | ||||||
|     kwargs.setdefault("comment", "check apache configuration") |  | ||||||
|     kwargs.setdefault("register", "apache_checks_out") |  | ||||||
| 
 |  | ||||||
|     return Command("apachectl configtest", **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def service_reload(name, **kwargs): |  | ||||||
|     """Reload a service. |  | ||||||
| 
 |  | ||||||
|     - name (str): The service name. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "reload %s service" % name) |  | ||||||
|     kwargs.setdefault("register", "%s_reloaded" % name) |  | ||||||
| 
 |  | ||||||
|     return Command("systemctl reload %s" % name, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def service_restart(name, **kwargs): |  | ||||||
|     """Restart a service. |  | ||||||
| 
 |  | ||||||
|     - name (str): The service name. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "restart %s service" % name) |  | ||||||
|     kwargs.setdefault("register", "%s_restarted" % name) |  | ||||||
| 
 |  | ||||||
|     return Command("ssystemctl restart %s" % name, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def service_start(name, **kwargs): |  | ||||||
|     """Start a service. |  | ||||||
| 
 |  | ||||||
|     - name (str): The service name. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "start %s service" % name) |  | ||||||
|     kwargs.setdefault("register", "%s_started" % name) |  | ||||||
| 
 |  | ||||||
|     return Command("systemctl start %s" % name, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def service_stop(name, **kwargs): |  | ||||||
|     """Stop a service. |  | ||||||
| 
 |  | ||||||
|     - name (str): The service name. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "stop %s service" % name) |  | ||||||
|     kwargs.setdefault("register", "%s_stopped" % name) |  | ||||||
| 
 |  | ||||||
|     return Command("systemctl stop %s" % name, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def system(op, **kwargs): |  | ||||||
|     """Perform a system operation. |  | ||||||
| 
 |  | ||||||
|     - op (str): The operation to perform; reboot, update, upgrade. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     if op == "reboot": |  | ||||||
|         return system_reboot(**kwargs) |  | ||||||
|     elif op == "update": |  | ||||||
|         return system_update(**kwargs) |  | ||||||
|     elif op == "upgrade": |  | ||||||
|         return system_upgrade(**kwargs) |  | ||||||
|     else: |  | ||||||
|         raise NameError("Unrecognized or unsupported system operation: %s" % op) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def system_install(name, **kwargs): |  | ||||||
|     """Install a system-level package. |  | ||||||
| 
 |  | ||||||
|     - name (str): The name of the package to install. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "install system package %s" % name) |  | ||||||
| 
 |  | ||||||
|     return Command("yum install -y %s" % name, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def system_reboot(**kwargs): |  | ||||||
|     kwargs.setdefault("comment", "reboot the system") |  | ||||||
| 
 |  | ||||||
|     return Command("reboot", **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def system_uninstall(name, **kwargs): |  | ||||||
|     """Uninstall a system-level package. |  | ||||||
| 
 |  | ||||||
|     - name (str): The name of the package to uninstall. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "remove system package %s" % name) |  | ||||||
| 
 |  | ||||||
|     return Command("yum remove -y %s" % name, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def system_update(**kwargs): |  | ||||||
|     kwargs.setdefault("comment", "update system package info") |  | ||||||
| 
 |  | ||||||
|     return Command("yum check-update", **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def system_upgrade(**kwargs): |  | ||||||
|     kwargs.setdefault("comment", "upgrade the system") |  | ||||||
| 
 |  | ||||||
|     return Command("yum update -y", **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def template(source, target, backup=True, parser=None, **kwargs): |  | ||||||
|     """Create a file from a template. |  | ||||||
| 
 |  | ||||||
|     - source (str): The path to the template file. |  | ||||||
|     - target (str): The path to where the new file should be created. |  | ||||||
|     - backup (bool): Indicates whether a backup should be made if the target file already exists. |  | ||||||
|     - parser (str): The parser to use ``jinja`` (the default) or ``simple``. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     return Template(source, target, backup=backup, parser=parser, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def user(name, groups=None, home=None, op="add", password=None, **kwargs): |  | ||||||
|     """Create or remove a user. |  | ||||||
| 
 |  | ||||||
|     - name (str): The user name. |  | ||||||
|     - groups (str | list): A list of groups to which the user should belong. |  | ||||||
|     - home (str): The path to the user's home directory. |  | ||||||
|     - op (str); The operation to perform; ``add`` or ``remove``. |  | ||||||
|     - password (str): The user's password. (NOT IMPLEMENTED) |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     if op == "add": |  | ||||||
|         kwargs.setdefault("comment", "create a user named %s" % name) |  | ||||||
| 
 |  | ||||||
|         commands = list() |  | ||||||
| 
 |  | ||||||
|         a = list() |  | ||||||
|         a.append('adduser %s' % name) |  | ||||||
|         if home is not None: |  | ||||||
|             a.append("--home %s" % home) |  | ||||||
| 
 |  | ||||||
|         commands.append(Command(" ".join(a), **kwargs)) |  | ||||||
| 
 |  | ||||||
|         if type(groups) is str: |  | ||||||
|             groups = split_csv(groups, smart=False) |  | ||||||
| 
 |  | ||||||
|         if type(groups) in [list, tuple]: |  | ||||||
|             for group in groups: |  | ||||||
|                 commands.append(Command("gpasswd -a %s %s" % (name, group), **kwargs)) |  | ||||||
| 
 |  | ||||||
|         a = list() |  | ||||||
|         for c in commands: |  | ||||||
|             a.append(c.get_statement(suppress_comment=True)) |  | ||||||
| 
 |  | ||||||
|         return Command("\n".join(a), **kwargs) |  | ||||||
|     elif op == "remove": |  | ||||||
|         kwargs.setdefault("comment", "remove a user named %s" % name) |  | ||||||
|         return Command("userdel -r %s" % name, **kwargs) |  | ||||||
|     else: |  | ||||||
|         raise NameError("Unsupported or unrecognized operation: %s" % op) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| MAPPINGS = { |  | ||||||
|     'apache': apache, |  | ||||||
|     'install': system_install, |  | ||||||
|     'reboot': system_reboot, |  | ||||||
|     'reload': service_reload, |  | ||||||
|     'restart': service_restart, |  | ||||||
|     'start': service_start, |  | ||||||
|     'stop': service_stop, |  | ||||||
|     'system': system, |  | ||||||
|     'template': template, |  | ||||||
|     'update': system_update, |  | ||||||
|     'uninstall': system_uninstall, |  | ||||||
|     'upgrade': system_upgrade, |  | ||||||
|     'user': user, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| MAPPINGS.update(COMMON_MAPPINGS) |  | ||||||
| MAPPINGS.update(DJANGO_MAPPINGS) |  | ||||||
| MAPPINGS.update(MYSQL_MAPPINGS) |  | ||||||
| MAPPINGS.update(PGSQL_MAPPINGS) |  | ||||||
| MAPPINGS.update(POSIX_MAPPINGS) |  | ||||||
| @ -1,150 +0,0 @@ | |||||||
| # Imports |  | ||||||
| 
 |  | ||||||
| from ..commands import Command |  | ||||||
| 
 |  | ||||||
| # Exports |  | ||||||
| 
 |  | ||||||
| __all__ = ( |  | ||||||
|     "COMMON_MAPPINGS", |  | ||||||
|     "python_pip", |  | ||||||
|     "python_virtualenv", |  | ||||||
|     "run", |  | ||||||
|     "slack", |  | ||||||
|     "twist", |  | ||||||
|     "udf", |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| # Functions |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def python_pip(name, op="install", upgrade=False, venv=None, version=3, **kwargs): |  | ||||||
|     """Use pip to install or uninstall a Python package. |  | ||||||
| 
 |  | ||||||
|     - name (str): The name of the package. |  | ||||||
|     - op (str): The operation to perform; install, uninstall |  | ||||||
|     - upgrade (bool): Upgrade an installed package. |  | ||||||
|     - venv (str): The name of the virtual environment to load. |  | ||||||
|     - version (int): The Python version to use, e.g. ``2`` or ``3``. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     manager = "pip" |  | ||||||
|     if version == 3: |  | ||||||
|         manager = "pip3" |  | ||||||
| 
 |  | ||||||
|     if upgrade: |  | ||||||
|         statement = "%s install --upgrade %s" % (manager, name) |  | ||||||
|     else: |  | ||||||
|         statement = "%s %s %s" % (manager, op, name) |  | ||||||
| 
 |  | ||||||
|     if venv is not None: |  | ||||||
|         kwargs['prefix'] = "source %s/bin/activate" % venv |  | ||||||
| 
 |  | ||||||
|     kwargs.setdefault("comment", "%s %s" % (op, name)) |  | ||||||
| 
 |  | ||||||
|     return Command(statement, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def python_virtualenv(name, **kwargs): |  | ||||||
|     """Create a Python virtual environment. |  | ||||||
| 
 |  | ||||||
|     - name (str): The name of the environment to create. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "create %s virtual environment" % name) |  | ||||||
| 
 |  | ||||||
|     return Command("virtualenv %s" % name, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def run(statement, **kwargs): |  | ||||||
|     """Run any statement. |  | ||||||
| 
 |  | ||||||
|     - statement (str): The statement to be executed. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "run statement") |  | ||||||
|     return Command(statement, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def slack(message, url=None, **kwargs): |  | ||||||
|     """Send a message to Slack. |  | ||||||
| 
 |  | ||||||
|     - message (str): The message to be sent. |  | ||||||
|     - url (str): The webhook URL. This is required. See documentation. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     if url is None: |  | ||||||
|         raise ValueError("A url is required to use the slack command.") |  | ||||||
| 
 |  | ||||||
|     kwargs.setdefault("comment", "send a message to slack") |  | ||||||
| 
 |  | ||||||
|     a = list() |  | ||||||
| 
 |  | ||||||
|     a.append("curl -X POST -H 'Content-type: application/json' --data") |  | ||||||
|     a.append("'" + '{"text": "%s"}' % message + "'") |  | ||||||
|     a.append(url) |  | ||||||
| 
 |  | ||||||
|     return Command(" ".join(a), **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def twist(message, title="Notice", url=None, **kwargs): |  | ||||||
|     """Send a message to Twist. |  | ||||||
| 
 |  | ||||||
|     - message (str): The message to be sent. |  | ||||||
|     - title (str): The message title. |  | ||||||
|     - url (str): The webhook URL. This is required. See documentation. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     if url is None: |  | ||||||
|         raise ValueError("A url is required to use the twist command.") |  | ||||||
| 
 |  | ||||||
|     kwargs.setdefault("comment", "send a message to twist") |  | ||||||
| 
 |  | ||||||
|     a = list() |  | ||||||
| 
 |  | ||||||
|     # curl -X POST -H 'Content-type: application/json' --data '{"content": "This is the message.", "title": "Message Title"}' "https://twist.com/api/v3/integration_incoming/post_data?install_id=116240&install_token=116240_bfb05bde51ecd0f728b4b161bee6fcee" |  | ||||||
|     a.append("curl -X POST -H 'Content-type: application/json' --data") |  | ||||||
| 
 |  | ||||||
|     data = '{"content": "%s", "title": "%s"}' % (message, title) |  | ||||||
|     a.append("'%s'" % data) |  | ||||||
|     a.append('"%s"' % url) |  | ||||||
| 
 |  | ||||||
|     return Command(" ".join(a), **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def udf(name, default=None, example=None, label=None, **kwargs): |  | ||||||
|     """Create a UDF prompt for a StackScript. |  | ||||||
| 
 |  | ||||||
|     - name (str): The name of the variable. |  | ||||||
|     - default: The default value. |  | ||||||
|     - example: An example value, instead of a default. |  | ||||||
|     - label (str): The label for the variable. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("prompt for %s in stackscript" % name) |  | ||||||
| 
 |  | ||||||
|     label = label or name.replace("_", " ").title() |  | ||||||
| 
 |  | ||||||
|     a = ['# <UDF name="%s" label="%s"' % (name, label)] |  | ||||||
| 
 |  | ||||||
|     if default is not None: |  | ||||||
|         a.append('default="%s"' % default) |  | ||||||
|     elif example is not None: |  | ||||||
|         a.append('example="%s"' % example) |  | ||||||
|     else: |  | ||||||
|         pass |  | ||||||
| 
 |  | ||||||
|     a.append("/>") |  | ||||||
| 
 |  | ||||||
|     return Command(" ".join(a), **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # Mappings |  | ||||||
| 
 |  | ||||||
| COMMON_MAPPINGS = { |  | ||||||
|     'pip': python_pip, |  | ||||||
|     'run': run, |  | ||||||
|     'slack': slack, |  | ||||||
|     'twist': twist, |  | ||||||
|     'udf': udf, |  | ||||||
|     'virtualenv': python_virtualenv, |  | ||||||
| } |  | ||||||
| @ -1,188 +0,0 @@ | |||||||
| # Imports |  | ||||||
| 
 |  | ||||||
| import os |  | ||||||
| from ..commands import Command |  | ||||||
| 
 |  | ||||||
| # Exports |  | ||||||
| 
 |  | ||||||
| __all__ = ( |  | ||||||
|     "DJANGO_MAPPINGS", |  | ||||||
|     "django", |  | ||||||
|     "django_check", |  | ||||||
|     "django_collect_static", |  | ||||||
|     "django_dumpdata", |  | ||||||
|     "django_loaddata", |  | ||||||
|     "django_migrate", |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| # Functions |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _django(name, *args, venv=None, **kwargs): |  | ||||||
|     """Process a django-based command. |  | ||||||
| 
 |  | ||||||
|     :param name: The name of the management command. |  | ||||||
|     :type name: str |  | ||||||
| 
 |  | ||||||
|     :param venv: The virtual environment to use. |  | ||||||
|     :type venv: str |  | ||||||
| 
 |  | ||||||
|     args and kwargs are used to instantiate the command instance. |  | ||||||
| 
 |  | ||||||
|     This exists because we need ``django()`` to serve as an interface for any management command. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     if venv is not None: |  | ||||||
|         kwargs['prefix'] = "source %s/bin/activate" % venv |  | ||||||
| 
 |  | ||||||
|     kwargs.setdefault("comment", "run %s django management command" % name) |  | ||||||
| 
 |  | ||||||
|     # Base parameters need to be captured, because all others are assumed to be switches for the management command. |  | ||||||
|     _kwargs = { |  | ||||||
|         'comment': kwargs.pop("comment", None), |  | ||||||
|         'condition': kwargs.pop("condition", None), |  | ||||||
|         'cd': kwargs.pop("cd", None), |  | ||||||
|         'environments': kwargs.pop("environments", None), |  | ||||||
|         'function': kwargs.pop("function", None), |  | ||||||
|         # 'local': kwargs.pop("local", False), |  | ||||||
|         'prefix': kwargs.pop("prefix", None), |  | ||||||
|         'register': kwargs.pop("register", None), |  | ||||||
|         'shell': kwargs.pop("shell", "/bin/bash"), |  | ||||||
|         'stop': kwargs.pop("stop", False), |  | ||||||
|         'sudo': kwargs.pop('sudo', False), |  | ||||||
|         'tags': kwargs.pop("tags", None), |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     statement = list() |  | ||||||
|     statement.append("./manage.py %s" % name) |  | ||||||
| 
 |  | ||||||
|     # Remaining kwargs are assumed to be switches. |  | ||||||
|     for key, value in kwargs.items(): |  | ||||||
|         key = key.replace("_", "-") |  | ||||||
|         if type(value) is bool: |  | ||||||
|             if value is True: |  | ||||||
|                 statement.append("--%s" % key) |  | ||||||
|         else: |  | ||||||
|             statement.append("--%s=%s" % (key, value)) |  | ||||||
| 
 |  | ||||||
|     if len(args) > 0: |  | ||||||
|         statement.append(" ".join(args)) |  | ||||||
| 
 |  | ||||||
|     return Command(" ".join(statement), **_kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def django(name, *args, venv=None, **kwargs): |  | ||||||
|     """Run any Django management command. |  | ||||||
| 
 |  | ||||||
|     - name (str): The name of the management command. |  | ||||||
|     - venv (str): The of the virtual environment to use. |  | ||||||
| 
 |  | ||||||
|     args are passed as positional arguments, while kwargs are given as switches. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     if name == "check": |  | ||||||
|         return django_check(venv=venv, **kwargs) |  | ||||||
|     elif name in ("collectstatic", "static"): |  | ||||||
|         return django_collect_static(venv=venv, **kwargs) |  | ||||||
|     elif name == "migrate": |  | ||||||
|         return django_migrate(venv=venv, **kwargs) |  | ||||||
|     else: |  | ||||||
|         return _django(name, *args, venv=venv, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def django_check(venv=None, **kwargs): |  | ||||||
|     """Run the Django check command. |  | ||||||
| 
 |  | ||||||
|     - venv (str): The of the virtual environment to use. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "run django checks") |  | ||||||
|     kwargs.setdefault("register", "django_checks_out") |  | ||||||
| 
 |  | ||||||
|     return _django("check", venv=venv, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def django_collect_static(venv=None, **kwargs): |  | ||||||
|     """Collect static files. |  | ||||||
| 
 |  | ||||||
|     - venv (str): The of the virtual environment to use. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "collect static files") |  | ||||||
| 
 |  | ||||||
|     return _django("collectstatic", venv=venv, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def django_dumpdata(app_name, base_path="local", file_name="initial", indent=4, natural_foreign=False, |  | ||||||
|                     natural_primary=False, path=None, venv=None, **kwargs): |  | ||||||
|     """Dump data from the database. |  | ||||||
| 
 |  | ||||||
|     - app_name (str): The name (app label) of the app. ``app_label.ModelName`` may also be given. |  | ||||||
|     - base_path (str): The path under which apps are located in source. |  | ||||||
|     - file_name (str): The file name to which the data will be dumped. |  | ||||||
|     - indent (int): Indentation of the exported fixtures. |  | ||||||
|     - natural_foreign (bool): Use the natural foreign parameter. |  | ||||||
|     - natural_primary (bool): Use the natural primary parameter. |  | ||||||
|     - path (str): The path to the data file. |  | ||||||
|     - venv (str): The of the virtual environment to use. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "export fixtures for %s" % app_name) |  | ||||||
| 
 |  | ||||||
|     output_format = kwargs.pop("format", "json") |  | ||||||
| 
 |  | ||||||
|     _path = path or os.path.join(base_path, app_name, "fixtures", "%s.%s" % (file_name, output_format)) |  | ||||||
| 
 |  | ||||||
|     return _django( |  | ||||||
|         "dumpdata", |  | ||||||
|         app_name, |  | ||||||
|         "> %s" % _path, |  | ||||||
|         format=output_format, |  | ||||||
|         indent=indent, |  | ||||||
|         natural_foreign=natural_foreign, |  | ||||||
|         natural_primary=natural_primary, |  | ||||||
|         venv=venv, |  | ||||||
|         **kwargs |  | ||||||
|     ) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def django_loaddata(app_name, base_path="local", file_name="initial", path=None, venv=None, **kwargs): |  | ||||||
|     """Load data into the database. |  | ||||||
| 
 |  | ||||||
|     - app_name (str): The name (app label) of the app. ``app_label.ModelName`` may also be given. |  | ||||||
|     - base_path (str): The path under which apps are located in source. |  | ||||||
|     - file_name (str): The file name to which the data will be dumped. |  | ||||||
|     - path (str): The path to the data file. |  | ||||||
|     - venv (str): The of the virtual environment to use. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "load fixtures for %s" % app_name) |  | ||||||
| 
 |  | ||||||
|     output_format = kwargs.pop("format", "json") |  | ||||||
| 
 |  | ||||||
|     _path = path or os.path.join(base_path, app_name, "fixtures", "%s.%s" % (file_name, output_format)) |  | ||||||
| 
 |  | ||||||
|     return _django("loaddata", _path, venv=venv, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def django_migrate(venv=None, **kwargs): |  | ||||||
|     """Apply database migrations. |  | ||||||
| 
 |  | ||||||
|     - venv (str): The of the virtual environment to use. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "run django database migrations") |  | ||||||
| 
 |  | ||||||
|     return _django("migrate", venv=venv, **kwargs) |  | ||||||
| 
 |  | ||||||
| # Mapping |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| DJANGO_MAPPINGS = { |  | ||||||
|     'django': django, |  | ||||||
|     'django.check': django_check, |  | ||||||
|     'django.collect_static': django_collect_static, |  | ||||||
|     'django.dumpdata': django_dumpdata, |  | ||||||
|     'django.loaddata': django_loaddata, |  | ||||||
|     'django.migrate': django_migrate, |  | ||||||
| } |  | ||||||
| @ -1,262 +0,0 @@ | |||||||
| # Imports |  | ||||||
| 
 |  | ||||||
| from ..commands import Command |  | ||||||
| 
 |  | ||||||
| # Exports |  | ||||||
| 
 |  | ||||||
| __all__ = ( |  | ||||||
|     "MYSQL_MAPPINGS", |  | ||||||
|     "mysql_create", |  | ||||||
|     "mysql_drop", |  | ||||||
|     "mysql_dump", |  | ||||||
|     "mysql_exec", |  | ||||||
|     "mysql_exists", |  | ||||||
|     "mysql_grant", |  | ||||||
|     "mysql_user", |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| # Functions |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _get_mysql_command(host="localhost", name="mysql", password=None, port=3306, user="root"): |  | ||||||
|     a = list() |  | ||||||
|     a.append("%s --user=%s" % (name, user)) |  | ||||||
|     a.append("--host=%s" % host) |  | ||||||
|     a.append("--port=%s" % port) |  | ||||||
| 
 |  | ||||||
|     if password: |  | ||||||
|         a.append('--password="%s"' % password) |  | ||||||
| 
 |  | ||||||
|     return a |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def mysql_create(database, host="localhost", owner=None, password=None, port=3306, user="root", **kwargs): |  | ||||||
|     """Create a MySQL database. |  | ||||||
| 
 |  | ||||||
|     - database (str): The database name. |  | ||||||
|     - host (str): The database host name or IP address. |  | ||||||
|     - password (str): The password for the user with sufficient access privileges to execute the command. |  | ||||||
|     - owner (str): The owner (user/role name) of the new database. |  | ||||||
|     - port (int): The TCP port number of the MySQL service running on the host. |  | ||||||
|     - user (str): The name of the user with sufficient access privileges to execute the command. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "create the %s mysql database" % database) |  | ||||||
| 
 |  | ||||||
|     # MySQL commands always run without sudo because the --user may be provided. |  | ||||||
|     kwargs['sudo'] = False |  | ||||||
| 
 |  | ||||||
|     # Assemble the command. |  | ||||||
|     a = _get_mysql_command(host=host, name="mysqladmin", password=password, port=port, user=user) |  | ||||||
|     a.append("create %s" % database) |  | ||||||
| 
 |  | ||||||
|     if owner: |  | ||||||
|         grant = mysql_grant( |  | ||||||
|             owner, |  | ||||||
|             database=database, |  | ||||||
|             host=host, |  | ||||||
|             password=password, |  | ||||||
|             port=port, |  | ||||||
|             user=user, |  | ||||||
|         ) |  | ||||||
|         a.append("&& %s" % grant.get_statement(suppress_comment=True)) |  | ||||||
| 
 |  | ||||||
|     return Command(" ".join(a), **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def mysql_drop(database, host="localhost", password=None, port=3306, user="root", **kwargs): |  | ||||||
|     """Drop (remove) a MySQL database. |  | ||||||
| 
 |  | ||||||
|     - database (str): The database name. |  | ||||||
|     - host (str): The database host name or IP address. |  | ||||||
|     - password (str): The password for the user with sufficient access privileges to execute the command. |  | ||||||
|     - port (int): The TCP port number of the MySQL service running on the host. |  | ||||||
|     - user (str): The name of the user with sufficient access privileges to execute the command. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "remove the %s mysql database" % database) |  | ||||||
| 
 |  | ||||||
|     # MySQL commands always run without sudo because the --user may be provided. |  | ||||||
|     kwargs['sudo'] = False |  | ||||||
| 
 |  | ||||||
|     # Assemble the command. |  | ||||||
|     a = _get_mysql_command(host=host, name="mysqladmin", password=password, port=port, user=user) |  | ||||||
|     a.append("drop %s" % database) |  | ||||||
| 
 |  | ||||||
|     return Command(" ".join(a), **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def mysql_dump(database, file_name=None, host="localhost", inserts=False, password=None, port=3306, user="root", |  | ||||||
|                **kwargs): |  | ||||||
|     """Dump (export) a MySQL database. |  | ||||||
| 
 |  | ||||||
|     - database (str): The database name. |  | ||||||
|     - host (str): The database host name or IP address. |  | ||||||
|     - password (str): The password for the user with sufficient access privileges to execute the command. |  | ||||||
|     - port (int): The TCP port number of the MySQL service running on the host. |  | ||||||
|     - user (str): The name of the user with sufficient access privileges to execute the command. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "dump the %s mysql database" % database) |  | ||||||
| 
 |  | ||||||
|     # MySQL commands always run without sudo because the --user may be provided. |  | ||||||
|     # kwargs['sudo'] = False |  | ||||||
| 
 |  | ||||||
|     # Assemble the command. |  | ||||||
|     a = _get_mysql_command(host=host, name="mysqldump", password=password, port=port, user=user) |  | ||||||
| 
 |  | ||||||
|     # if data_only: |  | ||||||
|     #     a.append("--no-create-info") |  | ||||||
|     # elif schema_only: |  | ||||||
|     #     a.append("--no-data") |  | ||||||
|     # else: |  | ||||||
|     #     pass |  | ||||||
| 
 |  | ||||||
|     if inserts: |  | ||||||
|         a.append("--complete-inserts") |  | ||||||
| 
 |  | ||||||
|     a.append(database) |  | ||||||
| 
 |  | ||||||
|     _file_name = file_name or "%s.sql" % database |  | ||||||
|     a.append("> %s" % _file_name) |  | ||||||
| 
 |  | ||||||
|     return Command(" ".join(a), **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def mysql_exec(sql, database="default", host="localhost", password=None, port=3306, user="root", **kwargs): |  | ||||||
|     """Execute a MySQL statement. |  | ||||||
| 
 |  | ||||||
|     - sql (str): The SQL to run. |  | ||||||
|     - database (str): The name of the database. |  | ||||||
|     - host (str): The host name. |  | ||||||
|     - password (str): The password for the user with sufficient access privileges to execute the command. |  | ||||||
|     - port (int): The TCP port number. |  | ||||||
|     - user (str): The name of the user with sufficient access privileges to execute the command. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs['sudo'] = False |  | ||||||
|     kwargs.setdefault("comment", "execute mysql statement") |  | ||||||
| 
 |  | ||||||
|     a = _get_mysql_command(host=host, password=password, port=port, user=user) |  | ||||||
|     a.append('--execute="%s"' % sql) |  | ||||||
|     a.append(database) |  | ||||||
| 
 |  | ||||||
|     return Command(" ".join(a), **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def mysql_exists(database, host="localhost", password=None, port=3306, user="root", **kwargs): |  | ||||||
|     """Determine if a MySQL database exists. |  | ||||||
| 
 |  | ||||||
|     - database (str): The database name. |  | ||||||
|     - host (str): The database host name or IP address. |  | ||||||
|     - password (str): The password for the user with sufficient access privileges to execute the command. |  | ||||||
|     - port (int): The TCP port number of the MySQL service running on the host. |  | ||||||
|     - user (str): The name of the user with sufficient access privileges to execute the command. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "determine if the %s mysql database exists" % database) |  | ||||||
|     kwargs.setdefault("register", "mysql_database_exists") |  | ||||||
| 
 |  | ||||||
|     # MySQL commands always run without sudo because the --user may be provided. |  | ||||||
|     kwargs['sudo'] = False |  | ||||||
| 
 |  | ||||||
|     # Assemble the command. |  | ||||||
|     a = _get_mysql_command(host=host, password=password, port=port, user=user) |  | ||||||
| 
 |  | ||||||
|     sql = "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '%s'" % database |  | ||||||
|     a.append('--execute="%s"' % sql) |  | ||||||
| 
 |  | ||||||
|     return Command(" ".join(a), **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def mysql_grant(to, database=None, host="localhost", password=None, port=3306, privileges="ALL", user="root", **kwargs): |  | ||||||
|     """Grant privileges to a user. |  | ||||||
| 
 |  | ||||||
|     - to (str): The user name to which privileges are granted. |  | ||||||
|     - database (str): The database name. |  | ||||||
|     - host (str): The database host name or IP address. |  | ||||||
|     - password (str): The password for the user with sufficient access privileges to execute the command. |  | ||||||
|     - port (int): The TCP port number of the MySQL service running on the host. |  | ||||||
|     - privileges (str): The privileges to be granted. |  | ||||||
|     - user (str): The name of the user with sufficient access privileges to execute the command. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "grant mysql privileges to %s" % to) |  | ||||||
| 
 |  | ||||||
|     a = _get_mysql_command(host=host, password=password, port=port, user=user) |  | ||||||
| 
 |  | ||||||
|     # See https://dev.mysql.com/doc/refman/5.7/en/grant.html |  | ||||||
|     _database = database or "*" |  | ||||||
|     sql = "GRANT %(privileges)s ON %(database)s.* TO '%(user)s'@'%(host)s'" % { |  | ||||||
|         'database': _database, |  | ||||||
|         'host': host, |  | ||||||
|         'privileges': privileges, |  | ||||||
|         'user': to, |  | ||||||
|     } |  | ||||||
|     a.append('--execute="%s"' % sql) |  | ||||||
| 
 |  | ||||||
|     return Command(" ".join(a)) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def mysql_user(name, host="localhost", op="create", passwd=None, password=None, port=3306, user="root", **kwargs): |  | ||||||
|     """Work with a MySQL user. |  | ||||||
| 
 |  | ||||||
|     - name (str): The user name. |  | ||||||
|     - host (str): The host name. |  | ||||||
|     - op (str): The operation to perform: ``create``, ``drop``, ``exists``. |  | ||||||
|     - passwd (str): The password for a new user. |  | ||||||
|     - password (str): The password for the user with sufficient access privileges to execute the command. |  | ||||||
|     - port (int): The TCP port number. |  | ||||||
|     - user (str): The name of the user with sufficient access privileges to execute the command. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs['sudo'] = False |  | ||||||
|     if op == "create": |  | ||||||
|         kwargs.setdefault("comment", "create %s mysql user" % name) |  | ||||||
| 
 |  | ||||||
|         a = _get_mysql_command(host=host, password=password, port=port, user=user) |  | ||||||
|         sql = "CREATE USER IF NOT EXISTS '%(user)s'@'%(host)s'" % { |  | ||||||
|             'host': host, |  | ||||||
|             'user': name, |  | ||||||
|         } |  | ||||||
|         if passwd: |  | ||||||
|             sql += " IDENTIFIED BY PASSWORD('%s')" % passwd |  | ||||||
| 
 |  | ||||||
|         a.append('--execute="%s"' % sql) |  | ||||||
| 
 |  | ||||||
|         return Command(" ".join(a), **kwargs) |  | ||||||
|     elif op == "drop": |  | ||||||
|         kwargs.setdefault("comment", "drop %s mysql user" % name) |  | ||||||
| 
 |  | ||||||
|         a = _get_mysql_command(host=host, password=password, port=port, user=user) |  | ||||||
| 
 |  | ||||||
|         sql = "DROP USER IF EXISTS '%(user)s'@'%(host)s'" % { |  | ||||||
|             'host': host, |  | ||||||
|             'user': name, |  | ||||||
|         } |  | ||||||
|         a.append('--execute="%s"' % sql) |  | ||||||
| 
 |  | ||||||
|         return Command(" ".join(a), **kwargs) |  | ||||||
|     elif op == "exists": |  | ||||||
|         kwargs.setdefault("comment", "determine if %s mysql user exists" % name) |  | ||||||
|         kwargs.setdefault("register", "mysql_user_exists") |  | ||||||
| 
 |  | ||||||
|         a = _get_mysql_command(host=host, password=password, port=port, user=user) |  | ||||||
| 
 |  | ||||||
|         sql = "SELECT EXISTS(SELECT 1 FROM mysql.user WHERE user = '%s')" % name |  | ||||||
|         a.append('--execute="%s"' % sql) |  | ||||||
| 
 |  | ||||||
|         return Command(" ".join(a), **kwargs) |  | ||||||
|     else: |  | ||||||
|         raise NameError("Unrecognized or unsupported MySQL user operation: %s" % op) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| MYSQL_MAPPINGS = { |  | ||||||
|     'mysql.create': mysql_create, |  | ||||||
|     'mysql.drop': mysql_drop, |  | ||||||
|     'mysql.dump': mysql_dump, |  | ||||||
|     'mysql.exists': mysql_exists, |  | ||||||
|     'mysql.grant': mysql_grant, |  | ||||||
|     'mysql.sql': mysql_exec, |  | ||||||
|     'mysql.user': mysql_user, |  | ||||||
| } |  | ||||||
| @ -1,226 +0,0 @@ | |||||||
| # Imports |  | ||||||
| 
 |  | ||||||
| from ..commands import Command |  | ||||||
| 
 |  | ||||||
| # Exports |  | ||||||
| 
 |  | ||||||
| __all__ = ( |  | ||||||
|     "PGSQL_MAPPINGS", |  | ||||||
|     "pgsql_create", |  | ||||||
|     "pgsql_drop", |  | ||||||
|     "pgsql_dump", |  | ||||||
|     "pgsql_exec", |  | ||||||
|     "pgsql_exists", |  | ||||||
|     "pgsql_user", |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| # Functions |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _get_pgsql_command(name, host="localhost", password=None, port=5432, user="postgres"): |  | ||||||
|     """Get a postgres-related command using commonly required parameters. |  | ||||||
| 
 |  | ||||||
|     :param name: The name of the command. |  | ||||||
|     :type name: str |  | ||||||
| 
 |  | ||||||
|     :param host: The host name. |  | ||||||
|     :type host: str |  | ||||||
| 
 |  | ||||||
|     :param password: The password to use. |  | ||||||
|     :type password: str |  | ||||||
| 
 |  | ||||||
|     :param port: The TCP port number. |  | ||||||
|     :type port: int |  | ||||||
| 
 |  | ||||||
|     :param user: The user name that will be used to execute the command. |  | ||||||
| 
 |  | ||||||
|     :rtype: list[str] |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     a = list() |  | ||||||
| 
 |  | ||||||
|     if password: |  | ||||||
|         a.append('export PGPASSWORD="%s" &&' % password) |  | ||||||
| 
 |  | ||||||
|     a.append(name) |  | ||||||
| 
 |  | ||||||
|     a.append("--host=%s" % host) |  | ||||||
|     a.append("--port=%s" % port) |  | ||||||
|     a.append("--username=%s" % user) |  | ||||||
| 
 |  | ||||||
|     return a |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def pgsql_create(database, admin_pass=None, admin_user="postgres", host="localhost", owner=None, port=5432, template=None, |  | ||||||
|               **kwargs): |  | ||||||
|     """Create a PostgreSQL database. |  | ||||||
| 
 |  | ||||||
|     - database (str): The database name. |  | ||||||
|     - admin_pass (str): The password for the user with sufficient access privileges to execute the command. |  | ||||||
|     - admin_user (str): The name of the user with sufficient access privileges to execute the command. |  | ||||||
|     - host (str): The database host name or IP address. |  | ||||||
|     - owner (str): The owner (user/role name) of the new database. |  | ||||||
|     - port (int): The port number of the Postgres service running on the host. |  | ||||||
|     - template (str): The database template name to use, if any. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     _owner = owner or admin_user |  | ||||||
| 
 |  | ||||||
|     # Postgres commands always run without sudo because the -U may be provided. |  | ||||||
|     kwargs['sudo'] = False |  | ||||||
| 
 |  | ||||||
|     # Assemble the command. |  | ||||||
|     base = _get_pgsql_command("createdb", host=host, password=admin_pass, port=port) |  | ||||||
|     base.append("--owner=%s" % _owner) |  | ||||||
| 
 |  | ||||||
|     if template is not None: |  | ||||||
|         base.append("--template=%s" % template) |  | ||||||
| 
 |  | ||||||
|     base.append(database) |  | ||||||
| 
 |  | ||||||
|     return Command(" ".join(base), **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def pgsql_drop(database, admin_pass=None, admin_user="postgres", host="localhost", port=5432, **kwargs): |  | ||||||
|     """Remove a PostgreSQL database. |  | ||||||
| 
 |  | ||||||
|     - database (str): The database name. |  | ||||||
|     - admin_pass (str): The password for the user with sufficient access privileges to execute the command. |  | ||||||
|     - admin_user (str): The name of the user with sufficient access privileges to execute the command. |  | ||||||
|     - host (str): The database host name or IP address. |  | ||||||
|     - port (int): The port number of the Postgres service running on the host. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     # Postgres commands always run without sudo because the -U may be provided. |  | ||||||
|     kwargs['sudo'] = False |  | ||||||
| 
 |  | ||||||
|     # Assemble the command. |  | ||||||
|     base = _get_pgsql_command("dropdb", host=host, password=admin_pass, port=port, user=admin_user) |  | ||||||
|     base.append(database) |  | ||||||
| 
 |  | ||||||
|     return  Command(" ".join(base), **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def pgsql_dump(database, admin_pass=None, admin_user="postgres", file_name=None, host="localhost", port=5432, **kwargs): |  | ||||||
|     """Export a Postgres database. |  | ||||||
| 
 |  | ||||||
|     - database (str): The database name. |  | ||||||
|     - admin_pass (str): The password for the user with sufficient access privileges to execute the command. |  | ||||||
|     - admin_user (str): The name of the user with sufficient access privileges to execute the command. |  | ||||||
|     - file_name (str): The name/path of the export file. Defaults the database name plus ``.sql``. |  | ||||||
|     - host (str): The database host name or IP address. |  | ||||||
|     - port (int): The port number of the Postgres service running on the host. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     _file_name = file_name or "%s.sql" % database |  | ||||||
| 
 |  | ||||||
|     # Postgres commands always run without sudo because the -U may be provided. |  | ||||||
|     # kwargs['sudo'] = False |  | ||||||
| 
 |  | ||||||
|     # Assemble the command. |  | ||||||
|     base = _get_pgsql_command("pg_dump", host=host, password=admin_pass, port=port, user=admin_user) |  | ||||||
|     base.append("--column-inserts") |  | ||||||
|     base.append("--file=%s" % _file_name) |  | ||||||
|     base.append(database) |  | ||||||
| 
 |  | ||||||
|     return Command(" ".join(base), **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def pgsql_exec(sql, database="template1", host="localhost", password=None, port=5432, user="postgres", **kwargs): |  | ||||||
|     """Execute a psql command. |  | ||||||
| 
 |  | ||||||
|     - sql (str): The SQL to be executed. |  | ||||||
|     - database (str): The database name. |  | ||||||
|     - admin_pass (str): The password for the user with sufficient access privileges to execute the command. |  | ||||||
|     - admin_user (str): The name of the user with sufficient access privileges to execute the command. |  | ||||||
|     - host (str): The database host name or IP address. |  | ||||||
|     - port (int): The port number of the Postgres service running on the host. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     # Postgres commands always run without sudo because the -U may be provided. |  | ||||||
|     kwargs['sudo'] = False |  | ||||||
| 
 |  | ||||||
|     # Assemble the command. |  | ||||||
|     base = _get_pgsql_command("psql", host=host, password=password, port=port, user=user) |  | ||||||
|     base.append("--dbname=%s" % database) |  | ||||||
|     base.append('-c "%s"' % sql) |  | ||||||
| 
 |  | ||||||
|     return Command(" ".join(base), **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def pgsql_exists(database, admin_pass=None, admin_user="postgres", host="localhost", port=5432, **kwargs): |  | ||||||
|     """Determine if a Postgres database exists. |  | ||||||
| 
 |  | ||||||
|     - database (str): The database name. |  | ||||||
|     - admin_pass (str): The password for the user with sufficient access privileges to execute the command. |  | ||||||
|     - admin_user (str): The name of the user with sufficient access privileges to execute the command. |  | ||||||
|     - host (str): The database host name or IP address. |  | ||||||
|     - owner (str): The owner (user/role name) of the new database. |  | ||||||
|     - port (int): The port number of the Postgres service running on the host. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     # Postgres commands always run without sudo because the -U may be provided. |  | ||||||
|     kwargs['sudo'] = False |  | ||||||
|     kwargs.setdefault("register", "pgsql_db_exists") |  | ||||||
| 
 |  | ||||||
|     base = _get_pgsql_command("psql", host=host, password=admin_pass, port=port, user=admin_user) |  | ||||||
|     base.append(r"-lqt | cut -d \| -f 1 | grep -qw %s" % database) |  | ||||||
| 
 |  | ||||||
|     return Command(" ".join(base), **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def pgsql_user(name, admin_pass=None, admin_user="postgres", host="localhost", op="create", password=None, port=5432, **kwargs): |  | ||||||
|     """Work with a PostgreSQL user. |  | ||||||
| 
 |  | ||||||
|     - name (str): The user name. |  | ||||||
|     - host (str): The host name. |  | ||||||
|     - op (str): The operation to perform: ``create``, ``drop``, ``exists``. |  | ||||||
|     - passwd (str): The password for a new user. |  | ||||||
|     - password (str): The password for the user with sufficient access privileges to execute the command. |  | ||||||
|     - port (int): The TCP port number. |  | ||||||
|     - user (str): The name of the user with sufficient access privileges to execute the command. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     # Postgres commands always run without sudo because the -U may be provided. |  | ||||||
|     kwargs['sudo'] = False |  | ||||||
| 
 |  | ||||||
|     if op == "create": |  | ||||||
|         kwargs.setdefault("comment", "create %s postgres user" % name) |  | ||||||
|         # Assemble the command. |  | ||||||
|         base = _get_pgsql_command("createuser", host=host, password=admin_pass, port=port) |  | ||||||
|         base.append("-DRS") |  | ||||||
|         base.append(name) |  | ||||||
| 
 |  | ||||||
|         if password is not None: |  | ||||||
|             base.append("&& psql -h %s -U %s" % (host, admin_user)) |  | ||||||
|             base.append("-c \"ALTER USER %s WITH ENCRYPTED PASSWORD '%s';\"" % (name, password)) |  | ||||||
| 
 |  | ||||||
|         return Command(" ".join(base), **kwargs) |  | ||||||
|     elif op == "drop": |  | ||||||
|         kwargs.setdefault("comment", "drop %s postgres user" % name) |  | ||||||
|         base = _get_pgsql_command("dropuser", host=host, password=admin_pass, port=port, user=admin_user) |  | ||||||
|         base.append(name) |  | ||||||
| 
 |  | ||||||
|         return Command(" ".join(base), **kwargs) |  | ||||||
|     elif op == "exists": |  | ||||||
|         kwargs.setdefault("comment", "determine if %s postgres user exits" % name) |  | ||||||
|         kwargs.setdefault("register", "pgsql_use_exists") |  | ||||||
| 
 |  | ||||||
|         base = _get_pgsql_command("psql", host=host, password=admin_pass, port=port, user=admin_user) |  | ||||||
| 
 |  | ||||||
|         sql = "SELECT 1 FROM pgsql_roles WHERE rolname='%s'" % name |  | ||||||
|         base.append('-c "%s"' % sql) |  | ||||||
| 
 |  | ||||||
|         return Command(" ".join(base), **kwargs) |  | ||||||
|     else: |  | ||||||
|         raise NameError("Unrecognized or unsupported Postgres user operation: %s" % op) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| PGSQL_MAPPINGS = { |  | ||||||
|     'pgsql.create': pgsql_create, |  | ||||||
|     'pgsql.drop': pgsql_drop, |  | ||||||
|     'pgsql.dump': pgsql_dump, |  | ||||||
|     'pgsql.exists': pgsql_exists, |  | ||||||
|     'pgsql.sql': pgsql_exec, |  | ||||||
|     'pgsql.user': pgsql_user, |  | ||||||
| } |  | ||||||
| @ -1,758 +0,0 @@ | |||||||
| # Imports |  | ||||||
| 
 |  | ||||||
| from commonkit import indent, split_csv |  | ||||||
| import os |  | ||||||
| from ..commands import Command |  | ||||||
| 
 |  | ||||||
| # Exports |  | ||||||
| 
 |  | ||||||
| __all__ = ( |  | ||||||
|     "POSIX_MAPPINGS", |  | ||||||
|     "archive", |  | ||||||
|     "certbot", |  | ||||||
|     "dialog", |  | ||||||
|     "echo", |  | ||||||
|     "extract", |  | ||||||
|     "file_append", |  | ||||||
|     "file_copy", |  | ||||||
|     "file_write", |  | ||||||
|     "mkdir", |  | ||||||
|     "move", |  | ||||||
|     "perms", |  | ||||||
|     "prompt", |  | ||||||
|     "remove", |  | ||||||
|     "rename", |  | ||||||
|     "rsync", |  | ||||||
|     "scopy", |  | ||||||
|     "sed", |  | ||||||
|     "symlink", |  | ||||||
|     "touch", |  | ||||||
|     "wait", |  | ||||||
|     "Function", |  | ||||||
|     "Prompt", |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| # Functions |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def archive(from_path, absolute=False, exclude=None, file_name="archive.tgz", strip=None, to_path=".", view=False, |  | ||||||
|             **kwargs): |  | ||||||
|     """Create a file archive. |  | ||||||
| 
 |  | ||||||
|     - from_path (str): The path that should be archived. |  | ||||||
|     - absolute (bool): Set to ``True`` to preserve the leading slash. |  | ||||||
|     - exclude (str): A pattern to be excluded from the archive. |  | ||||||
|     - strip (int): Remove the specified number of leading elements from the path. |  | ||||||
|     - to_path (str): Where the archive should be created. This should *not* include the file name. |  | ||||||
|     - view (bool): View the output of the command as it happens. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     tokens = ["tar"] |  | ||||||
|     switches = ["-cz"] |  | ||||||
| 
 |  | ||||||
|     if absolute: |  | ||||||
|         switches.append("P") |  | ||||||
| 
 |  | ||||||
|     if view: |  | ||||||
|         switches.append("v") |  | ||||||
| 
 |  | ||||||
|     tokens.append("".join(switches)) |  | ||||||
| 
 |  | ||||||
|     if exclude: |  | ||||||
|         tokens.append("--exclude %s" % exclude) |  | ||||||
| 
 |  | ||||||
|     if strip: |  | ||||||
|         tokens.append("--strip-components %s" % strip) |  | ||||||
| 
 |  | ||||||
|     to_path = os.path.join(to_path, file_name) |  | ||||||
|     tokens.append('-f %s %s' % (to_path, from_path)) |  | ||||||
| 
 |  | ||||||
|     name = " ".join(tokens) |  | ||||||
| 
 |  | ||||||
|     return Command(name, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def certbot(domain_name, email=None, webroot=None, **kwargs): |  | ||||||
|     """Get new SSL certificate from Let's Encrypt. |  | ||||||
| 
 |  | ||||||
|     - domain_name (str): The domain name for which the SSL certificate is requested. |  | ||||||
|     - email (str): The email address of the requester sent to the certificate authority. Required. |  | ||||||
|     - webroot (str): The directory where the challenge file will be created. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     _email = email or os.environ.get("SCRIPTTEASE_CERTBOT_EMAIL", None) |  | ||||||
|     _webroot = webroot or os.path.join("/var", "www", "domains", domain_name.replace(".", "_"), "www") |  | ||||||
| 
 |  | ||||||
|     if not _email: |  | ||||||
|         raise ValueError("Email is required for certbot command.") |  | ||||||
| 
 |  | ||||||
|     template = "certbot certonly --agree-tos --email %(email)s -n --webroot -w %(webroot)s -d %(domain_name)s" |  | ||||||
|     name = template % { |  | ||||||
|         'domain_name': domain_name, |  | ||||||
|         'email': _email, |  | ||||||
|         'webroot': _webroot, |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return Command(name, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def dialog(message, height=15, title="Message", width=100, **kwargs): |  | ||||||
|     """Display a dialog message. |  | ||||||
| 
 |  | ||||||
|     - message (str): The message to be displayed. |  | ||||||
|     - height (int): The height of the dialog. |  | ||||||
|     - title (str): The title of the dialog. |  | ||||||
|     - width (int): The width of the dialog. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "display a dialog message") |  | ||||||
| 
 |  | ||||||
|     a = list() |  | ||||||
|     a.append('dialog --clear --backtitle "%s"' % title) |  | ||||||
|     a.append('--msgbox "%s" %s %s; clear;' % (message, height, width)) |  | ||||||
| 
 |  | ||||||
|     return Command(" ".join(a), **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def echo(message, **kwargs): |  | ||||||
|     """Echo a message. |  | ||||||
| 
 |  | ||||||
|     - message (str): The message to be printed to screen. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "print message to screen") |  | ||||||
| 
 |  | ||||||
|     return Command('echo "%s"' % message, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def extract(from_path, absolute=False, exclude=None, strip=None, to_path=None, view=False, **kwargs): |  | ||||||
|     """Extract a file archive. |  | ||||||
| 
 |  | ||||||
|     - from_path (str): The path that should be archived. |  | ||||||
|     - absolute (bool): Set to ``True`` to preserve the leading slash. |  | ||||||
|     - exclude (str): A pattern to be excluded from the archive. |  | ||||||
|     - strip (int): Remove the specified number of leading elements from the path. |  | ||||||
|     - to_path (str): Where the archive should be extracted. This should *not* include the file name. |  | ||||||
|     - view (bool): View the output of the command as it happens. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     _to_path = to_path or "./" |  | ||||||
| 
 |  | ||||||
|     tokens = ["tar"] |  | ||||||
|     switches = ["-xz"] |  | ||||||
| 
 |  | ||||||
|     if absolute: |  | ||||||
|         switches.append("P") |  | ||||||
| 
 |  | ||||||
|     if view: |  | ||||||
|         switches.append("v") |  | ||||||
| 
 |  | ||||||
|     tokens.append("".join(switches)) |  | ||||||
| 
 |  | ||||||
|     if exclude: |  | ||||||
|         tokens.append("--exclude %s" % exclude) |  | ||||||
| 
 |  | ||||||
|     if strip: |  | ||||||
|         tokens.append("--strip-components %s" % strip) |  | ||||||
| 
 |  | ||||||
|     tokens.append('-f %s %s' % (from_path, _to_path)) |  | ||||||
| 
 |  | ||||||
|     name = " ".join(tokens) |  | ||||||
| 
 |  | ||||||
|     return Command(name, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def file_append(path, content=None, **kwargs): |  | ||||||
|     """Append content to a file. |  | ||||||
| 
 |  | ||||||
|     - path (str): The path to the file. |  | ||||||
|     - content (str): The content to be appended. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "append to %s" % path) |  | ||||||
| 
 |  | ||||||
|     statement = 'echo "%s" >> %s' % (content or "", path) |  | ||||||
| 
 |  | ||||||
|     return Command(statement, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def file_copy(from_path, to_path, overwrite=False, recursive=False, **kwargs): |  | ||||||
|     """Copy a file or directory. |  | ||||||
| 
 |  | ||||||
|     - from_path (str): The file or directory to be copied. |  | ||||||
|     - to_path (str): The location to which the file or directory should be copied. |  | ||||||
|     - overwrite (bool): Indicates files and directories should be overwritten if they exist. |  | ||||||
|     - recursive (bool): Copy sub-directories. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "copy %s to %s" % (from_path, to_path)) |  | ||||||
| 
 |  | ||||||
|     a = list() |  | ||||||
|     a.append("cp") |  | ||||||
| 
 |  | ||||||
|     if not overwrite: |  | ||||||
|         a.append("-n") |  | ||||||
| 
 |  | ||||||
|     if recursive: |  | ||||||
|         a.append("-R") |  | ||||||
| 
 |  | ||||||
|     a.append(from_path) |  | ||||||
|     a.append(to_path) |  | ||||||
| 
 |  | ||||||
|     return Command(" ".join(a), **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def file_write(path, content=None, **kwargs): |  | ||||||
|     """Write to a file. |  | ||||||
| 
 |  | ||||||
|     - path (str): The file to be written. |  | ||||||
|     - content (str): The content to be written. Note: If omitted, this command is equivalent to ``touch``. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     _content = content or "" |  | ||||||
| 
 |  | ||||||
|     kwargs.setdefault("comment", "write to %s" % path) |  | ||||||
| 
 |  | ||||||
|     a = list() |  | ||||||
| 
 |  | ||||||
|     if len(_content.split("\n")) > 1: |  | ||||||
|         a.append("cat > %s << EOF" % path) |  | ||||||
|         a.append(_content) |  | ||||||
|         a.append("EOF") |  | ||||||
|     else: |  | ||||||
|         a.append('echo "%s" > %s' % (_content, path)) |  | ||||||
| 
 |  | ||||||
|     return Command(" ".join(a), **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def mkdir(path, mode=None, recursive=True, **kwargs): |  | ||||||
|     """Create a directory. |  | ||||||
| 
 |  | ||||||
|     - path (str): The path to be created. |  | ||||||
|     - mode (int | str): The access permissions of the new directory. |  | ||||||
|     - recursive (bool): Create all directories along the path. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "create directory %s" % path) |  | ||||||
| 
 |  | ||||||
|     statement = ["mkdir"] |  | ||||||
|     if mode is not None: |  | ||||||
|         statement.append("-m %s" % mode) |  | ||||||
| 
 |  | ||||||
|     if recursive: |  | ||||||
|         statement.append("-p") |  | ||||||
| 
 |  | ||||||
|     statement.append(path) |  | ||||||
| 
 |  | ||||||
|     return Command(" ".join(statement), **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def move(from_path, to_path, **kwargs): |  | ||||||
|     """Move a file or directory. |  | ||||||
|      |  | ||||||
|     - from_path (str): The current path. |  | ||||||
|     - to_path (str): The new path. |  | ||||||
|      |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "move %s to %s" % (from_path, to_path)) |  | ||||||
|     statement = "mv %s %s" % (from_path, to_path) |  | ||||||
| 
 |  | ||||||
|     return Command(statement, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def perms(path, group=None, mode=None, owner=None, recursive=False, **kwargs): |  | ||||||
|     """Set permissions on a file or directory. |  | ||||||
| 
 |  | ||||||
|     - path (str): The path to be changed. |  | ||||||
|     - group (str): The name of the group to be applied. |  | ||||||
|     - mode (int | str): The access permissions of the file or directory. |  | ||||||
|     - owner (str): The name of the user to be applied. |  | ||||||
|     - recursive: Create all directories along the path. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     commands = list() |  | ||||||
| 
 |  | ||||||
|     kwargs['comment'] = "set permissions on %s" % path |  | ||||||
| 
 |  | ||||||
|     if group is not None: |  | ||||||
|         statement = ["chgrp"] |  | ||||||
| 
 |  | ||||||
|         if recursive: |  | ||||||
|             statement.append("-R") |  | ||||||
| 
 |  | ||||||
|         statement.append(group) |  | ||||||
|         statement.append(path) |  | ||||||
| 
 |  | ||||||
|         commands.append(Command(" ".join(statement), **kwargs)) |  | ||||||
| 
 |  | ||||||
|     if owner is not None: |  | ||||||
|         statement = ["chown"] |  | ||||||
| 
 |  | ||||||
|         if recursive: |  | ||||||
|             statement.append("-R") |  | ||||||
| 
 |  | ||||||
|         statement.append(owner) |  | ||||||
|         statement.append(path) |  | ||||||
| 
 |  | ||||||
|         commands.append(Command(" ".join(statement), **kwargs)) |  | ||||||
| 
 |  | ||||||
|     if mode is not None: |  | ||||||
|         statement = ["chmod"] |  | ||||||
| 
 |  | ||||||
|         if recursive: |  | ||||||
|             statement.append("-R") |  | ||||||
| 
 |  | ||||||
|         statement.append(str(mode)) |  | ||||||
|         statement.append(path) |  | ||||||
| 
 |  | ||||||
|         commands.append(Command(" ".join(statement), **kwargs)) |  | ||||||
| 
 |  | ||||||
|     kwargs.setdefault("comment", "set permissions on %s" % path) |  | ||||||
| 
 |  | ||||||
|     a = list() |  | ||||||
|     for c in commands: |  | ||||||
|         a.append(c.get_statement(suppress_comment=True)) |  | ||||||
| 
 |  | ||||||
|     return Command("\n".join(a), **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def prompt(name, back_title="Input", choices=None, default=None, fancy=False, help_text=None, label=None, **kwargs): |  | ||||||
|     """Prompt the user for input. |  | ||||||
| 
 |  | ||||||
|     - name (str): The programmatic name of the input. |  | ||||||
|     - back_title (str): The back title used with the dialog command. |  | ||||||
|     - choices (str | list): A list of valid choices. |  | ||||||
|     - default: The default value. |  | ||||||
|     - fancy (bool): Use a dialog command for the prompt. |  | ||||||
|     - help_text (str): The text to display with the dialog command. |  | ||||||
|     - label (str): The label for the input. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     return Prompt( |  | ||||||
|         name, |  | ||||||
|         back_title=back_title, |  | ||||||
|         choices=choices, |  | ||||||
|         default=default, |  | ||||||
|         fancy=fancy, |  | ||||||
|         help_text=help_text, |  | ||||||
|         label=label, |  | ||||||
|         **kwargs |  | ||||||
|     ) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def remove(path, force=False, recursive=False, **kwargs): |  | ||||||
|     """Remove a file or directory. |  | ||||||
| 
 |  | ||||||
|     - path (str): The path to be removed. |  | ||||||
|     - force (bool): Force the removal. |  | ||||||
|     - recursive (bool): Remove all directories along the path. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "remove %s" % path) |  | ||||||
| 
 |  | ||||||
|     statement = ["rm"] |  | ||||||
| 
 |  | ||||||
|     if force: |  | ||||||
|         statement.append("-f") |  | ||||||
| 
 |  | ||||||
|     if recursive: |  | ||||||
|         statement.append("-r") |  | ||||||
| 
 |  | ||||||
|     statement.append(path) |  | ||||||
| 
 |  | ||||||
|     return Command(" ".join(statement), **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def rename(from_name, to_name, **kwargs): |  | ||||||
|     """Rename a file or directory. |  | ||||||
| 
 |  | ||||||
|     - from_name (str): The name (or path) of the existing file. |  | ||||||
|     - to_name (str): The name (or path) of the new file. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "rename %s" % from_name) |  | ||||||
|     return move(from_name, to_name, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def rsync(source, target, delete=False, exclude=None, host=None, key_file=None, links=True, port=22, |  | ||||||
|           recursive=True, user=None, **kwargs): |  | ||||||
|     """Synchronize a directory structure. |  | ||||||
| 
 |  | ||||||
|     - source (str): The source directory. |  | ||||||
|     - target (str): The target directory. |  | ||||||
|     - delete (bool): Indicates target files that exist in source but not in target should be removed. |  | ||||||
|     - exclude (str): The path to an exclude file. |  | ||||||
|     - host (str): The host name or IP address. This causes the command to run over SSH. |  | ||||||
|     - key_file (str): The privacy SSH key (path) for remote connections. User expansion is automatically applied. |  | ||||||
|     - links (bool): Include symlinks in the sync. |  | ||||||
|     - port (int): The SSH port to use for remote connections. |  | ||||||
|     - recursive (bool): Indicates source contents should be recursively synchronized. |  | ||||||
|     - user (str): The user name to use for remote connections. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     # - guess: When ``True``, the ``host``, ``key_file``, and ``user`` will be guessed based on the base name of |  | ||||||
|     #               the source path. |  | ||||||
|     # :type guess: bool |  | ||||||
|     # if guess: |  | ||||||
|     #     host = host or os.path.basename(source).replace("_", ".") |  | ||||||
|     #     key_file = key_file or os.path.expanduser(os.path.join("~/.ssh", os.path.basename(source))) |  | ||||||
|     #     user = user or os.path.basename(source) |  | ||||||
|     # else: |  | ||||||
|     #     host = host |  | ||||||
|     #     key_file = key_file |  | ||||||
|     #     user = user |  | ||||||
| 
 |  | ||||||
|     kwargs.setdefault("comment", "sync %s with %s" % (source, target)) |  | ||||||
| 
 |  | ||||||
|     # rsync -e "ssh -i $(SSH_KEY) -p $(SSH_PORT)" -P -rvzc --delete |  | ||||||
|     # $(OUTPUTH_PATH) $(SSH_USER)@$(SSH_HOST):$(UPLOAD_PATH) --cvs-exclude; |  | ||||||
| 
 |  | ||||||
|     tokens = list() |  | ||||||
|     tokens.append("rsync") |  | ||||||
|     tokens.append("--cvs-exclude") |  | ||||||
|     tokens.append("--checksum") |  | ||||||
|     tokens.append("--compress") |  | ||||||
| 
 |  | ||||||
|     if links: |  | ||||||
|         tokens.append("--copy-links") |  | ||||||
| 
 |  | ||||||
|     if delete: |  | ||||||
|         tokens.append("--delete") |  | ||||||
| 
 |  | ||||||
|     if exclude is not None: |  | ||||||
|         tokens.append("--exclude-from=%s" % exclude) |  | ||||||
| 
 |  | ||||||
|     # --partial and --progress |  | ||||||
|     tokens.append("-P") |  | ||||||
| 
 |  | ||||||
|     if recursive: |  | ||||||
|         tokens.append("--recursive") |  | ||||||
| 
 |  | ||||||
|     tokens.append(source) |  | ||||||
| 
 |  | ||||||
|     conditions = [ |  | ||||||
|         host is not None, |  | ||||||
|         key_file is not None, |  | ||||||
|         user is not None, |  | ||||||
|     ] |  | ||||||
|     if all(conditions): |  | ||||||
|         tokens.append('-e "ssh -i %s -p %s"' % (key_file, port)) |  | ||||||
|         tokens.append("%s@%s:%s" % (user, host, target)) |  | ||||||
|     else: |  | ||||||
|         tokens.append(target) |  | ||||||
| 
 |  | ||||||
|     statement = " ".join(tokens) |  | ||||||
| 
 |  | ||||||
|     return Command(statement, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def scopy(from_path, to_path, host=None, key_file=None, port=22, user=None, **kwargs): |  | ||||||
|     """Copy a file or directory to a remote server. |  | ||||||
| 
 |  | ||||||
|     - from_path (str): The source directory. |  | ||||||
|     - to_path (str): The target directory. |  | ||||||
|     - host (str): The host name or IP address. Required. |  | ||||||
|     - key_file (str): The privacy SSH key (path) for remote connections. User expansion is automatically applied. |  | ||||||
|     - port (int): The SSH port to use for remote connections. |  | ||||||
|     - user (str): The user name to use for remote connections. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "copy %s to remote %s" % (from_path, to_path)) |  | ||||||
| 
 |  | ||||||
|     # TODO: What to do to force local versus remote commands? |  | ||||||
|     # kwargs['local'] = True |  | ||||||
| 
 |  | ||||||
|     kwargs['sudo'] = False |  | ||||||
| 
 |  | ||||||
|     statement = ["scp"] |  | ||||||
| 
 |  | ||||||
|     if key_file is not None: |  | ||||||
|         statement.append("-i %s" % key_file) |  | ||||||
| 
 |  | ||||||
|     statement.append("-P %s" % port) |  | ||||||
|     statement.append(from_path) |  | ||||||
| 
 |  | ||||||
|     if host is not None and user is not None: |  | ||||||
|         statement.append("%s@%s:%s" % (user, host, to_path)) |  | ||||||
|     elif host is not None: |  | ||||||
|         statement.append("%s:%s" % (host, to_path)) |  | ||||||
|     else: |  | ||||||
|         raise ValueError("Host is a required keyword argument.") |  | ||||||
| 
 |  | ||||||
|     return Command(" ".join(statement), **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def sed(path, backup=".b", delimiter="/", find=None, replace=None, **kwargs): |  | ||||||
|     """Find and replace text in a file. |  | ||||||
| 
 |  | ||||||
|     - path (str): The path to the file to be edited. |  | ||||||
|     - backup (str): The backup file extension to use. |  | ||||||
|     - delimiter (str): The pattern delimiter. |  | ||||||
|     - find (str): The old text. Required. |  | ||||||
|     - replace (str): The new text. Required. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     kwargs.setdefault("comment", "find and replace in %s" % path) |  | ||||||
| 
 |  | ||||||
|     context = { |  | ||||||
|         'backup': backup, |  | ||||||
|         'delimiter': delimiter, |  | ||||||
|         'path': path, |  | ||||||
|         'pattern': find, |  | ||||||
|         'replace': replace, |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     template = "sed -i %(backup)s 's%(delimiter)s%(pattern)s%(delimiter)s%(replace)s%(delimiter)sg' %(path)s" |  | ||||||
| 
 |  | ||||||
|     statement = template % context |  | ||||||
| 
 |  | ||||||
|     return Command(statement, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def symlink(source, force=False, target=None, **kwargs): |  | ||||||
|     """Create a symlink. |  | ||||||
| 
 |  | ||||||
|     - source (str): The source of the link. |  | ||||||
|     - force (bool): Force the creation of the link. |  | ||||||
|     - target (str): The name or path of the target. Defaults to the base name of the source path. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     _target = target or os.path.basename(source) |  | ||||||
| 
 |  | ||||||
|     kwargs.setdefault("comment", "link to %s" % source) |  | ||||||
| 
 |  | ||||||
|     statement = ["ln -s"] |  | ||||||
| 
 |  | ||||||
|     if force: |  | ||||||
|         statement.append("-f") |  | ||||||
| 
 |  | ||||||
|     statement.append(source) |  | ||||||
|     statement.append(_target) |  | ||||||
| 
 |  | ||||||
|     return Command(" ".join(statement), **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def touch(path, **kwargs): |  | ||||||
|     """Touch a file or directory. |  | ||||||
| 
 |  | ||||||
|     - path (str): The file or directory to touch. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "touch %s" % path) |  | ||||||
| 
 |  | ||||||
|     return Command("touch %s" % path, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def wait(seconds, **kwargs): |  | ||||||
|     """Pause execution for a number of seconds. |  | ||||||
| 
 |  | ||||||
|     - seconds (int): The number of seconds to wait. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "pause for %s seconds" % seconds) |  | ||||||
| 
 |  | ||||||
|     return Command("sleep %s" % seconds, **kwargs) |  | ||||||
| 
 |  | ||||||
| # Classes |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Function(object): |  | ||||||
|     """A function that may be used to organize related commands to be called together.""" |  | ||||||
| 
 |  | ||||||
|     def __init__(self, name, commands=None, comment=None): |  | ||||||
|         """Initialize a function. |  | ||||||
| 
 |  | ||||||
|         :param name: The name of the function. |  | ||||||
|         :type name: str |  | ||||||
| 
 |  | ||||||
|         :param commands: The command instances to be included in the function's output. |  | ||||||
|         :type commands: list |  | ||||||
| 
 |  | ||||||
|         :param comment: A comment regarding the function. |  | ||||||
|         :type comment: str |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         self.commands = commands or list() |  | ||||||
|         self.comment = comment |  | ||||||
|         self.name = name |  | ||||||
| 
 |  | ||||||
|     def to_string(self): |  | ||||||
|         """Export the function as a string. |  | ||||||
| 
 |  | ||||||
|         :rtype: str |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         a = list() |  | ||||||
| 
 |  | ||||||
|         if self.comment is not None: |  | ||||||
|             a.append("# %s" % self.comment) |  | ||||||
| 
 |  | ||||||
|         a.append("function %s()" % self.name) |  | ||||||
|         a.append("{") |  | ||||||
|         for command in self.commands: |  | ||||||
|             a.append(indent(command.get_statement(cd=True))) |  | ||||||
|             a.append("") |  | ||||||
| 
 |  | ||||||
|         a.append("}") |  | ||||||
| 
 |  | ||||||
|         return "\n".join(a) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Prompt(Command): |  | ||||||
|     """Prompt the user for input.""" |  | ||||||
| 
 |  | ||||||
|     def __init__(self, name, back_title="Input", choices=None, default=None, fancy=False, help_text=None, label=None, |  | ||||||
|                  **kwargs): |  | ||||||
|         """Initialize a prompt for user input. |  | ||||||
| 
 |  | ||||||
|         :param name: The variable name. |  | ||||||
|         :type name: str |  | ||||||
| 
 |  | ||||||
|         :param back_title: The back title of the input. Used only when ``dialog`` is enabled. |  | ||||||
|         :type back_title: str |  | ||||||
| 
 |  | ||||||
|         :param choices: Valid choices for the variable. May be given as a list of strings or a comma separated string. |  | ||||||
|         :type choices: list[str] | str |  | ||||||
| 
 |  | ||||||
|         :param default: The default value of the variable. |  | ||||||
| 
 |  | ||||||
|         :param fancy: Indicates the dialog command should be used. |  | ||||||
|         :type fancy: bool |  | ||||||
| 
 |  | ||||||
|         :param help_text: Additional text to display. Only use when ``fancy`` is ``True``. |  | ||||||
|         :type help_text: str |  | ||||||
| 
 |  | ||||||
|         :param label: The label of the prompt. |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         self.back_title = back_title |  | ||||||
|         self.default = default |  | ||||||
|         self.dialog_enabled = fancy |  | ||||||
|         self.help_text = help_text |  | ||||||
|         self.label = label or name.replace("_", " ").title() |  | ||||||
|         self.variable_name = name |  | ||||||
| 
 |  | ||||||
|         if type(choices) in (list, tuple): |  | ||||||
|             self.choices = choices |  | ||||||
|         elif type(choices) is str: |  | ||||||
|             self.choices = split_csv(choices, smart=False) |  | ||||||
|             # for i in choices.split(","): |  | ||||||
|             #     self.choices.append(i.strip()) |  | ||||||
|         else: |  | ||||||
|             self.choices = None |  | ||||||
| 
 |  | ||||||
|         kwargs.setdefault("comment", "prompt user for %s input" % name) |  | ||||||
| 
 |  | ||||||
|         super().__init__(name, **kwargs) |  | ||||||
| 
 |  | ||||||
|     def get_statement(self, cd=False, suppress_comment=False): |  | ||||||
|         """Get the statement using dialog or read.""" |  | ||||||
|         if self.dialog_enabled: |  | ||||||
|             return self._get_dialog_statement() |  | ||||||
| 
 |  | ||||||
|         return self._get_read_statement() |  | ||||||
| 
 |  | ||||||
|     def _get_dialog_statement(self): |  | ||||||
|         """Get the dialog statement.""" |  | ||||||
|         a = list() |  | ||||||
| 
 |  | ||||||
|         a.append('dialog --clear --backtitle "%s" --title "%s"' % (self.back_title, self.label)) |  | ||||||
| 
 |  | ||||||
|         if self.choices is not None: |  | ||||||
|             a.append('--menu "%s" 15 40 %s' % (self.help_text or "Select", len(self.choices))) |  | ||||||
|             count = 1 |  | ||||||
|             for choice in self.choices: |  | ||||||
|                 a.append('"%s" %s' % (choice, count)) |  | ||||||
|                 count += 1 |  | ||||||
| 
 |  | ||||||
|             a.append('2>/tmp/input.txt') |  | ||||||
|         else: |  | ||||||
|             if self.help_text is not None: |  | ||||||
|                 a.append('--inputbox "%s"' % self.help_text) |  | ||||||
|             else: |  | ||||||
|                 a.append('--inputbox ""') |  | ||||||
| 
 |  | ||||||
|             a.append('8 60 2>/tmp/input.txt') |  | ||||||
| 
 |  | ||||||
|         b = list() |  | ||||||
| 
 |  | ||||||
|         b.append('touch /tmp/input.txt') |  | ||||||
|         b.append(" ".join(a)) |  | ||||||
| 
 |  | ||||||
|         b.append('%s=$(</tmp/input.txt)' % self.variable_name) |  | ||||||
|         b.append('clear') |  | ||||||
|         b.append('rm /tmp/input.txt') |  | ||||||
| 
 |  | ||||||
|         if self.default is not None: |  | ||||||
|             b.append('if [[ -z "$%s" ]]; then %s="%s"; fi;' % (self.variable_name, self.variable_name, self.default)) |  | ||||||
| 
 |  | ||||||
|         # b.append('echo "$%s"' % self.name) |  | ||||||
| 
 |  | ||||||
|         return "\n".join(b) |  | ||||||
| 
 |  | ||||||
|     def _get_read_statement(self): |  | ||||||
|         """Get the standard read statement.""" |  | ||||||
|         a = list() |  | ||||||
| 
 |  | ||||||
|         if self.choices is not None: |  | ||||||
|             a.append('echo "%s "' % self.label) |  | ||||||
| 
 |  | ||||||
|             options = list() |  | ||||||
|             for choice in self.choices: |  | ||||||
|                 options.append('"%s"' % choice) |  | ||||||
| 
 |  | ||||||
|             a.append('options=(%s)' % " ".join(options)) |  | ||||||
|             a.append('select opt in "${options[@]}"') |  | ||||||
|             a.append('do') |  | ||||||
|             a.append('    case $opt in') |  | ||||||
| 
 |  | ||||||
|             for choice in self.choices: |  | ||||||
|                 a.append('        "%s") %s=$opt; break;;' % (choice, self.variable_name)) |  | ||||||
| 
 |  | ||||||
|             # a.append('        %s) %s=$opt;;' % ("|".join(self.choices), self.name)) |  | ||||||
|             a.append('        *) echo "invalid choice";;') |  | ||||||
|             a.append('    esac') |  | ||||||
|             a.append('done') |  | ||||||
| 
 |  | ||||||
|             # a.append("read %s" % self.name) |  | ||||||
|         else: |  | ||||||
|             a.append('echo -n "%s "' % self.label) |  | ||||||
|             a.append("read %s" % self.variable_name) |  | ||||||
| 
 |  | ||||||
|         if self.default is not None: |  | ||||||
|             a.append('if [[ -z "$%s" ]]; then %s="%s"; fi;' % (self.variable_name, self.variable_name, self.default)) |  | ||||||
| 
 |  | ||||||
|         # a.append('echo "$%s"' % self.name) |  | ||||||
| 
 |  | ||||||
|         return "\n".join(a) |  | ||||||
| 
 |  | ||||||
| # Mappings |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| POSIX_MAPPINGS = { |  | ||||||
|     'append': file_append, |  | ||||||
|     'archive': archive, |  | ||||||
|     'certbot': certbot, |  | ||||||
|     'copy': file_copy, |  | ||||||
|     'dialog': dialog, |  | ||||||
|     'echo': echo, |  | ||||||
|     'extract': extract, |  | ||||||
|     'func': Function, |  | ||||||
|     # 'function': Function, |  | ||||||
|     'mkdir': mkdir, |  | ||||||
|     'move': move, |  | ||||||
|     'perms': perms, |  | ||||||
|     'prompt': prompt, |  | ||||||
|     'push': rsync, |  | ||||||
|     'remove': remove, |  | ||||||
|     'rename': rename, |  | ||||||
|     'rsync': rsync, |  | ||||||
|     'scopy': scopy, |  | ||||||
|     'sed': sed, |  | ||||||
|     'ssl': certbot, |  | ||||||
|     'symlink': symlink, |  | ||||||
|     'touch': touch, |  | ||||||
|     'wait': wait, |  | ||||||
|     'write': file_write, |  | ||||||
| } |  | ||||||
| @ -1,338 +0,0 @@ | |||||||
| # Imports |  | ||||||
| 
 |  | ||||||
| from commonkit import split_csv |  | ||||||
| from ..commands import Command, Template |  | ||||||
| from .common import COMMON_MAPPINGS |  | ||||||
| from .django import DJANGO_MAPPINGS |  | ||||||
| from .mysql import MYSQL_MAPPINGS |  | ||||||
| from .pgsql import PGSQL_MAPPINGS |  | ||||||
| from .posix import POSIX_MAPPINGS, Function |  | ||||||
| 
 |  | ||||||
| # Exports |  | ||||||
| 
 |  | ||||||
| __all__ = ( |  | ||||||
|     "MAPPINGS", |  | ||||||
|     "apache", |  | ||||||
|     "apache_disable_module", |  | ||||||
|     "apache_disable_site", |  | ||||||
|     "apache_enable_module", |  | ||||||
|     "apache_enable_site", |  | ||||||
|     "apache_reload", |  | ||||||
|     "apache_restart", |  | ||||||
|     "apache_start", |  | ||||||
|     "apache_stop", |  | ||||||
|     "apache_test", |  | ||||||
|     "command_exists", |  | ||||||
|     "service_reload", |  | ||||||
|     "service_restart", |  | ||||||
|     "service_start", |  | ||||||
|     "service_stop", |  | ||||||
|     "system", |  | ||||||
|     "system_install", |  | ||||||
|     "system_reboot", |  | ||||||
|     "system_update", |  | ||||||
|     "system_upgrade", |  | ||||||
|     "system_uninstall", |  | ||||||
|     "template", |  | ||||||
|     "user", |  | ||||||
|     "Function", |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def command_exists(name): |  | ||||||
|     """Indicates whether a given command exists in this overlay. |  | ||||||
| 
 |  | ||||||
|     :param name: The name of the command. |  | ||||||
|     :type name: str |  | ||||||
| 
 |  | ||||||
|     :rtype: bool |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     return name in MAPPINGS |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def apache(op, **kwargs): |  | ||||||
|     """Execute an Apache-related command. |  | ||||||
| 
 |  | ||||||
|     - op (str): The operation to perform; reload, restart, start, stop, test. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     if op == "reload": |  | ||||||
|         return apache_reload(**kwargs) |  | ||||||
|     elif op == "restart": |  | ||||||
|         return apache_restart(**kwargs) |  | ||||||
|     elif op == "start": |  | ||||||
|         return apache_start(**kwargs) |  | ||||||
|     elif op == "stop": |  | ||||||
|         return apache_stop(**kwargs) |  | ||||||
|     elif op == "test": |  | ||||||
|         return apache_test(**kwargs) |  | ||||||
|     else: |  | ||||||
|         raise NameError("Unrecognized or unsupported apache operation: %s" % op) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def apache_disable_module(name, **kwargs): |  | ||||||
|     """Disable an Apache module. |  | ||||||
| 
 |  | ||||||
|     - name (str): The module name. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "disable %s apache module" % name) |  | ||||||
| 
 |  | ||||||
|     return Command("a2dismod %s" % name, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def apache_disable_site(name, **kwargs): |  | ||||||
|     """Disable an Apache site. |  | ||||||
| 
 |  | ||||||
|     - name (str): The domain name. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "disable %s apache site" % name) |  | ||||||
| 
 |  | ||||||
|     return Command("a2dissite %s" % name, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def apache_enable_module(name, **kwargs): |  | ||||||
|     """Enable an Apache module. |  | ||||||
| 
 |  | ||||||
|     - name (str): The module name. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "enable %s apache module" % name) |  | ||||||
| 
 |  | ||||||
|     return Command("a2enmod %s" % name, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def apache_enable_site(name, **kwargs): |  | ||||||
|     """Enable an Apache site. |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "enable %s apache module" % name) |  | ||||||
| 
 |  | ||||||
|     return Command("a2ensite %s" % name, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def apache_reload(**kwargs): |  | ||||||
|     kwargs.setdefault("comment", "reload apache") |  | ||||||
|     kwargs.setdefault("register", "apache_reloaded") |  | ||||||
| 
 |  | ||||||
|     return Command("service apache2 reload", **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def apache_restart(**kwargs): |  | ||||||
|     kwargs.setdefault("comment", "restart apache") |  | ||||||
|     kwargs.setdefault("register", "apache_restarted") |  | ||||||
| 
 |  | ||||||
|     return Command("service apache2 restart", **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def apache_start(**kwargs): |  | ||||||
|     kwargs.setdefault("comment", "start apache") |  | ||||||
|     kwargs.setdefault("register", "apache_started") |  | ||||||
| 
 |  | ||||||
|     return Command("service apache2 start", **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def apache_stop(**kwargs): |  | ||||||
|     kwargs.setdefault("comment", "stop apache") |  | ||||||
| 
 |  | ||||||
|     return Command("service apache2 stop", **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def apache_test(**kwargs): |  | ||||||
|     kwargs.setdefault("comment", "check apache configuration") |  | ||||||
|     kwargs.setdefault("register", "apache_checks_out") |  | ||||||
| 
 |  | ||||||
|     return Command("apachectl configtest", **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def service_reload(name, **kwargs): |  | ||||||
|     """Reload a service. |  | ||||||
| 
 |  | ||||||
|     - name (str): The service name. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "reload %s service" % name) |  | ||||||
|     kwargs.setdefault("register", "%s_reloaded" % name) |  | ||||||
| 
 |  | ||||||
|     return Command("service %s reload" % name, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def service_restart(name, **kwargs): |  | ||||||
|     """Restart a service. |  | ||||||
| 
 |  | ||||||
|     - name (str): The service name. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "restart %s service" % name) |  | ||||||
|     kwargs.setdefault("register", "%s_restarted" % name) |  | ||||||
| 
 |  | ||||||
|     return Command("service %s restart" % name, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def service_start(name, **kwargs): |  | ||||||
|     """Start a service. |  | ||||||
| 
 |  | ||||||
|     - name (str): The service name. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "start %s service" % name) |  | ||||||
|     kwargs.setdefault("register", "%s_started" % name) |  | ||||||
| 
 |  | ||||||
|     return Command("service %s start" % name, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def service_stop(name, **kwargs): |  | ||||||
|     """Stop a service. |  | ||||||
| 
 |  | ||||||
|     - name (str): The service name. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "stop %s service" % name) |  | ||||||
|     kwargs.setdefault("register", "%s_stopped" % name) |  | ||||||
| 
 |  | ||||||
|     return Command("service %s stop" % name, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def system(op, **kwargs): |  | ||||||
|     """Perform a system operation. |  | ||||||
| 
 |  | ||||||
|     - op (str): The operation to perform; reboot, update, upgrade. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     if op == "reboot": |  | ||||||
|         return system_reboot(**kwargs) |  | ||||||
|     elif op == "update": |  | ||||||
|         return system_update(**kwargs) |  | ||||||
|     elif op == "upgrade": |  | ||||||
|         return system_upgrade(**kwargs) |  | ||||||
|     else: |  | ||||||
|         raise NameError("Unrecognized or unsupported system operation: %s" % op) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def system_install(name, **kwargs): |  | ||||||
|     """Install a system-level package. |  | ||||||
| 
 |  | ||||||
|     - name (str): The name of the package to install. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "install system package %s" % name) |  | ||||||
| 
 |  | ||||||
|     return Command("apt-get install -y %s" % name, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def system_reboot(**kwargs): |  | ||||||
|     kwargs.setdefault("comment", "reboot the system") |  | ||||||
| 
 |  | ||||||
|     return Command("reboot", **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def system_uninstall(name, **kwargs): |  | ||||||
|     """Uninstall a system-level package. |  | ||||||
| 
 |  | ||||||
|     - name (str): The name of the package to uninstall. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     kwargs.setdefault("comment", "remove system package %s" % name) |  | ||||||
| 
 |  | ||||||
|     return Command("apt-get uninstall -y %s" % name, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def system_update(**kwargs): |  | ||||||
|     kwargs.setdefault("comment", "update system package info") |  | ||||||
| 
 |  | ||||||
|     return Command("apt-get update -y", **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def system_upgrade(**kwargs): |  | ||||||
|     kwargs.setdefault("comment", "upgrade the system") |  | ||||||
| 
 |  | ||||||
|     return Command("apt-get upgrade -y", **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def template(source, target, backup=True, parser=None, **kwargs): |  | ||||||
|     """Create a file from a template. |  | ||||||
| 
 |  | ||||||
|     - source (str): The path to the template file. |  | ||||||
|     - target (str): The path to where the new file should be created. |  | ||||||
|     - backup (bool): Indicates whether a backup should be made if the target file already exists. |  | ||||||
|     - parser (str): The parser to use ``jinja`` (the default) or ``simple``. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     return Template(source, target, backup=backup, parser=parser, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def user(name, groups=None, home=None, op="add", password=None, **kwargs): |  | ||||||
|     """Create or remove a user. |  | ||||||
| 
 |  | ||||||
|     - name (str): The user name. |  | ||||||
|     - groups (str | list): A list of groups to which the user should belong. |  | ||||||
|     - home (str): The path to the user's home directory. |  | ||||||
|     - op (str); The operation to perform; ``add`` or ``remove``. |  | ||||||
|     - password (str): The user's password. (NOT IMPLEMENTED) |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     if op == "add": |  | ||||||
|         kwargs.setdefault("comment", "create a user named %s" % name) |  | ||||||
| 
 |  | ||||||
|         commands = list() |  | ||||||
| 
 |  | ||||||
|         # The gecos switch eliminates the prompts. |  | ||||||
|         a = list() |  | ||||||
|         a.append('adduser %s --disabled-password --gecos ""' % name) |  | ||||||
|         if home is not None: |  | ||||||
|             a.append("--home %s" % home) |  | ||||||
| 
 |  | ||||||
|         commands.append(Command(" ".join(a), **kwargs)) |  | ||||||
| 
 |  | ||||||
|         if type(groups) is str: |  | ||||||
|             groups = split_csv(groups, smart=False) |  | ||||||
| 
 |  | ||||||
|         if type(groups) in [list, tuple]: |  | ||||||
|             for group in groups: |  | ||||||
|                 commands.append(Command("adduser %s %s" % (name, group), **kwargs)) |  | ||||||
| 
 |  | ||||||
|         a = list() |  | ||||||
|         for c in commands: |  | ||||||
|             a.append(c.get_statement(suppress_comment=True)) |  | ||||||
| 
 |  | ||||||
|         return Command("\n".join(a), **kwargs) |  | ||||||
|     elif op == "remove": |  | ||||||
|         kwargs.setdefault("comment", "remove a user named %s" % name) |  | ||||||
|         return Command("deluser %s" % name, **kwargs) |  | ||||||
|     else: |  | ||||||
|         raise NameError("Unsupported or unrecognized operation: %s" % op) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| MAPPINGS = { |  | ||||||
|     'apache': apache, |  | ||||||
|     'apache.disable_module': apache_disable_module, |  | ||||||
|     'apache.disable_site': apache_disable_site, |  | ||||||
|     'apache.enable_module': apache_enable_module, |  | ||||||
|     'apache.enable_site': apache_enable_site, |  | ||||||
|     'apache.reload': apache_reload, |  | ||||||
|     'apache.restart': apache_restart, |  | ||||||
|     'apache.start': apache_start, |  | ||||||
|     'apache.stop': apache_stop, |  | ||||||
|     'apache.test': apache_test, |  | ||||||
|     'install': system_install, |  | ||||||
|     'reboot': system_reboot, |  | ||||||
|     'reload': service_reload, |  | ||||||
|     'restart': service_restart, |  | ||||||
|     'start': service_start, |  | ||||||
|     'stop': service_stop, |  | ||||||
|     'system': system, |  | ||||||
|     'template': template, |  | ||||||
|     'update': system_update, |  | ||||||
|     'uninstall': system_uninstall, |  | ||||||
|     'upgrade': system_upgrade, |  | ||||||
|     'user': user, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| MAPPINGS.update(COMMON_MAPPINGS) |  | ||||||
| MAPPINGS.update(DJANGO_MAPPINGS) |  | ||||||
| MAPPINGS.update(MYSQL_MAPPINGS) |  | ||||||
| MAPPINGS.update(PGSQL_MAPPINGS) |  | ||||||
| MAPPINGS.update(POSIX_MAPPINGS) |  | ||||||
| @ -1,69 +0,0 @@ | |||||||
| # Classes |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Script(object): |  | ||||||
|     """A script is a collection of commands.""" |  | ||||||
| 
 |  | ||||||
|     def __init__(self, name, commands=None, functions=None, shell="bash"): |  | ||||||
|         """Initialize a script. |  | ||||||
| 
 |  | ||||||
|         :param name: The name of the script. Note: This becomes the file name. |  | ||||||
|         :type name: str |  | ||||||
| 
 |  | ||||||
|         :param commands: The commands to be included. |  | ||||||
|         :type commands: list[scripttease.library.commands.base.Command] |  | ||||||
| 
 |  | ||||||
|         :param functions: The functions to be included. |  | ||||||
|         :type functions: list[Function] |  | ||||||
| 
 |  | ||||||
|         :param shell: The shell to use for the script. |  | ||||||
|         :type shell: str |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         self.commands = commands or list() |  | ||||||
|         self.functions = functions |  | ||||||
|         self.name = name |  | ||||||
|         self.shell = shell |  | ||||||
| 
 |  | ||||||
|     def __str__(self): |  | ||||||
|         return self.to_string() |  | ||||||
| 
 |  | ||||||
|     def append(self, command): |  | ||||||
|         """Append a command instance to the script's commands. |  | ||||||
| 
 |  | ||||||
|         :param command: The command instance to be included. |  | ||||||
|         :type command: BaseType[Command] | ItemizedCommand |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         self.commands.append(command) |  | ||||||
| 
 |  | ||||||
|     def to_string(self, shebang="#! /usr/bin/env %(shell)s"): |  | ||||||
|         """Export the script as a string. |  | ||||||
| 
 |  | ||||||
|         :param shebang: The shebang to be included. Set to ``None`` to omit the shebang. |  | ||||||
|         :type shebang: str |  | ||||||
| 
 |  | ||||||
|         :rtype: str |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         a = list() |  | ||||||
| 
 |  | ||||||
|         if shebang is not None: |  | ||||||
|             a.append(shebang % {'shell': self.shell}) |  | ||||||
|             a.append("") |  | ||||||
| 
 |  | ||||||
|         if self.functions is not None: |  | ||||||
|             for function in self.functions: |  | ||||||
|                 a.append(function.to_string()) |  | ||||||
|                 a.append("") |  | ||||||
| 
 |  | ||||||
|             # for function in self.functions: |  | ||||||
|             #     a.append("%s;" % function.name) |  | ||||||
| 
 |  | ||||||
|             a.append("") |  | ||||||
| 
 |  | ||||||
|         for command in self.commands: |  | ||||||
|             a.append(command.get_statement(cd=True)) |  | ||||||
|             a.append("") |  | ||||||
| 
 |  | ||||||
|         return "\n".join(a) |  | ||||||
| @ -1,4 +0,0 @@ | |||||||
| # Imports |  | ||||||
| 
 |  | ||||||
| from .ini import Config |  | ||||||
| from .utils import filter_commands, load_commands, load_config |  | ||||||
| @ -1,80 +0,0 @@ | |||||||
| # Imports |  | ||||||
| 
 |  | ||||||
| from commonkit import File |  | ||||||
| from ..factory import Factory |  | ||||||
| from ..library.scripts import Script |  | ||||||
| 
 |  | ||||||
| # Exports |  | ||||||
| 
 |  | ||||||
| __all__ = ( |  | ||||||
|     "Parser", |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| # Classes |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Parser(File): |  | ||||||
|     """Base class for implementing a command parser.""" |  | ||||||
| 
 |  | ||||||
|     def __init__(self, path, context=None, locations=None, options=None, overlay="ubuntu"): |  | ||||||
|         super().__init__(path) |  | ||||||
| 
 |  | ||||||
|         self.context = context |  | ||||||
|         self.factory = Factory(overlay) |  | ||||||
|         self.is_loaded = False |  | ||||||
|         self.locations = locations or list() |  | ||||||
|         self.options = options or dict() |  | ||||||
|         self.overlay = overlay |  | ||||||
|         self._commands = list() |  | ||||||
|         self._functions = list() |  | ||||||
| 
 |  | ||||||
|     def as_script(self): |  | ||||||
|         """Convert loaded commands to a script. |  | ||||||
| 
 |  | ||||||
|         :rtype: Script |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         return Script( |  | ||||||
|             "%s.sh" % self.name, |  | ||||||
|             commands=self.get_commands(), |  | ||||||
|             functions=self.get_functions() |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
|     def get_commands(self): |  | ||||||
|         """Get the commands that have been loaded from the file. |  | ||||||
| 
 |  | ||||||
|         :rtype: list[BaseType[scripttease.library.commands.base.Command]] |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         a = list() |  | ||||||
|         for c in self._commands: |  | ||||||
|             if c.function is not None: |  | ||||||
|                 continue |  | ||||||
| 
 |  | ||||||
|             a.append(c) |  | ||||||
| 
 |  | ||||||
|         return a |  | ||||||
| 
 |  | ||||||
|     def get_functions(self): |  | ||||||
|         """Get the functions that have been loaded from the file. |  | ||||||
| 
 |  | ||||||
|         :rtype: list[scripttease.library.scripts.Function] |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         a = list() |  | ||||||
|         for f in self._functions: |  | ||||||
|             for c in self._commands: |  | ||||||
|                 if c.function is not None and f.name == c.function: |  | ||||||
|                     f.commands.append(c) |  | ||||||
| 
 |  | ||||||
|             a.append(f) |  | ||||||
| 
 |  | ||||||
|         return a |  | ||||||
| 
 |  | ||||||
|     def load(self): |  | ||||||
|         """Load the factory and the configuration file. |  | ||||||
| 
 |  | ||||||
|         :rtype: bool |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         raise NotImplementedError() |  | ||||||
| @ -1,179 +0,0 @@ | |||||||
| # Imports |  | ||||||
| 
 |  | ||||||
| from commonkit import parse_jinja_template, read_file, smart_cast, split_csv |  | ||||||
| from configparser import ConfigParser, ParsingError |  | ||||||
| import logging |  | ||||||
| import os |  | ||||||
| from ..constants import LOGGER_NAME |  | ||||||
| from ..library.commands import ItemizedCommand |  | ||||||
| from ..library.commands.templates import Template |  | ||||||
| from .base import Parser |  | ||||||
| 
 |  | ||||||
| log = logging.getLogger(LOGGER_NAME) |  | ||||||
| 
 |  | ||||||
| # Exports |  | ||||||
| 
 |  | ||||||
| __all__ = ( |  | ||||||
|     "Config", |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| # Classes |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Config(Parser): |  | ||||||
|     """An INI configuration for loading commands.""" |  | ||||||
| 
 |  | ||||||
|     def load(self): |  | ||||||
|         """Load commands from a INI file.""" |  | ||||||
|         if not self.exists: |  | ||||||
|             return False |  | ||||||
| 
 |  | ||||||
|         if not self.factory.load(): |  | ||||||
|             return False |  | ||||||
| 
 |  | ||||||
|         ini = self._load_ini() |  | ||||||
|         if ini is None: |  | ||||||
|             return False |  | ||||||
| 
 |  | ||||||
|         success = True |  | ||||||
|         for comment in ini.sections(): |  | ||||||
|             args = list() |  | ||||||
|             command_name = None |  | ||||||
|             count = 0 |  | ||||||
|             kwargs = self.options.copy() |  | ||||||
|             kwargs['comment'] = comment |  | ||||||
| 
 |  | ||||||
|             for key, value in ini.items(comment): |  | ||||||
|                 # The first key/value pair is the command name and arguments. |  | ||||||
|                 if count == 0: |  | ||||||
|                     command_name = key |  | ||||||
| 
 |  | ||||||
|                     # Arguments surrounded by quotes are considered to be one argument. All others are split into a |  | ||||||
|                     # list to be passed to the callback. It is also possible that this is a call where no arguments are |  | ||||||
|                     # present, so the whole thing is wrapped to protect against an index error. |  | ||||||
|                     try: |  | ||||||
|                         if value[0] == '"': |  | ||||||
|                             args.append(value.replace('"', "")) |  | ||||||
|                         else: |  | ||||||
|                             args = value.split(" ") |  | ||||||
|                     except IndexError: |  | ||||||
|                         pass |  | ||||||
|                 else: |  | ||||||
|                     _key, _value = self._get_key_value(key, value) |  | ||||||
| 
 |  | ||||||
|                     kwargs[_key] = _value |  | ||||||
| 
 |  | ||||||
|                 count += 1 |  | ||||||
| 
 |  | ||||||
|             command = self.factory.get_command(command_name, *args, **kwargs) |  | ||||||
|             if command is not None: |  | ||||||
|                 if isinstance(command, self.factory.overlay.Function): |  | ||||||
|                     self._functions.append(command) |  | ||||||
|                 elif isinstance(command, Template): |  | ||||||
|                     self._load_template(command) |  | ||||||
|                     self._commands.append(command) |  | ||||||
|                 elif isinstance(command, ItemizedCommand): |  | ||||||
|                     itemized_template = False |  | ||||||
|                     for c in command.get_commands(): |  | ||||||
|                         if isinstance(c, Template): |  | ||||||
|                             itemized_template = True |  | ||||||
|                             self._load_template(c) |  | ||||||
|                             self._commands.append(c) |  | ||||||
| 
 |  | ||||||
|                     if not itemized_template: |  | ||||||
|                         self._commands.append(command) |  | ||||||
|                 else: |  | ||||||
|                     self._commands.append(command) |  | ||||||
| 
 |  | ||||||
|                 # if isinstance(command, Function): |  | ||||||
|                 #     self._functions.append(command) |  | ||||||
|                 # elif isinstance(command, Include): |  | ||||||
|                 #     subcommands = self._load_include(command) |  | ||||||
|                 #     if subcommands is not None: |  | ||||||
|                 #         self._commands += subcommands |  | ||||||
|                 # elif isinstance(command, Template): |  | ||||||
|                 #     self._load_template(command) |  | ||||||
|                 #     self._commands.append(command) |  | ||||||
|                 # elif isinstance(command, ItemizedCommand) and issubclass(command.command_class, Template): |  | ||||||
|                 #     for c in command.get_commands(): |  | ||||||
|                 #         self._load_template(c) |  | ||||||
|                 #         self._commands.append(c) |  | ||||||
|                 # else: |  | ||||||
|                 #     self._commands.append(command) |  | ||||||
|             else: |  | ||||||
|                 success = False |  | ||||||
| 
 |  | ||||||
|         self.is_loaded = success |  | ||||||
|         return self.is_loaded |  | ||||||
| 
 |  | ||||||
|     # noinspection PyMethodMayBeStatic |  | ||||||
|     def _get_key_value(self, key, value): |  | ||||||
|         """Process a key/value pair from an INI section. |  | ||||||
| 
 |  | ||||||
|         :param key: The key to be processed. |  | ||||||
|         :type key: str |  | ||||||
| 
 |  | ||||||
|         :param value: The value to be processed. |  | ||||||
| 
 |  | ||||||
|         :rtype: tuple |  | ||||||
|         :returns: The key and value, both of which may be modified from the originals. |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         if key in ("environments", "environs", "envs", "env"): |  | ||||||
|             _key = "environments" |  | ||||||
|             _value = split_csv(value) |  | ||||||
|         elif key in ("func", "function"): |  | ||||||
|             _key = "function" |  | ||||||
|             _value = value |  | ||||||
|         elif key == "items": |  | ||||||
|             _key = "items" |  | ||||||
|             _value = split_csv(value) |  | ||||||
|         elif key == "tags": |  | ||||||
|             _key = "tags" |  | ||||||
|             _value = split_csv(value) |  | ||||||
|         else: |  | ||||||
|             _key = key |  | ||||||
|             _value = smart_cast(value) |  | ||||||
| 
 |  | ||||||
|         return _key, _value |  | ||||||
| 
 |  | ||||||
|     def _load_ini(self): |  | ||||||
|         """Load the configuration file. |  | ||||||
| 
 |  | ||||||
|         :rtype: ConfigParser | None |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         ini = ConfigParser() |  | ||||||
|         if self.context is not None: |  | ||||||
|             try: |  | ||||||
|                 content = parse_jinja_template(self.path, self.context) |  | ||||||
|             except Exception as e: |  | ||||||
|                 log.error("Failed to parse %s as template: %s" % (self.path, e)) |  | ||||||
|                 return None |  | ||||||
|         else: |  | ||||||
|             content = read_file(self.path) |  | ||||||
| 
 |  | ||||||
|         try: |  | ||||||
|             ini.read_string(content) |  | ||||||
|             return ini |  | ||||||
|         except ParsingError as e: |  | ||||||
|             log.error("Failed to parse %s: %s" % (self.path, e)) |  | ||||||
|             return None |  | ||||||
| 
 |  | ||||||
|     def _load_template(self, command): |  | ||||||
|         """Load additional resources for a template command. |  | ||||||
| 
 |  | ||||||
|         :param command: The template command. |  | ||||||
|         :type command: Template |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         # This may produce problems if template kwargs are the same as the given context. |  | ||||||
|         if self.context is not None: |  | ||||||
|             command.context.update(self.context) |  | ||||||
| 
 |  | ||||||
|         # Custom locations come before default locations. |  | ||||||
|         command.locations += self.locations |  | ||||||
| 
 |  | ||||||
|         # This allows template files to be specified relative to the configuration file. |  | ||||||
|         command.locations.append(os.path.join(self.directory, "templates")) |  | ||||||
|         command.locations.append(self.directory) |  | ||||||
| @ -1,325 +0,0 @@ | |||||||
| # Imports |  | ||||||
| 
 |  | ||||||
| from commonkit import any_list_item, smart_cast, split_csv |  | ||||||
| from configparser import RawConfigParser |  | ||||||
| import logging |  | ||||||
| import os |  | ||||||
| from ..constants import LOGGER_NAME |  | ||||||
| from .ini import Config |  | ||||||
| 
 |  | ||||||
| log = logging.getLogger(LOGGER_NAME) |  | ||||||
| 
 |  | ||||||
| # Exports |  | ||||||
| 
 |  | ||||||
| __all__ = ( |  | ||||||
|     "filter_commands", |  | ||||||
|     "load_commands", |  | ||||||
|     "load_config", |  | ||||||
|     "load_variables", |  | ||||||
|     "Context", |  | ||||||
|     "Variable", |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| # Functions |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def filter_commands(commands, environments=None, tags=None): |  | ||||||
|     """Filter commands based on the given criteria.  |  | ||||||
|      |  | ||||||
|     :param commands: The commands to be filtered. |  | ||||||
|     :type commands: list |  | ||||||
|      |  | ||||||
|     :param environments: Environment names to be matched. |  | ||||||
|     :type environments: list[str] |  | ||||||
|       |  | ||||||
|     :param tags: Tag names to be matched. |  | ||||||
|     :type tags: list[str] |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     filtered = list() |  | ||||||
|     for command in commands: |  | ||||||
|         if environments is not None and len(command.environments) > 0: |  | ||||||
|             if not any_list_item(environments, command.environments): |  | ||||||
|                 continue |  | ||||||
|          |  | ||||||
|         if tags is not None: |  | ||||||
|             if not any_list_item(tags, command.tags): |  | ||||||
|                 continue |  | ||||||
|          |  | ||||||
|         filtered.append(command) |  | ||||||
|          |  | ||||||
|     return filtered |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def load_commands(path, filters=None, overlay="ubuntu", **kwargs): |  | ||||||
|     """Load commands from a configuration file. |  | ||||||
| 
 |  | ||||||
|     :param path: The path to the configuration file. |  | ||||||
|     :type path: str |  | ||||||
| 
 |  | ||||||
|     :param filters: Used to filter commands. |  | ||||||
|     :type filters: dict |  | ||||||
| 
 |  | ||||||
|     :param overlay: The name of the command overlay to apply to generated commands. |  | ||||||
|     :type overlay: str |  | ||||||
| 
 |  | ||||||
|     :rtype: list[scriptetease.library.commands.base.Command] | scriptetease.library.commands.base.ItemizedCommand] | |  | ||||||
|             None |  | ||||||
| 
 |  | ||||||
|     :returns: A list of command instances or ``None`` if the configuration could not be loaded. |  | ||||||
| 
 |  | ||||||
|     kwargs are passed to the configuration class for instantiation. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     _config = load_config(path, overlay, **kwargs) |  | ||||||
|     if _config is None: |  | ||||||
|         return None |  | ||||||
| 
 |  | ||||||
|     commands = _config.get_commands() |  | ||||||
| 
 |  | ||||||
|     if filters is not None: |  | ||||||
|         criteria = dict() |  | ||||||
|         for attribute, values in filters.items(): |  | ||||||
|             criteria[attribute] = values |  | ||||||
| 
 |  | ||||||
|         commands = filter_commands(commands, **criteria) |  | ||||||
| 
 |  | ||||||
|     return commands |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def load_config(path, overlay="ubuntu", **kwargs): |  | ||||||
|     """Load a command configuration. |  | ||||||
| 
 |  | ||||||
|     :param path: The path to the configuration file. |  | ||||||
|     :type path: str |  | ||||||
| 
 |  | ||||||
|     :param overlay: The name of the command overlay to apply to generated commands. |  | ||||||
|     :type overlay: str |  | ||||||
| 
 |  | ||||||
|     :rtype: Config | None |  | ||||||
| 
 |  | ||||||
|     kwargs are passed to the configuration class for instantiation. |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     if path.endswith(".ini"): |  | ||||||
|         _config = Config(path, overlay=overlay, **kwargs) |  | ||||||
|     # elif path.endswith(".yml"): |  | ||||||
|     #     _config = YAML(path, **kwargs) |  | ||||||
|     else: |  | ||||||
|         log.warning("Input file format is not currently supported: %s" % path) |  | ||||||
|         return None |  | ||||||
| 
 |  | ||||||
|     if not _config.load(): |  | ||||||
|         log.error("Failed to load config file: %s" % path) |  | ||||||
|         return None |  | ||||||
| 
 |  | ||||||
|     return _config |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def load_variables(path, environment=None): |  | ||||||
|     """Load variables from a file. |  | ||||||
| 
 |  | ||||||
|     :param path: The path to the file. |  | ||||||
|     :type path: str |  | ||||||
| 
 |  | ||||||
|     :param environment: Filter variables by the given environment name. |  | ||||||
|     :type environment: str |  | ||||||
| 
 |  | ||||||
|     :rtype: list[scripttease.parsers.utils.Variable] |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
|     if not os.path.exists(path): |  | ||||||
|         log.warning("Path to variables file does not exist: %s" % path) |  | ||||||
|         return list() |  | ||||||
| 
 |  | ||||||
|     if path.endswith(".ini"): |  | ||||||
|         return _load_variables_ini(path, environment=environment) |  | ||||||
|     else: |  | ||||||
|         log.warning("Variable file format is not currently supports: %s" % path) |  | ||||||
|         return list() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _load_variables_ini(path, environment=None): |  | ||||||
|     """Load variables from an INI file. See ``load_variables()``.""" |  | ||||||
| 
 |  | ||||||
|     ini = RawConfigParser() |  | ||||||
|     ini.read(path) |  | ||||||
| 
 |  | ||||||
|     a = list() |  | ||||||
|     for section in ini.sections(): |  | ||||||
|         if ":" in section: |  | ||||||
|             variable_name, _environment = section.split(":") |  | ||||||
|         else: |  | ||||||
|             _environment = None |  | ||||||
|             variable_name = section |  | ||||||
| 
 |  | ||||||
|         _kwargs = { |  | ||||||
|             'environment': _environment, |  | ||||||
|         } |  | ||||||
|         for key, value in ini.items(section): |  | ||||||
|             if key == "tags": |  | ||||||
|                 value = split_csv(value) |  | ||||||
|             else: |  | ||||||
|                 value = smart_cast(value) |  | ||||||
| 
 |  | ||||||
|             _kwargs[key] = value |  | ||||||
| 
 |  | ||||||
|         a.append(Variable(variable_name, **_kwargs)) |  | ||||||
| 
 |  | ||||||
|     if environment is not None: |  | ||||||
|         b = list() |  | ||||||
|         for var in a: |  | ||||||
|             if var.environment and var.environment == environment or var.environment is None: |  | ||||||
|                 b.append(var) |  | ||||||
| 
 |  | ||||||
|         return b |  | ||||||
| 
 |  | ||||||
|     return a |  | ||||||
| 
 |  | ||||||
| # Classes |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Context(object): |  | ||||||
|     """A collection of variables.""" |  | ||||||
| 
 |  | ||||||
|     def __init__(self, **kwargs): |  | ||||||
|         """Initialize the context. |  | ||||||
| 
 |  | ||||||
|         kwargs are added as variable instances. |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         self.variables = dict() |  | ||||||
| 
 |  | ||||||
|         for key, value in kwargs.items(): |  | ||||||
|             self.add(key, value) |  | ||||||
| 
 |  | ||||||
|     def __getattr__(self, item): |  | ||||||
|         if item in self.variables: |  | ||||||
|             return self.variables[item].value |  | ||||||
| 
 |  | ||||||
|         return None |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         return "<%s (%s)>" % (self.__class__.__name__, len(self.variables)) |  | ||||||
| 
 |  | ||||||
|     def add(self, name, value, environment=None, tags=None): |  | ||||||
|         """Add a variable to the context. |  | ||||||
| 
 |  | ||||||
|         :param name: The name of the variable. |  | ||||||
|         :type name: str |  | ||||||
| 
 |  | ||||||
|         :param value: The value of the variable in this context. |  | ||||||
| 
 |  | ||||||
|         :param environment: The environment name to which the variable applies. ``None`` applies to all environments. |  | ||||||
|         :type environment: str |  | ||||||
| 
 |  | ||||||
|         :param tags: A list of tags that describe the variable. |  | ||||||
|         :type tags: list[str] |  | ||||||
| 
 |  | ||||||
|         :rtype: scripttease.parsers.utils.Variable |  | ||||||
| 
 |  | ||||||
|         :raise: RuntimeError |  | ||||||
|         :raises: ``RuntimeError`` if the variable already exists. |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         if name in self.variables: |  | ||||||
|             raise RuntimeError("Variable already exists: %s" % name) |  | ||||||
| 
 |  | ||||||
|         v = Variable(name, value, environment=environment, tags=tags) |  | ||||||
|         self.variables[name] = v |  | ||||||
| 
 |  | ||||||
|         return v |  | ||||||
| 
 |  | ||||||
|     def get(self, name, default=None): |  | ||||||
|         """Get a the value of the variable from the context. |  | ||||||
| 
 |  | ||||||
|         :param name: The name of the variable. |  | ||||||
|         :type name: str |  | ||||||
| 
 |  | ||||||
|         :param default: The default value to return. |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         if not self.has(name): |  | ||||||
|             return default |  | ||||||
| 
 |  | ||||||
|         return self.variables[name].value |  | ||||||
| 
 |  | ||||||
|     def has(self, name): |  | ||||||
|         """Indicates whether the named variable exists in this context, and whether the value is not ``None``. |  | ||||||
| 
 |  | ||||||
|         :rtype: bool |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         if name not in self.variables: |  | ||||||
|             return False |  | ||||||
| 
 |  | ||||||
|         return self.variables[name].value is not None |  | ||||||
| 
 |  | ||||||
|     def join(self, variables): |  | ||||||
|         """Join a list of variables to the context. |  | ||||||
| 
 |  | ||||||
|         :param variables: the list of variables to be added. |  | ||||||
|         :type variables: list[scripttease.parsers.utils.Variable] |  | ||||||
| 
 |  | ||||||
|         .. note:: |  | ||||||
|             This *replaces* a variable if it already exists. |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         for v in variables: |  | ||||||
|             self.variables[v.name] = v |  | ||||||
| 
 |  | ||||||
|     def mapping(self): |  | ||||||
|         """Export the context as a dictionary. |  | ||||||
| 
 |  | ||||||
|         :rtype: dict |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         values = dict() |  | ||||||
|         for key, var in self.variables.items(): |  | ||||||
|             values[key] = var.value or var.default |  | ||||||
| 
 |  | ||||||
|         return values |  | ||||||
| 
 |  | ||||||
|     def merge(self, context): |  | ||||||
|         """Merge another context with this one. |  | ||||||
| 
 |  | ||||||
|         :param context: The context to be merged. |  | ||||||
|         :type context: scripttease.parser.utils.Context |  | ||||||
| 
 |  | ||||||
|         .. note:: |  | ||||||
|             Variables that exist in the current context are *not* replaced with variables from the provided context. |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         for name, var in context.variables.items(): |  | ||||||
|             if not self.has(name): |  | ||||||
|                 self.variables[name] = var |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Variable(object): |  | ||||||
|     """Represents a variable to be used in the context of pre-processing a config file.""" |  | ||||||
| 
 |  | ||||||
|     def __init__(self, name, value, **kwargs): |  | ||||||
|         """Initialize a variable. |  | ||||||
| 
 |  | ||||||
|         :param name: The variable name. |  | ||||||
|         :type name: str |  | ||||||
| 
 |  | ||||||
|         :param value: The value of the variable. |  | ||||||
| 
 |  | ||||||
|         kwargs are added as attributes of the instance. |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         self.name = name |  | ||||||
|         self.value = value |  | ||||||
| 
 |  | ||||||
|         kwargs.setdefault("tags", list()) |  | ||||||
|         self._attributes = kwargs |  | ||||||
| 
 |  | ||||||
|     def __eq__(self, other): |  | ||||||
|         return self.value == other |  | ||||||
| 
 |  | ||||||
|     def __getattr__(self, item): |  | ||||||
|         return self._attributes.get(item) |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         return "<%s %s>" % (self.__class__.__name__, self.name) |  | ||||||
| @ -1,5 +1,5 @@ | |||||||
| DATE = "2022-06-14" | DATE = "2023-03-30" | ||||||
| VERSION = "6.8.15" | VERSION = "7.0.0" | ||||||
| MAJOR = 6 | MAJOR = 7 | ||||||
| MINOR = 8 | MINOR = 0 | ||||||
| PATCH = 15 | PATCH = 0 | ||||||
|  | |||||||
| @ -0,0 +1,9 @@ | |||||||
|  | [disable the default site] | ||||||
|  | apache.disable_site = default | ||||||
|  | 
 | ||||||
|  | [enable SSL] | ||||||
|  | apache.enable_module = ssl | ||||||
|  | 
 | ||||||
|  | ; see test_lib_factories | ||||||
|  | [this will raise a type error because bad_custom_command doesn't accept kwargs] | ||||||
|  | bad_custom =  path/to/display | ||||||
| @ -0,0 +1,15 @@ | |||||||
|  | [domain_name | ||||||
|  | value = example.com | ||||||
|  | 
 | ||||||
|  | [domain_tld] | ||||||
|  | value = example_com | ||||||
|  | 
 | ||||||
|  | [debug_enabled:testing] | ||||||
|  | value = True | ||||||
|  | 
 | ||||||
|  | [postgres_version] | ||||||
|  | value = 11 | ||||||
|  | tags = postgres | ||||||
|  | 
 | ||||||
|  | [mailgun_domain:live] | ||||||
|  | value = mg.example.com | ||||||
| @ -0,0 +1,9 @@ | |||||||
|  | [disable the default site] | ||||||
|  | apache.disable_site = default | ||||||
|  | 
 | ||||||
|  | [enable SSL] | ||||||
|  | apache.enable_module = ssl | ||||||
|  | 
 | ||||||
|  | ; see test_lib_factories | ||||||
|  | [this requires that a mapping be passed to the command factory] | ||||||
|  | custom = path/to/display | ||||||
| @ -0,0 +1,3 @@ | |||||||
|  | TESTING = %(testing)s | ||||||
|  | TOTAL_TIMES = %(times)s | ||||||
|  | 
 | ||||||
| @ -1,45 +0,0 @@ | |||||||
| import pytest |  | ||||||
| from scripttease.library.commands import Command, ItemizedCommand |  | ||||||
| from scripttease.factory import Factory |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class TestFactory(object): |  | ||||||
| 
 |  | ||||||
|     def test_get_command(self): |  | ||||||
|         f = Factory("ubuntu") |  | ||||||
|         with pytest.raises(RuntimeError): |  | ||||||
|             f.get_command("testing") |  | ||||||
| 
 |  | ||||||
|         f = Factory("ubuntu") |  | ||||||
|         f.load() |  | ||||||
| 
 |  | ||||||
|         # Non-existent command. |  | ||||||
|         c = f.get_command("nonexistent") |  | ||||||
|         assert c is None |  | ||||||
| 
 |  | ||||||
|         # A good command with itemized parameters. |  | ||||||
|         c = f.get_command( |  | ||||||
|             "pip", |  | ||||||
|             "$item", |  | ||||||
|             items=["Pillow", "psycopg2-binary", "django"] |  | ||||||
|         ) |  | ||||||
|         assert isinstance(c, ItemizedCommand) |  | ||||||
| 
 |  | ||||||
|         # A good, normal command. |  | ||||||
|         c = f.get_command("pip", "django") |  | ||||||
|         assert isinstance(c, Command) |  | ||||||
| 
 |  | ||||||
|         # Command exists, but given bad arguments. |  | ||||||
|         c = f.get_command("pip") |  | ||||||
|         assert c is None |  | ||||||
| 
 |  | ||||||
|     def test_load(self): |  | ||||||
|         f = Factory("nonexistent") |  | ||||||
|         assert f.load() is False |  | ||||||
| 
 |  | ||||||
|         f = Factory("ubuntu") |  | ||||||
|         assert f.load() is True |  | ||||||
| 
 |  | ||||||
|     def test_repr(self): |  | ||||||
|         f = Factory("centos") |  | ||||||
|         assert repr(f) == "<Factory centos>" |  | ||||||
| @ -0,0 +1,416 @@ | |||||||
|  | from scripttease.lib.commands.base import Command, Content, ItemizedCommand, MultipleCommands, Prompt, Sudo, Template | ||||||
|  | from scripttease.lib.commands.python import python_pip | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestCommand(object): | ||||||
|  | 
 | ||||||
|  |     def test_getattr(self): | ||||||
|  |         c = Command("ls -ls", extra=True) | ||||||
|  |         assert c.extra is True | ||||||
|  | 
 | ||||||
|  |     def test_get_statement(self): | ||||||
|  |         c = Command( | ||||||
|  |             "ls -ls", | ||||||
|  |             comment="kitchen sink", | ||||||
|  |             condition="$last_command -eq 0", | ||||||
|  |             cd="/path/to/project", | ||||||
|  |             prefix="source python/bin/active", | ||||||
|  |             register="list_success", | ||||||
|  |             stop=True, | ||||||
|  |             sudo="deploy" | ||||||
|  |         ) | ||||||
|  |         statement = c.get_statement(cd=True) | ||||||
|  |         assert "( cd" in statement | ||||||
|  |         assert "sudo" in statement | ||||||
|  |         assert ")" in statement | ||||||
|  |         assert "# kitchen sink" in statement | ||||||
|  |         assert "if [[ $last_command" in statement | ||||||
|  |         assert "list_success=$?" in statement | ||||||
|  |         assert "if [[ $list_success" in statement | ||||||
|  | 
 | ||||||
|  |         c = Command( | ||||||
|  |             "ls -ls", | ||||||
|  |             stop=True | ||||||
|  |         ) | ||||||
|  |         statement = c.get_statement() | ||||||
|  |         assert "if [[ $?" in statement | ||||||
|  | 
 | ||||||
|  |     def test_init(self): | ||||||
|  |         c = Command("ls -ls", sudo=Sudo(user="deploy")) | ||||||
|  |         assert isinstance(c.sudo, Sudo) | ||||||
|  |         assert c.sudo.user == "deploy" | ||||||
|  | 
 | ||||||
|  |         c = Command("ls -ls", sudo="deploy") | ||||||
|  |         assert isinstance(c.sudo, Sudo) | ||||||
|  |         assert c.sudo.user == "deploy" | ||||||
|  | 
 | ||||||
|  |         c = Command("ls -ls", sudo=True) | ||||||
|  |         assert isinstance(c.sudo, Sudo) | ||||||
|  |         assert c.sudo.user == "root" | ||||||
|  | 
 | ||||||
|  |         c = Command("ls -ls") | ||||||
|  |         assert isinstance(c.sudo, Sudo) | ||||||
|  |         assert c.sudo.user == "root" | ||||||
|  |         assert c.sudo.enabled is False | ||||||
|  | 
 | ||||||
|  |     def test_is_itemized(self): | ||||||
|  |         c = Command("ls -ls") | ||||||
|  |         assert c.is_itemized is False | ||||||
|  | 
 | ||||||
|  |     def test_repr(self): | ||||||
|  |         c = Command("ls -ls", comment="listing") | ||||||
|  |         assert repr(c) == "<Command listing>" | ||||||
|  | 
 | ||||||
|  |         c = Command("ls -ls") | ||||||
|  |         assert repr(c) == "<Command>" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestContent(object): | ||||||
|  | 
 | ||||||
|  |     def test_getattr(self): | ||||||
|  |         c = Content("testing", extra=True) | ||||||
|  |         assert c.extra is True | ||||||
|  | 
 | ||||||
|  |     def test_get_image_output(self): | ||||||
|  |         c = Content("screenshot", caption="this is a test", image="static/images/testing.png") | ||||||
|  |         assert "# this is a test" in c.get_output("bash") | ||||||
|  |         assert "# static/images/testing.png" in c.get_output("bash") | ||||||
|  | 
 | ||||||
|  |         c.css = "img right" | ||||||
|  |         c.height = 100 | ||||||
|  |         c.width = 150 | ||||||
|  |         assert '<img src="static/images/testing.png"' in c.get_output("html") | ||||||
|  |         assert 'alt="this is a test"' in c.get_output("html") | ||||||
|  |         assert 'class="img right"' in c.get_output("html") | ||||||
|  |         assert 'height="100"' in c.get_output("html") | ||||||
|  |         assert 'width="150"' in c.get_output("html") | ||||||
|  | 
 | ||||||
|  |         assert c.get_output("md") == "\n" | ||||||
|  | 
 | ||||||
|  |         assert ".. figure:: static/images/testing.png" in c.get_output("rst") | ||||||
|  |         assert ":alt: this is a test" in c.get_output("rst") | ||||||
|  |         assert ":height: 100" in c.get_output("rst") | ||||||
|  |         assert ":width: 150" in c.get_output("rst") | ||||||
|  | 
 | ||||||
|  |         assert "this is a test: static/images/testing.png" in c.get_output("plain") | ||||||
|  |         c.caption = None | ||||||
|  |         assert "static/images/testing.png" in c.get_output("plain") | ||||||
|  | 
 | ||||||
|  |     def test_get_message_output(self): | ||||||
|  |         c = Content("explain", message="this is a test") | ||||||
|  |         assert "# this is a test" in c.get_output("bash") | ||||||
|  |         assert "<p>this is a test" in c.get_output("html") | ||||||
|  |         assert "this is a test" in c.get_output("md") | ||||||
|  |         assert "this is a test" in c.get_output("rst") | ||||||
|  |         assert "this is a test" in c.get_output("plain") | ||||||
|  | 
 | ||||||
|  |         c.heading = "Test" | ||||||
|  |         assert "# Test: this is a test" in c.get_output("bash") | ||||||
|  |         assert "<h2>Test</h2>" in c.get_output("html") | ||||||
|  |         assert "## Test" in c.get_output("md") | ||||||
|  |         assert "Test" in c.get_output("rst") | ||||||
|  |         assert "====" in c.get_output("rst") | ||||||
|  |         assert "***** Test *****" in c.get_output("plain") | ||||||
|  | 
 | ||||||
|  |     def test_get_output(self): | ||||||
|  |         c = Content("testing") | ||||||
|  |         assert c.get_output("nonexistent") is None | ||||||
|  | 
 | ||||||
|  |     def test_is_itemized(self): | ||||||
|  |         c = Content("testing") | ||||||
|  |         assert c.is_itemized is False | ||||||
|  | 
 | ||||||
|  |     def test_repr(self): | ||||||
|  |         c = Content("testing") | ||||||
|  |         assert repr(c) == "<Content testing>" | ||||||
|  | 
 | ||||||
|  |     def test_get_statement(self): | ||||||
|  |         c = Content("screenshot", caption="this is a test", image="static/images/testing.png") | ||||||
|  |         assert "# this is a test" in c.get_statement() | ||||||
|  |         assert "# static/images/testing.png" in c.get_statement() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestItemizedCommand(object): | ||||||
|  | 
 | ||||||
|  |     def test_getattr(self): | ||||||
|  |         c = ItemizedCommand(python_pip, ["Pillow", "psycopg2-binary", "django"], "$item", extra=True) | ||||||
|  |         assert c.extra is True | ||||||
|  | 
 | ||||||
|  |     def test_get_commands(self): | ||||||
|  |         c = ItemizedCommand(python_pip, ["Pillow", "psycopg2-binary", "django"], "$item") | ||||||
|  |         commands = c.get_commands() | ||||||
|  |         for i in commands: | ||||||
|  |             assert isinstance(i, Command) | ||||||
|  | 
 | ||||||
|  |     def test_get_statement(self): | ||||||
|  |         c = ItemizedCommand(python_pip, ["Pillow", "psycopg2-binary", "django"], "$item") | ||||||
|  |         statement = c.get_statement() | ||||||
|  |         assert "Pillow" in statement | ||||||
|  |         assert "psycopg2-binary" in statement | ||||||
|  |         assert "django" in statement | ||||||
|  | 
 | ||||||
|  |     def test_is_itemized(self): | ||||||
|  |         c = ItemizedCommand(python_pip, ["Pillow", "psycopg2-binary", "django"], "$item") | ||||||
|  |         assert c.is_itemized is True | ||||||
|  | 
 | ||||||
|  |     def test_repr(self): | ||||||
|  |         c = ItemizedCommand(python_pip, ["Pillow", "psycopg2-binary", "django"], "$item") | ||||||
|  |         assert repr(c) == "<ItemizedCommand python_pip>" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestMultipleCommands(object): | ||||||
|  | 
 | ||||||
|  |     def test_getattr(self): | ||||||
|  |         commands = [ | ||||||
|  |             Command("ls -ls", name="run"), | ||||||
|  |             Command("pip install django", name="pip"), | ||||||
|  |             Command("touch /tmp/testing.txt", name="touch") | ||||||
|  |         ] | ||||||
|  |         multiple = MultipleCommands(commands, extra=True) | ||||||
|  |         assert multiple.extra is True | ||||||
|  | 
 | ||||||
|  |     def test_iter(self): | ||||||
|  |         commands = [ | ||||||
|  |             Command("ls -ls", name="run"), | ||||||
|  |             Command("pip install django", name="pip"), | ||||||
|  |             Command("touch /tmp/testing.txt", name="touch") | ||||||
|  |         ] | ||||||
|  |         multiple = MultipleCommands(commands) | ||||||
|  | 
 | ||||||
|  |         count = 0 | ||||||
|  |         for c in multiple: | ||||||
|  |             count += 1 | ||||||
|  | 
 | ||||||
|  |         assert count == 3 | ||||||
|  | 
 | ||||||
|  |     def test_repr(self): | ||||||
|  |         commands = [ | ||||||
|  |             Command("ls -ls", name="run"), | ||||||
|  |             Command("pip install django", name="pip"), | ||||||
|  |             Command("touch /tmp/testing.txt", name="touch") | ||||||
|  |         ] | ||||||
|  |         multiple = MultipleCommands(commands) | ||||||
|  |         assert repr(multiple) == "<MultipleCommands run multiple commands>" | ||||||
|  | 
 | ||||||
|  |     def test_get_statement(self): | ||||||
|  |         commands = [ | ||||||
|  |             Command("ls -ls", name="run"), | ||||||
|  |             Command("pip install django", name="pip"), | ||||||
|  |             Command("touch /tmp/testing.txt", name="touch") | ||||||
|  |         ] | ||||||
|  |         multiple = MultipleCommands(commands) | ||||||
|  |         statement = multiple.get_statement() | ||||||
|  |         assert "ls -ls" in statement | ||||||
|  |         assert "pip install django" in statement | ||||||
|  |         assert "touch /tmp/testing.txt" in statement | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestPrompt(object): | ||||||
|  | 
 | ||||||
|  |     def test_get_dialog_statement(self): | ||||||
|  |         prompt = Prompt("testing", choices=["1", "2", "3"], default="1", dialog=True, help_text="This is a test.", label="Test") | ||||||
|  |         statement = prompt.get_statement() | ||||||
|  |         assert "--menu" in statement | ||||||
|  |         assert "This is a test." in statement | ||||||
|  | 
 | ||||||
|  |         prompt = Prompt("testing", choices="1,2,3", default="1", dialog=True, help_text="This is a test.", label="Test") | ||||||
|  |         statement = prompt.get_statement() | ||||||
|  |         assert "--menu" in statement | ||||||
|  | 
 | ||||||
|  |         prompt = Prompt("testing", default="1", dialog=True, help_text="This is a test.", label="Test") | ||||||
|  |         statement = prompt.get_statement() | ||||||
|  |         assert "--inputbox" in statement | ||||||
|  |         assert "This is a test." in statement | ||||||
|  | 
 | ||||||
|  |         prompt = Prompt("testing", default="1", dialog=True, label="Test") | ||||||
|  |         statement = prompt.get_statement() | ||||||
|  |         assert "--inputbox" in statement | ||||||
|  | 
 | ||||||
|  |     def test_get_read_statement(self): | ||||||
|  |         prompt = Prompt("testing", choices="1,2,3", default="1", help_text="This is a test.", label="Test") | ||||||
|  |         statement = prompt.get_statement() | ||||||
|  |         assert "select opt in" in statement | ||||||
|  | 
 | ||||||
|  |         prompt = Prompt("testing", default="1", help_text="This is a test.", label="Test") | ||||||
|  |         statement = prompt.get_statement() | ||||||
|  |         assert "echo -n" in statement | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestSudo(object): | ||||||
|  | 
 | ||||||
|  |     def test_bool(self): | ||||||
|  |         s = Sudo() | ||||||
|  |         assert bool(s) is False | ||||||
|  | 
 | ||||||
|  |         s = Sudo(True) | ||||||
|  |         assert bool(s) is True | ||||||
|  | 
 | ||||||
|  |     def test_str(self): | ||||||
|  |         s = Sudo() | ||||||
|  |         assert str(s) == "" | ||||||
|  | 
 | ||||||
|  |         s = Sudo(True) | ||||||
|  |         assert str(s) == "sudo -u root" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestTemplate(object): | ||||||
|  | 
 | ||||||
|  |     def test_get_content(self): | ||||||
|  |         context = { | ||||||
|  |             'testing': "yes", | ||||||
|  |             'times': 123, | ||||||
|  |         } | ||||||
|  |         t = Template( | ||||||
|  |             "tests/examples/templates/simple.txt", | ||||||
|  |             "tests/tmp/simple.txt", | ||||||
|  |             backup=False, | ||||||
|  |             context=context, | ||||||
|  |             parser=Template.PARSER_SIMPLE | ||||||
|  |         ) | ||||||
|  |         content = t.get_content() | ||||||
|  |         assert "I am testing? yes" in content | ||||||
|  |         assert "How many times? 123" in content | ||||||
|  | 
 | ||||||
|  |         context = { | ||||||
|  |             'testing': "yes", | ||||||
|  |             'times': 123, | ||||||
|  |         } | ||||||
|  |         t = Template( | ||||||
|  |             "tests/examples/templates/simple.sh.txt", | ||||||
|  |             "tests/tmp/simple.sh", | ||||||
|  |             backup=False, | ||||||
|  |             context=context, | ||||||
|  |             parser=Template.PARSER_SIMPLE | ||||||
|  |         ) | ||||||
|  |         content = t.get_content() | ||||||
|  |         assert "I am testing? yes" in content | ||||||
|  |         assert "How many times? 123" in content | ||||||
|  | 
 | ||||||
|  |         context = { | ||||||
|  |             'testing': "yes", | ||||||
|  |             'times': 123, | ||||||
|  |         } | ||||||
|  |         t = Template( | ||||||
|  |             "tests/examples/templates/good.j2.txt", | ||||||
|  |             "tests/tmp/good.txt", | ||||||
|  |             backup=False, | ||||||
|  |             context=context | ||||||
|  |         ) | ||||||
|  |         content = t.get_content() | ||||||
|  |         assert "I am testing? yes" in content | ||||||
|  |         assert "How many times? 123" in content | ||||||
|  | 
 | ||||||
|  |         t = Template("tests/examples/templates/nonexistent.j2.txt", "test/tmp/nonexistent.txt") | ||||||
|  |         assert t.get_content() is None | ||||||
|  | 
 | ||||||
|  |         t = Template("tests/examples/templates/bad.j2.txt", "test/tmp/nonexistent.txt") | ||||||
|  |         assert t.get_content() is None | ||||||
|  | 
 | ||||||
|  |         context = { | ||||||
|  |             'testing': True, | ||||||
|  |             'times': 3, | ||||||
|  |         } | ||||||
|  |         t = Template("tests/examples/templates/settings.py", "test/tmp/settings.py", context=context, parser=Template.PARSER_PYTHON) | ||||||
|  |         content = t.get_content() | ||||||
|  |         assert "TESTING = True" in content | ||||||
|  |         assert "TOTAL_TIMES = 3" in content | ||||||
|  | 
 | ||||||
|  |     def test_get_statement(self): | ||||||
|  |         context = { | ||||||
|  |             'testing': "yes", | ||||||
|  |             'times': 123, | ||||||
|  |         } | ||||||
|  |         t = Template( | ||||||
|  |             "tests/examples/templates/simple.txt", | ||||||
|  |             "tests/tmp/simple.txt", | ||||||
|  |             context=context, | ||||||
|  |             comment="A simple parser example.", | ||||||
|  |             parser=Template.PARSER_SIMPLE, | ||||||
|  |             register="template_created", | ||||||
|  |             stop=True, | ||||||
|  |             sudo=Sudo(user="root") | ||||||
|  |         ) | ||||||
|  |         s = t.get_statement() | ||||||
|  |         assert "I am testing? yes" in s | ||||||
|  |         assert "How many times? 123" in s | ||||||
|  | 
 | ||||||
|  |         context = { | ||||||
|  |             'testing': "yes", | ||||||
|  |             'times': 123, | ||||||
|  |         } | ||||||
|  |         t = Template( | ||||||
|  |             "tests/examples/templates/simple.sh.txt", | ||||||
|  |             "tests/tmp/simple.txt", | ||||||
|  |             context=context, | ||||||
|  |             parser=Template.PARSER_SIMPLE, | ||||||
|  |             stop=True, | ||||||
|  |             sudo="root" | ||||||
|  |         ) | ||||||
|  |         s = t.get_statement() | ||||||
|  |         assert "I am testing? yes" in s | ||||||
|  |         assert "How many times? 123" in s | ||||||
|  | 
 | ||||||
|  |         context = { | ||||||
|  |             'testing': "yes", | ||||||
|  |             'times': 123, | ||||||
|  |         } | ||||||
|  |         t = Template( | ||||||
|  |             "tests/examples/templates/good.j2.txt", | ||||||
|  |             "tests/tmp/good.txt", | ||||||
|  |             context=context, | ||||||
|  |             sudo=True | ||||||
|  |         ) | ||||||
|  |         s = t.get_statement() | ||||||
|  |         assert "I am testing? yes" in s | ||||||
|  |         assert "How many times? 123" in s | ||||||
|  | 
 | ||||||
|  |         t = Template( | ||||||
|  |             "tests/examples/templates/simple.txt", | ||||||
|  |             "tests/tmp/simple.txt", | ||||||
|  |             parser="nonexistent" | ||||||
|  |         ) | ||||||
|  |         assert "# NO CONTENT AVAILABLE" in t.get_statement() | ||||||
|  | 
 | ||||||
|  |     def test_repr(self): | ||||||
|  |         t = Template("/path/to/template.conf", "/path/to/file.conf") | ||||||
|  |         assert repr(t) == "<Template /path/to/template.conf>" | ||||||
|  | 
 | ||||||
|  |     def test_get_target_language(self): | ||||||
|  |         t = Template("/path/to/template.conf", "/path/to/file.conf", lang="c++") | ||||||
|  |         assert t.get_target_language() == "c++" | ||||||
|  | 
 | ||||||
|  |         t = Template("/path/to/template.conf", "/path/to/file.conf") | ||||||
|  |         assert t.get_target_language() == "conf" | ||||||
|  | 
 | ||||||
|  |         t = Template("/path/to/template.ini", "/path/to/file.ini") | ||||||
|  |         assert t.get_target_language() == "ini" | ||||||
|  | 
 | ||||||
|  |         t = Template("/path/to/template.php", "/path/to/file.php") | ||||||
|  |         assert t.get_target_language() == "php" | ||||||
|  | 
 | ||||||
|  |         t = Template("/path/to/template.py", "/path/to/file.py") | ||||||
|  |         assert t.get_target_language() == "python" | ||||||
|  | 
 | ||||||
|  |         t = Template("/path/to/template.sh", "/path/to/file.sh") | ||||||
|  |         assert t.get_target_language() == "bash" | ||||||
|  | 
 | ||||||
|  |         t = Template("/path/to/template.sql", "/path/to/file.sql") | ||||||
|  |         assert t.get_target_language() == "sql" | ||||||
|  | 
 | ||||||
|  |         t = Template("/path/to/template.yml", "/path/to/file.yml") | ||||||
|  |         assert t.get_target_language() == "yaml" | ||||||
|  | 
 | ||||||
|  |         t = Template("/path/to/template.txt", "/path/to/file.txt") | ||||||
|  |         assert t.get_target_language() == "text" | ||||||
|  | 
 | ||||||
|  |     def test_get_template(self): | ||||||
|  |         t = Template( | ||||||
|  |             "simple.txt", | ||||||
|  |             "tests/tmp/simple.txt", | ||||||
|  |             locations=["tests/examples/templates"] | ||||||
|  |         ) | ||||||
|  |         assert t.get_template() == "tests/examples/templates/simple.txt" | ||||||
|  | 
 | ||||||
|  |     def test_is_itemized(self): | ||||||
|  |         t = Template("/path/to/template.conf", "/path/to/file.conf") | ||||||
|  |         assert t.is_itemized is False | ||||||
| @ -0,0 +1,46 @@ | |||||||
|  | import pytest | ||||||
|  | from scripttease.exceptions import InvalidInput | ||||||
|  | from scripttease.lib.commands.messages import * | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_dialog(): | ||||||
|  |     c = dialog("This is a test.", title="Testing") | ||||||
|  |     s = c.get_statement(include_comment=False) | ||||||
|  |     # dialog --clear --backtitle "Testing" --msgbox "This is a test." 15 100; clear; | ||||||
|  |     assert 'dialog --clear --backtitle "Testing"' in s | ||||||
|  |     assert '--msgbox "This is a test." 15 100; clear;' | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_echo(): | ||||||
|  |     c = echo("This is a test.") | ||||||
|  |     s = c.get_statement(include_comment=False) | ||||||
|  |     assert "echo" in s | ||||||
|  |     assert "This is a test." in s | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_explain(): | ||||||
|  |     assert explain("this is a test") is not None | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_screenshot(): | ||||||
|  |     assert screenshot("static/images/testing.png") is not None | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_slack(): | ||||||
|  |     with pytest.raises(InvalidInput): | ||||||
|  |         slack("This is a test.") | ||||||
|  | 
 | ||||||
|  |     c = slack("This is a test.", url="https://example.slack.com/asdf/1234") | ||||||
|  |     s = c.get_statement(include_comment=False) | ||||||
|  |     assert "curl -X POST -H 'Content-type: application/json' --data" in s | ||||||
|  |     assert "This is a test." in s | ||||||
|  |     assert "https://example.slack.com/asdf/1234" in s | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_twist(): | ||||||
|  |     with pytest.raises(InvalidInput): | ||||||
|  |         twist("This is a test.") | ||||||
|  | 
 | ||||||
|  |     c = twist("This is a test.", url="https://example.twist.com/asdf/1234") | ||||||
|  |     s = c.get_statement(include_comment=False) | ||||||
|  |     print(s) | ||||||
| @ -0,0 +1,7 @@ | |||||||
|  | from scripttease.lib.commands.php import * | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_php_module(): | ||||||
|  |     c = php_module("testing") | ||||||
|  |     s = c.get_statement() | ||||||
|  |     assert "phpenmod testing" in s | ||||||
| @ -0,0 +1,25 @@ | |||||||
|  | import pytest | ||||||
|  | from scripttease.lib.commands.python import * | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_python_pip(): | ||||||
|  |     c = python_pip("Pillow") | ||||||
|  |     assert "pip3 install Pillow" in c.get_statement() | ||||||
|  | 
 | ||||||
|  |     c = python_pip("Pillow", upgrade=True) | ||||||
|  |     assert "--upgrade" in c.get_statement() | ||||||
|  | 
 | ||||||
|  |     c = python_pip("Pillow", venv="python") | ||||||
|  |     assert "source python/bin/activate" in c.get_statement() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_python_pip_file(): | ||||||
|  |     c = python_pip_file("deploy/packages/testing.pip", venv="python") | ||||||
|  |     s = c.get_statement() | ||||||
|  |     assert "pip3 install -r deploy/packages/testing.pip" in s | ||||||
|  |     assert "source python/bin/activate" in s | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_python_virtual_env(): | ||||||
|  |     c = python_virtualenv("python") | ||||||
|  |     assert "virtualenv python" in c.get_statement() | ||||||
| @ -0,0 +1,37 @@ | |||||||
|  | from scripttease.lib.contexts import * | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestContext(object): | ||||||
|  | 
 | ||||||
|  |     def test_add(self): | ||||||
|  |         c = Context() | ||||||
|  |         v = c.add("testing", True) | ||||||
|  |         assert isinstance(v, Variable) | ||||||
|  | 
 | ||||||
|  |     def test_append(self): | ||||||
|  |         c = Context() | ||||||
|  |         v = Variable("testing", True) | ||||||
|  |         c.append(v) | ||||||
|  |         assert len(c.variables.keys()) == 1 | ||||||
|  | 
 | ||||||
|  |     def test_getattr(self): | ||||||
|  |         c = Context() | ||||||
|  |         c.add("testing", True) | ||||||
|  |         assert c.testing.value is True | ||||||
|  | 
 | ||||||
|  |     def test_mapping(self): | ||||||
|  |         c = Context() | ||||||
|  |         c.add("testing", True) | ||||||
|  |         assert 'testing' in c.mapping() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestVariable(object): | ||||||
|  | 
 | ||||||
|  |     def test_getattr(self): | ||||||
|  |         tags = ["this", "is", "a", "test"] | ||||||
|  |         v = Variable("testing", True, tags=tags) | ||||||
|  |         assert v.tags == tags | ||||||
|  | 
 | ||||||
|  |     def test_str(self): | ||||||
|  |         v = Variable("testing", True) | ||||||
|  |         assert str(v) == "True" | ||||||
| @ -0,0 +1,50 @@ | |||||||
|  | import pytest | ||||||
|  | from scripttease.exceptions import InvalidInput | ||||||
|  | from scripttease.lib.commands.base import Command | ||||||
|  | from scripttease.lib.loaders import INILoader | ||||||
|  | from scripttease.lib.factories import * | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def bad_custom_command(path): | ||||||
|  |     # this will fail because the function doesn't except kwargs. | ||||||
|  |     pass | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def custom_command(path, **kwargs): | ||||||
|  |     return Command("ls -ls %s" % path, name="custom", **kwargs) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_command_factory(): | ||||||
|  |     ini = INILoader("tests/examples/kitchen_sink.ini") | ||||||
|  |     assert command_factory(ini, profile="nonexistent") is None | ||||||
|  | 
 | ||||||
|  |     ini = INILoader("tests/examples/kitchen_sink.ini") | ||||||
|  |     ini.load() | ||||||
|  |     commands = command_factory(ini) | ||||||
|  |     assert len(commands) == 48 | ||||||
|  | 
 | ||||||
|  |     ini = INILoader("tests/examples/bad_command.ini") | ||||||
|  |     ini.load() | ||||||
|  |     commands = command_factory(ini) | ||||||
|  |     assert len(commands) == 0 | ||||||
|  | 
 | ||||||
|  |     ini = INILoader("tests/examples/apache_examples.ini") | ||||||
|  |     ini.load() | ||||||
|  |     commands = command_factory(ini) | ||||||
|  |     assert len(commands) == 2 | ||||||
|  | 
 | ||||||
|  |     # This should result in no commands because CentOS doesn't have enable/disable site or module. | ||||||
|  |     ini = INILoader("tests/examples/apache_examples.ini") | ||||||
|  |     ini.load() | ||||||
|  |     commands = command_factory(ini, profile="centos") | ||||||
|  |     assert len(commands) == 0 | ||||||
|  | 
 | ||||||
|  |     ini = INILoader("tests/examples/custom_example.ini") | ||||||
|  |     ini.load() | ||||||
|  |     commands = command_factory(ini, mappings={'custom': custom_command}) | ||||||
|  |     assert len(commands) == 3 | ||||||
|  | 
 | ||||||
|  |     ini = INILoader("tests/examples/bad_custom_example.ini") | ||||||
|  |     ini.load() | ||||||
|  |     with pytest.raises(InvalidInput): | ||||||
|  |         command_factory(ini, mappings={'bad_custom': bad_custom_command}) | ||||||
| @ -0,0 +1,83 @@ | |||||||
|  | import pytest | ||||||
|  | from scripttease.exceptions import InvalidInput | ||||||
|  | from scripttease.lib.contexts import Context | ||||||
|  | from scripttease.lib.loaders.base import * | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_load_variables(): | ||||||
|  |     vars = load_variables("nonexistent.ini") | ||||||
|  |     assert len(vars) == 0 | ||||||
|  | 
 | ||||||
|  |     vars = load_variables("tests/examples/bad_variables.ini") | ||||||
|  |     assert len(vars) == 0 | ||||||
|  | 
 | ||||||
|  |     vars = load_variables("tests/examples/variables.ini") | ||||||
|  |     assert len(vars) == 5 | ||||||
|  | 
 | ||||||
|  |     vars = load_variables("tests/examples/variables.ini", env="testing") | ||||||
|  |     assert len(vars) == 4 | ||||||
|  | 
 | ||||||
|  |     vars = load_variables("tests/examples/variables.ini", env="live") | ||||||
|  |     assert len(vars) == 4 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestBaseLoader(object): | ||||||
|  | 
 | ||||||
|  |     def test_get_context(self): | ||||||
|  |         c = Context() | ||||||
|  |         c.add("testing", True) | ||||||
|  |         o = BaseLoader("path/does/not/matter.txt", context=c) | ||||||
|  |         assert 'testing' in o.get_context() | ||||||
|  | 
 | ||||||
|  |     def test_get_key_value(self): | ||||||
|  |         o = BaseLoader("path/does/not/matter.txt") | ||||||
|  | 
 | ||||||
|  |         key, value = o._get_key_value("env", ["development", "testing"]) | ||||||
|  |         assert value == ["development", "testing"] | ||||||
|  | 
 | ||||||
|  |         key, value = o._get_key_value("env", "testing") | ||||||
|  |         assert value == ["testing"] | ||||||
|  | 
 | ||||||
|  |         key, value = o._get_key_value("env", "development, testing") | ||||||
|  |         assert value == ["development", "testing"] | ||||||
|  | 
 | ||||||
|  |         key, value = o._get_key_value("func", "test_function") | ||||||
|  |         assert key == "function" | ||||||
|  |         assert value == "test_function" | ||||||
|  | 
 | ||||||
|  |         key, value = o._get_key_value("groups", ["one", "two", "three"]) | ||||||
|  |         assert value == ["one", "two", "three"] | ||||||
|  | 
 | ||||||
|  |         key, value = o._get_key_value("groups", "one, two, three") | ||||||
|  |         assert value == ["one", "two", "three"] | ||||||
|  | 
 | ||||||
|  |         key, value = o._get_key_value("items", ["one", "two", "three"]) | ||||||
|  |         assert value == ["one", "two", "three"] | ||||||
|  | 
 | ||||||
|  |         key, value = o._get_key_value("items", "one, two, three") | ||||||
|  |         assert value == ["one", "two", "three"] | ||||||
|  | 
 | ||||||
|  |         key, value = o._get_key_value("tags", ["one", "two", "three"]) | ||||||
|  |         assert value == ["one", "two", "three"] | ||||||
|  | 
 | ||||||
|  |         key, value = o._get_key_value("tags", "one, two, three") | ||||||
|  |         assert value == ["one", "two", "three"] | ||||||
|  | 
 | ||||||
|  |         key, value = o._get_key_value("testing", "1") | ||||||
|  |         assert value == 1 | ||||||
|  | 
 | ||||||
|  |     def test_load(self): | ||||||
|  |         o = BaseLoader("path/does/not/matter.txt") | ||||||
|  |         with pytest.raises(NotImplementedError): | ||||||
|  |             o.load() | ||||||
|  | 
 | ||||||
|  |     def test_read_file(self): | ||||||
|  |         c = Context() | ||||||
|  |         c.add("domain_tld", "example_app") | ||||||
|  |         o = BaseLoader("tests/examples/template_example.ini", context=c) | ||||||
|  |         assert "example_app" in o.read_file() | ||||||
|  | 
 | ||||||
|  |         c = Context() | ||||||
|  |         c.add("domain_tld", "example_app") | ||||||
|  |         o = BaseLoader("tests/examples/bad_template_example.ini", context=c) | ||||||
|  |         assert o.read_file() is None | ||||||
| @ -0,0 +1,23 @@ | |||||||
|  | import pytest | ||||||
|  | from scripttease.exceptions import InvalidInput | ||||||
|  | from scripttease.lib.contexts import Context | ||||||
|  | from scripttease.lib.loaders import INILoader | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestINILoader(object): | ||||||
|  | 
 | ||||||
|  |     def test_load(self): | ||||||
|  |         o = INILoader("nonexistent.ini") | ||||||
|  |         assert o.load() is False | ||||||
|  | 
 | ||||||
|  |         # ConfigParser raises InterpolationSyntaxError if context is not provided. | ||||||
|  |         c = Context() | ||||||
|  |         c.add("testing", True) | ||||||
|  |         o = INILoader("tests/examples/bad_template_example.ini", context=c) | ||||||
|  |         assert o.load() is False | ||||||
|  | 
 | ||||||
|  |         o = INILoader("tests/examples/python_examples.ini") | ||||||
|  |         assert o.load() is True | ||||||
|  | 
 | ||||||
|  |         o = INILoader('tests/examples/bad_examples.ini') | ||||||
|  |         assert o.load() is False | ||||||
| @ -0,0 +1,4 @@ | |||||||
|  | import pytest | ||||||
|  | from scripttease.exceptions import InvalidInput | ||||||
|  | from scripttease.lib.loaders import YMLLoader | ||||||
|  | 
 | ||||||
| @ -1,130 +0,0 @@ | |||||||
| from scripttease.library.commands.base import Command, ItemizedCommand, Sudo |  | ||||||
| from scripttease.library.overlays.common import python_pip |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class TestCommand(object): |  | ||||||
| 
 |  | ||||||
|     def test_getattr(self): |  | ||||||
|         c = Command("ls -ls", extra=True) |  | ||||||
|         assert c.extra is True |  | ||||||
| 
 |  | ||||||
|     def test_get_statement(self): |  | ||||||
|         c = Command( |  | ||||||
|             "ls -ls", |  | ||||||
|             comment="kitchen sink", |  | ||||||
|             condition="$last_command -eq 0", |  | ||||||
|             cd="/path/to/project", |  | ||||||
|             prefix="source python/bin/active", |  | ||||||
|             register="list_success", |  | ||||||
|             stop=True, |  | ||||||
|             sudo="deploy" |  | ||||||
|         ) |  | ||||||
|         statement = c.get_statement(cd=True) |  | ||||||
|         assert "( cd" in statement |  | ||||||
|         assert "sudo" in statement |  | ||||||
|         assert ")" in statement |  | ||||||
|         assert "# kitchen sink" in statement |  | ||||||
|         assert "if [[ $last_command" in statement |  | ||||||
|         assert "list_success=$?" in statement |  | ||||||
|         assert "if [[ $list_success" in statement |  | ||||||
| 
 |  | ||||||
|         c = Command( |  | ||||||
|             "ls -ls", |  | ||||||
|             stop=True |  | ||||||
|         ) |  | ||||||
|         statement = c.get_statement() |  | ||||||
|         assert "if [[ $?" in statement |  | ||||||
| 
 |  | ||||||
|     def test_has_attribute(self): |  | ||||||
|         c = Command("ls -ls") |  | ||||||
|         assert c.has_attribute("testing") is False |  | ||||||
| 
 |  | ||||||
|     def test_init(self): |  | ||||||
|         c = Command("ls -ls", sudo=Sudo(user="deploy")) |  | ||||||
|         assert isinstance(c.sudo, Sudo) |  | ||||||
|         assert c.sudo.user == "deploy" |  | ||||||
| 
 |  | ||||||
|         c = Command("ls -ls", sudo="deploy") |  | ||||||
|         assert isinstance(c.sudo, Sudo) |  | ||||||
|         assert c.sudo.user == "deploy" |  | ||||||
| 
 |  | ||||||
|         c = Command("ls -ls", sudo=True) |  | ||||||
|         assert isinstance(c.sudo, Sudo) |  | ||||||
|         assert c.sudo.user == "root" |  | ||||||
| 
 |  | ||||||
|         c = Command("ls -ls") |  | ||||||
|         assert isinstance(c.sudo, Sudo) |  | ||||||
|         assert c.sudo.user == "root" |  | ||||||
|         assert c.sudo.enabled is False |  | ||||||
| 
 |  | ||||||
|     def test_is_itemized(self): |  | ||||||
|         c = Command("ls -ls") |  | ||||||
|         assert c.is_itemized is False |  | ||||||
| 
 |  | ||||||
|     def test_repr(self): |  | ||||||
|         c = Command("ls -ls", comment="listing") |  | ||||||
|         assert repr(c) == "<Command listing>" |  | ||||||
| 
 |  | ||||||
|         c = Command("ls -ls") |  | ||||||
|         assert repr(c) == "<Command>" |  | ||||||
| 
 |  | ||||||
|     def test_set_attribute(self): |  | ||||||
|         c = Command("ls -ls") |  | ||||||
|         assert c.testing is None |  | ||||||
|         c.set_attribute("testing", True) |  | ||||||
|         assert c.testing is True |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class TestItemizedCommand(object): |  | ||||||
| 
 |  | ||||||
|     def test_getattr(self): |  | ||||||
|         c = ItemizedCommand(python_pip, ["Pillow", "psycopg2-binary", "django"], "$item", extra=True) |  | ||||||
|         assert c.extra is True |  | ||||||
| 
 |  | ||||||
|     def test_get_commands(self): |  | ||||||
|         c = ItemizedCommand(python_pip, ["Pillow", "psycopg2-binary", "django"], "$item") |  | ||||||
|         commands = c.get_commands() |  | ||||||
|         for i in commands: |  | ||||||
|             assert isinstance(i, Command) |  | ||||||
| 
 |  | ||||||
|     def test_get_statement(self): |  | ||||||
|         c = ItemizedCommand(python_pip, ["Pillow", "psycopg2-binary", "django"], "$item") |  | ||||||
|         statement = c.get_statement() |  | ||||||
|         assert "Pillow" in statement |  | ||||||
|         assert "psycopg2-binary" in statement |  | ||||||
|         assert "django" in statement |  | ||||||
| 
 |  | ||||||
|     def test_has_attribute(self): |  | ||||||
|         c = ItemizedCommand(python_pip, ["Pillow", "psycopg2-binary", "django"], "$item") |  | ||||||
|         assert c.has_attribute("testing") is False |  | ||||||
| 
 |  | ||||||
|     def test_is_itemized(self): |  | ||||||
|         c = ItemizedCommand(python_pip, ["Pillow", "psycopg2-binary", "django"], "$item") |  | ||||||
|         assert c.is_itemized is True |  | ||||||
| 
 |  | ||||||
|     def test_repr(self): |  | ||||||
|         c = ItemizedCommand(python_pip, ["Pillow", "psycopg2-binary", "django"], "$item") |  | ||||||
|         assert repr(c) == "<ItemizedCommand python_pip>" |  | ||||||
| 
 |  | ||||||
|     def test_set_attribute(self): |  | ||||||
|         c = ItemizedCommand(python_pip, ["Pillow", "psycopg2-binary", "django"], "$item") |  | ||||||
|         assert c.testing is None |  | ||||||
|         c.set_attribute("testing", True) |  | ||||||
|         assert c.testing is True |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class TestSudo(object): |  | ||||||
| 
 |  | ||||||
|     def test_bool(self): |  | ||||||
|         s = Sudo() |  | ||||||
|         assert bool(s) is False |  | ||||||
| 
 |  | ||||||
|         s = Sudo(True) |  | ||||||
|         assert bool(s) is True |  | ||||||
| 
 |  | ||||||
|     def test_str(self): |  | ||||||
|         s = Sudo() |  | ||||||
|         assert str(s) == "" |  | ||||||
| 
 |  | ||||||
|         s = Sudo(True) |  | ||||||
|         assert str(s) == "sudo -u root" |  | ||||||
| @ -1,113 +0,0 @@ | |||||||
| from scripttease.library.commands.base import Command, ItemizedCommand, Sudo |  | ||||||
| from scripttease.library.commands.templates import Template |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class TestTemplate(object): |  | ||||||
| 
 |  | ||||||
|     def test_get_content(self): |  | ||||||
|         context = { |  | ||||||
|             'testing': "yes", |  | ||||||
|             'times': 123, |  | ||||||
|         } |  | ||||||
|         t = Template( |  | ||||||
|             "tests/examples/templates/simple.txt", |  | ||||||
|             "tests/tmp/simple.txt", |  | ||||||
|             backup=False, |  | ||||||
|             context=context, |  | ||||||
|             parser=Template.PARSER_SIMPLE |  | ||||||
|         ) |  | ||||||
|         content = t.get_content() |  | ||||||
|         assert "I am testing? yes" in content |  | ||||||
|         assert "How many times? 123" in content |  | ||||||
| 
 |  | ||||||
|         context = { |  | ||||||
|             'testing': "yes", |  | ||||||
|             'times': 123, |  | ||||||
|         } |  | ||||||
|         t = Template( |  | ||||||
|             "tests/examples/templates/simple.sh.txt", |  | ||||||
|             "tests/tmp/simple.sh", |  | ||||||
|             backup=False, |  | ||||||
|             context=context, |  | ||||||
|             parser=Template.PARSER_SIMPLE |  | ||||||
|         ) |  | ||||||
|         content = t.get_content() |  | ||||||
|         assert "I am testing? yes" in content |  | ||||||
|         assert "How many times? 123" in content |  | ||||||
| 
 |  | ||||||
|         context = { |  | ||||||
|             'testing': "yes", |  | ||||||
|             'times': 123, |  | ||||||
|         } |  | ||||||
|         t = Template( |  | ||||||
|             "tests/examples/templates/good.j2.txt", |  | ||||||
|             "tests/tmp/good.txt", |  | ||||||
|             backup=False, |  | ||||||
|             context=context |  | ||||||
|         ) |  | ||||||
|         content = t.get_content() |  | ||||||
|         assert "I am testing? yes" in content |  | ||||||
|         assert "How many times? 123" in content |  | ||||||
| 
 |  | ||||||
|         t = Template("tests/examples/templates/nonexistent.j2.txt", "test/tmp/nonexistent.txt") |  | ||||||
|         assert t.get_content() is None |  | ||||||
| 
 |  | ||||||
|         t = Template("tests/examples/templates/bad.j2.txt", "test/tmp/nonexistent.txt") |  | ||||||
|         assert t.get_content() is None |  | ||||||
| 
 |  | ||||||
|     def test_get_statement(self): |  | ||||||
|         context = { |  | ||||||
|             'testing': "yes", |  | ||||||
|             'times': 123, |  | ||||||
|         } |  | ||||||
|         t = Template( |  | ||||||
|             "tests/examples/templates/simple.txt", |  | ||||||
|             "tests/tmp/simple.txt", |  | ||||||
|             context=context, |  | ||||||
|             parser=Template.PARSER_SIMPLE |  | ||||||
|         ) |  | ||||||
|         s = t.get_statement() |  | ||||||
|         assert "I am testing? yes" in s |  | ||||||
|         assert "How many times? 123" in s |  | ||||||
| 
 |  | ||||||
|         context = { |  | ||||||
|             'testing': "yes", |  | ||||||
|             'times': 123, |  | ||||||
|         } |  | ||||||
|         t = Template( |  | ||||||
|             "tests/examples/templates/simple.sh.txt", |  | ||||||
|             "tests/tmp/simple.txt", |  | ||||||
|             context=context, |  | ||||||
|             parser=Template.PARSER_SIMPLE |  | ||||||
|         ) |  | ||||||
|         s = t.get_statement() |  | ||||||
|         assert "I am testing? yes" in s |  | ||||||
|         assert "How many times? 123" in s |  | ||||||
| 
 |  | ||||||
|         context = { |  | ||||||
|             'testing': "yes", |  | ||||||
|             'times': 123, |  | ||||||
|         } |  | ||||||
|         t = Template( |  | ||||||
|             "tests/examples/templates/good.j2.txt", |  | ||||||
|             "tests/tmp/good.txt", |  | ||||||
|             context=context |  | ||||||
|         ) |  | ||||||
|         s = t.get_statement() |  | ||||||
|         assert "I am testing? yes" in s |  | ||||||
|         assert "How many times? 123" in s |  | ||||||
| 
 |  | ||||||
|         t = Template( |  | ||||||
|             "tests/examples/templates/simple.txt", |  | ||||||
|             "tests/tmp/simple.txt", |  | ||||||
|             parser="nonexistent" |  | ||||||
|         ) |  | ||||||
|         assert t.get_statement() is None |  | ||||||
| 
 |  | ||||||
|     def test_get_template(self): |  | ||||||
|         t = Template( |  | ||||||
|             "simple.txt", |  | ||||||
|             "tests/tmp/simple.txt", |  | ||||||
|             locations=["tests/examples/templates"] |  | ||||||
|         ) |  | ||||||
|         assert t.get_template() == "tests/examples/templates/simple.txt" |  | ||||||
| @ -1,57 +0,0 @@ | |||||||
| import pytest |  | ||||||
| from scripttease.library.overlays.common import * |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def test_python_pip(): |  | ||||||
|     c = python_pip("Pillow") |  | ||||||
|     assert "pip3 install Pillow" in c.get_statement() |  | ||||||
| 
 |  | ||||||
|     c = python_pip("Pillow", upgrade=True) |  | ||||||
|     assert "--upgrade" in c.get_statement() |  | ||||||
| 
 |  | ||||||
|     c = python_pip("Pillow", venv="python") |  | ||||||
|     assert "source python/bin/activate" in c.get_statement() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def test_python_virtual_env(): |  | ||||||
|     c = python_virtualenv("python") |  | ||||||
|     assert "virtualenv python" in c.get_statement() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def test_run(): |  | ||||||
|     c = run("ls -ls") |  | ||||||
|     assert "ls -ls" in c.get_statement() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def test_slack(): |  | ||||||
|     with pytest.raises(ValueError): |  | ||||||
|         slack("This is a test.") |  | ||||||
| 
 |  | ||||||
|     c = slack("This is a test.", url="https://example.slack.com/asdf/1234") |  | ||||||
|     s = c.get_statement(suppress_comment=True) |  | ||||||
|     assert "curl -X POST -H 'Content-type: application/json' --data" in s |  | ||||||
|     assert "This is a test." in s |  | ||||||
|     assert "https://example.slack.com/asdf/1234" in s |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def test_twist(): |  | ||||||
|     with pytest.raises(ValueError): |  | ||||||
|         twist("This is a test.") |  | ||||||
| 
 |  | ||||||
|     c = twist("This is a test.", url="https://example.twist.com/asdf/1234") |  | ||||||
|     s = c.get_statement(suppress_comment=True) |  | ||||||
|     print(s) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def test_udf(): |  | ||||||
|     c = udf("testing") |  | ||||||
|     s = c.get_statement() |  | ||||||
|     assert s == '# <UDF name="testing" label="Testing" />' |  | ||||||
| 
 |  | ||||||
|     c = udf("testing", default="yes") |  | ||||||
|     s = c.get_statement() |  | ||||||
|     assert s == '# <UDF name="testing" label="Testing" default="yes" />' |  | ||||||
| 
 |  | ||||||
|     c = udf("testing", example="example.com") |  | ||||||
|     s = c.get_statement() |  | ||||||
|     assert s == '# <UDF name="testing" label="Testing" example="example.com" />' |  | ||||||
| @ -1,31 +0,0 @@ | |||||||
| from scripttease.library.commands import Command, ItemizedCommand |  | ||||||
| from scripttease.library.overlays.posix import Function |  | ||||||
| from scripttease.library.scripts import Script |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class TestScript(object): |  | ||||||
| 
 |  | ||||||
|     def test_append(self): |  | ||||||
|         s = Script("testing") |  | ||||||
|         s.append(Command("ls -ls", comment="list some stuff")) |  | ||||||
|         s.append(Command("touch /path/to/file.txt", comment="touch a file")) |  | ||||||
|         s.append(Command("ln -s /path/to/file.txt", comment="link to a file")) |  | ||||||
| 
 |  | ||||||
|         assert len(s.commands) == 3 |  | ||||||
| 
 |  | ||||||
|     def test_to_string(self): |  | ||||||
|         s = Script("testing") |  | ||||||
|         s.append(Command("ls -ls", comment="list some stuff")) |  | ||||||
|         s.append(Command("touch /path/to/file.txt", comment="touch a file")) |  | ||||||
|         s.append(Command("ln -s /path/to/file.txt", comment="link to a file")) |  | ||||||
| 
 |  | ||||||
|         s.functions = list() |  | ||||||
|         s.functions.append(Function("testing")) |  | ||||||
| 
 |  | ||||||
|         output = s.to_string() |  | ||||||
|         assert output == str(s) |  | ||||||
| 
 |  | ||||||
|         assert "ls -ls" in output |  | ||||||
|         assert "touch /path/to/file.txt" in output |  | ||||||
|         assert "ln -s /path/to/file.txt" in output |  | ||||||
|         assert "function testing()" in output |  | ||||||
| @ -1,30 +0,0 @@ | |||||||
| import pytest |  | ||||||
| from scripttease.library.overlays.posix import touch, Function |  | ||||||
| from scripttease.library.scripts import Script |  | ||||||
| # from scripttease.parsers import filter_commands, load_commands |  | ||||||
| from scripttease.parsers.base import Parser |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class TestParser(object): |  | ||||||
| 
 |  | ||||||
|     def test_as_script(self): |  | ||||||
|         p = Parser("/path/to/nonexistent.txt") |  | ||||||
|         assert isinstance(p.as_script(), Script) |  | ||||||
| 
 |  | ||||||
|     # def test_get_commands(self): |  | ||||||
|     #     pass |  | ||||||
|     # |  | ||||||
|     def test_get_functions(self): |  | ||||||
|         parser = Parser("/it/does/not/matter.ini") |  | ||||||
| 
 |  | ||||||
|         command = touch("/path/to/file.txt", function="testing") |  | ||||||
|         function = Function("testing") |  | ||||||
|         parser._commands.append(command) |  | ||||||
|         parser._functions.append(function) |  | ||||||
| 
 |  | ||||||
|         assert len(parser.get_functions()) == 1 |  | ||||||
| 
 |  | ||||||
|     def test_load(self): |  | ||||||
|         p = Parser("/path/to/nonexistent.txt") |  | ||||||
|         with pytest.raises(NotImplementedError): |  | ||||||
|             p.load() |  | ||||||
| @ -1,48 +0,0 @@ | |||||||
| import pytest |  | ||||||
| from scripttease.parsers.ini import Config |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class TestConfig(object): |  | ||||||
| 
 |  | ||||||
|     def test_get_commands(self): |  | ||||||
|         c = Config("tests/examples/kitchen_sink.ini") |  | ||||||
|         assert c.load() is True |  | ||||||
| 
 |  | ||||||
|         assert len(c.get_commands()) > 0 |  | ||||||
| 
 |  | ||||||
|     def test_get_functions(self): |  | ||||||
|         c = Config("tests/examples/kitchen_sink.ini") |  | ||||||
|         assert c.load() is True |  | ||||||
| 
 |  | ||||||
|         assert len(c.get_functions()) > 0 |  | ||||||
| 
 |  | ||||||
|     def test_load(self): |  | ||||||
|         c = Config("nonexistent.ini") |  | ||||||
|         assert c.load() is False |  | ||||||
| 
 |  | ||||||
|         c = Config("tests/examples/python_examples.ini", overlay="nonexistent") |  | ||||||
|         assert c.load() is False |  | ||||||
| 
 |  | ||||||
|         c = Config("tests/examples/bad_examples.ini") |  | ||||||
|         assert c.load() is False |  | ||||||
| 
 |  | ||||||
|         c = Config("tests/examples/kitchen_sink.ini") |  | ||||||
|         assert c.load() is True |  | ||||||
| 
 |  | ||||||
|         c = Config("tests/examples/kitchen_sink.ini", context={'testing': "yes"}) |  | ||||||
|         assert c.load() is True |  | ||||||
| 
 |  | ||||||
|         c = Config("tests/examples/bad_command.ini") |  | ||||||
|         assert c.load() is False |  | ||||||
| 
 |  | ||||||
|         context = { |  | ||||||
|             'domain_tld': "example_com", |  | ||||||
|         } |  | ||||||
|         c = Config("tests/examples/template_example.ini", context=context) |  | ||||||
|         assert c.load() is True |  | ||||||
| 
 |  | ||||||
|         context = { |  | ||||||
|             'domain_tld': "example_com", |  | ||||||
|         } |  | ||||||
|         c = Config("tests/examples/bad_template_example.ini", context=context) |  | ||||||
|         assert c.load() is False |  | ||||||
| @ -1,133 +0,0 @@ | |||||||
| import os |  | ||||||
| import pytest |  | ||||||
| from scripttease.library.commands import Command, ItemizedCommand |  | ||||||
| from scripttease.parsers.utils import * |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def test_filter_commands(): |  | ||||||
|     commands = [ |  | ||||||
|         Command("apt-get install apache2 -y", environments=["base"], tags=["web"]), |  | ||||||
|         Command("apt-get install apache-top -y", environments=["live"], tags=["web"]), |  | ||||||
|         Command("pip install django-debug-toolbar", environments=["development"], tags=["django"]), |  | ||||||
|         Command("pip install django", environments=["base"], tags=["django"]), |  | ||||||
|     ] |  | ||||||
|     f1 = filter_commands(commands, environments=["base", "live"]) |  | ||||||
|     assert len(f1) == 3 |  | ||||||
| 
 |  | ||||||
|     f2 = filter_commands(commands, tags=["django"]) |  | ||||||
|     assert len(f2) == 2 |  | ||||||
| 
 |  | ||||||
|     f3 = filter_commands(commands, environments=["base", "development"]) |  | ||||||
|     assert len(f3) == 3 |  | ||||||
| 
 |  | ||||||
|     f4 = filter_commands(commands, environments=["base"], tags=["web"]) |  | ||||||
|     assert len(f4) == 1 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def test_load_commands(): |  | ||||||
|     commands = load_commands("nonexistent.xml") |  | ||||||
|     assert commands is None |  | ||||||
| 
 |  | ||||||
|     commands = load_commands("nonexistent.ini") |  | ||||||
|     assert commands is None |  | ||||||
| 
 |  | ||||||
|     commands = load_commands("tests/examples/bad_examples.ini") |  | ||||||
|     assert commands is None |  | ||||||
| 
 |  | ||||||
|     commands = load_commands( |  | ||||||
|         "tests/examples/python_examples.ini", |  | ||||||
|         filters={ |  | ||||||
|             'tags': ["python-support"], |  | ||||||
|         } |  | ||||||
|     ) |  | ||||||
|     assert len(commands) == 2 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def test_load_variables(): |  | ||||||
|     assert len(load_variables("nonexistent.ini")) == 0 |  | ||||||
| 
 |  | ||||||
|     assert len(load_variables(os.path.join("tests", "examples", "templates", "simple.txt"))) == 0 |  | ||||||
| 
 |  | ||||||
|     variables = load_variables(os.path.join("tests", "examples", "variables.ini")) |  | ||||||
|     assert len(variables) == 5 |  | ||||||
| 
 |  | ||||||
|     variables = load_variables(os.path.join("tests", "examples", "variables.ini"), environment="testing") |  | ||||||
|     assert len(variables) == 4 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class TestContext(object): |  | ||||||
| 
 |  | ||||||
|     def test_add(self): |  | ||||||
|         c = Context() |  | ||||||
|         c.add("testing", True) |  | ||||||
|         assert len(c.variables) == 1 |  | ||||||
| 
 |  | ||||||
|         c.add("also_testing", False) |  | ||||||
|         assert len(c.variables) == 2 |  | ||||||
| 
 |  | ||||||
|         assert isinstance(c.add("still_testing", True), Variable) |  | ||||||
| 
 |  | ||||||
|         with pytest.raises(RuntimeError): |  | ||||||
|             c.add("testing", True) |  | ||||||
| 
 |  | ||||||
|     def test_get(self): |  | ||||||
|         c = Context(testing=True) |  | ||||||
|         assert c.get("testing") is True |  | ||||||
|         assert c.get("nonexistent") is None |  | ||||||
|         assert c.get("nonexistent", default=True) is True |  | ||||||
| 
 |  | ||||||
|     def test_getattr(self): |  | ||||||
|         c = Context(testing=True) |  | ||||||
|         assert c.testing is True |  | ||||||
|         assert c.nonexistent is None |  | ||||||
| 
 |  | ||||||
|     def test_has(self): |  | ||||||
|         c = Context(testing=True) |  | ||||||
|         assert c.has("testing") is True |  | ||||||
|         assert c.has("nonexistent") is False |  | ||||||
| 
 |  | ||||||
|     def test_init(self): |  | ||||||
|         c = Context(testing=True, also_testing=123) |  | ||||||
|         assert len(c.variables) == 2 |  | ||||||
| 
 |  | ||||||
|     def test_join(self): |  | ||||||
|         c = Context(testing=True) |  | ||||||
| 
 |  | ||||||
|         variables = [ |  | ||||||
|             Variable("testing", True), |  | ||||||
|             Variable("also_testing", True), |  | ||||||
|         ] |  | ||||||
|         c.join(variables) |  | ||||||
|         assert len(c.variables) == 2 |  | ||||||
| 
 |  | ||||||
|     def test_mapping(self): |  | ||||||
|         c = Context(testing=True, also_testing=False, still_testing=True) |  | ||||||
|         assert type(c.mapping()) is dict |  | ||||||
|         assert len(c.mapping()) == 3 |  | ||||||
| 
 |  | ||||||
|     def test_merge(self): |  | ||||||
|         c1 = Context(testing=True, also_testing=False) |  | ||||||
|         c2 = Context(still_testing=True) |  | ||||||
|         c1.merge(c2) |  | ||||||
|         assert len(c1.variables) == 3 |  | ||||||
| 
 |  | ||||||
|     def test_repr(self): |  | ||||||
|         c = Context(testing=True, also_testing=False, still_testing=True) |  | ||||||
|         assert repr(c) == "<Context (3)>" |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class TestVariable(object): |  | ||||||
| 
 |  | ||||||
|     def test_eq(self): |  | ||||||
|         var = Variable("testing", True) |  | ||||||
|         assert var == True |  | ||||||
| 
 |  | ||||||
|     def test_getattr(self): |  | ||||||
|         var = Variable("testing", True, one="a", two="b") |  | ||||||
|         assert var.one == "a" |  | ||||||
|         assert var.two == "b" |  | ||||||
|         assert var.three is None |  | ||||||
| 
 |  | ||||||
|     def test_repr(self): |  | ||||||
|         var = Variable("testing", True) |  | ||||||
|         assert repr(var) == "<Variable testing>" |  | ||||||
					Loading…
					
					
				
		Reference in new issue