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.
* 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.
* Check for null parameters.
### Ideas

View File

@@ -109,13 +109,55 @@ Java_net_rubygrapefruit_platform_internal_jni_PosixProcessFunctions_setWorkingDi
if (dirPath == NULL) {
return;
}
if (!SetCurrentDirectoryW(dirPath)) {
BOOL ok = SetCurrentDirectoryW(dirPath);
free(dirPath);
if (!ok) {
mark_failed_with_errno(env, "could not set current directory", result);
free(dirPath);
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" {
#endif
#define NATIVE_VERSION 12
#define NATIVE_VERSION 13
/*
* Marks the given result as failed, using the given error message

View File

@@ -1,49 +1,68 @@
/*
* Copyright 2012 Adam Murdoch
*
* 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 net.rubygrapefruit.platform;
import java.io.File;
/**
* Functions to query and modify a process' state.
*/
@ThreadSafe
public interface Process extends NativeIntegration {
/**
* Returns the process identifier.
*
* @throws NativeException On failure.
*/
@ThreadSafe
int getProcessId() throws NativeException;
/**
* Returns the process' current working directory.
*
* @throws NativeException On failure.
*/
@ThreadSafe
File getWorkingDirectory() throws NativeException;
/**
* Sets the process' working directory.
*
* @throws NativeException On failure.
*/
@ThreadSafe
void setWorkingDirectory(File directory) throws NativeException;
}
/*
* Copyright 2012 Adam Murdoch
*
* 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 net.rubygrapefruit.platform;
import java.io.File;
/**
* Functions to query and modify a process' state.
*/
@ThreadSafe
public interface Process extends NativeIntegration {
/**
* Returns the process identifier.
*
* @throws NativeException On failure.
*/
@ThreadSafe
int getProcessId() throws NativeException;
/**
* Returns the process' current working directory.
*
* @throws NativeException On failure.
*/
@ThreadSafe
File getWorkingDirectory() throws NativeException;
/**
* Sets the process' working directory.
*
* @throws NativeException On failure.
*/
@ThreadSafe
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
*
* 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 net.rubygrapefruit.platform.internal;
import net.rubygrapefruit.platform.*;
import net.rubygrapefruit.platform.internal.jni.PosixProcessFunctions;
import java.io.File;
public class DefaultProcess implements net.rubygrapefruit.platform.Process {
public int getProcessId() throws NativeException {
return PosixProcessFunctions.getPid();
}
public File getWorkingDirectory() throws NativeException {
FunctionResult result = new FunctionResult();
String dir = PosixProcessFunctions.getWorkingDirectory(result);
if (result.isFailed()) {
throw new NativeException(String.format("Could not get process working directory: %s", result.getMessage()));
}
return new File(dir);
}
public void setWorkingDirectory(File directory) throws NativeException {
FunctionResult result = new FunctionResult();
PosixProcessFunctions.setWorkingDirectory(directory.getAbsolutePath(), result);
if (result.isFailed()) {
throw new NativeException(String.format("Could not set process working directory: %s", result.getMessage()));
}
System.setProperty("user.dir", directory.getAbsolutePath());
}
}
/*
* Copyright 2012 Adam Murdoch
*
* 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 net.rubygrapefruit.platform.internal;
import net.rubygrapefruit.platform.NativeException;
import net.rubygrapefruit.platform.Process;
import net.rubygrapefruit.platform.internal.jni.PosixProcessFunctions;
import java.io.File;
public class DefaultProcess implements Process {
private final Object workingDirectoryLock = new Object();
private final Object environmentLock = new Object();
public int getProcessId() throws NativeException {
return PosixProcessFunctions.getPid();
}
public File getWorkingDirectory() throws NativeException {
FunctionResult result = new FunctionResult();
String dir;
synchronized (workingDirectoryLock) {
dir = PosixProcessFunctions.getWorkingDirectory(result);
}
if (result.isFailed()) {
throw new NativeException(String.format("Could not get process working directory: %s",
result.getMessage()));
}
return new File(dir);
}
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
*
* 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 net.rubygrapefruit.platform.internal.jni;
import net.rubygrapefruit.platform.internal.FunctionResult;
import net.rubygrapefruit.platform.internal.MutableSystemInfo;
public class NativeLibraryFunctions {
public static final int VERSION = 12;
public static native int getVersion();
public static native void getSystemInfo(MutableSystemInfo systemInfo, FunctionResult result);
}
/*
* Copyright 2012 Adam Murdoch
*
* 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 net.rubygrapefruit.platform.internal.jni;
import net.rubygrapefruit.platform.internal.FunctionResult;
import net.rubygrapefruit.platform.internal.MutableSystemInfo;
public class NativeLibraryFunctions {
public static final int VERSION = 13;
public static native int getVersion();
public static native void getSystemInfo(MutableSystemInfo systemInfo, FunctionResult result);
}

View File

@@ -1,27 +1,31 @@
/*
* Copyright 2012 Adam Murdoch
*
* 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 net.rubygrapefruit.platform.internal.jni;
import net.rubygrapefruit.platform.internal.FunctionResult;
public class PosixProcessFunctions {
public static native int getPid();
public static native String getWorkingDirectory(FunctionResult result);
public static native void setWorkingDirectory(String dir, FunctionResult result);
}
/*
* Copyright 2012 Adam Murdoch
*
* 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 net.rubygrapefruit.platform.internal.jni;
import net.rubygrapefruit.platform.internal.FunctionResult;
public class PosixProcessFunctions {
public static native int getPid();
public static native String getWorkingDirectory(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:
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)
}
}