Displaying and parsing real-time command-line output in Ruby - ruby

I am writing a command-line Ruby gem for CraftBukkit (of Minecraft fame).
So, CraftBukkit's .jar file functions as any command-line server interface should: it accepts user input and sends it to the server when the admin presses enter, while displaying a live feed of server events.
Executed in the command-line directly, then,
java -Xmx1024M -Xms1024M -jar craftbukkit.jar
functions perfectly. I need to execute that same command within my Ruby gem and accept user input in the same way. I am currently using %x{} like so:
%x{java -Xmx1024M -Xms1024M -jar craftbukkit.jar}
This functions reasonably well, as it displays output as it should and executes commands typed into the command line window. It does not, however, show user input as it is typed.
I need to fix this. What Ruby commands/frameworks can I use to make the java command function perfectly?
If possible, I would also like to be able to parse the output.
I am using Clamp to parse command line arguments, if that matters.

Does
system "java -Xmx1024M -Xms1024M -jar craftbukkit.jar"
do what you wanted? It should at least display the input and output. Or did you want to parse the output from within Ruby?

Related

What is the exact meaning / purpose of the J and R flags in jshell?

From the help information:
-J<flag> Pass <flag> directly to the runtime system.
Use one -J for each runtime flag or flag argument
-R<flag> Pass <flag> to the remote runtime system.
Use one -R for each remote flag or flag argument
I cannot find an explanation in both the tools documentation and jshell user guide.
Also, what is "the remote runtime system" in the context of jshell?
As I understand it, JShell has 3 main 'places' to execute code:
In the current process (see DirectExecutionControl)
In the same JVM as the JShell client (see LocalExecutionControl)
On the remote agent (see JdiDefaultExecutionControl)
Using jshell tool, we have no current process before launch, so we have only two options - use one JVM (locally), or use two JVMs - one for JShell client (locally) and another for the execution engine (possibly remotely).
The interesting thing is, JShell always launch two JVMs by default, as the hard-coded --execution key is "failover:0(jdi:hostname(" + loopback + ")),1(jdi:launch(true)), 2(jdi)" (see JShell class source code).
Closer to the point. I've made a couple of experiments with -verbose option and checked JVM options in runtime with ManagementFactory.getRuntimeMXBean().getInputArguments().
jshell -J-verbose command
Printed -verbose output in the console.
No -verbose option in the input arguments: [-agentlib:jdwp=transport=dt_socket,address=127.0.0.1:63305]
jshell -R-verbose command
No -verbose output in the console.
Printed -verbose option in the input arguments: [-agentlib:jdwp=transport=dt_socket,address=127.0.0.1:63339, -verbose]
jshell --execution="local" -J-verbose command
Printed -verbose output in the console.
Printed -verbose option in the input arguments: [-Dapplication.home=C:\Program Files\Java\jdk-9, -Xms8m, -verbose, -Djdk.module.main=jdk.jshell]
jshell --execution="local" -R-verbose
No -verbose output in the console.
No -verbose option in the input arguments: [-Dapplication.home=C:\Program Files\Java\jdk-9, -Xms8m, -Djdk.module.main=jdk.jshell]
TL;DR
Remote execution (default case, execution over JDI)
-J<flag> passes option to the JShell client JVM
-R<flag> passes option to the execution engine JVM
Local execution (--execution="local")
-J<flag> passes option to the only present JVM
-R<flag> does nothing
I still find the scope of explaining the usage of the flags used in both the attributes for the question to be answered completely, hence putting that in words here.
➜ -J flag is used to provide a runtime argument to the JShell which is similar to the way one provides while performing via an IDE under Run -> Configuration to specify arguments as -Dkey=value.
The usage of the attribute is documented and quite similar to ones illustrated for the flag -C just that the -J flags are instead the java command line options.
For example, using the -XX:+PrintCommandLineFlags would detail out the runtime flags used by the current JVM.
So, the default values of command line flags used by your JShell instance(without setting any additional flag) could be as:-
But let's say you don't want to make use of the CompactStrings of Java9 in your JShell execution you can tell the JVM using the -J flag and -XX:-CompactStrings attribute to do so, as -
jshell -R-XX:+PrintCommandLineFlags -R-XX:-CompactStrings
would list out the following output:
➜ Similar java command line options/flags, when attached with and used to start JShell on a remote JVM, are linked to -R attribute of the JShell during remote execution.
jshell -R-XX:+PrintCommandLineFlags -R-XX:-CompactStrings
Anatoly's answer has got some good amount of research attached to it and I would suggest that to be read to understand about control and execution engine of the JShell for local Vs remote execution.

