pvl/backup/invoke.py
author Tero Marttila <terom@paivola.fi>
Mon, 22 Apr 2013 00:36:14 +0300
changeset 72 2d2494132e9c
parent 68 adc190def3b1
permissions -rw-r--r--
depend on pvl-common
5
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     1
"""
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     2
    Invoke external commands.
72
2d2494132e9c depend on pvl-common
Tero Marttila <terom@paivola.fi>
parents: 68
diff changeset
     3
2d2494132e9c depend on pvl-common
Tero Marttila <terom@paivola.fi>
parents: 68
diff changeset
     4
    XXX: replace with pvl.invoke
5
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     5
"""
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     6
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     7
import subprocess
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     8
import logging
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     9
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    10
log = logging.getLogger('pvl.backup.invoke')
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    11
68
adc190def3b1 pvl.backup.invoke: implement sudo=True to exec via sudo
Tero Marttila <terom@paivola.fi>
parents: 27
diff changeset
    12
SUDO = '/usr/bin/sudo'
adc190def3b1 pvl.backup.invoke: implement sudo=True to exec via sudo
Tero Marttila <terom@paivola.fi>
parents: 27
diff changeset
    13
5
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    14
class InvokeError (Exception) :
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    15
    def __init__ (self, cmd, exit) :
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    16
        self.cmd = cmd
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    17
        self.exit = exit
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    18
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    19
    def __str__ (self) :
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    20
        return "{cmd} failed: {exit}".format(cmd=self.cmd, exit=self.exit)
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    21
68
adc190def3b1 pvl.backup.invoke: implement sudo=True to exec via sudo
Tero Marttila <terom@paivola.fi>
parents: 27
diff changeset
    22
def invoke (cmd, args, data=None, sudo=False) :
5
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    23
    """
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    24
        Invoke a command directly.
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    25
        
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    26
        data:       data to pass in on stdin, returning stdout.
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    27
                    if given as False, passes through our process stdin/out
68
adc190def3b1 pvl.backup.invoke: implement sudo=True to exec via sudo
Tero Marttila <terom@paivola.fi>
parents: 27
diff changeset
    28
        sudo:       exec using sudo
5
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    29
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    30
        Doesn't give any data on stdin, and keeps process stderr.
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    31
        Returns stdout.
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    32
    """
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    33
    
68
adc190def3b1 pvl.backup.invoke: implement sudo=True to exec via sudo
Tero Marttila <terom@paivola.fi>
parents: 27
diff changeset
    34
    log.debug("{sudo}{cmd} {args}".format(sudo=('sudo ' if sudo else ''), cmd=cmd, args=' '.join(args)))
5
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    35
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    36
    if data is False :
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    37
        # keep process stdin/out
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    38
        io = None
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    39
    else :
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    40
        io = subprocess.PIPE
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    41
68
adc190def3b1 pvl.backup.invoke: implement sudo=True to exec via sudo
Tero Marttila <terom@paivola.fi>
parents: 27
diff changeset
    42
    args = [cmd] + args
adc190def3b1 pvl.backup.invoke: implement sudo=True to exec via sudo
Tero Marttila <terom@paivola.fi>
parents: 27
diff changeset
    43
adc190def3b1 pvl.backup.invoke: implement sudo=True to exec via sudo
Tero Marttila <terom@paivola.fi>
parents: 27
diff changeset
    44
    if sudo :
adc190def3b1 pvl.backup.invoke: implement sudo=True to exec via sudo
Tero Marttila <terom@paivola.fi>
parents: 27
diff changeset
    45
        args = [SUDO] + args
adc190def3b1 pvl.backup.invoke: implement sudo=True to exec via sudo
Tero Marttila <terom@paivola.fi>
parents: 27
diff changeset
    46
adc190def3b1 pvl.backup.invoke: implement sudo=True to exec via sudo
Tero Marttila <terom@paivola.fi>
parents: 27
diff changeset
    47
    p = subprocess.Popen(args, stdin=io, stdout=io)
