Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Improved startup and auto-detection of Erlang environment + Misc changes #62

Merged
merged 8 commits into from

2 participants

@jetztgradnet

Erlang env is searched for in:

  • -root arg
  • <classpath>
  • $PATH (searching for erl)

Other changes:

  • ERTS and OTP versions are detected automatically.
  • loading Erlang environment from class path now works correctly.
  • calling Kilim weaver in Eclipse build, so weaving is also done from within Eclipse
  • added EObjectIterator
  • bumped version to 0.2

Note
Currently, epmd needs to be started manually, otherwise ej fails. I will add some auto-detection code later, which starts the (internal) epmd, if it is not already running.

@krestenkrab
Owner

I have written a java based epmd, but it seems to sometimes have issues. Would be great to fix that and run it in the same JVM

@krestenkrab krestenkrab merged commit 8449498 into from
@jetztgradnet

What kind of issues? Do you have any error description?

Can you describe the required steps to reproduce this behavior?

@krestenkrab
Owner

Don't remember exactly, I think it had to do with running "real Erlang" with the java epmd.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 26, 2011
  1. @jetztgradnet
Commits on Dec 14, 2011
  1. @jetztgradnet

    ignoring some more files

    jetztgradnet authored
Commits on Apr 12, 2012
  1. @jetztgradnet
Commits on Apr 14, 2012
  1. @jetztgradnet

    Improved startup and auto-detection of Erlang environment.

    jetztgradnet authored
    Erlang env is searched for in:
     -root arg
     <classpath>
     $PATH (searching for 'erl')
    
    ERTS and OTP versions are detected automatically.
    
    Also, loading Erlang environment from class path now works correctly
  2. @jetztgradnet
  3. @jetztgradnet

    ignoring more files

    jetztgradnet authored
  4. @jetztgradnet

    bumped version to 0.2

    jetztgradnet authored
  5. @jetztgradnet

    cleaned up ejc starter

    jetztgradnet authored
