使环境变量可供 Gradle 任务访问



我需要在 shell 环境中运行一个 Gradle 任务,该任务必须在任务启动之前创建。使用commandLineexecutable是不合适的,因为我需要在与 shell 脚本相同的进程中运行任务。最初,我直接在gradlew中调用脚本,但后来我决定从build.gradle.kts获取它,并通过gradlew调用后续任务:

val setupRosEnv by tasks.creating(Exec::class) {
executable = "bash"
args("-c", "source $rosPath/setup.sh && source gradlew myTask")
}

我可以通过从 CLI 运行./gradlew setupRosEnv来构建所有内容。除了获取脚本然后运行gradlew之外,有没有办法使用 Gradle API 来实现这一点?当前的解决方案似乎有点笨拙,并且对于其他任务依赖于setupRosEnv来说很笨拙,因为这将导致无限循环或必须显式处理以防止任务多次运行。

由于 shell 脚本本身是由 ROS 生成的,因此无法将其转换为 Gradle 或轻松解析。

这取决于您的 gradle 任务myTask如何使用环境。如果它通过System.getenv使用环境,则可以使用以下步骤。

  1. 解析 bash 环境文件env.sh并将所有变量加载到Properties
  2. 通过反射将环境变量附加到java.lang.ProcessEnvironment中的当前进程
  3. 在构建任务中使用注入的环境变量

下面是一个粗略地从 Java 复制的示例代码,经过细微修改,但它在 gradle 构建任务中工作正常。

task myEnvironInjected << {
println("task with injected enviroment")
}
task myBuildTask(dependsOn: myEnvironInjected) << {
def v1 = System.getenv("V1")
println("my build task running V1=${v1}")
}
myEnvironInjected.doFirst {
final Map<String, String> bashEnvMap = new HashMap<>();
try {
// a simple simulation of bash command source env.sh
// use it carefully
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream
("/path/to/env.sh")));
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
String line;
while ((line = reader.readLine()) != null) {
if (line.length() > 0 && line.startsWith("export ")) {
String newLine = line.trim().replaceFirst("^export ", "");
// remove single or double quote from the value if it has
int quoteIndex = newLine.indexOf('=')+1;
if (quoteIndex < newLine.length() && (newLine.charAt(quoteIndex) == ('"' as char) ||
newLine.charAt(quoteIndex) == (''' as char))) {
newLine = newLine.substring(0, quoteIndex) + newLine.substring(quoteIndex+1, newLine.length()-1);
}
writer.write(newLine);
writer.newLine();
}
}
writer.flush();
writer.close();
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
Properties properties = new Properties();
properties.load(inputStream);
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
bashEnvMap.put(((String) entry.getKey()), ((String) entry.getValue()));
}
outputStream.close();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
for (Class<?> aClass : Collections.class.getDeclaredClasses()) {
if ("java.util.Collections$UnmodifiableMap".equals(aClass.getName())) {
try {
Field mapField = aClass.getDeclaredField("m");
mapField.setAccessible(true);
Object mapObject = mapField.get(System.getenv());
Map<String, String> environMap = ((Map<String, String>) mapObject);
environMap.putAll(bashEnvMap);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
for (Map.Entry<String, String> envEntry : System.getenv().entrySet()) {
System.out.println(envEntry.getKey() + "=" + envEntry.getValue());
}
}

我的测试文件env.sh如下所示。

export V1="v1 vvv"
export V2='v 2222'
export V3=v33333

如果您的构建任务不使用环境变量System.getenv,您的黑客方法可能是最好的解决方案。

task myBuildTaskWithSourceEnv(type: Exec) {
commandLine '/bin/bash'
setArgs(['-c', 'source ../env.sh;set;../gradlew :app:assembleDebug'])
}

最新更新