Debugging Gradle daemon while using Tools API

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Debugging Gradle daemon while using Tools API

alex.ruiz.05
Greetings,

I'm new to Gradle and I'm learning how the Tooling API work. I wrote a simple program, similar to one of the samples in the samples/toolingApi. It has a main method and I'm debugging it to see what it does.

The issue I found is that I cannot step into the Gradle daemon with the debugger. I try Google and StackOverflow but nothing really useful.

I'm using Gradle v 1.5-20130227173909+0000

Any help will be greatly appreciated.

Regards,
-Alex
Reply | Threaded
Open this post in threaded view
|

Re: Debugging Gradle daemon while using Tools API

alex.ruiz.05
I got it working by using an embedded daemon. Doing all the wiring required used of reflection though. The key was to override some functionality in the creation of the GradleConnector.

Here is the code:

  private static GradleConnector getGradleConnector() {
    ToolingImplementationLoader delegate = new DefaultToolingImplementationLoader();
    final SynchronizedToolingImplementationLoader loader = new SynchronizedToolingImplementationLoader(delegate);
    final ProtocolToModelAdapter adapter = new ProtocolToModelAdapter();
    final DefaultExecutorFactory executorFactory = new DefaultExecutorFactory();
    ConnectionFactory connectionFactory = new ConnectionFactory(loader) {
      @Override
      public ProjectConnection create(Distribution distribution, ConnectionParameters parameters) {
        try {
          Field field = DefaultConnectionParameters.class.getDeclaredField("embedded");
          field.setAccessible(true);
          field.set(parameters, Boolean.TRUE);
        } catch (Throwable e) {
          throw new RuntimeException(e);
        }
        SynchronizedLogging synchronizedLogging = new SynchronizedLogging();
        ConsumerConnection lazyConnection = new LazyConnection(distribution, loader, synchronizedLogging, parameters.getVerboseLogging());
        ConsumerConnection progressLoggingConnection = new ProgressLoggingConnection(lazyConnection, synchronizedLogging);
        final ConsumerConnection initializingConnection = new LoggingInitializerConnection(progressLoggingConnection, synchronizedLogging);
        AsyncConnection asyncConnection = new DefaultAsyncConnection(initializingConnection, executorFactory) {
          @Override
          public <T> void run(Class<T> type, ConsumerOperationParameters operationParameters, ResultHandlerVersion1<? super T> handler) throws UnsupportedOperationException, IllegalStateException {
            System.out.println(operationParameters.isEmbedded());
            super.run(type, operationParameters, handler);
            // initializingConnection.run(type, operationParameters);
          }
        };
        try {
          Class<?> type = Class.forName("org.gradle.tooling.internal.consumer.DefaultProjectConnection");
          Constructor<?> constructor =
              type.getConstructor(AsyncConnection.class, ProtocolToModelAdapter.class, ConnectionParameters.class);
          constructor.setAccessible(true);
          return (ProjectConnection) constructor.newInstance(asyncConnection, adapter, parameters);
        } catch (Throwable e) {
          throw new RuntimeException(e);
        }
      }
    };
    DistributionFactory distributionFactory = new DistributionFactory(new File("/Users/alruiz"));
    return new DefaultGradleConnector(connectionFactory, distributionFactory);
  }

Is there a better/easier way to do this?

Thanks,
-Alex
Reply | Threaded
Open this post in threaded view
|

Re: Debugging Gradle daemon while using Tools API

Adam Murdoch

On 01/03/2013, at 11:41 AM, alex.ruiz.05 wrote:

I got it working by using an embedded daemon. Doing all the wiring required
used of reflection though. The key was to override some functionality in the
creation of the GradleConnector.

