Check-in [a325214b04]
Overview
| Comment: | Implement new commandline parsing options, kxrs` cmdline_split as found on SO. And configurable simple quote (but still enabled for conf.windows by default). |
|---|---|
| Downloads: | Tarball | ZIP archive | SQL archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA1: |
a325214b04ac5401e21ecdc1943a374a |
| User & Date: | mario on 2017-10-16 22:58:29 |
| Other Links: | manifest | tags |
Context
|
2017-11-17
| ||
| 13:20 | Change default streamripper user agent to 'iTunes 12.5/Gecko/SR' check-in: e4d747b68a user: mario tags: trunk | |
|
2017-10-16
| ||
| 22:58 | Implement new commandline parsing options, kxrs` cmdline_split as found on SO. And configurable simple quote (but still enabled for conf.windows by default). check-in: a325214b04 user: mario tags: trunk | |
|
2017-10-14
| ||
| 23:07 | Jamendo radios are not available; prepared to use API however, in case they're relocated.. check-in: e161173e94 user: mario tags: trunk | |
Changes
Modified contrib/st2subprocess.py from [dfd2e2745d] to [43791deb88].
1 2 3 4 | # encoding: utf-8 # api: streamtuner2 # title: win32/subprocess # description: Utilizes subprocess spawning or win32 API instead of os.system | | | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# encoding: utf-8
# api: streamtuner2
# title: win32/subprocess
# description: Utilizes subprocess spawning or win32 API instead of os.system
# version: 0.5
# depends: streamtuner2 > 2.2.0, python >= 2.7
# priority: optional
# config:
# { name: cmd_spawn, type: select, select: "popen|shell|call|execv|spawnv|pywin32|win32api|system", value: popen, description: Spawn method }
# { name: cmd_flags, type: select, select: "none|nowait|detached|nowaito|all|sw_hide|sw_maximize|sw_minimize|sw_show", value: detached, description: Process creation flags (win32) }
# { name: cmd_quote, type: bool, value: 0, description: Simple quoting override (for Windows) }
# { name: cmd_split, type: select, select: kxr|shlex|nonposix, value: kxr, description: Command string splitting variant }
# type: handler
# category: io
# license: MITL, CC-BY-SA-3.0
#
# Overrides the action.run method with subprocess.Popen() and a bit
# cmdline parsing. Which mostly makes sense on Windows to avoid some
# `start` bugs, such as "http://.." arguments getting misinterpreted.
# Also works on Linux, though with few advantages and some gotchas.
#
# +------------------+-----+------+---------+-------+----------------------+
|
| ︙ | ︙ | |||
43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# or features obviously. Unless you wrap player commands with `sh -c …`
#
import subprocess
import os
import shlex
import re
from config import *
from channels import FeaturePlugin
import action
try:
import win32process
| > | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# or features obviously. Unless you wrap player commands with `sh -c …`
#
import subprocess
import os
import shlex
import pipes
import re
from config import *
from channels import FeaturePlugin
import action
try:
import win32process
|
| ︙ | ︙ | |||
82 83 84 85 86 87 88 |
"sw_show": 5, # https://msdn.microsoft.com/en-us/library/windows/desktop/ms633548(v=vs.85).aspx
}
# swap out action.run()
def init2(self, parent, *k, **kw):
action.run = self.run
| | | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
"sw_show": 5, # https://msdn.microsoft.com/en-us/library/windows/desktop/ms633548(v=vs.85).aspx
}
# swap out action.run()
def init2(self, parent, *k, **kw):
action.run = self.run
if conf.windows or conf.cmd_split:
action.quote = self.quote
# override for action.quote
def quote(self, ins):
# use default for string-style exec methods / or array arg
if conf.cmd_spawn in ("system", "default", "win32api") or type(ins) is list:
|
| ︙ | ︙ | |||
104 105 106 107 108 109 110 |
# blacklist
if re.search("streamripper|cmd\.exe", cmd):
return orig_run(cmd)
# split args
| > > > | | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# blacklist
if re.search("streamripper|cmd\.exe", cmd):
return orig_run(cmd)
# split args
if conf.cmd_split in ("kxr", "cmdline_split", "multi"):
args = self.cmdline_split(cmd, platform=(not conf.windows))
else:
args = shlex.split(cmd, posix=(cmd_split=="shlex"))
# undo win32 quoting damage
if conf.windows and re.search('\^', cmd): #and action.quote != self.quote:
args = [re.sub(r'\^(?=[()<>"&^])', '', s) for s in args]
# flags
if conf.windows and conf.cmd_flags in self.flagmap:
flags = self.flagmap[conf.cmd_flags]
else:
|
| ︙ | ︙ | |||
160 161 162 163 164 165 166 167 |
win32api.WinExec(cmd, flags) # should only use SW_* flags
)
# fallback
else:
return orig_run(cmd)
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
win32api.WinExec(cmd, flags) # should only use SW_* flags
)
# fallback
else:
return orig_run(cmd)
# shlex.split for Windows
def cmdline_split(self, s, platform='this'):
"""Multi-platform variant of shlex.split() for command-line splitting.
For use with subprocess, for argv injection etc. Using fast REGEX.
platform: 'this' = auto from current platform;
1 = POSIX;
0 = Windows/CMD
(other values reserved)
author: kxr / Philip Jenvey
license: CC-BB-SA-3.0
src: https://stackoverflow.com/questions/33560364/python-windows-parsing-command-lines-with-shlex
"""
if platform == 'this':
platform = (sys.platform != 'win32')
if platform == 1:
RE_CMD_LEX = r'''"((?:\\["\\]|[^"])*)"|'([^']*)'|(\\.)|(&&?|\|\|?|\d?\>|[<])|([^\s'"\\&|<>]+)|(\s+)|(.)'''
elif platform == 0:
RE_CMD_LEX = r'''"((?:""|\\["\\]|[^"])*)"?()|(\\\\(?=\\*")|\\")|(&&?|\|\|?|\d?>|[<])|([^\s"&|<>]+)|(\s+)|(.)'''
else:
raise AssertionError('unkown platform %r' % platform)
args = []
accu = None # collects pieces of one arg
for qs, qss, esc, pipe, word, white, fail in re.findall(RE_CMD_LEX, s):
if word:
pass # most frequent
elif esc:
word = esc[1]
elif white or pipe:
if accu is not None:
args.append(accu)
if pipe:
args.append(pipe)
accu = None
continue
elif fail:
raise ValueError("invalid or incomplete shell string")
elif qs:
word = qs.replace('\\"', '"').replace('\\\\', '\\')
if platform == 0:
word = word.replace('""', '"')
else:
word = qss # may be even empty; must be last
accu = (accu or '') + word
if accu is not None:
args.append(accu)
return args
|