blob: f57ba8bded42490ec2b614d7968d0aac66bce0fe [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.shared.release.util;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import org.apache.maven.model.Model;
import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.release.ReleaseExecutionException;
import org.apache.maven.shared.release.config.ReleaseDescriptor;
import org.apache.maven.shared.release.config.ReleaseDescriptorBuilder;
import org.apache.maven.shared.release.config.ReleaseUtils;
import org.codehaus.plexus.interpolation.InterpolationException;
import org.codehaus.plexus.interpolation.MapBasedValueSource;
import org.codehaus.plexus.interpolation.ObjectBasedValueSource;
import org.codehaus.plexus.interpolation.PrefixAwareRecursionInterceptor;
import org.codehaus.plexus.interpolation.PrefixedObjectValueSource;
import org.codehaus.plexus.interpolation.StringSearchInterpolator;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.ReaderFactory;
/**
* @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
*/
public class ReleaseUtil {
@SuppressWarnings("checkstyle:constantname")
public static final String RELEASE_POMv4 = "release-pom.xml";
@SuppressWarnings("checkstyle:constantname")
public static final String POMv4 = "pom.xml";
/**
* The line separator to use.
*/
public static final String LS = System.getProperty("line.separator");
private ReleaseUtil() {
// noop
}
public static MavenProject getRootProject(List<MavenProject> reactorProjects) {
MavenProject project = reactorProjects.get(0);
for (MavenProject currentProject : reactorProjects) {
if (currentProject.isExecutionRoot()) {
project = currentProject;
break;
}
}
return project;
}
public static File getStandardPom(MavenProject project) {
if (project == null) {
return null;
}
File pom = project.getFile();
if (pom == null) {
return null;
}
File releasePom = getReleasePom(project);
if (pom.equals(releasePom)) {
pom = new File(pom.getParent(), POMv4);
}
return pom;
}
public static File getReleasePom(MavenProject project) {
if (project == null) {
return null;
}
File pom = project.getFile();
if (pom == null) {
return null;
}
return new File(pom.getParent(), RELEASE_POMv4);
}
/**
* Gets the string contents of the specified XML file. Note: In contrast to an XML processor, the line separators in
* the returned string will be normalized to use the platform's native line separator. This is basically to save
* another normalization step when writing the string contents back to an XML file.
*
* @param file The path to the XML file to read in, must not be <code>null</code>.
* @return The string contents of the XML file.
* @throws IOException If the file could not be opened/read.
*/
public static String readXmlFile(File file) throws IOException {
return readXmlFile(file, LS);
}
public static String readXmlFile(File file, String ls) throws IOException {
try (Reader reader = ReaderFactory.newXmlReader(file)) {
return normalizeLineEndings(IOUtil.toString(reader), ls);
}
}
/**
* Normalizes the line separators in the specified string.
*
* @param text The string to normalize, may be <code>null</code>.
* @param separator The line separator to use for normalization, typically "\n" or "\r\n", must not be
* <code>null</code>.
* @return The input string with normalized line separators or <code>null</code> if the string was <code>null</code>
* .
*/
public static String normalizeLineEndings(String text, String separator) {
String norm = text;
if (text != null) {
norm = text.replaceAll("(\r\n)|(\n)|(\r)", separator);
}
return norm;
}
public static ReleaseDescriptor createBasedirAlignedReleaseDescriptor(
ReleaseDescriptor releaseDescriptor, List<MavenProject> reactorProjects) throws ReleaseExecutionException {
int parentLevels = Paths.get(releaseDescriptor.getPomFileName()).getNameCount() - 1;
String url = releaseDescriptor.getScmSourceUrl();
url = realignScmUrl(parentLevels, url);
ReleaseDescriptorBuilder builder = new ReleaseDescriptorBuilder();
builder.setWorkingDirectory(releaseDescriptor.getWorkingDirectory());
builder.setScmSourceUrl(url);
return ReleaseUtils.buildReleaseDescriptor(builder);
}
public static int getBaseWorkingDirectoryParentCount(final Path baseDirectory, final Path workingDirectory) {
return Math.max(
0,
workingDirectory.normalize().getNameCount()
- baseDirectory.normalize().getNameCount());
}
public static String realignScmUrl(int parentLevels, String url) {
if (!(url == null || url.isEmpty())) {
// normalize
url = url.replaceAll("/\\./", "/")
.replaceAll("/\\.$", "")
.replaceAll("/[^/]+/\\.\\./", "/")
.replaceAll("/[^/]+/\\.\\.$", "");
int index = url.length();
String suffix = "";
if (url.endsWith("/")) {
index--;
suffix = "/";
}
for (int i = 0; i < parentLevels && index > 0; i++) {
index = url.lastIndexOf('/', index - 1);
}
if (index > 0) {
url = url.substring(0, index) + suffix;
}
}
return url;
}
public static String interpolate(String value, Model model) throws ReleaseExecutionException {
if (value != null && value.contains("${")) {
StringSearchInterpolator interpolator = new StringSearchInterpolator();
List<String> pomPrefixes = Arrays.asList("pom.", "project.");
interpolator.addValueSource(new PrefixedObjectValueSource(pomPrefixes, model, false));
interpolator.addValueSource(new MapBasedValueSource(model.getProperties()));
interpolator.addValueSource(new ObjectBasedValueSource(model));
try {
value = interpolator.interpolate(value, new PrefixAwareRecursionInterceptor(pomPrefixes));
} catch (InterpolationException e) {
throw new ReleaseExecutionException(
"Failed to interpolate " + value + " for project " + model.getId(), e);
}
}
return value;
}
}