Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (539)
Games in Android Showcase (132)
games submitted by our members
Games in WIP (603)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  ProcessBuilder behaviour on different platforms  (Read 3860 times)
0 Members and 1 Guest are viewing this topic.
Offline Orangy Tang

JGO Kernel


Medals: 56
Projects: 11


Monkey for a head


« Posted 2010-11-05 15:57:09 »

I'm writing a Minecraft server wrapper, and so part of that involves starting the minecraft process via my webapp. The minecraft command line looks like this:

1  
java -Xmx1024M -Xms1024M -jar /path/to/minecraft.jar nogui


Unfortunately I'm having problems dealing with the case where the path to the jar file contains spaces. If I surround the path with "double quotes" then it works on windows, but fails on OSX. If I escape the spaces with backslashes (eg. "C:/Program\ Files/foo.jar") then it works on OSX but fails on windows. In both cases it fails because it's splitting the path in half on the space.

Annoyingly, both methods work just fine if they're actually pasted into a command prompt, it's just via ProcessBuilder that they cause issues. And it doesn't make a difference if I use the ProcessBuilder(List<String>) constructor or the ProcessBuilder(String...) constructor.

Does anyone know what's going on here? Is there a single 'proper' way to pass a path with spaces to the command line via ProcessBuilder?


Thanks.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline ryanm

Senior Devvie


Projects: 1
Exp: 15 years


Used to be bleb


« Reply #1 - Posted 2010-11-05 16:25:29 »

I don't have a direct answer unfortunately, but failing all else you could probably just pass the complete string into Runtime.exec()

A bit more work to deal with the out and err streams seems to be the only penalty.
Offline nsigma
« Reply #2 - Posted 2010-11-05 19:13:58 »

Sorry if this is a daft question, but wasn't sure from what you wrote.  Are you passing in each argument as a separate String - "java" "-jar" "/path/to/minecraft.jar", etc.?

Praxis LIVE - open-source intermedia toolkit and live interactive visual editor
Digital Prisoners - interactive spaces and projections
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 841
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #3 - Posted 2010-11-05 21:17:55 »

Indeed. You must always use a String[] to pass the arguments, quoting simply isn't reliable cross platform, there have been cases where I simply could not get it to work.

I normally make a List<String> and call toArray(new String[]) on it.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social
Offline JL235

JGO Coder


Medals: 10



« Reply #4 - Posted 2010-11-05 21:21:43 »

A second solution (just for reference) would be just to check if your on Windows and use the Windows version and otherwise use your MacOS version (as I'd presume it would work on other Unix like systems).

Offline Orangy Tang

JGO Kernel


Medals: 56
Projects: 11


Monkey for a head


« Reply #5 - Posted 2010-11-06 10:03:18 »

Here's my current code:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
List<String> commands = new ArrayList<String>();
         commands.add("java");
         commands.add("-Xmx1024M");
         commands.add("-Xms1024M");
         commands.add("-jar");
         
         String exePath = "";
         if (OsDetect.isMac())
         {
            exePath = exe.file.getAbsolutePath().replace(" ", "\\ ");
         }
         else
         {
            exePath = "\"" + exe.file.getAbsolutePath() + "\"";
         }
         commands.add(exePath);
         
         if (!showGui)
            commands.add("nogui");
         ProcessBuilder builder = new ProcessBuilder(commands);


ryanm: the whole point of process builder (as far as I know) is that by passing an array of args rather than one string they'll be correctly separated, rather than relying on platform-specific parsing. I suspect that going with Runtime.exec will be even more quirky between platforms.

nsigma, Riven: I should have been more specific. Smiley Hopefully my code above shows you that I'm already doing that (either that or I've misunderstood you).

JL235: Yeah, that's the method I've currently gone with. However it's pretty hacky - it reminds me of generating different html for different browsers, and once you start down that road it gets ugly fast. Sad It'll do for the time being though.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline Mr. Gol

Senior Devvie


Medals: 1



« Reply #6 - Posted 2010-11-06 13:42:45 »

1  
2  
3  
4  
5  
6  
7  
         if (OsDetect.isMac())
         {
            exePath = exe.file.getAbsolutePath().replace(" ", "\\ ");
         }
[/quote]

No need for that, just throw in file.getAbsolutePath() directly.
Offline Orangy Tang

JGO Kernel


Medals: 56
Projects: 11


Monkey for a head


« Reply #7 - Posted 2010-11-06 14:17:52 »

