mirror of https://gitlab.com/ita1024/waf.git
Simplify long command processing
This commit is contained in:
parent
4a09e1943a
commit
537d1fcd45
|
@ -6,7 +6,7 @@
|
|||
Tasks represent atomic operations such as processes.
|
||||
"""
|
||||
|
||||
import re, sys
|
||||
import os, re, sys, tempfile
|
||||
from waflib import Utils, Logs, Errors
|
||||
|
||||
# task states
|
||||
|
@ -174,6 +174,19 @@ class TaskBase(evil):
|
|||
self.generator.bld.fatal('Working folders given to tasks must be Node objects')
|
||||
return ret
|
||||
|
||||
def quote_flag(self, x):
|
||||
old = x
|
||||
if '\\' in x:
|
||||
x = x.replace('\\', '\\\\')
|
||||
if '"' in x:
|
||||
x = x.replace('"', '\\"')
|
||||
if old != x or ' ' in x or '\t' in x or "'" in x:
|
||||
x = '"%s"' % x
|
||||
return x
|
||||
|
||||
def split_argfile(self, cmd):
|
||||
return ([cmd[0]], [self.quote_flag(x) for x in cmd[1:]])
|
||||
|
||||
def exec_command(self, cmd, **kw):
|
||||
"""
|
||||
Wrapper for :py:meth:`waflib.Context.Context.exec_command` which sets a current working directory to ``build.variant_dir``
|
||||
|
@ -183,7 +196,24 @@ class TaskBase(evil):
|
|||
"""
|
||||
if not 'cwd' in kw:
|
||||
kw['cwd'] = self.get_cwd()
|
||||
return self.generator.bld.exec_command(cmd, **kw)
|
||||
|
||||
# workaround for command line length limit:
|
||||
# http://support.microsoft.com/kb/830473
|
||||
if not isinstance(cmd, str) and len(repr(cmd)) >= 8192:
|
||||
cmd, args = self.split_argfile(cmd)
|
||||
try:
|
||||
(fd, tmp) = tempfile.mkstemp()
|
||||
os.write(fd, '\r\n'.join(args).encode())
|
||||
os.close(fd)
|
||||
return self.generator.bld.exec_command(cmd + ['@' + tmp], **kw)
|
||||
finally:
|
||||
try:
|
||||
os.remove(tmp)
|
||||
except OSError:
|
||||
# anti-virus and indexers can keep files open -_-
|
||||
pass
|
||||
else:
|
||||
return self.generator.bld.exec_command(cmd, **kw)
|
||||
|
||||
def runnable_status(self):
|
||||
"""
|
||||
|
|
|
@ -126,41 +126,9 @@ class mcs(Task.Task):
|
|||
run_str = '${MCS} ${CSTYPE} ${CSFLAGS} ${ASS_ST:ASSEMBLIES} ${RES_ST:RESOURCES} ${OUT} ${SRC}'
|
||||
|
||||
def exec_command(self, cmd, **kw):
|
||||
if not 'cwd' in kw:
|
||||
kw['cwd'] = self.get_cwd()
|
||||
|
||||
try:
|
||||
tmp = None
|
||||
if isinstance(cmd, list) and len(' '.join(cmd)) >= 8192:
|
||||
program = cmd[0] #unquoted program name, otherwise exec_command will fail
|
||||
cmd = [self.quote_response_command(x) for x in cmd]
|
||||
(fd, tmp) = tempfile.mkstemp()
|
||||
os.write(fd, '\r\n'.join(i.replace('\\', '\\\\') for i in cmd[1:]).encode())
|
||||
os.close(fd)
|
||||
cmd = [program, '@' + tmp]
|
||||
# no return here, that's on purpose
|
||||
ret = self.generator.bld.exec_command(cmd, **kw)
|
||||
finally:
|
||||
if tmp:
|
||||
try:
|
||||
os.remove(tmp)
|
||||
except OSError:
|
||||
pass # anti-virus and indexers can keep the files open -_-
|
||||
return ret
|
||||
|
||||
def quote_response_command(self, flag):
|
||||
# /noconfig is not allowed when using response files
|
||||
if flag.lower() == '/noconfig':
|
||||
return ''
|
||||
|
||||
if flag.find(' ') > -1:
|
||||
for x in ('/r:', '/reference:', '/resource:', '/lib:', '/out:'):
|
||||
if flag.startswith(x):
|
||||
flag = '%s"%s"' % (x, '","'.join(flag[len(x):].split(',')))
|
||||
break
|
||||
else:
|
||||
flag = '"%s"' % flag
|
||||
return flag
|
||||
if '/noconfig' in cmd:
|
||||
raise ValueError('/noconfig is not allowed when using response files, check your flags!')
|
||||
return super(self.__class__, self).exec_command(cmd, **kw)
|
||||
|
||||
def configure(conf):
|
||||
"""
|
||||
|
|
|
@ -94,8 +94,8 @@ def configure(conf):
|
|||
conf.fc_add_flags()
|
||||
conf.ifort_modifier_platform()
|
||||
|
||||
import os, sys, re, tempfile
|
||||
from waflib import Task, Logs, Options, Errors
|
||||
import os, re
|
||||
from waflib import Task, Logs, Errors
|
||||
from waflib.TaskGen import after_method, feature
|
||||
|
||||
from waflib.Configure import conf
|
||||
|
@ -449,38 +449,7 @@ def exec_mf(self):
|
|||
lst.extend(['-manifest', manifest])
|
||||
lst.append('-outputresource:%s;%s' % (outfile, mode))
|
||||
|
||||
return self.exec_command(lst)
|
||||
|
||||
def quote_response_command(self, flag):
|
||||
if flag.find(' ') > -1:
|
||||
for x in ('/LIBPATH:', '/IMPLIB:', '/OUT:', '/I'):
|
||||
if flag.startswith(x):
|
||||
flag = '%s"%s"' % (x, flag[len(x):])
|
||||
break
|
||||
else:
|
||||
flag = '"%s"' % flag
|
||||
return flag
|
||||
|
||||
def exec_response_command(self, cmd, **kw):
|
||||
# not public yet
|
||||
try:
|
||||
tmp = None
|
||||
if sys.platform.startswith('win') and isinstance(cmd, list) and len(' '.join(cmd)) >= 8192:
|
||||
program = cmd[0] #unquoted program name, otherwise exec_command will fail
|
||||
cmd = [self.quote_response_command(x) for x in cmd]
|
||||
(fd, tmp) = tempfile.mkstemp()
|
||||
os.write(fd, '\r\n'.join(i.replace('\\', '\\\\') for i in cmd[1:]).encode())
|
||||
os.close(fd)
|
||||
cmd = [program, '@' + tmp]
|
||||
# no return here, that's on purpose
|
||||
ret = super(self.__class__, self).exec_command(cmd, **kw)
|
||||
finally:
|
||||
if tmp:
|
||||
try:
|
||||
os.remove(tmp)
|
||||
except OSError:
|
||||
pass # anti-virus and indexers can keep the files open -_-
|
||||
return ret
|
||||
return super(self.__class__, self).exec_command(lst)
|
||||
|
||||
def exec_command_ifort(self, *k, **kw):
|
||||
"""
|
||||
|
@ -503,10 +472,9 @@ def exec_command_ifort(self, *k, **kw):
|
|||
env.update(PATH = ';'.join(self.env['PATH']))
|
||||
kw['env'] = env
|
||||
|
||||
|
||||
if not 'cwd' in kw:
|
||||
kw['cwd'] = self.get_cwd()
|
||||
ret = self.exec_response_command(k[0], **kw)
|
||||
ret = super(self.__class__, self).exec_command(k[0], **kw)
|
||||
if not ret and getattr(self, 'do_manifest', None):
|
||||
ret = self.exec_mf()
|
||||
return ret
|
||||
|
@ -527,15 +495,13 @@ def wrap_class(class_name):
|
|||
if self.env.IFORT_WIN32:
|
||||
return self.exec_command_ifort(*k, **kw)
|
||||
else:
|
||||
return super(derived_class, self).exec_command(*k, **kw)
|
||||
return super(self.__class__, self).exec_command(*k, **kw)
|
||||
|
||||
# Chain-up monkeypatch needed since exec_command() is in base class API
|
||||
derived_class.exec_command = exec_command
|
||||
|
||||
# No chain-up behavior needed since the following methods aren't in
|
||||
# base class API
|
||||
derived_class.exec_response_command = exec_response_command
|
||||
derived_class.quote_response_command = quote_response_command
|
||||
derived_class.exec_command_ifort = exec_command_ifort
|
||||
derived_class.exec_mf = exec_mf
|
||||
|
||||
|
|
|
@ -26,8 +26,8 @@ You would have to run::
|
|||
[1] http://www.jython.org/
|
||||
"""
|
||||
|
||||
import os, tempfile, shutil
|
||||
from waflib import Task, Utils, Errors, Node, Logs
|
||||
import os, shutil
|
||||
from waflib import Task, Utils, Errors, Node
|
||||
from waflib.Configure import conf
|
||||
from waflib.TaskGen import feature, before_method, after_method
|
||||
|
||||
|
@ -210,7 +210,19 @@ def use_jar_files(self):
|
|||
y.post()
|
||||
self.jar_task.run_after.update(y.tasks)
|
||||
|
||||
class jar_create(Task.Task):
|
||||
class JTask(Task.Task):
|
||||
def split_argfile(self, cmd):
|
||||
inline = [cmd[0]]
|
||||
infile = []
|
||||
for x in cmd[1:]:
|
||||
# jar and javac do not want -J flags in @file
|
||||
if x.startswith('-J'):
|
||||
inline.append(x)
|
||||
else:
|
||||
infile.append(self.quote_flag(x))
|
||||
return (inline, infile)
|
||||
|
||||
class jar_create(JTask):
|
||||
"""
|
||||
Create a jar file
|
||||
"""
|
||||
|
@ -233,12 +245,12 @@ class jar_create(Task.Task):
|
|||
raise Errors.WafError('Could not find the basedir %r for %r' % (self.basedir, self))
|
||||
return super(jar_create, self).runnable_status()
|
||||
|
||||
class javac(Task.Task):
|
||||
class javac(JTask):
|
||||
"""
|
||||
Compile java files
|
||||
"""
|
||||
color = 'BLUE'
|
||||
|
||||
run_str = '${JAVAC} -classpath ${CLASSPATH} -d ${OUTDIR} ${JAVACFLAGS} ${SRC}'
|
||||
vars = ['CLASSPATH', 'JAVACFLAGS', 'JAVAC', 'OUTDIR']
|
||||
"""
|
||||
The javac task will be executed again if the variables CLASSPATH, JAVACFLAGS, JAVAC or OUTDIR change.
|
||||
|
@ -265,50 +277,6 @@ class javac(Task.Task):
|
|||
self.inputs.extend(x.ant_glob(SOURCE_RE, remove=False))
|
||||
return super(javac, self).runnable_status()
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
Execute the javac compiler
|
||||
"""
|
||||
env = self.env
|
||||
gen = self.generator
|
||||
bld = gen.bld
|
||||
wd = bld.bldnode
|
||||
def to_list(xx):
|
||||
if isinstance(xx, str): return [xx]
|
||||
return xx
|
||||
cmd = []
|
||||
cmd.extend(to_list(env['JAVAC']))
|
||||
cmd.extend(['-classpath'])
|
||||
cmd.extend(to_list(env['CLASSPATH']))
|
||||
cmd.extend(['-d'])
|
||||
cmd.extend(to_list(env['OUTDIR']))
|
||||
cmd.extend(to_list(env['JAVACFLAGS']))
|
||||
|
||||
files = [a.path_from(self.get_cwd()) for a in self.inputs]
|
||||
|
||||
# workaround for command line length limit:
|
||||
# http://support.microsoft.com/kb/830473
|
||||
tmp = None
|
||||
try:
|
||||
if len(str(files)) + len(str(cmd)) > 8192:
|
||||
(fd, tmp) = tempfile.mkstemp(dir=bld.bldnode.abspath())
|
||||
try:
|
||||
os.write(fd, '\n'.join(files).encode())
|
||||
finally:
|
||||
if tmp:
|
||||
os.close(fd)
|
||||
if Logs.verbose:
|
||||
Logs.debug('runner: %r', cmd + files)
|
||||
cmd.append('@' + tmp)
|
||||
else:
|
||||
cmd += files
|
||||
|
||||
ret = self.exec_command(cmd, cwd=wd, env=env.env or None)
|
||||
finally:
|
||||
if tmp:
|
||||
os.remove(tmp)
|
||||
return ret
|
||||
|
||||
def post_run(self):
|
||||
"""
|
||||
"""
|
||||
|
|
|
@ -52,7 +52,7 @@ cmd.exe /C "chcp 1252 & set PYTHONUNBUFFERED=true && set && waf configure"
|
|||
Setting PYTHONUNBUFFERED gives the unbuffered output.
|
||||
"""
|
||||
|
||||
import os, sys, re, tempfile
|
||||
import os, sys, re
|
||||
from waflib import Utils, Task, Logs, Options, Errors
|
||||
from waflib.TaskGen import after_method, feature
|
||||
|
||||
|
@ -980,38 +980,7 @@ def exec_mf(self):
|
|||
lst.extend(['-manifest', manifest])
|
||||
lst.append('-outputresource:%s;%s' % (outfile, mode))
|
||||
|
||||
return self.exec_command(lst)
|
||||
|
||||
def quote_response_command(self, flag):
|
||||
if flag.find(' ') > -1:
|
||||
for x in ('/LIBPATH:', '/IMPLIB:', '/OUT:', '/I'):
|
||||
if flag.startswith(x):
|
||||
flag = '%s"%s"' % (x, flag[len(x):])
|
||||
break
|
||||
else:
|
||||
flag = '"%s"' % flag
|
||||
return flag
|
||||
|
||||
def exec_response_command(self, cmd, **kw):
|
||||
# not public yet
|
||||
try:
|
||||
tmp = None
|
||||
if sys.platform.startswith('win') and isinstance(cmd, list) and len(' '.join(cmd)) >= 8192:
|
||||
program = cmd[0] #unquoted program name, otherwise exec_command will fail
|
||||
cmd = [self.quote_response_command(x) for x in cmd]
|
||||
(fd, tmp) = tempfile.mkstemp()
|
||||
os.write(fd, '\r\n'.join(i.replace('\\', '\\\\') for i in cmd[1:]).encode())
|
||||
os.close(fd)
|
||||
cmd = [program, '@' + tmp]
|
||||
# no return here, that's on purpose
|
||||
ret = self.generator.bld.exec_command(cmd, **kw)
|
||||
finally:
|
||||
if tmp:
|
||||
try:
|
||||
os.remove(tmp)
|
||||
except OSError:
|
||||
pass # anti-virus and indexers can keep the files open -_-
|
||||
return ret
|
||||
return super(self.__class__, self).exec_command(lst)
|
||||
|
||||
########## stupid evil command modification: concatenate the tokens /Fx, /doc, and /x: with the next token
|
||||
|
||||
|
@ -1039,7 +1008,7 @@ def exec_command_msvc(self, *k, **kw):
|
|||
|
||||
if not 'cwd' in kw:
|
||||
kw['cwd'] = self.get_cwd()
|
||||
ret = self.exec_response_command(k[0], **kw)
|
||||
ret = super(self.__class__, self).exec_command(k[0], **kw)
|
||||
if not ret and getattr(self, 'do_manifest', None):
|
||||
ret = self.exec_mf()
|
||||
return ret
|
||||
|
@ -1060,15 +1029,13 @@ def wrap_class(class_name):
|
|||
if self.env['CC_NAME'] == 'msvc':
|
||||
return self.exec_command_msvc(*k, **kw)
|
||||
else:
|
||||
return super(derived_class, self).exec_command(*k, **kw)
|
||||
return super(self.__class__, self).exec_command(*k, **kw)
|
||||
|
||||
# Chain-up monkeypatch needed since exec_command() is in base class API
|
||||
derived_class.exec_command = exec_command
|
||||
|
||||
# No chain-up behavior needed since the following methods aren't in
|
||||
# base class API
|
||||
derived_class.exec_response_command = exec_response_command
|
||||
derived_class.quote_response_command = quote_response_command
|
||||
derived_class.exec_command_msvc = exec_command_msvc
|
||||
derived_class.exec_mf = exec_mf
|
||||
|
||||
|
|
Loading…
Reference in New Issue