2016-10-12 09:44:31 +00:00
/ *
* This file is part of fabric - loom , licensed under the MIT License ( MIT ) .
*
2021-07-10 20:50:53 +00:00
* Copyright ( c ) 2016 - 2021 FabricMC
2016-10-12 09:44:31 +00:00
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the "Software" ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED "AS IS" , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE .
* /
2019-05-10 22:53:50 +00:00
package net.fabricmc.loom.task ;
2016-10-12 09:44:31 +00:00
2019-11-02 20:23:27 +00:00
import java.io.File ;
import java.io.FileNotFoundException ;
2020-06-27 19:18:32 +00:00
import java.io.IOException ;
2021-07-13 22:10:07 +00:00
import java.io.InputStream ;
import java.io.OutputStream ;
2019-11-02 20:23:27 +00:00
import java.nio.file.Files ;
import java.nio.file.Path ;
2020-12-21 21:02:39 +00:00
import java.util.ArrayList ;
2021-03-12 22:16:24 +00:00
import java.util.Collections ;
import java.util.LinkedHashSet ;
2020-12-21 21:02:39 +00:00
import java.util.List ;
2021-03-12 22:16:24 +00:00
import java.util.Set ;
2021-07-13 22:10:07 +00:00
import java.util.jar.Manifest ;
import java.util.zip.ZipEntry ;
2019-11-02 20:23:27 +00:00
2020-08-26 19:15:21 +00:00
import com.google.common.base.Preconditions ;
2020-12-21 21:02:39 +00:00
import org.gradle.api.Action ;
2019-11-02 20:23:27 +00:00
import org.gradle.api.Project ;
2021-03-12 22:16:24 +00:00
import org.gradle.api.artifacts.Configuration ;
2020-12-21 20:42:23 +00:00
import org.gradle.api.file.FileCollection ;
2019-11-02 20:23:27 +00:00
import org.gradle.api.file.RegularFileProperty ;
import org.gradle.api.provider.Property ;
import org.gradle.api.tasks.Input ;
import org.gradle.api.tasks.InputFile ;
import org.gradle.api.tasks.TaskAction ;
import org.gradle.jvm.tasks.Jar ;
2021-03-12 22:16:24 +00:00
import org.jetbrains.annotations.ApiStatus ;
2020-06-27 19:18:32 +00:00
import org.zeroturnaround.zip.ZipUtil ;
2021-07-13 22:10:07 +00:00
import org.zeroturnaround.zip.transform.StreamZipEntryTransformer ;
import org.zeroturnaround.zip.transform.ZipEntryTransformerEntry ;
2019-11-02 20:23:27 +00:00
2016-10-12 09:44:31 +00:00
import net.fabricmc.loom.LoomGradleExtension ;
2020-12-24 20:58:30 +00:00
import net.fabricmc.loom.build.JarRemapper ;
import net.fabricmc.loom.build.MixinRefmapHelper ;
2021-03-12 22:16:24 +00:00
import net.fabricmc.loom.build.nesting.JarNester ;
import net.fabricmc.loom.build.nesting.MergedNestedJarProvider ;
import net.fabricmc.loom.build.nesting.NestedDependencyProvider ;
2021-07-13 22:10:07 +00:00
import net.fabricmc.loom.build.nesting.NestedJarPathProvider ;
2021-03-12 22:16:24 +00:00
import net.fabricmc.loom.build.nesting.NestedJarProvider ;
2021-07-13 22:10:07 +00:00
import net.fabricmc.loom.configuration.JarManifestConfiguration ;
2020-12-24 20:58:30 +00:00
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerJarProcessor ;
2021-06-14 17:39:03 +00:00
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl ;
2021-03-12 22:16:24 +00:00
import net.fabricmc.loom.util.Constants ;
2019-05-10 22:53:50 +00:00
import net.fabricmc.loom.util.TinyRemapperMappingsHelper ;
2021-03-15 23:31:18 +00:00
import net.fabricmc.loom.util.ZipReprocessorUtil ;
2020-06-27 19:18:32 +00:00
import net.fabricmc.stitch.util.Pair ;
2018-10-31 13:20:50 +00:00
import net.fabricmc.tinyremapper.TinyRemapper ;
import net.fabricmc.tinyremapper.TinyUtils ;
2016-10-12 09:44:31 +00:00
2019-06-11 02:20:57 +00:00
public class RemapJarTask extends Jar {
2021-07-13 22:10:07 +00:00
private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF" ;
2020-07-26 20:32:10 +00:00
private final RegularFileProperty input ;
private final Property < Boolean > addNestedDependencies ;
2021-03-12 22:16:24 +00:00
private final Property < Boolean > addDefaultNestedDependencies ;
2020-07-26 20:32:10 +00:00
private final Property < Boolean > remapAccessWidener ;
2020-12-21 21:02:39 +00:00
private final List < Action < TinyRemapper . Builder > > remapOptions = new ArrayList < > ( ) ;
2020-06-27 19:18:32 +00:00
public JarRemapper jarRemapper ;
2020-12-21 20:42:23 +00:00
private FileCollection classpath ;
2021-03-12 22:16:24 +00:00
private final Set < Object > nestedPaths = new LinkedHashSet < > ( ) ;
2019-06-11 02:20:57 +00:00
public RemapJarTask ( ) {
super ( ) ;
2021-04-04 22:02:00 +00:00
input = getProject ( ) . getObjects ( ) . fileProperty ( ) ;
2019-06-11 02:20:57 +00:00
addNestedDependencies = getProject ( ) . getObjects ( ) . property ( Boolean . class ) ;
2021-03-12 22:16:24 +00:00
addDefaultNestedDependencies = getProject ( ) . getObjects ( ) . property ( Boolean . class ) ;
2020-05-11 11:48:04 +00:00
remapAccessWidener = getProject ( ) . getObjects ( ) . property ( Boolean . class ) ;
2020-05-11 12:09:42 +00:00
// false by default, I have no idea why I have to do it for this property and not the other one
remapAccessWidener . set ( false ) ;
2021-03-12 22:16:24 +00:00
addDefaultNestedDependencies . set ( true ) ;
2019-06-11 02:20:57 +00:00
}
2016-10-12 09:44:31 +00:00
2019-05-10 22:53:50 +00:00
@TaskAction
public void doTask ( ) throws Throwable {
2021-03-12 22:16:24 +00:00
boolean singleRemap = false ;
2018-11-04 21:28:46 +00:00
2021-03-12 22:16:24 +00:00
if ( jarRemapper = = null ) {
singleRemap = true ;
jarRemapper = new JarRemapper ( ) ;
2018-06-18 16:01:39 +00:00
}
2018-11-06 09:36:35 +00:00
2021-07-13 23:03:21 +00:00
scheduleRemap ( singleRemap | | LoomGradleExtension . get ( getProject ( ) ) . isRootProject ( ) ) ;
2018-11-06 09:36:35 +00:00
2021-03-12 22:16:24 +00:00
if ( singleRemap ) {
jarRemapper . remap ( ) ;
2020-12-21 19:47:08 +00:00
}
2019-06-11 02:20:57 +00:00
}
2019-05-10 22:53:50 +00:00
2021-03-12 22:16:24 +00:00
public void scheduleRemap ( boolean isMainRemapTask ) throws Throwable {
2020-06-27 19:18:32 +00:00
Project project = getProject ( ) ;
2021-07-13 23:03:21 +00:00
LoomGradleExtension extension = LoomGradleExtension . get ( getProject ( ) ) ;
2020-06-27 19:18:32 +00:00
Path input = this . getInput ( ) . getAsFile ( ) . get ( ) . toPath ( ) ;
Path output = this . getArchivePath ( ) . toPath ( ) ;
if ( ! Files . exists ( input ) ) {
throw new FileNotFoundException ( input . toString ( ) ) ;
}
2021-06-14 17:39:03 +00:00
MappingsProviderImpl mappingsProvider = extension . getMappingsProvider ( ) ;
2020-06-27 19:18:32 +00:00
String fromM = "named" ;
String toM = "intermediary" ;
2021-03-12 22:16:24 +00:00
if ( isMainRemapTask ) {
2020-12-21 20:42:23 +00:00
jarRemapper . addToClasspath ( getRemapClasspath ( ) ) ;
2020-06-27 19:18:32 +00:00
jarRemapper . addMappings ( TinyRemapperMappingsHelper . create ( mappingsProvider . getMappings ( ) , fromM , toM , false ) ) ;
}
2020-09-06 19:21:08 +00:00
for ( File mixinMapFile : extension . getAllMixinMappings ( ) ) {
if ( mixinMapFile . exists ( ) ) {
jarRemapper . addMappings ( TinyUtils . createTinyMappingProvider ( mixinMapFile . toPath ( ) , fromM , toM ) ) ;
}
2020-06-27 19:18:32 +00:00
}
2020-12-21 21:02:39 +00:00
// Add remap options to the jar remapper
jarRemapper . addOptions ( this . remapOptions ) ;
2021-03-12 22:16:24 +00:00
NestedJarProvider nestedJarProvider = getNestedJarProvider ( ) ;
nestedJarProvider . prepare ( getProject ( ) ) ;
2020-06-27 19:18:32 +00:00
jarRemapper . scheduleRemap ( input , output )
. supplyAccessWidener ( ( remapData , remapper ) - > {
2021-07-13 23:03:21 +00:00
if ( getRemapAccessWidener ( ) . getOrElse ( false ) & & extension . getAccessWidener ( ) ! = null ) {
2020-06-27 19:18:32 +00:00
AccessWidenerJarProcessor accessWidenerJarProcessor = extension . getJarProcessorManager ( ) . getByType ( AccessWidenerJarProcessor . class ) ;
byte [ ] data ;
try {
data = accessWidenerJarProcessor . getRemappedAccessWidener ( remapper ) ;
} catch ( IOException e ) {
throw new RuntimeException ( "Failed to remap access widener" ) ;
}
2020-08-26 19:15:21 +00:00
String awPath = accessWidenerJarProcessor . getAccessWidenerPath ( remapData . input ) ;
Preconditions . checkNotNull ( awPath , "Failed to find accessWidener in fabric.mod.json: " + remapData . input ) ;
return Pair . of ( awPath , data ) ;
2020-06-27 19:18:32 +00:00
}
return null ;
} )
. complete ( ( data , accessWidener ) - > {
if ( ! Files . exists ( output ) ) {
throw new RuntimeException ( "Failed to remap " + input + " to " + output + " - file missing!" ) ;
}
2021-02-11 18:12:27 +00:00
if ( MixinRefmapHelper . addRefmapName ( extension . getRefmapName ( ) , output ) ) {
2020-06-27 19:18:32 +00:00
project . getLogger ( ) . debug ( "Transformed mixin reference maps in output JAR!" ) ;
}
if ( getAddNestedDependencies ( ) . getOrElse ( false ) ) {
2021-03-12 22:16:24 +00:00
JarNester . nestJars ( nestedJarProvider . provide ( ) , output . toFile ( ) , project . getLogger ( ) ) ;
2020-06-27 19:18:32 +00:00
}
if ( accessWidener ! = null ) {
2020-08-26 19:15:21 +00:00
boolean replaced = ZipUtil . replaceEntry ( data . output . toFile ( ) , accessWidener . getLeft ( ) , accessWidener . getRight ( ) ) ;
Preconditions . checkArgument ( replaced , "Failed to remap access widener" ) ;
2020-06-27 19:18:32 +00:00
}
2021-03-15 23:31:18 +00:00
2021-07-13 22:10:07 +00:00
// Add data to the manifest
boolean transformed = ZipUtil . transformEntries ( data . output . toFile ( ) , new ZipEntryTransformerEntry [ ] {
new ZipEntryTransformerEntry ( MANIFEST_PATH , new StreamZipEntryTransformer ( ) {
@Override
protected void transform ( ZipEntry zipEntry , InputStream in , OutputStream out ) throws IOException {
var manifest = new Manifest ( in ) ;
var manifestConfiguration = new JarManifestConfiguration ( project ) ;
manifestConfiguration . configure ( manifest ) ;
manifest . getMainAttributes ( ) . putValue ( "Fabric-Mapping-Namespace" , toM ) ;
manifest . write ( out ) ;
}
} )
} ) ;
Preconditions . checkArgument ( transformed , "Failed to transform jar manifest" ) ;
2021-03-15 23:31:18 +00:00
if ( isReproducibleFileOrder ( ) | | ! isPreserveFileTimestamps ( ) ) {
try {
ZipReprocessorUtil . reprocessZip ( output . toFile ( ) , isReproducibleFileOrder ( ) , isPreserveFileTimestamps ( ) ) ;
} catch ( IOException e ) {
throw new RuntimeException ( "Failed to re-process jar" , e ) ;
}
}
2020-06-27 19:18:32 +00:00
} ) ;
}
2021-03-12 22:16:24 +00:00
private NestedJarProvider getNestedJarProvider ( ) {
Configuration includeConfiguration = getProject ( ) . getConfigurations ( ) . getByName ( Constants . Configurations . INCLUDE ) ;
if ( ! addDefaultNestedDependencies . getOrElse ( true ) ) {
return new NestedJarPathProvider ( nestedPaths ) ;
}
NestedJarProvider baseProvider = NestedDependencyProvider . createNestedDependencyProviderFromConfiguration ( getProject ( ) , includeConfiguration ) ;
if ( nestedPaths . isEmpty ( ) ) {
return baseProvider ;
}
return new MergedNestedJarProvider (
baseProvider ,
new NestedJarPathProvider ( nestedPaths )
) ;
}
2020-12-21 20:42:23 +00:00
private Path [ ] getRemapClasspath ( ) {
FileCollection files = this . classpath ;
if ( files = = null ) {
files = getProject ( ) . getConfigurations ( ) . getByName ( "compileClasspath" ) ;
}
return files . getFiles ( ) . stream ( )
. map ( File : : toPath )
. filter ( Files : : exists )
. toArray ( Path [ ] : : new ) ;
}
2019-06-11 02:20:57 +00:00
@InputFile
public RegularFileProperty getInput ( ) {
return input ;
2016-10-12 09:44:31 +00:00
}
2018-08-07 17:52:17 +00:00
2019-06-11 02:20:57 +00:00
@Input
public Property < Boolean > getAddNestedDependencies ( ) {
return addNestedDependencies ;
}
2020-05-11 11:48:04 +00:00
2021-03-12 22:16:24 +00:00
@Input
public Property < Boolean > getAddDefaultNestedDependencies ( ) {
return addDefaultNestedDependencies ;
}
2020-05-11 11:48:04 +00:00
@Input
public Property < Boolean > getRemapAccessWidener ( ) {
return remapAccessWidener ;
}
2020-12-21 20:42:23 +00:00
2020-12-21 21:02:39 +00:00
public void remapOptions ( Action < TinyRemapper . Builder > action ) {
this . remapOptions . add ( action ) ;
}
2020-12-21 20:42:23 +00:00
public RemapJarTask classpath ( FileCollection collection ) {
if ( this . classpath = = null ) {
this . classpath = collection ;
} else {
this . classpath = this . classpath . plus ( collection ) ;
}
return this ;
}
2021-03-12 22:16:24 +00:00
@ApiStatus.Experimental // This only allows mod jars, proceed with care when trying to pass in configurations with projects, or something that depends on a task.
public RemapJarTask include ( Object . . . paths ) {
Collections . addAll ( nestedPaths , paths ) ;
this . addNestedDependencies . set ( true ) ;
return this ;
}
2016-10-12 09:44:31 +00:00
}