shlex 2.78 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env python3
"""
	shlex - execve but apply shlex to argv
"""
import shlex
import subprocess
import logging
import os
import sys
import argparse
11
import shutil
12
import re
13
14
15
16

LOGGER = logging.getLogger(os.path.basename(__file__))

ARGP = argparse.ArgumentParser()
17
18
ARGP.add_argument('--subprocess-shell', '-S', action='store_true')
ARGP.add_argument('--verbose', '-v', action='store_true')
dylan grafmyre's avatar
dylan grafmyre committed
19
ARGP.add_argument('--low', action='store_true')
dylan grafmyre's avatar
dylan grafmyre committed
20
21
ARGP.add_argument('--tail-bin')
ARGP.add_argument('--tail', help="follow a file while supervising a subprocess")
22
23
ARGP.add_argument('remainder', nargs=argparse.REMAINDER)

dylan grafmyre's avatar
dylan grafmyre committed
24
BELOW_NORMAL_PRIORITY_CLASS = 0x00004000
25
26
RE_GITBASH_STYLE = re.compile('^/(\w)/')

27
28
29
def main(argp=None, argv=None):
    if argp is None:
        argp = ARGP.parse_args(argv)
30
31
32
    logging.basicConfig(
        level=(logging.INFO if argp.verbose else logging.WARNING),
    )
33

34
35
36
    if argp.remainder and argp.remainder[0] == '--':
        argp.remainder = argp.remainder[1:]

37
38
39
    LOGGER.info('execve_orig: %r', argp.remainder)
    execve = shlex.split(' '.join(argp.remainder))  #  + ['&', 'exit']  windows hack to get returncode?
    LOGGER.info('execve_shlex: %r', execve)
40
41
42
43
    execve_sub = [
        [orig, os.path.normpath(RE_GITBASH_STYLE.subn('\\1:\\\\', orig, count=1)[0])]
        for orig in execve
    ]
44
    execve = [
45
46
        (i[1] if os.path.isfile(i[1]) else i[0])
        for i in execve_sub
47
48
    ]
    LOGGER.info('execve_shlex_normpath: %r', execve)
49
50
51
52
53
54
55
56
57
58
59

    bin_ = execve[0]
    #if not os.path.isfile(bin_):
    #    LOGGER.error('os path is not file: %r', bin_)
    which_bin = shutil.which(bin_)
    if which_bin is not None and which_bin != bin_:
        LOGGER.error('execve[0]: %r -> %r', bin_, which_bin)
        execve[0] = which_bin

    LOGGER.info('execve: %r', execve)
    LOGGER.info('execve_shell: %r', argp.subprocess_shell)
dylan grafmyre's avatar
dylan grafmyre committed
60
61
62
63
64
65
66
67
68
    tail_popen = None
    if argp.tail:
        if not argp.tail_bin:
            raise RuntimeError('--tail-bin is required')
        if 'CPROGRAMFILESOLD' in argp.tail:
            argp.tail = argp.tail.replace('CPROGRAMFILESOLD', 'C:\\program files (x86)')
        if 'CPROGRAMFILES' in argp.tail_bin:
            argp.tail_bin = argp.tail_bin.replace('CPROGRAMFILES', 'C:\\program files')
        tail_popen = subprocess.Popen([argp.tail_bin, '-fn0', argp.tail], stdout=sys.stderr.buffer)
69
70
    cproc = None
    try:
dylan grafmyre's avatar
dylan grafmyre committed
71
72
73
74
75
        cproc = subprocess.run(
            execve,
            shell=argp.subprocess_shell,
            creationflags=(BELOW_NORMAL_PRIORITY_CLASS if argp.low else None),
        )
76
77
78
    except OSError as err:
        LOGGER.error('%s:%s\nprogram: %r', err.__class__.__name__, err, execve[0])
        return 2
dylan grafmyre's avatar
dylan grafmyre committed
79
80
    if tail_popen:
        tail_popen.kill()
81
82
83
84
85
    LOGGER.info('execve_rc: %r', cproc.returncode)
    return cproc.returncode

if __name__ == '__main__':
	exit(main())