Skip to content

Commit

Permalink
Add support for a process API
Browse files Browse the repository at this point in the history
Maven Mojos (and maybe components) can create / fork processes, common
examples would include:

- ant-run plugin
- maven-exec-plugin
- maven-surefire

currently the IDE has no effective way to know about forked processes,
so there is no way to visualize them (e.g. in a process manager) nor to
take special actions on them (e.g. automatically request to open a debug
port). For executions of tests, the IDE even may want to be notified
about individual test runs while the process is running.

This now adds a new build-process API that mitigates the problem by
allowing a mojo or component to make the IDE aware of subprocesses but
is completely disabled if running outside an IDE. An integration can
range from very basic, that is only notify that a process is running
over to specialized callbacks that allows the IDE to intercept process
creation in a generic way. An example implementation is provided for
either resuse, extension or own implementation of such callbacks.

To reflect this new opportunity, the minor version is increase to 1.3
even though neither consumers nor providers of the API need to take
immediate actions here.
  • Loading branch information
Christoph Läubrich committed Feb 28, 2024
1 parent 48fe7ea commit 93f6a58
Show file tree
Hide file tree
Showing 10 changed files with 470 additions and 2 deletions.
59 changes: 58 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,76 @@ Plexus Build API

This API allows IDEs to integrate with Maven deeper than it would be possible by just using regular Maven/Mojo API.

## Marker and File Delta support
It supports

- incremental builds e.g. allows to query which files have been touched since last build
- fine-grained error/info markers (referring to specific files in particular line numbers)
- notifications about updated files

## Process support

This API is located in the package `org.codehaus.plexus.build.process` and allows the IDE to interact with a mojo that starts new processes and has the following purposes:

- allow representation of processes in the UI e.g with a name and its current state together with a way to optionally terminate a running process
- optionally decorate the process dependeing on the use case e.g. add additional environment variables, supply classpath entries or provide listeners

The main entry point for this is the `ProcessContext` that can be injected in a mojo in the follwoing way:

```
public MyMojo extends AbstractMojo {
@Component
private ProcessManager processContext;
public void execute() {
ProcessContext context = ...
BuildProcess process = processContext.newProcess(context);
}
}
```

As one can see we have a `ProcessManager` that is capable of creating a Process for the user to see it in the IDE and the `BuildProcess` can be used to notify the IDE about process changes, e.g. if it is terminated.
There is also a `ProcessContext` passed to the call that allow the mojo to supply basic information like the name or if it can be terminated but also can implements different callbacks that might (or might not) be called to furhter decorate the process.
The follwoing callbacks are currently supported:

### ProcessCallback

`ProcessCallback` are quite bare callback that allow to request for adding (or replacing) an environment variable with `ProcessCallback#setEnvironmentVariable`,
any context that support should implement the interface. Even though a request is made it could be reqjected, e.g because the context don't allow this because
it uses a variable with the same name already and don'T want to replace it.

A basic implementation of this is provided with `ProcessBuilderContext` what implements this using a ProcessBuilder, so if processes are currently implemented that way it can be reused.

### JavaCallback

`JavaCallback` offers specialized way to add options to a launch that is running in a JVM (either directly or forked). The possible callbacks are

- setSystemProperty for requesting to add (or replace) a system property
- setVMOption for requesting to add (or replace) a VM option
- addClasspathEntry for requesting to add a new jar on the classpath

There is currently no implementation added here but one can reuse `ProcessBuilderContext` for performin neccesary actions.

### JUnitCallback

`JUnitCallback` offer specialized option to a launch that is executing test using JUnit framework. The possible callbacks are

- addTestClasspathEntry for requesting to add a new jar on the test classpath
- addTestExecutionListener for reuqest to add a new listener that is notified about test events
- getJUnitVersion allows to query for the used JUnit version

Current Implementations
-----

### Default Implementation

The default implementation shipping with this artifact is supposed to impose minimal overhead. It doesn't support incremental build and acts directly on the file system. Errors and warning are just logged through SLF4J.
- Marker and File Delta support is supposed to impose minimal overhead. It doesn't support incremental build and acts directly on the file system. Errors and warning are just logged through SLF4J.
- Process support is simply a no-op, it never will call any callbacks and just discards the name, all calls on the listener will simply do nothing

## Process support

### M2Eclipse

Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ See the Apache License Version 2.0 for the specific language governing permissio
</parent>

<artifactId>plexus-build-api</artifactId>
<version>1.2.1-SNAPSHOT</version>
<version>1.3.0-SNAPSHOT</version>

<scm>
<connection>scm:git:https://github.com/codehaus-plexus/plexus-build-api.git</connection>
Expand Down
50 changes: 50 additions & 0 deletions src/main/java/org/codehaus/plexus/build/process/BuildProcess.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright 2024 Christoph Läubrich
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.codehaus.plexus.build.process;