No need for that, just throw in file.getAbsolutePath() directly.

Um, did you read the thread properly? Without escaping the spaces it'll fail to get the right jar path on OSX.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline Mr. Gol

Senior Devvie


Medals: 1



« Reply #8 - Posted 2010-11-06 14:44:02 »

Um, did you read the thread properly? Without escaping the spaces it'll fail to get the right jar path on OSX.

That was in the original post, when you were still passing in a single string. I have used Runtime.exec with JAR paths with spaces in them for years, I haven't actually tested the same code with ProcessBuilder but I would be surprised if ProcessBuilder and Runtime.exec behaved differently in this area. And the reason why they take a String[] as input is so that platform-specific stuff such as putting spaces between options, quoting, and escaping are done for you.
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 841
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #9 - Posted 2010-11-06 14:58:27 »

This is what happens behind the scenes, in java.lang.ProcessImpl:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
   private ProcessImpl(String cmd[],
         String envblock,
         String path,
         boolean redirectErrorStream)
   throws IOException
    {
   // Win32 CreateProcess requires cmd[0] to be normalized
   cmd[0] = new File(cmd[0]).getPath();

   StringBuilder cmdbuf = new StringBuilder(80);
   for (int i = 0; i < cmd.length; i++) {
            if (i > 0) {
                cmdbuf.append(' ');
            }
       String s = cmd[i];
       if (s.indexOf(' ') >= 0 || s.indexOf('\t') >= 0) {
           if (s.charAt(0) != '"') {
          cmdbuf.append('"');
          cmdbuf.append(s);
          if (s.endsWith("\\")) {
         cmdbuf.append("\\");
          }
          cmdbuf.append('"');
                } else if (s.endsWith("\"")) {
          /* The argument has already been quoted. */
          cmdbuf.append(s);
      } else {
          /* Unmatched quote for the argument. */
          throw new IllegalArgumentException();
      }
       } else {
           cmdbuf.append(s);
       }
   }
   String cmdstr = cmdbuf.toString();

   stdin_fd  = new FileDescriptor();
   stdout_fd = new FileDescriptor();
   stderr_fd = new FileDescriptor();

   handle = create(cmdstr, envblock, path, redirectErrorStream,
         stdin_fd, stdout_fd, stderr_fd);

   java.security.AccessController.doPrivileged(
       new java.security.PrivilegedAction() {
       public Object run() {
      stdin_stream =
          new BufferedOutputStream(new FileOutputStream(stdin_fd));
      stdout_stream =
          new BufferedInputStream(new FileInputStream(stdout_fd));
      stderr_stream =
          new FileInputStream(stderr_fd);
      return null;
       }
   });
    }


It shows how quoting your arguments on Windows is not required.

I wouldn't know why Mac OS X requires the additional space escaping.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Orangy Tang

JGO Kernel


Medals: 56
Projects: 11


Monkey for a head


« Reply #10 - Posted 2010-11-06 17:22:14 »

That was in the original post, when you were still passing in a single string.

I should have been more clear - the code I've tested has *always* been passing an array of strings, never as one big string.

Quote
I haven't actually tested the same code with ProcessBuilder

I have. And as described, it doesn't work without escaping or quotes.

Quote
And the reason why they take a String[] as input is so that platform-specific stuff such as putting spaces between options, quoting, and escaping are done for you.

Well yes. I know this. However as I've said, I've tested it and it doesn't work in practice.

I feel like i'm repeating myself here - I know how it *should* work in theory, and I know that because i'm passing it as an array of strings it *should* take care of paths with spaces automatically, but please believe me when I say I've actually tested this on multiple machines and it doesn't work.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

rwatson462 (33 views)
2014-12-15 09:26:44

Mr.CodeIt (23 views)
2014-12-14 19:50:38

BurntPizza (51 views)
2014-12-09 22:41:13

BurntPizza (84 views)
2014-12-08 04:46:31

JscottyBieshaar (45 views)
2014-12-05 12:39:02

SHC (59 views)
2014-12-03 16:27:13

CopyableCougar4 (59 views)
2014-11-29 21:32:03

toopeicgaming1999 (123 views)
2014-11-26 15:22:04

toopeicgaming1999 (114 views)
2014-11-26 15:20:36

toopeicgaming1999 (32 views)
2014-11-26 15:20:08
Resources for WIP games
by kpars
2014-12-18 10:26:14

Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!