使环境变量可用于Gradle任务

时间:2018-10-23 01:56:34

标签: bash gradle kotlin ros gradle-kotlin-dsl

我需要在外壳环境中运行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或轻松地对其进行解析。

1 个答案:

答案 0 :(得分:5)

这取决于您的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'])
}