/**
* A {@link BuildProcess} represents a process created inside a maven execution
* that performs a specialized task and can be represented as something other
* than a mojo executions, for example a mojo that executes tests in a forked VM
* can handle multiple forks in one invocation. Also a process allows to be
* controlled from the outside, e.g. the user can request to terminate it.
*/
public interface BuildProcess {

/**
* @return the name of the process
*/
String getName();

/**
* Notify the manager that the given process was started
*/
void notifyStarted();

/**
* @return true if the process is requested to terminate or has already
* terminated.
*/
boolean isTerminated();

/**
* Notify the manager that the given process has finished with the given exit
* code where an exit code of zero usually indicates a successful termination
*
* @param exitcode
*/
void notifyFinished(int exitcode);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2024 Christoph Läubrich
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.codehaus.plexus.build.process;

/**
* A {@link BuildProcessContext} is used to create a {@link BuildProcess}, it
* can implement any number of specialized callbacks that allow to further
* customize the about to executed process, that allows IDEs to install
* additional code to track progress or getting notified about results.
*/
public interface BuildProcessContext {

/**
* Provides the name of process that is created, this is something that might be
* presented to the user in an IDE
*
* @return the name
*/
String getName();

/**
* Determines if termination of this process is possible, an IDE will possibly
* present a way to terminate an individual process. A request to terminate the
* process is then reflected in the process but it is the responsibility of the
* implementation to act on it.
*
* @return <code>true</code>
*/
boolean canTerminate();
}
57 changes: 57 additions & 0 deletions src/main/java/org/codehaus/plexus/build/process/JUnitCallback.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2024 Christoph Läubrich
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.codehaus.plexus.build.process;

import java.nio.file.Path;

/**
* Callback targeting a JUnit execution.
*/
public interface JUnitCallback {

enum JUnitVersion {
JUNIT3,
JUNIT4,
JUNIT5;
}

/**
* Request to add a new classpath entry to the junit execution, this might
* contain additional classes needed to perform some actions.
*
* @param extraTestClasspath the extra classpath element
*
* @return <code>true</code> if the request was accepted, <code>false</code>
* otherwise.
*/
boolean addTestClasspathEntry(Path extraTestClasspath);

/**
* Request to add a new TestExecutionListener specified by the full qualified
* class name, this must either be a default one or one that can be loaded by
* the extra test classpath added before.
*
* @param fqcn full qualified classname of the listener implementation
* @return <code>true</code> if the listener was accepted, <code>false</code>
* otherwise.
*/
boolean addTestExecutionListener(String fqcn);

/**
* @return the version of JUnit that will be executed
*/
JUnitVersion getJUnitVersion();
}
55 changes: 55 additions & 0 deletions src/main/java/org/codehaus/plexus/build/process/JavaCallback.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright 2024 Christoph Läubrich
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.codehaus.plexus.build.process;

import java.nio.file.Path;

/**
* A callback for a context that is working around java processes to be started,
* a {@link BuildProcessContext} should implement this if it allows to further
* customize a process that is running a java VM. Depending on the launch type
* (e.g embedded or forked) some options might not be possible and can maybe
* rejected.
*/
public interface JavaCallback {

/**
* Request to add a system property to the launch.
*
* @param key the key
* @param value the value
* @return <code>true</code> if the request was accepted, false otherwise.
*/
boolean setSystemProperty(String key, String value);

/**
* Request to add a VM option to the launch.
*
* @param option the VM option to add
* @param value the value or <code>null</code> if this option has no value
* @return <code>true</code> if the request was accepted, false otherwise.
*/
boolean setVMOption(String option, String value);

/**
* Request to add a new classpath entry to the launch
*
* @param extraClasspath the extra classpath element
*
* @return <code>true</code> if the request was accepted, false otherwise.
*/
boolean addClasspathEntry(Path extraClasspath);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright 2024 Christoph Läubrich
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.codehaus.plexus.build.process;

/**
* A {@link ProcessCallback} can be implemented by a context if it is able to
* accept additional environment variables to be set on a process they create.
*/
public interface ProcessCallback {

/**
* Request to set an additional environment variable, the context provider is
* free to reject the request
*
* @param variable
* @param value
* @return <code>true</code> if the context accepted the request and will add
* the environment variable to the launch, false otherwise.
*/
boolean setEnvironmentVariable(String variable, String value);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2024 Christoph Läubrich
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.codehaus.plexus.build.process;

/**
* The {@link ProcessManager} is responsible for connecting a process created by
* a mojo (usually a forked one but thats not required) to the IDE and allows
* some visual representation but also some customization using callbacks.
*/
public interface ProcessManager {

/**
* Create a new {@link BuildProcess} given the {@link BuildProcessContext}
* calling any supported callbacks.
*
* @param context the context to use
* @return the created {@link BuildProcess} that can be used to further control
* the process e.g inform about termination or <code>null</code> if no
* process can be created, for example this can happen because required
* callbacks are not supported for this kind of launch.
*/
BuildProcess newProcess(BuildProcessContext context);
}
Loading

0 comments on commit 93f6a58

Please sign in to comment.