Giter VIP home page Giter VIP logo

native-platform's Introduction

Native-platform: Java bindings for native APIs

A collection of cross-platform Java APIs for various native APIs. Currently supports OS X, Linux, Windows and FreeBSD on Intel architectures.

These APIs support Java 5 and later. Some of these APIs overlap with APIs available in later Java versions.

Available bindings

Terminal and console

These bindings work for the UNIX terminal, the Windows console and Mintty from Cygwin and MSys on Windows.

  • Determine whether stdin/stdout/stderr are attached to a terminal.
  • Query the terminal size. Not supported for Mintty
  • Change foreground color on the terminal.
  • Switch between bold and normal text mode on the terminal.
  • Switch between dim, bright and normal text intensity on the terminal.
  • Move terminal cursor up, down, left, right, start of line.
  • Clear to end of line.
  • Show and hide the cursor.
  • Read raw input from the terminal. Not support for Mintty.
  • Read arrow keys and other function keys from the terminal. Not support for Mintty.

See Terminals

  • Utility class to display various kinds of prompts to the user on the terminal.

See Prompter

System information

  • Query kernel name and version.
  • Query machine architecture.
  • Query hostname.
  • Query total and available memory (OS X and Windows only).
  • Query system commit total and limit (Windows only).

See SystemInfo

Processes

  • Query the PID of the current process.
  • Query and set the process working directory.
  • Query and set the process environment variables.
  • Detach process from its controlling console

See Process

File systems

  • Query and set UNIX file mode.
  • Create and read symbolic links on UNIX and Windows.
  • Query UNIX file uid and gid.
  • Query file type, size and timestamps.
  • Query directory contents.

See Files

  • List the available file systems on the machine and details of each file system.
  • Query file system mount point.
  • Query file system type.
  • Query file system device name.
  • Query whether a file system is local or remote.
  • Query whether a file system is case-sensitive and case preserving.

See FileSystems

Windows registry

  • Query registry value.
  • Query the subkeys and values of a registry key.

See WindowsRegistry

Supported platforms

Currently ported to OS X, Linux, FreeBSD and Windows. Support for Solaris is a work in progress. Supported on:

  • OS X, version 10.13 and later (x86_64)
  • Fedora 23 and later (amd64).
  • Ubuntu 8.04 and later (amd64).
  • Ubuntu 18.04 and later (aarch64).
  • FreeBSD 10 and later (amd64).
  • Windows XP and later (amd64, i386). Console integration works with cmd.exe, powershell, ConEmu, Mintty from Cygwin, Mintty from Msys (includes Git for Windows).

Using

Include native-platform.jar and native-platform-${os}-${arch}.jar in your classpath. From Gradle, you can do this:

repositories {
    jcenter()
}

dependencies {
    compile "net.rubygrapefruit:native-platform:0.21"
}

You can also download the Jars from bintray

A test application is also available from bintray

Some sample code to use the terminal:

import net.rubygrapefruit.platform.Native;
import net.rubygrapefruit.platform.terminal.Terminals;
import net.rubygrapefruit.platform.terminal.TerminalOutput;
import static net.rubygrapefruit.platform.terminal.Terminals.Output.*;

Terminals terminals = Native.get(Terminals.class);

// check if terminal
terminals.isTerminal(Stdout);

// use terminal
TerminalOutput stdout = terminals.getTerminal(Stdout);
stdout.bold();
System.out.println("bold text");

Changes

0.22 (unreleased)

  • Remove support for 32bit Linux & FreeBSD, as well as support for FreeBSD < 10.
  • Implement Memory and add WindowsMemory for Windows.

0.21

  • Some preparation for a new API to watch the file system for changes.

0.20

  • Removed FileEvents API for watching the file system for changes.

0.19

  • Added SystemInfo.getHostname(). Thanks to Tom Dunstan
  • Fixed terminal integration on Arch linux.
  • Fixed terminal integration on Amazon linux 2 aarch64.

0.18

  • Support for symlinks on Windows. Thanks to Renaud Paquay.
  • Fixed handling of long paths on Windows. Thanks to Renaud Paquay.
  • Support for Linux on aarch64. Thanks to Amey.

0.17

  • Fixed handling of supplementary characters in environment variable values. Thanks to Gary Hale.
  • Added TerminalInput.supportsRawMode() to determine whether terminal supports raw mode.
  • Improve Prompter to show an alternate UI when the terminal input does not support raw mode.

0.16

  • Change Terminals to support running under Mintty from Cygwin and MSYS on Windows. Supported for Windows 2008 and later. TerminalOutput is supported, however TerminalInput is not.

0.15

  • Fixed Files.stat() when the path points to a descendent of a file. Thanks to Gary Hale.
  • Renamed Terminal to TerminalOutput.
  • Moved some types to subpackages.
  • Added TerminalInput to read text from the terminal. Supports raw mode and arrow keys.
  • Added method to Terminals to determine whether stdin is attached to a terminal.
  • Added method to Terminals to force the use of ANSI escape sequences to write the terminal output.
  • Added methods to TerminalOutput to show and hide the cursor.
  • Added methods to TerminalOutput to set foreground text color to its default value.
  • Added methods to TerminalOutput to set bright and dim foreground text intensity.
  • Added methods to TerminalOutput to write text to the terminal. Anything written to System.out or System.err is no longer automatically flushed before cursor or text attributes are changed.
  • Added Prompter utility class to display prompts on the terminal to ask the user various questions.
  • Moved releases to JCenter.

0.14

  • Added Memory, for OS X only. Thanks to Paul Merlin
  • NativeIntegrationLinkageException is thrown by Native.get() when a particular native library cannot be loaded due to a linkage error.

0.13

  • Added overloads of Files.stat() and Files.listDir() that follow links.
  • Improvements to error handling for Files.stat() and listDir().
  • Fixes for build time detection of ncurses 6. Thanks to Marcin Zajączkowski

0.12

  • Added Files.listDir().
  • Fixes for terminal integration for Linux distributions that use ncurses 6, such as Fedora 24 and later.
  • Fixes for running on FreeBSD 10 and later without requiring GCC to be installed on the machine.

0.11

  • Added support to detach the current process from its controlling console. Thanks to Gary Hale.
  • Fixes for handling Windows shares from Linux. Thanks to Thierry Guérin.
  • Added initial implementation of FileEvents, which allows an application to listen for changes to a file system directory.
  • Added more properties to PosixFile.
  • Added Files and WindowsFiles.
  • Added FileSystem.isCaseSensitive() and FileSystem.isCasePreserving().
  • Fixes running under GCJ.

0.10

  • Fixes for broken 0.9 release.

0.9

  • Fixes for non-ascii file names on OS X when running under the Apple JVM.

You should avoid using this release, and use 0.10 or later instead.

0.8

0.7

  • Some fixes for a broken 0.6 release.

0.6

  • Some fixes for Windows 7 and OS X 10.6.

You should avoid using this release, and use 0.7 or later instead.

0.5

  • Query the available values of a Windows registry key. Thanks to Michael Putters.

0.4

  • Get file type.
  • Query Windows registry value and subkeys.
  • Fixes to work on 64-bit Windows XP.

