I am building a CLI tool that is running the following Maven command
mvn archetype:generate -B -DarchetypeGroupId=me.pablo -DarchetypeArtifactId=fleeti-archetype -DarchetypeVersion=1.0 -Dversion=1.0 -DgroupId=me.pablo -Dpackage=me.pablo -Dname=Test -DartifactId=test
it's supposed to run this command in the following directory
C:\Users\35356\Desktop\Test
Now, I created my own utility class to run the commands I need using ProcessBuilder:
package me.pablo.processes;
import me.pablo.FleetiMessage;
import me.pablo.FleetiMessageType;
import me.pablo.commands.Command;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.Arrays;
public class FleetiProcess
{
private List<Command> commands;
private List<Process> allProcesses;
public FleetiProcess(final List<Command> commands) {
this.commands = commands;
this.allProcesses = new ArrayList<>();
}
public void execute() {
runProcess();
}
public void executeAsync(final int delayInSeconds) {
Executors.newSingleThreadScheduledExecutor().schedule(this::runProcess, delayInSeconds, TimeUnit.SECONDS);
}
public void execute(final int delayInSeconds) {
Executors.newSingleThreadScheduledExecutor().schedule(this::stopFleetiProcess, delayInSeconds, TimeUnit.SECONDS);
runProcess();
}
public void stopFleetiProcess() {
allProcesses.forEach(Process::destroyForcibly);
}
private void runProcess() {
commands.forEach(command -> {
// Debug messages
System.out.println("Raw command is \n" + command.getRawCommand());
System.out.println("Split command is \n" + Arrays.toString(command.getRawCommand().split(" ")));
System.out.println("Target file exist: \n" + new File(command.getPath()).exists());
final ProcessBuilder commandBuilder = new ProcessBuilder();
commandBuilder.command(command.getRawCommand().split(" "));
commandBuilder.directory(new File(command.getPath()));
try {
final Process commandProcess = commandBuilder.start();
final StreamGobbler streamGobbler = new StreamGobbler(commandProcess.getInputStream(), System.out::println);
Executors.newSingleThreadExecutor().submit(streamGobbler);
allProcesses.add(commandProcess);
int exitVal = commandProcess.waitFor();
if (exitVal == 0) {
FleetiMessage.printMessage(
new FleetiMessage(FleetiMessageType.SUCCESS, "Successfully ran process for " + command.getRawCommand()));
} else {
FleetiMessage.printMessage(
new FleetiMessage(FleetiMessageType.ERROR, "Could not run process for command " + command.getRawCommand()));
}
} catch (final IOException | InterruptedException e) {
e.printStackTrace();
}
});
}
private static class StreamGobbler implements Runnable {
private InputStream inputStream;
private Consumer<String> consumer;
StreamGobbler(InputStream inputStream, Consumer<String> consumer) {
this.inputStream = inputStream;
this.consumer = consumer;
}
#Override
public void run() {
new BufferedReader(new InputStreamReader(inputStream)).lines()
.forEach(consumer);
}
}
}
Every time I run this code, I run into the same error:
java.io.IOException: Cannot run program "mvn" (in directory "C:\Users\35356\Desktop\Test"): CreateProcess error=2, The system cannot find the file specified
I've researched this problem, and I've tried the suggested solutions: trying to pass the command in the ProcessBuilder constructor, running the command as a single String, and making sure the file actually exists.
However, I know for a fact that the file exists. This is the complete console output:
Raw command is
mvn archetype:generate -B -DarchetypeGroupId=me.pablo -DarchetypeArtifactId=fleeti-archetype -DarchetypeVersion=1.0 -Dversion=1.0 -DgroupId=me.pablo -Dpackage=me.pablo -Dname=Test -DartifactId=test
Split command is
[mvn, archetype:generate, -B, -DarchetypeGroupId=me.pablo, -DarchetypeArtifactId=fleeti-archetype, -DarchetypeVersion=1.0, -Dversion=1.0, -DgroupId=me.pablo, -Dpackage=me.pablo, -Dname=Test, -DartifactId=test]
Target file exist:
true
java.io.IOException: Cannot run program "mvn" (in directory "C:\Users\35356\Desktop\Test"): CreateProcess error=2, The system cannot find the file specified
at java.base/java.lang.ProcessBuilder.start(Unknown Source)
at java.base/java.lang.ProcessBuilder.start(Unknown Source)
at me.pablo.processes.FleetiProcess.lambda$runProcess$0(FleetiProcess.java:53)
at java.base/java.lang.Iterable.forEach(Unknown Source)
at me.pablo.processes.FleetiProcess.runProcess(FleetiProcess.java:43)
at me.pablo.processes.FleetiProcess.execute(FleetiProcess.java:26)
at me.pablo.commands.FleetiCreateAppCommand.run(FleetiCreateAppCommand.java:89)
at picocli.CommandLine.executeUserObject(CommandLine.java:1729)
at picocli.CommandLine.access$900(CommandLine.java:145)
at picocli.CommandLine$RunLast.handle(CommandLine.java:2101)
at picocli.CommandLine$RunLast.handle(CommandLine.java:2068)
at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:1935)
at picocli.CommandLine.execute(CommandLine.java:1864)
at me.pablo.FleetiCLI.main(FleetiCLI.java:19)
Caused by: java.io.IOException: CreateProcess error=2, The system cannot find the file specified
at java.base/java.lang.ProcessImpl.create(Native Method)
at java.base/java.lang.ProcessImpl.<init>(Unknown Source)
at java.base/java.lang.ProcessImpl.start(Unknown Source)
... 14 more
I ran this code in MacOS and worked perfectly. I am only having this issue when running on a Windows. Does anyone know what could be the issue?
Related
I created a simplest Spring-Boot application to test running command, see the completed code below, after click Run 'Application' in InteliJ, console ends up with Process finished with exit code 0, no directory structures in console display.
Run dir c: in terminal returns all the files and directories, seems Process process = Runtime.getRuntime().exec("cmd /c dir C:"); does not run at all.
I put process = Runtime.getRuntime().exec("dir C:");, running application again, this time console output ends up with java.io.IOException: CreateProcess error=2, apparently Java runtime recognized command as invalid.
Why Process process = Runtime.getRuntime().exec("cmd /c dir C:"); does not return any result?
package
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
#SpringBootApplication
public class Application {
public static void main(String[] args) { SpringApplication.run(Application.class); }
#Bean
public CommandLineRunner CommandLineRunnerBean() {
return (args) -> {
Process process = Runtime.getRuntime().exec("cmd /c dir C:");
// process = Runtime.getRuntime().exec("dir C:");
}
}
}
First, code that you posted doesn't compile.
When you write this line of code:
Process process = Runtime.getRuntime().exec("cmd /c dir C:");
Process is executed, but you need to write code that will display result of this process in console.
You can get result of process by calling :
process.getInputStream()
getInputStream() method gets the input stream of the subprocess. The stream obtains data piped from the standard output stream of the process represented by Process object.
Third, to display all directories in C drive, you should use this path:
Process process = Runtime.getRuntime().exec(String.format("cmd /c dir %s", "C:\\"));
To summarize, if you want to see all directories in your C: drive, first you will need to create a class which will used to output result of process to java console as I mentioned above.
Let's call that class HelperReader.
Here is the code:
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.function.Consumer;
public class HelperReader implements Runnable {
private InputStream inputStream;
private Consumer<String> consumer;
public HelperReader(InputStream inputStream, Consumer<String> consumer) {
this.inputStream = inputStream;
this.consumer = consumer;
}
#Override
public void run() {
new BufferedReader(new InputStreamReader(inputStream)).lines()
.forEach(consumer);
}
}
Change code in your Application class to something like this:
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.util.concurrent.Executors;
#SpringBootApplication
public class Application implements CommandLineRunner {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
#Override
public void run(String... args) throws Exception {
Process process = Runtime.getRuntime().exec(String.format("cmd /c dir %s", "C:\\"));
HelperReader streamGobbler =
new HelperReader(process.getInputStream(), System.out::println);
Executors.newSingleThreadExecutor().submit(streamGobbler);
}
}
Run the application and you should see something like following picture in console.
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
public class TestUnZip {
public static void main(String[] args) throws IOException, InterruptedException{
String destFolder="E:\\TestScript";
/*
* Location where the Nodejs Project is Present
*/
System.out.println(destFolder);
String cmdPrompt="cmd";
String path="/c";
String npmUpdate="npm update";
String npm="npm";
String update="update";
File jsFile=new File(destFolder);
List<String> updateCommand=new ArrayList<String>();
updateCommand.add(cmdPrompt);
updateCommand.add(path);
updateCommand.add(npmUpdate);
runExecution(updateCommand,jsFile);
}
public static void runExecution(List<String> command, File navigatePath) throws IOException, InterruptedException{
System.out.println(command);
ProcessBuilder executeProcess=new ProcessBuilder(command);
executeProcess.directory(navigatePath);
Process resultExecution=executeProcess.start();
BufferedReader br=new BufferedReader(new InputStreamReader(resultExecution.getInputStream()));
StringBuffer sb=new StringBuffer();
String line;
while((line=br.readLine())!=null){
sb.append(line+System.getProperty("line.separator"));
}
br.close();
int resultStatust=resultExecution.waitFor();
System.out.println("Result of Execution"+(resultStatust==0?"\tSuccess":"\tFailure"));
}
}
The Above Program works fine, but this program is depend on Windows Machine, I want to run the same program in other Machine as well.
1) NPM is a Command comes as a bundle of NodeJS. (I run NodeJS as a service, I have defined the Environment Variable, so I can run npm update command from any folder)
2) I can't find a work around to run the npm update command without using the "cmd", "/c". If I do I get following error
Exception in thread "main" java.io.IOException: Cannot run program "npm update" (in directory "E:\TestScript"): CreateProcess error=2, The system cannot find the file specified
at java.lang.ProcessBuilder.start(Unknown Source)
3) Do we have option of Running the npm update command as a parameter of Node.exe. If so can anyone provide me the proper work around.
4) Same as I like, I use mocha framework to run the test script and result generates the .xml file.
5) I want mocha command also being invoked using process builder.
The problem is that ProcessBuilder does not respect the PATHEXT variable on Windows.
It's true there is no npm binary on Windows, there's a npm.cmd. My best solution is to check the platform. Something like this:
static boolean isWindows() {
return System.getProperty("os.name").toLowerCase().contains("win");
}
static String npm = isWindows() ? "npm.cmd" : "npm";
static void run() {
Process process = new ProcessBuilder(npm, "update")
.directory(navigatePath)
.start()
}
In Unix or Linux os , the PathBuilder takes the default environment path , so we have to change the environment path and run the npm command through the bash.
import java.io.File;
import java.util.Map;
public class CommandExecutor {
public void exceuteCommand(String commandString,String
directoryToExecuteCommand) {
try {
ProcessBuilder processBuilder = new ProcessBuilder(new String{"bash", "-c",commandString});
Map<String, String> env = processBuilder.environment();
processBuilder.directory(new File(directoryToExecuteCommand));
String envPath="/home/admin123/.nvm/versions/node/v10.15.3/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin";
env.put("PATH",envPath);
processBuilder.start();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
CommandExecutor commandExecutor=new CommandExecutor();
commandExecutor.exceuteCommand("npm install", "/home/admin123/Desktop");
}
}
import java.io.Console;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.Executor;
import com.jacob.com.LibraryLoader;
import autoitx4java.AutoItX;
public class SilentInstallation {
public static void main(String[] args) throws IOException, InterruptedException {
String[] cmd = { "C:\\WINDOWS\\system32\\cmd.exe", "/c", "start" };
try {
Runtime runtime = Runtime.getRuntime();
Process p = runtime.exec(cmd);
}
catch (java.io.IOException exception) {
System.out.println("Caught IOException: " + exception.getMessage());
}
}
}
Here is my code in which I am running command prompt using java. But the problem here I am facing is I can't be able to change the path in command prompt using java code.
Since this code is using in Automation, so is there any command or method in java that can be used to change the path in the command prompt.
I have also used ProcessBuilder to change the directory path.
Any Recommendations.....
This should be enough:
Process p = ...
p.getOutputStream().write("cd d:\\/r/n".getBytes());
I have some symlinks in my build system that point to jars which I need to build if the jars don't exist. i.e. if the symlinks are dangling. Is there an Ant task or workaround to check that?
As to why I can't include a proper Ant dependency to those jars, the reason is that their build process is lengthy, involving on-the-fly Internet downloads from ftp repositories that take too long and is out of my control.
Ok, so in the end I implemented a custom Ant task (code at the end), that can be used from Ant like this:
<file-pronouncer filePath="path/to/file" retProperty="prop-holding-type-of-that-file"/>
It can then be read with:
<echo message="the file-pronouncer task for file 'path/to/file' returned: ${prop-holding-type-of-that-file}"/>
With the following possible outcomes:
[echo] the file-pronouncer task for file 'a' returned: regular-file
[echo] the file-pronouncer task for file 'b' returned: symlink-ok
[echo] the file-pronouncer task for file 'c' returned: symlink-dangling
[echo] the file-pronouncer task for file 'd' returned: not-exists
code for the FilePronouncer custom Ant task
import java.io.IOException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import java.nio.file.Path;
import java.nio.file.Files;
import java.nio.file.FileSystems;
import java.nio.file.LinkOption;
import java.nio.file.attribute.BasicFileAttributes;
import org.apache.tools.ant.BuildException;
public class FilePronouncer extends Task {
private String filePath = null;
private String retProperty = null;
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public String getRetProperty() {
return retProperty;
}
public void setRetProperty(String property) {
this.retProperty = property;
}
public void execute() {
try {
Path path = FileSystems.getDefault().getPath(filePath);
boolean fileExists = Files.exists(path, LinkOption.NOFOLLOW_LINKS);
Boolean isSymlink = null;
Boolean filePointedToExists = null;
if (fileExists) {
BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
isSymlink = attrs.isSymbolicLink();
if (isSymlink)
filePointedToExists = Files.exists(path);
}
Project project = getProject();
String rv = null;
if (!fileExists)
rv = "not-exists";
else {
if (!isSymlink)
rv = "regular-file";
else {
if (filePointedToExists)
rv = "symlink-ok";
else
rv = "symlink-dangling";
}
}
project.setProperty(retProperty, rv);
} catch (IOException e) {
throw new BuildException(e);
}
}
}
I have this java program, which executes a pig script in MapReduce mode. Here is the code:
import java.io.IOException;
import java.util.Properties;
import org.apache.pig.ExecType;
import org.apache.pig.PigServer;
import org.apache.pig.backend.executionengine.ExecException;
public class pigCV {
public static void main(String args[]){
PigServer pigServer;
try {
Properties props = new Properties();
props.setProperty("fs.default.name", "hdfs://hdfs://localhost:8022");
props.setProperty("mapred.job.tracker", "localhost:8021");
pigServer = new PigServer(ExecType.MAPREDUCE, props);
pigServer.registerScript("Desktop/text_v3.pig");
}
catch (ExecException e) { e.printStackTrace(); }
catch (IOException e) { e.printStackTrace(); }
}
}
Via the linux command line, I'm able to pass arguments to the pig script with a command like this:
pig -f "Desktop/text_v3.pig" -param param1=value1 -param2=value2
But with PigServer, I did not find how to do it.
Do you know how to resolve the problem ?
Thank you.
You can use this version of the registerScript method:
public void registerScript(String fileName, Map<String,String> params)
The java docs explanation is the following: "Register a pig script file. The parameters in the file will be substituted with the values in params."