2
0
mirror of https://github.com/boostorg/build.git synced 2026-02-17 01:32:12 +00:00

Updated Boost Jam to execute commands directly on Windows when that is requested by setting the JAMSHELL variable to '%', the same as for Unix OSs, and not change the user's request under covers to running the command via the default shell if it is 8191 characters long or shorter. Renamed the related Boost Build core_nt_line_length.py test to core_nt_cmd_line.py and updated it with more detailed test cases.

[SVN r79097]
This commit is contained in:
Jurko Gospodnetić
2012-06-25 23:01:59 +00:00
parent d1e0fb099a
commit c5ab0d2e2c
4 changed files with 247 additions and 60 deletions

View File

@@ -233,13 +233,9 @@ int exec_check
if ( is_raw_command_request( *pShell ) )
{
int const raw_cmd_length = raw_command_length( command->value );
if ( !raw_cmd_length )
if ( raw_cmd_length < 0 )
{
return EXEC_CHECK_SKIP;
}
else if ( raw_cmd_length < maxline() )
{
/* Fallback to default shell. */
/* Invalid characters detected - fallback to default shell. */
list_free( *pShell );
*pShell = L0;
}
@@ -250,7 +246,7 @@ int exec_check
return EXEC_CHECK_TOO_LONG;
}
else
return EXEC_CHECK_OK;
return raw_cmd_length ? EXEC_CHECK_OK : EXEC_CHECK_SKIP;
}
/* Now we know we are using an external shell. Note that there is no need to

243
v2/test/core_nt_cmd_line.py Executable file
View File

@@ -0,0 +1,243 @@
#!/usr/bin/python
# Copyright 2001 Dave Abrahams
# Copyright 2011 Steven Watanabe
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
# Tests Windows command line construction.
#
# Note that the regular 'echo' is an internal shell command on Windows and
# therefore can not be called directly as a standalone Windows process.
import BoostBuild
import os
import re
import sys
executable = sys.executable.replace("\\", "/")
if " " in executable:
executable = '"%s"' % executable
def string_of_length(n):
if n <= 0:
return ""
n -= 1
y = ['', '$(1x10-1)', '$(10x10-1)', '$(100x10-1)', '$(1000x10-1)']
result = []
for i in reversed(xrange(5)):
x, n = divmod(n, 10 ** i)
result += [y[i]] * x
result.append('x')
return " ".join(result)
# Boost Jam currently does not allow preparing actions with completly empty
# content as it always requires at least a single whitespace after the opening
# brace in order to satisfy.
def test_raw_empty():
t = BoostBuild.Tester("-d2 -d+4", pass_d0=False, pass_toolset=0,
use_test_config=False)
t.write("file.jam", """\
actions do_empty { %s}
JAMSHELL = %% ;
do_empty all ;
""" % (" \n\n\r\r\v\v\t\t \t \r\r \n\n"))
t.run_build_system("-ffile.jam")
t.expect_output_line("do_empty*", False)
t.expect_output_line("Executing raw command directly", False)
t.cleanup()
def test_raw_nt(n=None, error=False):
t = BoostBuild.Tester("-d1 -d+4", pass_d0=False, pass_toolset=0,
use_test_config=False)
cmd_prefix = "%s -c \"print('XXX: " % executable
cmd_suffix = "')\""
cmd_extra_length = len(cmd_prefix) + len(cmd_suffix)
if n == None:
n = cmd_extra_length
data_length = n - cmd_extra_length
if data_length < 0:
BoostBuild.annotation("failure", """\
Can not construct Windows command of desired length. Requested command length
too short for the current test configuration.
Requested command length: %d
Minimal supported command length: %d
""" % (n, cmd_extra_length))
t.fail_test(1, dump_difference=False)
# Each $(Xx10-1) variable contains X words of 9 characters each, which,
# including spaces between words, brings the total number of characters in
# its string representation to X * 10 - 1 (X * 9 characters + (X - 1)
# spaces).
t.write("file.jam", """\
ten = 0 1 2 3 4 5 6 7 8 9 ;
1x10-1 = 123456789 ;
10x10-1 = $(ten)12345678 ;
100x10-1 = $(ten)$(ten)1234567 ;
1000x10-1 = $(ten)$(ten)$(ten)123456 ;
actions do_echo
{
%s%s%s
}
JAMSHELL = %% ;
do_echo all ;
""" % (cmd_prefix, string_of_length(data_length), cmd_suffix))
t.run_build_system("-ffile.jam", status=1 if error else 0)
if error:
t.expect_output_line("Executing raw command directly", False)
t.expect_output_line("do_echo action is too long (%d, max 32766):" % n)
t.expect_output_line("XXX: *", False)
else:
t.expect_output_line("Executing raw command directly")
t.expect_output_line("do_echo action is too long*", False)
m = re.search("^XXX: (.*)$", t.stdout(), re.MULTILINE)
if not m:
BoostBuild.annotation("failure", "Expected output line starting "
"with 'XXX: ' not found.")
t.fail_test(1, dump_difference=False)
if len(m.group(1)) != data_length:
BoostBuild.annotation("failure", """Unexpected output data length.
Expected: %d
Received: %d""" % (n, len(m.group(1))))
t.fail_test(1, dump_difference=False)
t.cleanup()
def test_raw_to_shell_fallback_nt():
t = BoostBuild.Tester("-d1 -d+4", pass_d0=False, pass_toolset=0,
use_test_config=False)
cmd_prefix = '%s -c print(' % executable
cmd_suffix = ')'
t.write("file_multiline.jam", """\
actions do_multiline
{
echo one
echo two
}
JAMSHELL = % ;
do_multiline all ;
""")
t.run_build_system("-ffile_multiline.jam")
t.expect_output_line("do_multiline all")
t.expect_output_line("one")
t.expect_output_line("two")
t.expect_output_line("Executing raw command directly", False)
t.expect_output_line("Executing using a command file and the shell: "
"cmd.exe /Q/C")
t.write("file_redirect.jam", """\
actions do_redirect { echo one > two.txt }
JAMSHELL = % ;
do_redirect all ;
""")
t.run_build_system("-ffile_redirect.jam")
t.expect_output_line("do_redirect all")
t.expect_output_line("one", False)
t.expect_output_line("Executing raw command directly", False)
t.expect_output_line("Executing using a command file and the shell: "
"cmd.exe /Q/C")
t.expect_addition("two.txt")
t.write("file_pipe.jam", """\
actions do_pipe { echo one | echo two }
JAMSHELL = % ;
do_pipe all ;
""")
t.run_build_system("-ffile_pipe.jam")
t.expect_output_line("do_pipe all")
t.expect_output_line("one", False)
t.expect_output_line("two")
t.expect_output_line("Executing raw command directly", False)
t.expect_output_line("Executing using a command file and the shell: "
"cmd.exe /Q/C")
t.write("file_single_quoted.jam", """\
actions do_single_quoted { %s'5>10'%s }
JAMSHELL = %% ;
do_single_quoted all ;
""" % (cmd_prefix, cmd_suffix))
t.run_build_system("-ffile_single_quoted.jam")
t.expect_output_line("do_single_quoted all")
t.expect_output_line("5>10")
t.expect_output_line("Executing raw command directly")
t.expect_output_line("Executing using a command file and the shell: "
"cmd.exe /Q/C", False)
t.expect_nothing_more()
t.write("file_double_quoted.jam", """\
actions do_double_quoted { %s"5>10"%s }
JAMSHELL = %% ;
do_double_quoted all ;
""" % (cmd_prefix, cmd_suffix))
t.run_build_system("-ffile_double_quoted.jam")
t.expect_output_line("do_double_quoted all")
# The difference between this example and the similar previous one using
# single instead of double quotes stems from how the used Python executable
# parses the command-line string received from Windows.
t.expect_output_line("False")
t.expect_output_line("Executing raw command directly")
t.expect_output_line("Executing using a command file and the shell: "
"cmd.exe /Q/C", False)
t.expect_nothing_more()
t.write("file_escaped_quote.jam", """\
actions do_escaped_quote { %s\\"5>10\\"%s }
JAMSHELL = %% ;
do_escaped_quote all ;
""" % (cmd_prefix, cmd_suffix))
t.run_build_system("-ffile_escaped_quote.jam")
t.expect_output_line("do_escaped_quote all")
t.expect_output_line("5>10")
t.expect_output_line("Executing raw command directly", False)
t.expect_output_line("Executing using a command file and the shell: "
"cmd.exe /Q/C")
t.expect_nothing_more()
t.cleanup()
###############################################################################
#
# main()
# ------
#
###############################################################################
if os.name == 'nt':
test_raw_empty()
# Can not test much shorter lengths as the shortest possible command line
# line length constructed in this depends on the runtime environment, e.g.
# path to the Panther executable running this test.
test_raw_nt()
test_raw_nt(255)
test_raw_nt(1000)
test_raw_nt(8000)
test_raw_nt(8191)
test_raw_nt(8192)
test_raw_nt(10000)
test_raw_nt(30000)
test_raw_nt(32766)
# CreateProcessA() Windows API places a limit of 32768 on the allowed
# command-line length, including a trailing Unicode (2-byte) nul-terminator
# character.
test_raw_nt(32767, error=True)
test_raw_nt(40000, error=True)
test_raw_nt(100001, error=True)
test_raw_to_shell_fallback_nt()

View File

@@ -1,52 +0,0 @@
#!/usr/bin/python
# Copyright 2001 Dave Abrahams
# Copyright 2011 Steven Watanabe
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
import BoostBuild
import os
t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
t.write("file.jam", """
if $(NT)
{
#
# Build a really long commandline. (> 10K characters).
#
ten = 0 1 2 3 4 5 6 7 8 9 ;
1x7chars = 0_____ ;
# add a digit and multiply by 10
10x8chars = $(ten)$(1x7chars) ;
# add a digit to each of 10 strings and multiply by 10
100x9chars = $(ten)$(10x8chars) ;
# add a digit to each of 100 strings and multiply by 10
1000x10chars = $(ten)$(100x9chars) ;
#
# Cause line_length_test to be built
#
actions do_echo
{
echo $(text)
}
400x10chars = $(ten[1-4])$(100x9chars) ;
text on line_length_test = $(400x10chars) 40$(10x8chars[1-9]) 01234 ;
text on line_length_test = $(1000x10chars) $(1000x10chars) ;
JAMSHELL on line_length_test = % ;
DEPENDS all : line_length_test ;
do_echo line_length_test ;
}
else
{
NOCARE all ;
}
""")
t.run_build_system("-ffile.jam")
t.cleanup()

View File

@@ -175,7 +175,7 @@ tests = ["absolute_sources",
"core_actions_quietly",
"core_at_file",
"core_bindrule",
"core_nt_line_length",
"core_nt_cmd_line",
"core_option_d2",
"core_option_l",
"core_option_n",