Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

init custom gradle tooling model #10459

Merged
merged 1 commit into from
Jul 24, 2020

Conversation

glefloch
Copy link
Member

@glefloch glefloch commented Jul 3, 2020

This branch aims to expose a custom model containing project structure. This model is generating using the gradle API.

This allows gradle users to:

  • run/debug tests from IDE
  • run/debug main Quarkus.run (simple / multi-module)

This branch closes:

@aloubyansky can you have a look? this should not evolve more (excepts with review comment and some test additions)

@boring-cyborg boring-cyborg bot added area/devtools Issues/PR related to maven, gradle, platform and cli tooling/plugins area/gradle Gradle area/testing labels Jul 3, 2020
&& appArtifact.getGroupId().equals(a.getModuleVersion().getId().getGroup())) {
appArtifact.setPath(a.getFile().toPath());
for (io.quarkus.gradle.workspace.model.Dependency dependency : model.getAppDependencies()) {
// TODO there used to be a check on appArtifact.getType()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it not available in the model?

&& appArtifact.getType().equals(a.getType())
&& appArtifact.getGroupId().equals(a.getModuleVersion().getId().getGroup())) {
appArtifact.setPath(a.getFile().toPath());
for (io.quarkus.gradle.workspace.model.Dependency dependency : model.getAppDependencies()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually very limiting, since the scope is limited to the app model only. I'll need to check whether the devtools could be affected.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you tried running the full testsuite with these changes? Or more specifically all the gradle tests including the tooling ones, such add/list extensions, create project? I'm wondering whether we should be changing this method at all. What we need to providing at the end is the AppModel and the workspace structure.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I run some tests on my machine on a sample project and everything was ok. Regarding the testsuite, I still have some failures. I will revert that change as you suggest.

if (!appArtifact.isResolved()) {
PathsCollection.Builder paths = PathsCollection.builder();
for (SourceSet sourceSet : model.getSourceSets()) {
sourceSet.getSourceDirectories().stream().filter(File::exists).map(File::toPath).forEach(paths::add);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these java sources?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are more BuildOutput such as build/classes/java/main

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well actually it's not, but I will update so it points to classes and not java files

@@ -284,7 +284,8 @@ public void startDev() {
StringBuilder classPathManifest = new StringBuilder();

final AppModel appModel;
final AppModelResolver modelResolver = extension().getAppModelResolver(LaunchMode.DEVELOPMENT);
final QuarkusModel quarkusModel = extension().getQuarkusModel(LaunchMode.DEVELOPMENT);
final AppModelResolver modelResolver = new AppModelGradleResolver(quarkusModel);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this could stay the way it was?

}

final SourceSet mainSourceSet = QuarkusGradleUtils.getSourceSet(project, SourceSet.MAIN_SOURCE_SET_NAME);
final SourceSet testSourceSet = QuarkusGradleUtils.getSourceSet(project, SourceSet.TEST_SOURCE_SET_NAME);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this could depend on the launch mode.

@@ -0,0 +1,13 @@
package io.quarkus.bootstrap.model;

public interface ArtifactKey {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this used anywhere else then in AppArtifactKey?


Collection<Dependency> getAppDependencies();

Collection<String> getExtensions();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this for? It looks like it also includes all the enforced platforms.

final SourceSet mainSourceSet = QuarkusGradleUtils.getSourceSet(project, SourceSet.MAIN_SOURCE_SET_NAME);
final SourceSet testSourceSet = QuarkusGradleUtils.getSourceSet(project, SourceSet.TEST_SOURCE_SET_NAME);

final Collection<org.gradle.api.artifacts.Dependency> platformExtension = getPlatformExtension(project);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure what platformExtension signifies here. These are application direct extension dependencies, maybe let's call it that?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree with you

platformExtension.addAll(getExtensions(configuration.getFirstLevelModuleDependencies(), appDependencies));
}

final Collection<Dependency> platformDependencies = collectExtensionDependencies(project, platformExtension);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's call them either extension dependencies or deployment dependencies.

@glefloch
Copy link
Member Author

glefloch commented Jul 6, 2020

@aloubyansky thanks for the review, I will update my branch :)

@glefloch glefloch force-pushed the fix/gradle-model branch from 96dc2f2 to b4139b6 Compare July 6, 2020 15:30
<dependency>
<groupId>org.gradle</groupId>
<artifactId>gradle-core-api</artifactId>
<version>6.1.1</version>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't realize we'd introduce Gradle deps in the app-model. This is not a good thing. For Maven we have quarkus-bootstrap-maven-resolver that depends on app-model and adds the Maven deps. I think we should do the same for Gradle.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be getting now into the launcher JAR. Have you noticed how much bigger it becomes with the Gradle part?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, we don't need this dependency anymore, we only need the gradle-tooling-api. But, yes I think externalizing it to a module could be a good idea.

@boring-cyborg boring-cyborg bot added area/core area/dependencies Pull requests that update a dependency file labels Jul 13, 2020
@glefloch glefloch changed the title WIP - init custom gradle tooling model init custom gradle tooling model Jul 15, 2020
@glefloch glefloch marked this pull request as ready for review July 15, 2020 19:04
@glefloch glefloch force-pushed the fix/gradle-model branch 8 times, most recently from 4503657 to 16632d2 Compare July 21, 2020 06:25
project.getBuildDir().getAbsoluteFile(), getSourceSourceSet(mainSourceSet), convert(mainSourceSet));
}

private Set<Workspace> getAdditionalWorkspaces(Project project, String mainProjectName) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is only one workspace that may include multiple projects.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I will introduce a project or module type to only keep one worksapce

return workspaces;
}

private Set<org.gradle.api.artifacts.Dependency> getDirectExtension(Project project) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should be renamed. It's not about extensions here. All it does it collects the enforced platforms. It should reflect that in the name.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 , I will rename it

Optional<Method> initAndRun = Arrays.stream(codeGenerator.getMethods())
.filter(m -> m.getName().equals(INIT_AND_RUN))
.findAny();
if (!initAndRun.isPresent()) {
throw new GradleException("Failed to find " + INIT_AND_RUN + " method in " + CodeGenerator.class.getName());
}

sourcesDirectories.forEach(System.out::println);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a left-over?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oupss


WorkspaceModule getMainModule();

Set<WorkspaceModule> getAllModule();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be plural, i.e. getAllModules

@glefloch glefloch force-pushed the fix/gradle-model branch 3 times, most recently from 03fa3c6 to a58138d Compare July 24, 2020 07:51
@glefloch
Copy link
Member Author

@aloubyansky, I fixed the gradle windows issue. It was a problem with the Process running the wrapper command.

CI should be ok now :)

