Started implementing environment variable methods on windows.

This commit is contained in:
Adam Murdoch
2013-02-07 17:58:13 +11:00
parent ff3abfd4fd
commit 6cab15ece4
8 changed files with 328 additions and 154 deletions

View File

@@ -199,6 +199,7 @@ You can run `$INSTALL_DIR/bin/native-platform-test` to run the test application.
libncurses cannot be loaded. libncurses cannot be loaded.
* Add a method to Terminal that indicates whether the cursor wraps to the next line when a character is written to the * Add a method to Terminal that indicates whether the cursor wraps to the next line when a character is written to the
rightmost character position. rightmost character position.
* Check for null parameters.
### Ideas ### Ideas

View File

@@ -109,13 +109,55 @@ Java_net_rubygrapefruit_platform_internal_jni_PosixProcessFunctions_setWorkingDi
if (dirPath == NULL) { if (dirPath == NULL) {
return; return;
} }
if (!SetCurrentDirectoryW(dirPath)) { BOOL ok = SetCurrentDirectoryW(dirPath);
free(dirPath);
if (!ok) {
mark_failed_with_errno(env, "could not set current directory", result); mark_failed_with_errno(env, "could not set current directory", result);
free(dirPath);
return; return;
} }
}
free(dirPath); JNIEXPORT jstring JNICALL
Java_net_rubygrapefruit_platform_internal_jni_PosixProcessFunctions_getEnvironmentVariable(JNIEnv *env, jclass target, jstring var, jobject result) {
wchar_t* varStr = java_to_wchar(env, var, result);
DWORD len = GetEnvironmentVariableW(varStr, NULL, 0);
if (len == 0) {
if (GetLastError() != ERROR_ENVVAR_NOT_FOUND) {
mark_failed_with_errno(env, "could not determine length of environment variable", result);
}
free(varStr);
return NULL;
}
wchar_t* valueStr = (wchar_t*)malloc(sizeof(wchar_t) * len);
DWORD copied = GetEnvironmentVariableW(varStr, valueStr, len);
if (copied == 0) {
if (len > 1) {
// If the value is empty, then copied will be 0
mark_failed_with_errno(env, "could not get environment variable", result);
}
free(varStr);
free(valueStr);
return NULL;
}
free(varStr);
jstring value = wchar_to_java(env, valueStr, copied, result);
free(valueStr);
return value;
}
JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_PosixProcessFunctions_setEnvironmentVariable(JNIEnv *env, jclass target, jstring var, jstring value, jobject result) {
wchar_t* varStr = java_to_wchar(env, var, result);
wchar_t* valueStr = value == NULL ? NULL : java_to_wchar(env, value, result);
BOOL ok = SetEnvironmentVariableW(varStr, valueStr);
free(varStr);
if (valueStr != NULL) {
free(valueStr);
}
if (!ok && GetLastError() != ERROR_ENVVAR_NOT_FOUND) {
mark_failed_with_errno(env, "could not set environment var", result);
return;
}
} }
/* /*

View File

@@ -23,7 +23,7 @@
extern "C" { extern "C" {
#endif #endif
#define NATIVE_VERSION 12 #define NATIVE_VERSION 13
/* /*
* Marks the given result as failed, using the given error message * Marks the given result as failed, using the given error message

View File

@@ -1,49 +1,68 @@
/* /*
* Copyright 2012 Adam Murdoch * Copyright 2012 Adam Murdoch
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package net.rubygrapefruit.platform; package net.rubygrapefruit.platform;
import java.io.File; import java.io.File;
/** /**
* Functions to query and modify a process' state. * Functions to query and modify a process' state.
*/ */
@ThreadSafe @ThreadSafe
public interface Process extends NativeIntegration { public interface Process extends NativeIntegration {
/** /**
* Returns the process identifier. * Returns the process identifier.
* *
* @throws NativeException On failure. * @throws NativeException On failure.
*/ */
@ThreadSafe @ThreadSafe
int getProcessId() throws NativeException; int getProcessId() throws NativeException;
/** /**
* Returns the process' current working directory. * Returns the process' current working directory.
* *
* @throws NativeException On failure. * @throws NativeException On failure.
*/ */
@ThreadSafe @ThreadSafe
File getWorkingDirectory() throws NativeException; File getWorkingDirectory() throws NativeException;
/** /**
* Sets the process' working directory. * Sets the process' working directory.
* *
* @throws NativeException On failure. * @throws NativeException On failure.
*/ */
@ThreadSafe @ThreadSafe
void setWorkingDirectory(File directory) throws NativeException; void setWorkingDirectory(File directory) throws NativeException;
}
/**
* Get the value of an environment variable.
*
* @return The value or null if no such environment variable.
* @throws NativeException On failure.
*/
@ThreadSafe
String getEnvironmentVariable(String name) throws NativeException;
/**
* Sets the value of an environment variable.
*
* @param value the new value. Use null to remove the environment variable. Note that on some platforms it is not
* possible to remove the environment variable. On such platforms, the value is set to an empty string instead.
* @throws NativeException On failure.
*/
@ThreadSafe
void setEnvironmentVariable(String name, String value) throws NativeException;
}

