1 package org.codehaus.mojo.wagon.shared;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.FileReader;
25 import java.io.FileWriter;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.Reader;
29 import java.io.Writer;
30 import java.security.MessageDigest;
31 import java.security.NoSuchAlgorithmException;
32
33 import org.apache.maven.artifact.repository.metadata.Metadata;
34 import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
35 import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Writer;
36 import org.apache.maven.plugin.logging.Log;
37 import org.apache.maven.shared.model.fileset.FileSet;
38 import org.apache.maven.wagon.ResourceDoesNotExistException;
39 import org.apache.maven.wagon.Wagon;
40 import org.apache.maven.wagon.WagonException;
41 import org.codehaus.plexus.component.annotations.Component;
42 import org.codehaus.plexus.component.annotations.Requirement;
43 import org.codehaus.plexus.util.DirectoryScanner;
44 import org.codehaus.plexus.util.FileUtils;
45 import org.codehaus.plexus.util.IOUtil;
46 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
47
48
49
50
51 @Component(role = MavenRepoMerger.class, hint = "default")
52 public class DefaultMavenRepoMerger
53 implements MavenRepoMerger
54 {
55 @Requirement
56 private WagonDownload downloader;
57
58 @Requirement
59 private WagonUpload uploader;
60
61 @Override
62 public void merge( Wagon src, Wagon target, boolean optimize, Log logger )
63 throws WagonException, IOException
64 {
65
66
67 File downloadSrcDir = createTempDirectory( "wagon-maven-plugin" );
68
69 WagonFileSet srcFileSet = new WagonFileSet();
70 srcFileSet.setDownloadDirectory( downloadSrcDir );
71
72 String[] excludes = { ".*/**", "archetype-catalog.xml*" };
73 srcFileSet.setExcludes( excludes );
74
75 try
76 {
77 downloader.download( src, srcFileSet, logger );
78
79
80 DirectoryScanner scanner = new DirectoryScanner();
81 scanner.setBasedir( downloadSrcDir );
82 String[] includes = { "**/" + MAVEN_METADATA };
83 scanner.setIncludes( includes );
84 scanner.scan();
85 String[] files = scanner.getIncludedFiles();
86
87 for ( String file : files )
88 {
89 File srcMetadaFile = new File( downloadSrcDir, file + IN_PROCESS_MARKER );
90
91 try
92 {
93 target.get( file.replace( '\\', '/' ), srcMetadaFile );
94 } catch ( ResourceDoesNotExistException e )
95 {
96
97
98 continue;
99 }
100
101 try
102 {
103 mergeMetadata( srcMetadaFile, logger );
104 } catch ( XmlPullParserException e )
105 {
106 throw new IOException( "Metadata file is corrupt " + file + " Reason: " + e.getMessage() );
107 }
108
109 }
110
111
112 FileSet tobeUploadedFileSet = new FileSet();
113 tobeUploadedFileSet.setDirectory( downloadSrcDir.getAbsolutePath() );
114
115 this.uploader.upload( target, tobeUploadedFileSet, optimize, logger );
116
117 }
118 finally
119 {
120 FileUtils.deleteDirectory( downloadSrcDir );
121 }
122
123 }
124
125 private void mergeMetadata( File existingMetadata, Log logger )
126 throws IOException, XmlPullParserException
127 {
128
129 Writer stagedMetadataWriter = null;
130 Reader existingMetadataReader = null;
131 Reader stagedMetadataReader = null;
132 File stagedMetadataFile;
133
134 try
135 {
136 MetadataXpp3Reader xppReader = new MetadataXpp3Reader();
137 MetadataXpp3Writer xppWriter = new MetadataXpp3Writer();
138
139
140 existingMetadataReader = new FileReader( existingMetadata );
141 Metadata existing = xppReader.read( existingMetadataReader );
142
143
144 stagedMetadataFile = new File( existingMetadata.getParentFile(), MAVEN_METADATA );
145 stagedMetadataReader = new FileReader( stagedMetadataFile );
146 Metadata staged = xppReader.read( stagedMetadataReader );
147
148
149 existing.merge( staged );
150
151 stagedMetadataWriter = new FileWriter( stagedMetadataFile );
152 xppWriter.write( stagedMetadataWriter, existing );
153
154 logger.info( "Merging metadata file: " + stagedMetadataFile );
155
156 }
157 finally
158 {
159 IOUtil.close( stagedMetadataWriter );
160 IOUtil.close( stagedMetadataReader );
161 IOUtil.close( existingMetadataReader );
162
163 existingMetadata.delete();
164 }
165
166
167
168
169 try
170 {
171 File newMd5 = new File( stagedMetadataFile.getParentFile(), MAVEN_METADATA + ".md5" );
172 FileUtils.fileWrite( newMd5.getAbsolutePath(), checksum( stagedMetadataFile, MD5 ) );
173
174 File newSha1 = new File( stagedMetadataFile.getParentFile(), MAVEN_METADATA + ".sha1" );
175 FileUtils.fileWrite( newSha1.getAbsolutePath(), checksum( stagedMetadataFile, SHA1 ) );
176 }
177 catch ( NoSuchAlgorithmException e )
178 {
179 throw new RuntimeException( e );
180 }
181
182
183
184 }
185
186 private String checksum( File file, String type )
187 throws IOException, NoSuchAlgorithmException
188 {
189 MessageDigest md5 = MessageDigest.getInstance( type );
190
191 InputStream is = new FileInputStream( file );
192
193 byte[] buf = new byte[8192];
194
195 int i;
196
197 while ( ( i = is.read( buf ) ) > 0 )
198 {
199 md5.update( buf, 0, i );
200 }
201
202 IOUtil.close( is );
203
204 return encode( md5.digest() );
205 }
206
207 private String encode( byte[] binaryData )
208 {
209 if ( binaryData.length != 16 && binaryData.length != 20 )
210 {
211 int bitLength = binaryData.length * 8;
212 throw new IllegalArgumentException( "Unrecognised length for binary data: " + bitLength + " bits" );
213 }
214
215 String retValue = "";
216
217 for ( byte aBinaryData : binaryData )
218 {
219 String t = Integer.toHexString( aBinaryData & 0xff );
220
221 if ( t.length() == 1 )
222 {
223 retValue += ( "0" + t );
224 }
225 else
226 {
227 retValue += t;
228 }
229 }
230
231 return retValue.trim();
232 }
233
234 public static File createTempDirectory( String prefix )
235 throws IOException
236 {
237 final File temp;
238
239 temp = File.createTempFile( prefix, Long.toString( System.nanoTime() ) );
240
241 if ( !( temp.delete() ) )
242 {
243 throw new IOException( "Could not delete temp file: " + temp.getAbsolutePath() );
244 }
245
246 if ( !( temp.mkdir() ) )
247 {
248 throw new IOException( "Could not create temp directory: " + temp.getAbsolutePath() );
249 }
250
251 return ( temp );
252 }
253
254 }