Adam Howell
Adam Howell

Reputation: 455

Getting Java ProcessBuilder environment to persist for multiple commands

I want to use ProcessBuilder to create an environment that I can reuse for multiple batch files, in order to automate some testing I repeatedly perform. Specifically, I need to run vcvars64.bat (x64 Native Tools Command Prompt for VS 2019) to set up the system environment, before I run my tests.

To manually run the tests, I would bring up a command prompt, run vcvars64.bat, and then manually run a number of batch files.

I have been able to use ProcessBuilder to launch my test batch files, but they return the error that I see if I forgot to run vcvars64.bat before running the tests.

My attempts so far have been to instantiate a ProcessBuilder using vcvars64.bat as the command, .start() it, .waitFor() the Process to finish, then reuse that same ProcessBuilder for Test1.bat then Test2.bat etc, in the hopes it would retain the environment settings.

Here is the relevant section of my code:

ProcessBuilder processBuilder = new ProcessBuilder();
Process process;
Map<String, String> envMap = processBuilder.environment();
for( Map.Entry<String, String> entry : envMap.entrySet() )
{
    System.out.println( "1 - Key: \"" + entry.getKey() + "\", Value: \"" + entry.getValue() + "\"" );
}
try
{
    process = processBuilder.command( "C:\\Windows\\system32\\cmd.exe", "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise\\VC\\Auxiliary\\Build\\vcvars64.bat" )
        .directory( new File( "C:\\bat\\" ) )
        .redirectInput( new File( "C:\\bat\\", "cr4.txt" ) )
        .redirectOutput( new File( edgePath, "tempFile.txt" ) )
        .start();
    MAIN_LOGGER.log( Level.INFO, "Waiting for the CMD process to finish..." );
    process.waitFor();
    envMap = processBuilder.environment();
    for( Map.Entry<String, String> entry : envMap.entrySet() )
    {
        System.out.println( "2 - Key: \"" + entry.getKey() + "\", Value: \"" + entry.getValue() + "\"" );
    }
    // Now try to run my batch file that requires parameters normally set by vcvars64.bat
    process = processBuilder.command( "C:\\bat\\TestBatch.bat" )
        .directory( new File( "C:\\bat\\" ) )
        .redirectInput( new File( "C:\\bat\\", "cr4.txt" ) )
        .redirectOutput( new File( "C:\\bat\\", "tempFile.txt" ) )
        .start();
}
catch( IOException | InterruptedException e )
{
    System.out.println( e.getLocalizedMessage() );
}

Is my plan correct, and my implementation buggy? Or do I need a new plan?

Upvotes: 1

Views: 646

Answers (1)

DuncG
DuncG

Reputation: 15136

Unfortunately processBuilder.environment() won't pick up any changes inside the VC bat file so your double launch won't help. However depending on what vcvars64.bat looks like you may be able to package up your own launch.cmd file which you call passing two parameters: path to VC batch, and the path to your actual script to run. Then your ProcessBuilder command is just something like:

String launch = "C:\\bat\\launch.cmd";
String vcenv = "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise\\VC\\Auxiliary\\Build\\vcvars64.bat";
String task  = "C:\\bat\\TestBatch.bat";

String[] cmd = new String[] {"cmd.exe", "/c", launch, vcenv, task};

process = processBuilder.command(cmd);

Example launch.cmd:

call %1
call %2
exit /b %errorlevel%

Example task.bat:

echo RUNNING TASK %0

Upvotes: 1

Related Questions