0.3

  • Get and set process working directory.
  • Get and set process environment variables.
  • Launch processes.
  • Fixed character set issue on Linux and Mac OS X.
  • Fixes to work with 64-bit OpenJDK 7 on Mac OS X. Thanks to Rene Groeschke.

0.2

  • Fixes to make native library extraction multi-process safe.
  • Fixes to windows terminal detection and reset.

0.1

  • Initial release.

Development

Building

This project uses (Gradle)[https://www.gradle.org] to build. Just run gradlew in the root of the source repo. You will need Java 8 or later to run the tests.

Ubuntu

The g++ compiler is required to build the native library. You will need to install the g++ package for this. Alternatively, you can use the Clang C++ compiler.

You need to install the libncurses5-dev package to pick up the ncurses header files. Also worth installing the ncurses-doc package too.

64-bit machines with multi-arch support

Where multi-arch support is available (e.g. recent Ubuntu releases), you can build the i386 and amd64 versions of the library on the same machine.

You need to install the gcc-multilib and g++-multilib packages to pick up i386 support.

You need to install the lib32ncurses5-dev package to pick up the ncurses i386 version.

Windows

You need to install Visual studio 2012 or later, plus the Windows SDK to allow you to build both x86 and x64 binaries.

OS X

The clang compiler is required to build the native library. You will need to install the XCode command-line tools for this.

Solaris

For Solaris 11, you need to install the development/gcc-45 and system/header packages.

Running

Run gradlew installDist to install the test application into test-app/build/install/native-platform-test. Or gradle distZip to create an application distribution in test-app/build/distributions/native-platform-test-$version.zip.

You can run $INSTALL_DIR/bin/native-platform-test to run the test application.

Testing integration with another project

When developing a new feature in native platform, you often want to test the features in a real-world project which uses native platform. There are various ways how to test the changes of native platform in the consuming project.

Use composite build on a developer machine

From the command line

From the checkout directory of the consuming project you can run:

./gradlew --include-build ../native-platform ...

This assumes that native-platform is checked out in ../native-platform relative to the consuming project.

From IDEA

In IDEA, open the consuming project. Then link the native-platform project. Finally, add the linked native-platform project as a participant to the Gradle build and sync the consuming project.

WARNING: You need to use IDEA 2020.1 for the composite build to work. See https://youtrack.jetbrains.com/issue/IDEA-228368 and https://youtrack.jetbrains.com/issue/IDEA-206799.

Use a published snapshot on a developer machine/CI

  • Publish a snapshot from the branch you want to test by using this Teamcity build.
  • Change the version of native platform in the consuming project to match the version you just published, e.g. 0.22-snapshot-20200128143135+0000, and push the changes to a branch.
  • Run some tests on CI on the branch of the consuming project you just pushed.
  • Test what you want to test on the consuming project.

Use mavenLocal() on a developer machine

  • Install a dev version of native platform to your local Maven repository by running
    ./gradlew publishToMavenLocal -PonlyLocalVariants
  • Add mavenLocal() as a repository in the consuming project.
  • Change the version of native platform in the consuming project to match the version you just built, e.g. 0.22-dev.
  • Test what you want to test on the consuming project.

Releasing

See this issue first.

In the meantime, this TC job should be used to publish a milestone. Add a tag afterward.

To publish manually:

  1. Check the version number in build.gradle.
  2. Create a tag
  3. Build each variant.
    1. Checkout tag.
    2. ./gradlew clean :native-platform:test :native-platform:uploadJni -Prelease -PpublishUserName=<> -PpublishApiKey=<>.
  4. Build Java library:
    1. Checkout tag.
    2. ./gradlew clean :native-platform:test :native-platform:uploadMain -Prelease -PpublishUserName=<> -PpublishApiKey=<>
  5. Build the test app:
    1. Checkout tag.
    2. ./gradlew clean :test-app:uploadMain -Prelease -PpublishUserName=<> -PpublishApiKey=<>
  6. Publish on bintray
  7. Checkout master
  8. Increment version number in gradle.properties and this readme.
  9. Push changes.

Use -Pmilestone instead of -Prelease to publish a milestone version.

Testing

  • Test on IBM JVM.
  • Test on Java 5, 6, 7.
  • Test on Windows 7, Windows XP

TODO

Fixes

  • OS X: Watch for changes to files in directory.
  • FreeBSD: Watch for changes to files in directory.
  • Linux: Fix spurious change event on close.
  • All: Handle deletion and recreation of watched file/directory.
  • All: Watch for creation and changes to missing file/directory.
  • Windows: Watch for changes to a file (directory works, file does not).
  • All: FileWatch tests: file truncated, last modified changed, content changed, recreated as file/dir, file renamed
  • All: Thread safety for FileWatch.
  • All: Bulk read of multiple file change events, coalesce events, use background thread to drain queue.
  • Linux: Fix detection of multiarch support
  • FreeBSD: Fix detection of multiarch support
  • All: Process.getPid() should return a long
  • All: fail subsequent calls to Native.get() when Native.initialize() fails.
  • Posix: allow terminal to be detected when ncurses cannot be loaded
  • Windows: fix detection of shared drive under VMWare fusion and Windows XP
  • Windows: restore std handles after launching child process
  • Linux: detect remote filesystems.
  • All: cache reflective lookup in native functions.
  • Solaris: fix unicode file name handling.
  • Solaris: fail for unsupported architecture.
  • Solaris: build 32 bit and 64 bit libraries.

Improvements

  • All: fall back to WrapperProcessLauncher + DefaultProcessLauncher for all platforms, regardless of whether a native integration is available or not.
  • All: change the terminal API to handle the fact that stdout/stderr/stdin can all be attached to the same or to different terminals.
  • All: have Terminal extend Appendable and Flushable
  • All: add a method to Terminal that returns a PrintStream that can be used to write to the terminal, regardless of what System.out or System.err point to.
  • Windows: use wchar_to_java() for system and file system info.
  • All: test network file systems
  • Windows: test mount points
  • All: cache class, method and field lookups
  • Unix: change readLink() implementation so that it does not need to NULL terminate the encoded content
  • All: don't use NewStringUTF() anywhere
  • Mac: change java_to_char() to convert java string directly to utf-8 char string.
  • Mac: change char_to_java() to assume utf-8 encoding and convert directly to java string.
  • Linux: change char_to_java() to use iconv() to convert from C char string to UTF-16 then to java string.
  • Windows: support for cygwin terminal input
  • Solaris: use TERM=xtermc instead of TERM=xterm.
  • All: add diagnostics for terminal.
  • All: version each native interface separately.
  • Windows: string names for errno values.
  • All: split into multiple projects.
  • Mac: use fully decomposed form for unicode file names on hfs+ filesystems.
  • All: extend FileSystem to deal with removable media.
  • Unix: add a Terminal implementation that uses ANSI control codes. Use this when TERM != 'dumb' and libncurses cannot be loaded.
  • All: 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.
  • All: check for null parameters.

Ideas

native-platform's People

Contributors

adammurdoch avatar big-guy avatar blindpirate avatar bot-teamcity avatar breskeby avatar cobexer avatar eskatos avatar gavra0 avatar ghale avatar jlleitschuh avatar lptr avatar modmuss50 avatar octylfractal avatar ov7a avatar rpaquay avatar rraziel avatar schwingsk avatar szpak avatar tinca avatar tomdcc avatar valery1707 avatar wolfs avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

native-platform's Issues

native-platform fails to run on FreeBSD 10 without gcc

The standard distribution for FreeBSD 10 does not include gcc, but includes clang instead. This causes the native-platform to fail to run. The native-platform should be updated to build with clang on FreeBSD so as to not require users to install gcc in addition to clang.

Native file watcher threads stay attached to the JVM even after watcher stops

In both the Windows and the macOS file watcher the native thread is attached to the JVM every time an event is received. This has two problems:

  1. we are doing unnecessary work, slowing down event delivery

  2. since we never detach the native thread, the JVM is left alive even after all other threads exit, as the (already stopped) native thread is still represented as a RUNNING JVM thread:

    "DestroyJavaVM@679" prio=5 tid=0x16 nid=NA runnable
      java.lang.Thread.State: RUNNABLE
    
    "Thread-0@677" prio=5 tid=0x15 nid=NA runnable
      java.lang.Thread.State: RUNNABLE
    

Attaching should happen when we start the watcher thread, and detaching should happen when we stop the thread.

https://github.com/adammurdoch/native-platform/blob/79a56f78ea83f3bc0a9e85303814e3c553de15ad/src/main/cpp/apple_fsnotifier.cpp#L40-L51

Module Support

It seems like it's not possible to use the native-platform project in modular applications. The native-platform jars cannot be converted to dynamic modules because 'native' is unfortunately a Java keyword and so the naming algorithm fails. Please consider adding Automatic Module Names (http://branchandbound.net/blog/java/2017/12/automatic-module-name/) to these JARs so they can be used from modular Java applications.

Investigate macOS event delivered late

Looks for the root directory created before watching started we received a CREATED event, meaning on macOS it is possible to receive late events:

https://e.grdev.net/s/3jwr2jy2wdo3m/tests/si6uhuz4tdufy-xcwnm6gwgua5w

00:04:00.397  INFO    >>> Running 'fails when watching directory twice'
00:04:00.432  FINE    Starting thread
00:04:00.437  FINE    Started thread
00:04:00.457  FINE    Event flags: 0x20100 for /Users/tcagent/agent/temp/buildTmp/junit4445026303787438839/fails when watching directory twice/root
00:04:00.457  FINE    Changed: /Users/tcagent/agent/temp/buildTmp/junit4445026303787438839/fails when watching directory twice/root 0
00:04:00.458  INFO    > Received  CREATED /Users/tcagent/agent/temp/buildTmp/junit4445026303787438839/fails when watching directory twice/root

(The NullPointerException comes from the fact that we are not expecting any events. We should change the test to print some more useful message in this case.)

native-platform license ?

Hi,

I'm currently working to provide a Debian GNU/Linux package for gradle 1.3 and I'm stuck with native-platform : it seems there is no license assignement in this project.

  • no COPYING / LICENSE.txt file in rootdir
  • no Copyright or license header in any files

Could you please have a look and provide a license for this project ?

Thanks in advance,

Platforms built with `--enable-widec` only have `libncursesw.so`

On distributions (like Arch Linux) that have been built with --enable-widec, ncurses produces only a libncursesw.so (note the w).

Since native-platform links against libncurses.so (5 or 6), Gradle falls back to a plain terminal.

I don't think it's necessarily safe, but symlinking libncurses.so.6 to libncursesw.so worked.

Package requires gcc on FreeBSD 10 to work

Prior to installing the gcc package on a fresh FreeBSD 10.0-RELEASE (amd64) machine, Gradle will give me wacky build errors:

It appears that installing the gcc package (pkg install gcc) solves this.

FYI.

$ ./gradlew clean check --stacktrace 
:clean
:compileJava UP-TO-DATE
:compileGroovy
:processResources FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':processResources'.
> net.rubygrapefruit.platform.internal.jni.PosixFileFunctions.stat(Ljava/lang/String;Lnet/rubygrapefruit/platform/internal/FileStat;Lnet/rubygrapefruit/platform/internal/FunctionResult;)V

* Try:
Run with --info or --debug option to get more log output.

* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':processResources'.
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:69)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:46)
    at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:35)
    at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:64)
    at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
    at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:42)
    at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
    at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:53)
    at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
    at org.gradle.api.internal.AbstractTask.executeWithoutThrowingTaskFailure(AbstractTask.java:305)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.executeTask(AbstractTaskPlanExecutor.java:79)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:63)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:51)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:23)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:88)
    at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:29)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:62)
    at org.gradle.execution.DefaultBuildExecuter.access$200(DefaultBuildExecuter.java:23)
    at org.gradle.execution.DefaultBuildExecuter$2.proceed(DefaultBuildExecuter.java:68)
    at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:62)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:55)
    at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:149)
    at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:106)
    at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:86)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:80)
    at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:33)
    at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:24)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:36)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:26)
    at org.gradle.launcher.cli.RunBuildAction.run(RunBuildAction.java:51)
    at org.gradle.internal.Actions$RunnableActionAdapter.execute(Actions.java:171)
    at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:237)
    at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:210)
    at org.gradle.launcher.cli.JavaRuntimeValidationAction.execute(JavaRuntimeValidationAction.java:35)
    at org.gradle.launcher.cli.JavaRuntimeValidationAction.execute(JavaRuntimeValidationAction.java:24)
    at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:206)
    at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:169)
    at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:33)
    at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:22)
    at org.gradle.launcher.Main.doAction(Main.java:33)
    at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:45)
    at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:54)
    at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:35)
    at org.gradle.launcher.GradleMain.main(GradleMain.java:23)
    at org.gradle.wrapper.BootstrapMainStarter.start(BootstrapMainStarter.java:30)
    at org.gradle.wrapper.WrapperExecutor.execute(WrapperExecutor.java:127)
    at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:56)
