All Downloads are FREE. Search and download functionalities are using the official Maven repository.

hudson.scm.SubversionChangeLogSet Maven / Gradle / Ivy

There is a newer version: 2.3.11
Show newest version
/*
 * The MIT License
 * 
 * Copyright (c) 2004-2011, Oracle Corporation, Inc., Kohsuke Kawaguchi, Erik Ramfelt, Nikita Levyankov
 * 
 * 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.AbstractBuild;
import hudson.model.User;
import hudson.scm.SubversionChangeLogSet.LogEntry;
import hudson.scm.SubversionSCM.ModuleLocation;
import java.io.IOException;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.kohsuke.stapler.export.Exported;
import org.kohsuke.stapler.export.ExportedBean;

/**
 * {@link ChangeLogSet} for Subversion.
 *
 * @author Kohsuke Kawaguchi
 * @author Nikita Levyankov
 */
public final class SubversionChangeLogSet extends ChangeLogSet {
    private final List logs;

    /**
     * @GuardedBy this
     */
    private Map revisionMap;

    /*package*/ SubversionChangeLogSet(AbstractBuild build, List logs) {
        super(build);
        this.logs = prepareChangeLogEntries(logs);
    }

    public List getLogs() {
        return logs;
    }

    @Override
    public String getKind() {
        return "svn";
    }

    public synchronized Map getRevisionMap() throws IOException {
        if (revisionMap == null) {
            revisionMap = SubversionSCM.parseRevisionFile(build);
        }
        return revisionMap;
    }

    @Exported
    public List getRevisions() throws IOException {
        List r = new ArrayList();
        for (Map.Entry e : getRevisionMap().entrySet()) {
            r.add(new RevisionInfo(e.getKey(), e.getValue().longValue()));
        }
        return r;
    }

    protected List prepareChangeLogEntries(List items) {
        items = removeDuplicatedEntries(items);
        // we want recent changes first
        Collections.sort(items, new LogEntryComparator());
        for (LogEntry log : items) {
            log.setParent(this);
        }
        return Collections.unmodifiableList(items);
    }

    /**
     * Removes duplicate entries, ie those coming form svn:externals.
     *
     * @param items list of items
     * @return filtered list without duplicated entries
     */
    protected static List removeDuplicatedEntries(List items) {
        Set entries = new HashSet(items);
        return new ArrayList(entries);
    }

    @ExportedBean(defaultVisibility = 999)
    public static final class RevisionInfo {
        @Exported
        public final String module;
        @Exported
        public final long revision;

        public RevisionInfo(String module, long revision) {
            this.module = module;
            this.revision = revision;
        }
    }

    /**
     * One commit.
     * 

* Setter methods are public only so that the objects can be constructed from Digester. * So please consider this object read-only. */ public static class LogEntry extends ChangeLogSet.Entry { private int revision; private User author; private String date; private String msg; private List paths = new ArrayList(); /** * Gets the {@link SubversionChangeLogSet} to which this change set belongs. */ public SubversionChangeLogSet getParent() { return (SubversionChangeLogSet) super.getParent(); } // because of the classloader difference, we need to extend this method to make it accessible // to the rest of SubversionSCM @Override @SuppressWarnings({"PMD"}) protected void setParent(ChangeLogSet changeLogSet) { super.setParent(changeLogSet); } /** * Gets the revision of the commit. *

*

* If the commit made the repository revision 1532, this * method returns 1532. */ @Exported public int getRevision() { return revision; } public void setRevision(int revision) { this.revision = revision; } /** * {@inheritDoc} */ @Override public String getCurrentRevision() { return String.valueOf(getRevision()); } /** * {@inheritDoc} */ public User getAuthor() { if (author == null) { return User.getUnknown(); } return author; } /** * {@inheritDoc} */ public Collection getAffectedPaths() { return new AbstractList() { public String get(int index) { return preparePath(paths.get(index).value); } public int size() { return paths.size(); } }; } private String preparePath(String path) { SCM scm = getParent().build.getProject().getScm(); if (!(scm instanceof SubversionSCM)) { return path; } ModuleLocation[] locations = ((SubversionSCM) scm).getLocations(); for (int i = 0; i < locations.length; i++) { String commonPart = findCommonPart(locations[i].remote, path); if (commonPart != null) { if (path.startsWith("/")) { path = path.substring(1); } String newPath = path.substring(commonPart.length()); if (newPath.startsWith("/")) { newPath = newPath.substring(1); } return newPath; } } return path; } private String findCommonPart(String folder, String filePath) { if (folder == null || filePath == null) { return null; } if (filePath.startsWith("/")) { filePath = filePath.substring(1); } for (int i = 0; i < folder.length(); i++) { String part = folder.substring(i); if (filePath.startsWith(part)) { return part; } } return null; } public void setUser(String author) { this.author = User.get(author); } @Exported public String getUser() {// digester wants read/write property, even though it never reads. Duh. return getAuthor().getDisplayName(); } @Exported public String getDate() { return date; } public void setDate(String date) { this.date = date; } @Exported public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public void addPath(Path p) { p.entry = this; paths.add(p); } /** * Gets the files that are changed in this commit. * * @return can be empty but never null. */ @Exported public List getPaths() { return paths; } @Override public Collection getAffectedFiles() { return paths; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof LogEntry)) { return false; } LogEntry that = (LogEntry) o; if (revision != that.revision) { return false; } if (author != null ? !author.equals(that.author) : that.author != null) { return false; } if (date != null ? !date.equals(that.date) : that.date != null) { return false; } if (msg != null ? !msg.equals(that.msg) : that.msg != null) { return false; } return true; } @Override public int hashCode() { int result = revision; result = 31 * result + (author != null ? author.hashCode() : 0); result = 31 * result + (date != null ? date.hashCode() : 0); result = 31 * result + (msg != null ? msg.hashCode() : 0); return result; } } /** * A file in a commit. *

* Setter methods are public only so that the objects can be constructed from Digester. * So please consider this object read-only. */ @ExportedBean(defaultVisibility = 999) public static class Path implements AffectedFile { private LogEntry entry; private char action; private String value; /** * Gets the {@link LogEntry} of which this path is a member. */ public LogEntry getLogEntry() { return entry; } /** * Sets the {@link LogEntry} of which this path is a member. */ public void setLogEntry(LogEntry entry) { this.entry = entry; } public void setAction(String action) { this.action = action.charAt(0); } /** * Path in the repository. Such as /test/trunk/foo.c */ @Exported(name = "file") public String getValue() { return value; } /** * Inherited from AffectedFile */ public String getPath() { return getValue(); } public void setValue(String value) { this.value = value; } @Exported public EditType getEditType() { if (action == 'A') { return EditType.ADD; } if (action == 'D') { return EditType.DELETE; } return EditType.EDIT; } } private static final class LogEntryComparator implements Comparator { public int compare(LogEntry a, LogEntry b) { return b.getRevision() - a.getRevision(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy