From 679ffdee686110d52b092866abc251ae2585a0c1 Mon Sep 17 00:00:00 2001 From: kohsuke Date: Mon, 15 Jun 2009 20:44:56 +0000 Subject: [PATCH] Implemented more intelligent polling assisted by commit-hook from SVN repository. git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@18915 71c3de6d-444a-0410-be80-ed276b4c234a --- core/src/main/java/hudson/model/Hudson.java | 3 + .../main/java/hudson/model/RootAction.java | 17 +++ .../scm/SubversionRepositoryStatus.java | 103 ++++++++++++++++++ .../main/java/hudson/scm/SubversionSCM.java | 31 ++++++ .../java/hudson/scm/SubversionStatus.java | 65 +++++++++++ .../hudson/scm/SubversionSCM/help.html | 5 + 6 files changed, 224 insertions(+) create mode 100644 core/src/main/java/hudson/model/RootAction.java create mode 100644 core/src/main/java/hudson/scm/SubversionRepositoryStatus.java create mode 100644 core/src/main/java/hudson/scm/SubversionStatus.java create mode 100644 core/src/main/resources/hudson/scm/SubversionSCM/help.html diff --git a/core/src/main/java/hudson/model/Hudson.java b/core/src/main/java/hudson/model/Hudson.java index 0becac9c5d..b30248f06b 100644 --- a/core/src/main/java/hudson/model/Hudson.java +++ b/core/src/main/java/hudson/model/Hudson.java @@ -2063,6 +2063,9 @@ public final class Hudson extends Node implements ItemGroup, Stapl // Initialize the filter with the crumb issuer setCrumbIssuer(crumbIssuer); + + // auto register root actions + actions.addAll(getExtensionList(RootAction.class)); LOGGER.info(String.format("Took %s ms to load",System.currentTimeMillis()-startTime)); if(KILL_AFTER_LOAD) diff --git a/core/src/main/java/hudson/model/RootAction.java b/core/src/main/java/hudson/model/RootAction.java new file mode 100644 index 0000000000..b442871dde --- /dev/null +++ b/core/src/main/java/hudson/model/RootAction.java @@ -0,0 +1,17 @@ +package hudson.model; + +import hudson.ExtensionPoint; +import hudson.Extension; + +/** + * Marker interface for actions that are added to {@link Hudson}. + * + *