Caused by: java.lang.UnsatisfiedLinkError: net.rubygrapefruit.platform.internal.jni.PosixFileFunctions.stat(Ljava/lang/String;Lnet/rubygrapefruit/platform/internal/FileStat;Lnet/rubygrapefruit/platform/internal/FunctionResult;)V
    at net.rubygrapefruit.platform.internal.jni.PosixFileFunctions.stat(Native Method)
    at net.rubygrapefruit.platform.internal.DefaultPosixFiles.stat(DefaultPosixFiles.java:30)
    at net.rubygrapefruit.platform.internal.DefaultPosixFiles.getMode(DefaultPosixFiles.java:46)
    at org.gradle.internal.nativeplatform.filesystem.NativePlatformBackedStat.getUnixMode(NativePlatformBackedStat.java:32)
    at org.gradle.internal.nativeplatform.filesystem.GenericFileSystem.getUnixMode(GenericFileSystem.java:56)
    at org.gradle.api.internal.file.DefaultFileTreeElement.getMode(DefaultFileTreeElement.java:67)
    at org.gradle.api.internal.file.AbstractFileTreeElement.copyTo(AbstractFileTreeElement.java:76)
    at org.gradle.api.internal.file.copy.DefaultFileCopyDetails.copyTo(DefaultFileCopyDetails.java:104)
    at org.gradle.api.internal.file.copy.FileCopyAction$FileCopyDetailsInternalAction.processFile(FileCopyAction.java:44)
    at org.gradle.api.internal.file.copy.NormalizingCopyActionDecorator$1.maybeVisit(NormalizingCopyActionDecorator.java:97)
    at org.gradle.api.internal.file.copy.NormalizingCopyActionDecorator$1.maybeVisit(NormalizingCopyActionDecorator.java:87)
    at org.gradle.api.internal.file.copy.NormalizingCopyActionDecorator$1.access$000(NormalizingCopyActionDecorator.java:52)
    at org.gradle.api.internal.file.copy.NormalizingCopyActionDecorator$1$1.processFile(NormalizingCopyActionDecorator.java:64)
    at org.gradle.api.internal.file.copy.DuplicateHandlingCopyActionDecorator$1$1.processFile(DuplicateHandlingCopyActionDecorator.java:60)
    at org.gradle.api.internal.file.copy.CopyFileVisitorImpl.processFile(CopyFileVisitorImpl.java:60)
    at org.gradle.api.internal.file.copy.CopyFileVisitorImpl.visitFile(CopyFileVisitorImpl.java:44)
    at org.gradle.api.internal.file.collections.DirectoryFileTree.walkDir(DirectoryFileTree.java:157)
    at org.gradle.api.internal.file.collections.DirectoryFileTree.walkDir(DirectoryFileTree.java:172)
    at org.gradle.api.internal.file.collections.DirectoryFileTree.walkDir(DirectoryFileTree.java:172)
    at org.gradle.api.internal.file.collections.DirectoryFileTree.visitFrom(DirectoryFileTree.java:125)
    at org.gradle.api.internal.file.collections.DirectoryFileTree.visit(DirectoryFileTree.java:115)
    at org.gradle.api.internal.file.collections.FileTreeAdapter.visit(FileTreeAdapter.java:96)
    at org.gradle.api.internal.file.CompositeFileTree.visit(CompositeFileTree.java:54)
    at org.gradle.api.internal.file.copy.CopySpecActionImpl.execute(CopySpecActionImpl.java:37)
    at org.gradle.api.internal.file.copy.CopySpecActionImpl.execute(CopySpecActionImpl.java:24)
    at org.gradle.api.internal.file.copy.DefaultCopySpec$DefaultCopySpecResolver.walk(DefaultCopySpec.java:498)
    at org.gradle.api.internal.file.copy.DefaultCopySpec$DefaultCopySpecResolver.walk(DefaultCopySpec.java:500)
    at org.gradle.api.internal.file.copy.DefaultCopySpec.walk(DefaultCopySpec.java:322)
    at org.gradle.api.internal.file.copy.DelegatingCopySpecInternal.walk(DelegatingCopySpecInternal.java:206)
    at org.gradle.api.internal.file.copy.CopySpecBackedCopyActionProcessingStream.process(CopySpecBackedCopyActionProcessingStream.java:36)
    at org.gradle.api.internal.file.copy.DuplicateHandlingCopyActionDecorator$1.process(DuplicateHandlingCopyActionDecorator.java:44)
    at org.gradle.api.internal.file.copy.NormalizingCopyActionDecorator$1.process(NormalizingCopyActionDecorator.java:56)
    at org.gradle.api.internal.file.copy.FileCopyAction.execute(FileCopyAction.java:35)
    at org.gradle.api.internal.file.copy.NormalizingCopyActionDecorator.execute(NormalizingCopyActionDecorator.java:52)
    at org.gradle.api.internal.file.copy.DuplicateHandlingCopyActionDecorator.execute(DuplicateHandlingCopyActionDecorator.java:42)
    at org.gradle.api.internal.file.copy.CopyActionExecuter.execute(CopyActionExecuter.java:38)
    at org.gradle.api.tasks.AbstractCopyTask.copy(AbstractCopyTask.java:83)
    at org.gradle.language.jvm.tasks.ProcessResources.copy(ProcessResources.java:33)
    at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:63)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.doExecute(AnnotationProcessingTaskFactory.java:218)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:211)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:200)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:579)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:562)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:80)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:61)
    ... 47 more


