Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ProGuard Gradle Plugin Throws an Exception When Outputting All Obfuscated Jars (outjars) to a Single Directory #442

Open
philliplbryant opened this issue Oct 14, 2024 · 1 comment

Comments

@philliplbryant
Copy link

philliplbryant commented Oct 14, 2024

proguard-outjars-error

The attached reproducer project (also located on GitHub here) uses the ProGuard Gradle plugin (version 7.5.0) to output all obfuscated jars (outjars) to a single directory for the purpose of demonstrating the plugin does not appear to support this feature as documented:

If you want to preserve the structure of your input jars (and/or apks, aars, wars, ears, jmods, zips, or directories), you can specify an output directory (or an apk, an aar, a war, an ear, a jmod, or a zip). For example:

-injars in1.jar
-injars in2.jar
-injars in3.jar
-outjars out

The input jars will then be reconstructed in the directory out, with their original names.

The reproducer project contains a markdown document, similar to this one, containing links to files referenced herein.

Observations

  • Specifying the single output directory in the ProGuard configuration file appears to work as documented above and demonstrated below.
  • Executing gradlew obfuscate --scan on the reproducer project does not report any warnings, deprecations, or errors.

Testing

  1. Execute gradlew obfuscate from the root project directory.
  2. Observe the single Zip file, ./my-application/build/release/obfuscated.zip) containing the obfuscated JARs is output.
  3. Modify the ProGuard Gradle plugin configuration, build-logic/src/main/kotlin/my.release.proguard-convention.gradle.kts, to output to a directory instead of a Zip file by changing outjars(obfuscatedJarsZipFile) to outjars(obfuscatedJarsDir) as marked with the FIXME comment.
  4. Execute gradlew obfuscate from the root project directory.
  5. Observe an exception is thrown, indicating something similar to:

Expected 'C:/Demos/proguard-outjars-error/my-application/build/release/obfuscated' to be a file

  1. Comment out the aforementioned outjars line altogether
  2. Add -outjars my-application/build/release/obfuscated to the ProGuard configuration file, shared-resources/obfuscation/proguard-configuration.pro, below -basedirectory ../../
  3. Execute gradlew obfuscate from the root project directory.
  4. Observe the single directory, my-application/build/release/obfuscated, containing the obfuscated JARs is output.
@ianbrandt
Copy link

With Gradle 8.10.2, ProGuard 7.6.0, and outjars(project.layout.buildDirectory.dir("obfuscated")), here is the error I get for my project:

FAILURE: Build failed with an exception.

* What went wrong:
A problem was found with the configuration of task ':my-app:obfuscate' (type 'ProGuardTask').
  - Type 'proguard.gradle.ProGuardTask' property 'outJarFileCollection' is not writable because 'C:\Dev\Repos\my-checkout\my-app\build\obfuscated' is not a file.
    
    Reason: Cannot write a file to a location pointing at a directory.
    
    Possible solutions:
      1. Configure 'outJarFileCollection' to point to a file, not a directory.
      2. Annotate 'outJarFileCollection' with @OutputDirectory instead of @OutputFiles.
    
    For more information, please refer to https://docs.gradle.org/8.10.2/userguide/validation_problems.html#cannot_write_output in the Gradle documentation.

* Try:
> Run with --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.

* Exception is:
org.gradle.internal.execution.WorkValidationException: A problem was found with the configuration of task ':my-app:obfuscate' (type 'ProGuardTask').
  - Type 'proguard.gradle.ProGuardTask' property 'outJarFileCollection' is not writable because 'C:\Dev\Repos\my-checkout\my-app\build\obfuscated' is not a file.
    
    Reason: Cannot write a file to a location pointing at a directory.
    
    Possible solutions:
      1. Configure 'outJarFileCollection' to point to a file, not a directory.
      2. Annotate 'outJarFileCollection' with @OutputDirectory instead of @OutputFiles.
    
    For more information, please refer to https://docs.gradle.org/8.10.2/userguide/validation_problems.html#cannot_write_output in the Gradle documentation.
	at org.gradle.internal.execution.WorkValidationException$BuilderWithSummary.build(WorkValidationException.java:137)
	at org.gradle.internal.execution.WorkValidationException$BuilderWithSummary.get(WorkValidationException.java:119)
	at org.gradle.internal.execution.steps.ValidateStep.throwValidationException(ValidateStep.java:174)
	at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:99)
	at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:56)
	at org.gradle.internal.execution.steps.AbstractCaptureStateBeforeExecutionStep.execute(AbstractCaptureStateBeforeExecutionStep.java:64)
	at org.gradle.internal.execution.steps.AbstractCaptureStateBeforeExecutionStep.execute(AbstractCaptureStateBeforeExecutionStep.java:43)
	at org.gradle.internal.execution.steps.AbstractSkipEmptyWorkStep.executeWithNonEmptySources(AbstractSkipEmptyWorkStep.java:125)
	at org.gradle.internal.execution.steps.AbstractSkipEmptyWorkStep.execute(AbstractSkipEmptyWorkStep.java:56)
	at org.gradle.internal.execution.steps.AbstractSkipEmptyWorkStep.execute(AbstractSkipEmptyWorkStep.java:36)
	at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:38)
	at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:36)
	at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:23)
	at org.gradle.internal.execution.steps.HandleStaleOutputsStep.execute(HandleStaleOutputsStep.java:75)
	at org.gradle.internal.execution.steps.HandleStaleOutputsStep.execute(HandleStaleOutputsStep.java:41)
	at org.gradle.internal.execution.steps.AssignMutableWorkspaceStep.lambda$execute$0(AssignMutableWorkspaceStep.java:35)
	at org.gradle.api.internal.tasks.execution.TaskExecution$4.withWorkspace(TaskExecution.java:289)
	at org.gradle.internal.execution.steps.AssignMutableWorkspaceStep.execute(AssignMutableWorkspaceStep.java:31)
	at org.gradle.internal.execution.steps.AssignMutableWorkspaceStep.execute(AssignMutableWorkspaceStep.java:22)
	at org.gradle.internal.execution.steps.ChoosePipelineStep.execute(ChoosePipelineStep.java:40)
	at org.gradle.internal.execution.steps.ChoosePipelineStep.execute(ChoosePipelineStep.java:23)
	at org.gradle.internal.execution.steps.ExecuteWorkBuildOperationFiringStep.lambda$execute$2(ExecuteWorkBuildOperationFiringStep.java:67)
	at org.gradle.internal.execution.steps.ExecuteWorkBuildOperationFiringStep.execute(ExecuteWorkBuildOperationFiringStep.java:67)
	at org.gradle.internal.execution.steps.ExecuteWorkBuildOperationFiringStep.execute(ExecuteWorkBuildOperationFiringStep.java:39)
	at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:46)
	at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:34)
	at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:48)
	at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:35)
	at org.gradle.internal.execution.impl.DefaultExecutionEngine$1.execute(DefaultExecutionEngine.java:61)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:127)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:116)
	at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
	at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51)
	at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
	at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:74)
	at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
	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:166)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
	at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:42)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:331)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:318)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.lambda$execute$0(DefaultTaskExecutionGraph.java:314)
	at org.gradle.internal.operations.CurrentBuildOperationRef.with(CurrentBuildOperationRef.java:85)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:314)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:303)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:459)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:376)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
	at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:48)


BUILD FAILED in 24s
16:43:06: Execution finished ':my-app:obfuscate --info'.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants