Customize VisualStudio plugin tasks to generate vcxproj.user file

Hello,

I am trying to customize default Visual Studio gradle tasks to generate a vcxproj.user file along the vcxproj file for every project in a solution that is an executable (I want to skip libraries).

The idea was to find all tasks that are of type GenerateProjectFileTask, somehow filter only those that represent an executable binary (this part I don’t know how to do yet) and a finalizedBy clause to make them run my task that will also generate the .user file.

I need this since my project has a custom workingDirectory path and I have to regenerate the project each time I add new source files etc. and obviously when I do so (after clean) I have to set those paths again for each executable. This is pretty annoying.

What I was trying to do so far was

subprojects {
    // every proejct with plugin cpp also uses visual-studio plugin
    plugins.withId('cpp') {
        afterEvaluate {
      tasks.withType(GenerateProjectFileTask) { task ->
        def project = task.getVisualStudioProject()
        if(project != null) {
          println project.projectFile.location
        }
        else {
          println "Project is null"
        }
          //println task.getOutputFile().getPath() <- this didnt work either
          task.finalizedBy "someGeneratedTaskForEachProjectToCreateUserProperties"
      }
        }
    }
}

But it always prints null and I don’t understand why. I need the path to know where to generate the file.

Also I dont like the finalizedBy clause since it always run no matter if the finalized task failed or not. Is there a better solution to this problem?

In short what I want to achieve is when I run a task for instance: gradlew demoAppVisualStudio it should generate not only solution and all necessary projects but also run my generated tasks for projects that represent executable to create additonal vcxproj.user file with contents I will prepare (mainly the <LocalDebuggerWorkingDirectory> part)

Everytime I have to do something in gradle I feel like I am hacking NASA. Finally I managed to do what I wanted but it looks so ugly that I am not sure if this is even close to the ‘proper’ solution of this problem.

subprojects { subproj ->
  plugins.withId('cpp') {
    model {
      components {
        withType(NativeExecutableSpec) { c ->
          subproj.tasks.whenTaskAdded {
            if(it.name == "${c.name}VisualStudio") {

              it.dependsOn task("${c.name}_${c.name}VisualStudioUserProperties", type:Task) {

                def projectTask = tasks["${c.name}_${c.name}ExeVisualStudioProject"]
                def path = projectTask.outputs.files.singleFile.parentFile.absolutePath
                def outputPath = "${path}/${c.name}_${c.name}Exe.vcxproj.user"
                
                inputs.file(file("data/vsDebuggerWorkingDirectory.xml"))
                outputs.file(outputPath)
                
                doLast {
                  new File(outputPath).write(("${inputs.files.singleFile.text}"))
                }
                mustRunAfter "${c.name}_${c.name}ExeVisualStudioProject"
              }
            }
          }
        }
      }
    }
  }
}

Can it be done easier?