BUILD FAILED

Fix flaky detection of file renames on Windows

10:34:09.143  INFO    >>> Running 'can detect file moved in'
10:34:09.145  INFO    > Creating C:\tcagent1\temp\buildTmp\junit1844794372588176522\junit588397345475646162\source-outside.txt
10:34:09.145  INFO    < Created C:\tcagent1\temp\buildTmp\junit1844794372588176522\junit588397345475646162\source-outside.txt
10:34:09.196  INFO    Server thread 11404 with handle 000000000000048C running
10:34:09.196  FINE    Watching directory 'C:\tcagent1\temp\buildTmp\junit1844794372588176522\can detect file moved in'
10:34:09.197  INFO    > Expecting CREATED C:\tcagent1\temp\buildTmp\junit1844794372588176522\can detect file moved in\target-inside.txt
10:34:09.197  FINE    Change detected: 0x1 'C:\tcagent1\temp\buildTmp\junit1844794372588176522\can detect file moved in\target-inside.txt'
10:34:09.198  INFO    > Received  CREATED C:\tcagent1\temp\buildTmp\junit1844794372588176522\can detect file moved in\target-inside.txt
10:34:09.198  FINE    Watching directory 'C:\tcagent1\temp\buildTmp\junit1844794372588176522\can detect file moved in'
10:34:09.198  FINE    Change detected: 0x3 'C:\tcagent1\temp\buildTmp\junit1844794372588176522\can detect file moved in\target-inside.txt'
10:34:09.199  INFO    > Received  MODIFIED C:\tcagent1\temp\buildTmp\junit1844794372588176522\can detect file moved in\target-inside.txt
10:34:09.199  FINE    Watching directory 'C:\tcagent1\temp\buildTmp\junit1844794372588176522\can detect file moved in'
10:34:09.201  FINE    Requesting termination of server thread 000000000000048C
10:34:09.201  INFO    Finished watching 'C:\tcagent1\temp\buildTmp\junit1844794372588176522\can detect file moved in'
10:34:09.201  INFO    Server thread 11404 finishing
10:34:09.202  INFO    Termination of server thread 000000000000048C finished normally
10:34:09.202  INFO    <<< Finished 'can detect file moved in'

and:

