blob: 37ac28b62404e7d6091958cfcd5ff26c4f86c6c2 [file] [log] [blame]
package org.apache.maven.model.transform;
/*
* 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.
*/
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import org.apache.maven.model.transform.pull.NodeBufferingParser;
import org.codehaus.plexus.util.xml.pull.XmlPullParser;
/**
* <p>
* Transforms relativePath to version.
* We could decide to simply allow {@code <parent/>}, but let's require the GA for now for checking
* This filter does NOT remove the relativePath (which is done by {@link RelativePathXMLFilter}, it will only
* optionally include the version based on the path
* </p>
*
* @author Robert Scholte
* @author Guillaume Nodet
* @since 4.0.0
*/
class ParentXMLFilter
extends NodeBufferingParser
{
private final Function<Path, Optional<RelativeProject>> relativePathMapper;
private final Path projectPath;
/**
* @param relativePathMapper
*/
ParentXMLFilter( XmlPullParser parser,
Function<Path, Optional<RelativeProject>> relativePathMapper, Path projectPath )
{
super( parser, "parent" );
this.relativePathMapper = relativePathMapper;
this.projectPath = projectPath;
}
protected void process( List<Event> buffer )
{
String tagName = null;
String groupId = null;
String artifactId = null;
String version = null;
String relativePath = null;
String whitespaceAfterParentStart = "";
boolean hasVersion = false;
boolean hasRelativePath = false;
for ( int i = 0; i < buffer.size(); i++ )
{
Event event = buffer.get( i );
if ( event.event == START_TAG )
{
tagName = event.name;
hasVersion |= "version".equals( tagName );
hasRelativePath |= "relativePath".equals( tagName );
}
else if ( event.event == TEXT )
{
if ( event.text.matches( "\\s+" ) )
{
if ( whitespaceAfterParentStart.isEmpty() )
{
whitespaceAfterParentStart = event.text;
}
}
else if ( "groupId".equals( tagName ) )
{
groupId = nullSafeAppend( groupId, event.text );
}
else if ( "artifactId".equals( tagName ) )
{
artifactId = nullSafeAppend( artifactId, event.text );
}
else if ( "relativePath".equals( tagName ) )
{
relativePath = nullSafeAppend( relativePath, event.text );
}
else if ( "version".equals( tagName ) )
{
version = nullSafeAppend( version, event.text );
}
}
else if ( event.event == END_TAG && "parent".equals( event.name ) )
{
Optional<RelativeProject> resolvedParent;
if ( !hasVersion && ( !hasRelativePath || relativePath != null ) )
{
Path relPath = Paths.get( Objects.toString( relativePath, "../pom.xml" ) );
resolvedParent = resolveRelativePath( relPath, groupId, artifactId );
}
else
{
resolvedParent = Optional.empty();
}
if ( !hasVersion && resolvedParent.isPresent() )
{
int pos = buffer.get( i - 1 ).event == TEXT ? i - 1 : i;
Event e = new Event();
e.event = TEXT;
e.text = whitespaceAfterParentStart;
buffer.add( pos++, e );
e = new Event();
e.event = START_TAG;
e.namespace = buffer.get( 0 ).namespace;
e.prefix = buffer.get( 0 ).prefix;
e.name = "version";
buffer.add( pos++, e );
e = new Event();
e.event = TEXT;
e.text = resolvedParent.get().getVersion();
buffer.add( pos++, e );
e = new Event();
e.event = END_TAG;
e.name = "version";
e.namespace = buffer.get( 0 ).namespace;
e.prefix = buffer.get( 0 ).prefix;
buffer.add( pos++, e );
}
break;
}
}
buffer.forEach( this::pushEvent );
}
protected Optional<RelativeProject> resolveRelativePath( Path relativePath, String groupId, String artifactId )
{
Path pomPath = projectPath.resolve( relativePath );
if ( Files.isDirectory( pomPath ) )
{
pomPath = pomPath.resolve( "pom.xml" );
}
Optional<RelativeProject> mappedProject = relativePathMapper.apply( pomPath.normalize() );
if ( mappedProject.isPresent() )
{
RelativeProject project = mappedProject.get();
if ( Objects.equals( groupId, project.getGroupId() )
&& Objects.equals( artifactId, project.getArtifactId() ) )
{
return mappedProject;
}
}
return Optional.empty();
}
}