001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.ivy.plugins.conflict;
019:
020: import java.util.Arrays;
021: import java.util.Collection;
022: import java.util.Collections;
023: import java.util.Iterator;
024: import java.util.regex.Matcher;
025: import java.util.regex.Pattern;
026:
027: import org.apache.ivy.core.resolve.IvyNode;
028: import org.apache.ivy.util.Message;
029:
030: /**
031: * A ConflictManager that can be used to resolve conflicts based on regular expressions of the
032: * revision of the module. The conflict manager is added like this:
033: *
034: * <pre>
035: * <!-- Match all revisions, but ignore the last dot(.) and the character after it.
036: * Used to match api changes in out milestones. -->
037: * <conflict-managers>
038: * <regexp-cm name="regexp"
039: * regexp="(.*)\..$" ignoreNonMatching="true"/>
040: * </conflict-managers>
041: * </pre>
042: *
043: * The regular expression must contain a capturing group. The group will be used to resolve the
044: * conflicts by an String.equals() test. If ignoreNonMatching is false non matching modules will
045: * result in an exception. If it is true they will be compaired by their full revision.
046: */
047: public class RegexpConflictManager extends AbstractConflictManager {
048: private Pattern pattern = Pattern.compile("(.*)");
049:
050: private boolean mIgnoreNonMatching;
051:
052: public RegexpConflictManager() {
053: }
054:
055: public void setRegexp(String regexp) {
056: pattern = Pattern.compile(regexp);
057: Matcher matcher = pattern.matcher("abcdef");
058: if (matcher.groupCount() != 1) {
059: String message = "Pattern does not contain ONE (capturing group): '"
060: + pattern + "'";
061: Message.error(message);
062: throw new IllegalArgumentException(message);
063: }
064: }
065:
066: public void setIgnoreNonMatching(boolean ignoreNonMatching) {
067: mIgnoreNonMatching = ignoreNonMatching;
068: }
069:
070: public Collection resolveConflicts(IvyNode parent,
071: Collection conflicts) {
072: IvyNode lastNode = null;
073: for (Iterator iter = conflicts.iterator(); iter.hasNext();) {
074: IvyNode node = (IvyNode) iter.next();
075:
076: if (lastNode != null && !matchEquals(node, lastNode)) {
077: String msg = lastNode + ":" + getMatch(lastNode)
078: + " (needed by "
079: + Arrays.asList(lastNode.getAllRealCallers())
080: + ") conflicts with " + node + ":"
081: + getMatch(node) + " (needed by "
082: + Arrays.asList(node.getAllRealCallers()) + ")";
083: throw new StrictConflictException(msg);
084: }
085: if (lastNode == null || nodeIsGreater(node, lastNode)) {
086: lastNode = node;
087: }
088: }
089:
090: return Collections.singleton(lastNode);
091: }
092:
093: private boolean nodeIsGreater(IvyNode node, IvyNode lastNode) {
094: return getMatch(node).compareTo(getMatch(lastNode)) > 0;
095: }
096:
097: private boolean matchEquals(IvyNode lastNode, IvyNode node) {
098: return getMatch(lastNode).equals(getMatch(node));
099: }
100:
101: private String getMatch(IvyNode node) {
102: String revision = node.getId().getRevision();
103: Matcher matcher = pattern.matcher(revision);
104: if (matcher.matches()) {
105: String match = matcher.group(1);
106: if (match != null) {
107: return match;
108: }
109: warnOrThrow("First group of pattern: '" + pattern
110: + "' does not match: " + revision + " " + node);
111: } else {
112: warnOrThrow("Pattern: '" + pattern + "' does not match: "
113: + revision + " " + node);
114: }
115: return revision;
116: }
117:
118: private void warnOrThrow(String message) {
119: if (mIgnoreNonMatching) {
120: Message.warn(message);
121: } else {
122: throw new StrictConflictException(message);
123: }
124: }
125: }
|