Tom Eyckmans wrote:


2009/9/16 Adam Murdoch <[email protected] <mailto:[email protected]>>



    Steve Appling wrote:



        Adam Murdoch wrote:



            Steve Appling wrote:

                I have not been paying enough attention to the source
                set changes, but one item caught my eye today that I
                really would like to see changed.

                I fully support the concept of source sets where you
                have groups of source divided by function: main, test,
                integTest, etc.  This is great!

                I don't, however, like the inclusion of the language
                as part of the task name. I don't think that the user
                should have to know whether to call compileGroovy or
                compile or compileScala.  I have been bit several
                times now by calling project:compile and nothing
                happens.  There is a compile task, it just does
                nothing.  I didn't know to call project:compileGroovy.


            I'm curious why you're calling the compile task from the
            command-line? Not that what you point out above isn't a
            problem, I think it is. If we know what your use case is,
            we can come up with a solution.

        The first time I ran into this was a dependency problem in the
        gradle-ui project.  It has:
          compileTest.dependsOn project( ':gradle-core' ).compileTest
        This is now broken because "compileTest" doesn't do anything.
         It needs to now be compileTestGroovy.  I didn't know that and
        it took me a while to puzzle out.

        Aside - Perhaps you could suggest a better way to do this.  We
        needed to have the tests in the gradle-ui project depend on
        the tests in the gradle-core project.  It seemed that this
        should be easier, but we solved it with the above task
        dependency and a configuration of:
           testCompile files(project( ':gradle-core'
        ).dependencyProject.source.test.classesDir)


    I think the best option is for projects to consume gradle-core's
    test classes using exactly the same mechanism as they do for
    gradle-core's production classes. Currently, we publish a jar
    containing the production classes to a configuration, and the
    other projects pick this up using a project dependency. We should
    do the same for the tests, though we might just publish the test
    classes dir, rather than bothering to jar them up.

    Then, the auto-wiring will pick up the correct dependencies,
    without anyone needing to explicitly add dependOn compile or
    compileTestGroovy or whatever.

    Something like:

    In gradle-core:

    configurations {
      testFixtures
      testFixturesRuntime
    }

    dependencies {
     testFixtures source.test.classes, source.test.compileClasspath
     testFixturesRuntime source.test.runtimeClasspath
    }

    In gradle-*

    dependencies {
     testCompile project(path: ':gradle-core', configuration:
    ':testFixtures')
     testRuntime project(path: ':gradle-core', configuration:
    ':testFixturesRuntime')

    }



        Later I noted that the gradle-ui/src/main/groovy only contains
        java files and I wanted to compare the compile speed for
        building this under groovy and under java. I was running
        gradlew :gradle-ui:compile and comparing the performance with
        a java directory and a groovy directory.  Surprisingly the
        groovy one was faster - but only because the compile task
        doesn't do anything when you have the groovy directory.  After
        comparing using the correct tasks I saw that it compiled about
        1.5 sec faster when under the java directory.  I plan to check
        it in this way.  This isn't a common thing to do, but it
        pointed out an area of confusion to me.  I do think that
        people call compile (and certainly test) directly and they
        shouldn't have to specify the language.


    Perhaps we should rename 'compile' to 'compileJava', and add a
    'compile' task which depends on {compileJava, compileGroovy,
    compileScala} as appropriate?


I also find it really ood to have to specify the language here, I thought we planned on having a distinction between main and test source sets and have the compile and compileTests as tasks that compile all main source sets and compileTests compile all test source sets.


I'm curious why you would want to do this? What use cases do you have in mind?

Right now, source sets are untyped, so there is no distinction between which are production source sets and which are test source sets. I still think it is a good idea to type them somehow. My plan was to go slowly at this, and leave them untyped for the 0.8 release. Then, we can see how they are being used and what does and does not work, and address that in later releases.

I'm not, for example, 100% convinced that 'main' and 'test' is the right way to slice them. It feels to me we want a more descriptive slicing, something like:
- library
- application
- web app
- unit tests
- integration tests

We might allow multiple of the 'roles' to be applied to a source set. One option would be to allow plugins to be applied to a source set:

source {
  main {
     usePlugin 'java-application'  // (1)
     mainClass = 'org.gradle.BootstrapMain'

     usePlugin 'library' // (2)
     api {
          exclude '**/internal/*
     }
  }
  test {
       usePlugin 'library' // (3)
  }
  integTest {
      usePlugin 'integration-test' // (4)
  }
}

Where

(1) might add a dist task which creates a Zip containing launcher scripts, the runtime classpath, the main jar, plus anything from src/dist. Similarly, it might also add sourceDist, distTar, distTarGz and explodedDist tasks which do the same thing in different formats. It might also add the dist archives to the 'dists' configuration.

(2) might add the javadoc task, and wire it up so it is included in the dist image. It might also add an apiJar task, and include that Jar in the 'api' configuration.

(3) might publish the test classes api to the 'testFixtures' configuration, and the test classes impl to the 'testFixturesRuntime' configuration.

(4) might add in an integTest task which runs against the main jar from the dist image, rather than the main classes dir.

We might default to main { usePlugin 'library' } and test { usePlugin 'unit-test' }. Or maybe just test { usePlugin 'unit-test' }.

We still get the distinction between production and test source sets, but we end up with a model that is much, much richer. We could also then fix up some odd things like the fact that the war plugin disables the jar task.

To limit the gradle -t output we need to have a way to segment the output, like for synthetic tasks for source sets only show the global tasks that execute all of the main/test source set compiles/tests/....


This problem is independent of what we do with source sets, and affects anyone with large builds regardless of how the tasks get added.

We really need some way to distinguish between the important tasks that are intended for a user to run from the command-line, and all the internal tasks. Personally, I like John's suggestion of having gradle -t show only lifecycle tasks by default, and maybe having gradle -t --all show all the tasks.

Additionally, gradle -t might take a set of task name patterns, eg gradle -t compile*

Or perhaps we should get some HTML project reports happening, which could potentially offer a better way of exploring and navigating the tasks of the build.


Adam

Reply via email to