Skip to content

Commit

Permalink
A bit of javadoc for codegen and path tree API
Browse files Browse the repository at this point in the history
Co-authored-by: Peter Palaga <ppalaga@redhat.com>
  • Loading branch information
aloubyansky and ppalaga committed Mar 23, 2023
1 parent 5c601df commit 6800df5
Show file tree
Hide file tree
Showing 7 changed files with 196 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

import io.quarkus.bootstrap.model.ApplicationModel;

/**
* Code generation context
*/
public class CodeGenContext {
private final ApplicationModel model;
private final Path outDir;
Expand All @@ -15,6 +18,17 @@ public class CodeGenContext {
private final Config config;
private final boolean test;

/**
* Creates a code generation context
*
* @param model application model
* @param outDir target directory for the generated output
* @param workDir working directory, typically the main build directory of the project
* @param inputDir directory containing input content for a code generator
* @param redirectIO whether the code generating process should redirect its IO
* @param config application build time configuration
* @param test indicates whether the code generation is being triggered for tests
*/
public CodeGenContext(ApplicationModel model, Path outDir, Path workDir, Path inputDir, boolean redirectIO,
Config config, boolean test) {
this.model = model;
Expand All @@ -26,30 +40,77 @@ public CodeGenContext(ApplicationModel model, Path outDir, Path workDir, Path in
this.test = test;
}

/**
* Application model
*
* @return application model
*/
public ApplicationModel applicationModel() {
return model;
}

/**
* Target directory for the generated output.
* The directory would typically be resolved as {@code <project.build.directory>/generated-sources/<codegen-provider-id>},
* where {@code <codegen-provider-id> would match the value of {@link CodeGenProvider#providerId()}.
* For example, for a code gen provider {@code foo}, the output directory in a typical Maven project would be
* {@code target/generated-sources/foo}.
*
* @return target directory for the generated output
*/
public Path outDir() {
return outDir;
}

/**
* Working directory, typically the main build directory of the project.
* For a typical Maven project it would be the {@code target} directory.
*
* @return working directory, typically the main build directory of the project
*/
public Path workDir() {
return workDir;
}

/**
* Directory containing input content for a code generator.
* For the main application build of a typical Maven project the input sources directory
* would be {@code <project.basedir>/src/main/<codegen-provider-id>}, while for the tests it would be
* {@code <project.basedir>/src/test/<codegen-provider-id>}, where {@code <codegen-provider-id}
* would match the value of {@link CodeGenProvider#providerId()}.
*
* @return directory containing input content a code generator
*/
public Path inputDir() {
return inputDir;
}

/**
* Whether any new processes spawned by a given {@link CodeGenProvider} should inherit the
* launching process' output streams
* or redirect its output and error streams using {@link java.lang.ProcessBuilder.Redirect#PIPE}.
* In the current implementation this is typically set to {@code true} by the framework.
*
* @return whether the code generation process should redirect its error and output streams
*/
public boolean shouldRedirectIO() {
return redirectIO;
}

/**
* Application build time configuration
*
* @return application build time configuration
*/
public Config config() {
return config;
}

/**
* Indicates whether the code generation is being triggered for tests
*
* @return indicates whether the code generation is being triggered for tests
*/
public boolean test() {
return test;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ public interface CodeGenProvider {
String inputExtension();

/**
* Name of the directory containing the input files for the CodeGenProvider
* for <code>foo</code>, <code>src/main/foo</code> for application and <code>src/test/foo</code> for test resources
* Name of the directory containing input files for a given {@link CodeGenProvider} implementation
* relative to a sources root directory. For example, if an input directory is configured as <code>foo</code>,
* for a production build of an application the sources will be looked up at <code>src/main/foo</code> path
* and at <code>src/test/foo</code> for tests.
*
* @return the input directory
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,33 @@

import io.quarkus.deployment.CodeGenProvider;

/**
* Links a {@link CodeGenProvider} instance, an input and output directories for the provider.
*/
public class CodeGenData {
public final CodeGenProvider provider;
public final Path outPath;
public final Path sourceDir;
public final Path buildDir;
public boolean redirectIO;

/**
* @param provider code gen provider
* @param outPath where the generated output should be stored
* @param sourceDir where the input sources are
* @param buildDir base project output directory
*/
public CodeGenData(CodeGenProvider provider, Path outPath, Path sourceDir, Path buildDir) {
this(provider, outPath, sourceDir, buildDir, true);
}

/**
* @param provider code gen provider
* @param outPath where the generated output should be stored
* @param sourceDir where the input sources are
* @param buildDir base project output directory
* @param redirectIO whether to redirect IO, in case a provider is logging something
*/
public CodeGenData(CodeGenProvider provider, Path outPath, Path sourceDir, Path buildDir, boolean redirectIO) {
this.provider = provider;
this.outPath = outPath;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.quarkus.bootstrap.model;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
Expand All @@ -13,31 +12,85 @@
import io.quarkus.maven.dependency.Dependency;
import io.quarkus.maven.dependency.ResolvedDependency;

/**
* Application dependency model. Allows to explore application dependencies,
* Quarkus platforms found in the project configuration and Quarkus platform configuration properties.
*/
public interface ApplicationModel {

/**
* Main application artifact
*
* @return main application artifact
*/
ResolvedDependency getAppArtifact();

/**
* All the dependencies of an application including runtime and build time dependencies.
*
* @return application runtime and build time dependencies
*/
Collection<ResolvedDependency> getDependencies();

/**
* Runtime dependencies of an application
*
* @return runtime dependencies of an application
*/
default Collection<ResolvedDependency> getRuntimeDependencies() {
return getDependencies().stream().filter(Dependency::isRuntimeCp).collect(Collectors.toList());
}

/**
* Quarkus platforms (BOMs) found in the configuration of an application
*
* @return Quarkus platforms (BOMs) found in the configuration of an application
*/
PlatformImports getPlatforms();

/**
* Quarkus platform configuration properties
*
* @return Quarkus platform configuration properties
*/
default Map<String, String> getPlatformProperties() {
final PlatformImports platformImports = getPlatforms();
return platformImports == null ? Collections.emptyMap() : platformImports.getPlatformProperties();
return platformImports == null ? Map.of() : platformImports.getPlatformProperties();
}

/**
* Extension capability requirements collected from the extensions found on the classpath of an application
*
* @return Extension capability requirements collected from the extensions found on the classpath of an application
*/
Collection<ExtensionCapabilities> getExtensionCapabilities();

/**
* Class loading parent-first artifacts
*
* @return class loading parent-first artifacts
*/
Set<ArtifactKey> getParentFirst();

/**
* Class loading runner parent-first artifacts
*
* @return class loading runner parent-first artifacts
*/
Set<ArtifactKey> getRunnerParentFirst();

/**
* Class loading lower priority artifacts
*
* @return class loading lower priority artifacts
*/
Set<ArtifactKey> getLowerPriorityArtifacts();

/**
* Local project dependencies that are live-reloadable in dev mode.
*
* @return local project dependencies that are live-reloadable in dev mode.
*/
Set<ArtifactKey> getReloadableWorkspaceDependencies();

/**
Expand All @@ -47,10 +100,20 @@ default Map<String, String> getPlatformProperties() {
*/
Map<ArtifactKey, Set<String>> getRemovedResources();

/**
* Main workspace module of an application. Could be null, in case the project is not available during the build.
*
* @return main workspace module of an application, could be null, in case the project is not available during the build
*/
default WorkspaceModule getApplicationModule() {
return getAppArtifact().getWorkspaceModule();
}

/**
* All the workspace modules found as dependencies of an application
*
* @return all the workspace modules found as dependencies of an application
*/
default Collection<WorkspaceModule> getWorkspaceModules() {
final Map<WorkspaceModuleId, WorkspaceModule> result = new HashMap<>();
collectModules(getAppArtifact().getWorkspaceModule(), result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
Expand Down Expand Up @@ -35,15 +34,15 @@ static void walk(Path root, Path rootDir, PathFilter pathFilter, Map<String, Str
}

static <T> T process(Path root, Path rootDir, Path path, PathFilter pathFilter, Function<PathVisit, T> func) {
final PathTreeVisit visit = new PathTreeVisit(root, rootDir, pathFilter, Collections.emptyMap());
final PathTreeVisit visit = new PathTreeVisit(root, rootDir, pathFilter, Map.of());
if (visit.setCurrent(path)) {
return func.apply(visit);
}
return func.apply(null);
}

static void consume(Path root, Path rootDir, Path path, PathFilter pathFilter, Consumer<PathVisit> func) {
final PathTreeVisit visit = new PathTreeVisit(root, rootDir, pathFilter, Collections.emptyMap());
final PathTreeVisit visit = new PathTreeVisit(root, rootDir, pathFilter, Map.of());
if (visit.setCurrent(path)) {
func.accept(visit);
} else {
Expand All @@ -64,7 +63,7 @@ private PathTreeVisit(Path root, Path rootDir, PathFilter pathFilter, Map<String
this.root = root;
this.baseDir = rootDir;
this.pathFilter = pathFilter;
this.multiReleaseMapping = multiReleaseMapping == null || multiReleaseMapping.isEmpty() ? Collections.emptyMap()
this.multiReleaseMapping = multiReleaseMapping == null || multiReleaseMapping.isEmpty() ? Map.of()
: new HashMap<>(multiReleaseMapping);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,34 @@
import java.net.URL;
import java.nio.file.Path;

/**
* Provides context for a given path visit
*/
public interface PathVisit {

/**
* The root of the path tree the current path belongs to.
* For a {@link PathTree} created for an archive, this will be the path to the archive file.
* For a {@link PathTree} created for a directory, this will be the path to the directory.
*
* @return root of the path tree the current path belongs to
*/
Path getRoot();

/**
* The path being visited. The {@link java.nio.file.FileSystem} the path belongs to
* will depend on the implementation of the {@link PathTree} being visited. For example,
* for an archive it will be a ZIP {@link java.nio.file.FileSystem} implementation.
*
* @return path being visited
*/
Path getPath();

/**
* {@link java.net.URL} that can be used to read the content of the path.
*
* @return URL that can be used to read the content of the path
*/
default URL getUrl() {
try {
return getPath().toUri().toURL();
Expand All @@ -18,7 +40,20 @@ default URL getUrl() {
}
}

/**
* Path relative to the root of the tree as a string with a provided path element separator.
* For a {@link PathTree} created for an archive, the returned path will be relative to the root
* of the corresponding {@link java.nio.file.FileSystem} implementation.
* For a {@link PathTree} created for a directory, the returned path will be relative to the directory
* used as the root of the path tree.
*
* @param separator path element separator
* @return path relative to the root of the tree as a string with a provided path element separator
*/
String getRelativePath(String separator);

/**
* Terminates walking over a {@link PathTree} after this visit.
*/
void stopWalking();
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
package io.quarkus.paths;

/**
* {@link PathTree} path visitor
*/
public interface PathVisitor {

/**
* Called to visit a path when walking a path tree or when a caller
* requested to visit a specific path in a tree. In the latter case
* if the requested path does not exist, the {@code visit} argument
* will be null and it'll be up to the caller how to handle that,
* i.e. whether to throw a path not found exception or return silently.
*
* @param visit visit object or null, in case the requested path does not exist
*/
void visitPath(PathVisit visit);
}

0 comments on commit 6800df5

Please sign in to comment.