paparazzi icon indicating copy to clipboard operation
paparazzi copied to clipboard

lateinit property mergeResourcesTask has not been initialized

Open PaulWoitaschek opened this issue 2 years ago • 8 comments

Description We have several gradle modules that are pure compose. Our project default is android.library.defaults.buildfeatures.androidresources=false. If you run paparrazi on a module without androidResources, it crashes in the configuration phase.

Caused by: kotlin.UninitializedPropertyAccessException: lateinit property mergeResourcesTask has not been initialized
        at com.android.build.gradle.internal.scope.MutableTaskContainer.getMergeResourcesTask(MutableTaskContainer.kt:67)
        at com.android.build.gradle.internal.api.BaseVariantImpl.getMergeResourcesProvider(BaseVariantImpl.java:384)
        at com.android.build.gradle.internal.api.LibraryVariantImpl_Decorated.getMergeResourcesProvider(Unknown Source)
        at app.cash.paparazzi.gradle.PaparazziPlugin.setupPaparazzi$lambda-22(PaparazziPlugin.kt:68)
        at org.gradle.configuration.internal.DefaultUserCodeApplicationContext$CurrentApplication$1.execute(DefaultUserCodeApplicationContext.java:123)
        at org.gradle.api.internal.DefaultCollectionCallbackActionDecorator$BuildOperationEmittingAction$1.run(DefaultCollectionCallbackActionDecorator.java:110)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68)
        at org.gradle.api.internal.DefaultCollectionCallbackActionDecorator$BuildOperationEmittingAction.execute(DefaultCollectionCallbackActionDecorator.java:107)
        at org.gradle.internal.ImmutableActionSet$SetWithFewActions.execute(ImmutableActionSet.java:285)
        at org.gradle.api.internal.DefaultDomainObjectCollection.doAdd(DefaultDomainObjectCollection.java:262)
        at org.gradle.api.internal.DefaultDomainObjectCollection.add(DefaultDomainObjectCollection.java:251)
        at com.android.build.gradle.LibraryExtension.addVariant(LibraryExtension.kt:102)
        at com.android.build.gradle.internal.ApiObjectFactory.create(ApiObjectFactory.java:115)
        ... 184 more
  • Paparazzi Version: 1.0.0
  • OS: Macos
  • Compile SDK: 32
  • Gradle Version: 7.4.2
  • Android Gradle Plugin Version: 7.3.0-beta04

PaulWoitaschek avatar Jun 24 '22 17:06 PaulWoitaschek

Ok, took a shot at this (branch), and it's a bit tricky.

We can read the buildFeatures.androidResources flag off the LibraryBuildFeatures extension and use that to:

  1. write a dummy sentinel value to resources.txt in place of the merged resources path, and
  2. ignore looking for the module-specific R class when non transitive R classes are enabled

but...if the view/composable under snapshot is part of a larger view/composable hierarchy which looks up resources, then things will still crash because of 1. Ultimately variant.mergeResourcesProvider is not present when androidResources = false, but we kinda need it, in order to use its output directory in order to read the other transitive resources.

So, I think:

  • the workaround for now, is to not disable this flag. Hopefully running AAPT on a module without resources isn't really a huge speed slowdown.
  • the real fix is not to use mergeResourcesProvider.outputDir, but rather the original resource source sets (or nothing, if the flag is enabled) as tracked in https://github.com/cashapp/paparazzi/issues/524.

jrodbx avatar Sep 20 '22 02:09 jrodbx

Technically, this is now fixed by the work done in https://github.com/cashapp/paparazzi/issues/524, but let's move this and close in an upcoming release, once we deem the new mechanism stable and the old code deleted.

jrodbx avatar Jul 08 '23 23:07 jrodbx

I do not see this working out-of-the-box with 1.3.1. Stacktrace is mostly the same

Caused by: kotlin.UninitializedPropertyAccessException: lateinit property mergeResourcesTask has not been initialized
	at com.android.build.gradle.internal.scope.MutableTaskContainer.getMergeResourcesTask(MutableTaskContainer.kt:67)
	at com.android.build.gradle.internal.api.BaseVariantImpl.getMergeResourcesProvider(BaseVariantImpl.java:394)
	at com.android.build.gradle.internal.api.LibraryVariantImpl_Decorated.getMergeResourcesProvider(Unknown Source)
	at app.cash.paparazzi.gradle.PaparazziPlugin$setupPaparazzi$1.invoke(PaparazziPlugin.kt:119)
	at app.cash.paparazzi.gradle.PaparazziPlugin$setupPaparazzi$1.invoke(PaparazziPlugin.kt:115)
	at app.cash.paparazzi.gradle.PaparazziPlugin.setupPaparazzi$lambda$7(PaparazziPlugin.kt:115)
	at org.gradle.configuration.internal.DefaultUserCodeApplicationContext$CurrentApplication$1.execute(DefaultUserCodeApplicationContext.java:123)
	at org.gradle.api.internal.DefaultCollectionCallbackActionDecorator$BuildOperationEmittingAction$1.run(DefaultCollectionCallbackActionDecorator.java:110)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68)
	at org.gradle.api.internal.DefaultCollectionCallbackActionDecorator$BuildOperationEmittingAction.execute(DefaultCollectionCallbackActionDecorator.java:107)
	at org.gradle.internal.ImmutableActionSet$SetWithFewActions.execute(ImmutableActionSet.java:285)
	at org.gradle.api.internal.DefaultDomainObjectCollection.doAdd(DefaultDomainObjectCollection.java:262)
	at org.gradle.api.internal.DefaultDomainObjectCollection.add(DefaultDomainObjectCollection.java:251)
	at com.android.build.gradle.LibraryExtension.addVariant(LibraryExtension.kt:102)
	at com.android.build.gradle.internal.ApiObjectFactory.create(ApiObjectFactory.java:119)
	... 188 more

JakeWharton avatar Jul 18 '23 14:07 JakeWharton

Seems like the legacy codepath is only ignored at runtime and not within the plugin which still wires its folders through the task. So that's why we have to wait until the legacy codepath is fully deleted.

JakeWharton avatar Jul 18 '23 14:07 JakeWharton

@PaulWoitaschek I delved deeper into this issue, and noticed currently we cannot support the module with androidresources=false, even if deleting legacy codepath for resource loading.

The reason is today Paparazzi is using ComposeView to render snapshot for compose and ComposeView is using android resource internally

java.lang.NoClassDefFoundError: androidx/customview/poolingcontainer/R$id
        at androidx.customview.poolingcontainer.PoolingContainer.<clinit>(PoolingContainer.kt:121)
        at androidx.compose.ui.platform.ViewCompositionStrategy$DisposeOnDetachedFromWindowOrReleasedFromPool.installFor(ViewCompositionStrategy.android.kt:97)
        at androidx.compose.ui.platform.AbstractComposeView.<init>(ComposeView.android.kt:125)
        at androidx.compose.ui.platform.ComposeView.<init>(ComposeView.android.kt:418)
        at androidx.compose.ui.platform.ComposeView.<init>(ComposeView.android.kt:414)
        at app.cash.paparazzi.Paparazzi.snapshot(Paparazzi.kt:199)
        at app.cash.paparazzi.Paparazzi.snapshot$default(Paparazzi.kt:198)
        at app.cash.paparazzi.sample.HelloComposeTest.compose(HelloComposeTest.kt:25)

But there is no issue for compose preview in Android Studio, so we need to investigate further to update how compose is rendered in Paparazzi

cc @jrodbx @JakeWharton

kevinzheng-ap avatar Aug 01 '23 00:08 kevinzheng-ap