Add contains() and append() convenience functions

basically stolen from Fabric v1 source code
This commit is contained in:
Lance Edgar 2019-07-23 19:07:14 -05:00
parent bac78764d0
commit 72c03a8ac9
2 changed files with 123 additions and 18 deletions

View file

@ -38,4 +38,4 @@ from .core import (
set_timezone,
UNSPECIFIED,
)
from .util import exists
from .util import exists, contains, append

View file

@ -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