10:34:08.906  INFO    >>> Running 'can detect file renamed'
10:34:08.907  INFO    > Creating C:\tcagent1\temp\buildTmp\junit6545636757211262256\can detect file renamed\source.txt
10:34:08.907  INFO    < Created C:\tcagent1\temp\buildTmp\junit6545636757211262256\can detect file renamed\source.txt
10:34:08.959  INFO    Server thread 7796 with handle 000000000000048C running
10:34:08.960  FINE    Watching directory 'C:\tcagent1\temp\buildTmp\junit6545636757211262256\can detect file renamed'
10:34:08.961  INFO    > Expecting REMOVED C:\tcagent1\temp\buildTmp\junit6545636757211262256\can detect file renamed\source.txt
10:34:08.967  FINE    Change detected: 0x4 'C:\tcagent1\temp\buildTmp\junit6545636757211262256\can detect file renamed\source.txt'
10:34:08.967  INFO    > Received  REMOVED C:\tcagent1\temp\buildTmp\junit6545636757211262256\can detect file renamed\source.txt
10:34:08.968  FINE    Watching directory 'C:\tcagent1\temp\buildTmp\junit6545636757211262256\can detect file renamed'
10:34:08.968  FINE    Change detected: 0x3 'C:\tcagent1\temp\buildTmp\junit6545636757211262256\can detect file renamed\target.txt'
10:34:08.969  INFO    > Received  MODIFIED C:\tcagent1\temp\buildTmp\junit6545636757211262256\can detect file renamed\target.txt
10:34:08.975  FINE    Watching directory 'C:\tcagent1\temp\buildTmp\junit6545636757211262256\can detect file renamed'
10:34:09.077  FINE    Requesting termination of server thread 000000000000048C
10:34:09.080  INFO    Finished watching 'C:\tcagent1\temp\buildTmp\junit6545636757211262256\can detect file renamed'
10:34:09.081  INFO    Server thread 7796 finishing
10:34:09.082  INFO    Termination of server thread 000000000000048C finished normally
10:34:09.082  INFO    <<< Finished 'can detect file renamed'

Use UTF16 in macOS watcher

JNI's modified UTF has issues we should avoid. Using UTF16 instead of UTF7/8 everywhere where it is possible would help fix this.

Doing so would also allow easier code sharing with Windows where UTF16 is the norm.

Notes on converting UTF8 char* to wstring: https://riptutorial.com/cplusplus/example/4190/conversion-to-std--wstring

We can then use env->NewString() instead of NewStringUTF().

On the reverse side we can use env->GetStringCritical() to access the UTF16 character array directly instead of using java_to_char().

We should also add a test for 4-byte UTF characters, something that is not supported when using env->NewStringUTF() for example.

Unable to stat files with UTF characters

We ran into a project with a file with an emoji filename (no really), and looks like stat chokes:

Caused by: net.rubygrapefruit.platform.NativeException: Could not get UNIX mode on /mnt/builds/slave/workspace/project/src/node_modules/.bin/🐹: file does not exist.
	at net.rubygrapefruit.platform.internal.DefaultPosixFiles.getMode(DefaultPosixFiles.java:68)
	at org.gradle.internal.nativeintegration.filesystem.services.NativePlatformBackedStat.getUnixMode(NativePlatformBackedStat.java:34)
	at org.gradle.internal.nativeintegration.filesystem.services.GenericFileSystem.getUnixMode(GenericFileSystem.java:74)
	... 83 more

I'd guess if this affects emojis, it might affect any file UTF-8 characters?

Produce release variant from file-watcher native library

We currently only produce a debug variant of the file-watcher native library. Perhaps we'll never use a release version in gradle/gradle, but testing the native code without the handholding of a debug output could uncover some bugs.

Java 11 and later - Process.setWorkingDirectory() has inconsistent behavior

On macOS High Sierra and CentOS 7 (not sure about other OSes), the same code snippet will print different values on Java < 11 and Java >= 11

        Process p = Native.get(Process.class);

        System.out.println("Setting working dir to /");
        p.setWorkingDirectory(new File("/"));

        System.out.println(new File("build.gradle").exists());
        System.out.println(new File(new File("build.gradle").getAbsolutePath()).exists());

On Java 8, it will print: false false (i.e. working directory was changed successfully)
On Java 11, it will print: false true (i.e. working directory was NOT changed correctly)

To reproduce the issue: Unzip the attached zip file and run below commands (make sure to cd into project directory before running "gradlew run")
gradle-native.zip

$ cd gradle-native/
$ ./gradlew run

> Task :run
Setting working dir to /
false
true

OSX Xpc support?

Hi.

I am thinking of bridging Java to OSX Xpc calls. Is this something that can (or is in the scope of) be added to this library?

The reason for using Xpc on OSX is to implement as simple BLE (Bluetooth Low Energy) lib on top of it. Bluecove (Java BL lib) is always problematic and I want to create a more robust lib based on how NodeJS Noble lib does it (https://github.com/sandeepmistry/noble).

BR,
Sten Roger

Windows file watcher reports renames incorrectly

The Windows native watcher currently sends one event for the removal of the source path, and no event for the target path.

For some reason we get events like this when renaming source.txt to target.txt in a watched directory:

~~~~ Configuring...
~~~~ Watching C:\Users\vmadmin\AppData\Local\Temp\junit3569962616360979317\junit2117301140375774919\
~~~~ Starting thread
~~~~ Changed: 4 C:\Users\vmadmin\AppData\Local\Temp\junit3569962616360979317\junit2117301140375774919\source.txt
~~~~ Changed: 3 C:\Users\vmadmin\AppData\Local\Temp\junit3569962616360979317\junit2117301140375774919
~~~~ Ignoring C:\Users\vmadmin\AppData\Local\Temp\junit3569962616360979317\junit2117301140375774919 (root is not watched)
~~~~ Stopping thread

The event we get for source.txt (4 = FILE_ACTION_RENAMED_OLD_NAME) is correct, but we should be getting a number 5 event (FILE_ACTION_RENAMED_OLD_NAME) for target.txt according to the (docs)[https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-file_notify_information]. Instead we get a 3 (FILE_ACTION_MODIFIED ) for the parent directory.

Building with Glibc 2.3.4....

The comments says that this should work with Java 5 or newer. I'm trying to build it with java 1.6.0_45 because I need a version of libnative-platform.so that is NOT dependent on GLIBC_2.4. (which java 1.6 is not). note the machine I'm building on is a Rhel4 (hence the reason why it is stuck on glibc 2.3.4)

Unfortunatley, building this with gradle in an environment with glibc 2.3.4 doesn't work.

Is there any way to build this library with glibc 2.3.4?

PosixFileFunctions.stat fails with UnsatisfiedLinkError in Linux for Gradle 2.3

gradle build fails in my DEV environment. My colleagues have the same configuration as that of mine but it works fine for them. Also, I was able to execute the build command successfully last week.

Environment configuration:

Gradle 2.3
Groovy: 2.3.9
Ant: Apache Ant(TM) version 1.9.3 compiled on December 23 2013
JVM: 1.8.0_73 (Oracle Corporation 25.73-b02)
OS: Linux 2.6.32-300.3.1.el6uek.x86_64 amd64

Task:

task updateLibraries {
   delete "lib/compile"
   delete "lib/test"
   // error at the line below
   copy {
       from configurations.compile.copy()
       into( 'lib/compile' )
    }
    copy {
       from configurations.testCompile.copy()
       into( 'lib/test' )
    }
 }

Error:


FAILURE: Build failed with an exception.

Where:
Build file '/home/user/ProjectName/build.gradle' line: 303

What went wrong:
A problem occurred evaluating root project 'ProjectName'.

net.rubygrapefruit.platform.internal.jni.PosixFileFunctions.stat(Ljava/lang/String;Lnet/rubygrapefruit/platform/internal/FileStat;Lnet/rubygrapefruit/platform/internal/FunctionResult;)V
Try:
Run with --info or --debug option to get more log output.

Exception is:

org.gradle.api.GradleScriptException: A problem occurred evaluating root project 'ProjectName'.
at org.gradle.groovy.scripts.internal.DefaultScriptRunnerFactory$ScriptRunnerImpl.run(DefaultScriptRunnerFactory.java:54)
at org.gradle.configuration.DefaultScriptPluginFactory$ScriptPluginImpl.apply(DefaultScriptPluginFactory.java:154)
at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:39)
at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:26)
at org.gradle.configuration.project.ConfigureActionsProjectEvaluator.evaluate(ConfigureActionsProjectEvaluator.java:34)
at org.gradle.configuration.project.LifecycleProjectEvaluator.evaluate(LifecycleProjectEvaluator.java:59)
at org.gradle.api.internal.project.AbstractProject.evaluate(AbstractProject.java:492)
at org.gradle.api.internal.project.AbstractProject.evaluate(AbstractProject.java:86)
at org.gradle.execution.TaskPathProjectEvaluator.configureHierarchy(TaskPathProjectEvaluator.java:42)
at org.gradle.configuration.DefaultBuildConfigurer.configure(DefaultBuildConfigurer.java:35)
at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:129)
at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:106)
at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:86)
at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:80)
at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:33)
at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:24)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:36)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:26)
at org.gradle.launcher.cli.RunBuildAction.run(RunBuildAction.java:51)
at org.gradle.internal.Actions$RunnableActionAdapter.execute(Actions.java:169)
at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:237)
at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:210)
at org.gradle.launcher.cli.JavaRuntimeValidationAction.execute(JavaRuntimeValidationAction.java:35)
at org.gradle.launcher.cli.JavaRuntimeValidationAction.execute(JavaRuntimeValidationAction.java:24)
at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:206)
at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:169)
at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:33)
at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:22)
at org.gradle.launcher.Main.doAction(Main.java:33)
at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:45)
at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:54)
at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:35)
at org.gradle.launcher.GradleMain.main(GradleMain.java:23)

