Skip to content

Commit 7e7d7eb

Browse files
authored
Support Processing libraries (#133)
* *: Support Processing libraries in Processing.R Signed-off-by: Ce Gao <[email protected]> * RLangEditor: Add a TODO comment Signed-off-by: Ce Gao <[email protected]> * Runner: Fix the bug about CLI runner jar Signed-off-by: Ce Gao <[email protected]>
1 parent 4643a9e commit 7e7d7eb

File tree

8 files changed

+302
-56
lines changed

8 files changed

+302
-56
lines changed

src/rprocessing/RLangPApplet.java

+1-4
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,9 @@
88
import java.util.Arrays;
99
import java.util.concurrent.CountDownLatch;
1010

11-
import javax.script.ScriptEngine;
12-
import javax.script.ScriptEngineManager;
1311
import javax.script.ScriptException;
1412

1513
import org.renjin.parser.RParser;
16-
import org.renjin.script.RenjinScriptEngine;
1714
import org.renjin.sexp.Closure;
1815
import org.renjin.sexp.ExpressionVector;
1916
import org.renjin.sexp.FunctionCall;
@@ -310,7 +307,7 @@ private boolean isMixMode() {
310307
Class closureClass = Closure.class;
311308
return isSameClass(this.renjinEngine.get(Constant.SIZE_NAME), closureClass);
312309
}
313-
310+
314311
/**
315312
* Set Environment variables in R top context.
316313
*/

src/rprocessing/RunnableSketch.java

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
package rprocessing;
22

33
import java.io.File;
4+
import java.util.List;
45

56
/**
6-
* // Ignore CheckstyleBear (JavadocParagraph)
7-
* Everything Runner.runSketchBlocking needs to know to be able to run a sketch.
7+
* // Ignore CheckstyleBear (JavadocParagraph) Everything Runner.runSketchBlocking needs to know to
8+
* be able to run a sketch.
89
*
910
*/
1011
public interface RunnableSketch {
@@ -40,10 +41,10 @@ public interface RunnableSketch {
4041
// */
4142
// public abstract List<File> getPathEntries();
4243

43-
// /**
44-
// * @return Directories to search for Processing libraries
45-
// */
46-
// public abstract List<File> getLibraryDirectories();
44+
/**
45+
* @return Directories to search for Processing libraries
46+
*/
47+
public abstract List<File> getLibraryDirectories();
4748

4849
// /**
4950
// * @return How eagerly we should look for libraries

src/rprocessing/Runner.java

+96-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
11
package rprocessing;
22

3+
import java.io.File;
4+
import java.io.FileFilter;
5+
import java.io.FilenameFilter;
6+
import java.util.HashSet;
7+
import java.util.List;
8+
import java.util.Set;
9+
310
import javax.script.ScriptException;
411

512
import org.renjin.eval.EvalException;
613

14+
import processing.core.PApplet;
15+
import processing.core.PConstants;
716
import rprocessing.exception.NotFoundException;
817
import rprocessing.exception.REvalException;
918
import rprocessing.lancher.StandaloneSketch;
19+
import rprocessing.mode.library.LibraryImporter;
1020
import rprocessing.util.Printer;
1121
import rprocessing.util.StreamPrinter;
1222

@@ -21,6 +31,22 @@ public class Runner {
2131

2232
private static final boolean VERBOSE = Boolean.parseBoolean(System.getenv("VERBOSE_RLANG_MODE"));
2333

34+
private static final String ARCH;
35+
36+
static {
37+
log("Getting the architecture.");
38+
final int archBits = Integer.parseInt(System.getProperty("sun.arch.data.model"));
39+
if (PApplet.platform == PConstants.MACOSX) {
40+
ARCH = "macosx" + archBits;
41+
} else if (PApplet.platform == PConstants.WINDOWS) {
42+
ARCH = "macosx" + archBits;
43+
} else if (PApplet.platform == PConstants.LINUX) {
44+
ARCH = "linux" + archBits;
45+
} else {
46+
ARCH = "unknown" + archBits;
47+
}
48+
}
49+
2450
private static void log(final Object... objs) {
2551
if (!VERBOSE) {
2652
return;
@@ -36,14 +62,15 @@ public static void main(final String[] args) throws Exception {
3662
throw new NotFoundException("The path of your R script is needed as an argument.");
3763
}
3864
try {
65+
log("Run the runner in Main.");
3966
sketch = new StandaloneSketch(args);
4067
runSketchBlocking(sketch, new StreamPrinter(System.out), new StreamPrinter(System.err));
4168

4269
// See https://github.com/gaocegege/Processing.R/issues/89
4370
// It can't be reproduced, so comment the statement.
4471
// System.exit(0);
4572
} catch (final Throwable t) {
46-
System.err.println(t);
73+
System.err.println("Runner raises an exception: " + t);
4774
System.exit(-1);
4875
}
4976
}
@@ -66,6 +93,16 @@ public static synchronized void runSketchBlocking(final RunnableSketch sketch,
6693
rp.addPAppletToRContext();
6794
rp.evaluateCoreCode();
6895

96+
final List<File> libDirs = sketch.getLibraryDirectories();
97+
if (libDirs != null) {
98+
LibraryImporter libraryImporter = new LibraryImporter(libDirs, rp.getRenjinEngine());
99+
final Set<String> libs = new HashSet<>();
100+
for (final File dir : libDirs) {
101+
searchForExtraStuff(dir, libs);
102+
}
103+
libraryImporter.loadLibraries(libs);
104+
}
105+
69106
try {
70107
// Run Sketch.
71108
rp.runBlock(args);
@@ -74,4 +111,62 @@ public static synchronized void runSketchBlocking(final RunnableSketch sketch,
74111
throw new REvalException(ee.getMessage());
75112
}
76113
}
114+
115+
/**
116+
* Recursively search the given directory for jar files and directories containing dynamic
117+
* libraries, adding them to the classpath and the library path respectively.
118+
*/
119+
private static void searchForExtraStuff(final File dir, final Set<String> entries) {
120+
if (dir == null) {
121+
throw new IllegalArgumentException("null dir");
122+
}
123+
124+
final String dirName = dir.getName();
125+
if (!dirName.equals(ARCH) && dirName.matches("^(macosx|windows|linux)(32|64)$")) {
126+
log("Ignoring wrong architecture " + dir);
127+
return;
128+
}
129+
130+
log("Searching: ", dir);
131+
132+
final File[] dlls = dir.listFiles(new FilenameFilter() {
133+
@Override
134+
public boolean accept(final File dir, final String name) {
135+
return name.matches("^.+\\.(so|dll|jnilib|dylib)$");
136+
}
137+
});
138+
if (dlls != null && dlls.length > 0) {
139+
entries.add(dir.getAbsolutePath());
140+
} else {
141+
log("No DLLs in ", dir);
142+
}
143+
144+
final File[] jars = dir.listFiles(new FilenameFilter() {
145+
@Override
146+
public boolean accept(final File dir, final String name) {
147+
return name.matches("^.+\\.jar$");
148+
}
149+
});
150+
if (!(jars == null || jars.length == 0)) {
151+
for (final File jar : jars) {
152+
entries.add(jar.getAbsolutePath());
153+
}
154+
} else {
155+
log("No JARs in ", dir);
156+
}
157+
158+
final File[] dirs = dir.listFiles(new FileFilter() {
159+
@Override
160+
public boolean accept(final File f) {
161+
return f.isDirectory() && f.getName().charAt(0) != '.';
162+
}
163+
});
164+
if (!(dirs == null || dirs.length == 0)) {
165+
for (final File d : dirs) {
166+
searchForExtraStuff(d, entries);
167+
}
168+
} else {
169+
log("No dirs in ", dir);
170+
}
171+
}
77172
}

src/rprocessing/applet/BuiltinApplet.java

+10-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package rprocessing.applet;
22

3-
import org.renjin.script.RenjinScriptEngine;
4-
import org.renjin.sexp.StringVector;
5-
63
import javax.script.ScriptEngine;
74
import javax.script.ScriptEngineManager;
85

6+
import org.renjin.script.RenjinScriptEngine;
7+
import org.renjin.sexp.StringVector;
8+
99
import processing.core.PApplet;
1010
import rprocessing.exception.NotFoundException;
1111

@@ -22,6 +22,10 @@ public class BuiltinApplet extends PApplet {
2222
/** Engine to interpret R code */
2323
protected final RenjinScriptEngine renjinEngine;
2424

25+
public RenjinScriptEngine getRenjinEngine() {
26+
return renjinEngine;
27+
}
28+
2529
public BuiltinApplet() throws NotFoundException {
2630
// Create a script engine manager.
2731
ScriptEngineManager manager = new ScriptEngineManager();
@@ -61,7 +65,7 @@ public double getPI() {
6165
@Override
6266
public void focusGained() {
6367
super.focusGained();
64-
this.renjinEngine.put("focused",super.focused);
68+
this.renjinEngine.put("focused", super.focused);
6569
}
6670

6771
/**
@@ -71,7 +75,7 @@ public void focusGained() {
7175
@Override
7276
public void focusLost() {
7377
super.focusLost();
74-
this.renjinEngine.put("focused",super.focused);
78+
this.renjinEngine.put("focused", super.focused);
7579
}
7680

7781
@Override
@@ -84,6 +88,6 @@ protected void wrapMouseVariables() {
8488
this.renjinEngine.put("mouseY", mouseY);
8589
this.renjinEngine.put("pmouseX", pmouseX);
8690
this.renjinEngine.put("pmouseY", pmouseY);
87-
//this.renjinEngine.put("mouseButton", mouseButton);
91+
// this.renjinEngine.put("mouseButton", mouseButton);
8892
}
8993
}

src/rprocessing/lancher/StandaloneSketch.java

+26-38
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public class StandaloneSketch implements RunnableSketch {
2323

2424
private final File sketchPath;
2525
private final String code;
26+
private final List<File> libraryDirs;
2627

2728
// private final List<File> libraryDirs;
2829

@@ -32,7 +33,7 @@ private static void log(final Object... objs) {
3233
return;
3334
}
3435
for (final Object o : objs) {
35-
System.err.print(String.valueOf(o));
36+
System.err.print(StandaloneSketch.class.getSimpleName() + ": " + String.valueOf(o));
3637
}
3738
System.err.println();
3839
}
@@ -54,6 +55,11 @@ public File getMainJarFile() {
5455
return null;
5556
}
5657

58+
@Override
59+
public List<File> getLibraryDirectories() {
60+
return libraryDirs;
61+
}
62+
5763
/**
5864
* Returns the 'root' folder of this instance. Used when running with a wrapper.
5965
*
@@ -96,26 +102,34 @@ public StandaloneSketch(final String[] args) throws Exception {
96102
// Read main code in
97103
this.code = RScriptReader.readText(sketchPath.toPath());
98104

99-
// populate library directories
105+
// TODO: Support library in standalone sketch.
106+
this.libraryDirs = null;
100107
// {
108+
// log("Populate library directories.");
101109
// this.libraryDirs = new ArrayList<>();
102-
// final String BUILD_PROPERTIES = "build.properties";
110+
// final String buildProperties = "build.properties";
103111
// final String propsResource;
104112
// try {
105-
// propsResource = URLDecoder.decode(Runner.class.getResource(BUILD_PROPERTIES)
106-
// .toString(), "UTF-8");
113+
// propsResource =
114+
// URLDecoder.decode(Runner.class.getResource(buildProperties).toString(), "UTF-8");
115+
// log(propsResource);
107116
// } catch (final UnsupportedEncodingException e) {
108117
// throw new RuntimeException("Impossible: " + e);
109118
// }
110119
//
111-
// final Pattern JAR_RESOURCE = Pattern
112-
// .compile("jar:file:(.+?)/processing-py\\.jar!/jycessing/"
113-
// + Pattern.quote(BUILD_PROPERTIES));
114-
// final Pattern FILE_RESOURCE = Pattern.compile("file:(.+?)/bin/jycessing/"
115-
// + Pattern.quote(BUILD_PROPERTIES));
120+
// if (propsResource == null) {
121+
// log("Could not get build.properties from Runner.");
122+
// libraryDirs.add(new File("libraries"));
123+
// return;
124+
// }
125+
//
126+
// final Pattern jarResource = Pattern
127+
// .compile("jar:file:(.+?)/RLangMode\\.jar!/rprocessing/" + Pattern.quote(buildProperties));
128+
// final Pattern fileResource =
129+
// Pattern.compile("file:(.+?)/bin/rprocessing/" + Pattern.quote(buildProperties));
116130
//
117-
// final Matcher jarMatcher = JAR_RESOURCE.matcher(propsResource);
118-
// final Matcher fileMatcher = FILE_RESOURCE.matcher(propsResource);
131+
// final Matcher jarMatcher = jarResource.matcher(propsResource);
132+
// final Matcher fileMatcher = fileResource.matcher(propsResource);
119133
// if (jarMatcher.matches()) {
120134
// log("We're running from a JAR file.");
121135
// libraryDirs.add(new File(jarMatcher.group(1), "libraries"));
@@ -147,16 +161,6 @@ public String[] getPAppletArguments() {
147161
};
148162
}
149163

150-
// @Override
151-
// public List<File> getLibraryDirectories() {
152-
// return libraryDirs;
153-
// }
154-
155-
// @Override
156-
// public LibraryPolicy getLibraryPolicy() {
157-
// return LibraryPolicy.PROMISCUOUS;
158-
// }
159-
160164
@Override
161165
public String getMainCode() {
162166
return code;
@@ -166,20 +170,4 @@ public String getMainCode() {
166170
public boolean shouldRun() {
167171
return true;
168172
}
169-
170-
// @Override
171-
// public List<File> getPathEntries() {
172-
// final List<File> entries = new ArrayList<>();
173-
//
174-
// // Main sketch folder
175-
// entries.add(sketchPath.getParentFile());
176-
//
177-
// for (final File dir : getLibraryDirectories()) {
178-
// // In case the user has added python libraries in their library directories
179-
// entries.add(dir);
180-
// }
181-
//
182-
// return entries;
183-
// }
184-
185173
}

src/rprocessing/mode/RLangEditor.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,9 @@ protected void handleCommentUncomment() {
226226
* @see processing.app.ui.Editor#handleImportLibrary(java.lang.String)
227227
*/
228228
@Override
229-
public void handleImportLibrary(String arg0) {}
229+
public void handleImportLibrary(String libraryName) {
230+
// TODO: Support import specific library.
231+
}
230232

231233
/**
232234
* @see processing.app.ui.Editor#internalCloseRunner()

0 commit comments

Comments
 (0)