18

How can I pass variables to Exec during execution? I want to write a pass through gradle file that will exec my current build commands which let's me move configuration from build server plans to source control managed build.gradle file. This is also part of my getting to know gradle in preparation for larger projects.

I want to have execute commands using different variables for configurations. In ant, I'd set my properties and then pass them to exec via nested env blocks. In gradle, I'm populating a map which I merge with the task's environment but this isn't working.

I can't add '<<' to the checkenv so the task code executes prior buildEnvironmentVariables being populated or is in the wrong scope. I know I'm not following proper task configuration.

Please offer suggestions or point me at the right part of the manual/docs.

build.gradle - execution gradle checkenv

def buildEnvironmentVariables = [:]
task setEnv() << {
    buildEnvironmentVariables['JAVA_OPTS']="-XX:ErrorFile=foo/logs" 
}

task checkenv(dependsOn: 'printEnv', type:Exec) {
    workingDir '../..'
    executable = 'cmd'
    environment << buildEnvironmentVariables
    println "buildEnvironmentVariables = " << buildEnvironmentVariables['JAVA_OPTS']
    args = ['/c','set','JAVA_OPTS']
}

Should I be only adding a task to the project when it is the equivalent of a "target" and encapsulating actions like the exec within the top level tasks?

Added task is like ant target and encapsulated tasks is like ant task?

def buildEnvironmentVariables = [:]
task setEnv() << {
    buildEnvironmentVariables['JAVA_OPTS']="-XX:ErrorFile=foo/logs" 
}

task checkenv(dependsOn: 'printEnv') << {
    println "buildEnvironmentVariables = " << buildEnvironmentVariables['JAVA_OPTS']
    ext.check = exec() {
        workingDir '../..'
        executable = 'cmd'
        environment << buildEnvironmentVariables
        args = ['/c','set','JAVA_OPTS']
    }
}

Thanks

Peter Kahn
  • 12,364
  • 20
  • 77
  • 135

2 Answers2

36

It's probably better to start from a clean slate:

task doSomething(type: Exec) {
    workingDir ...
    executable ...
    args ...
    environment JAVA_OPTS: "-XX:ErrorFile=foo/logs"
}

You can then run this task with gradle doSomething. Does this accomplish your goals?

Peter Niederwieser
  • 121,412
  • 21
  • 324
  • 259
  • Close to it. I want to have a setenv that determines OS and sets environment accordingly and a generic runCommand task. Guess, I could bundle the setting of environment based on OS into a single tasks but feels like that would combine different concerns in a single code block (I'm being pedantic though). – Peter Kahn Oct 05 '12 at 21:45
  • Actually, What I really should do is create a custom task "BuildShell" which automatically selects between cmd or sh and accepts additional env map. That's how we handled this in ant and I can replicate in gradle much easier. – Peter Kahn Oct 05 '12 at 21:55
  • 1
    In Gradle, you typically make such decisions in the *configuration phase*, without using a separate task. For example, you can do things like `tasks.withType(Exec) { environment ... }` to configure all `Exec` tasks at once. – Peter Niederwieser Oct 06 '12 at 03:17
  • Oh, that's excellent. Thanks Peter. I'll follow that pattern. I had a feeling I was confusing the two phases. – Peter Kahn Oct 06 '12 at 14:19
  • Similar thread here that incorporates some of Peter Niederwieser's suggestions: http://stackoverflow.com/questions/27530263/unable-to-build-gstreamer-tutorials-using-android-studio – svenyonson Dec 18 '14 at 16:42
8

Ok, here's the course I eventually followed using the patterns Peter N. suggested

  • Define/use routines for detection of OS and Arch
  • Method to configuration environment for all exec tasks during configuration
  • Example exec task

.........

import org.apache.tools.ant.taskdefs.condition.Os

def is64Arch() {
    return System.properties['os.arch'].toLowerCase().contains('64')
}

task configureEnvironment() {
    def envVars = [:]


    envVars['JAVA_OPTS']="-Dlog.directory=target/logs -Djava.awt.headless=true -XX:ErrorFile=target/logs"

    if (is64Arch()) 
    {
        envVars['JAVA_OPTS'] +=" -Xmx2048m -XX:MaxPermSize=768m" 
        println "*** ARCH: 64"
    }
    else
    {
        envVars['JAVA_OPTS'] +=" -Xmx1792m -XX:MaxPermSize=512m" 
        println "*** ARCH: 86"
    }

    tasks.withType(Exec) { environment << envVars }

}


task checkJavaEnvVars(type:Exec)  {
    workingDir '../..'
    commandLine 'cmd','/c','set JAVA'
}
Peter Kahn
  • 12,364
  • 20
  • 77
  • 135
  • 1
    `configureEnvironment` should be a method, not a task. The import seems obsolete. – Peter Niederwieser Oct 15 '12 at 04:49
  • Actually, I eventually pulled the whole think into a plugin and a custom task to set env and then run the exec. It works well altough capturing both STDerr and STDout to the log still proves tricky as exec doesn't seem to provided a redirect. – Peter Kahn Jul 26 '16 at 15:50