CSI: Nashorn - Shell Scripting in JavaScript, WAT?

I was reading the article in The Register with the heading GNOME project picks JavaScript as sole app dev language, when I remembered that we haven't said much about shell scripting using Nashorn.

This may seem sacrilegious to both JavaScripters and shell scripters, but think about it. The features that make JavaScript good for browser support are similar to what is needed for shell scripting. Plus you have access to all those Java libraries, and JavaFX, wink, wink, nudge, nudge (think visualization.)

There is an option (-scripting) in the Nashorn engine that extends the JavaScript language with features that make JavaScript very useful for writing shell scripts (even shebang scripts.) These features include;
  • function $EXEC("command args", "input"); that executes a command string as a separate process with handling of stdin, stdout $OUT, stderr $ERR and exit code $EXIT,
  • an exec string `command args` syntax for simple execution,
  • edit strings for embedding expressions in a double quote or exec strings, single quote strings are always unedited,
  • here strings, with editing for multi-line strings, <<TAG…TAG for include end of line and <<<TAG…TAG for exclude end of line,
  • environment variable $ENV for access to shell variables,
  • access to command line arguments with $ARG,
  • exit(code) and quit() for terminating the script,
  • and, # style comments
I will submit more scripting examples in the future, but let's start off with the following teaser.

Fingerprinting Source Code 


Often enough, when we are working on Nashorn, we run across some source that is unfamiliar and we would like to discuss the code with the original author. This is sometimes called blaming, but really, it's just about getting up to speed on the code without a lot of pain and suffering.  Nashorn is stored in a Mercurial repository on openjdk.java.net. Mercurial already supports basic change set annotation of source, but sometimes you just want to cut to the chase and get the full details of a specific source line.

The following shell script, suspect, takes a root source file name and a line number, and then displays the change set information associated with the source line.

#!/usr/bin/jjs
# This script hunts down the change set associated with a
# source file and a line number.
#

// Report proper command usage.
function usage() {
    error(<<EOS);
usage: suspect javaFileName lineNumber
    javaFileName - name of file in local mercurial repository
    lineNumber   - file line number
EOS
}

// Report on stderr.
function error(message) {
    java.lang.System.err.print(message);
    exit(1);
}

// Provide meaningful names for arguments.
var fileName   = $ARG[0];
var lineNumber = $ARG[1];

// If arguments are missing, report proper usage.
if (!fileName || !lineNumber) {
    usage();
}

// Add .java if not present.
if (!fileName.endsWith(".java")) {
    fileName += ".java";
}

// Search for matching files and convert the result to an array of paths.
var where = `find . -name ${fileName}`.trim().split("\n");

// If not found
if (where == "") {
    error("File ${fileName} is not in the current repository.\n");
} else if (where.length != 1) {
    error("File ${fileName} found in multiple locations\n${where.join('\n')}\n");
}

// Get the source annotated with change set number.
var annotated = `hg annotate -c ${where}`.split("\n");

// Get the target source line.
var line = annotated[lineNumber];

// Make sure the line exists.
if (!line) {
    error("File ${fileName} does not contain line number ${lineNumber}\n");
}

// Extract the revision number.
var revision = line.substring(0, 12);

// Report the change set information from the revision number.
print(`hg log -r ${revision}`);

If I wanted to find out about the changed set for line 63 of SpillProperty.java,

>> suspect SpillProperty 63
changeset:   2:da1e581c933b
user:        jlaskey
date:        Fri Dec 21 16:36:24 2012 -0400
summary:     8005403: Open-source Nashorn

This is just the beginning.

Comments:

Has this been pushed yet? The #! and # comments work fine, as does $ARG

The backticks do not, I get "expected operand but got error" from your examples.

The exit function is also not available. Nor is $EXEC

Posted by Benji Weber on February 17, 2013 at 05:14 AM PST #

Until Nashorn is integrated into the JDK8 build (soon), you have to go thru a few steps to work with shell scripting. Note: there are a couple bugs filed against shabang that prevent $ARGS and stdin from working correctly, but you can still use shell scripting directly with the jjs command.

I just double checked and this works for me on MacOSX;

cd /Projects/
hg clone http://hg.openjdk.java.net/nashorn/jdk8 jdk8~nashorn
cd jdk8~nashorn
sh ./get_source.sh
sh configure
make all NEWBUILD=true
cd build/macosx-x86_64-normal-server-release/images/j2sdk-bundle/jdk1.8.0.jdk/Contents/Home
setenv JAVA_HOME .
bin/jjs -scripting -- ThisArg
jjs> var a = `ls`;
jjs> print(a);
ASSEMBLY_EXCEPTION
LICENSE
THIRD_PARTY_README
bin
demo
include
jre
lib
man
release
sample
src.zip

jjs> var b = $EXEC("ls");
jjs> print(b);
ASSEMBLY_EXCEPTION
LICENSE
THIRD_PARTY_README
bin
demo
include
jre
lib
man
release
sample
src.zip

jjs> print($ARG[0]);
ThisArg
jjs> exit(0);

Posted by jlaskey on February 18, 2013 at 04:54 AM PST #

That works, thank you.

Posted by Benji Weber on February 19, 2013 at 12:35 AM PST #

What is /usr/bin/jjs and will jrunscript finally be officually supported by the JDK?

I am looking at all kinds of CLI/Shell Frameworks for Java to build a modular comamnd line admin tool. When jrunscript would be supported, and with some default scripts, nashorn would be a good option, I guess.

Posted by Bernd on March 18, 2013 at 07:26 PM PDT #

The jjs command line tool will be part of the jdk8 installation. Nashorn will be available thru the jrunscript tool, both explicitly and as the default for javascript.

Posted by jlaskey on March 19, 2013 at 04:30 AM PDT #

Hi,

I like the sound of this, particularly the 'here strings'. It seems to me that the lack of an easy way to embed strings in either or java and javascript has been the root cause of so much complexity in web frameworks etc over the years.

Will any of these features be available when running nashorn in embedded mode via the javax.scripting API and if so how ?

Posted by john parry on July 27, 2013 at 08:06 AM PDT #

-scripting command line flag has to be used with "jjs" tool to enable "scripting mode" features such as "here strings" etc. When using javax.script API to execute scripts, -scripting option is enabled automatically.

Posted by sundar on July 28, 2013 at 09:14 PM PDT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

Technical discussions and status of the Nashorn JavaScript Project.

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
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
   
       
Today