blob: 79e56114023135cfdf331b5de6af2caecb510f57 [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.scm.provider.svn;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.scm.CommandParameters;
import org.apache.maven.scm.ScmException;
import org.apache.maven.scm.ScmFileSet;
import org.apache.maven.scm.ScmResult;
import org.apache.maven.scm.command.add.AddScmResult;
import org.apache.maven.scm.command.blame.BlameScmResult;
import org.apache.maven.scm.command.branch.BranchScmResult;
import org.apache.maven.scm.command.changelog.ChangeLogScmResult;
import org.apache.maven.scm.command.checkin.CheckInScmResult;
import org.apache.maven.scm.command.checkout.CheckOutScmResult;
import org.apache.maven.scm.command.diff.DiffScmResult;
import org.apache.maven.scm.command.export.ExportScmResult;
import org.apache.maven.scm.command.info.InfoItem;
import org.apache.maven.scm.command.info.InfoScmResult;
import org.apache.maven.scm.command.list.ListScmResult;
import org.apache.maven.scm.command.mkdir.MkdirScmResult;
import org.apache.maven.scm.command.remove.RemoveScmResult;
import org.apache.maven.scm.command.status.StatusScmResult;
import org.apache.maven.scm.command.tag.TagScmResult;
import org.apache.maven.scm.command.untag.UntagScmResult;
import org.apache.maven.scm.command.update.UpdateScmResult;
import org.apache.maven.scm.provider.AbstractScmProvider;
import org.apache.maven.scm.provider.ScmProviderRepository;
import org.apache.maven.scm.provider.svn.command.SvnCommand;
import org.apache.maven.scm.provider.svn.repository.SvnScmProviderRepository;
import org.apache.maven.scm.provider.svn.util.SvnUtil;
import org.apache.maven.scm.repository.ScmRepository;
import org.apache.maven.scm.repository.ScmRepositoryException;
import org.apache.maven.scm.repository.UnknownRepositoryStructure;
/**
* SCM Provider for Subversion
*
* @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
*
*/
public abstract class AbstractSvnScmProvider extends AbstractScmProvider {
// ----------------------------------------------------------------------
//
// ----------------------------------------------------------------------
private static class ScmUrlParserResult {
private final List<String> messages = new ArrayList<>();
private ScmProviderRepository repository;
}
public static final String CURRENT_WORKING_DIRECTORY = "scmCheckWorkingDirectoryUrl.currentWorkingDirectory";
// ----------------------------------------------------------------------
// ScmProvider Implementation
// ----------------------------------------------------------------------
/**
* {@inheritDoc}
*/
public String getScmSpecificFilename() {
return ".svn";
}
/**
* {@inheritDoc}
*/
public ScmProviderRepository makeProviderScmRepository(String scmSpecificUrl, char delimiter)
throws ScmRepositoryException {
ScmUrlParserResult result = parseScmUrl(scmSpecificUrl);
if (checkCurrentWorkingDirectoryUrl()) {
logger.debug("Checking svn info 'URL:' field matches current sources directory");
try {
String workingDir = System.getProperty(CURRENT_WORKING_DIRECTORY);
InfoScmResult info =
info(result.repository, new ScmFileSet(new File(workingDir)), new CommandParameters());
String url = findUrlInfoItem(info);
String comparison = "'" + url + "' vs. '" + scmSpecificUrl + "'";
logger.debug("Comparing : " + comparison);
if (url != null && !url.equals(scmSpecificUrl)) {
result.messages.add("Scm url does not match the value returned by svn info (" + comparison + ")");
}
} catch (ScmException e) {
throw new ScmRepositoryException("An error occurred while trying to svn info", e);
}
}
if (result.messages.size() > 0) {
throw new ScmRepositoryException("The scm url is invalid.", result.messages);
}
return result.repository;
}
private boolean checkCurrentWorkingDirectoryUrl() {
return StringUtils.isNotEmpty(System.getProperty(CURRENT_WORKING_DIRECTORY));
}
private String findUrlInfoItem(InfoScmResult infoScmResult) {
for (InfoItem infoItem : infoScmResult.getInfoItems()) {
if (infoItem.getURL() != null) {
logger.debug("URL found: " + infoItem.getURL());
return infoItem.getURL();
}
}
logger.debug("URL not found (command output=" + infoScmResult.getCommandOutput() + ")");
return null;
}
/**
* {@inheritDoc}
*/
public ScmProviderRepository makeProviderScmRepository(File path)
throws ScmRepositoryException, UnknownRepositoryStructure {
if (path == null) {
throw new NullPointerException("Path argument is null");
}
if (!path.isDirectory()) {
throw new ScmRepositoryException(path.getAbsolutePath() + " isn't a valid directory.");
}
if (!new File(path, ".svn").exists()) {
throw new ScmRepositoryException(path.getAbsolutePath() + " isn't a svn checkout directory.");
}
try {
return makeProviderScmRepository(getRepositoryURL(path), ':');
} catch (ScmException e) {
// XXX We should allow throwing of SCMException.
throw new ScmRepositoryException("Error executing info command", e);
}
}
protected abstract String getRepositoryURL(File path) throws ScmException;
/**
* {@inheritDoc}
*/
public List<String> validateScmUrl(String scmSpecificUrl, char delimiter) {
List<String> messages = new ArrayList<>();
try {
makeProviderScmRepository(scmSpecificUrl, delimiter);
} catch (ScmRepositoryException e) {
messages = e.getValidationMessages();
}
return messages;
}
/**
* {@inheritDoc}
*/
public String getScmType() {
return "svn";
}
// ----------------------------------------------------------------------
//
// ----------------------------------------------------------------------
private ScmUrlParserResult parseScmUrl(String scmSpecificUrl) {
ScmUrlParserResult result = new ScmUrlParserResult();
// ----------------------------------------------------------------------
// Do some sanity checking of the SVN url
// ----------------------------------------------------------------------
if (scmSpecificUrl.startsWith("file")) {
if (!scmSpecificUrl.startsWith("file://")) {
result.messages.add("A svn 'file' url must be on the form 'file://[hostname]/'.");
return result;
}
} else if (scmSpecificUrl.startsWith("https")) {
if (!scmSpecificUrl.startsWith("https://")) {
result.messages.add("A svn 'http' url must be on the form 'https://'.");
return result;
}
} else if (scmSpecificUrl.startsWith("http")) {
if (!scmSpecificUrl.startsWith("http://")) {
result.messages.add("A svn 'http' url must be on the form 'http://'.");
return result;
}
}
// Support of tunnels: svn+xxx with xxx defined in subversion conf file
else if (scmSpecificUrl.startsWith("svn+")) {
if (scmSpecificUrl.indexOf("://") < 0) {
result.messages.add("A svn 'svn+xxx' url must be on the form 'svn+xxx://'.");
return result;
} else {
String tunnel = scmSpecificUrl.substring("svn+".length(), scmSpecificUrl.indexOf("://"));
// ssh is always an allowed tunnel
if (!"ssh".equals(tunnel)) {
SvnConfigFileReader reader = new SvnConfigFileReader();
if (SvnUtil.getSettings().getConfigDirectory() != null) {
reader.setConfigDirectory(new File(SvnUtil.getSettings().getConfigDirectory()));
}
if (StringUtils.isEmpty(reader.getProperty("tunnels", tunnel))) {
result.messages.add(
"The tunnel '" + tunnel + "' isn't defined in your subversion configuration file.");
return result;
}
}
}
} else if (scmSpecificUrl.startsWith("svn")) {
if (!scmSpecificUrl.startsWith("svn://")) {
result.messages.add("A svn 'svn' url must be on the form 'svn://'.");
return result;
}
} else {
result.messages.add(scmSpecificUrl + " url isn't a valid svn URL.");
return result;
}
result.repository = new SvnScmProviderRepository(scmSpecificUrl);
return result;
}
protected abstract SvnCommand getAddCommand();
/**
* {@inheritDoc}
*/
public AddScmResult add(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
throws ScmException {
return (AddScmResult) executeCommand(getAddCommand(), repository, fileSet, parameters);
}
protected abstract SvnCommand getBranchCommand();
/**
* {@inheritDoc}
*/
protected BranchScmResult branch(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
throws ScmException {
return (BranchScmResult) executeCommand(getBranchCommand(), repository, fileSet, parameters);
}
protected abstract SvnCommand getChangeLogCommand();
/**
* {@inheritDoc}
*/
public ChangeLogScmResult changelog(
ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters) throws ScmException {
return (ChangeLogScmResult) executeCommand(getChangeLogCommand(), repository, fileSet, parameters);
}
protected abstract SvnCommand getCheckInCommand();
/**
* {@inheritDoc}
*/
public CheckInScmResult checkin(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
throws ScmException {
return (CheckInScmResult) executeCommand(getCheckInCommand(), repository, fileSet, parameters);
}
protected abstract SvnCommand getCheckOutCommand();
/**
* {@inheritDoc}
*/
public CheckOutScmResult checkout(
ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters) throws ScmException {
return (CheckOutScmResult) executeCommand(getCheckOutCommand(), repository, fileSet, parameters);
}
protected abstract SvnCommand getDiffCommand();
/**
* {@inheritDoc}
*/
public DiffScmResult diff(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
throws ScmException {
return (DiffScmResult) executeCommand(getDiffCommand(), repository, fileSet, parameters);
}
protected abstract SvnCommand getExportCommand();
/**
* {@inheritDoc}
*/
protected ExportScmResult export(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
throws ScmException {
return (ExportScmResult) executeCommand(getExportCommand(), repository, fileSet, parameters);
}
protected abstract SvnCommand getRemoveCommand();
/**
* {@inheritDoc}
*/
public RemoveScmResult remove(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
throws ScmException {
return (RemoveScmResult) executeCommand(getRemoveCommand(), repository, fileSet, parameters);
}
protected abstract SvnCommand getStatusCommand();
/**
* {@inheritDoc}
*/
public StatusScmResult status(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
throws ScmException {
return (StatusScmResult) executeCommand(getStatusCommand(), repository, fileSet, parameters);
}
protected abstract SvnCommand getTagCommand();
/**
* {@inheritDoc}
*/
public TagScmResult tag(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
throws ScmException {
return (TagScmResult) executeCommand(getTagCommand(), repository, fileSet, parameters);
}
protected abstract SvnCommand getUntagCommand();
/**
* {@inheritDoc}
*/
@Override
public UntagScmResult untag(ScmRepository repository, ScmFileSet fileSet, CommandParameters parameters)
throws ScmException {
return (UntagScmResult)
executeCommand(getUntagCommand(), repository.getProviderRepository(), fileSet, parameters);
}
protected abstract SvnCommand getUpdateCommand();
/**
* {@inheritDoc}
*/
public UpdateScmResult update(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
throws ScmException {
return (UpdateScmResult) executeCommand(getUpdateCommand(), repository, fileSet, parameters);
}
protected ScmResult executeCommand(
SvnCommand command, ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
throws ScmException {
return command.execute(repository, fileSet, parameters);
}
protected abstract SvnCommand getListCommand();
/**
* {@inheritDoc}
*/
public ListScmResult list(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
throws ScmException {
SvnCommand cmd = getListCommand();
return (ListScmResult) executeCommand(cmd, repository, fileSet, parameters);
}
protected abstract SvnCommand getInfoCommand();
public InfoScmResult info(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
throws ScmException {
SvnCommand cmd = getInfoCommand();
return (InfoScmResult) executeCommand(cmd, repository, fileSet, parameters);
}
/**
* {@inheritDoc}
*/
protected BlameScmResult blame(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
throws ScmException {
SvnCommand cmd = getBlameCommand();
return (BlameScmResult) executeCommand(cmd, repository, fileSet, parameters);
}
protected abstract SvnCommand getBlameCommand();
/**
* {@inheritDoc}
*/
public MkdirScmResult mkdir(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
throws ScmException {
SvnCommand cmd = getMkdirCommand();
return (MkdirScmResult) executeCommand(cmd, repository, fileSet, parameters);
}
protected abstract SvnCommand getMkdirCommand();
/**
* @param repository
* @param parameters
* @return true if remote url exists
* @throws ScmException
* @since 1.8
*/
public abstract boolean remoteUrlExist(ScmProviderRepository repository, CommandParameters parameters)
throws ScmException;
}