- Added Process.getPid() and Terminal.isTerminal().
- Added a test command-line app.
This commit is contained in:
@@ -2,6 +2,7 @@ apply plugin: 'java'
|
|||||||
apply plugin: 'groovy'
|
apply plugin: 'groovy'
|
||||||
apply plugin: 'cpp-lib'
|
apply plugin: 'cpp-lib'
|
||||||
apply plugin: 'idea'
|
apply plugin: 'idea'
|
||||||
|
apply plugin: 'application'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
@@ -12,6 +13,7 @@ dependencies {
|
|||||||
testCompile 'org.spockframework:spock-core:0.6-groovy-1.8'
|
testCompile 'org.spockframework:spock-core:0.6-groovy-1.8'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mainClassName = 'net.rubygrapefruit.platform.Main'
|
||||||
def nativeHeadersDir = file("$buildDir/nativeHeaders")
|
def nativeHeadersDir = file("$buildDir/nativeHeaders")
|
||||||
|
|
||||||
libraries {
|
libraries {
|
||||||
@@ -34,6 +36,8 @@ task nativeHeaders {
|
|||||||
args '-o', outputFile
|
args '-o', outputFile
|
||||||
args '-classpath', sourceSets.main.output.classesDir
|
args '-classpath', sourceSets.main.output.classesDir
|
||||||
args 'net.rubygrapefruit.platform.internal.PosixFileFunctions'
|
args 'net.rubygrapefruit.platform.internal.PosixFileFunctions'
|
||||||
|
args 'net.rubygrapefruit.platform.internal.PosixProcessFunctions'
|
||||||
|
args 'net.rubygrapefruit.platform.internal.PosixTerminalFunctions'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
void markFailed(JNIEnv *env, jobject result) {
|
void markFailed(JNIEnv *env, jobject result) {
|
||||||
jclass destClass = env->GetObjectClass(result);
|
jclass destClass = env->GetObjectClass(result);
|
||||||
@@ -30,4 +31,20 @@ Java_net_rubygrapefruit_platform_internal_PosixFileFunctions_stat(JNIEnv *env, j
|
|||||||
jclass destClass = env->GetObjectClass(dest);
|
jclass destClass = env->GetObjectClass(dest);
|
||||||
jfieldID modeField = env->GetFieldID(destClass, "mode", "I");
|
jfieldID modeField = env->GetFieldID(destClass, "mode", "I");
|
||||||
env->SetIntField(dest, modeField, 0777 & fileInfo.st_mode);
|
env->SetIntField(dest, modeField, 0777 & fileInfo.st_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_net_rubygrapefruit_platform_internal_PosixProcessFunctions_getPid(JNIEnv *env, jclass target) {
|
||||||
|
return getpid();
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_net_rubygrapefruit_platform_internal_PosixTerminalFunctions_isatty(JNIEnv *env, jclass target, jint output) {
|
||||||
|
switch (output) {
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
return isatty(output+1) ? JNI_TRUE : JNI_FALSE;
|
||||||
|
default:
|
||||||
|
return JNI_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/main/java/net/rubygrapefruit/platform/Main.java
Normal file
11
src/main/java/net/rubygrapefruit/platform/Main.java
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package net.rubygrapefruit.platform;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Process process = Platform.get(Process.class);
|
||||||
|
System.out.println("* PID: " + process.getPid());
|
||||||
|
Terminal terminal = Platform.get(Terminal.class);
|
||||||
|
System.out.println("* stdout: " + (terminal.isTerminal(Terminal.Output.Stdout) ? "terminal" : "not a terminal"));
|
||||||
|
System.out.println("* stderr: " + (terminal.isTerminal(Terminal.Output.Stderr) ? "terminal" : "not a terminal"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
package net.rubygrapefruit.platform;
|
package net.rubygrapefruit.platform;
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.internal.FileStat;
|
import net.rubygrapefruit.platform.internal.*;
|
||||||
import net.rubygrapefruit.platform.internal.FunctionResult;
|
|
||||||
import net.rubygrapefruit.platform.internal.PosixFileFunctions;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides access to the native integrations. Use {@link #get(Class)} to load a particular integration.
|
||||||
|
*/
|
||||||
public class Platform {
|
public class Platform {
|
||||||
private static final Object lock = new Object();
|
private static final Object lock = new Object();
|
||||||
private static boolean loaded;
|
private static boolean loaded;
|
||||||
@@ -23,26 +24,50 @@ public class Platform {
|
|||||||
loaded = true;
|
loaded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return type.cast(new UnixFileMode() {
|
if (type.equals(PosixFile.class)) {
|
||||||
@Override
|
return type.cast(new DefaultPosixFile());
|
||||||
public void setMode(File file, int perms) {
|
}
|
||||||
FunctionResult result = new FunctionResult();
|
if (type.equals(Process.class)) {
|
||||||
PosixFileFunctions.chmod(file.getPath(), perms, result);
|
return type.cast(new DefaultProcess());
|
||||||
if (result.isFailed()) {
|
}
|
||||||
throw new NativeException(String.format("Could not set UNIX mode on %s. Errno is %d.", file, result.getErrno()));
|
if (type.equals(Terminal.class)) {
|
||||||
|
return type.cast(new Terminal(){
|
||||||
|
@Override
|
||||||
|
public boolean isTerminal(Output output) {
|
||||||
|
return PosixTerminalFunctions.isatty(output.ordinal());
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
throw new UnsupportedOperationException(String.format("Cannot load unknown native integration %s.",
|
||||||
|
type.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
private static class DefaultPosixFile implements PosixFile {
|
||||||
public int getMode(File file) {
|
@Override
|
||||||
FunctionResult result = new FunctionResult();
|
public void setMode(File file, int perms) {
|
||||||
FileStat stat = new FileStat();
|
FunctionResult result = new FunctionResult();
|
||||||
PosixFileFunctions.stat(file.getPath(), stat, result);
|
PosixFileFunctions.chmod(file.getPath(), perms, result);
|
||||||
if (result.isFailed()) {
|
if (result.isFailed()) {
|
||||||
throw new NativeException(String.format("Could not get UNIX mode on %s. Errno is %d.", file, result.getErrno()));
|
throw new NativeException(String.format("Could not set UNIX mode on %s. Errno is %d.", file, result.getErrno()));
|
||||||
}
|
|
||||||
return stat.mode;
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMode(File file) {
|
||||||
|
FunctionResult result = new FunctionResult();
|
||||||
|
FileStat stat = new FileStat();
|
||||||
|
PosixFileFunctions.stat(file.getPath(), stat, result);
|
||||||
|
if (result.isFailed()) {
|
||||||
|
throw new NativeException(String.format("Could not get UNIX mode on %s. Errno is %d.", file, result.getErrno()));
|
||||||
|
}
|
||||||
|
return stat.mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DefaultProcess implements Process {
|
||||||
|
@Override
|
||||||
|
public int getPid() throws NativeException {
|
||||||
|
return PosixProcessFunctions.getPid();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ package net.rubygrapefruit.platform;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
public interface UnixFileMode extends NativeIntegration {
|
/**
|
||||||
|
* Functions to query and modify a file's POSIX meta-data.
|
||||||
|
*/
|
||||||
|
public interface PosixFile extends NativeIntegration {
|
||||||
void setMode(File path, int perms) throws NativeException;
|
void setMode(File path, int perms) throws NativeException;
|
||||||
|
|
||||||
int getMode(File path) throws NativeException;
|
int getMode(File path) throws NativeException;
|
||||||
8
src/main/java/net/rubygrapefruit/platform/Process.java
Normal file
8
src/main/java/net/rubygrapefruit/platform/Process.java
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package net.rubygrapefruit.platform;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Functions to query and modify a process' meta-data
|
||||||
|
*/
|
||||||
|
public interface Process extends NativeIntegration {
|
||||||
|
int getPid() throws NativeException;
|
||||||
|
}
|
||||||
7
src/main/java/net/rubygrapefruit/platform/Terminal.java
Normal file
7
src/main/java/net/rubygrapefruit/platform/Terminal.java
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package net.rubygrapefruit.platform;
|
||||||
|
|
||||||
|
public interface Terminal extends NativeIntegration {
|
||||||
|
enum Output {Stdout, Stderr}
|
||||||
|
|
||||||
|
boolean isTerminal(Output output);
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package net.rubygrapefruit.platform.internal;
|
||||||
|
|
||||||
|
public class PosixProcessFunctions {
|
||||||
|
public static native int getPid();
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package net.rubygrapefruit.platform.internal;
|
||||||
|
|
||||||
|
public class PosixTerminalFunctions {
|
||||||
|
public static native boolean isatty(int fildes);
|
||||||
|
}
|
||||||
@@ -4,9 +4,9 @@ import spock.lang.Specification
|
|||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.rules.TemporaryFolder
|
import org.junit.rules.TemporaryFolder
|
||||||
|
|
||||||
class UnixFileModeTest extends Specification {
|
class PosixFileTest extends Specification {
|
||||||
@Rule TemporaryFolder tmpDir
|
@Rule TemporaryFolder tmpDir
|
||||||
final UnixFileMode file = Platform.get(UnixFileMode.class)
|
final PosixFile file = Platform.get(PosixFile.class)
|
||||||
|
|
||||||
def "can set mode on a file"() {
|
def "can set mode on a file"() {
|
||||||
def testFile = tmpDir.newFile("test.txt")
|
def testFile = tmpDir.newFile("test.txt")
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
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 = Platform.get(Process.class)
|
||||||
|
|
||||||
|
def "can get PID"() {
|
||||||
|
expect:
|
||||||
|
process.getPid() != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package net.rubygrapefruit.platform
|
||||||
|
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.rules.TemporaryFolder
|
||||||
|
import spock.lang.Specification
|
||||||
|
|
||||||
|
class TerminalTest extends Specification {
|
||||||
|
@Rule TemporaryFolder tmpDir
|
||||||
|
final Terminal terminal = Platform.get(Terminal.class)
|
||||||
|
|
||||||
|
def "can check if attached to terminal"() {
|
||||||
|
expect:
|
||||||
|
!terminal.isTerminal(Terminal.Output.Stdout);
|
||||||
|
!terminal.isTerminal(Terminal.Output.Stderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user