@@ -201,6 +201,7 @@
<webjars-locator-core.version>0.46</webjars-locator-core.version>
<log4j2-jboss-logmanager.version>1.0.0.Beta1</log4j2-jboss-logmanager.version>
<avro.version>1.10.0</avro.version>
<gradle-tooling.version>6.5</gradle-tooling.version>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this property could be removed from this pom. But let's see if there are other things to change in this PR first.

}
appArtifact.setPaths(paths.build());
}
throw new AppModelResolverException("Requested artifact does not match loaded model");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be good to include the conflicting artifacts into the message.

}

final Set<ResolvedDependency> resolvedChildren = d.getChildren();
if (!resolvedChildren.isEmpty()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had addChildExtension and walked the whole tree because we also used to collect all the extension properties. Given that you are doing it elsewhere, I think you could have changed this if to addChildExtension && !resolvedChildren.isEmpty(). I don't think you need firstLevel arg in your impl.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I.e. you could have removed addChildExtension too. We are simply collecting the first met extension dependencies but not its children.

gradlePluginPortal()
}
plugins {
id 'io.quarkus' version '999-SNAPSHOT'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't be using specific quarkus versions in the test configs. This will break the release process.

gradlePluginPortal()
}
plugins {
id 'io.quarkus' version '999-SNAPSHOT'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here as well.

if (Files.exists(currentPath.resolve(BuildTool.MAVEN.getBuildFile()))) {
return true;
}
currentPath = currentPath.getParent();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you copy this from somewhere? This is not a good idea. What kind of path is expected to be passed in? Project root or any path inside a project?
A little bit better version would be checking each directory for all the recognizable build files instead of walking up to the root of the FS for each build file.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes I copier that from here:

private static Path locateCurrentProjectPom(Path path, boolean required) throws BootstrapMavenException {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, that path is derived from a class name (that is in the classes dir of a project) or is a project root.


public static QuarkusModel enableGradleAppModel(Path projectRoot, String mode)
throws IOException, AppModelResolverException {
if (isMavenProject(projectRoot)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If projectRoot is actually the project root we shouldn't be walking up to the root of the FS looking for the pom.xml.

public class WorkspaceImpl implements Workspace, Serializable {

public ArtifactCoords mainModuleKey;
public Set<WorkspaceModule> modules;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WorkspaceModuleImpl does not implement hashCode/equals. It would probably be better to have a map instead here. Also given that there is getModule(key)

Map<AppArtifactKey, AppDependency> versionMap = new HashMap<>();
model.getAppDependencies().stream().map(QuarkusModelHelper::toAppDependency).forEach(appDependency -> {
userDeps.add(appDependency);
versionMap.put(appArtifact.getKey(), appDependency);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you need appDependency.getArtifact().getKey() or something here.

}
}
}
if (!userDeps.contains(appDep)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not correct. You need to be comparing the keys instead. Otherwise, you are not aligning versions here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually done like this in the current model, should i update it to use the appDep.getArtifact() instead? (

)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, that's clearly a bug. It should be appDep.getArtifact().getKey()

@@ -4,6 +4,7 @@ plugins {

dependencies {
implementation project(":runtime")
implementation project(":deployment")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, applications can't depend on the deployment artifact.

@@ -168,6 +170,12 @@ private ExtensionState doJavaStart(ExtensionContext context, Class<? extends Qua
rootBuilder.add(appResourcesLocation);
}

Path root = Paths.get("").normalize().toAbsolutePath();
// If gradle project running directly with IDE
if (System.getProperty(BootstrapConstants.SERIALIZED_APP_MODEL) == null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this property set? I see it in exportModel but has it been called by this point?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could already have been set by the gradle plugin in the before test

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need a delegating impl of AppModelResolver. For now it's ok, I think.

Copy link
Member

@aloubyansky aloubyansky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. We'll need to refactor some bootstrap API and setup later to have a cleaner Maven/Gradle bootstrap integration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/core area/dependencies Pull requests that update a dependency file area/devtools Issues/PR related to maven, gradle, platform and cli tooling/plugins area/gradle Gradle area/testing
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants