More sketching of gradle plugin and related cli.

This commit is contained in:
JesseBrault0709 2024-05-06 14:43:56 +02:00
parent 6c4406bc80
commit 4cf74da120
14 changed files with 288 additions and 14 deletions

View File

@ -1,6 +1,5 @@
plugins { plugins {
id 'GroowtConventions' id 'GroowtConventions'
id 'application'
id 'com.jessebrault.jbarchiva' version '0.1.0' id 'com.jessebrault.jbarchiva' version '0.1.0'
id 'maven-publish' id 'maven-publish'
} }
@ -8,14 +7,27 @@ plugins {
group = 'groowt' group = 'groowt'
version = '0.1.0' version = '0.1.0'
application { repositories {
mainClass = 'groowt.cli.GroowtCli' maven {
url 'https://repo.gradle.org/gradle/libs-releases'
}
}
dependencies {
implementation libs.gradle.tooling, libs.picocli, project(':groowt-gradle-model')
} }
tasks.named('jar', Jar) { tasks.named('jar', Jar) {
manifest { manifest {
attributes('Main-Class': 'groowt.cli.GroowtCli') attributes('Main-Class': 'groowt.cli.GroowtCli')
} }
from sourceSets.main.runtimeClasspath.filter(File.&exists).collect { it.isDirectory() ? it : zipTree(it) }
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
dependsOn ':groowt-gradle-model:jar'
}
tasks.withType(GenerateModuleMetadata) {
enabled = false
} }
publishing { publishing {
@ -23,6 +35,13 @@ publishing {
create('groowtCli', MavenPublication) { create('groowtCli', MavenPublication) {
artifactId = 'groowt-cli' artifactId = 'groowt-cli'
from components.java from components.java
pom {
withXml {
def rootNode = asNode()
def dependenciesNode = rootNode.get('dependencies')
rootNode.remove(dependenciesNode)
}
}
} }
} }
} }

View File

@ -0,0 +1,62 @@
package groowt.cli;
import groowt.gradle.model.GroowtGradleModel;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.concurrent.Callable;
@Command(name = "generate", aliases = "gen", description = "Generate a component, template, model, etc.")
public class Generate implements Callable<Integer> {
@CommandLine.ParentCommand
private GroowtCli cli;
@CommandLine.Option(
names = { "-c", "--component" },
description = "Create a component with the given name."
)
private String componentName;
@CommandLine.Option(
names = { "-s", "--sourceSet" },
description = "The source set in which to generate the component, etc.",
defaultValue = "main"
)
private String sourceSet;
@CommandLine.Option(
names = { "-d", "--srcDir", "--sourceDir", "--sourceDirectory" },
description = "The directory in the source set in which to generate the component, etc."
)
private File sourceDir;
@SuppressWarnings("ResultOfMethodCallIgnored")
@Override
public Integer call() {
if (this.componentName != null) {
GradleUtil.doWith(this.cli.getProjectDir(), project -> {
final var model = project.getModel(GroowtGradleModel.class);
if (sourceDir == null) {
this.sourceDir = new File(String.join(File.separator, "src", this.sourceSet, "groovy"));
}
final File packageDir = new File(
this.sourceDir, model.getBasePackage().replace(".", File.separator)
);
packageDir.mkdirs();
final File componentFile = new File(packageDir, this.componentName + ".txt");
try (final OutputStream componentFileOutputStream = new FileOutputStream(componentFile)) {
componentFileOutputStream.write("Hello, Groowt!".getBytes());
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
return 0;
}
}

View File

@ -0,0 +1,20 @@
package groowt.cli;
import org.gradle.tooling.GradleConnector;
import org.gradle.tooling.ProjectConnection;
import java.io.File;
import java.util.function.Consumer;
public final class GradleUtil {
public static void doWith(File projectDir, Consumer<ProjectConnection> action) {
final var gradleConnector = GradleConnector.newConnector().forProjectDirectory(projectDir);
try (final var projectConnection = gradleConnector.connect()) {
action.accept(projectConnection);
}
}
private GradleUtil() {}
}

View File

@ -1,9 +1,42 @@
package groowt.cli; package groowt.cli;
import picocli.CommandLine;
import java.io.File;
@CommandLine.Command(
name = "groowt",
description = "The command line interface facilitating development of a Groowt project.",
mixinStandardHelpOptions = true,
version = "0.1.0",
subcommands = { Generate.class }
)
public class GroowtCli { public class GroowtCli {
@CommandLine.Option(
names = { "-v", "--verbose" },
description = "Log verbosely to standard out."
)
private boolean verbose;
@CommandLine.Option(
names = { "--projectDir" },
defaultValue = ".",
description = "The root directory of the groowt project."
)
private File projectDir;
public static void main(String[] args) { public static void main(String[] args) {
System.out.println("Hello from Groowt!"); System.out.println("Hello from Groowt!");
System.exit(new CommandLine(new GroowtCli()).execute(args));
}
public boolean isVerbose() {
return this.verbose;
}
public File getProjectDir() {
return this.projectDir;
} }
} }

View File

@ -14,6 +14,7 @@ slf4j = '2.0.12'
antlr = { module = 'org.antlr:antlr4', version.ref = 'antlr' } antlr = { module = 'org.antlr:antlr4', version.ref = 'antlr' }
antlr-runtime = { module = 'org.antlr:antlr4-runtime', version.ref = 'antlr' } antlr-runtime = { module = 'org.antlr:antlr4-runtime', version.ref = 'antlr' }
asm = 'org.ow2.asm:asm:9.7' asm = 'org.ow2.asm:asm:9.7'
gradle-tooling = 'org.gradle:gradle-tooling-api:8.6'
groovy = { module = 'org.apache.groovy:groovy', version.ref = 'groovy' } groovy = { module = 'org.apache.groovy:groovy', version.ref = 'groovy' }
groovy-all = { module = 'org.apache.groovy:groovy-all', version.ref = 'groovy' } groovy-all = { module = 'org.apache.groovy:groovy-all', version.ref = 'groovy' }
groovy-console = { module = 'org.apache.groovy:groovy-console', version.ref = 'groovy' } groovy-console = { module = 'org.apache.groovy:groovy-console', version.ref = 'groovy' }

View File

@ -0,0 +1,23 @@
plugins {
id 'GroowtConventions'
id 'java-library'
id 'maven-publish'
}
group = 'groowt'
version = '0.1.0'
repositories {
maven {
url 'https://repo.gradle.org/gradle/libs-releases'
}
}
publishing {
publications {
create('groowtGradleModel', MavenPublication) {
artifactId = 'groowt-gradle-model'
from components.java
}
}
}

View File

@ -0,0 +1,34 @@
package groowt.gradle.model;
import java.io.File;
import java.io.Serializable;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
public class DefaultGroowtGradleModel implements GroowtGradleModel, Serializable {
private String basePackage;
private Map<String, Set<File>> sourceSetToTemplatesDirs;
@Override
public String getBasePackage() {
return this.basePackage;
}
public void setBasePackage(String basePackage) {
this.basePackage = Objects.requireNonNull(basePackage);
}
@Override
public Map<String, Set<File>> getSourceSetToTemplatesDirs() {
return Objects.requireNonNull(this.sourceSetToTemplatesDirs);
}
public void setSourceFileSets(Map<String, Set<File>> sourceSetToTemplateDir) {
this.sourceSetToTemplatesDirs = sourceSetToTemplateDir;
}
}

View File

@ -0,0 +1,13 @@
package groowt.gradle.model;
import java.io.File;
import java.util.Map;
import java.util.Set;
public interface GroowtGradleModel {
String getBasePackage();
Map<String, Set<File>> getSourceSetToTemplatesDirs();
}

View File

@ -1,4 +1,5 @@
plugins { plugins {
id 'GroowtConventions'
id 'java-gradle-plugin' id 'java-gradle-plugin'
id 'com.jessebrault.jbarchiva' version '0.1.0' id 'com.jessebrault.jbarchiva' version '0.1.0'
id 'maven-publish' id 'maven-publish'
@ -9,10 +10,13 @@ version = '0.1.0'
repositories { repositories {
mavenCentral() mavenCentral()
maven {
url 'https://repo.gradle.org/gradle/libs-releases'
}
} }
dependencies { dependencies {
implementation libs.groovy implementation libs.groovy, libs.gradle.tooling, project(':groowt-gradle-model')
} }
gradlePlugin { gradlePlugin {
@ -26,9 +30,10 @@ gradlePlugin {
publishing { publishing {
publications { publications {
groowtGradlePlugin(MavenPublication) { create('groowtGradlePlugin', MavenPublication) {
artifactId = 'groowt-gradle' artifactId = 'groowt-gradle'
from components.java from components.java
} }
} }
} }

View File

@ -1,23 +1,22 @@
package groowt.gradle; package groowt.gradle;
import org.gradle.api.internal.tasks.DefaultSourceSetContainer;
import org.gradle.api.tasks.SourceSetContainer;
import org.gradle.api.model.ObjectFactory; import org.gradle.api.model.ObjectFactory;
import org.gradle.api.provider.Property;
import javax.inject.Inject; import javax.inject.Inject;
public class DefaultGroowtExtension implements GroowtExtension { public class DefaultGroowtExtension implements GroowtExtension {
private final SourceSetContainer sourceSets; private final Property<String> basePackage;
@Inject @Inject
public DefaultGroowtExtension(ObjectFactory objectFactory) { public DefaultGroowtExtension(ObjectFactory objectFactory) {
this.sourceSets = objectFactory.newInstance(DefaultSourceSetContainer.class); this.basePackage = objectFactory.property(String.class);
} }
@Override @Override
public SourceSetContainer getSourceSets() { public Property<String> getBasePackage() {
return this.sourceSets; return this.basePackage;
} }
} }

View File

@ -1,7 +1,7 @@
package groowt.gradle; package groowt.gradle;
import org.gradle.api.tasks.SourceSetContainer; import org.gradle.api.provider.Property;
public interface GroowtExtension { public interface GroowtExtension {
SourceSetContainer getSourceSets(); Property<String> getBasePackage();
} }

View File

@ -1,5 +1,6 @@
package groowt.gradle; package groowt.gradle;
import groowt.gradle.model.GroowtGradleModelBuilder;
import org.gradle.api.Plugin; import org.gradle.api.Plugin;
import org.gradle.api.Project; import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.Configuration;
@ -10,11 +11,21 @@ import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginExtension; import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.provider.Provider; import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.SourceSetContainer; import org.gradle.api.tasks.SourceSetContainer;
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry;
import javax.inject.Inject;
import static org.gradle.api.internal.lambdas.SerializableLambdas.spec; import static org.gradle.api.internal.lambdas.SerializableLambdas.spec;
public class GroowtGradlePlugin implements Plugin<Project> { public class GroowtGradlePlugin implements Plugin<Project> {
private final ToolingModelBuilderRegistry modelBuilderRegistry;
@Inject
public GroowtGradlePlugin(ToolingModelBuilderRegistry modelBuilderRegistry) {
this.modelBuilderRegistry = modelBuilderRegistry;
}
@Override @Override
public void apply(Project project) { public void apply(Project project) {
// Apply java and groovy plugins, if not done already // Apply java and groovy plugins, if not done already
@ -35,6 +46,7 @@ public class GroowtGradlePlugin implements Plugin<Project> {
"groowt", "groowt",
DefaultGroowtExtension.class DefaultGroowtExtension.class
); );
groowtExtension.getBasePackage().convention("");
final JavaPluginExtension javaExtension = project.getExtensions().getByType(JavaPluginExtension.class); final JavaPluginExtension javaExtension = project.getExtensions().getByType(JavaPluginExtension.class);
final SourceSetContainer javaSourceSets = javaExtension.getSourceSets(); final SourceSetContainer javaSourceSets = javaExtension.getSourceSets();
@ -71,6 +83,9 @@ public class GroowtGradlePlugin implements Plugin<Project> {
// create init task // create init task
project.getTasks().create("groowtInit", GroowtInitTask.class, groowtConfigurationProvider); project.getTasks().create("groowtInit", GroowtInitTask.class, groowtConfigurationProvider);
// tooling models for cli
this.modelBuilderRegistry.register(new GroowtGradleModelBuilder());
} }
} }

View File

@ -0,0 +1,50 @@
package groowt.gradle.model;
import groowt.gradle.GroowtExtension;
import groowt.gradle.TemplateSourceDirectorySet;
import org.gradle.api.Project;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.provider.Property;
import org.gradle.tooling.provider.model.ToolingModelBuilder;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class GroowtGradleModelBuilder implements ToolingModelBuilder {
@Override
public boolean canBuild(String modelName) {
return modelName.equals(GroowtGradleModel.class.getName());
}
@Override
public @NotNull Object buildAll(@NotNull String modelName, Project project) {
final DefaultGroowtGradleModel model = new DefaultGroowtGradleModel();
final var groowtExtension = project.getExtensions().getByType(GroowtExtension.class);
// base package
final Property<String> basePackage = groowtExtension.getBasePackage();
if (!basePackage.isPresent()) {
throw new RuntimeException(
"The property 'basePackage' must be set under the 'groowt' extension in build.gradle"
);
}
model.setBasePackage(basePackage.get());
// templates dirs
final Map<String, Set<File>> sourceSetToTemplatesDirs = new HashMap<>();
final var javaExtension = project.getExtensions().getByType(JavaPluginExtension.class);
javaExtension.getSourceSets().forEach(sourceSet -> {
final TemplateSourceDirectorySet templateSourceDirectorySet =
sourceSet.getExtensions().getByType(TemplateSourceDirectorySet.class);
sourceSetToTemplatesDirs.put(sourceSet.getName(), templateSourceDirectorySet.getFiles());
});
model.setSourceFileSets(sourceSetToTemplatesDirs);
return model;
}
}

View File

@ -26,7 +26,7 @@ pluginManagement {
rootProject.name = 'groowt' rootProject.name = 'groowt'
include 'cli', 'groowt-gradle', 'views', 'view-components', 'web-views' include 'cli', 'groowt-gradle', 'groowt-gradle-model', 'views', 'view-components', 'web-views'
file('util').eachDir { file('util').eachDir {
include it.name include it.name