blob: f870f482c8a8e699e8177a9aedbb32861d076a2e [file] [log] [blame]
/**
* @copyright
* ====================================================================
* 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.
* ====================================================================
* @endcopyright
*/
package org.apache.subversion.javahl.types;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import org.apache.subversion.javahl.SubversionException;
/**
* Merge history for a path.
*/
public class Mergeinfo implements java.io.Serializable
{
// Update the serialVersionUID when there is an incompatible change made to
// this class. See the Java documentation (following link or its counter-
// part in your specific Java release) for when a change is incompatible.
// https://docs.oracle.com/en/java/javase/11/docs/specs/serialization/version.html#type-changes-affecting-serialization
private static final long serialVersionUID = 1L;
/**
* A mapping of repository-relative paths to a list of revision
* ranges.
*/
private Map<String, List<RevisionRange>> mergeSources;
public Mergeinfo()
{
mergeSources = new HashMap<String, List<RevisionRange>>();
}
/**
* Create and populate an instance using the contents of the
* <code>svn:mergeinfo</code> property.
* @param mergeinfo <code>svn:mergeinfo</code> property value.
*/
public Mergeinfo(String mergeinfo)
{
this();
this.loadFromMergeinfoProperty(mergeinfo);
}
/**
* The three ways to request mergeinfo affecting a given path
* in {@link org.apache.subversion.javahl.ISVNRemote#getMergeinfo}.
* @since 1.9
*/
public static enum Inheritance
{
/** Explicit mergeinfo only. */
explicit,
/**
* Explicit mergeinfo, or if that doesn't exist, the inherited
* mergeinfo from a target's nearest (path-wise, not history-wise)
* ancestor.
*/
inherited,
/**
* Mergeinfo inherited from a target's nearest (path-wise,
* not history-wise) ancestor, regardless of whether target
* has explicit mergeinfo.
*/
nearest_ancestor;
}
/**
* Add one or more RevisionRange objects to merge info. If the
* merge source is already stored, the list of revisions is
* replaced.
* @param mergeSrc The merge source URL.
* @param ranges RevisionRange objects to add.
* @throws SubversionException If range list contains objects of
* type other than RevisionRange.
*/
public void addRevisions(String mergeSrc, List<RevisionRange> ranges)
{
for (RevisionRange range : ranges)
addRevisionRange(mergeSrc, range);
}
public void addRevisions(String mergeSrc, RevisionRangeList ranges)
{
addRevisions(mergeSrc, ranges.getRanges());
}
/**
* Add a revision range to the merged revisions for a path. If
* the merge source already has associated revision ranges, add
* the revision range to the existing list.
* @param mergeSrc The merge source URL.
* @param range The revision range to add.
*/
public void addRevisionRange(String mergeSrc, RevisionRange range)
{
List<RevisionRange> revisions = this.getRevisions(mergeSrc);
if (revisions == null)
revisions = new ArrayList<RevisionRange>();
revisions.add(range);
this.setRevisionList(mergeSrc, revisions);
}
/**
* Get the merge source URLs.
* @return The merge source URLs.
*/
public Set<String> getPaths()
{
return mergeSources.keySet();
}
/**
* Get the revision ranges for the specified merge source URL.
* @param mergeSrc The merge source URL, or <code>null</code>.
* @return List of RevisionRange objects, or <code>null</code>.
*/
public List<RevisionRange> getRevisions(String mergeSrc)
{
if (mergeSrc == null)
return null;
return mergeSources.get(mergeSrc);
}
/**
* Get the RevisionRange objects for the specified merge source URL
* @param mergeSrc The merge source URL, or <code>null</code>.
* @return Array of RevisionRange objects, or <code>null</code>.
*/
public List<RevisionRange> getRevisionRange(String mergeSrc)
{
return this.getRevisions(mergeSrc);
}
/**
* Like {@link #getReivsionRange}, but returns a {@link RevisionRangeList}.
*/
public RevisionRangeList getRevisionRangeList(String mergeSrc)
{
return new RevisionRangeList(getRevisionRange(mergeSrc));
}
/**
* Parse the <code>svn:mergeinfo</code> property to populate the
* merge source URLs and revision ranges of this instance.
* @param mergeinfo <code>svn:mergeinfo</code> property value.
*/
public void loadFromMergeinfoProperty(String mergeinfo)
{
if (mergeinfo == null)
return;
StringTokenizer st = new StringTokenizer(mergeinfo, "\n");
while (st.hasMoreTokens())
{
parseMergeinfoLine(st.nextToken());
}
}
/**
* Parse a merge source line from a <code>svn:mergeinfo</code>
* property value (e.g.
* <code>"/trunk:1-100,104,108,110-115"</code>).
*
* @param line A line of merge info for a single merge source.
*/
private void parseMergeinfoLine(String line)
{
int colon = line.indexOf(':');
if (colon > 0)
{
String pathElement = line.substring(0, colon);
String revisions = line.substring(colon + 1);
parseRevisions(pathElement, revisions);
}
}
/**
* Parse the revisions in a merge info line into RevisionRange
* objects and adds each of them to the internal Map
* (e.g. <code>"1-100,104,108,110-115"</code>)
*
* @param path The merge source path.
* @param revisions A textual representation of the revision ranges.
*/
private void parseRevisions(String path, String revisions)
{
List<RevisionRange> rangeList = this.getRevisions(path);
StringTokenizer st = new StringTokenizer(revisions, ",");
while (st.hasMoreTokens())
{
String revisionElement = st.nextToken();
RevisionRange range = new RevisionRange(revisionElement);
if (rangeList == null)
rangeList = new ArrayList<RevisionRange>();
rangeList.add(range);
}
if (rangeList != null)
setRevisionList(path, rangeList);
}
/**
* Add the List object to the map. This method is only
* used internally where we know that List contains a
* type-safe set of RevisionRange objects.
* @param mergeSrc The merge source URL.
* @param range List of RevisionRange objects to add.
*/
private void setRevisionList(String mergeSrc, List<RevisionRange> range)
{
mergeSources.put(mergeSrc, range);
}
/**
* Constants to specify which collection of revisions to report in
* getMergeinfoLog.
*/
public enum LogKind
{
/** Revisions eligible for merging from merge-source to merge-target. */
eligible,
/** Revisions already merged from merge-source to merge-target. */
merged;
}
}