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 |