Caused by: java.lang.UnsatisfiedLinkError: net.rubygrapefruit.platform.internal.jni.PosixFileFunctions.stat(Ljava/lang/String;Lnet/rubygrapefruit/platform/internal/FileStat;Lnet/rubygrapefruit/platform/internal/FunctionResult;)V
at net.rubygrapefruit.platform.internal.jni.PosixFileFunctions.stat(Native Method)
at net.rubygrapefruit.platform.internal.DefaultPosixFiles.stat(DefaultPosixFiles.java:30)
at net.rubygrapefruit.platform.internal.DefaultPosixFiles.getMode(DefaultPosixFiles.java:46)
at org.gradle.internal.nativeintegration.filesystem.services.NativePlatformBackedStat.getUnixMode(NativePlatformBackedStat.java:33)
at org.gradle.internal.nativeintegration.filesystem.services.GenericFileSystem.getUnixMode(GenericFileSystem.java:61)
at org.gradle.api.internal.file.DefaultFileTreeElement.getMode(DefaultFileTreeElement.java:67)
at org.gradle.api.internal.file.AbstractFileTreeElement.copyTo(AbstractFileTreeElement.java:76)
at org.gradle.api.internal.file.copy.DefaultFileCopyDetails.copyTo(DefaultFileCopyDetails.java:104)
at org.gradle.api.internal.file.copy.FileCopyAction$FileCopyDetailsInternalAction.processFile(FileCopyAction.java:44)
at org.gradle.api.internal.file.copy.NormalizingCopyActionDecorator$1$1.processFile(NormalizingCopyActionDecorator.java:65)
at org.gradle.api.internal.file.copy.DuplicateHandlingCopyActionDecorator$1$1.processFile(DuplicateHandlingCopyActionDecorator.java:60)
at org.gradle.api.internal.file.copy.CopyFileVisitorImpl.processFile(CopyFileVisitorImpl.java:60)
at org.gradle.api.internal.file.copy.CopyFileVisitorImpl.visitFile(CopyFileVisitorImpl.java:44)
at org.gradle.api.internal.file.AbstractFileTree$FilteredFileTree$1.visitFile(AbstractFileTree.java:145)
at org.gradle.api.internal.file.collections.SingletonFileTree.visit(SingletonFileTree.java:43)
at org.gradle.api.internal.file.collections.FileTreeAdapter.visit(FileTreeAdapter.java:96)
at org.gradle.api.internal.file.AbstractFileTree$FilteredFileTree.visit(AbstractFileTree.java:136)
at org.gradle.api.internal.file.CompositeFileTree.visit(CompositeFileTree.java:54)
at org.gradle.api.internal.file.copy.CopySpecActionImpl.execute(CopySpecActionImpl.java:37)
at org.gradle.api.internal.file.copy.CopySpecActionImpl.execute(CopySpecActionImpl.java:24)
at org.gradle.api.internal.file.copy.DefaultCopySpec$DefaultCopySpecResolver.walk(DefaultCopySpec.java:498)
at org.gradle.api.internal.file.copy.DefaultCopySpec.walk(DefaultCopySpec.java:322)
at org.gradle.api.internal.file.copy.DelegatingCopySpecInternal.walk(DelegatingCopySpecInternal.java:206)
at org.gradle.api.internal.file.copy.CopySpecBackedCopyActionProcessingStream.process(CopySpecBackedCopyActionProcessingStream.java:36)
at org.gradle.api.internal.file.copy.DuplicateHandlingCopyActionDecorator$1.process(DuplicateHandlingCopyActionDecorator.java:44)
at org.gradle.api.internal.file.copy.NormalizingCopyActionDecorator$1.process(NormalizingCopyActionDecorator.java:56)
at org.gradle.api.internal.file.copy.FileCopyAction.execute(FileCopyAction.java:35)
at org.gradle.api.internal.file.copy.NormalizingCopyActionDecorator.execute(NormalizingCopyActionDecorator.java:52)
at org.gradle.api.internal.file.copy.DuplicateHandlingCopyActionDecorator.execute(DuplicateHandlingCopyActionDecorator.java:42)
at org.gradle.api.internal.file.copy.CopyActionExecuter.execute(CopyActionExecuter.java:38)
at org.gradle.api.internal.file.copy.FileCopier.doCopy(FileCopier.java:64)
at org.gradle.api.internal.file.copy.FileCopier.copy(FileCopier.java:49)
at org.gradle.api.internal.file.DefaultFileOperations.copy(DefaultFileOperations.java:125)
at org.gradle.api.internal.project.AbstractProject.copy(AbstractProject.java:746)
at org.gradle.groovy.scripts.DefaultScript.copy(DefaultScript.java:169)
at org.gradle.groovy.scripts.DefaultScript.copy(DefaultScript.java:165)
at build_3o7k207plxbmxd2hy7hl6sbsq$runclosure22.doCall(/home/user/ProjectName/build.gradle:303)
at org.gradle.api.internal.ClosureBackedAction.execute(ClosureBackedAction.java:67)
at org.gradle.util.ConfigureUtil.configure(ConfigureUtil.java:130)
at org.gradle.util.ConfigureUtil.configure(ConfigureUtil.java:110)
at org.gradle.api.internal.AbstractTask.configure(AbstractTask.java:488)
at org.gradle.api.internal.project.AbstractProject.task(AbstractProject.java:851)
at org.gradle.api.internal.BeanDynamicObject$MetaClassAdapter.invokeMethod(BeanDynamicObject.java:225)
at org.gradle.api.internal.BeanDynamicObject.invokeMethod(BeanDynamicObject.java:129)
at org.gradle.api.internal.CompositeDynamicObject.invokeMethod(CompositeDynamicObject.java:147)
at org.gradle.groovy.scripts.BasicScript.methodMissing(BasicScript.java:79)
at build_3o7k207plxbmxd2hy7hl6sbsq.run(/home/user/ProjectName/build.gradle:299)
at org.gradle.groovy.scripts.internal.DefaultScriptRunnerFactory$ScriptRunnerImpl.run(DefaultScriptRunnerFactory.java:52)
... 32 more
BUILD FAILED