View File

@@ -1,46 +1,79 @@
/* /*
* Copyright 2012 Adam Murdoch * Copyright 2012 Adam Murdoch
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package net.rubygrapefruit.platform.internal; package net.rubygrapefruit.platform.internal;
import net.rubygrapefruit.platform.*; import net.rubygrapefruit.platform.NativeException;
import net.rubygrapefruit.platform.internal.jni.PosixProcessFunctions; import net.rubygrapefruit.platform.Process;
import net.rubygrapefruit.platform.internal.jni.PosixProcessFunctions;
import java.io.File;
import java.io.File;
public class DefaultProcess implements net.rubygrapefruit.platform.Process {
public int getProcessId() throws NativeException { public class DefaultProcess implements Process {
return PosixProcessFunctions.getPid(); private final Object workingDirectoryLock = new Object();
} private final Object environmentLock = new Object();
public File getWorkingDirectory() throws NativeException { public int getProcessId() throws NativeException {
FunctionResult result = new FunctionResult(); return PosixProcessFunctions.getPid();
String dir = PosixProcessFunctions.getWorkingDirectory(result); }
if (result.isFailed()) {
throw new NativeException(String.format("Could not get process working directory: %s", result.getMessage())); public File getWorkingDirectory() throws NativeException {
} FunctionResult result = new FunctionResult();
return new File(dir); String dir;
} synchronized (workingDirectoryLock) {
dir = PosixProcessFunctions.getWorkingDirectory(result);
public void setWorkingDirectory(File directory) throws NativeException { }
FunctionResult result = new FunctionResult(); if (result.isFailed()) {
PosixProcessFunctions.setWorkingDirectory(directory.getAbsolutePath(), result); throw new NativeException(String.format("Could not get process working directory: %s",
if (result.isFailed()) { result.getMessage()));
throw new NativeException(String.format("Could not set process working directory: %s", result.getMessage())); }
} return new File(dir);
System.setProperty("user.dir", directory.getAbsolutePath()); }
}
} public void setWorkingDirectory(File directory) throws NativeException {
FunctionResult result = new FunctionResult();
synchronized (workingDirectoryLock) {
PosixProcessFunctions.setWorkingDirectory(directory.getAbsolutePath(), result);
System.setProperty("user.dir", directory.getAbsolutePath());
}
if (result.isFailed()) {
throw new NativeException(String.format("Could not set process working directory: %s",
result.getMessage()));
}
}
public String getEnvironmentVariable(String name) throws NativeException {
FunctionResult result = new FunctionResult();
String value;
synchronized (environmentLock) {
value = PosixProcessFunctions.getEnvironmentVariable(name, result);
}
if (result.isFailed()) {
throw new NativeException(String.format("Could not get the value of environment variable '%s': %s", name, result.getMessage()));
}
return value;
}
public void setEnvironmentVariable(String name, String value) throws NativeException {
FunctionResult result = new FunctionResult();
synchronized (environmentLock) {
PosixProcessFunctions.setEnvironmentVariable(name, value, result);
}
if (result.isFailed()) {
throw new NativeException(String.format("Could not set the value of environment variable '%s': %s", name, result.getMessage()));
}
}
}

View File

@@ -1,28 +1,28 @@
/* /*
* Copyright 2012 Adam Murdoch * Copyright 2012 Adam Murdoch
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package net.rubygrapefruit.platform.internal.jni; package net.rubygrapefruit.platform.internal.jni;
import net.rubygrapefruit.platform.internal.FunctionResult; import net.rubygrapefruit.platform.internal.FunctionResult;
import net.rubygrapefruit.platform.internal.MutableSystemInfo; import net.rubygrapefruit.platform.internal.MutableSystemInfo;
public class NativeLibraryFunctions { public class NativeLibraryFunctions {
public static final int VERSION = 12; public static final int VERSION = 13;
public static native int getVersion(); public static native int getVersion();
public static native void getSystemInfo(MutableSystemInfo systemInfo, FunctionResult result); public static native void getSystemInfo(MutableSystemInfo systemInfo, FunctionResult result);
} }

View File

@@ -1,27 +1,31 @@
/* /*
* Copyright 2012 Adam Murdoch * Copyright 2012 Adam Murdoch
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package net.rubygrapefruit.platform.internal.jni; package net.rubygrapefruit.platform.internal.jni;
import net.rubygrapefruit.platform.internal.FunctionResult; import net.rubygrapefruit.platform.internal.FunctionResult;
public class PosixProcessFunctions { public class PosixProcessFunctions {
public static native int getPid(); public static native int getPid();
public static native String getWorkingDirectory(FunctionResult result); public static native String getWorkingDirectory(FunctionResult result);
public static native void setWorkingDirectory(String dir, FunctionResult result); public static native void setWorkingDirectory(String dir, FunctionResult result);
}
public static native String getEnvironmentVariable(String var, FunctionResult result);
public static native void setEnvironmentVariable(String var, String value, FunctionResult result);
}

View File

@@ -58,4 +58,79 @@ class ProcessTest extends Specification {
where: where:
dir << ['dir', 'dir\u03b1'] dir << ['dir', 'dir\u03b1']
} }
def "cannot set working directory to a directory that does not exist"() {
def newDir = new File(tmpDir.root, "does not exist");
when:
process.workingDirectory = newDir
then:
NativeException e = thrown()
e.message.startsWith("Could not set process working directory:")
}
def "can get and set and remove environment variable"() {
when:
def value = process.getEnvironmentVariable(varName)
then:
value == null
System.getenv(varName) == null
System.getenv()[varName] == null
when:
process.setEnvironmentVariable(varName, varValue)
then:
process.getEnvironmentVariable(varName) == varValue
System.getenv(varName) == varValue
System.getenv()[varName] == varValue
when:
process.setEnvironmentVariable(varName, null)
then:
process.getEnvironmentVariable(varName) == null
System.getenv(varName) == null
System.getenv()[varName] == null
where:
varName | varValue
'TEST_ENV_VAR' | 'test value'
'TEST_ENV_VAR\u03b1' | 'value\u03b2'
}
def "setting environment variable to null or empty string remove the environment variable"() {
when:
def value = process.getEnvironmentVariable(varName)
then:
value == null
System.getenv(varName) == null
System.getenv()[varName] == null
when:
process.setEnvironmentVariable(varName, varValue)
then:
process.getEnvironmentVariable(varName) == null
System.getenv(varName) == null
System.getenv()[varName] == null
where:
varName | varValue
'TEST_ENV_VAR_EMPTY' | ''
'TEST_ENV_VAR_NULL' | null
}
def "can remove environment variable that does not exist"() {
assert process.getEnvironmentVariable("TEST_ENV_UNKNOWN") == null
when:
process.setEnvironmentVariable("TEST_ENV_UNKNOWN", null)
then:
notThrown(NativeException)
}
} }