5
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    48
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    49
    # get output
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    50
    stdout, stderr = p.communicate(input=data)
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    51
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    52
    if p.returncode :
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    53
        # failed
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    54
        raise InvokeError(cmd, p.returncode)
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    55
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    56
    return stdout
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    57
12
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    58
def process_opt (opt, value) :
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    59
    """
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    60
        Mangle from python keyword-argument dict format to command-line option tuple format.
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    61
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    62
        >>> process_opt('foo', True)
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    63
        ('--foo',)
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    64
        >>> process_opt('foo', 2)
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    65
        ('--foo', '2')
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    66
        >>> process_opt('foo', 'bar')
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    67
        ('--foo', 'bar')
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    68
        >>> process_opt('foo_bar', 'asdf')
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    69
        ('--foo-bar', 'asdf')
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    70
27
689407a261c3 invoke: change process_opt behaviour to omit all bool(...) == False options, including empty strings (fixes mount --options use)
Tero Marttila <terom@paivola.fi>
parents: 13
diff changeset
    71
        # empty
689407a261c3 invoke: change process_opt behaviour to omit all bool(...) == False options, including empty strings (fixes mount --options use)
Tero Marttila <terom@paivola.fi>
parents: 13
diff changeset
    72
        >>> process_opt('foo', False)
689407a261c3 invoke: change process_opt behaviour to omit all bool(...) == False options, including empty strings (fixes mount --options use)
Tero Marttila <terom@paivola.fi>
parents: 13
diff changeset
    73
        ()
689407a261c3 invoke: change process_opt behaviour to omit all bool(...) == False options, including empty strings (fixes mount --options use)
Tero Marttila <terom@paivola.fi>
parents: 13
diff changeset
    74
        >>> process_opt('foo', None)
689407a261c3 invoke: change process_opt behaviour to omit all bool(...) == False options, including empty strings (fixes mount --options use)
Tero Marttila <terom@paivola.fi>
parents: 13
diff changeset
    75
        ()
12
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    76
        >>> process_opt('bar', '')
27
689407a261c3 invoke: change process_opt behaviour to omit all bool(...) == False options, including empty strings (fixes mount --options use)
Tero Marttila <terom@paivola.fi>
parents: 13
diff changeset
    77
        ()
12
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    78
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    79
        Returns a tuple of argv items.
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    80
    """
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    81
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    82
    # mangle opt
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    83
    opt = '--' + opt.replace('_', '-')
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    84
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    85
    if value is True :
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    86
        # flag opt
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    87
        return (opt, )
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    88
27
689407a261c3 invoke: change process_opt behaviour to omit all bool(...) == False options, including empty strings (fixes mount --options use)
Tero Marttila <terom@paivola.fi>
parents: 13
diff changeset
    89
    elif not value :
12
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    90
        # flag opt / omit
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    91
        return ( )
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    92
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    93
    else :
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    94
        # as-is
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    95
        return (opt, str(value))
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
    96
5
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    97
def optargs (*args, **kwargs) :
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    98
    """
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    99
        Convert args/options into command-line format
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   100
    """
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   101
12
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
   102
    ## opts
5
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   103
    # process
12
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
   104
    opts = [process_opt(opt, value) for opt, value in kwargs.iteritems()]
5
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   105
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   106
    # flatten
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   107
    opts = [str(opt_part) for opt_parts in opts for opt_part in opt_parts if opt_part]
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   108
12
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
   109
    ## args
5
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   110
    args = [str(arg) for arg in args if arg]
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   111
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   112
    return opts + args
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   113
 
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   114
def command (cmd, *args, **opts) :
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   115
    """
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   116
        Invoke a command with options/arguments, given via Python arguments/keyword arguments.
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   117
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   118
        Return stdout.
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   119
    """
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   120
    
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   121
    log.debug("{cmd} {opts} {args}".format(cmd=cmd, args=args, opts=opts))
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   122
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   123
    # invoke
23371d26fdd0 split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   124
    return invoke(cmd, optargs(*args, **opts))
12
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
   125
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
   126
if __name__ == '__main__':
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
   127
    import doctest
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
   128
    doctest.testmod()
fbfdde7326f4 rsync-snapshot: manage --link-dest'd interval snapshots
Tero Marttila <terom@paivola.fi>
parents: 5
diff changeset
   129