macOS file watcher crashes in `printlog()`

A couple failures like this here: https://builds.gradle.org/buildConfiguration/Gradle_Check_VfsRetention_32_bucket12/31251294

Stack: [0x0000700008166000,0x00007000081e6000],  sp=0x00007000081df8b0,  free space=486k
Native frames: (J=compiled Java code, A=aot compiled Java code, j=interpreted, Vv=VM code, C=native code)
C  [libnative-platform.dylib+0x17c4]  JNIEnv_::NewStringUTF(char const*)+0x14
C  [libnative-platform.dylib+0x1b4a]  printlog+0x23a
C  [libnative-platform.dylib+0x3aef]  callback(__FSEventStream const*, void*, unsigned long, void*, unsigned int const*, unsigned long long const*)+0x8f
C  [FSEvents+0x289a]  implementation_callback_rpc+0xb6e
C  [FSEvents+0x1caf]  _Xcallback_rpc+0xe9
C  [FSEvents+0x1ba9]  FSEventsD2F_server+0x37
C  [FSEvents+0x4629]  FSEventsClientProcessMessageCallback+0x2e
C  [CoreFoundation+0x52cd5]  __CFMachPortPerform+0xfa
C  [CoreFoundation+0x52bd1]  __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__+0x29
C  [CoreFoundation+0x52b24]  __CFRunLoopDoSource1+0x21d
C  [CoreFoundation+0x3ab7f]  __CFRunLoopRun+0xa42
C  [CoreFoundation+0x39ec8]  CFRunLoopRunSpecific+0x1f7
C  [CoreFoundation+0x39c9d]  CFRunLoopRun+0x28
C  [libnative-platform.dylib+0x3cfe]  EventProcessingThread(void*)+0x9e
C  [libsystem_pthread.dylib+0x5d36]  _pthread_start+0x7d
C  [libsystem_pthread.dylib+0x258f]  thread_start+0xf

Expose a way to indicate if standard input is attached to console

The class Terminals can already detect if standard output and error is attached to console with the help of the method isTerminal(Output). Additionally, a method should be available to indicate if standard input can be used from the console with the goal to know if the console is interactive or non-interactive.

Update native log level automatically

Currently the log level for the watcher Logger is stored on the native side upon initializing the logging. However, in a Java application, the log level can change. Indeed, in gradle/gradle we'd like to let the user alter the log level for file watching.

Ideally, we should query the log level whenever we try to log any message, but this would be prohibitively expensive; one of the two goals of checking the log level on the native side is to avoid having to call through JNI (the other being to avoid the cost of sprintf()).

We could do an alternative, and cache the log level on the native side with a relatively short timeout, such as one second. This way we'd update the native log level frequently enough, but wouldn't incur the cost too often.

If we did this the logging would not need to be initialized, making the code simpler.

Please clarify license for the published artifacts

native-platform project publishes a lot of jar files, however they do not mention which license is in place.

  1. Please add Bundle-License: Apache-2.0 manifest entry (where Apache-2.0 is SPDX identifier, see https://osgi.org/specification/osgi.core/7.0.0/framework.module.html#framework.module-bundle-license )
    Well, current pom.xml tags are quite obvious (even though you might want to replace <licence><name> with SPDX id of Apache-2.0), however adding explicit Bundle-License would simplify automatic analysis.

  2. Please add LICENSE file to the produced jar files.
    The suggested file locations is META-INF/LICENSE

  3. You might want to mention the license in pom.xml via <license> tag, however it is not that required.

Provide a method to get the system hostname

The native-platform project is really cool. Just discovered it today and really liking it! Thanks for it.

I would like to suggest that the native-platform project should provide a method for retrieving the system hostname. There's really no good and reliable way to do this using pure Java. But it's a very common requirement -- along with getting the current process PID -- for many applications.

There's another project https://github.com/mattsheppard/gethostname4j by @mattsheppard which already provides this functionality. It's MIT LICENSE. It may make sense to leverage that code or perhaps even merge that project this into this one.

Keep up the good work!

Handle timeouts in file watchers

Currently we are waiting on things forever in several places in the file watcher code. We should stop after a few seconds probably and break instead.

Drop Java 5 and 6 support

We should supporting Java 5 and 6 with native-platform, since there is not much value in keeping the support around and it complicates things for the newer things we do like file watching.

That means we can rise the target compatibility to Java 7.

We should also remove the features that provide backports of Java 7 APIs.

Platforms built without a separate `libtinfo.so` fail to detect terminal

native-platform links against libtinfo.so, but the symbols for this library can also be found in libncurses for some platforms (those built without --with-termlib).

This causes Gradle to fail to detect that the console supports rich output (ANSI codes, colors, etc).

Symlinking libtinfo.so.6 to libncurses.so.6 is enough to work around this.

Consider starting processor thread from Java

From Android's JNI tips:

It's usually best to use Thread.start() to create any thread that needs to call in to Java code. Doing so will ensure that you have sufficient stack space, that you're in the correct ThreadGroup, and that you're using the same ClassLoader as your Java code. It's also easier to set the thread's name for debugging in Java than from native code (see pthread_setname_np() if you have a pthread_t or thread_t, and std::thread::native_handle() if you have a std::thread and want a pthread_t).

Use batch API for (un)registering watches

On Linux an application typically registers a large number of watch points (as inotify requires each directory in a hierarchy to be registered). With the current API this takes a long time for two reasons:

  1. There's a separate call through JNI for each watch point to (un)register it. JNI being slow this adds quite a bit of overhead. (We also call back to Java to log the fact of the registration, which can add to the overhead. This is going to be made better in #128.)
  2. Each watch point is passed to the processing thread one-by-one, waiting for each (un)registration to finish before passing the next one. The extra context switches and synchronization probably also adds to the overhead.

We could avoid these problems if we used a batched API where the caller application could (un)register a number of paths at the same time.

The downside of a batched API is that we can't return individual errors about the registrations. This might be acceptable if the caller application would stop watching if any error occurred.

We could also return a number of exceptions, or some other error descriptor so the caller application could decide which watches have been registered, and which didn't. The caller could also provide an error handler that would be called if there's a problem.

Stop doing sneaky things :)

Gradle that uses your code doesn't work with latest build of jdk9 jigsaw (build 136 on 09-15-2016 )
https://jdk9.java.net/jigsaw/
because trying to to remove the unmodifiableMap wrapper of the return value of System.getEnv() [1] is not allowed with jigsaw.

Basically, you can not use setAccessible on any platform modules (java., jdk.) code anymore.

regards,
Rémi

