blob: d8be8d4552a2f4406624a5d353f8d5ac3d2efca9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.buildcache;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Enumeration;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.maven.buildcache.xml.CacheConfig;
import org.apache.maven.project.MavenProject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Singleton
@Named
public class DefaultRestoredArtifactHandler implements RestoredArtifactHandler
{
private static final Logger LOGGER = LoggerFactory.getLogger( DefaultRestoredArtifactHandler.class );
private static final String DIR_NAME = "cache-build-tmp";
private final boolean adjustMetaInfVersion;
@Inject
public DefaultRestoredArtifactHandler( CacheConfig cacheConfig )
{
this.adjustMetaInfVersion = cacheConfig.adjustMetaInfVersion();
}
@Override
public Path adjustArchiveArtifactVersion( MavenProject project, String originalArtifactVersion, Path artifactFile )
throws IOException
{
if ( !adjustMetaInfVersion )
{
// option is disabled in cache configuration, return file as is
return artifactFile;
}
File file = artifactFile.toFile();
if ( project.getVersion().equals( originalArtifactVersion ) || !CacheUtils.isArchive( file ) )
{
// versions of artifact and building project are the same or this is not an archive, return file as is
return artifactFile;
}
File tempDirName = Paths.get( project.getBuild().getDirectory() )
.normalize()
.resolve( DIR_NAME )
.toFile();
if ( tempDirName.mkdirs() )
{
LOGGER.debug( "Temporary directory to restore artifact was created [artifactFile={}, "
+ "originalVersion={}, tempDir={}]",
artifactFile, originalArtifactVersion, tempDirName );
}
String currentVersion = project.getVersion();
File tmpJarFile = File.createTempFile( artifactFile.toFile().getName(),
'.' + FilenameUtils.getExtension( file.getName() ), tempDirName );
tmpJarFile.deleteOnExit();
String originalImplVersion = Attributes.Name.IMPLEMENTATION_VERSION + ": " + originalArtifactVersion;
String implVersion = Attributes.Name.IMPLEMENTATION_VERSION + ": " + currentVersion;
String commonXmlOriginalVersion = "<version>" + originalArtifactVersion + "</version>";
String commonXmlVersion = "<version>" + currentVersion + "</version>";
String originalPomPropsVersion = "version=" + originalArtifactVersion;
String pomPropsVersion = "version=" + currentVersion;
try ( JarFile jarFile = new JarFile( artifactFile.toFile() ) )
{
try ( JarOutputStream jos = new JarOutputStream(
new BufferedOutputStream( new FileOutputStream( tmpJarFile ) ) ) )
{
// Copy original jar file to the temporary one.
Enumeration<JarEntry> jarEntries = jarFile.entries();
byte[] buffer = new byte[1024];
while ( jarEntries.hasMoreElements() )
{
JarEntry entry = jarEntries.nextElement();
String entryName = entry.getName();
if ( entryName.startsWith( "META-INF/maven" )
&& ( entryName.endsWith( "plugin.xml" )
|| entryName.endsWith( "plugin-help.xml" ) ) )
{
replaceEntry( jarFile, entry, commonXmlOriginalVersion, commonXmlVersion, jos );
continue;
}
if ( entryName.endsWith( "pom.xml" ) )
{
replaceEntry( jarFile, entry, commonXmlOriginalVersion, commonXmlVersion, jos );
continue;
}
if ( entryName.endsWith( "pom.properties" ) )
{
replaceEntry( jarFile, entry, originalPomPropsVersion, pomPropsVersion, jos );
continue;
}
if ( JarFile.MANIFEST_NAME.equals( entryName ) )
{
replaceEntry( jarFile, entry, originalImplVersion, implVersion, jos );
continue;
}
jos.putNextEntry( entry );
try ( InputStream entryInputStream = jarFile.getInputStream( entry ) )
{
int bytesRead;
while ( ( bytesRead = entryInputStream.read( buffer ) ) != -1 )
{
jos.write( buffer, 0, bytesRead );
}
}
}
}
}
return tmpJarFile.toPath();
}
private static void replaceEntry( JarFile jarFile, JarEntry entry,
String toReplace, String replacement, JarOutputStream jos ) throws IOException
{
String fullManifest = IOUtils.toString( jarFile.getInputStream( entry ), StandardCharsets.UTF_8.name() );
String modified = fullManifest.replaceAll( toReplace, replacement );
byte[] bytes = modified.getBytes( StandardCharsets.UTF_8 );
JarEntry newEntry = new JarEntry( entry.getName() );
jos.putNextEntry( newEntry );
jos.write( bytes );
}
}