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

Collision logging, Transformers for JSON and Standard Files #773

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
0bc643f
Displaying `warn` level messages when adding a file attempts to overw…
chapmajs Mar 16, 2015
8dec628
Adding tests, not filtering META-INF/ by default
chapmajs Mar 19, 2015
394ebe2
Updated depedencies without braking changes for vulnerabilities
Jun 8, 2022
e43da40
Merged "Collision logging" into current HEAD
Jun 8, 2022
524c19e
Cleaned up "Collision logging" and added StandardFilesMergeTransforme…
Jun 10, 2022
77aeb95
Made StandardFilesMergeTransformer cacheable.
Jun 10, 2022
4131e18
Merge branch 'master' into chapmajs-collision_logging
Jul 20, 2022
9450b60
Merge remote-tracking branch 'origin/master'
Oct 5, 2022
39ee49f
Merge branch 'master' into chapmajs-collision_logging
Oct 5, 2022
dcc54a3
Merge branch 'johnrengelman:master' into master
Oct 12, 2022
ad60c5c
Merge branch 'master' into chapmajs-collision_logging
Oct 12, 2022
a215438
Merged latest changes for Gradle 8.0 into master
Mar 3, 2023
08cba3a
Displaying `warn` level messages when adding a file attempts to overw…
chapmajs Mar 16, 2015
1c893c8
Adding tests, not filtering META-INF/ by default
chapmajs Mar 19, 2015
972c1fe
Cleaned up "Collision logging" and added StandardFilesMergeTransforme…
Jun 10, 2022
bc01434
Made StandardFilesMergeTransformer cacheable.
Jun 10, 2022
a9590c0
Fixed merge problems
Mar 3, 2023
f041ec4
Merge remote-tracking branch 'original_repo/master'
Oct 29, 2023
782b769
Merged Gradle 8 ready version with collision logging
Oct 30, 2023
1acac73
Lower the log-level for duplicated "META-INF/MANIFEST.MF" from warn t…
Oct 31, 2023
c70c174
Merge branch 'chapmajs-collision_logging_merge' into chapmajs-collisi…
Oct 31, 2023
b7c7b33
Adding JsonTransformer and tests for it
Nov 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ src/docs/.vuepress/dist/
jd-gui.cfg
bin/
.vscode/
/package-lock.json
1 change: 1 addition & 0 deletions gradle/dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ dependencies {
shadow 'org.codehaus.groovy:groovy-backports-compat23:3.0.8'

implementation 'org.jdom:jdom2:2.0.6.1'
implementation 'com.google.code.gson:gson:2.10.1'
implementation 'org.ow2.asm:asm:9.4'
implementation 'org.ow2.asm:asm-commons:9.4'
implementation 'commons-io:commons-io:2.11.0'
Expand Down
1 change: 1 addition & 0 deletions src/docs/changes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## v8.1.1 (2023-03-20)

**NOTE: ** As of this version, the Github repository has migrated to the `main` branch as the default branch for releases.
* Added collision logging from chapmajs.

[Release Notes](https://github.com/johnrengelman/shadow/releases/tag/8.1.1)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import com.github.jengelman.gradle.plugins.shadow.impl.RelocatorRemapper
import com.github.jengelman.gradle.plugins.shadow.internal.UnusedTracker
import com.github.jengelman.gradle.plugins.shadow.internal.ZipCompressor
import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator
import com.github.jengelman.gradle.plugins.shadow.transformers.StandardFilesMergeTransformer
import com.github.jengelman.gradle.plugins.shadow.transformers.Transformer
import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext
import groovy.util.logging.Log
import groovy.util.logging.Slf4j
import org.apache.commons.io.FilenameUtils
import org.apache.commons.io.IOUtils
Expand All @@ -15,6 +17,7 @@ import org.apache.tools.zip.Zip64RequiredException
import org.apache.tools.zip.ZipEntry
import org.apache.tools.zip.ZipFile
import org.apache.tools.zip.ZipOutputStream
import org.codehaus.groovy.transform.LogASTTransformation
import org.gradle.api.Action
import org.gradle.api.GradleException
import org.gradle.api.UncheckedIOException
Expand All @@ -37,13 +40,18 @@ import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.commons.ClassRemapper
import org.slf4j.Logger
import org.slf4j.LoggerFactory

import javax.annotation.Nullable
import java.util.zip.ZipException

@Slf4j

class ShadowCopyAction implements CopyAction {
static final long CONSTANT_TIME_FOR_ZIP_ENTRIES = (new GregorianCalendar(1980, 1, 1, 0, 0, 0)).getTimeInMillis()

final static Logger log = LoggerFactory.getLogger(ShadowCopyAction.class);

private final File zipFile
private final ZipCompressor compressor
private final DocumentationRegistry documentationRegistry
Expand All @@ -57,9 +65,9 @@ class ShadowCopyAction implements CopyAction {
private final UnusedTracker unusedTracker

ShadowCopyAction(File zipFile, ZipCompressor compressor, DocumentationRegistry documentationRegistry,
String encoding, List<Transformer> transformers, List<Relocator> relocators,
PatternSet patternSet, ShadowStats stats,
boolean preserveFileTimestamps, boolean minimizeJar, UnusedTracker unusedTracker) {
String encoding, List<Transformer> transformers, List<Relocator> relocators,
PatternSet patternSet, ShadowStats stats,
boolean preserveFileTimestamps, boolean minimizeJar, UnusedTracker unusedTracker) {

this.zipFile = zipFile
this.compressor = compressor
Expand Down Expand Up @@ -148,7 +156,7 @@ class ShadowCopyAction implements CopyAction {
private static <T extends Closeable> void withResource(T resource, Action<? super T> action) {
try {
action.execute(resource)
} catch(Throwable t) {
} catch (Throwable t) {
try {
resource.close()
} catch (IOException ignored) {
Expand Down Expand Up @@ -197,25 +205,50 @@ class ShadowCopyAction implements CopyAction {
private final Set<String> unused
private final ShadowStats stats

private Set<String> visitedFiles = new HashSet<String>()
private Map<String, Map> visitedFiles = new HashMap<>()

StreamAction(ZipOutputStream zipOutStr, String encoding, List<Transformer> transformers,
List<Relocator> relocators, PatternSet patternSet, Set<String> unused,
ShadowStats stats) {
List<Relocator> relocators, PatternSet patternSet, Set<String> unused,
ShadowStats stats) {
this.zipOutStr = zipOutStr
this.transformers = transformers
this.relocators = relocators
this.remapper = new RelocatorRemapper(relocators, stats)
this.patternSet = patternSet
this.unused = unused
this.stats = stats
if(encoding != null) {
if (encoding != null) {
this.zipOutStr.setEncoding(encoding)
}
}

private boolean recordVisit(RelativePath path) {
return visitedFiles.add(path.pathString)
/**
* Record visit and return true if visited for the first time.
*
* @param path Visited path.
* @param size Size.
* @param originJar JAR it originated from.
* @return True if wasn't visited already.
*/
private boolean recordVisit(String path, long size, @Nullable RelativePath originJar) {
if (visitedFiles.containsKey(path)) {
return false
}

if (originJar == null) {
originJar = new RelativePath(false)
}

visitedFiles.put(path.toString(), [size: size, originJar: originJar])
return true
}

private boolean recordVisit(path) {
return recordVisit(path.toString(), 0, null)
}

private boolean recordVisit(FileCopyDetails fileCopyDetails) {
return recordVisit(fileCopyDetails.relativePath.toString(), fileCopyDetails.size, null)
}

@Override
Expand All @@ -238,7 +271,7 @@ class ShadowCopyAction implements CopyAction {
} else if (isClass && !isUnused(fileDetails.path)) {
remapClass(fileDetails)
}
recordVisit(fileDetails.relativePath)
recordVisit(fileDetails)
} catch (Exception e) {
throw new GradleException(String.format("Could not add %s to ZIP '%s'.", fileDetails, zipFile), e)
}
Expand All @@ -260,7 +293,7 @@ class ShadowCopyAction implements CopyAction {
}
filteredArchiveElements.each { ArchiveFileTreeElement archiveElement ->
if (archiveElement.relativePath.file) {
visitArchiveFile(archiveElement, archive)
visitArchiveFile(archiveElement, archive, fileDetails)
}
}
} finally {
Expand All @@ -270,21 +303,50 @@ class ShadowCopyAction implements CopyAction {
}

private void visitArchiveDirectory(RelativeArchivePath archiveDir) {
if (recordVisit(archiveDir)) {
if (recordVisit(archiveDir.toString())) {
zipOutStr.putNextEntry(archiveDir.entry)
zipOutStr.closeEntry()
}
}

private void visitArchiveFile(ArchiveFileTreeElement archiveFile, ZipFile archive) {
def archiveFilePath = archiveFile.relativePath
private void visitArchiveFile(ArchiveFileTreeElement archiveFile, ZipFile archive, FileCopyDetails fileDetails) {
RelativeArchivePath archiveFilePath = archiveFile.relativePath
long archiveFileSize = archiveFile.size

if (archiveFile.classFile || !isTransformable(archiveFile)) {
if (recordVisit(archiveFilePath) && !isUnused(archiveFilePath.entry.name)) {
String path = archiveFilePath.toString()
if (recordVisit(path, archiveFileSize, archiveFilePath) && !isUnused(archiveFilePath.entry.name)) {
if (!remapper.hasRelocators() || !archiveFile.classFile) {
copyArchiveEntry(archiveFilePath, archive)
} else {
remapClass(archiveFilePath, archive)
}
} else {
def archiveFileInVisitedFiles = visitedFiles.get(path)
if (archiveFileInVisitedFiles && (archiveFileInVisitedFiles.size != fileDetails.size)) {
// Give of only a debug-level warning for this file:
final String lowLevelWarningFile = "META-INF/MANIFEST.MF"

final logDebug = (String msg) -> { log.debug(msg) }
final logWarn = (String msg) -> { log.warn(msg) }

final Closure logger
if (archiveFilePath.toString() == lowLevelWarningFile) {
logger = logDebug
} else {
logger = logWarn
}
logger("IGNORING ${archiveFilePath} from ${fileDetails.relativePath}," +
" size is different (${fileDetails.size} vs ${archiveFileInVisitedFiles.size})")
if (archiveFileInVisitedFiles.originJar) {
logger("\t--> origin JAR was ${archiveFileInVisitedFiles.originJar}")
} else {
logger("\t--> file originated from project sourcecode")
}
if (new StandardFilesMergeTransformer().canTransformResource(archiveFile)) {
logger("\t--> Recommended transformer is " + StandardFilesMergeTransformer.class.name)
}
}
}
} else {
transform(archiveFile, archive)
Expand Down Expand Up @@ -377,6 +439,12 @@ class ShadowCopyAction implements CopyAction {
}
}

/**
* Copy archive entry.
*
* @param archiveFile Source archive entry.
* @param archive Source archive.
*/
private void copyArchiveEntry(RelativeArchivePath archiveFile, ZipFile archive) {
String mappedPath = remapper.map(archiveFile.entry.name)
ZipEntry entry = new ZipEntry(mappedPath)
Expand Down Expand Up @@ -410,19 +478,20 @@ class ShadowCopyAction implements CopyAction {
}

private void transform(ArchiveFileTreeElement element, ZipFile archive) {
transformAndClose(element, archive.getInputStream(element.relativePath.entry))
transformAndClose(element, archive, archive.getInputStream(element.relativePath.entry))
}

private void transform(FileCopyDetails details) {
transformAndClose(details, details.file.newInputStream())
transformAndClose(details, null, details.file.newInputStream())
}

private void transformAndClose(FileTreeElement element, InputStream is) {
private void transformAndClose(FileTreeElement element, @Nullable ZipFile archive, InputStream is) {
try {
String mappedPath = remapper.map(element.relativePath.pathString)
transformers.find { it.canTransformResource(element) }.transform(
TransformerContext.builder()
.path(mappedPath)
.origin(archive)
.is(is)
.relocators(relocators)
.stats(stats)
Expand Down
Loading