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.