This page is out of date. Refresh to see the latest.
View
17 .externalToolBuilders/Kilim Weaver.launch
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.ant.AntBuilderLaunchConfigurationType">
+<booleanAttribute key="org.eclipse.ant.ui.ATTR_TARGETS_UPDATED" value="true"/>
+<booleanAttribute key="org.eclipse.ant.ui.DEFAULT_VM_INSTALL" value="true"/>
+<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
+<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.ant.ui.AntClasspathProvider"/>
+<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="true"/>
+<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.launching.macosx.MacOSXType/JVM Contents (MacOS X Default)"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.eclipse.ant.internal.launching.remote.InternalAntRunner"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="erjang"/>
+<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="true"/>
+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/erjang/weave.xml}"/>
+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,"/>
+<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/erjang}"/>
+<stringAttribute key="process_factory_id" value="org.eclipse.ant.ui.remoteAntProcessFactory"/>
+</launchConfiguration>
View
5 .gitignore
@@ -7,4 +7,7 @@ classes
target
*.beam
src/main/java/erjang/beam/interpreter/Interpreter.java
-src/test/java/erjang/*_TEST.java
+src/test/java/erjang/*_TEST.java
+otp-*.jar
+erjang.log*
+*.launch
View
14 .project
@@ -6,18 +6,18 @@
</projects>
<buildSpec>
<buildCommand>
- <name>org.eclipse.dltk.core.scriptbuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.erjang.kilim_builder.KilimBuilder</name>
+ <name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
+ <name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
+ <triggers>full,incremental,</triggers>
<arguments>
+ <dictionary>
+ <key>LaunchConfigHandle</key>
+ <value>&lt;project&gt;/.externalToolBuilders/Kilim Weaver.launch</value>
+ </dictionary>
</arguments>
</buildCommand>
</buildSpec>
View
2  build.xml
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<project name="erjang" default="all">
- <property name="erjang.version" value="0.1" />
+ <property name="erjang.version" value="0.2" />
<property file="erjang_cfg.properties" />
<path id="erjang.classpath">
View
10 ej
@@ -7,23 +7,15 @@ EJ_CMD=`which "$0"`
while LINK=`readlink "$EJ_CMD"`; do EJ_CMD=$LINK; done
ERJANG_DIR=`dirname "$EJ_CMD"`
-source "$ERJANG_DIR/env_cfg"
-
## -Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,address=8787,server=n,suspend=n \
exec java \
-server \
-Xmx1g -Xss50m \
-XX:PermSize=128m \
- -Derjang.configfile="$PROP_FILE" \
- -Derjang.erts.version="$ERTS_VSN" \
- -Derjang.otp.version="$OTP_VSN" \
- -jar $ERJANG_DIR/erjang-0.1.jar \
+ -jar $ERJANG_DIR/erjang-0.2.jar \
\
-progname ej \
- -home "$HOME" \
- -root "$ERL_ROOT" \
+A 10 \
+S 1 \
- +e "$ERTS_VSN" \
"$@"
View
10 ejc
@@ -7,8 +7,6 @@ EJC_CMD=`which "$0"`
while LINK=`readlink "$EJC_CMD"`; do EJC_CMD=$LINK; done
ERJANG_DIR=`dirname "$EJC_CMD"`
-source "$ERJANG_DIR/env_cfg"
-
###########################################################
# OS X - specific config
if [[ $(uname) == "Darwin" ]]; then
@@ -24,14 +22,8 @@ exec java \
-Xmx2g \
$OSX_DOCK_ICON \
$OSX_DOCK_NAME \
- -Derjang.configfile="$PROP_FILE" \
- -Derjang.erts.version="$ERTS_VSN" \
- -Derjang.otp.version="$OTP_VSN" \
- -cp "$ERJANG_DIR/erjang-0.1.jar" erjang.console.ERLConsole \
+ -cp "$ERJANG_DIR/erjang-0.2.jar" erjang.console.ERLConsole \
\
- -root "$ERL_ROOT" \
+A 10 \
+S 1 \
- +e "$ERTS_VSN" \
- -home "$HOME" \
"$@"
View
6 erjang_cfg.properties
@@ -1,6 +1,6 @@
-erjang.otp.root = /usr/local/lib/erlang
-erjang.erts.version = 5.8.3
-erjang.otp.version = R14B02
+#erjang.otp.root = /usr/local/lib/erlang
+#erjang.erts.version = 5.8.3
+#erjang.otp.version = R14B02
# erjang.debug.port=true
# erjang.debug.inet=true
View
2  erl.cmd
@@ -2,7 +2,7 @@
IF "x%OTPROOT%" == "x" SET OTPROOT="C:/Program Files/erl5.7.5"
-java -cp erjang-0.1.jar ^
+java -cp erjang-0.2.jar ^
erjang.Main ^
-root %OTPROOT% ^
%1 %2 %3 %4 %5 %6 %7 %8 %9
View
2  fib_test.sh
@@ -1,3 +1,3 @@
#!/bin/sh
-java -server -cp erjang-0.1.jar -Derjpath=./src/main/erl/preloaded/ebin:src/main/erl erjang.Erj fib:main
+java -server -cp erjang-0.2.jar -Derjpath=./src/main/erl/preloaded/ebin:src/main/erl erjang.Erj fib:main
View
7 src/main/java/erjang/ECons.java
@@ -21,6 +21,7 @@
import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.io.IOException;
+import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -28,7 +29,7 @@
import erjang.m.ets.EPattern;
import erjang.m.ets.ETermPattern;
-public abstract class ECons extends EObject {
+public abstract class ECons extends EObject implements Iterable<EObject> {
@Override
int cmp_order() {
@@ -241,4 +242,8 @@ public void collectCharList(CharCollector out)
} else tail.collectCharList(out);
}
+ @Override
+ public Iterator<EObject> iterator() {
+ return new EObjectIterator(this);
+ }
}
View
58 src/main/java/erjang/EObjectIterator.java
@@ -0,0 +1,58 @@
+package erjang;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+
+public class EObjectIterator implements Iterator<EObject> {
+ private EObject object = null;
+
+ public EObjectIterator(EObject object) {
+ this.object = object;
+ }
+
+ /* (non-Javadoc)
+ * @see java.util.Iterator#hasNext()
+ */
+ public boolean hasNext() {
+ if (object == null) {
+ return false;
+ }
+ return !object.isNil();
+ }
+
+ /* (non-Javadoc)
+ * @see java.util.Iterator#next()
+ */
+ public EObject next() {
+ if ((object == null)
+ || object.isNil()) {
+ throw new NoSuchElementException();
+ }
+
+ EObject next;
+
+ ECons cons = object.testCons();
+ if ((cons != null)
+ // TODO how to handle EString? return each character? Or return it as single element only?
+ // for now we don't treat EString as collection, but as single element
+ && !(cons instanceof EString)) {
+ next = cons.head();
+ object = cons.tail();
+ }
+ else {
+ // simple object, return it and set next object to null
+ next = object;
+ object = null;
+ }
+ return next;
+ }
+
+ /* (non-Javadoc)
+ * @see java.util.Iterator#remove()
+ */
+ public void remove() {
+ // not supported
+ throw new UnsupportedOperationException();
+ }
+}
View
16 src/main/java/erjang/ERT.java
@@ -626,7 +626,7 @@ public static EFun resolve_fun(EObject mod, EObject fun, int arity) {
final EFun pfun = EModuleManager.resolve(new FunID(pmod, f, arity+1));
- return EFun.get_fun_with_handler(m.toString(), f.toString(), arity, new EFunHandler() {
+ return EFun.get_fun_with_handler(pmod.toString(), f.toString(), arity, new EFunHandler() {
@Override
public EObject invoke(EProc proc, EObject[] args) throws Pausable {
EObject[] real_args = new EObject[args.length+1];
@@ -1141,4 +1141,18 @@ public void write(byte[] b, int off, int len) throws IOException {
}
}
+ /**
+ * contains versions, paths and other information.
+ * use {@link ERT#setRuntimeInfo(RuntimeInfo)} to set this field.
+ */
+ public static RuntimeInfo runtime_info = null;
+
+ public static void setRuntimeInfo(RuntimeInfo info) {
+ // TODO perform synchronization? We usually set this
+ // field only once from Main before ERT is started
+ runtime_info = info;
+ if (runtime_info != null) {
+ System.setProperty("erjang.path", runtime_info.erl_bootstrap_ebindir);
+ }
+ }
}
View
4 src/main/java/erjang/ErjangConfig.java
@@ -36,9 +36,9 @@
static {
String configFileName = System.getProperty("erjang.configfile");
- if (configFileName != null) {
+ if (configFileName != null && configFileName.trim().length() > 0) {
try {
- FileInputStream in = new FileInputStream(configFileName);
+ FileInputStream in = new FileInputStream(configFileName.trim());
try {
Properties properties = new Properties();
properties.load(in);
View
196 src/main/java/erjang/Main.java
@@ -18,171 +18,16 @@
package erjang;
-import java.io.BufferedReader;
import java.io.File;
-import java.io.FileReader;
-import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
import erjang.driver.efile.EFile;
public class Main {
public static final String SYSTEM_ARCHITECTURE = "java";
public static final String DRIVER_VERSION = "1.5";
-
- // determine dynamically from $OTPROOT (and make therefore non-final), if unspecified
- public static String otp_version = (ErjangConfig.hasString("erjang.otp.version") ? ErjangConfig.getString("erjang.otp.version", null) : null);
- static String erts_version = (ErjangConfig.hasString("erjang.erts.version") ? "erts-"+ErjangConfig.getString("erjang.erts.version", null) : null);
- static String erl_rootdir;
- static String erl_bootstrap_ebindir;
-
- public static String erts_version() {
- return erts_version;
- }
-
- static String setup(String cmd_line_root) {
-
- erl_rootdir = cmd_line_root;
- if (cmd_line_root == null)
- erl_rootdir = System.getenv("OTPROOT");
-
- if (erl_rootdir == null) {
- erl_rootdir = guess_erl_root();
- }
-
- File erlangRoot = new File(erl_rootdir);
- if (!erlangRoot.isDirectory()) {
- return null;
- }
-
- if (erts_version == null) {
- // guess erts version from directory $OTPROOT/lib/erts-<version>
- File libDir = new File(erlangRoot, "lib");
- String[] ertsDirs = libDir.list(new FilenameFilter() {
- @Override
- public boolean accept(File dir, String name) {
- return name.startsWith("erts-");
- }
- });
- if (ertsDirs != null) {
- for (int d = 0; d < ertsDirs.length; d++) {
- String dir = ertsDirs[d];
- erts_version = dir;
- }
- }
- }
-
- if (otp_version == null) {
- // guess OTP version from directory $OTPROOT/bin/start.script
- File startScript = new File(erlangRoot, "bin/start.script");
- otp_version = guess_otp_version(startScript);
- }
-
- if (otp_version == null) {
- // guess OTP version from directory $OTPROOT/bin/start.script
- File startScript = new File(erlangRoot, "releases/RELEASES");
- otp_version = guess_otp_version(startScript);
- }
-
- if (otp_version == null) {
- ERT.log.severe("Cannot determine OTP version! Please specify system property 'erjang.otp.version'");
- return null;
- }
-
- erl_bootstrap_ebindir = System.getenv("ERL_BOOTSTRAP_EBIN");
- if (erl_bootstrap_ebindir == null) {
- erl_bootstrap_ebindir = erl_rootdir + File.separator + "lib" + File.separator
- + erts_version + File.separator + "ebin";
- }
-
- return erl_rootdir;
- }
-
- private static String guess_otp_version(File file) {
- if ((file == null) || !file.exists() || !file.canRead()) {
- return null;
- }
-
- BufferedReader reader = null;
- try {
- Pattern pattern = Pattern.compile(".*\"(.*OTP[\\s]+APN.*)\",\"(R\\w+)\".*");
- reader = new BufferedReader(new FileReader(file));
- String line;
- while ((line = reader.readLine()) != null) {
- Matcher match = pattern.matcher(line);
- if (!match.matches()) {
- continue;
- }
- String otpVersion = match.group(2);
- if ((otpVersion != null)
- && (otpVersion.length() > 0)) {
- return otpVersion;
- }
- }
-
- }
- catch (Throwable t) {
- // ignore
- }
- finally {
- // close reader
- if (reader != null) {
- try {
- reader.close();
- }
- catch (Throwable t) {
- // ignore
- }
- }
- }
-
- return null;
- }
- private static String guess_erl_root() {
-
- if (Main.class.getClassLoader().getResource("bin/start.boot") != null) {
- return EFile.RESOURCE_PREFIX.substring(0, EFile.RESOURCE_PREFIX.length()-1);
- }
-
- // this logic works on Unixes ... what about windows?
- String path = System.getenv("PATH");
- List<String> paths = new ArrayList<String>();
- paths.addAll(Arrays.asList(path.split(File.pathSeparator)));
- // also check canonical locations /usr/local/lib/erlang and
- // /opt/local/lib/erlang
- paths.add("/usr/local/lib/erlang/bin");
- paths.add("/opt/local/lib/erlang/bin");
- for (String elem : paths) {
- File dir = new File(elem);
- // TODO check for some other file, which might not be s
- // symbolic link in a generic bin dir such as /usr/local/bin
- File erl = new File(dir, "erl");
- if (erl.exists()) {
-
- if (dir.getParent() == null)
- continue;
-
- File lib = new File (dir.getParent(), "lib");
- File root = new File(lib, "erlang");
-
- if (root.exists()) {
- return root.getAbsolutePath();
- }
-
- }
- }
-
- ERT.log.severe("Cannot find OTPROOT directory\n"
- + "Pass -root <dir>, or set environment variable.");
-
- return null;
- }
/**
* @param args
@@ -197,6 +42,8 @@ public static void main(String[] args) throws Exception {
ArrayList<String> ra = new ArrayList<String>();
String cmd_line_root = null;
+ String otp_version = (ErjangConfig.hasString("erjang.otp.version") ? ErjangConfig.getString("erjang.otp.version", null) : null);
+ String erts_version = (ErjangConfig.hasString("erjang.erts.version") ? "erts-"+ErjangConfig.getString("erjang.erts.version", null) : null);
for (int i = 0; i < args.length; i++) {
if ("-root".equals(args[i]) && i < args.length) {
cmd_line_root = args[i+1];
@@ -207,13 +54,22 @@ public static void main(String[] args) throws Exception {
}
}
- String root = setup(cmd_line_root);
-
- if (cmd_line_root == null) {
- ra.add("-root");
- ra.add(root);
+ RuntimeInfo runtimeInfo = RuntimeInfo.setup(erts_version, otp_version, cmd_line_root);
+ try {
+ // verify we have a working configuration
+ runtimeInfo.verify();
+ }
+ catch (RuntimeException e) {
+ String reason = e.getMessage();
+ ERT.log.severe(reason);
+ System.err.println(reason);
+ return;
}
+ String root = runtimeInfo.erl_rootdir;
+ ra.add("-root");
+ ra.add(root);
+
arg_loop:
for (int i = 0; i < args.length; i++) {
String arg = args[i];
@@ -225,6 +81,12 @@ public static void main(String[] args) throws Exception {
break;
}
+ if ("-root".equals(args[i]) && i < args.length) {
+ // skip "-root <dir>" arg, was set above
+ i++;
+ continue;
+ }
+
if (arg.startsWith("+")) {
switch (arg.charAt(1)) {
case 'a':
@@ -253,14 +115,18 @@ public static void main(String[] args) throws Exception {
ra.add(arg);
}
- System.setProperty("erjang.path", erl_bootstrap_ebindir);
+ if (!ra.contains("-home")) {
+ ra.add("-home");
+ ra.add(System.getProperty("user.home"));
+ }
+
+ ERT.setRuntimeInfo(runtimeInfo);
- if (!(new File(erl_bootstrap_ebindir)).exists() && !erl_bootstrap_ebindir.startsWith(EFile.RESOURCE_PREFIX)) {
- ERT.log.severe("No bootstrap classes at: "+erl_bootstrap_ebindir);
- throw new IllegalArgumentException("No bootstrap classes at: "+erl_bootstrap_ebindir);
+ if (!(new File(runtimeInfo.erl_bootstrap_ebindir)).exists() && !runtimeInfo.erl_bootstrap_ebindir.startsWith(EFile.RESOURCE_PREFIX)) {
+ ERT.log.severe("No bootstrap classes at: "+runtimeInfo.erl_bootstrap_ebindir);
+ throw new IllegalArgumentException("No bootstrap classes at: "+runtimeInfo.erl_bootstrap_ebindir);
}
OTPMain.main(ra.toArray(new String[ra.size()]));
}
-
}
View
60 src/main/java/erjang/OTPMain.java
@@ -21,6 +21,7 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
@@ -50,31 +51,33 @@
new erjang.driver.js.EJSDriver()
};
- public static void load_modules_and_drivers() throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException {
-
- if (Main.erl_bootstrap_ebindir.startsWith(EFile.RESOURCE_PREFIX)) {
-
- for (String m : MODULES) {
- String beam_path = Main.erl_bootstrap_ebindir + "/" + m + ".beam";
- EBinary bin = ClassPathResource.read_file(beam_path);
- if (bin == null) {
- throw new FileNotFoundException(beam_path);
+ public static void load_modules_and_drivers(List<String> modules, List<EDriver> drivers) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException {
+
+ if (modules != null) {
+ String erl_bootstrap_ebindir = ERT.runtime_info.erl_bootstrap_ebindir;
+ if (ClassPathResource.isResource(erl_bootstrap_ebindir)) {
+
+ for (String m : modules) {
+ String beam_path = erl_bootstrap_ebindir + "/" + m + ".beam";
+ EBinary bin = ClassPathResource.read_file(beam_path);
+ if (bin == null) {
+ throw new FileNotFoundException(beam_path);
+ }
+ EModuleLoader.load_module(m, bin);
}
- EModuleLoader.load_module(m, bin);
- }
-
- } else {
- for (String m : MODULES) {
- ERT.load_module(EAtom.intern(m));
- }
+
+ } else {
+ for (String m : modules) {
+ ERT.load_module(EAtom.intern(m));
+ }
+ }
}
- for (EDriver d : DRIVERS) {
- erjang.driver.Drivers.register(d);
- }
- for (EDriver d : extra_drivers) {
- erjang.driver.Drivers.register(d);
- }
+ if (drivers != null) {
+ for (EDriver d : drivers) {
+ erjang.driver.Drivers.register(d);
+ }
+ }
}
public static void start_otp_ring0(ESeq argv) {
@@ -111,6 +114,14 @@ protected static ESeq process_args(String[] args) {
return argv;
}
+ /**
+ * {@link ERT#setRuntimeInfo(RuntimeInfo)} should have been called, before calling this method
+ * @param args
+ * @throws ClassNotFoundException
+ * @throws InstantiationException
+ * @throws IllegalAccessException
+ * @throws IOException
+ */
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException {
ESeq argv = process_args(args);
@@ -119,10 +130,11 @@ public static void main(String[] args) throws ClassNotFoundException, Instantiat
// Logger.getLogger("erjang").setLevel(Level.FINE);
// Logger.getLogger("kilim.Task").setLevel(Level.FINEST);
- load_modules_and_drivers();
+ load_modules_and_drivers(Arrays.asList(MODULES), Arrays.asList(DRIVERS));
+ load_modules_and_drivers(null, extra_drivers);
start_otp_ring0(argv);
- System.out.println("done.");
+ ERT.getOutputStream().println("done.");
}
static List<EDriver> extra_drivers = new ArrayList<EDriver>();
View
330 src/main/java/erjang/RuntimeInfo.java
@@ -0,0 +1,330 @@
+/**
+ * This file is part of Erjang - A JVM-based Erlang VM
+ *
+ * Copyright (c) 2010 by Wolfgang Schell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+package erjang;
+
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FilenameFilter;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import erjang.driver.efile.ClassPathResource;
+import erjang.driver.efile.EFile;
+
+/**
+ * Holder of runtime information such as Erlang and OTP version,
+ * root path, etc.
+ *
+ * @author jetztgradnet
+ */
+public class RuntimeInfo {
+ public final String erts_version;
+ public final String otp_version;
+ public final String erl_rootdir;
+ public final String erl_bootstrap_ebindir;
+
+ /**
+ * the new unicode driver interface is used since OTP version R14B01.
+ *
+ * @see http://www.erlang.org/doc/apps/stdlib/unicode_usage.html#id60205
+ */
+ public final boolean unicodeDriverInterface;
+
+ public RuntimeInfo(String erts_version, String otp_version, String erl_rootdir, String erl_bootstrap_ebindir) {
+ this.erts_version = erts_version;
+ this.otp_version = otp_version;
+ this.erl_rootdir = erl_rootdir;
+ this.erl_bootstrap_ebindir = erl_bootstrap_ebindir;
+
+ if (otp_version != null) {
+ unicodeDriverInterface = ("R14B".compareTo(otp_version) < 0);
+ }
+ else {
+ unicodeDriverInterface = false;
+ }
+ }
+
+ public void verify() throws RuntimeException {
+ if (isNullOrEmpty(erl_rootdir)) {
+ throw new RuntimeException("Erlang runtime not found, please specify root directory using parameter '-root <OTP_ROOT>'");
+ }
+
+ if (isNullOrEmpty(erts_version)) {
+ throw new RuntimeException("Cannot determine ERTS version! Please specify system property 'erjang.erts.version'");
+ }
+
+ if (isNullOrEmpty(otp_version)) {
+ throw new RuntimeException("Cannot determine OTP version! Please specify system property 'erjang.otp.version'");
+ }
+ }
+
+ public boolean isClassPathInstallation() {
+ return isClassPathInstallation(erl_rootdir);
+ }
+
+ public static boolean isClassPathInstallation(String erl_rootdir) {
+ return ClassPathResource.isResource(erl_rootdir);
+ }
+
+ protected static final String ERLANG_RELEASESTARTFILE = "releases/start_erl.data";
+ protected static final String ERLANG_RELEASEFILE = "releases/RELEASES";
+ protected static final String ERLANG_STARTSCRIPT = "bin/start.script";
+ protected static final String ERLANG_BOOTFILE = "bin/start.boot";
+ protected static final String ERLANG_STARTSCRIPT_REGEX = ".*\".*OTP[\\s]+APN.*\",\"(R\\w+)\".*";
+ protected static final String ERLANG_RELEASEFILE_REGEX = ".*\".*OTP[\\s]+APN.*\",\"(R\\w+)\",\"([0-9]\\.[0-9]\\.[0-9])\".*";
+ protected static final String ERLANG_RELEASESTARTFILE_REGEX = "(\\S+)\\s+(\\S+)";
+
+ // determine dynamically from $OTPROOT (and make therefore non-final), if unspecified
+
+ public static RuntimeInfo setup(String erts_version, String otp_version, String erl_rootdir) {
+ if (isNullOrEmpty(erl_rootdir)) {
+ erl_rootdir = guess_erl_root();
+ }
+ if (!isNullOrEmpty(erl_rootdir)) {
+ if (erl_rootdir.endsWith("/") || erl_rootdir.endsWith("\\")) {
+ erl_rootdir = erl_rootdir.substring(0, erl_rootdir.length() - 1);
+ }
+ }
+
+ if (isNullOrEmpty(erts_version)) {
+ erts_version = guess_erts_version(erl_rootdir);
+ }
+
+ if (isNullOrEmpty(otp_version)) {
+ otp_version = guess_otp_version(erl_rootdir);
+ }
+
+ String erl_bootstrap_ebindir = System.getenv("ERL_BOOTSTRAP_EBIN");
+ if (isNullOrEmpty(erl_bootstrap_ebindir)) {
+ erl_bootstrap_ebindir = erl_rootdir;
+ if (!erl_bootstrap_ebindir.endsWith("/") && !erl_bootstrap_ebindir.endsWith("\\")) {
+ erl_bootstrap_ebindir += File.separator;
+ }
+ erl_bootstrap_ebindir += "lib" + File.separator + "erts-" + erts_version + File.separator + "ebin";
+ }
+
+ return new RuntimeInfo(erts_version, otp_version, erl_rootdir, erl_bootstrap_ebindir);
+ }
+
+ public static String guess_otp_version(String erl_rootdir) {
+ // guess OTP version from directory $OTPROOT/releases/RELEASES
+ String otp_version = guess_version(ERLANG_RELEASESTARTFILE_REGEX, 2, erl_rootdir, ERLANG_RELEASESTARTFILE);
+ if (isNullOrEmpty(otp_version)) {
+ otp_version = guess_version(ERLANG_RELEASEFILE_REGEX, 1, erl_rootdir, ERLANG_RELEASEFILE);
+ }
+ if (isNullOrEmpty(otp_version)) {
+ // fallback: guess OTP version from directory $OTPROOT/bin/start.script
+ otp_version = guess_version(ERLANG_STARTSCRIPT_REGEX, 1, erl_rootdir, ERLANG_STARTSCRIPT);
+ }
+
+ return otp_version;
+ }
+
+ public static String guess_erts_version(String erl_rootdir) {
+ // guess ERTS version from directory $OTPROOT/releases/RELEASES
+ String erts_version = guess_version(ERLANG_RELEASESTARTFILE_REGEX, 1, erl_rootdir, ERLANG_RELEASESTARTFILE);
+ if (isNullOrEmpty(erts_version)) {
+ erts_version = guess_version(ERLANG_RELEASEFILE_REGEX, 2, erl_rootdir, ERLANG_RELEASEFILE);
+ }
+ if (isNullOrEmpty(erts_version)) {
+ // fallback: guess ERTS version from erts directory
+ File erlangRoot = new File(erl_rootdir);
+ if (erlangRoot.isDirectory()) {
+ // guess erts version from directory $OTPROOT/lib/erts-<version>
+ File libDir = new File(erlangRoot, "lib");
+ String[] ertsDirs = libDir.list(new FilenameFilter() {
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.startsWith("erts-");
+ }
+ });
+ if (ertsDirs != null) {
+ for (int d = 0; d < ertsDirs.length; d++) {
+ String dir = ertsDirs[d];
+ erts_version = dir;
+ }
+ }
+ }
+ }
+ return erts_version;
+ }
+
+ protected static String guess_version(String regex, int group, String erl_rootdir, String fileName) {
+ if (isNullOrEmpty(erl_rootdir) || RuntimeInfo.isClassPathInstallation(erl_rootdir)) {
+ return guess_version_from_resource(regex, group, fileName);
+ }
+ File erlangRoot = new File(erl_rootdir);
+ if (erlangRoot.isDirectory()) {
+ return guess_version_from_file(regex, group, new File(erlangRoot, fileName));
+ }
+ else {
+ return guess_version_from_resource(regex, group, fileName);
+ }
+ }
+
+ protected static String guess_version_from_resource(String regex, int group, String fileName) {
+ InputStream input = null;
+
+ try {
+ input = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
+ return guess_version_from_reader(regex, group, new InputStreamReader(input));
+ }
+ catch (Throwable t) {
+ // ignore
+ }
+ finally {
+ // close reader
+ closeQuietly(input);
+ }
+
+ return null;
+ }
+
+ protected static String guess_version_from_file(String regex, int group, File file) {
+ if ((file == null) || !file.exists() || !file.canRead()) {
+ return null;
+ }
+
+ FileReader reader = null;
+ try {
+ reader = new FileReader(file);
+ return guess_version_from_reader(regex, group, reader);
+ }
+ catch (Throwable t) {
+ // ignore
+ }
+ finally {
+ // close reader
+ closeQuietly(reader);
+ }
+
+ return null;
+ }
+
+ protected static String guess_version_from_reader(String regex, int group, Reader input) {
+ BufferedReader reader = null;
+ try {
+ Pattern pattern = Pattern.compile(regex);
+ reader = new BufferedReader(input);
+ String line;
+ while ((line = reader.readLine()) != null) {
+ Matcher match = pattern.matcher(line);
+ if (!match.matches()) {
+ continue;
+ }
+ String versionString = match.group(group);
+ if ((versionString != null)
+ && (versionString.length() > 0)) {
+ return versionString.trim();
+ }
+ }
+ }
+ catch (Throwable t) {
+ // ignore
+ }
+ finally {
+ // close reader
+ closeQuietly(reader);
+ }
+
+ return null;
+ }
+
+ protected static boolean isNullOrEmpty(String text) {
+ if (text == null || text.trim().length() == 0) {
+ return true;
+ }
+ return false;
+ }
+
+ public static String guess_erl_root() {
+
+ String erl_rootdir = System.getenv("OTPROOT");
+
+ if (isNullOrEmpty(erl_rootdir)) {
+ // check whether we have Erlang/OTP on the classpath
+ if (Thread.currentThread().getContextClassLoader().getResource(ERLANG_BOOTFILE) != null) {
+ erl_rootdir = EFile.RESOURCE_PREFIX;
+ }
+ }
+
+ if (isNullOrEmpty(erl_rootdir)) {
+ // discover Erlang from $PATH
+ // this logic works on Unixes ... what about windows?
+ String path = System.getenv("PATH");
+ List<String> paths = new ArrayList<String>();
+ paths.addAll(Arrays.asList(path.split(File.pathSeparator)));
+ // also check canonical locations /usr/local/lib/erlang and
+ // /opt/local/lib/erlang
+ paths.add("/usr/local/lib/erlang/bin");
+ paths.add("/opt/local/lib/erlang/bin");
+ for (String elem : paths) {
+ File dir = new File(elem);
+ // TODO check for some other file, which might not be a
+ // symbolic link in a generic bin dir such as /usr/local/bin
+ File erl = new File(dir, "erl");
+ if (erl.exists()) {
+ File baseDir = dir.getParentFile();
+ if (baseDir == null)
+ continue;
+
+ // check for <basedir>/releases
+ File releases = new File(baseDir, "releases");
+ if (releases.isDirectory()) {
+ erl_rootdir = baseDir.getAbsolutePath();
+ break;
+ }
+
+
+ // check for <basedir>/lib/erlang
+ // (Unix-style installation with Erlang bin living next to lib/erlang)
+ File lib = new File (baseDir, "lib");
+ File root = new File(lib, "erlang");
+
+ if (root.exists()) {
+ erl_rootdir = root.getAbsolutePath();
+ break;
+ }
+ }
+ }
+ }
+
+ return erl_rootdir;
+ }
+
+ protected static void closeQuietly(Closeable stream) {
+ if (stream != null) {
+ try {
+ stream.close();
+ }
+ catch (Throwable t) {
+ // ignore
+ }
+ }
+ }
+
+}
View
29 src/main/java/erjang/driver/efile/ClassPathResource.java
@@ -19,15 +19,34 @@
import erjang.driver.IO;
public class ClassPathResource {
+ public static boolean isResource(String fileName) {
+ return fileName.startsWith(EFile.RESOURCE_PREFIX);
+ }
+ public static String getResourceName(String fileName) {
+ if (!isResource(fileName))
+ return fileName;
+
+ fileName = fileName.substring(EFile.RESOURCE_PREFIX.length());
+ if (fileName.startsWith(File.separator) || fileName.startsWith("/")) {
+ fileName = fileName.substring(1);
+ }
+
+ return fileName;
+ }
public static EBinary read_file(String name) {
if (!name.startsWith(EFile.RESOURCE_PREFIX))
return null;
-
+
+ String fileName = getResourceName(name);
InputStream resource = ClassPathResource.class.getClassLoader()
- .getResourceAsStream(
- name.substring(EFile.RESOURCE_PREFIX.length()));
+ .getResourceAsStream(fileName);
+ if (resource == null) {
+ // fallback: check context class loader
+ resource = Thread.currentThread().getContextClassLoader()
+ .getResourceAsStream(fileName);
+ }
if (resource == null) {
return null;
@@ -196,8 +215,8 @@ private static void put_time(ByteBuffer res, long time) {
}
static ZipEntry get_entry(String path) throws IOException {
- Enumeration<URL> out = ClassPathResource.class.getClassLoader()
- .getResources(path.substring(EFile.RESOURCE_PREFIX.length()));
+ String fileName = getResourceName(path);
+ Enumeration<URL> out = ClassPathResource.class.getClassLoader().getResources(fileName);
while (out.hasMoreElements()) {
URL u = out.nextElement();
View
14 src/main/java/erjang/driver/efile/EFile.java
@@ -795,8 +795,7 @@ public void ready() throws Pausable {
return;
}
- if (name.startsWith(RESOURCE_PREFIX)) {
-
+ if (ClassPathResource.isResource(name)) {
EBinary data = ClassPathResource.read_file(name);
if (data == null) {
reply_posix_error(Posix.ENOENT);
@@ -1516,7 +1515,7 @@ public void ready() throws Pausable {
final String file_name = IO.strcpy(buf);
final File file = ERT.newFile(file_name);
- if (file_name.startsWith(RESOURCE_PREFIX)) {
+ if (ClassPathResource.isResource(file_name)) {
ClassPathResource.fstat(this, file_name);
return;
}
@@ -1961,13 +1960,6 @@ void reply_list_directory(String[] files) throws Pausable {
}
/**
- * the new unicode driver interface is used since OTP version R14B01.
- *
- * @see http://www.erlang.org/doc/apps/stdlib/unicode_usage.html#id60205
- */
- static boolean unicodeDriverInterface = ("R14B".compareTo(erjang.Main.otp_version == null ? "" : erjang.Main.otp_version) < 0);
-
- /**
* Determine whether to use the new unicode driver interface
* from R14B01.
*
@@ -1978,6 +1970,6 @@ void reply_list_directory(String[] files) throws Pausable {
* @see http://www.erlang.org/doc/apps/stdlib/unicode_usage.html#id60205
*/
private static boolean isUnicodeDriverInterface() {
- return unicodeDriverInterface;
+ return ERT.runtime_info.unicodeDriverInterface;
}
}
View
23 src/main/java/erjang/m/erlang/ErlProc.java
@@ -34,7 +34,6 @@
import erjang.ECons;
import erjang.EFun;
import erjang.EHandle;
-import erjang.EInternalPID;
import erjang.EModuleManager;
import erjang.EObject;
import erjang.EPID;
@@ -57,7 +56,6 @@
import erjang.Import;
import erjang.Main;
import erjang.NotImplemented;
-import erjang.OTPMain;
/**
*
@@ -300,7 +298,7 @@ public static EObject halt(EProc proc, EObject value) {
}
ERT.shutdown();
- throw new erjang.ErlangHalt();
+ throw new ErlangHalt();
}
@BIF
@@ -412,10 +410,10 @@ static public EObject demonitor(EProc self, EObject ref) throws Pausable {
*/
@BIF
static public EObject demonitor(EProc self, EObject ref, EObject options) throws Pausable {
- return demonitor((ETask)self, ref, options);
+ return demonitor((ETask<?>)self, ref, options);
}
- static public EObject demonitor(ETask self, EObject ref, EObject options) throws Pausable {
+ static public EObject demonitor(ETask<?> self, EObject ref, EObject options) throws Pausable {
ERef r = ref.testReference();
ESeq o = options.testSeq();
@@ -582,7 +580,6 @@ static EObject system_info(EProc proc, EObject type) {
return ERT.TRUE;
} else if (type == am_thread_pool_size) {
-
// TODO: hook up to thread pool
return new ESmall(ERT.threadPoolSize());
@@ -598,12 +595,16 @@ static EObject system_info(EProc proc, EObject type) {
return ERT.TRUE;
} else if (type == am_version) {
- return EString.fromString( erjang.Main.erts_version().substring("erts-".length()) );
+ String erts_version = ERT.runtime_info.erts_version;
+ // remove prefix
+ String prefix = "erts-";
+ if (erts_version.startsWith(prefix)) {
+ erts_version = erts_version.substring(prefix.length());
+ }
+ return EString.fromString(erts_version);
} else if (type == am_otp_release) {
- // TODO: be smarter somehow
- return new EString(Main.otp_version);
-
+ return new EString(ERT.runtime_info.otp_version);
} else if (type == am_logical_processors) {
// TODO: be smarter somehow
return ERT.box(Runtime.getRuntime().availableProcessors());
@@ -631,7 +632,7 @@ static EObject system_info(EProc proc, EObject type) {
return am_undefined;
} else if (type == am_system_version) {
- return new EString("Erjang ["+ erjang.Main.erts_version()+"]");
+ return new EString("Erjang ["+ ERT.runtime_info.erts_version+"]");
} else if ((tup=ETuple2.cast(type)) != null) {
View
190 src/test/java/erjang/EObjectIteratorTest.java
@@ -0,0 +1,190 @@
+package erjang;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import junit.framework.TestCase;
+
+public class EObjectIteratorTest extends TestCase {
+ public void testNil() throws Exception {
+ Iterator<EObject> it = new EObjectIterator(ERT.NIL);
+ assertNotNull(it);
+ assertFalse(it.hasNext());
+ }
+
+ public void testNull() throws Exception {
+ Iterator<EObject> it = new EObjectIterator(null);
+ assertNotNull(it);
+ assertFalse(it.hasNext());
+ }
+
+ public void testEString() throws Exception {
+ EString message = EString.fromString("Hello, World!");
+ Iterator<EObject> it = new EObjectIterator(message);
+ assertNotNull(it);
+ assertTrue(it.hasNext());
+ EObject o = it.next();
+ assertNotNull(o);
+ assertEquals(message, o);
+ assertFalse(it.hasNext());
+ try {
+ it.next();
+ fail("no more elements, iterator should throw exception");
+ }
+ catch (NoSuchElementException t) {
+ // expected
+ }
+ }
+
+ public void testEInt() throws Exception {
+ EInteger num = ESmall.make(42);
+ Iterator<EObject> it = new EObjectIterator(num);
+ assertNotNull(it);
+ assertTrue(it.hasNext());
+ EObject o = it.next();
+ assertNotNull(o);
+ assertEquals(num, o);
+ assertFalse(it.hasNext());
+ try {
+ it.next();
+ fail("no more elements, iterator should throw exception");
+ }
+ catch (NoSuchElementException t) {
+ // expected
+ }
+ }
+
+ public void testSeqWithSingleNil() throws Exception {
+ ESeq seq = ESeq.fromArray(new EObject[] {
+ ERT.NIL
+ });
+ assertEquals(1, seq.length());
+ Iterator<EObject> it = seq.iterator();
+ assertNotNull(it);
+ assertTrue(it.hasNext());
+ EObject o = it.next();
+ assertNotNull(o);
+ assertTrue(o.isNil());
+ assertEquals(ERT.NIL, o);
+ assertFalse(it.hasNext());
+ try {
+ it.next();
+ fail("no more elements, iterator should throw exception");
+ }
+ catch (NoSuchElementException t) {
+ // expected
+ }
+ }
+
+ public void testSeqWithTwoNils() throws Exception {
+ ESeq seq = ESeq.fromArray(new EObject[] {
+ ERT.NIL,
+ ERT.NIL
+ });
+ assertEquals(2, seq.length());
+ Iterator<EObject> it = seq.iterator();
+ assertNotNull(it);
+ assertTrue(it.hasNext());
+ EObject o = it.next();
+ assertNotNull(o);
+ assertTrue(o.isNil());
+ assertEquals(ERT.NIL, o);
+ assertTrue(it.hasNext());
+ o = it.next();
+ assertNotNull(o);
+ assertTrue(o.isNil());
+ assertEquals(ERT.NIL, o);
+ assertFalse(it.hasNext());
+ try {
+ it.next();
+ fail("no more elements, iterator should throw exception");
+ }
+ catch (NoSuchElementException t) {
+ // expected
+ }
+ }
+
+ public void testSeqWithSingleObject() throws Exception {
+ EObject first = EString.fromString("Hello");
+ ESeq seq = ESeq.fromArray(new EObject[] {
+ first
+ });
+ assertEquals(1, seq.length());
+ Iterator<EObject> it = seq.iterator();
+ assertNotNull(it);
+ assertTrue(it.hasNext());
+ EObject o = it.next();
+ assertNotNull(o);
+ assertEquals(first, o);
+ assertFalse(it.hasNext());
+ try {
+ it.next();
+ fail("no more elements, iterator should throw exception");
+ }
+ catch (NoSuchElementException t) {
+ // expected
+ }
+ }
+
+ public void testSeqWithTwoObjects() throws Exception {
+ EObject first = EString.fromString("Hello");
+ EObject second = EString.fromString("World");
+ ESeq seq = ESeq.fromArray(new EObject[] {
+ first,
+ second
+ });
+ assertEquals(2, seq.length());
+ Iterator<EObject> it = seq.iterator();
+ assertNotNull(it);
+ assertTrue(it.hasNext());
+ EObject o = it.next();
+ assertNotNull(o);
+ assertEquals(first, o);
+ assertTrue(it.hasNext());
+ o = it.next();
+ assertNotNull(o);
+ assertEquals(second, o);
+ assertFalse(it.hasNext());
+ try {
+ it.next();
+ fail("no more elements, iterator should throw exception");
+ }
+ catch (NoSuchElementException t) {
+ // expected
+ }
+ }
+
+ public void testSeqWithThreeObjects() throws Exception {
+ EObject first = EString.fromString("Hello");
+ EObject second = EString.fromString("World");
+ EObject third = ESmall.make(42);
+ ESeq seq = ESeq.fromArray(new EObject[] {
+ first,
+ second,
+ third
+ });
+ assertEquals(3, seq.length());
+ Iterator<EObject> it = seq.iterator();
+ assertNotNull(it);
+ assertTrue(it.hasNext());
+ EObject o = it.next();
+ assertNotNull(o);
+ assertEquals(first, o);
+ assertTrue(it.hasNext());
+ o = it.next();
+ assertNotNull(o);
+ assertEquals(second, o);
+ assertTrue(it.hasNext());
+ o = it.next();
+ assertNotNull(o);
+ assertEquals(third, o);
+ assertFalse(it.hasNext());
+ try {
+ it.next();
+ fail("no more elements, iterator should throw exception");
+ }
+ catch (NoSuchElementException t) {
+ // expected
+ }
+ }
+}
View
40 weave.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+<project name="erjang" default="weave">
+ <path id="erjang.classpath">
+ <pathelement location="target/classes/" />
+ <pathelement location="lib/js.jar" />
+ <pathelement location="lib/kilim-0.6-krab.jar" />
+ <pathelement location="lib/OtpErlang.jar" />
+ <pathelement location="lib/junit.jar" />
+ <pathelement location="lib/clj-ds.jar" />
+ <pathelement location="lib/antlr-3.2.jar" />
+ <pathelement path="${java.class.path}" />
+ </path>
+
+ <target name="weave" depends="">
+ <echo message="Weaving files ===================" />
+ <java classname="kilim.tools.Weaver" fork="yes">
+ <classpath refid="erjang.classpath" />
+ <assertions>
+ <enable />
+ </assertions>
+ <arg value="-d" />
+ <arg value="./target/classes" />
+ <arg line="./target/classes" />
+ </java>
+ </target>
+
+ <target name="incremental-weave" depends="">
+ <echo message="Weaving files ===================" />
+ <java classname="kilim.tools.Weaver" fork="yes">
+ <classpath refid="erjang.classpath" />
+ <assertions>
+ <enable />
+ </assertions>
+ <arg value="-d" />
+ <arg value="./target/classes" />
+ <!--<arg line="${system.files}" />-->
+ <arg line="./target/classes" />
+ </java>
+ </target>
+</project>
Something went wrong with that request. Please try again.