+ * Extend from this interface and put {@link Extension} on your subtype + * to have them auto-registered to {@link Hudson}. + * + * @author Kohsuke Kawaguchi + * @since 1.311 + */ +public interface RootAction extends Action, ExtensionPoint { +} diff --git a/core/src/main/java/hudson/scm/SubversionRepositoryStatus.java b/core/src/main/java/hudson/scm/SubversionRepositoryStatus.java new file mode 100644 index 0000000000..83d5f8e2db --- /dev/null +++ b/core/src/main/java/hudson/scm/SubversionRepositoryStatus.java @@ -0,0 +1,103 @@ +package hudson.scm; + +import hudson.model.AbstractModelObject; +import hudson.model.AbstractProject; +import hudson.model.Hudson; +import hudson.scm.SubversionSCM.ModuleLocation; +import hudson.triggers.SCMTrigger; +import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerResponse; +import org.tmatesoft.svn.core.SVNException; + +import javax.servlet.ServletException; +import static javax.servlet.http.HttpServletResponse.SC_OK; +import java.io.BufferedReader; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import static java.util.logging.Level.FINE; +import static java.util.logging.Level.WARNING; +import java.util.logging.Logger; + +/** + * Per repository status. + * + * @author Kohsuke Kawaguchi + * @see SubversionStatus + */ +public class SubversionRepositoryStatus extends AbstractModelObject { + public final UUID uuid; + + public SubversionRepositoryStatus(UUID uuid) { + this.uuid = uuid; + } + + public String getDisplayName() { + return uuid.toString(); + } + + public String getSearchUrl() { + return uuid.toString(); + } + + /** + * Notify the commit to this repository. + * + *

+ * Because this URL is not guarded, we can't really trust the data that's sent to us. But we intentionally + * don't protect this URL to simplify post-commit script set up. + */ + public void doNotifyCommit(StaplerRequest req, StaplerResponse rsp) throws ServletException, IOException { + requirePOST(); + + // compute the affected paths + Set affectedPath = new HashSet(); + String line; + while((line=new BufferedReader(req.getReader()).readLine())!=null) + affectedPath.add(line.substring(4)); + if(LOGGER.isLoggable(FINE)) + LOGGER.fine("Change reported to Subversion repository "+uuid+" on "+affectedPath); + + OUTER: + for (AbstractProject p : Hudson.getInstance().getItems(AbstractProject.class)) { + try { + SCM scm = p.getScm(); + if (!(scm instanceof SubversionSCM)) continue; + + SCMTrigger trigger = p.getTrigger(SCMTrigger.class); + if(trigger==null) continue; + + SubversionSCM sscm = (SubversionSCM) scm; + for (ModuleLocation loc : sscm.getLocations()) { + if(!loc.getUUID().equals(uuid)) continue; // different repository + + String m = loc.getSVNURL().getPath(); + String n = loc.getRepositoryRoot().getPath(); + if(!m.startsWith(n)) continue; // repository root should be a subpath of the module path, but be defensive + + String remaining = m.substring(n.length()); + if(remaining.startsWith("/")) remaining=remaining.substring(1); + String remainingSlash = remaining + '/'; + + for (String path : affectedPath) { + if(path.equals(remaining) /*for files*/ || path.startsWith(remainingSlash) /*for dirs*/) { + // this project is possibly changed. poll now. + // if any of the data we used was bogus, the trigger will not detect a chaange + LOGGER.fine("Scheduling the immediate polling of "+p); + trigger.run(); + + continue OUTER; + } + } + } + } catch (SVNException e) { + LOGGER.log(WARNING,"Failed to handle Subversion commit notification",e); + } + } + + rsp.setStatus(SC_OK); + } + + private static final Logger LOGGER = Logger.getLogger(SubversionRepositoryStatus.class.getName()); +} diff --git a/core/src/main/java/hudson/scm/SubversionSCM.java b/core/src/main/java/hudson/scm/SubversionSCM.java index 1eb4f23679..11e3a35b8e 100644 --- a/core/src/main/java/hudson/scm/SubversionSCM.java +++ b/core/src/main/java/hudson/scm/SubversionSCM.java @@ -122,6 +122,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Random; import java.util.StringTokenizer; +import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; @@ -1674,6 +1675,12 @@ public class SubversionSCM extends SCM implements Serializable { */ public final String local; + /** + * Cache of the repository UUID. + */ + private transient volatile UUID repositoryUUID; + private transient volatile SVNURL repositoryRoot; + public ModuleLocation(String remote, String local) { if(local==null) local = getLastPathComponent(remote); @@ -1707,6 +1714,30 @@ public class SubversionSCM extends SCM implements Serializable { return SVNURL.parseURIEncoded(getURL()); } + /** + * Repository UUID. Lazy computed and cached. + */ + public UUID getUUID() throws SVNException { + if(repositoryUUID==null || repositoryRoot==null) { + synchronized (this) { + SVNRepository r = openRepository(); + r.testConnection(); // make sure values are fetched + repositoryUUID = UUID.fromString(r.getRepositoryUUID(false)); + repositoryRoot = r.getRepositoryRoot(false); + } + } + return repositoryUUID; + } + + public SVNRepository openRepository() throws SVNException { + return Hudson.getInstance().getDescriptorByType(DescriptorImpl.class).getRepository(getSVNURL()); + } + + public SVNURL getRepositoryRoot() throws SVNException { + getUUID(); + return repositoryRoot; + } + /** * Figures out which revision to check out. * diff --git a/core/src/main/java/hudson/scm/SubversionStatus.java b/core/src/main/java/hudson/scm/SubversionStatus.java new file mode 100644 index 0000000000..622e22185c --- /dev/null +++ b/core/src/main/java/hudson/scm/SubversionStatus.java @@ -0,0 +1,65 @@ +/* + * The MIT License + * + * Copyright (c) 2004-2009, Sun Microsystems, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package hudson.scm; + +import hudson.model.AbstractModelObject; +import hudson.model.Action; +import hudson.model.RootAction; +import hudson.Extension; + +import java.util.regex.Pattern; +import java.util.UUID; + +/** + * Information screen for the use of Subversion in Hudson. + * + * @author Kohsuke Kawaguchi + */ +@Extension +public class SubversionStatus extends AbstractModelObject implements RootAction { + public String getDisplayName() { + return "Subversion"; + } + + public String getSearchUrl() { + return getUrlName(); + } + + public String getIconFileName() { + // TODO + return null; + } + + public String getUrlName() { + return "subversion"; + } + + public SubversionRepositoryStatus getDynamic(String uuid) { + if(UUID_PATTERN.matcher(uuid).matches()) + return new SubversionRepositoryStatus(UUID.fromString(uuid)); + return null; + } + + private static final Pattern UUID_PATTERN = Pattern.compile("\\p{XDigit}{8}-\\p{XDigit}{4}-\\p{XDigit}{4}-\\p{XDigit}{4}-\\p{XDigit}{12}"); +} diff --git a/core/src/main/resources/hudson/scm/SubversionSCM/help.html b/core/src/main/resources/hudson/scm/SubversionSCM/help.html new file mode 100644 index 0000000000..7df1d2513d --- /dev/null +++ b/core/src/main/resources/hudson/scm/SubversionSCM/help.html @@ -0,0 +1,5 @@ +

+ Checks out the source code from Subversion repositories. See + post-commit hook set up + for improved turn-around time and performance in polling. +
\ No newline at end of file -- GitLab