Skip to content

Commit

Permalink
Allow disabling ENV write-through to the real environment [JRUBY-5934]
Browse files Browse the repository at this point in the history
This adds updateNativeENVEnabled to RubyInstanceConfig with a default of true.
If it is true and jruby.native.enabled is also true, any modifications to
the runtime's ruby ENV will be reflected in the system env via POSIX. Otherwise,
the modifications are not written through.

This setting has not yet been pushed out to the embedding API's (ScriptingContainer
& JRubyEngine), nor has it been documented.
  • Loading branch information
tobias committed Jul 21, 2011
1 parent c1bb372 commit 217f31a
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 10 deletions.
17 changes: 10 additions & 7 deletions src/org/jruby/RubyGlobal.java
Expand Up @@ -73,8 +73,8 @@ public class RubyGlobal {
*/
public static class CaseInsensitiveStringOnlyRubyHash extends StringOnlyRubyHash {

public CaseInsensitiveStringOnlyRubyHash(Ruby runtime, Map valueMap, IRubyObject defaultValue) {
super(runtime, valueMap, defaultValue, true);
public CaseInsensitiveStringOnlyRubyHash(Ruby runtime, Map valueMap, IRubyObject defaultValue, boolean updateRealENV) {
super(runtime, valueMap, defaultValue, updateRealENV);
}

@Override
Expand Down Expand Up @@ -382,11 +382,14 @@ private static void defineGlobalEnvConstants(Ruby runtime) {
environmentVariableMap = new HashMap();
}

CaseInsensitiveStringOnlyRubyHash h1 = new CaseInsensitiveStringOnlyRubyHash(runtime,
environmentVariableMap, runtime.getNil());
h1.getSingletonClass().defineAnnotatedMethods(CaseInsensitiveStringOnlyRubyHash.class);
runtime.defineGlobalConstant("ENV", h1);
runtime.setENV(h1);
CaseInsensitiveStringOnlyRubyHash env = new CaseInsensitiveStringOnlyRubyHash(runtime,
environmentVariableMap,
runtime.getNil(),
RubyInstanceConfig.nativeEnabled &&
runtime.getInstanceConfig().isUpdateNativeENVEnabled() );
env.getSingletonClass().defineAnnotatedMethods(CaseInsensitiveStringOnlyRubyHash.class);
runtime.defineGlobalConstant("ENV", env);
runtime.setENV(env);

// Define System.getProperties() in ENV_JAVA
Map systemProps = environment.getSystemPropertiesMap(runtime);
Expand Down
14 changes: 13 additions & 1 deletion src/org/jruby/RubyInstanceConfig.java
Expand Up @@ -251,7 +251,8 @@ public enum ProfilingMode {
private String threadDumpSignal = null;
private boolean hardExit = false;
private boolean disableGems = false;

private boolean updateNativeENVEnabled = true;

private int safeLevel = 0;

private String jrubyHome;
Expand Down Expand Up @@ -427,6 +428,7 @@ public RubyInstanceConfig(RubyInstanceConfig parentConfig) {
runRubyInProcess = parentConfig.runRubyInProcess;
excludedMethods = parentConfig.excludedMethods;
threadDumpSignal = parentConfig.threadDumpSignal;
updateNativeENVEnabled = parentConfig.updateNativeENVEnabled;

classCache = new ClassCache<Script>(loader, jitMax);

Expand Down Expand Up @@ -1029,6 +1031,16 @@ private String verifyHome(String home) {
return home;
}


public boolean isUpdateNativeENVEnabled() {
return updateNativeENVEnabled;
}

public void setUpdateNativeENVEnabled(boolean updateNativeENVEnabled) {
this.updateNativeENVEnabled = updateNativeENVEnabled;
}


private final class Argument {
public final String originalValue;
public final String dashedValue;
Expand Down
55 changes: 53 additions & 2 deletions test/org/jruby/test/TestRuby.java
Expand Up @@ -35,14 +35,16 @@

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;

import org.jruby.Ruby;
import org.jruby.RubyArray;
import org.jruby.RubyException;
import org.jruby.RubyInstanceConfig;
import org.jruby.RubyIO;
import org.jruby.RubyInstanceConfig;
import org.jruby.RubyString;
import org.jruby.exceptions.RaiseException;
import org.jruby.runtime.Block;
Expand All @@ -55,7 +57,7 @@
* @author Benoit
*/
public class TestRuby extends TestRubyBase {

public TestRuby(String name) {
super(name);
}
Expand All @@ -80,6 +82,55 @@ public void testVarAndMet() throws Exception {
assertEquals("135 20 3", eval("puts $f, \" \", $g, \" \", $h"));
}

public void testNativeENVSetting() throws Exception {
runtime = Ruby.newInstance();
runtime.evalScriptlet("ENV['ham'] = 'biscuit'");
assertEquals("biscuit", runtime.getPosix().getenv("ham"));
}

public void testNativeENVSettingWhenItIsDisabledOnTheRuntime() throws Exception {
RubyInstanceConfig cfg = new RubyInstanceConfig();
cfg.setUpdateNativeENVEnabled(false);
runtime = Ruby.newInstance(cfg);
runtime.evalScriptlet("ENV['biscuit'] = 'gravy'");
assertNull(runtime.getPosix().getenv("biscuit"));
}

public void testNativeENVSettingWhenNativeIsDisabledGlobally() throws Exception {
try {
setNativeEnabled(false);
runtime = Ruby.newInstance();
runtime.evalScriptlet("ENV['gravy'] = 'with sausage'");
assertNull(runtime.getPosix().getenv("gravy"));
} finally {
setNativeEnabled(true);
}
}

public void testNativeENVSettingWhenNativeIsDisabledGloballyButExplicitlyEnabledOnTheRuntime() throws Exception {
try {
setNativeEnabled(false);
RubyInstanceConfig cfg = new RubyInstanceConfig();
cfg.setUpdateNativeENVEnabled(true);
runtime = Ruby.newInstance(cfg);
runtime.evalScriptlet("ENV['sausage'] = 'biscuits'");
assertNull(runtime.getPosix().getenv("sausage"));
} finally {
setNativeEnabled(true);
}
}

private void setNativeEnabled(boolean nativeEnabled) throws Exception {
Field nativeEnabledField = RubyInstanceConfig.class.getDeclaredField("nativeEnabled");
nativeEnabledField.setAccessible(true);

Field modifiers = Field.class.getDeclaredField("modifiers");
modifiers.setAccessible(true);
modifiers.setInt(nativeEnabledField, nativeEnabledField.getModifiers() & ~Modifier.FINAL);

nativeEnabledField.set(RubyInstanceConfig.class, nativeEnabled);
}

public void testPrintErrorWithNilBacktrace() throws Exception {
testPrintErrorWithBacktrace("nil");
}
Expand Down
1 change: 1 addition & 0 deletions test/org/jruby/test/TestRubyInstanceConfig.java
Expand Up @@ -56,6 +56,7 @@ public void testRubyInstanceConfigDefaults() throws Exception {
assertNull(config.getScriptFileName());
assertTrue(config.loadPaths().isEmpty());
assertTrue(config.requiredLibraries().isEmpty());
assertTrue(config.isUpdateNativeENVEnabled());
}

protected final static class NullLoadService extends LoadService {
Expand Down

0 comments on commit 217f31a

Please sign in to comment.