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

VsCode debug support #30

Merged
merged 19 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ repo
.metadata
.classpath
.project
/.vscode/
bin
/.vscode/

Expand Down
1 change: 1 addition & 0 deletions common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ dependencies {
api "codechicken:DiffPatch:${project.diffpatch_version}"
api "commons-codec:commons-codec:${project.commons_codec_version}"
api "net.neoforged:EclipseLaunchConfigs:${project.eclipse_launch_configs_version}"
api "cz.nightenom:vsc-launch-writer:${project.vscode_launch_configs_version}"
Nightenom marked this conversation as resolved.
Show resolved Hide resolved
api "net.neoforged:JarJarMetadata:${project.jarjar_version}"
api "net.neoforged:JarJarSelector:${project.jarjar_version}"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
import org.jetbrains.gradle.ext.ProjectSettings;
import org.jetbrains.gradle.ext.TaskTriggersConfig;

import java.io.File;
import java.nio.file.Files;
import java.util.function.BiConsumer;
import javax.inject.Inject;

/**
Expand Down Expand Up @@ -68,13 +71,39 @@ public boolean isEclipseImport() {
return System.getProperty("eclipse.application") != null;
}

/**
* @return true if should rather perform VsCode setup instead of Eclipse setup.
* @implNote reinvestigate after https://github.com/microsoft/vscode-java-debug/issues/1106
*/
private boolean isLikelyVscodeImport()
{
final boolean hasVscodeDirectory = Files.isDirectory(project.getRootDir().toPath().resolve(".vscode"));
final boolean hasExtensionGradlePlugin = isDefinitelyVscodeImport(project);
project.getLogger().debug("vscode detection - dir .vscode: " + hasVscodeDirectory);
project.getLogger().debug("vscode detection - extension vscjava.vscode-gradle: " + hasExtensionGradlePlugin);
return hasVscodeDirectory || hasExtensionGradlePlugin;
}

/**
* @return true if must perform VsCode setup instead of Eclipse setup.
*/
public static boolean isDefinitelyVscodeImport(final Project project)
{
final String pathToCheck = String.join(File.separator, new String[]{"data", "extensions", "vscjava.vscode-gradle"});
final boolean hasUserDirProperty = System.getProperty("user.dir").contains(pathToCheck);
final boolean hasExtensionGradlePlugin = project.getPlugins().stream().anyMatch(p -> p.getClass().getName().equals("com.microsoft.gradle.GradlePlugin"));
project.getLogger().debug("vscode detection - user.dir contains " + pathToCheck + ": " + hasUserDirProperty);
project.getLogger().debug("vscode detection - extension vscjava.vscode-gradle: " + hasExtensionGradlePlugin);
return hasUserDirProperty || hasExtensionGradlePlugin;
}

/**
* Indicates if an IDE import in any of the supported IDEs is ongoing.
*
* @return {@code true} if an IDE import is ongoing, {@code false} otherwise
*/
public boolean isIdeImportInProgress() {
return isIdeaImport() || isEclipseImport();
return isIdeaImport() || isEclipseImport() || isDefinitelyVscodeImport(project);
}

/**
Expand Down Expand Up @@ -111,6 +140,12 @@ public void eclipse(Project project, EclipseModel eclipse) {
//Register the task to run after the Eclipse import is complete, via its build-in support.
eclipse.synchronizationTasks(idePostSyncTask);
}

@Override
public void vscode(Project project, EclipseModel eclipse) {
// vscode ~= eclipse
eclipse(project, eclipse);
}
});
}
else {
Expand All @@ -130,7 +165,9 @@ public void eclipse(Project project, EclipseModel eclipse) {
*/
public void apply(final IdeImportAction toPerform) {
onIdea(toPerform);
onEclipse(toPerform);
// likely because we want to generate launch.json even if we don't have gradle extension
if (isLikelyVscodeImport()) onVscode(toPerform);
else onEclipse(toPerform);
onGradle(toPerform);
}

Expand Down Expand Up @@ -169,7 +206,15 @@ public void onIdea(final IdeaIdeImportAction toPerform) {
toPerform.idea(project, model, ideaExt);
});
}


public void onEclipse(final EclipseIdeImportAction toPerform) {
onCommonEclipse(toPerform::eclipse);
}