Command line interaction using Ruby

I have a Rails application and am trying to communicate with a Java program via the CLI.
When I run the Java code using system:
system "java askQuestion"
it prompts for user input and waits for an answer, such as "What is your age?"
I want to pass a value in from a variable, and capture the output.
How can I interact with the CLI and run the command?
I did research but I couldn't find anything or I missed the correct term to search.
Solution: IO.popen
update -->
I found here what exactly I want and share maybe help someone else too , http://ruby.bastardsbook.com/chapters/external-programs/
Kernel#system just executes the command in a subshell, returning the result (true/false) of process start.
To catch the output, use backticks (or %x||).
To interact with a shell, one might use IO#popen, but in your case I would just stick to executing
output = `echo 37 | java askQuestion`
The above will pass the output of echo (37 in this particular case) to the Java process. The response of the Java process will be stored in the output variable.

Getting continuous output from shell script that is run by Applescript in Cocoa

I have a shell script that is using echo to give a continuous output (the progress of an rsync) that I am using AppleScript to run with administrator privileges. Before I was using NSTask to run the shell script, but I couldn't find a way to run it with the privileges that it needed, so now I am using applescript to run it. When it was running via NSTask, I could use an output pipe and waitForDataInbackgroundAndNotify to get the continuous output and put it into a text field, but now that I am using AppleScript, I cannot seem to find a way to accomplish this. The shell script is still using echo, but it seems to get lost in the AppleScript "wrapper." How do I make sure that the AppleScript sees the output from the shell script and passes it on to the application? Remember, this isn't one single output, but continuous output.
Zero is correct. When you use do shell script, you can consider it similar to using backticks in perl. The command will be executed, and the everything sent to STDOUT will be returned as the result.
The only work around would be to have the your command write the output to a temporary file and then use do shell script "foo" without waiting. From there, you can read from the file sequentially using native AppleScript commands. It's clunky, but it'll work in a pinch.

Unable to send terminal commands using Ruby

I need to know how to send terminal commands through Ruby to execute another application. I would like to call the SIKULI script at a certain point within my Watir script to handle some steps that Watir can't.
I am not sure how to do it. I read a few of the articles here at Stack Overflow, but can't get it to work.
These are the steps to execute it manually:
jfleck-mbp:~ joe.fleck$ SIKULI_HOME=/Applications/Sikuli-IDE.app/Contents/Resources/Java
jfleck-mbp:~ joe.fleck$ java -jar $SIKULI_HOME/sikuli-script.jar '/Users/joe.fleck/Desktop/Save_File_Button.sikuli'
These are in a Ruby file I am trying to execute:
require 'rubygems'
system('SIKULI_HOME=/Applications/Sikuli-IDE.app/Contents/Resources/Java')
system ("java -jar $SIKULI_HOME/sikuli-script.jar '/Users/joe.fleck/Desktop/Save_File_Button.sikuli'")
The output I get is:
Unable to access jarfile /sikuli-script.jar
which tells me the first line in my script did not execute which allows the access.
Any suggestions would be appreciated.
I think you're getting a different shell with each system() command.
One easy way to verify, and a more maintainable approach, IMHO, would be put all the commands in a single (bash/zsh/whatever) script and run that with system().
Fix it like this:
ENV['SIKULI_HOME'] = '/Applications/Sikuli-IDE.app/Contents/Resources/Java'
system ("java -jar $SIKULI_HOME/sikuli-script.jar '/Users/joe.fleck/Desktop/Save_File_Button.sikuli'")
The issue is that when you call system, you are invoking a child process. Child processes inherit the environment from the parent processes (in this case your Ruby script). Using system to set an environment variable sets it for that child process only, the next call to system is a new child process with a fresh environment.
The solution shown above sets the environment variable in the parent process, thus it will be set for all child processes.

Calling ruby script from groovy

I have a groovy script and I need to call a ruby script.
I would like to pass arguments to Ruby script and would like to capture the output from Ruby script to use it in Groovy Script. Can somebody suggest how I can do this? I tried Process.execute(). It works for other dos commands but not for cmd /c ruby test.rb.
Since a ruby file isn't a batch file you don't need to use cmd to execute it. You could do
Process.execute("ruby.exe test.rb")
Assuming ruby.exe is on your path. Another option depending on your requirements may be to use JRuby which will allow you to run ruby code on the JVm and integrate nicely with Groovy.

Resources