From 64a738008e64dd08e3c32702d3a87bd1e73b7154 Mon Sep 17 00:00:00 2001 From: Adam Murdoch Date: Sat, 26 Jan 2013 17:51:10 +1100 Subject: [PATCH] Added Process.getWorkingDirectory() and setWorkingDirectory() and posix implementation. --- readme.md | 1 + src/main/cpp/posix.cpp | 24 +++++ src/main/headers/generic.h | 2 +- .../net/rubygrapefruit/platform/Native.java | 2 +- .../net/rubygrapefruit/platform/Process.java | 18 ++++ .../platform/internal/DefaultProcess.java | 20 ++++ .../internal/jni/NativeLibraryFunctions.java | 2 +- .../internal/jni/PosixProcessFunctions.java | 48 +++++----- .../platform/ProcessTest.groovy | 94 ++++++++++++------- 9 files changed, 151 insertions(+), 60 deletions(-) diff --git a/readme.md b/readme.md index fead017..ec23230 100755 --- a/readme.md +++ b/readme.md @@ -15,6 +15,7 @@ These APIs support Java 5 and later. Some of these APIs overlap with APIs availa ### Processes * Get the PID of the current process. +* Get and set the process working directory. ### Terminal and console diff --git a/src/main/cpp/posix.cpp b/src/main/cpp/posix.cpp index 5c7a643..1938753 100755 --- a/src/main/cpp/posix.cpp +++ b/src/main/cpp/posix.cpp @@ -144,6 +144,30 @@ Java_net_rubygrapefruit_platform_internal_jni_PosixProcessFunctions_getPid(JNIEn return getpid(); } +JNIEXPORT jstring JNICALL +Java_net_rubygrapefruit_platform_internal_jni_PosixProcessFunctions_getWorkingDirectory(JNIEnv *env, jclass target, jobject result) { + char* path = getcwd(NULL, 0); + if (path == NULL) { + mark_failed_with_errno(env, "could not getcwd()", result); + return NULL; + } + jstring dir = char_to_java(env, path, result); + free(path); + return dir; +} + +JNIEXPORT void JNICALL +Java_net_rubygrapefruit_platform_internal_jni_PosixProcessFunctions_setWorkingDirectory(JNIEnv *env, jclass target, jstring dir, jobject result) { + char* path = java_to_char(env, dir, result); + if (path == NULL) { + return; + } + if (chdir(path) != 0) { + mark_failed_with_errno(env, "could not setcwd()", result); + } + free(path); +} + /* * Terminal functions */ diff --git a/src/main/headers/generic.h b/src/main/headers/generic.h index 4fef8a7..b5a1dde 100755 --- a/src/main/headers/generic.h +++ b/src/main/headers/generic.h @@ -23,7 +23,7 @@ extern "C" { #endif -#define NATIVE_VERSION 11 +#define NATIVE_VERSION 12 /* * Marks the given result as failed, using the given error message diff --git a/src/main/java/net/rubygrapefruit/platform/Native.java b/src/main/java/net/rubygrapefruit/platform/Native.java index 6c79c70..e9d9011 100755 --- a/src/main/java/net/rubygrapefruit/platform/Native.java +++ b/src/main/java/net/rubygrapefruit/platform/Native.java @@ -55,7 +55,7 @@ public class Native { loader.load(platform.getLibraryName()); int nativeVersion = NativeLibraryFunctions.getVersion(); if (nativeVersion != NativeLibraryFunctions.VERSION) { - throw new NativeException(String.format("Unexpected native library version loaded. Expected %s, was %s.", nativeVersion, NativeLibraryFunctions.VERSION)); + throw new NativeException(String.format("Unexpected native library version loaded. Expected %s, was %s.", NativeLibraryFunctions.VERSION, nativeVersion)); } } catch (NativeException e) { throw e; diff --git a/src/main/java/net/rubygrapefruit/platform/Process.java b/src/main/java/net/rubygrapefruit/platform/Process.java index 1b3b545..6a970fe 100755 --- a/src/main/java/net/rubygrapefruit/platform/Process.java +++ b/src/main/java/net/rubygrapefruit/platform/Process.java @@ -16,6 +16,8 @@ package net.rubygrapefruit.platform; +import java.io.File; + /** * Functions to query and modify a process' state. */ @@ -28,4 +30,20 @@ public interface Process extends NativeIntegration { */ @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; } diff --git a/src/main/java/net/rubygrapefruit/platform/internal/DefaultProcess.java b/src/main/java/net/rubygrapefruit/platform/internal/DefaultProcess.java index 5951590..17b440f 100755 --- a/src/main/java/net/rubygrapefruit/platform/internal/DefaultProcess.java +++ b/src/main/java/net/rubygrapefruit/platform/internal/DefaultProcess.java @@ -19,8 +19,28 @@ 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()); + } } diff --git a/src/main/java/net/rubygrapefruit/platform/internal/jni/NativeLibraryFunctions.java b/src/main/java/net/rubygrapefruit/platform/internal/jni/NativeLibraryFunctions.java index 32564c0..8a2c68a 100755 --- a/src/main/java/net/rubygrapefruit/platform/internal/jni/NativeLibraryFunctions.java +++ b/src/main/java/net/rubygrapefruit/platform/internal/jni/NativeLibraryFunctions.java @@ -20,7 +20,7 @@ import net.rubygrapefruit.platform.internal.FunctionResult; import net.rubygrapefruit.platform.internal.MutableSystemInfo; public class NativeLibraryFunctions { - public static final int VERSION = 11; + public static final int VERSION = 12; public static native int getVersion(); diff --git a/src/main/java/net/rubygrapefruit/platform/internal/jni/PosixProcessFunctions.java b/src/main/java/net/rubygrapefruit/platform/internal/jni/PosixProcessFunctions.java index 7e3a8f0..0110afd 100755 --- a/src/main/java/net/rubygrapefruit/platform/internal/jni/PosixProcessFunctions.java +++ b/src/main/java/net/rubygrapefruit/platform/internal/jni/PosixProcessFunctions.java @@ -1,21 +1,27 @@ -/* - * 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; - -public class PosixProcessFunctions { - public static native int getPid(); -} +/* + * 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); +} diff --git a/src/test/groovy/net/rubygrapefruit/platform/ProcessTest.groovy b/src/test/groovy/net/rubygrapefruit/platform/ProcessTest.groovy index 6478fc2..0819bdd 100755 --- a/src/test/groovy/net/rubygrapefruit/platform/ProcessTest.groovy +++ b/src/test/groovy/net/rubygrapefruit/platform/ProcessTest.groovy @@ -1,36 +1,58 @@ -/* - * 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 org.junit.Rule -import org.junit.rules.TemporaryFolder -import spock.lang.Specification - -class ProcessTest extends Specification { - @Rule TemporaryFolder tmpDir - final Process process = Native.get(Process.class) - - def "caches process instance"() { - expect: - Native.get(Process.class) == process - } - - def "can get PID"() { - expect: - process.getProcessId() != 0 - } -} +/* + * 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 org.junit.Rule +import org.junit.rules.TemporaryFolder +import spock.lang.Specification + +class ProcessTest extends Specification { + @Rule TemporaryFolder tmpDir + final Process process = Native.get(Process.class) + + def "caches process instance"() { + expect: + Native.get(Process.class) == process + } + + def "can get PID"() { + expect: + process.getProcessId() != 0 + } + + def "can change working directory"() { + def newDir = tmpDir.newFolder("dir").canonicalFile + + when: + def original = process.workingDirectory + + then: + original == new File(".").canonicalFile + original == new File(System.getProperty("user.dir")) + + when: + process.workingDirectory = newDir + + then: + process.workingDirectory == newDir + new File(".").canonicalFile == newDir + new File(System.getProperty("user.dir")) == newDir + + cleanup: + process.workingDirectory = original + } +}