Skip to content

Commit

Permalink
Last batch of trial on gradle's native-platform
Browse files Browse the repository at this point in the history
This is the last batch, because native-platform uses macOs's fsevents
to handle file events, which does not pickup all file changes.
While `tail` is based on BSD's kqueue, and report correctly file
changes.

This finding has been confirmed with the tool fswatch (it implements
various way to watch files ; on macos: fsevents, kqueue, or polling).

Reference issues :
* gradle/native-platform#269
* emcrisostomo/fswatch#265
  • Loading branch information
bric3 committed Jan 12, 2021
1 parent cab6970 commit 05443b0
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 18 deletions.
30 changes: 26 additions & 4 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask
import de.undercouch.gradle.tasks.download.Download

plugins {
application
id("de.undercouch.download") version ("4.1.1")
id("com.github.johnrengelman.shadow") version ("6.1.0")
id("com.github.ben-manes.versions") version ("0.36.0")
}

repositories {
jcenter()

maven {
setUrl("https://dl.bintray.com/adammurdoch/maven")
setUrl("https://repo.gradle.org/gradle/libs/")
}
}

dependencies {
implementation("net.rubygrapefruit:file-events:0.22-milestone-7")
implementation("net.rubygrapefruit:native-platform:0.22-milestone-7")
implementation("net.rubygrapefruit:file-events:0.22-milestone-10")
implementation("net.rubygrapefruit:native-platform:0.22-milestone-10")

implementation("net.rubygrapefruit:native-platform-test:0.22-milestone-10")
implementation ("net.sf.jopt-simple:jopt-simple:5.0.4")

implementation("com.google.guava:guava:30.1-jre")
implementation("info.picocli:picocli:4.6.1")
annotationProcessor("info.picocli:picocli-codegen:4.6.1")
Expand Down Expand Up @@ -77,7 +84,22 @@ tasks {
)
}
}
}

named("dependencyUpdates", DependencyUpdatesTask::class.java).configure {
fun isNonStable(version: String): Boolean {
val stableKeyword = listOf("RELEASE", "FINAL", "GA").any { version.toUpperCase().contains(it) }
val regex = "^[0-9,.v-]+(-r)?$".toRegex()
val isStable = stableKeyword || regex.matches(version)
return isStable.not()
}

fun isSnapshot(version: String): Boolean {
return listOf("SNAPSHOT", "ALPHA").any { version.toUpperCase().contains(it) }
}

// Example 2: disallow release candidates as upgradable versions from stable versions
rejectVersionIf {
isSnapshot(candidate.version) || (isNonStable(candidate.version) && !isNonStable(currentVersion))
}
}
}
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-rc-5-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
59 changes: 46 additions & 13 deletions src/main/java/com/github/bric3/drain/GradleFileWatcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,37 @@
import net.rubygrapefruit.platform.file.FileWatchEvent;
import net.rubygrapefruit.platform.file.FileWatcher;
import net.rubygrapefruit.platform.internal.Platform;
import net.rubygrapefruit.platform.internal.jni.LinuxFileEventFunctions;
import net.rubygrapefruit.platform.internal.jni.OsxFileEventFunctions;
import net.rubygrapefruit.platform.internal.jni.WindowsFileEventFunctions;
import net.rubygrapefruit.platform.internal.jni.*;
import net.rubygrapefruit.platform.test.Main;

import java.nio.file.Path;
import java.util.List;
import java.util.Arrays;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

public class GradleFileWatcher {

public static void main(String[] args) throws Exception {
// watch(Path.of("/Users/bric3/Library/Logs/JetBrains/IntelliJIdea2020.3/idea.log"));


public static void watch(Path path) throws InterruptedException {
// LogManager.getLogManager().getLogger(NativeLogger.class.getCanonicalName()).setLevel(Level.ALL);

Main.main(new String[] {"--machine"});
Main.main(args);
}

public static void watch(Path... paths) throws InterruptedException {
var fileNames = Arrays.stream(paths)
.map(Path::getFileName)
.map(Path::toString)
.collect(Collectors.toSet());

final BlockingQueue<FileWatchEvent> eventQueue = new ArrayBlockingQueue<>(16);
Thread processorThread = new Thread(() -> {
final AtomicBoolean terminated = new AtomicBoolean(false);
Expand All @@ -34,6 +49,8 @@ public static void watch(Path path) throws InterruptedException {
@Override
public void handleChangeEvent(FileWatchEvent.ChangeType type, String absolutePath) {
System.out.printf("Change detected: %s / '%s'%n", type, absolutePath);
if (fileNames.stream().anyMatch(absolutePath::endsWith)) {
}
}

@Override
Expand All @@ -60,12 +77,12 @@ public void handleTerminated() {
}
}, "File watcher event handler");
processorThread.start();
FileWatcher watcher = createWatcher(path, eventQueue);
FileWatcher watcher = createWatcher(eventQueue, paths);
try {
System.out.println("Waiting - type ctrl-d to exit ...");
System.out.println("Waiting - type 'q' to exit ...");
while (true) {
int ch = System.in.read();
if (ch < 0) {
if (ch == 'q') {
break;
}
}
Expand All @@ -80,24 +97,40 @@ public void handleTerminated() {
}


private static FileWatcher createWatcher(Path path, BlockingQueue<FileWatchEvent> eventQueue) throws InterruptedException {
private static FileWatcher createWatcher(BlockingQueue<FileWatchEvent> eventQueue, Path... paths) throws InterruptedException {
FileWatcher watcher;
Logger.getLogger(NativeLogger.class.getName()).setLevel(Level.ALL);

if (Platform.current().isMacOs()) {
FileEvents.get(OsxFileEventFunctions.class).invalidateLogLevelCache();
watcher = FileEvents.get(OsxFileEventFunctions.class)
.newWatcher(eventQueue)
// .withLatency(100, TimeUnit.MILLISECONDS)
.start();
} else if (Platform.current().isLinux()) {
watcher = FileEvents.get(LinuxFileEventFunctions.class)
.newWatcher(eventQueue)
.start();
} else if (Platform.current().isWindows()) {
} else {
if (!Platform.current().isWindows()) {
throw new RuntimeException("Only Windows and macOS are supported for file watching");
}

watcher = FileEvents.get(WindowsFileEventFunctions.class)
.newWatcher(eventQueue)
.start();
} else {
throw new RuntimeException("Only Windows and macOS are supported for file watching");
}
watcher.startWatching(List.of(path.toFile()));

// it seems on osx we cannot watch files directly

var parentFolder = Arrays.stream(paths)
.map(Path::getParent)
.map(Path::toFile)
.collect(Collectors.toUnmodifiableList());
System.out.printf("parent folders to watch : %s%n", parentFolder);


watcher.startWatching(parentFolder);
return watcher;
}

Expand Down

0 comments on commit 05443b0

Please sign in to comment.