git-svn-id: https://svn.apache.org/repos/asf/maven/repository-manager/trunk@373039 13f79535-47bb-0310-9956-ffa450edef68tags/archiva-0.9-alpha-1
@@ -28,6 +28,7 @@ import org.apache.maven.artifact.repository.metadata.Versioning; | |||
import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader; | |||
import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Writer; | |||
import org.apache.maven.model.converter.ArtifactPomRewriter; | |||
import org.apache.maven.repository.converter.transaction.FileTransaction; | |||
import org.apache.maven.repository.digest.Digester; | |||
import org.apache.maven.repository.reporting.ArtifactReporter; | |||
import org.codehaus.plexus.i18n.I18N; | |||
@@ -37,10 +38,9 @@ import org.codehaus.plexus.util.xml.pull.XmlPullParserException; | |||
import java.io.File; | |||
import java.io.FileReader; | |||
import java.io.FileWriter; | |||
import java.io.IOException; | |||
import java.io.StringReader; | |||
import java.io.Writer; | |||
import java.io.StringWriter; | |||
import java.security.NoSuchAlgorithmException; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
@@ -96,34 +96,43 @@ public class DefaultRepositoryConverter | |||
if ( validateMetadata( artifact, reporter ) ) | |||
{ | |||
if ( copyArtifact( artifact, targetRepository, reporter ) ) | |||
{ | |||
copyPom( artifact, targetRepository, reporter ); | |||
FileTransaction transaction = new FileTransaction(); | |||
Metadata metadata = createBaseMetadata( artifact ); | |||
Versioning versioning = new Versioning(); | |||
versioning.addVersion( artifact.getBaseVersion() ); | |||
metadata.setVersioning( versioning ); | |||
updateMetadata( new ArtifactRepositoryMetadata( artifact ), targetRepository, metadata ); | |||
if ( copyArtifact( artifact, targetRepository, reporter, transaction ) ) | |||
{ | |||
if ( copyPom( artifact, targetRepository, reporter, transaction ) ) | |||
{ | |||
Metadata metadata = createBaseMetadata( artifact ); | |||
Versioning versioning = new Versioning(); | |||
versioning.addVersion( artifact.getBaseVersion() ); | |||
metadata.setVersioning( versioning ); | |||
updateMetadata( new ArtifactRepositoryMetadata( artifact ), targetRepository, metadata, | |||
transaction ); | |||
metadata = createBaseMetadata( artifact ); | |||
metadata.setVersion( artifact.getBaseVersion() ); | |||
versioning = new Versioning(); | |||
metadata = createBaseMetadata( artifact ); | |||
metadata.setVersion( artifact.getBaseVersion() ); | |||
versioning = new Versioning(); | |||
Matcher matcher = Artifact.VERSION_FILE_PATTERN.matcher( artifact.getVersion() ); | |||
if ( matcher.matches() ) | |||
{ | |||
Snapshot snapshot = new Snapshot(); | |||
snapshot.setBuildNumber( Integer.valueOf( matcher.group( 3 ) ).intValue() ); | |||
snapshot.setTimestamp( matcher.group( 2 ) ); | |||
versioning.setSnapshot( snapshot ); | |||
} | |||
Matcher matcher = Artifact.VERSION_FILE_PATTERN.matcher( artifact.getVersion() ); | |||
if ( matcher.matches() ) | |||
{ | |||
Snapshot snapshot = new Snapshot(); | |||
snapshot.setBuildNumber( Integer.valueOf( matcher.group( 3 ) ).intValue() ); | |||
snapshot.setTimestamp( matcher.group( 2 ) ); | |||
versioning.setSnapshot( snapshot ); | |||
} | |||
// TODO: merge latest/release/snapshot from source instead | |||
metadata.setVersioning( versioning ); | |||
updateMetadata( new SnapshotArtifactRepositoryMetadata( artifact ), targetRepository, metadata ); | |||
// TODO: merge latest/release/snapshot from source instead | |||
metadata.setVersioning( versioning ); | |||
updateMetadata( new SnapshotArtifactRepositoryMetadata( artifact ), targetRepository, metadata, | |||
transaction ); | |||
reporter.addSuccess( artifact ); | |||
if ( !dryrun ) | |||
{ | |||
transaction.commit(); | |||
} | |||
reporter.addSuccess( artifact ); | |||
} | |||
} | |||
} | |||
} | |||
@@ -137,7 +146,7 @@ public class DefaultRepositoryConverter | |||
} | |||
private void updateMetadata( RepositoryMetadata artifactMetadata, ArtifactRepository targetRepository, | |||
Metadata newMetadata ) | |||
Metadata newMetadata, FileTransaction transaction ) | |||
throws RepositoryConversionException | |||
{ | |||
File file = new File( targetRepository.getBasedir(), | |||
@@ -157,17 +166,18 @@ public class DefaultRepositoryConverter | |||
metadata = newMetadata; | |||
} | |||
if ( changed && !dryrun ) | |||
if ( changed ) | |||
{ | |||
Writer writer = null; | |||
StringWriter writer = null; | |||
try | |||
{ | |||
file.getParentFile().mkdirs(); | |||
writer = new FileWriter( file ); | |||
writer = new StringWriter(); | |||
MetadataXpp3Writer mappingWriter = new MetadataXpp3Writer(); | |||
mappingWriter.write( writer, metadata ); | |||
transaction.createFile( writer.toString(), file ); | |||
} | |||
catch ( IOException e ) | |||
{ | |||
@@ -327,7 +337,8 @@ public class DefaultRepositoryConverter | |||
return result; | |||
} | |||
private void copyPom( Artifact artifact, ArtifactRepository targetRepository, ArtifactReporter reporter ) | |||
private boolean copyPom( Artifact artifact, ArtifactRepository targetRepository, ArtifactReporter reporter, | |||
FileTransaction transaction ) | |||
throws RepositoryConversionException | |||
{ | |||
Artifact pom = artifactFactory.createProjectArtifact( artifact.getGroupId(), artifact.getArtifactId(), | |||
@@ -336,6 +347,7 @@ public class DefaultRepositoryConverter | |||
ArtifactRepository repository = artifact.getRepository(); | |||
File file = new File( repository.getBasedir(), repository.pathOf( pom ) ); | |||
boolean result = true; | |||
if ( file.exists() ) | |||
{ | |||
// TODO: utility methods in the model converter | |||
@@ -369,11 +381,7 @@ public class DefaultRepositoryConverter | |||
} | |||
if ( force || !matching ) | |||
{ | |||
if ( !dryrun ) | |||
{ | |||
targetFile.getParentFile().mkdirs(); | |||
FileUtils.fileWrite( targetFile.getAbsolutePath(), contents ); | |||
} | |||
transaction.createFile( contents, targetFile ); | |||
} | |||
} | |||
catch ( IOException e ) | |||
@@ -385,15 +393,17 @@ public class DefaultRepositoryConverter | |||
{ | |||
// v3 POM | |||
StringReader stringReader = new StringReader( contents ); | |||
Writer fileWriter = null; | |||
StringWriter writer = null; | |||
try | |||
{ | |||
fileWriter = new FileWriter( targetFile ); | |||
writer = new StringWriter(); | |||
// TODO: this api could be improved - is it worth having or go back to modelConverter? | |||
rewriter.rewrite( stringReader, fileWriter, false, artifact.getGroupId(), artifact.getArtifactId(), | |||
rewriter.rewrite( stringReader, writer, false, artifact.getGroupId(), artifact.getArtifactId(), | |||
artifact.getVersion(), artifact.getType() ); | |||
transaction.createFile( writer.toString(), targetFile ); | |||
List warnings = rewriter.getWarnings(); | |||
for ( Iterator i = warnings.iterator(); i.hasNext(); ) | |||
@@ -401,24 +411,32 @@ public class DefaultRepositoryConverter | |||
String message = (String) i.next(); | |||
reporter.addWarning( artifact, message ); | |||
} | |||
IOUtil.close( fileWriter ); | |||
} | |||
catch ( XmlPullParserException e ) | |||
{ | |||
reporter.addFailure( artifact, getI18NString( "failure.invalid.source.pom", e.getMessage() ) ); | |||
result = false; | |||
} | |||
catch ( Exception e ) | |||
{ | |||
if ( fileWriter != null ) | |||
{ | |||
IOUtil.close( fileWriter ); | |||
targetFile.delete(); | |||
} | |||
throw new RepositoryConversionException( "Unable to write converted POM", e ); | |||
} | |||
finally | |||
{ | |||
IOUtil.close( writer ); | |||
} | |||
} | |||
} | |||
else | |||
{ | |||
reporter.addWarning( artifact, getI18NString( "warning.missing.pom" ) ); | |||
} | |||
return result; | |||
} | |||
private String getI18NString( String key, String arg0 ) | |||
{ | |||
return i18n.format( getClass().getName(), Locale.getDefault(), key, arg0 ); | |||
} | |||
private String getI18NString( String key ) | |||
@@ -462,7 +480,8 @@ public class DefaultRepositoryConverter | |||
return result; | |||
} | |||
private boolean copyArtifact( Artifact artifact, ArtifactRepository targetRepository, ArtifactReporter reporter ) | |||
private boolean copyArtifact( Artifact artifact, ArtifactRepository targetRepository, ArtifactReporter reporter, | |||
FileTransaction transaction ) | |||
throws RepositoryConversionException | |||
{ | |||
File sourceFile = artifact.getFile(); | |||
@@ -488,10 +507,7 @@ public class DefaultRepositoryConverter | |||
{ | |||
if ( testChecksums( artifact, sourceFile, reporter ) ) | |||
{ | |||
if ( !dryrun ) | |||
{ | |||
FileUtils.copyFile( sourceFile, targetFile ); | |||
} | |||
transaction.copyFile( sourceFile, targetFile ); | |||
} | |||
else | |||
{ |
@@ -0,0 +1,55 @@ | |||
package org.apache.maven.repository.converter.transaction; | |||
/* | |||
* Copyright 2005-2006 The Apache Software Foundation. | |||
* | |||
* Licensed 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. | |||
*/ | |||
import org.codehaus.plexus.util.FileUtils; | |||
import java.io.File; | |||
import java.io.IOException; | |||
/** | |||
* Event to copy a file. | |||
* | |||
* @author <a href="mailto:brett@apache.org">Brett Porter</a> | |||
*/ | |||
public class CopyFileEvent | |||
implements TransactionEvent | |||
{ | |||
private final File source; | |||
private final File destination; | |||
public CopyFileEvent( File source, File destination ) | |||
{ | |||
this.source = source; | |||
this.destination = destination; | |||
} | |||
public void commit() | |||
throws IOException | |||
{ | |||
destination.getParentFile().mkdirs(); | |||
FileUtils.copyFile( source, destination ); | |||
} | |||
public void rollback() | |||
throws IOException | |||
{ | |||
// TODO: revert to backup/delete if was created | |||
} | |||
} |
@@ -0,0 +1,55 @@ | |||
package org.apache.maven.repository.converter.transaction; | |||
/* | |||
* Copyright 2005-2006 The Apache Software Foundation. | |||
* | |||
* Licensed 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. | |||
*/ | |||
import org.codehaus.plexus.util.FileUtils; | |||
import java.io.File; | |||
import java.io.IOException; | |||
/** | |||
* Event for creating a file from a string content. | |||
* | |||
* @author <a href="mailto:brett@apache.org">Brett Porter</a> | |||
*/ | |||
public class CreateFileEvent | |||
implements TransactionEvent | |||
{ | |||
private final File destination; | |||
private final String content; | |||
public CreateFileEvent( String content, File destination ) | |||
{ | |||
this.content = content; | |||
this.destination = destination; | |||
} | |||
public void commit() | |||
throws IOException | |||
{ | |||
destination.getParentFile().mkdirs(); | |||
FileUtils.fileWrite( destination.getAbsolutePath(), content ); | |||
} | |||
public void rollback() | |||
throws IOException | |||
{ | |||
// TODO: revert to backup/delete if was created | |||
} | |||
} |
@@ -0,0 +1,89 @@ | |||
package org.apache.maven.repository.converter.transaction; | |||
/* | |||
* Copyright 2005-2006 The Apache Software Foundation. | |||
* | |||
* Licensed 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. | |||
*/ | |||
import org.apache.maven.repository.converter.RepositoryConversionException; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.util.ArrayList; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
/** | |||
* Implement commit/rollback semantics for a set of files. | |||
* | |||
* @author <a href="mailto:brett@apache.org">Brett Porter</a> | |||
*/ | |||
public class FileTransaction | |||
{ | |||
private List events = new ArrayList(); | |||
public void commit() | |||
throws RepositoryConversionException | |||
{ | |||
List toRollback = new ArrayList( events.size() ); | |||
for ( Iterator i = events.iterator(); i.hasNext(); ) | |||
{ | |||
TransactionEvent event = (TransactionEvent) i.next(); | |||
try | |||
{ | |||
event.commit(); | |||
toRollback.add( event ); | |||
} | |||
catch ( IOException e ) | |||
{ | |||
try | |||
{ | |||
rollback( toRollback ); | |||
throw new RepositoryConversionException( "Unable to commit file transaction", e ); | |||
} | |||
catch ( IOException ioe ) | |||
{ | |||
throw new RepositoryConversionException( | |||
"Unable to commit file transaction, and rollback failed with error: '" + ioe.getMessage() + "'", | |||
e ); | |||
} | |||
} | |||
} | |||
} | |||
private void rollback( List toRollback ) | |||
throws IOException | |||
{ | |||
for ( Iterator i = toRollback.iterator(); i.hasNext(); ) | |||
{ | |||
TransactionEvent event = (TransactionEvent) i.next(); | |||
event.rollback(); | |||
} | |||
} | |||
public void copyFile( File source, File destination ) | |||
{ | |||
events.add( new CopyFileEvent( source, destination ) ); | |||
} | |||
public void createFile( String content, File destination ) | |||
{ | |||
events.add( new CreateFileEvent( content, destination ) ); | |||
} | |||
} |
@@ -0,0 +1,43 @@ | |||
package org.apache.maven.repository.converter.transaction; | |||
import java.io.IOException; | |||
/* | |||
* Copyright 2005-2006 The Apache Software Foundation. | |||
* | |||
* Licensed 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. | |||
*/ | |||
/** | |||
* Interface for individual events in a transaction. | |||
* | |||
* @author <a href="mailto:brett@apache.org">Brett Porter</a> | |||
*/ | |||
public interface TransactionEvent | |||
{ | |||
/** | |||
* Commit this event. | |||
* | |||
* @throws IOException if an error occurred committing the change | |||
*/ | |||
void commit() | |||
throws IOException; | |||
/** | |||
* Rollback the even already committed. | |||
* | |||
* @throws IOException if an error occurred reverting the change | |||
*/ | |||
void rollback() | |||
throws IOException; | |||
} |
@@ -16,8 +16,11 @@ | |||
failure.incorrect.md5=The MD5 checksum value was incorrect. | |||
failure.incorrect.sha1=The SHA1 checksum value was incorrect. | |||
warning.missing.pom=The artifact had no POM in the source repository. | |||
failure.target.already.exists=The artifact could not be converted because it already exists. | |||
failure.invalid.source.pom=The source POM was invalid: {0}. | |||
warning.missing.pom=The artifact had no POM in the source repository. | |||
exception.repositories.match=Source and target repositories are identical. | |||
failure.incorrect.groupMetadata.groupId=The group ID in the source group metadata is incorrect. |
@@ -643,31 +643,30 @@ public class RepositoryConverterTest | |||
} | |||
public void testRollbackArtifactCreated() | |||
throws RepositoryConversionException, IOException | |||
{ | |||
// test rollback can remove a created artifact, including checksums | |||
// TODO | |||
} | |||
public void testRollbackArtifactChanged() | |||
{ | |||
// test rollback can undo changes to an artifact, including checksums | |||
// TODO | |||
} | |||
Artifact artifact = createArtifact( "test", "rollback-created-artifact", "1.0.0" ); | |||
ArtifactMetadata artifactMetadata = new ArtifactRepositoryMetadata( artifact ); | |||
File artifactMetadataFile = new File( targetRepository.getBasedir(), | |||
targetRepository.pathOfRemoteRepositoryMetadata( artifactMetadata ) ); | |||
FileUtils.deleteDirectory( artifactMetadataFile.getParentFile() ); | |||
public void testRollbackMetadataCreated() | |||
{ | |||
// test rollback can remove a created artifact's metadata, including checksums | |||
ArtifactMetadata versionMetadata = new SnapshotArtifactRepositoryMetadata( artifact ); | |||
File versionMetadataFile = new File( targetRepository.getBasedir(), | |||
targetRepository.pathOfRemoteRepositoryMetadata( versionMetadata ) ); | |||
// TODO | |||
} | |||
File artifactFile = new File( targetRepository.getBasedir(), targetRepository.pathOf( artifact ) ); | |||
public void testRollbackMetadataChanged() | |||
{ | |||
// test rollback can undo changes to an artifact's metadata, including checksums | |||
repositoryConverter.convert( artifact, targetRepository, reporter ); | |||
checkFailure(); | |||
String pattern = "^" + getI18nString( "failure.invalid.source.pom" ).replace( "{0}", "(.*?)" ) + "$"; | |||
assertTrue( "Check failure message", getFailure().getReason().matches( pattern ) ); | |||
// TODO | |||
assertFalse( "check artifact rolled back", artifactFile.exists() ); | |||
assertFalse( "check metadata rolled back", artifactMetadataFile.exists() ); | |||
assertFalse( "check metadata rolled back", versionMetadataFile.exists() ); | |||
} | |||
public void testMultipleArtifacts() |
@@ -0,0 +1 @@ | |||
v3 |
@@ -0,0 +1,39 @@ | |||
<!-- | |||
~ Copyright 2005-2006 The Apache Software Foundation. | |||
~ | |||
~ Licensed 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. | |||
--> | |||
<project> | |||
<pomVersion>3</pomVersion> | |||
<artifactId>v3artifact</artifactId> | |||
<groupId>test</groupId> | |||
<currentVersion>1.0.0</currentVersion> | |||
<dependencies> | |||
<dependency> | |||
<groupId>groupId</groupId> | |||
<artifactId>artifactId</artifactId> | |||
<version>version</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>groupId</groupId> | |||
<artifactId>test-artifactId</artifactId> | |||
<version>version</version> | |||
<properties> | |||
<scope>test</scope> | |||
</properties> | |||
</dependency> | |||
</dependencies> | |||
<!-- deliberate parse error --> | |||
<repository> | |||
</project> |