/*******************************************************************************
*
* Copyright (c) 2004-2011 Oracle Corporation.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*
* Andreas Mande, Nikita Levyankov
*
*******************************************************************************/
package hudson.scm.browsers;
import hudson.Extension;
import hudson.model.AbstractProject;
import hudson.model.Descriptor;
import hudson.scm.RepositoryBrowser;
import hudson.util.FormValidation;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import hudson.scm.SubversionChangeLogSet;
import hudson.scm.SubversionRepositoryBrowser;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
/**
* {@link SubversionRepositoryBrowser} that produces links to http://www.websvn.info/ for SVN
* compatible with Version 2.3.1 of WebSVN.
*
* @author Andreas Mandel, based on ViewVC plugin by Mike Salnikov, based on Polarion plug-in by Jonny Wray
* @author Nikita Levyankov, changes were moved from WebSVN2 plugin
*/
public class WebSVN2 extends SubversionRepositoryBrowser {
// alternative: https://server/websvn/comp.php?repname=rep&compare[]=/@2222&compare[]=/@2225
private static final String CHANGE_SET_FORMAT = "revision.php?%1srev=%2d";
private static final String DIFF_FORMAT = "diff.php?%1spath=%2s&rev=%3d";
// alternative: "blame.php?%1spath=%2s&rev=%3d";
private static final String FILE_FORMAT = "filedetails.php?%1spath=%2s&rev=%3d";
private static final Pattern URL_PATTERN
= Pattern.compile("(.*/)(revision|diff|comp|filedetails|listing|blame|dl|log)"
+ "\\.php([^?]*)\\?(repname=([^&]*))?(.*)");
private static final int URL_PATTERN_BASE_URL_GROUP = 1;
private static final int URL_PATTERN_REPNAME_GROUP = 4;
public final URL url;
private final URL baseUrl;
private final String repname;
@DataBoundConstructor
public WebSVN2(URL url) throws MalformedURLException {
final Matcher webSVNurl = URL_PATTERN.matcher(url.toString());
this.url = url;
if (!webSVNurl.matches()) {
this.repname = "";
this.baseUrl = url;
} else {
this.baseUrl = new URL(webSVNurl.group(URL_PATTERN_BASE_URL_GROUP));
this.repname = webSVNurl.group(URL_PATTERN_REPNAME_GROUP) + "&";
}
}
@Override
public URL getDiffLink(SubversionChangeLogSet.Path path) throws IOException {
return new URL(this.baseUrl,
String.format(DIFF_FORMAT, this.repname, URLEncoder.encode(path.getValue(), "UTF-8"),
path.getLogEntry().getRevision()));
}
@Override
public URL getFileLink(SubversionChangeLogSet.Path path) throws IOException {
return new URL(this.baseUrl,
String.format(FILE_FORMAT, this.repname, URLEncoder.encode(path.getValue(), "UTF-8"),
path.getLogEntry().getRevision()));
}
@Override
public URL getChangeSetLink(SubversionChangeLogSet.LogEntry logEntry) throws IOException {
return new URL(this.baseUrl, String.format(CHANGE_SET_FORMAT, this.repname, logEntry.getRevision()));
}
@Extension
public static class DescriptorImpl extends Descriptor<RepositoryBrowser<?>> {
public String getDisplayName() {
return "WebSVN2";
}
public FormValidation doCheckUrl(@AncestorInPath AbstractProject project,
@QueryParameter(fixEmpty = true) final String value) {
FormValidation result;
if (value == null) {
return FormValidation.ok();
}
final Matcher matcher = URL_PATTERN.matcher(value);
if (matcher.matches()) {
try {
new URL(matcher.group(URL_PATTERN_BASE_URL_GROUP));
final String repName = matcher.group(URL_PATTERN_REPNAME_GROUP);
if (StringUtils.isBlank(repName)) { // Go online??
result = FormValidation.okWithMarkup(
"Please set a url including the repname property if needed.");
} else {
result = FormValidation.ok();
}
} catch (MalformedURLException ex) {
result = FormValidation.error("The entered url is not accepted: " + ex.getLocalizedMessage());
}
} else if (StringUtils.isBlank(value)) {
result = FormValidation.okWithMarkup(
"Please set a WebSVN url in the form "
+ "https://<i>server</i>/websvn/listing.php?repname=<i>rep</i>&path=/trunk/..");
} else {
result = FormValidation.error("Please set a url including the WebSVN php script.");
}
return result;
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
WebSVN2 that = (WebSVN2) o;
return new EqualsBuilder()
.append(baseUrl, that.baseUrl)
.append(repname, that.repname)
.append(url, that.url)
.isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder()
.append(baseUrl)
.append(repname)
.append(url)
.toHashCode();
}
}