Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
fabrizzio-dotCMS committed Jun 5, 2024
1 parent f1209df commit 231ca7e
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,16 @@ public class DirectoryWatcherService {
private final Logger logger = Logger.getLogger(DirectoryWatcherService.class);
private final Set<Path> paths = ConcurrentHashMap.newKeySet();
private final AtomicBoolean running = new AtomicBoolean(false);
private final AtomicBoolean suspended = new AtomicBoolean(false);


public DirectoryWatcherService() throws IOException {
watchService = FileSystems.getDefault().newWatchService();
scheduler = Executors.newScheduledThreadPool(1);
}


@SuppressWarnings("java:S1452")
public BlockingQueue<WatchEvent<?>> watch(Path path, long pollIntervalSeconds) throws IOException {
registerAll(path);
if(running.compareAndSet(false, true)){
Expand All @@ -49,10 +53,11 @@ public BlockingQueue<WatchEvent<?>> watch(Path path, long pollIntervalSeconds) t

private void processEvents() {
try{
pollEvents();
if (!suspended.get()) {
pollEvents();
}
} catch (Exception e) {
logger.error("Error processing events", e);

}
}

Expand All @@ -62,6 +67,7 @@ private void pollEvents() {
if (key != null) {
WatchEvent<?> lastEvent = null;
for (WatchEvent<?> event : key.pollEvents()) {
System.out.println("Event kind:" + event.kind() + ". File affected: " + event.context());
lastEvent = event;
}
if (lastEvent != null) {
Expand All @@ -75,6 +81,18 @@ public boolean isRunning() {
return running.get();
}

public boolean isSuspended() {
return suspended.get();
}

public void suspend() {
suspended.set(true);
}

public void resume() {
suspended.set(false);
}

public void stop() {
if (scheduler != null) {
scheduler.shutdown();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* Furthermore, it can provide the name of a custom mixin it uses, which is useful for custom
* command line configurations where specific logic may be associated with certain mixin names.
*/
public interface DotPush extends DotCommand{
public interface DotPush extends DotCommand {

/**
* Returns the {@link PushMixin} associated with the implementing class. This {@link PushMixin}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.dotcms.cli.command;

import com.dotcms.api.client.util.DirectoryWatcherService;
import com.dotcms.cli.common.AuthenticationMixin;
import com.dotcms.cli.common.CommandInterceptor;
import com.dotcms.cli.common.FullPushOptionsMixin;
Expand All @@ -11,12 +10,7 @@
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
import javax.enterprise.context.control.ActivateRequestContext;
import javax.enterprise.inject.Instance;
Expand Down Expand Up @@ -63,8 +57,6 @@ public class PushCommand implements Callable<Integer>, DotPush {
@Inject
Instance<DotPush> pushCommands;

@Inject
DirectoryWatcherService directoryWatcherService;

@Override
@CommandInterceptor
Expand All @@ -77,24 +69,6 @@ public Integer call() throws Exception {
// Validate we have a workspace at the specified path
checkValidWorkspace(pushMixin.path());

/*
if(pushMixin.isWatchOn()){
directoryWatcherService.watch(pushMixin.path(), pushMixin.interval, true, event -> {
execCommands();
});
return CommandLine.ExitCode.OK;
}
*/

final Integer exitCode = execSubCommands();
if (exitCode != null) {
return exitCode;
}

return CommandLine.ExitCode.OK;
}

private Integer execSubCommands() {
// Preparing the list of arguments to be passed to the subcommands
var expandedArgs = new ArrayList<>(spec.commandLine().getParseResult().expandedArgs());
expandedArgs.add("--noValidateUnmatchedArguments");
Expand All @@ -106,34 +80,19 @@ private Integer execSubCommands() {
.sorted(Comparator.comparingInt(DotPush::getOrder))
.collect(Collectors.toList());

// Usa ExecutorService for parallel execution of the subcommands
final ExecutorService executorService = Executors.newFixedThreadPool(pushCommandsSorted.size());
final List<Future<Integer>> futures = new ArrayList<>();

// Process each subcommand
for (var subCommand : pushCommandsSorted) {
Callable<Integer> task = () -> {
var cmdLine = createCommandLine(subCommand);
return cmdLine.execute(args);
};
futures.add(executorService.submit(task));
}

// Wait for all subcommands to finish and check for errors
for (Future<Integer> future : futures) {
try {
int exitCode = future.get();
if (exitCode != CommandLine.ExitCode.OK) {
executorService.shutdownNow();
return exitCode;
}
} catch (InterruptedException | ExecutionException e) {
executorService.shutdownNow();
throw new RuntimeException("Error executing subcommand", e);
var cmdLine = createCommandLine(subCommand);

// Use execute to parse the parameters with the subcommand
int exitCode = cmdLine.execute(args);
if (exitCode != CommandLine.ExitCode.OK) {
return exitCode;
}
}

executorService.shutdown();
return null;
return CommandLine.ExitCode.OK;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.dotcms.cli.command.DotCommand;
import com.dotcms.cli.command.DotPush;
import com.dotcms.cli.common.ApplyCommandOrder;
import com.dotcms.cli.common.CommandInterceptor;
import com.dotcms.cli.common.FullPushOptionsMixin;
import com.dotcms.cli.common.OutputOptionMixin;
import com.dotcms.cli.common.PushMixin;
Expand Down Expand Up @@ -63,6 +64,7 @@ public class ContentTypePush extends AbstractContentTypeCommand implements Calla
CommandLine.Model.CommandSpec spec;

@Override
@CommandInterceptor
public Integer call() throws Exception {

// When calling from the global push we should avoid the validation of the unmatched
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.dotcms.cli.command.DotPush;
import com.dotcms.cli.command.PushContext;
import com.dotcms.cli.common.ApplyCommandOrder;
import com.dotcms.cli.common.CommandInterceptor;
import com.dotcms.cli.common.ConsoleLoadingAnimation;
import com.dotcms.cli.common.OutputOptionMixin;
import com.dotcms.cli.common.PushMixin;
Expand Down Expand Up @@ -65,6 +66,7 @@ public class FilesPush extends AbstractFilesCommand implements Callable<Integer>
ManagedExecutor executor;

@Override
@CommandInterceptor
public Integer call() throws Exception {

// When calling from the global push we should avoid the validation of the unmatched
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.dotcms.cli.command.DotCommand;
import com.dotcms.cli.command.DotPush;
import com.dotcms.cli.common.ApplyCommandOrder;
import com.dotcms.cli.common.CommandInterceptor;
import com.dotcms.cli.common.FullPushOptionsMixin;
import com.dotcms.cli.common.OutputOptionMixin;
import com.dotcms.cli.common.PushMixin;
Expand Down Expand Up @@ -84,6 +85,7 @@ public class LanguagePush extends AbstractLanguageCommand implements Callable<In
CommandLine.Model.CommandSpec spec;

@Override
@CommandInterceptor
public Integer call() throws Exception {

// When calling from the global push we should avoid the validation of the unmatched
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.dotcms.cli.command.DotCommand;
import com.dotcms.cli.command.DotPush;
import com.dotcms.cli.common.ApplyCommandOrder;
import com.dotcms.cli.common.CommandInterceptor;
import com.dotcms.cli.common.FullPushOptionsMixin;
import com.dotcms.cli.common.OutputOptionMixin;
import com.dotcms.cli.common.PushMixin;
Expand Down Expand Up @@ -65,6 +66,7 @@ public class SitePush extends AbstractSiteCommand implements Callable<Integer>,
CommandLine.Model.CommandSpec spec;

@Override
@CommandInterceptor
public Integer call() throws Exception {

// When calling from the global push we should avoid the validation of the unmatched
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.dotcms.cli.common;

import static java.nio.file.StandardWatchEventKinds.OVERFLOW;

import com.dotcms.api.client.util.DirectoryWatcherService;
import com.dotcms.cli.command.DotPush;
import java.nio.file.Path;
Expand All @@ -22,28 +23,58 @@ public class CommandExecutionInterceptor {
@Inject
DirectoryWatcherService service;

// ThreadLocal to track the recursion depth for the interceptor
private static final ThreadLocal<Integer> callDepth = ThreadLocal.withInitial(() -> 0);

@AroundInvoke
public Object invoke(final InvocationContext context) throws Exception {
final Object target = context.getTarget();
logger.debug("Executing command: " + context.getTarget());
if (target instanceof DotPush) {
final DotPush push = (DotPush) target;
final PushMixin filesPushMixin = push.getPushMixin();
if (filesPushMixin.isWatchMode()) {
Object result = null;
final Path path = filesPushMixin.path();
final BlockingQueue<WatchEvent<?>> eventQueue = service.watch(path, filesPushMixin.interval);
while (service.isRunning()) {
final WatchEvent<?> event = eventQueue.take();
if (event.kind() == OVERFLOW) {
continue;

try {
// Increment the call depth
callDepth.set(callDepth.get() + 1);
if (callDepth.get() > 1) {
// If the call depth is greater than 1, we are in a recursive call and should not intercept
return context.proceed();
}
// otherwise, we are in the first call and should intercept
final Object target = context.getTarget();
logger.debug("Executing command: " + context.getTarget());
if (target instanceof DotPush) {
final DotPush push = (DotPush) target;
//Otherwise, we are in the first call and should intercept
final PushMixin filesPushMixin = push.getPushMixin();
if (filesPushMixin.isWatchMode()) {
push.getOutput().info("Running in Watch Mode on " + filesPushMixin.path());
Object result = null;
final Path path = filesPushMixin.path();
final BlockingQueue<WatchEvent<?>> eventQueue = service.watch(path, filesPushMixin.interval);
while (service.isRunning()) {
final WatchEvent<?> event = eventQueue.take();
if (event.kind() == OVERFLOW) {
continue;
}
try{
//Disengage the watch service to avoid recursion issues
//The command itself might trigger a file change
service.suspend();
result = context.proceed();
}finally {
//Re-engage the watch mode
service.resume();
}
}
result = context.proceed();
return result;
}
return result;
}
return context.proceed();
} finally {
// Decrement the call depth
callDepth.set(callDepth.get() - 1);
// Clean up ThreadLocal if it's no longer needed
if (callDepth.get() == 0) {
callDepth.remove();
}
}
return context.proceed();
}


Expand Down

0 comments on commit 231ca7e

Please sign in to comment.