Changeset - 72c03a8ac9fe
[Not reviewed]
0 2 0
Lance Edgar - 5 years ago 2019-07-23 19:07:14
ledgar@techsupport.coop
Add `contains()` and `append()` convenience functions

basically stolen from Fabric v1 source code
2 files changed with 123 insertions and 18 deletions:
0 comments (0 inline, 0 general) First comment
rattail_fabric2/__init__.py
Show inline comments
 
@@ -38,4 +38,4 @@ from .core import (
 
    set_timezone,
 
    UNSPECIFIED,
 
)
 
from .util import exists
 
from .util import exists, contains, append
rattail_fabric2/util.py
Show inline comments
 
@@ -2,7 +2,7 @@
 
################################################################################
 
#
 
#  Rattail -- Retail Software Framework
 
#  Copyright © 2010-2018 Lance Edgar
 
#  Copyright © 2010-2019 Lance Edgar
 
#
 
#  This file is part of Rattail.
 
#
 
@@ -24,7 +24,127 @@
 
Misc. Utilities
 
"""
 

	
 
from __future__ import unicode_literals, absolute_import
 

	
 
def exists(c, path, use_sudo=False):
 
    """
 
    Return True if given path exists on the current remote host.
 

	
 
    If ``use_sudo`` is True, will use `sudo` instead of `run`.
 

	
 
    .. note::
 

	
 
       This function is derived from one copied from fabric v1.
 
    """
 
    func = c.sudo if use_sudo else c.run
 
    cmd = 'stat %s' % _expand_path(c, path)
 
    return not func(cmd, warn=True).failed
 

	
 

	
 
def contains(c, filename, text, exact=False, use_sudo=False, escape=True,
 
             shell=False, case_sensitive=True):
 
    """
 
    NOTE: This was copied from the upstream ``fabric.contrib.files`` (v1) module.
 

	
 
    Return True if ``filename`` contains ``text`` (which may be a regex.)
 

	
 
    By default, this function will consider a partial line match (i.e. where
 
    ``text`` only makes up part of the line it's on). Specify ``exact=True`` to
 
    change this behavior so that only a line containing exactly ``text``
 
    results in a True return value.
 

	
 
    This function leverages ``egrep`` on the remote end (so it may not follow
 
    Python regular expression syntax perfectly), and skips ``env.shell``
 
    wrapper by default.
 

	
 
    If ``use_sudo`` is True, will use `sudo` instead of `run`.
 

	
 
    If ``escape`` is False, no extra regular expression related escaping is
 
    performed (this includes overriding ``exact`` so that no ``^``/``$`` is
 
    added.)
 

	
 
    The ``shell`` argument will be eventually passed to ``run/sudo``. See
 
    description of the same argument in ``~fabric.contrib.sed`` for details.
 

	
 
    If ``case_sensitive`` is False, the `-i` flag will be passed to ``egrep``.
 
    """
 
    func = use_sudo and c.sudo or c.run
 
    if escape:
 
        text = _escape_for_regex(text)
 
        if exact:
 
            text = "^%s$" % text
 
    # TODO: do we need to bother hiding things here?
 
    # with settings(hide('everything'), warn_only=True):
 
    egrep_cmd = 'egrep "%s" %s' % (text, _expand_path(c, filename))
 
    if not case_sensitive:
 
        egrep_cmd = egrep_cmd.replace('egrep', 'egrep -i', 1)
 
    return not func(egrep_cmd, shell=shell, warn=True).failed
 

	
 

	
 
def append(c, filename, text, use_sudo=False, partial=False, escape=True,
 
           shell=False):
 
    """
 
    NOTE: This was copied from the upstream ``fabric.contrib.files`` (v1) module.
 

	
 
    Append string (or list of strings) ``text`` to ``filename``.
 

	
 
    When a list is given, each string inside is handled independently (but in
 
    the order given.)
 

	
 
    If ``text`` is already found in ``filename``, the append is not run, and
 
    None is returned immediately. Otherwise, the given text is appended to the
 
    end of the given ``filename`` via e.g. ``echo '$text' >> $filename``.
 

	
 
    The test for whether ``text`` already exists defaults to a full line match,
 
    e.g. ``^<text>$``, as this seems to be the most sensible approach for the
 
    "append lines to a file" use case. You may override this and force partial
 
    searching (e.g. ``^<text>``) by specifying ``partial=True``.
 

	
 
    Because ``text`` is single-quoted, single quotes will be transparently
 
    backslash-escaped. This can be disabled with ``escape=False``.
 

	
 
    If ``use_sudo`` is True, will use `sudo` instead of `run`.
 

	
 
    The ``shell`` argument will be eventually passed to ``run/sudo``. See
 
    description of the same argumnet in ``~fabric.contrib.sed`` for details.
 
    """
 
    func = use_sudo and c.sudo or c.run
 
    # Normalize non-list input to be a list
 
    # TODO: do we need to check for six.something here?
 
    # if isinstance(text, basestring):
 
    if isinstance(text, str):
 
        text = [text]
 
    for line in text:
 
        regex = '^' + _escape_for_regex(line)  + ('' if partial else '$')
 
        if (exists(c, filename, use_sudo=use_sudo) and line
 
            and contains(c, filename, regex, use_sudo=use_sudo, escape=False,
 
                         shell=shell)):
 
            continue
 
        line = line.replace("'", r"'\\''") if escape else line
 
        func("echo '%s' >> %s" % (line, _expand_path(c, filename)))
 

	
 

	
 
def _escape_for_regex(text):
 
    """
 
    NOTE: This was copied from the upstream ``fabric.contrib.files`` (v1) module.
 

	
 
    Escape ``text`` to allow literal matching using egrep
 
    """
 
    re_specials = '\\^$|(){}[]*+?.'
 
    sh_specials = '\\$`"'
 
    re_chars = []
 
    sh_chars = []
 

	
 
    for c in text:
 
        if c in re_specials:
 
            re_chars.append('\\')
 
        re_chars.append(c)
 

	
 
    for c in re_chars:
 
        if c in sh_specials:
 
            sh_chars.append('\\')
 
        sh_chars.append(c)
 

	
 
    return ''.join(sh_chars)
 

	
 

	
 
def is_win(c):
 
@@ -58,18 +178,3 @@ def _expand_path(c, path):
 
       This function is derived from one copied from fabric v1.
 
    """
 
    return path if is_win(c) else '"$(echo %s)"' % path
 

	
 

	
 
def exists(c, path, use_sudo=False):
 
    """
 
    Return True if given path exists on the current remote host.
 

	
 
    If ``use_sudo`` is True, will use `sudo` instead of `run`.
 

	
 
    .. note::
 

	
 
       This function is derived from one copied from fabric v1.
 
    """
 
    func = c.sudo if use_sudo else c.run
 
    cmd = 'stat %s' % _expand_path(c, path)
 
    return not func(cmd, warn=True).failed
0 comments (0 inline, 0 general) First comment
You need to be logged in to comment. Login now