From 88336202786683dbdfbfa23b24a1878c2dde8b88 Mon Sep 17 00:00:00 2001 From: John Dennis Casey Date: Thu, 12 May 2005 18:59:54 +0000 Subject: [PATCH] o Added support to RewritePhase of repoclean to copy -SNAPSHOT.version.txt and -RELEASE.version.txt (or whatever it's called) using ArtifactMetadata, where these files exist in the source repo. o Reformatted mojo annotation doco to tabular format. o Committed a start to the plugin-overview (developer's PoV on this)...it's just an outline with an incomplete introduction for now, but it's still a start. git-svn-id: https://svn.apache.org/repos/asf/maven/components/trunk@169873 13f79535-47bb-0310-9956-ffa450edef68 --- .../developers/mojo-api-specification.xml | 424 +++++++++------ .../site/xdoc/developers/plugin-overview.xml | 130 +++++ .../tools/repoclean/phase/RewritePhase.java | 486 ++++++++++-------- 3 files changed, 680 insertions(+), 360 deletions(-) create mode 100644 maven-site/src/site/xdoc/developers/plugin-overview.xml diff --git a/maven-site/src/site/xdoc/developers/mojo-api-specification.xml b/maven-site/src/site/xdoc/developers/mojo-api-specification.xml index ea4b958809..7a9c336567 100644 --- a/maven-site/src/site/xdoc/developers/mojo-api-specification.xml +++ b/maven-site/src/site/xdoc/developers/mojo-api-specification.xml @@ -91,13 +91,15 @@
  • - void setLog( org.apache.maven.monitor.logging.Log ) + void setLog( org.apache.maven.monitor.logging.Log )

    Inject a standard Maven logging mechanism to allow this Mojo to communicate events and feedback to the user.

  • - void execute() throws org.apache.maven.plugin.MojoExecutionException + + void execute() throws org.apache.maven.plugin.MojoExecutionException +

    Perform whatever build-process behavior this Mojo implements. This is the main trigger for the Mojo inside the Maven system, and allows the Mojo to communicate fatal errors by throwing an @@ -128,7 +130,7 @@

  • - public void setLog( org.apache.maven.monitor.logging.Log ) + public void setLog( org.apache.maven.monitor.logging.Log )

    [IMPLEMENTED] @@ -146,7 +148,7 @@

  • - void execute() throws org.apache.maven.plugin.MojoExecutionException + void execute() throws org.apache.maven.plugin.MojoExecutionException

    [ABSTRACT] @@ -178,7 +180,7 @@

  • - void debug( java.lang.CharSequence, java.lang.Throwable ) + void debug( java.lang.CharSequence, java.lang.Throwable )

    Send a message (and accompanying exception) to the user in the debug error level. The error's stacktrace will be output @@ -196,7 +198,7 @@

  • - void info( java.lang.CharSequence, java.lang.Throwable ) + void info( java.lang.CharSequence, java.lang.Throwable )

    Send a message (and accompanying exception) to the user in the info error level. The error's stacktrace will be output @@ -214,7 +216,7 @@

  • - void warn( java.lang.CharSequence, java.lang.Throwable ) + void warn( java.lang.CharSequence, java.lang.Throwable )

    Send a message (and accompanying exception) to the user in the warn error level. The error's stacktrace will be output @@ -232,7 +234,7 @@

  • - void error( java.lang.CharSequence, java.lang.Throwable ) + void error( java.lang.CharSequence, java.lang.Throwable )

    Send a message (and accompanying exception) to the user in the error error level. The error's stacktrace will be output @@ -262,71 +264,127 @@ element name along with a javadoc annotation (if applicable) supporting that piece of the plugin descriptor. A couple of examples are: someElement - (@annotation parameterName="parameterValue") or + (@annotation parameterName="parameterValue") or someOtherElement (@annotation <rawAnnotationValue>).

    The plugin descriptor must be provided in a jar resource with the path: META-INF/maven/plugin.xml, and it must contain the following:

    -

    + + + + + + + + + + + + + + + + +
    Descriptor ElementRequired?Notes
    mojosYesDescriptors for each Mojo provided by the plugin, each inside a + mojo sub-element. Mojo descriptors are covered in detail + below. Obviously, a plugin without any declared mojos doesn't + make sense, so the mojos element is required, along with + at least one mojo sub-element.
    dependenciesYesA set of dependencies which the plugin requires in order to + function. Each dependency is provided inside a dependency + sub-element. Dependency specifications are covered below. Since + all plugins must have a dependency on + maven-plugin-api, this element is effectively + required. Using the plugin toolset, these dependencies can be + extracted from the POM's dependencies.

    Each Mojo specified inside a plugin descriptor must provide the - following:

    + following (annotations specified here are at the class level):

    -

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Descriptor ElementAnnotationRequired?Notes
    goal@goal <goalName>YesThe name for the Mojo that users will reference from the + command line to execute the Mojo directly, or inside a POM in + order to provide Mojo-specific configuration.
    implementationnone (detected)YesThe Mojo's fully-qualified class name (or script path in + the case of non-java mojos).
    languagenone (detected)No. Default: javaThe implementation language for this Mojo (marmalade, java, + beanshell, etc.).
    configuratornone (detected)NoThe configurator type to use when injecting parameter values + into this Mojo. NOTE: This will only be used in very special + cases, using a highly controlled vocabulary of possible values. + (Elements like this are why it's a good idea to use the + descriptor tools.)
    phase@phase <phaseName>NoBinds this Mojo to a particular phase of the standard build + lifecycle, if specified. NOTE: This is only required if this + Mojo is to participate in the standard build process.
    executePhase@executePhase <phaseName>NoWhen this Mojo's goal is invoked directly from the command + line, executePhase specifies the last phase in the + standard build lifecycle to execute before this Mojo + executes.
    requiresDependencyResolution@requiresDependencyResolution <requiredScope>NoFlags this Mojo as requiring the dependencies in the specified + scope (or an implied scope) to be resolved before it can execute. + NOTE: Currently supports compile, + runtime, and test scopes.
    descriptionnone (detected)NoThe description of this Mojo's functionality. Using the + toolset, this will be the class-level javadoc description + provided. NOTE: While this is not a required part of the mojo + specification, it SHOULD be provided to enable future + tool support for browsing, etc. and for clarity.
    parametersN/ANoSpecifications for the parameters which this Mojo uses will be + provided in parameter sub-elements in this section. + NOTE: Parameters are discussed in more detail below.

    Each Mojo specifies the parameters that it expects to be able to work with. These parameters are the Mojo's link to the outside world, and @@ -344,63 +402,104 @@

    Each parameter for a Mojo must be specified in the plugin descriptor as follows:

    -

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Descriptor ElementAnnotationRequired?Notes
    namenone (detected)YesThe name of the parameter, to be used in configuring this + parameter from the Mojo's declared defaults (discussed below) or + from the POM. Using the toolset, this is detected as the + java field name.
    alias@parameter alias="myAlias"NoSpecifies an alias which can be used to configure this + parameter from the POM. This is primarily useful to improve + user-friendliness, where Mojo field names are not intuitive to + the user or are otherwise not conducive to configuration via + the POM.
    typenone (detected)YesThe java type for this parameter. This is used to validate the + result of any expressions used to calculate the value which + should be injected into the Mojo for this parameter. Using the + toolset, this is detected as the class of the java field + corresponding to this parameter.
    required@requiredNoWhether this parameter is required for the Mojo to function. + This is used to validate the configuration for a Mojo before it + is injected, and before the Mojo is executed from some + half-state. NOTE: Specification of this annotation flags + the parameter as required; there is no true/false value.
    editable@readonlyNoSpecifies that this parameter cannot be configured directly by + the user (as in the case of POM-specified configuration). This is + useful when you want to force the user to use common POM elements + rather than plugin configurations, as in the case where you want + to use the artifact's final name as a parameter. In this case, + you want the user to modify + <build><finalName/></build> rather than + specifying a value for finalName directly in the plugin + configuration section. It is also useful to ensure that - for + example - a List-typed parameter which expects items of type + Artifact doesn't get a List full of Strings. NOTE: + Specification of this annotation flags the parameter as + non-editable; there is no true/false value.
    descriptionnone (detected)NoThe description of this parameter's use inside the Mojo. + Using the toolset, this is detected as the javadoc description + for the field. NOTE: While this is not a required part of the + parameter specification, it SHOULD be provided to enable future + tool support for browsing, etc. and for clarity.
    expression@parameter expression="${someExpression}"NoSpecifies the expression used to calculate the value to be + injected into this parameter of the Mojo at buildtime. This is + commonly used to refer to specific elements in the POM, such as + ${project.build.resources}, which refers to the List of resources + meant to accompany the classes in the resulting jar file. + NOTE: If not specified, an expression of ${<name>} is + assumed, which can only be satisfied from POM configuration or + System properties. The use of '${' and '}' is required to delimit + actual expressions which may be evaluated.
    deprecated@deprecatedNoMarks a parameter as deprecated. The rules on deprecation are + the same as normal java with language elements. This will trigger + a warning when a user tries to configure a parameter marked as + deprecated.

    The final component of a plugin descriptor is the dependencies. This enables the plugin to function independently of it's POM (or at least @@ -413,14 +512,17 @@

    By now, we've mentioned the plugin tools several times without telling - you what they are or how to use them. instead of writing (and - maintaining) this metadata file by hand, Maven 2.0 ships with some - tools to aid developers in this task. In fact, the only thing a plugin - developer needs to do is declare his project to be a plugin from within - the POM. Once this is done, Maven will call the appropriate descriptor + you what they are or how to use them. Instead of manually writing (and + maintaining) the metadata detailed above, Maven 2.0 ships with some + tools to aid in this task. In fact, the only thing a plugin developer + needs to do is declare his project to be a plugin from within the POM. + Once this is done, Maven will call the appropriate descriptor generators, etc. to produce an artifact that is ready for use within - Maven builds. The section below describes the changes to the POM - which are necessary to create plugin artifacts.

    + Maven builds. Optional metadata can be injected via javadoc annotation + (and possibly jdk5 annotations in the future) as described above, + enabling richer interactions between the Mojo and the user. The + section below describes the changes to the POM which are necessary to + create plugin artifacts.

    From the POM, Maven plugin projects look quite similar to any other @@ -428,30 +530,52 @@ for script-based plugins. The following details the POM elements which are necessary to build a Maven plugin artifact.

    -

      -
    • packaging Element. The POM must declare a packaging - element which describes this project as a Maven plugin project. The - element is specified as: - <packaging>maven-plugin</packaging>
    • -
    • scriptSourceDirectory Element. In the case of script-based - Mojos (which are not covered in detail within this document), the - POM must include an additional element to distinguish script - sources from (optional) java supporting classes. This element is - the scriptSourceDirectory, inside the build section. It is - specified as: - <scriptSourceDirectory>src/main/scripts</scriptSourceDirectory>. - This directory is included in the list of resources which accompany - any compiled code in the resulting artifact. It is specified - separately from the resources in the build section to denote its - special status as an alternate source directory for scripts.
    • -
    + + + + + + + + + + + + + + + + + + + +
    POM ElementRequired for Java Mojos?Sample DeclarationNotes
    packagingYes<packaging>maven-plugin</packaging>The POM must declare a packaging element which describes this + project as a Maven plugin project.
    scriptSourceDirectoryNo<scriptSourceDirectory>src/main/scripts</scriptSourceDirectory>In the case of script-based Mojos (which are not covered in + detail within this document), the POM must include an additional + element to distinguish script sources from (optional) java + supporting classes. This element is the scriptSourceDirectory, + inside the build section. This directory is included in the list + of resources which accompany any compiled code in the resulting + artifact. It is specified separately from the resources in the + build section to denote its special status as an alternate source + directory for scripts.

    -

    After making the changes above, the developer can simply call m2 - install to install the plugin to the local repository. (Any of - the other standard lifecycle targets like package, deploy, etc. are - also available in like fashion.)

    +

    After making the changes above, the developer can simply call +

    m2 install

    to install the plugin to + the local repository. (Any of the other standard lifecycle targets like + package, deploy, etc. are also available in like fashion.)

    +

    This section simply gives a listing of pointers for more + information.

    +

    +

      +
    • M2 Plugin Overview [link]
    • +
    • QDox Project (javadoc annotations) [link]
    • +
    +

    \ No newline at end of file diff --git a/maven-site/src/site/xdoc/developers/plugin-overview.xml b/maven-site/src/site/xdoc/developers/plugin-overview.xml new file mode 100644 index 0000000000..3e82ce3adf --- /dev/null +++ b/maven-site/src/site/xdoc/developers/plugin-overview.xml @@ -0,0 +1,130 @@ + + + + + + + Maven 2.0 Plugin Development + John Casey + + + +
    + +

    Maven 2.0 is similar to its predecessor in that it has two main + functions. First, it organizes project data into a coherent whole, + and exposes this data for use within the build process. Second, Maven + marshals a set of plugins to do the heavy lifting and execute the + actual steps of the build.

    +

    Many things in Maven 2 will have at least superficial familiarity + to users of Maven 1, and the plugin system is no exception. Maven 2 + plugins appear to behave much as their 1.x counterparts do. Like 1.x + plugins, they use both project information and custom-defined + configurations to perform their work. Also, Maven 2 plugins are + organized and executed in a coherent way by the build engine itself - + that is to say, the engine is still responsible for organizing and + fulfilling a plugin's requirements before executing the plugin + itself.

    +

    Operationally, Maven 2.0 should feel very much like a more + performant big brother of Maven 1.x. While the POM has definitely + changed, it has the same basic layout and features (with notable + additions). However, this is where the similarity ends. Maven 2.0 is + a complete redesign and reimplementation of the Maven build concept. + As such, it has a much different - and more evolved, at least to + our minds ;-) - architecture.

    +
    + +

    However similar the architectures may seem, Maven 2 offers a much + richer environment for its plugins than Maven 1 ever did. The new + architecture offers a managed lifecycle, multiple implementation + languages, reusability outside of the build system, and many more + advantages. Arguably the biggest advantage is the ability to write + Maven plugins entirely in Java, which allows developers to tap into a + rich landscape of development and testing tools to aid in their + efforts.

    +

    Prior to Maven 2.0, the build system organized relevant plugins + into a loosely defined lifecycle, which was determined based on goal + prerequisites and decoration via preGoals and postGoals. That + experience was critical for the Maven community. It taught us that + even though there may be a million different build scenarios out + there, most of the activities in those builds fit into just a few + broad categories. Moreover, the category to which a goal fits serves + as an accurate predictor for where in the build process the goal + should execute. Drawing on this experience, Maven 2.0 defines a + lifecycle within which plugins are managed according to their + relative position within this lifecycle

    +

    Starting with Maven 2.0, plugins implemented in different + programming or scripting languages can coexist within the same build + process. This removes the requirement that plugin developers learn a + particular scripting language in order to interact with Maven. It + also reduced the risk associated with the stability or richness of + any particular scripting language.

    +

    Also starting with Maven 2.0 is an effort to integrate multiproject + builds directly into the core architecture. In Maven 1.x, many large + projects were fragmented into smaller builds to sidestep issues such + as conditional compilation of a subset of classes; separation + of client-server code; or cyclical dependencies between + distinct application libraries.

    +
    + + +
    +
    + + + + + + +
    +
    + + + + + + +
    +
    + + + + + + +
    +
    + + + + + + +
    +
    + +
    + +
    \ No newline at end of file diff --git a/sandbox/repoclean/src/main/java/org/apache/maven/tools/repoclean/phase/RewritePhase.java b/sandbox/repoclean/src/main/java/org/apache/maven/tools/repoclean/phase/RewritePhase.java index 623ea1cd41..f2bf38ba35 100644 --- a/sandbox/repoclean/src/main/java/org/apache/maven/tools/repoclean/phase/RewritePhase.java +++ b/sandbox/repoclean/src/main/java/org/apache/maven/tools/repoclean/phase/RewritePhase.java @@ -2,10 +2,13 @@ package org.apache.maven.tools.repoclean.phase; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.metadata.ArtifactMetadata; +import org.apache.maven.artifact.metadata.ReleaseArtifactMetadata; +import org.apache.maven.artifact.metadata.SnapshotArtifactMetadata; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout; import org.apache.maven.tools.repoclean.RepositoryCleanerConfiguration; import org.apache.maven.tools.repoclean.artifact.metadata.ProjectMetadata; +import org.apache.maven.tools.repoclean.digest.DigestException; import org.apache.maven.tools.repoclean.digest.DigestVerifier; import org.apache.maven.tools.repoclean.report.FileReporter; import org.apache.maven.tools.repoclean.report.ReportWriteException; @@ -15,6 +18,7 @@ import org.apache.maven.tools.repoclean.transaction.RewriteTransaction; import org.apache.maven.tools.repoclean.transaction.RollbackException; import org.codehaus.plexus.PlexusConstants; import org.codehaus.plexus.PlexusContainer; +import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException; import org.codehaus.plexus.context.Context; import org.codehaus.plexus.context.ContextException; import org.codehaus.plexus.logging.AbstractLogEnabled; @@ -70,238 +74,313 @@ public class RewritePhase { Logger logger = getLogger(); - ArtifactPomRewriter artifactPomRewriter = null; - List rewritten = new ArrayList(); - try + File sourceBase = new File( new URL( sourceRepo.getUrl() ).getPath() ); + + File targetBase = new File( new URL( targetRepo.getUrl() ).getPath() ); + + for ( Iterator it = artifacts.iterator(); it.hasNext(); ) { - File sourceBase = new File( new URL( sourceRepo.getUrl() ).getPath() ); + Artifact artifact = (Artifact) it.next(); - File targetBase = new File( new URL( targetRepo.getUrl() ).getPath() ); + RewriteTransaction transaction = new RewriteTransaction( artifact ); - for ( Iterator it = artifacts.iterator(); it.hasNext(); ) + String artifactReportPath = buildArtifactReportPath( artifact ); + + FileReporter artifactReporter = null; + try { - Artifact artifact = (Artifact) it.next(); + artifactReporter = new FileReporter( reportsBase, artifactReportPath ); - RewriteTransaction transaction = new RewriteTransaction( artifact ); + boolean errorOccurred = false; - String artifactReportPath = buildArtifactReportPath( artifact ); + File artifactSource = new File( sourceRepo.getBasedir(), sourceRepo.pathOf( artifact ) ); + File artifactTarget = new File( targetRepo.getBasedir(), targetRepo.pathOf( artifact ).replace( '+', + '-' ) ); - FileReporter artifactReporter = null; - try + transaction.addFile( artifactTarget ); + + artifact.setFile( artifactSource ); + + boolean targetMissingOrOlder = !artifactTarget.exists() + || artifactTarget.lastModified() < artifactSource.lastModified(); + + if ( artifactSource.exists() && ( configuration.force() || targetMissingOrOlder ) ) { - artifactReporter = new FileReporter( reportsBase, artifactReportPath ); - - boolean errorOccurred = false; - - File artifactSource = new File( sourceRepo.getBasedir(), sourceRepo.pathOf( artifact ) ); - File artifactTarget = new File( targetRepo.getBasedir(), targetRepo.pathOf( artifact ) - .replace( '+', '-' ) ); - transaction.addFile( artifactTarget ); - artifact.setFile( artifactSource ); - - boolean targetMissingOrOlder = !artifactTarget.exists() - || artifactTarget.lastModified() < artifactSource.lastModified(); - - if ( artifactSource.exists() && ( configuration.force() || targetMissingOrOlder ) ) + try { - transaction.addFile( artifactTarget ); - - try + if ( !configuration.reportOnly() ) { - if ( !configuration.reportOnly() ) + if ( logger.isDebugEnabled() ) { - if ( logger.isDebugEnabled() ) - { - logger.debug( "sourceRepo basedir is: \'" + sourceRepo.getBasedir() + "\'" ); - logger.debug( "targetRepo basedir is: \'" + targetRepo.getBasedir() + "\'" ); - } - - File targetParent = artifactTarget.getParentFile(); - if ( !targetParent.exists() ) - { - targetParent.mkdirs(); - } - - if ( logger.isDebugEnabled() ) - { - logger.debug( "Copying artifact[" + artifact.getId() + "] from \'" + artifactSource - + "\' to \'" + artifactTarget + "\'." ); - } - - copyArtifact( artifact, artifactTarget, artifactReporter ); - } - } - catch ( Exception e ) - { - repoReporter.error( "Error transferring artifact[" + artifact.getId() - + "] to the target repository.", e ); - - throw e; - } - - if ( logger.isDebugEnabled() ) - { - logger.debug( "working on digest for artifact[" + artifact.getId() + "] with groupId: \'" - + artifact.getGroupId() + "\'" ); - } - - try - { - digestVerifier.verifyDigest( artifactSource, artifactTarget, transaction, artifactReporter, - configuration.reportOnly() ); - } - catch ( Exception e ) - { - repoReporter.error( "Error verifying digest for artifact[" + artifact.getId() + "]", e ); - - throw e; - } - - ArtifactMetadata pom = new ProjectMetadata( artifact ); - - File sourcePom = new File( sourceBase, sourceRepo.pathOfMetadata( pom ) ); - - String pomContents = null; - - String pomVersion = ArtifactPomRewriter.V3_POM; - - if ( sourcePom.exists() ) - { - pomContents = readPomContents( sourcePom ); - - if ( pomContents.indexOf( "modelVersion" ) > -1 ) - { - pomVersion = ArtifactPomRewriter.V4_POM; - } - } - - artifactPomRewriter = (ArtifactPomRewriter) container.lookup( ArtifactPomRewriter.ROLE, - pomVersion ); - - File targetPom = new File( targetBase, targetRepo.pathOfMetadata( pom ).replace( '+', '-' ) ); - - transaction.addFile( targetPom ); - - File bridgedTargetPom = new File( targetBase, bridgingLayout.pathOfMetadata( pom ) - .replace( '+', '-' ) ); - - transaction.addFile( bridgedTargetPom ); - - try - { - File targetPomParent = targetPom.getParentFile(); - if ( !targetPomParent.exists() ) - { - targetPomParent.mkdirs(); + logger.debug( "sourceRepo basedir is: \'" + sourceRepo.getBasedir() + "\'" ); + logger.debug( "targetRepo basedir is: \'" + targetRepo.getBasedir() + "\'" ); } - FileWriter to = null; - try + File targetParent = artifactTarget.getParentFile(); + if ( !targetParent.exists() ) { - StringReader from = null; - if ( pomContents != null ) - { - from = new StringReader( pomContents ); - } - - to = new FileWriter( targetPom ); - - artifactPomRewriter.rewrite( artifact, from, to, artifactReporter, configuration - .reportOnly() ); - } - finally - { - IOUtil.close( to ); + targetParent.mkdirs(); } - boolean wroteBridge = bridgePomLocations( targetPom, bridgedTargetPom, artifactReporter ); - - digestVerifier.verifyDigest( sourcePom, targetPom, transaction, artifactReporter, - configuration.reportOnly() ); - - if ( wroteBridge ) + if ( logger.isDebugEnabled() ) { - digestVerifier.verifyDigest( sourcePom, bridgedTargetPom, transaction, - artifactReporter, configuration.reportOnly() ); + logger.debug( "Copying artifact[" + artifact.getId() + "] from \'" + artifactSource + + "\' to \'" + artifactTarget + "\'." ); } + copyArtifact( artifact, artifactTarget, artifactReporter ); } - catch ( Exception e ) - { - repoReporter.error( "Error rewriting POM for artifact[" + artifact.getId() - + "] into the target repository.\n Error message: " + e.getMessage() ); - - throw e; - } - - rewritten.add( artifact ); } - else if ( !targetMissingOrOlder ) + catch ( Exception e ) { - artifactReporter.warn( "Target file for artifact is present and not stale. (Artifact: \'" - + artifact.getId() + "\' in path: \'" + artifactSource + "\' with target path: " - + artifactTarget + ")." ); - } - else - { - artifactReporter.error( "Cannot find source file for artifact: \'" + artifact.getId() - + "\' under path: \'" + artifactSource + "\'" ); + repoReporter.error( "Error transferring artifact[" + artifact.getId() + + "] to the target repository.", e ); + + throw e; } - if ( artifactReporter.hasError() ) + if ( logger.isDebugEnabled() ) { - repoReporter.warn( "Error(s) occurred while rewriting artifact: \'" + artifact.getId() - + "\' or its POM." ); + logger.debug( "working on digest for artifact[" + artifact.getId() + "] with groupId: \'" + + artifact.getGroupId() + "\'" ); } + + try + { + digestVerifier.verifyDigest( artifactSource, artifactTarget, transaction, artifactReporter, + configuration.reportOnly() ); + } + catch ( Exception e ) + { + repoReporter.error( "Error verifying digest for artifact[" + artifact.getId() + "]", e ); + + throw e; + } + + try + { + rewriteMetadata( artifact, transaction, sourceBase, sourceRepo, targetBase, targetRepo, + artifactReporter, configuration.reportOnly() ); + } + catch ( Exception e ) + { + repoReporter.error( "Error rewriting POM for artifact[" + artifact.getId() + + "] into the target repository.\n Error message: " + e.getMessage() ); + + throw e; + } + + rewritten.add( artifact ); + } + else if ( !targetMissingOrOlder ) + { + artifactReporter.warn( "Target file for artifact is present and not stale. (Artifact: \'" + + artifact.getId() + "\' in path: \'" + artifactSource + "\' with target path: " + + artifactTarget + ")." ); + } + else + { + artifactReporter.error( "Cannot find source file for artifact: \'" + artifact.getId() + + "\' under path: \'" + artifactSource + "\'" ); + } + + if ( artifactReporter.hasError() ) + { + repoReporter.warn( "Error(s) occurred while rewriting artifact: \'" + artifact.getId() + + "\' or its POM." ); + } + } + catch ( Exception e ) + { + if ( !configuration.force() ) + { + repoReporter.warn( "Rolling back conversion for: " + artifact ); + try + { + transaction.rollback(); + } + catch ( RollbackException re ) + { + repoReporter.error( "Error rolling back conversion transaction.", re ); + } + } + else + { + repoReporter.warn( "NOT Rolling back conversion for: " + artifact + "; we are in --force mode." ); + } + + artifactReporter.error( "Error while rewriting file or POM for artifact: \'" + artifact.getId() + + "\'. See report at: \'" + artifactReportPath + "\'.", e ); + } + finally + { + if ( artifactReporter != null ) + { + artifactReporter.close(); + } + } + } + + logger.info( "Actual number of artifacts rewritten: " + rewritten.size() + " (" + ( rewritten.size() * 2 ) + + " including POMs)." ); + + return rewritten; + } + + private void rewriteMetadata( Artifact artifact, RewriteTransaction transaction, File sourceBase, + ArtifactRepository sourceRepo, File targetBase, ArtifactRepository targetRepo, + Reporter artifactReporter, boolean reportOnly ) + throws Exception + { + // SNAPSHOT metadata + ArtifactMetadata snapshot = new SnapshotArtifactMetadata( artifact ); + + File snapshotSource = new File( sourceBase, sourceRepo.pathOfMetadata( snapshot ) ); + File snapshotTarget = new File( targetBase, targetRepo.pathOfMetadata( snapshot ) ); + + freshenSupplementalMetadata( snapshot, snapshotSource, snapshotTarget, transaction, artifactReporter, + reportOnly ); + + // RELEASE metadata + ArtifactMetadata release = new ReleaseArtifactMetadata( artifact ); + + File releaseSource = new File( sourceBase, sourceRepo.pathOfMetadata( release ) ); + File releaseTarget = new File( targetBase, targetRepo.pathOfMetadata( release ) ); + + freshenSupplementalMetadata( release, releaseSource, releaseTarget, transaction, artifactReporter, reportOnly ); + + // The rest is for POM metadata - translation and bridging of locations in the target repo may be required. + ArtifactMetadata pom = new ProjectMetadata( artifact ); + + File sourcePom = new File( sourceBase, sourceRepo.pathOfMetadata( pom ) ); + File targetPom = new File( targetBase, targetRepo.pathOfMetadata( pom ).replace( '+', '-' ) ); + + String pomContents = null; + + boolean pomNeedsRewriting = true; + + if ( sourcePom.exists() ) + { + pomContents = readPomContents( sourcePom ); + + if ( pomContents.indexOf( "modelVersion" ) > -1 ) + { + pomNeedsRewriting = false; + + freshenSupplementalMetadata( pom, sourcePom, targetPom, transaction, artifactReporter, reportOnly ); + } + } + + if ( pomNeedsRewriting ) + { + ArtifactPomRewriter artifactPomRewriter = null; + + try + { + artifactPomRewriter = (ArtifactPomRewriter) container.lookup( ArtifactPomRewriter.ROLE, + ArtifactPomRewriter.V3_POM ); + + transaction.addFile( targetPom ); + + File bridgedTargetPom = new File( targetBase, bridgingLayout.pathOfMetadata( pom ).replace( '+', '-' ) ); + + transaction.addFile( bridgedTargetPom ); + + try + { + File targetPomParent = targetPom.getParentFile(); + if ( !targetPomParent.exists() ) + { + targetPomParent.mkdirs(); + } + + FileWriter to = null; + try + { + StringReader from = null; + if ( pomContents != null ) + { + from = new StringReader( pomContents ); + } + + to = new FileWriter( targetPom ); + + artifactPomRewriter.rewrite( artifact, from, to, artifactReporter, reportOnly ); + } + finally + { + IOUtil.close( to ); + } + + boolean wroteBridge = bridgePomLocations( pom, targetPom, bridgedTargetPom, artifactReporter, + transaction, reportOnly ); + + digestVerifier.verifyDigest( sourcePom, targetPom, transaction, artifactReporter, reportOnly ); + + if ( wroteBridge ) + { + digestVerifier.verifyDigest( sourcePom, bridgedTargetPom, transaction, artifactReporter, + reportOnly ); + } + } catch ( Exception e ) { - if ( !configuration.force() ) - { - repoReporter.warn( "Rolling back conversion for: " + artifact ); - try - { - transaction.rollback(); - } - catch ( RollbackException re ) - { - repoReporter.error( "Error rolling back conversion transaction.", re ); - } - } - else - { - repoReporter - .warn( "NOT Rolling back conversion for: " + artifact + "; we are in --force mode." ); - } - - artifactReporter.error( "Error while rewriting file or POM for artifact: \'" + artifact.getId() - + "\'. See report at: \'" + artifactReportPath + "\'.", e ); - } - finally - { - if ( artifactReporter != null ) - { - artifactReporter.close(); - } + throw e; } } - - logger.info( "Actual number of artifacts rewritten: " + rewritten.size() + " (" + ( rewritten.size() * 2 ) - + " including POMs)." ); - } - finally - { - if ( artifactPomRewriter != null ) + finally { - container.release( artifactPomRewriter ); + if ( artifactPomRewriter != null ) + { + try + { + container.release( artifactPomRewriter ); + } + catch ( ComponentLifecycleException e ) + { + } + } } } + } - return rewritten; + private void freshenSupplementalMetadata( ArtifactMetadata metadata, File source, File target, + RewriteTransaction transaction, Reporter artifactReporter, + boolean reportOnly ) + throws IOException, DigestException, ReportWriteException + { + if ( source.exists() ) + { + File targetParent = target.getParentFile(); + if ( !targetParent.exists() ) + { + targetParent.mkdirs(); + } + + FileReader reader = null; + FileWriter writer = null; + + try + { + reader = new FileReader( source ); + writer = new FileWriter( target ); + + IOUtil.copy( reader, writer ); + } + finally + { + IOUtil.close( reader ); + IOUtil.close( writer ); + } + + digestVerifier.verifyDigest( source, target, transaction, artifactReporter, reportOnly ); + + } } private String readPomContents( File sourcePom ) @@ -377,8 +456,9 @@ public class RewritePhase } } - private boolean bridgePomLocations( File targetPom, File bridgedTargetPom, Reporter reporter ) - throws IOException, ReportWriteException + private boolean bridgePomLocations( ArtifactMetadata pom, File targetPom, File bridgedTargetPom, Reporter reporter, + RewriteTransaction transaction, boolean reportOnly ) + throws IOException, ReportWriteException, DigestException { if ( targetPom.equals( bridgedTargetPom ) ) { @@ -388,21 +468,7 @@ public class RewritePhase return false; } - FileInputStream in = null; - FileOutputStream out = null; - - try - { - in = new FileInputStream( targetPom ); - out = new FileOutputStream( bridgedTargetPom ); - - IOUtil.copy( in, out ); - } - finally - { - IOUtil.close( in ); - IOUtil.close( out ); - } + freshenSupplementalMetadata( pom, targetPom, bridgedTargetPom, transaction, reporter, reportOnly ); return true; }