Skip to content

Commit 92a9cfb

Browse files
author
Marcelo Vanzin
committed
Fix Win32 launcher, usage.
Some more characters need to be espaced now that SparkLauncher is running a batch script as a a child. Also some fixes for the handling of usage errors.
1 parent 6184c07 commit 92a9cfb

File tree

7 files changed

+57
-11
lines changed

7 files changed

+57
-11
lines changed

bin/spark-submit

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,11 @@
1818
#
1919

2020
SPARK_HOME="$(cd "`dirname "$0"`"/..; pwd)"
21+
22+
usage() {
23+
"$SPARK_HOME"/bin/spark-class org.apache.spark.deploy.SparkSubmit --help
24+
exit $1
25+
}
26+
export -f usage
27+
2128
exec "$SPARK_HOME"/bin/spark-class org.apache.spark.deploy.SparkSubmit "$@"

bin/spark-submit.cmd

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,15 @@ rem
2020
rem This is the entry point for running Spark submit. To avoid polluting the
2121
rem environment, it just launches a new cmd to do the real work.
2222

23-
cmd /V /E /C %~dp0spark-class2.cmd org.apache.spark.deploy.SparkSubmit %*
23+
set CLASS=org.apache.spark.deploy.SparkSubmit
24+
call %~dp0spark-class2.cmd %CLASS% %*
25+
set SPARK_ERROR_LEVEL=%ERRORLEVEL%
26+
if "%SPARK_LAUNCHER_USAGE_ERROR%"=="1" (
27+
call :usage
28+
exit /b 1
29+
)
30+
exit /b %SPARK_ERROR_LEVEL%
31+
32+
:usage
33+
call %SPARK_HOME%\bin\spark-class2.cmd %CLASS% --help
34+
goto :eof

launcher/src/main/java/org/apache/spark/launcher/CommandBuilderUtils.java

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -231,16 +231,19 @@ static void checkState(boolean check, String msg, Object... args) {
231231

232232
/**
233233
* Quote a command argument for a command to be run by a Windows batch script, if the argument
234-
* needs quoting. Arguments only seem to need quotes in batch scripts if they have whitespace.
234+
* needs quoting. Arguments only seem to need quotes in batch scripts if they have certain
235+
* special characters, some of which need extra (and different) escaping.
235236
*
236237
* For example:
237-
* original single argument: ab "cde" fgh
238-
* quoted: "ab ""cde"" fgh"
238+
* original single argument: ab="cde fgh"
239+
* quoted: "ab^=""cde fgh"""
239240
*/
240241
static String quoteForBatchScript(String arg) {
242+
241243
boolean needsQuotes = false;
242244
for (int i = 0; i < arg.length(); i++) {
243-
if (Character.isWhitespace(arg.codePointAt(i)) || arg.codePointAt(i) == '"') {
245+
int c = arg.codePointAt(i);
246+
if (Character.isWhitespace(c) || c == '"' || c == '=') {
244247
needsQuotes = true;
245248
break;
246249
}
@@ -252,8 +255,17 @@ static String quoteForBatchScript(String arg) {
252255
quoted.append("\"");
253256
for (int i = 0; i < arg.length(); i++) {
254257
int cp = arg.codePointAt(i);
255-
if (cp == '\"') {
256-
quoted.append("\"");
258+
switch (cp) {
259+
case '"':
260+
quoted.append('"');
261+
break;
262+
263+
case '=':
264+
quoted.append('^');
265+
break;
266+
267+
default:
268+
break;
257269
}
258270
quoted.appendCodePoint(cp);
259271
}

launcher/src/main/java/org/apache/spark/launcher/Main.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,9 @@ private static class UsageLauncher extends AbstractCommandBuilder {
147147
@Override
148148
public List<String> buildCommand(Map<String, String> env) {
149149
if (isWindows()) {
150-
return Arrays.asList("set SPARK_LAUNCHER_USAGE_ERROR=1");
150+
return Arrays.asList("set", "SPARK_LAUNCHER_USAGE_ERROR=1");
151151
} else {
152-
return Arrays.asList("usage 1");
152+
return Arrays.asList("usage", "1");
153153
}
154154
}
155155

launcher/src/main/java/org/apache/spark/launcher/SparkLauncher.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,9 +257,21 @@ public SparkLauncher setVerbose(boolean verbose) {
257257
*/
258258
public Process launch() throws IOException {
259259
List<String> cmd = new ArrayList<String>();
260-
cmd.add(join(File.separator, builder.getSparkHome(), "bin", "spark-submit"));
260+
String script = isWindows() ? "spark-submit.cmd" : "spark-submit";
261+
cmd.add(join(File.separator, builder.getSparkHome(), "bin", script));
261262
cmd.addAll(builder.buildSparkSubmitArgs());
262263

264+
// Since the child process is a batch script, let's quote things so that special characters are
265+
// preserved, otherwise the batch interpreter will mess up the arguments. Batch scripts are
266+
// weird.
267+
if (isWindows()) {
268+
List<String> winCmd = new ArrayList<String>();
269+
for (String arg : cmd) {
270+
winCmd.add(quoteForBatchScript(arg));
271+
}
272+
cmd = winCmd;
273+
}
274+
263275
ProcessBuilder pb = new ProcessBuilder(cmd.toArray(new String[cmd.size()]));
264276
for (Map.Entry<String, String> e : builder.childEnv.entrySet()) {
265277
pb.environment().put(e.getKey(), e.getValue());

launcher/src/main/java/org/apache/spark/launcher/SparkSubmitCommandBuilder.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ private List<String> buildPySparkShellCommand(Map<String, String> env) throws IO
245245

246246
private boolean isClientMode(Properties userProps) {
247247
String userMaster = firstNonEmpty(master, (String) userProps.get(SparkLauncher.SPARK_MASTER));
248+
// Default master is "local[*]", so assume client mode in that case.
248249
return userMaster == null ||
249250
"client".equals(deployMode) ||
250251
(!userMaster.equals("yarn-cluster") && deployMode == null);
@@ -292,7 +293,9 @@ protected boolean handle(String opt, String value) {
292293
}
293294
} else {
294295
sparkArgs.add(opt);
295-
sparkArgs.add(value);
296+
if (value != null) {
297+
sparkArgs.add(value);
298+
}
296299
}
297300
return true;
298301
}

launcher/src/test/java/org/apache/spark/launcher/CommandBuilderUtilsSuite.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public void testWindowsBatchQuoting() {
7474
assertEquals("\"a b c\"", quoteForBatchScript("a b c"));
7575
assertEquals("\"a \"\"b\"\" c\"", quoteForBatchScript("a \"b\" c"));
7676
assertEquals("\"a\"\"b\"\"c\"", quoteForBatchScript("a\"b\"c"));
77+
assertEquals("\"ab^=\"\"cd\"\"\"", quoteForBatchScript("ab=\"cd\""));
7778
}
7879

7980
@Test

0 commit comments

Comments
 (0)