https://github.com/adammurdoch/native-platform/blob/master/src/main/java/net/rubygrapefruit/platform/internal/WrapperProcess.java#L109

error open terminal

I am trying to run gradle command that running on centos from shell in os x and I am having the following error

net.rubygrapefruit.platform.NativeException: Could not open terminal for stdout: could not create locale
    at net.rubygrapefruit.platform.internal.TerminfoTerminal.init(TerminfoTerminal.java:29)
    at net.rubygrapefruit.platform.internal.WrapperTerminal.init(WrapperTerminal.java:25)
    at net.rubygrapefruit.platform.internal.AbstractTerminals.getTerminal(AbstractTerminals.java:19)
    at org.gradle.internal.nativeplatform.console.NativePlatformConsoleDetector.getConsole(NativePlatformConsoleDetector.java:42)
    at org.gradle.logging.internal.ConsoleConfigureAction.execute(ConsoleConfigureAction.java:32)
    at org.gradle.logging.internal.ConsoleConfigureAction.execute(ConsoleConfigureAction.java:27)
    at org.gradle.logging.internal.OutputEventRenderer.attachConsole(OutputEventRenderer.java:68)
    at org.gradle.logging.internal.DefaultLoggingManager.attachConsole(DefaultLoggingManager.java:149)
    at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:168)
    at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:139)
    at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:33)
    at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:22)
    at org.gradle.launcher.Main.doAction(Main.java:48)
    at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:45)
    at org.gradle.launcher.Main.main(Main.java:39)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:50)
    at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:32)
    at org.gradle.launcher.GradleMain.main(GradleMain.java:26)

when I am running from windows shell it works fine

Allow timeouts to be configured for file watching

We should make the following timeouts configurable:

  • ALL: event offering timeout before we declare an OVERFLOWED
  • ALL: termination timeout
  • Windows: execute on thread timeout

The basic option is to pass them in the WatcherBuilder, e.g. WatcherBuilder.withEventProcessingTimeout(5, SECONDS).

For termination we could also use this, or we switch away from close() and instead introduce something like terminateAndWaitFor(5, SECONDS). Another option is to implement something similar to what ExecutorService does with shutdown() + awaitTermination().

GetConsoleScreenBufferInfo return error on win7-amd64, but native program works.

net.rubygrapefruit.platform.NativeException: Could not open console for stdout: not a console
at net.rubygrapefruit.platform.internal.WindowsTerminal.init(WindowsTerminal.java:46)
at net.rubygrapefruit.platform.internal.WrapperTerminal.init(WrapperTerminal.java:41)
at net.rubygrapefruit.platform.internal.AbstractTerminals.getTerminal(AbstractTerminals.java:35)
at com.dinus.native_platform.demo.NativeDemo.main(NativeDemo.java:21)

win 7, amd64
with native-platform: 0.10/0.11

debug it:
Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_initConsole:
if (!GetConsoleScreenBufferInfo(handle, &console_info)) {
if (GetLastError() == ERROR_INVALID_HANDLE) {
mark_failed_with_message(env, "not a console", result); // issue, here

But, I has tried in Visual Studio to write native C++ program , it works.

Unhandled failure case for GetFileInformationByHandleEx when STD handles are pipes

This Gradle issue expose an interesting system configuration which cause GetFileInformationByHandleEx to fail with ERROR_INVALID_FUNCTION under a scenario where the STD handles are pipes on, what appears to be, very specific driver usage. Unfortunately, the reproduction case is still unknown but I will document what have been found.

I could only successfully creating STD handles as pipe when running on mintty with Cygwin 3. However, even with this setup the GetFileInformationByHandleEx function succeeded properly. The most plausible answer for the API call to return invalid function error is the underlying driver doesn't handle the IRP sent to it or it simply fail for some other reason which cause the invalid function error to be returned. Assuming this is correct, the possible scenarios could be where custom drivers would be used which involves containers, some sort of virtualization, network drives or specialized hardware. It seems the Gradle errors is flaky which makes it harder to narrow the issue further.

A better alternative could be to use NtQueryObject API instead. I can't confirmed yet if the API goes through the driver. The feeling is it's a Kernel call that return information from the object store.

Turn OS error codes into strings

Linux has strerror(), Windows has FormatMessage (see here). We should use these to turn error codes into strings when constructing our exceptions.

Fix `watch_all_parents: error trying to add kqueue for fd` warnings

When running the test task on master (ca15a65), the following output occurs:

2020-02-26 08:46 java[94718] (FSEvents.framework) process_dir_events: watch_all_parents: error trying to add kqueue for fd 52 (/private/var/folders/y8/lns4s7jn3jldwky0nm3dmx9m0000gn/T; Bad file descriptor)
2020-02-26 08:46 java[94718] (FSEvents.framework) process_dir_events: watch_all_parents: error trying to add kqueue for fd 47 (/private/var/folders/y8/lns4s7jn3jldwky0nm3dmx9m0000gn; Bad file descriptor)
2020-02-26 08:46 java[94718] (FSEvents.framework) process_dir_events: watch_all_parents: error trying to add kqueue for fd 51 (/private/var/folders/y8; Bad file descriptor)
2020-02-26 08:46 java[94718] (FSEvents.framework) process_dir_events: watch_all_parents: error trying to add kqueue for fd 53 (/private/var/folders; Bad file descriptor)
2020-02-26 08:46 java[94718] (FSEvents.framework) process_dir_events: watch_all_parents: error trying to add kqueue for fd 54 (/private/var; Bad file descriptor)
2020-02-26 08:46 java[94718] (FSEvents.framework) process_dir_events: watch_all_parents: error trying to add kqueue for fd 55 (/private; Bad file descriptor)
2020-02-26 08:46 java[94718] (FSEvents.framework) process_dir_events: watch_all_parents: error trying to add kqueue for fd 54 (/private/var/folders; Bad file descriptor)
2020-02-26 08:46 java[94718] (FSEvents.framework) process_dir_events: watch_all_parents: error trying to add kqueue for fd 47 (/private/var; Bad file descriptor)
2020-02-26 08:46 java[94718] (FSEvents.framework) process_dir_events: watch_all_parents: error trying to add kqueue for fd 52 (/private; Bad file descriptor)

We should understand what is going on there.

See https://e.grdev.net/s/6ma7wj7x5i2bu/console-log?anchor=72.

FTBFS with Gradle 1.3 release

Hi,

native-plaform actually depends on a specific (1.3-20120907220018+0000) snapshot of Gradle. "gradlew" take care of bootstraping it.
Bu when trying to build native-platform fails from source with Gradle 1.3 official release, I got the following exception :

FAILURE: Build failed with an exception.

* Where:
Build file '/home/drazzib/Dev/debian-pkg/work/gradle/native-platform-0.2/build.gradle' line: 89

* What went wrong:
A problem occurred evaluating root project 'native-platform'.
> Failed to notify action.
   > No such property: task for class: org.gradle.plugins.cpp.gpp.GppLibraryCompileSpec
     Possible solutions: name, ting, class

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

It seems to be using deprecated API :

The GppCompileSpec.getTask() method has been deprecated and will be removed in the next version of Gradle.
The Binary.getProject() method has been deprecated and will be removed in the next version of Gradle.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.