Here is the code:

 private static GradleConnector getGradleConnector() {
   ToolingImplementationLoader delegate = new
DefaultToolingImplementationLoader();
   final SynchronizedToolingImplementationLoader loader = new
SynchronizedToolingImplementationLoader(delegate);
   final ProtocolToModelAdapter adapter = new ProtocolToModelAdapter();
   final DefaultExecutorFactory executorFactory = new
DefaultExecutorFactory();
   ConnectionFactory connectionFactory = new ConnectionFactory(loader) {
     @Override
     public ProjectConnection create(Distribution distribution,
ConnectionParameters parameters) {
       try {
         Field field =
DefaultConnectionParameters.class.getDeclaredField("embedded");
         field.setAccessible(true);
         field.set(parameters, Boolean.TRUE);
       } catch (Throwable e) {
         throw new RuntimeException(e);
       }
       SynchronizedLogging synchronizedLogging = new SynchronizedLogging();
       ConsumerConnection lazyConnection = new LazyConnection(distribution,
loader, synchronizedLogging, parameters.getVerboseLogging());
       ConsumerConnection progressLoggingConnection = new
ProgressLoggingConnection(lazyConnection, synchronizedLogging);
       final ConsumerConnection initializingConnection = new
LoggingInitializerConnection(progressLoggingConnection,
synchronizedLogging);
       AsyncConnection asyncConnection = new
DefaultAsyncConnection(initializingConnection, executorFactory) {
         @Override
         public <T> void run(Class<T> type, ConsumerOperationParameters
operationParameters, ResultHandlerVersion1<? super T> handler) throws
UnsupportedOperationException, IllegalStateException {
           System.out.println(operationParameters.isEmbedded());
           super.run(type, operationParameters, handler);
           // initializingConnection.run(type, operationParameters);
         }
       };
       try {
         Class<?> type =
Class.forName("org.gradle.tooling.internal.consumer.DefaultProjectConnection");
         Constructor<?> constructor =
             type.getConstructor(AsyncConnection.class,
ProtocolToModelAdapter.class, ConnectionParameters.class);
         constructor.setAccessible(true);
         return (ProjectConnection)
constructor.newInstance(asyncConnection, adapter, parameters);
       } catch (Throwable e) {
         throw new RuntimeException(e);
       }
     }
   };
   DistributionFactory distributionFactory = new DistributionFactory(new
File("/Users/alruiz"));
   return new DefaultGradleConnector(connectionFactory,
distributionFactory);
 }

Is there a better/easier way to do this?

You can just cast GradleConnector to DefaultGradleConnector:

DefaultGradleConnector connector = (DefaultGradleConnector)GradleConnector.newConnector();
connector.embedded(true);
//... configure connector as you would normally ...
ProjectConnection connection = connector.connect();


--
Adam Murdoch
Gradle Co-founder
http://www.gradle.org
VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting
http://www.gradleware.com

Reply | Threaded
Open this post in threaded view
|

Re: Debugging Gradle daemon while using Tools API

Adam Murdoch
In reply to this post by alex.ruiz.05

On 01/03/2013, at 10:08 AM, alex.ruiz.05 wrote:

Greetings,

I'm new to Gradle and I'm learning how the Tooling API work. I wrote a
simple program, similar to one of the samples in the samples/toolingApi. It
has a main method and I'm debugging it to see what it does.

The issue I found is that I cannot step into the Gradle daemon with the
debugger. I try Google and StackOverflow but nothing really useful.

I'm using Gradle v 1.5-20130227173909+0000

Any help will be greatly appreciated.

There are 2 options:

* Running in embedded mode, which you've already discovered. Note that this is currently an internal feature and not completely supported. The embedded daemon is not (or at least, not yet) very well behaved when it comes to sharing a jvm with the owning application - it doesn't handle concurrent builds very well, it messes with the logging levels, system properties, environment variable, and so on. Having said that, it works fine if you're testing stuff out.

* Starting the daemon with the appropriate jvm args using LongRunningOperation.setJvmArguments(). This approach is fully supported, but it's not particularly convenient for development work.


--
Adam Murdoch
Gradle Co-founder
http://www.gradle.org
VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting
http://www.gradleware.com

Reply | Threaded
Open this post in threaded view
|

Re: Debugging Gradle daemon while using Tools API

alex.ruiz.05
Thanks, Adam.

I think it would be handy that the "embedded" method be part of the public API. There is at least one use case of it (mine) :)

It can be explained in Javadoc that is not so well-behaved and "use it at your own risk". I filed feature request http://issues.gradle.org/browse/GRADLE-2696

Regards,
-Alex
Reply | Threaded
Open this post in threaded view
|

Re: Debugging Gradle daemon while using Tools API

alex.ruiz.05
Actually, a patch would be a better way to contribute. I'll just create one and leave it to you guys to decide if you want to apply it or not :)

Regards,
-Alex