public void onVscode(final VscodeIdeImportAction toPerform) {
onCommonEclipse(toPerform::vscode);
}

/**
* Applies the specified configuration action to configure eclipse IDE projects only.
*
Expand All @@ -178,11 +223,11 @@ public void onIdea(final IdeaIdeImportAction toPerform) {
*
* @param toPerform the actions to perform
*/
public void onEclipse(final EclipseIdeImportAction toPerform) {
private void onCommonEclipse(final BiConsumer<Project, EclipseModel> toPerform) {
//When the Eclipse plugin is available, configure it
project.getPlugins().withType(EclipsePlugin.class, plugin -> {
//Do not configure the eclipse plugin if we are not importing.
if (!isEclipseImport()) {
if (!isEclipseImport() && !isDefinitelyVscodeImport(project)) {
return;
}

Expand All @@ -191,11 +236,13 @@ public void onEclipse(final EclipseIdeImportAction toPerform) {
EclipseModel model = project.getExtensions().findByType(EclipseModel.class);
if (model == null) {
model = rootProject.getExtensions().findByType(EclipseModel.class);
return;
if (model == null) {
return;
}
}

//Configure the project, passing the model and the relevant project. Which does not need to be the root, but can be.
toPerform.eclipse(project, model);
toPerform.accept(project, model);
});
}

Expand All @@ -205,7 +252,7 @@ public void onEclipse(final EclipseIdeImportAction toPerform) {
* @param toPerform the actions to perform
*/
public void onGradle(final GradleIdeImportAction toPerform) {
if (!isEclipseImport() && !isIdeaImport()) {
if (!isEclipseImport() && !isIdeaImport() && !isDefinitelyVscodeImport(project)) {
toPerform.gradle(project);
}
}
Expand Down Expand Up @@ -249,8 +296,22 @@ public interface EclipseIdeImportAction {
void eclipse(Project project, EclipseModel eclipse);
}

/**
* A configuration action for vscode IDE projects.
*/
public interface VscodeIdeImportAction {

/**
* Configure an vscode project.
*
* @param project the project being imported
* @param eclipse the eclipse project model to modify
*/
void vscode(Project project, EclipseModel eclipse);
}

/**
* A configuration action for IDE projects.
*/
public interface IdeImportAction extends IdeaIdeImportAction, EclipseIdeImportAction, GradleIdeImportAction { }
public interface IdeImportAction extends IdeaIdeImportAction, EclipseIdeImportAction, VscodeIdeImportAction, GradleIdeImportAction { }
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package net.neoforged.gradle.common.runs.ide;

import cz.nightenom.vsclaunch.BatchedLaunchWriter;
import cz.nightenom.vsclaunch.LaunchConfiguration;
import cz.nightenom.vsclaunch.attribute.PathLike;
import cz.nightenom.vsclaunch.attribute.ShortCmdBehaviour;
import cz.nightenom.vsclaunch.writer.WritingMode;
import net.neoforged.elc.configs.GradleLaunchConfig;
import net.neoforged.elc.configs.JavaApplicationLaunchConfig;
import net.neoforged.elc.configs.LaunchConfig;
Expand Down Expand Up @@ -179,6 +184,47 @@ public void eclipse(Project project, EclipseModel eclipse) {
});
}

@Override
public void vscode(Project project, EclipseModel eclipse)
{
ProjectUtils.afterEvaluate(project, () -> {
final BatchedLaunchWriter launchWriter = new BatchedLaunchWriter(WritingMode.MODIFY_CURRENT);
project.getExtensions().configure(RunsConstants.Extensions.RUNS, (Action<NamedDomainObjectContainer<Run>>) runs -> runs.getAsMap().forEach((name, run) -> {
final String runName = StringUtils.capitalize(project.getName() + " - " + StringUtils.capitalize(name.replace(" ", "-")));
final RunImpl runImpl = (RunImpl) run;

final TaskProvider<?> ideBeforeRunTask = createIdeBeforeRunTask(project, name, run, runImpl);

final LaunchConfiguration cfg = launchWriter.createGroup("NG - " + project.getName(), WritingMode.REMOVE_EXISTING)
.createLaunchConfiguration()
.withAdditionalJvmArgs(runImpl.realiseJvmArguments())
.withArguments(runImpl.getProgramArguments().get())
.withCurrentWorkingDirectory(PathLike.ofNio(runImpl.getWorkingDirectory().get().getAsFile().toPath()))
.withEnvironmentVariables(adaptEnvironment(runImpl, RunsUtil::buildRunWithEclipseModClasses))
.withShortenCommandLine(ShortCmdBehaviour.ARGUMENT_FILE)
.withMainClass(runImpl.getMainClass().get())
.withProjectName(project.getName())
.withName(runName);

if (IdeManagementExtension.isDefinitelyVscodeImport(project))
{
ideBeforeRunTask.configure(task -> addEclipseCopyResourcesTasks(eclipse, run, t -> task.dependsOn(t)));
cfg.withPreTaskName("gradle: " + ideBeforeRunTask.getName());
}
else
{
addEclipseCopyResourcesTasks(eclipse, run, eclipse::autoBuildTasks);
eclipse.autoBuildTasks(ideBeforeRunTask);
}
}));
try {
launchWriter.writeToLatestJson(project.getRootDir().toPath());
} catch (final IOException e) {
throw new RuntimeException("Failed to write launch files", e);
}
});
}

private static String quoteAndJoin(List<String> args) {
return quoteStream(args).collect(Collectors.joining(" "));
}
Expand All @@ -198,7 +244,7 @@ private static String quote(String arg) {
return "\"" + arg + "\"";
}

private TaskProvider<?> createIdeBeforeRunTask(Project project, String name, Run run, RunImpl runImpl) {
private TaskProvider<?> createIdeBeforeRunTask(Project project, String name, Run run, RunImpl runImpl, boolean addDefaultProcessResources) {
final TaskProvider<?> ideBeforeRunTask = project.getTasks().register(CommonRuntimeUtils.buildTaskName("ideBeforeRun", name), task -> {
RunsUtil.addRunSourcesDependenciesToTask(task, run);
});
Expand All @@ -214,6 +260,39 @@ private TaskProvider<?> createIdeBeforeRunTask(Project project, String name, Run

return ideBeforeRunTask;
}

private TaskProvider<?> createEclipseBeforeRunTask(EclipseModel eclipse, Project project, String name, Run run, RunImpl runImpl) {
final TaskProvider<?> ideBeforeRunTask = createIdeBeforeRunTask(project, name, run, runImpl, false);

for (SourceSet sourceSet : run.getModSources().get()) {
final Project sourceSetProject = SourceSetUtils.getProject(sourceSet);

//The following tasks are not guaranteed to be in the source sets build dependencies
//We however need at least the classes as well as the resources of the source set to be run
final String taskName = CommonRuntimeUtils.buildTaskName("eclipse", sourceSet.getProcessResourcesTaskName());
final TaskProvider<?> eclipseResourcesTask;

if (sourceSetProject.getTasks().findByName(taskName) != null)
{
eclipseResourcesTask = sourceSetProject.getTasks().named(taskName);
}
else
{
eclipseResourcesTask = sourceSetProject.getTasks().register(taskName, Copy.class, t -> {
final TaskProvider<ProcessResources> defaultProcessResources =
sourceSetProject.getTasks().named(sourceSet.getProcessResourcesTaskName(), ProcessResources.class);
t.from(defaultProcessResources.get().getDestinationDir());
t.into(eclipse.getClasspath().getDefaultOutputDir().toPath().resolve(sourceSet.getName()));

t.dependsOn(defaultProcessResources);
});
}

eclipse.autoBuildTasks(eclipseResourcesTask);
}

return ideBeforeRunTask;
}

private void addEclipseCopyResourcesTasks(EclipseModel eclipse, Run run, Consumer<TaskProvider<?>> tasksConsumer) {
for (SourceSet sourceSet : run.getModSources().get()) {
Expand Down
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ jetbrains_annotations_version=23.0.0
gradle_idea_extension_version=1.1.6
groovy_dsl_improver_version=1.0.13
eclipse_launch_configs_version=0.1.3
vscode_launch_configs_version=1.0.4

#Test dependencies
junit_version=5.9.2
Expand Down
Loading