diff --git a/README.md b/README.md
index 06f92161..290e9e8d 100644
--- a/README.md
+++ b/README.md
@@ -315,12 +315,10 @@ task.plugins {
```gradle
protobuf {
- generatedFilesBaseDir = "$projectDir/generated"
-
generateProtoTasks {
all().each { task ->
task.builtins {
- // Generates Python code in the output folder:
+ // Generates Python code
python { }
// If you wish to avoid generating Java files:
@@ -410,7 +408,7 @@ protobuf {
```gradle
{ task ->
// If true, will generate a descriptor_set.desc file under
- // $generatedFilesBaseDir/$sourceSet. Default is false.
+ // task.outputBaseDir. Default is false.
// See --descriptor_set_out in protoc documentation about what it is.
task.generateDescriptorSet = true
@@ -430,19 +428,11 @@ protobuf {
#### Change where files are generated
-By default generated Java files are under
-``$generatedFilesBaseDir/$sourceSet/$builtinPluginName``, where
-``$generatedFilesBaseDir`` is ``$buildDir/generated/source/proto`` by default,
-and is configurable. E.g.,
-
-```gradle
-protobuf {
- ...
- generatedFilesBaseDir = "$projectDir/src/generated"
-}
-```
+Generated files are under `task.outputBaseDir` with a subdirectory per
+builtin and plugin. This produces a folder structure of
+``$buildDir/generated/source/proto/$sourceSet/$builtinPluginName``.
-The subdirectory name, which is by default ``$builtinPluginName``, can also be
+The subdirectory name, which is by default ``$builtinPluginName``, can be
changed by setting the ``outputSubDir`` property in the ``builtins`` or
``plugins`` block of a task configuration within ``generateProtoTasks`` block
(see previous section). E.g.,
@@ -451,8 +441,7 @@ changed by setting the ``outputSubDir`` property in the ``builtins`` or
{ task ->
task.plugins {
grpc {
- // Write the generated files under
- // "$generatedFilesBaseDir/$sourceSet/grpcjava"
+ // Use subdirectory 'grpcjava' instead of the default 'grpc'
outputSubDir = 'grpcjava'
}
}
@@ -521,29 +510,6 @@ This plugin integrates with the ``idea`` plugin and automatically
registers the proto files and generated Java code as sources.
-```gradle
-apply plugin: 'idea'
-
-protobuf {
- ...
- generatedFilesBaseDir = "$projectDir/gen"
-}
-
-clean {
- delete protobuf.generatedFilesBaseDir
-}
-
-idea {
- module {
- // proto files and generated Java files are automatically added as
- // source dirs.
- // If you have additional sources, add them here:
- sourceDirs += file("/path/to/other/sources");
- }
-}
-```
-
-
## Testing the plugin
``testProject*`` are testing projects that uses this plugin to compile
diff --git a/config/codenarc/codenarc.xml b/config/codenarc/codenarc.xml
index 17af312e..12e743c1 100644
--- a/config/codenarc/codenarc.xml
+++ b/config/codenarc/codenarc.xml
@@ -82,9 +82,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+
diff --git a/src/main/groovy/com/google/protobuf/gradle/CopyActionFacade.java b/src/main/groovy/com/google/protobuf/gradle/CopyActionFacade.java
index 804f3aa7..64e08389 100644
--- a/src/main/groovy/com/google/protobuf/gradle/CopyActionFacade.java
+++ b/src/main/groovy/com/google/protobuf/gradle/CopyActionFacade.java
@@ -33,8 +33,11 @@
import org.gradle.api.Action;
import org.gradle.api.Project;
import org.gradle.api.file.CopySpec;
+import org.gradle.api.file.DeleteSpec;
import org.gradle.api.file.FileSystemOperations;
+import org.gradle.api.model.ObjectFactory;
import org.gradle.api.tasks.WorkResult;
+import org.gradle.util.GradleVersion;
import javax.inject.Inject;
@@ -46,6 +49,18 @@
@CompileStatic
interface CopyActionFacade {
WorkResult copy(Action super CopySpec> var1);
+ WorkResult delete(Action super DeleteSpec> action);
+
+ @CompileStatic
+ final class Loader {
+ public static CopyActionFacade create(Project project, ObjectFactory objectFactory) {
+ if (GradleVersion.current().compareTo(GradleVersion.version("6.0")) >= 0) {
+ // Use object factory to instantiate as that will inject the necessary service.
+ return objectFactory.newInstance(CopyActionFacade.FileSystemOperationsBased.class);
+ }
+ return new CopyActionFacade.ProjectBased(project);
+ }
+ }
@CompileStatic
class ProjectBased implements CopyActionFacade {
@@ -59,6 +74,11 @@ public ProjectBased(Project project) {
public WorkResult copy(Action super CopySpec> action) {
return project.copy(action);
}
+
+ @Override
+ public WorkResult delete(Action super DeleteSpec> action) {
+ return project.delete(action);
+ }
}
@CompileStatic
@@ -70,5 +90,10 @@ abstract class FileSystemOperationsBased implements CopyActionFacade {
public WorkResult copy(Action super CopySpec> action) {
return getFileSystemOperations().copy(action);
}
+
+ @Override
+ public WorkResult delete(Action super DeleteSpec> action) {
+ return getFileSystemOperations().delete(action);
+ }
}
}
diff --git a/src/main/groovy/com/google/protobuf/gradle/GenerateProtoTask.groovy b/src/main/groovy/com/google/protobuf/gradle/GenerateProtoTask.groovy
index 2e6f2510..ff419f2e 100644
--- a/src/main/groovy/com/google/protobuf/gradle/GenerateProtoTask.groovy
+++ b/src/main/groovy/com/google/protobuf/gradle/GenerateProtoTask.groovy
@@ -81,6 +81,7 @@ public abstract class GenerateProtoTask extends DefaultTask {
static final int CMD_ARGUMENT_EXTRA_LENGTH = 3
private static final String JAR_SUFFIX = ".jar"
+ private final CopyActionFacade copyActionFacade = CopyActionFacade.Loader.create(project, objectFactory)
// include dirs are passed to the '-I' option of protoc. They contain protos
// that may be "imported" from the source protos, but will not be compiled.
private final ConfigurableFileCollection includeDirs = objectFactory.fileCollection()
@@ -587,6 +588,9 @@ public abstract class GenerateProtoTask extends DefaultTask {
void compile() {
Preconditions.checkState(state == State.FINALIZED, 'doneConfig() has not been called')
+ copyActionFacade.delete { spec ->
+ spec.delete(outputBaseDir)
+ }
// Sort to ensure generated descriptors have a canonical representation
// to avoid triggering unnecessary rebuilds downstream
List protoFiles = sourceDirs.asFileTree.files.sort()
diff --git a/src/main/groovy/com/google/protobuf/gradle/ProtobufExtension.groovy b/src/main/groovy/com/google/protobuf/gradle/ProtobufExtension.groovy
index 74c090e0..0de530f8 100644
--- a/src/main/groovy/com/google/protobuf/gradle/ProtobufExtension.groovy
+++ b/src/main/groovy/com/google/protobuf/gradle/ProtobufExtension.groovy
@@ -37,6 +37,7 @@ import groovy.transform.TypeCheckingMode
import org.gradle.api.Action
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project
+import org.gradle.api.provider.Property
import org.gradle.api.tasks.TaskCollection
/**
@@ -52,18 +53,16 @@ abstract class ProtobufExtension {
private final ArrayList> taskConfigActions
private final NamedDomainObjectContainer sourceSets
- /**
- * The base directory of generated files. The default is
- * "${project.buildDir}/generated/source/proto".
- */
- private String generatedFilesBaseDir
+ @PackageScope
+ final String defaultGeneratedFilesBaseDir
public ProtobufExtension(final Project project) {
this.project = project
this.tasks = new GenerateProtoTaskCollection(project)
this.tools = new ToolsLocator(project)
this.taskConfigActions = []
- this.generatedFilesBaseDir = "${project.buildDir}/generated/source/proto"
+ this.defaultGeneratedFilesBaseDir = "${project.buildDir}/generated/source/proto"
+ this.generatedFilesBaseDirProperty.convention(defaultGeneratedFilesBaseDir)
this.sourceSets = project.objects.domainObjectContainer(ProtoSourceSet) { String name ->
new DefaultProtoSourceSet(name, project.objects)
}
@@ -80,13 +79,21 @@ abstract class ProtobufExtension {
}
String getGeneratedFilesBaseDir() {
- return generatedFilesBaseDir
+ return generatedFilesBaseDirProperty.get()
}
+ @Deprecated
void setGeneratedFilesBaseDir(String generatedFilesBaseDir) {
- this.generatedFilesBaseDir = generatedFilesBaseDir
+ generatedFilesBaseDirProperty.set(generatedFilesBaseDir)
}
+ /**
+ * The base directory of generated files. The default is
+ * "${project.buildDir}/generated/source/proto".
+ */
+ @PackageScope
+ abstract Property getGeneratedFilesBaseDirProperty()
+
@PackageScope
void configureTasks() {
this.taskConfigActions.each { action ->
diff --git a/src/main/groovy/com/google/protobuf/gradle/ProtobufExtract.groovy b/src/main/groovy/com/google/protobuf/gradle/ProtobufExtract.groovy
index 3da54eab..faafcae8 100644
--- a/src/main/groovy/com/google/protobuf/gradle/ProtobufExtract.groovy
+++ b/src/main/groovy/com/google/protobuf/gradle/ProtobufExtract.groovy
@@ -57,7 +57,7 @@ import javax.inject.Inject
@CompileStatic
abstract class ProtobufExtract extends DefaultTask {
- private final CopyActionFacade copyActionFacade = instantiateCopyActionFacade()
+ private final CopyActionFacade copyActionFacade = CopyActionFacade.Loader.create(project, objectFactory)
private final ArchiveActionFacade archiveActionFacade = instantiateArchiveActionFacade()
private final FileCollection filteredProtos = instantiateFilteredProtos()
@@ -98,14 +98,6 @@ abstract class ProtobufExtract extends DefaultTask {
@Inject
protected abstract ProviderFactory getProviderFactory()
- private CopyActionFacade instantiateCopyActionFacade() {
- if (GradleVersion.current() >= GradleVersion.version("6.0")) {
- // Use object factory to instantiate as that will inject the necessary service.
- return objectFactory.newInstance(CopyActionFacade.FileSystemOperationsBased)
- }
- return new CopyActionFacade.ProjectBased(project)
- }
-
private ArchiveActionFacade instantiateArchiveActionFacade() {
if (GradleVersion.current() >= GradleVersion.version("6.0")) {
// Use object factory to instantiate as that will inject the necessary service.
diff --git a/src/main/groovy/com/google/protobuf/gradle/ProtobufPlugin.groovy b/src/main/groovy/com/google/protobuf/gradle/ProtobufPlugin.groovy
index 8d237f4c..9853f0ee 100644
--- a/src/main/groovy/com/google/protobuf/gradle/ProtobufPlugin.groovy
+++ b/src/main/groovy/com/google/protobuf/gradle/ProtobufPlugin.groovy
@@ -374,15 +374,29 @@ class ProtobufPlugin implements Plugin {
) {
String sourceSetName = protoSourceSet.name
String taskName = 'generate' + Utils.getSourceSetSubstringForTaskNames(sourceSetName) + 'Proto'
- Provider outDir = project.providers.provider {
- "${this.protobufExtension.generatedFilesBaseDir}/${sourceSetName}".toString()
- }
+ String defaultGeneratedFilesBaseDir = protobufExtension.defaultGeneratedFilesBaseDir
+ Provider generatedFilesBaseDirProvider = protobufExtension.generatedFilesBaseDirProperty
Provider task = project.tasks.register(taskName, GenerateProtoTask) {
+ CopyActionFacade copyActionFacade = CopyActionFacade.Loader.create(it.project, it.objectFactory)
it.description = "Compiles Proto source for '${sourceSetName}'".toString()
- it.outputBaseDir = outDir
+ it.outputBaseDir = project.providers.provider {
+ "${defaultGeneratedFilesBaseDir}/${sourceSetName}".toString()
+ }
it.addSourceDirs(protoSourceSet.proto)
it.addIncludeDir(protoSourceSet.proto.sourceDirectories)
it.addIncludeDir(protoSourceSet.includeProtoDirs)
+ it.doLast { task ->
+ String generatedFilesBaseDir = generatedFilesBaseDirProvider.get()
+ if (generatedFilesBaseDir == defaultGeneratedFilesBaseDir) {
+ return
+ }
+ // Purposefully don't wire this up to outputs, as it can be mixed with other files.
+ copyActionFacade.copy { CopySpec spec ->
+ spec.includeEmptyDirs = false
+ spec.from(it.outputBaseDir)
+ spec.into("${generatedFilesBaseDir}/${sourceSetName}")
+ }
+ }
configureAction.execute(it)
}
protoSourceSet.output.from(task.map { GenerateProtoTask it -> it.outputSourceDirectories })