Skip to content

Commit bdd6b1a

Browse files
committed
Add a CLI entry point for SciJava scripts
See #451.
1 parent 10d8be7 commit bdd6b1a

File tree

1 file changed

+169
-0
lines changed

1 file changed

+169
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/*
2+
* #%L
3+
* SciJava Common shared library for SciJava software.
4+
* %%
5+
* Copyright (C) 2009 - 2023 SciJava developers.
6+
* %%
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice,
11+
* this list of conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright notice,
13+
* this list of conditions and the following disclaimer in the documentation
14+
* and/or other materials provided with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26+
* POSSIBILITY OF SUCH DAMAGE.
27+
* #L%
28+
*/
29+
30+
package org.scijava.script;
31+
32+
import java.io.File;
33+
import java.io.FileReader;
34+
import java.io.InputStreamReader;
35+
import java.io.Reader;
36+
import java.util.HashMap;
37+
import java.util.Map;
38+
import java.util.Map.Entry;
39+
40+
import org.scijava.Context;
41+
import org.scijava.log.LogLevel;
42+
import org.scijava.log.LogService;
43+
import org.scijava.module.Module;
44+
45+
/**
46+
* A command-line entry point for running SciJava scripts.
47+
*
48+
* @author Curtis Rueden
49+
*/
50+
public class ScriptCLI {
51+
52+
private static final String USAGE = "" + //
53+
"Usage: " + ScriptCLI.class.getSimpleName() + //
54+
" [-d] [-h] [-l language] [-o] [-r] /path/to/script [script-args]\n" + //
55+
"\n" + //
56+
"Options:\n" + //
57+
" -d, --debug : enable debug-level log output\n" + //
58+
" -h, --help : display this help message\n" + //
59+
" -l, --language : specify language of script to execute\n" + //
60+
" otherwise, inferred from script extension\n" + //
61+
" -o, --print-outputs : print output values\n" + //
62+
" -r, --print-return-value : print return value\n" + //
63+
"\n" + //
64+
"To read from stdin, use a dash (-) symbol for the script path.\n" + //
65+
"\n" + //
66+
"For script-args, give space-separated key=value pairs,\n" + //
67+
"while will be passed in as SciJava script arguments.";
68+
69+
public static void main(String... args) throws Exception {
70+
final Map<String, Object> inputs = new HashMap<>();
71+
File file = null;
72+
String language = null;
73+
boolean printOutputs = false;
74+
boolean printReturnValue = false;
75+
boolean parsingOptions = true;
76+
try (final Context context = new Context()) {
77+
// Parse command-line arguments.
78+
if (args.length == 0) args = new String[] {"-h"};
79+
for (int i = 0; i < args.length; i++) {
80+
if (parsingOptions) {
81+
// Parse options and filename.
82+
if (args[i].equals("-d") || args[i].equals("--debug")) {
83+
final LogService log = context.getService(LogService.class);
84+
if (log != null) log.setLevel(LogLevel.DEBUG);
85+
}
86+
else if (args[i].equals("-h") || args[i].equals("--help")) {
87+
System.err.println(USAGE);
88+
System.exit(1);
89+
}
90+
else if (i < args.length - 1 && //
91+
args[i].equals("-l") || args[i].equals("--language"))
92+
{
93+
language = args[++i];
94+
}
95+
else if (args[i].equals("-o") || args[i].equals("--print-outputs")) {
96+
printOutputs = true;
97+
}
98+
else if (args[i].equals("-r") || args[i].equals("--print-return-value")) {
99+
printReturnValue = true;
100+
}
101+
else if (args[i].equals("-")) {
102+
// read from stdin
103+
parsingOptions = false;
104+
}
105+
else if (i < args.length - 1 && args[i].equals("--")) {
106+
// argument after the -- separator must be the filename.
107+
file = new File(args[++i]);
108+
parsingOptions = false;
109+
}
110+
else if (new File(args[i]).exists()) {
111+
file = new File(args[i]);
112+
parsingOptions = false;
113+
}
114+
else {
115+
System.err.println("Invalid argument: " + args[i]);
116+
System.exit(2);
117+
}
118+
}
119+
else {
120+
// Parse script arguments.
121+
final int equals = args[i].indexOf("=");
122+
if (equals < 0) {
123+
System.err.println("Invalid argument: " + args[i]);
124+
System.exit(3);
125+
}
126+
final String key = args[i].substring(0, equals);
127+
final String val = args[i].substring(equals + 1);
128+
inputs.put(key, val);
129+
}
130+
}
131+
132+
final ScriptService ss = context.getService(ScriptService.class);
133+
if (ss == null) {
134+
System.err.println("Error: No script service available.");
135+
System.exit(4);
136+
}
137+
if (file == null && language == null) {
138+
System.err.println("Error: Must specify language when using stdin.");
139+
System.exit(5);
140+
}
141+
142+
final Module m;
143+
if (language == null) {
144+
m = ss.run(file, true, inputs).get();
145+
}
146+
else {
147+
ScriptLanguage lang = ss.getLanguageByName(language);
148+
if (lang == null) lang = ss.getLanguageByExtension(language);
149+
if (lang == null) {
150+
System.err.println("Error: Unsupported language: " + language);
151+
System.exit(6);
152+
}
153+
final Reader reader = file == null ? //
154+
new InputStreamReader(System.in) : //
155+
new FileReader(file);
156+
m = ss.run("." + language, reader, true, inputs).get();
157+
}
158+
if (printOutputs) {
159+
for (Entry<String, Object> output : m.getOutputs().entrySet()) {
160+
System.out.println(output.getKey() + " = " + output.getValue());
161+
}
162+
}
163+
if (printReturnValue && m instanceof ScriptModule) {
164+
System.out.println(((ScriptModule) m).getReturnValue());
165+
}
166+
}
167+
System.exit(0);
168+
}
169+
}

0 commit comments

Comments
 (0)