Skip to content

Commit

Permalink
Allow configuration of java executable
Browse files Browse the repository at this point in the history
The path of the java executable can now be configured in the ProtobufExtension and/or specific GenerateProtoTask instances.

* GenerateProtoTask gains the javaExecutablePath Property,
* ProtobufExtension gains the javaExecutablePath Property and the defaultJavaExecutablePath provider, which provides the default path using the same logic as previous versions
* computeJavaExePath moved from GenerateProtoTask to ProtobufExtension since it is now only used in ProtobufExtension
* isWindows moved from GenerateProtoTask to Util since it is now used in GenerateProtoTask and ProtobufExtension
  • Loading branch information
wfhartford committed Mar 13, 2024
1 parent ee41e2f commit 35e4908
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 20 deletions.
30 changes: 10 additions & 20 deletions src/main/groovy/com/google/protobuf/gradle/GenerateProtoTask.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import org.gradle.api.file.ProjectLayout
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.logging.LogLevel
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.provider.ProviderFactory
import org.gradle.api.tasks.CacheableTask
Expand Down Expand Up @@ -95,6 +96,10 @@ public abstract class GenerateProtoTask extends DefaultTask {
private final ProjectLayout projectLayout = project.layout
private final ToolsLocator toolsLocator = project.extensions.findByType(ProtobufExtension).tools

@Input
final Property<String> javaExecutablePath = objectFactory.property(String)
.convention(project.extensions.findByType(ProtobufExtension).javaExecutablePath)

// These fields are set by the Protobuf plugin only when initializing the
// task. Ideally they should be final fields, but Gradle task cannot have
// constructor arguments. We use the initializing flag to prevent users from
Expand Down Expand Up @@ -210,15 +215,7 @@ public abstract class GenerateProtoTask extends DefaultTask {
}

static int getCmdLengthLimit(String os) {
return isWindows(os) ? WINDOWS_CMD_LENGTH_LIMIT : DEFAULT_CMD_LENGTH_LIMIT
}

static boolean isWindows(String os) {
return os != null && os.toLowerCase(Locale.ROOT).indexOf("win") > -1
}

static boolean isWindows() {
return isWindows(System.getProperty("os.name"))
return Utils.isWindows(os) ? WINDOWS_CMD_LENGTH_LIMIT : DEFAULT_CMD_LENGTH_LIMIT
}

static String escapePathUnix(String path) {
Expand All @@ -243,14 +240,6 @@ public abstract class GenerateProtoTask extends DefaultTask {
}
}

static String computeJavaExePath(boolean isWindows) throws IOException {
File java = new File(System.getProperty("java.home"), isWindows ? "bin/java.exe" : "bin/java")
if (!java.exists()) {
throw new IOException("Could not find java executable at " + java.path)
}
return java.path
}

void setOutputBaseDir(Provider<String> outputBaseDir) {
checkInitializing()
Preconditions.checkState(this.outputBaseDir == null, 'outputBaseDir is already set')
Expand Down Expand Up @@ -744,7 +733,7 @@ public abstract class GenerateProtoTask extends DefaultTask {
*/
private String createJarTrampolineScript(String jarAbsolutePath) {
assert jarAbsolutePath.endsWith(JAR_SUFFIX)
boolean isWindows = isWindows()
boolean isWindows = Utils.isWindows()
String jarFileName = new File(jarAbsolutePath).getName()
if (jarFileName.length() <= JAR_SUFFIX.length()) {
throw new GradleException(".jar protoc plugin path '${jarAbsolutePath}' has no file name")
Expand All @@ -754,15 +743,16 @@ public abstract class GenerateProtoTask extends DefaultTask {
(isWindows ? "bat" : "sh"))
try {
mkdirsForFile(scriptExecutableFile)
String javaExe = computeJavaExePath(isWindows)
String javaExe = javaExecutablePath.get()
// Rewrite the trampoline file unconditionally (even if it already exists) in case the dependency or versioning
// changes we don't need to detect the delta (and the file content is cheap to re-generate).
String trampoline = isWindows ?
"@ECHO OFF\r\n\"${escapePathWindows(javaExe)}\" -jar \"${escapePathWindows(jarAbsolutePath)}\" %*\r\n" :
"#!/bin/sh\nexec '${escapePathUnix(javaExe)}' -jar '${escapePathUnix(jarAbsolutePath)}' \"\$@\"\n"
scriptExecutableFile.write(trampoline, US_ASCII.name())
setExecutableOrFail(scriptExecutableFile)
logger.info("Resolved artifact jar: ${jarAbsolutePath}. Created trampoline file: ${scriptExecutableFile}")
logger.info("Resolved artifact jar: ${jarAbsolutePath}. " +
"Created trampoline file: ${scriptExecutableFile} with java executable ${javaExe}")
return scriptExecutableFile.path
} catch (IOException e) {
throw new GradleException("Unable to generate trampoline for .jar protoc plugin", e)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ abstract class ProtobufExtension {
@PackageScope
final Provider<String> defaultGeneratedFilesBaseDir

@PackageScope
final Provider<String> defaultJavaExecutablePath

public ProtobufExtension(final Project project) {
this.project = project
this.tasks = new GenerateProtoTaskCollection(project)
Expand All @@ -66,11 +69,23 @@ abstract class ProtobufExtension {
it.asFile.path
}
this.generatedFilesBaseDirProperty.convention(defaultGeneratedFilesBaseDir)
this.defaultJavaExecutablePath = project.provider {
computeJavaExePath()
}
this.javaExecutablePath.convention(defaultJavaExecutablePath)
this.sourceSets = project.objects.domainObjectContainer(ProtoSourceSet) { String name ->
new DefaultProtoSourceSet(name, project.objects)
}
}

static String computeJavaExePath() throws IOException {
File java = new File(System.getProperty("java.home"), Utils.isWindows() ? "bin/java.exe" : "bin/java")
if (!java.exists()) {
throw new IOException("Could not find java executable at " + java.path)
}
return java.path
}

@PackageScope
NamedDomainObjectContainer<ProtoSourceSet> getSourceSets() {
return this.sourceSets
Expand All @@ -97,6 +112,13 @@ abstract class ProtobufExtension {
@PackageScope
abstract Property<String> getGeneratedFilesBaseDirProperty()

/**
* The location of the java executable used to run java based
* code generation plugins. The default is the java executable
* running gradle.
*/
abstract Property<String> getJavaExecutablePath()

@PackageScope
void configureTasks() {
this.taskConfigActions.each { action ->
Expand Down
8 changes: 8 additions & 0 deletions src/main/groovy/com/google/protobuf/gradle/Utils.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,12 @@ class Utils {
}
}
}

static boolean isWindows(String os) {
return os != null && os.toLowerCase(Locale.ROOT).indexOf("win") > -1
}

static boolean isWindows() {
return isWindows(System.getProperty("os.name"))
}
}

0 comments on commit 35e4908

Please sign in to comment.