Browse Source

RefSpecs: allow construction of weird wildcarded RefSpecs

Gerrit's superproject subscription feature uses RefSpecs to formalize
the ACLs of when the superproject subscription feature is allowed.

As this is a slightly different use case than describing a local/remote
pair of refs, we need to be more permissive. Specifically we want to allow:

    refs/heads/*
    refs/heads/*:refs/heads/master
    refs/heads/master:refs/heads/*

Introduce a new constructor, that allows constructing these RefSpecs.

Change-Id: I46c0bea9d876e61eb2c8d50f404b905792bc72b3
Signed-off-by: Stefan Beller <sbeller@google.com>
tags/v4.5.0.201609210915-r
Stefan Beller 7 years ago
parent
commit
a2d3c376a6

+ 25
- 0
org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java View File



import org.eclipse.jgit.lib.ObjectIdRef; import org.eclipse.jgit.lib.ObjectIdRef;
import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.transport.RefSpec.WildcardMode;
import org.junit.Test; import org.junit.Test;


public class RefSpecTest { public class RefSpecTest {
RefSpec a = new RefSpec("refs/heads/*:refs/remotes/origin/*"); RefSpec a = new RefSpec("refs/heads/*:refs/remotes/origin/*");
a.setDestination("refs/remotes/origin/*/*"); a.setDestination("refs/remotes/origin/*/*");
} }

@Test
public void sourceOnlywithWildcard() {
RefSpec a = new RefSpec("refs/heads/*",
WildcardMode.ALLOW_MISMATCH);
assertTrue(a.matchSource("refs/heads/master"));
assertNull(a.getDestination());
}

@Test
public void destinationWithWildcard() {
RefSpec a = new RefSpec("refs/heads/master:refs/heads/*",
WildcardMode.ALLOW_MISMATCH);
assertTrue(a.matchSource("refs/heads/master"));
assertTrue(a.matchDestination("refs/heads/master"));
assertTrue(a.matchDestination("refs/heads/foo"));
}

@Test
public void onlyWildCard() {
RefSpec a = new RefSpec("*", WildcardMode.ALLOW_MISMATCH);
assertTrue(a.matchSource("refs/heads/master"));
assertNull(a.getDestination());
}
} }

+ 1
- 0
org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties View File

invalidCharacterInBase64Data=Invalid character in Base64 data. invalidCharacterInBase64Data=Invalid character in Base64 data.
invalidCommitParentNumber=Invalid commit parent number invalidCommitParentNumber=Invalid commit parent number
invalidEncryption=Invalid encryption invalidEncryption=Invalid encryption
invalidExpandWildcard=ExpandFromSource on a refspec that can have mismatched wildcards does not make sense.
invalidGitdirRef = Invalid .git reference in file ''{0}'' invalidGitdirRef = Invalid .git reference in file ''{0}''
invalidGitType=invalid git type: {0} invalidGitType=invalid git type: {0}
invalidId=Invalid id: {0} invalidId=Invalid id: {0}

+ 1
- 0
org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java View File

/***/ public String invalidCharacterInBase64Data; /***/ public String invalidCharacterInBase64Data;
/***/ public String invalidCommitParentNumber; /***/ public String invalidCommitParentNumber;
/***/ public String invalidEncryption; /***/ public String invalidEncryption;
/***/ public String invalidExpandWildcard;
/***/ public String invalidGitdirRef; /***/ public String invalidGitdirRef;
/***/ public String invalidGitType; /***/ public String invalidGitType;
/***/ public String invalidId; /***/ public String invalidId;

+ 84
- 9
org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java View File

/** Is this specification actually a wildcard match? */ /** Is this specification actually a wildcard match? */
private boolean wildcard; private boolean wildcard;


enum WildcardMode {
REQUIRE_MATCH, ALLOW_MISMATCH
}
/** Whether a wildcard is allowed on one side but not the other. */
private WildcardMode allowMismatchedWildcards;

/** Name of the ref(s) we would copy from. */ /** Name of the ref(s) we would copy from. */
private String srcName; private String srcName;


wildcard = false; wildcard = false;
srcName = Constants.HEAD; srcName = Constants.HEAD;
dstName = null; dstName = null;
allowMismatchedWildcards = WildcardMode.REQUIRE_MATCH;
} }


/** /**
* <li><code>:refs/heads/master</code></li> * <li><code>:refs/heads/master</code></li>
* </ul> * </ul>
* *
* If the wildcard mode allows mismatches, then these ref specs are also
* valid:
* <ul>
* <li><code>refs/heads/*</code></li>
* <li><code>refs/heads/*:refs/heads/master</code></li>
* </ul>
*
* @param spec * @param spec
* string describing the specification. * string describing the specification.
* @param mode
* whether to allow a wildcard on one side without a wildcard on
* the other.
* @throws IllegalArgumentException * @throws IllegalArgumentException
* the specification is invalid. * the specification is invalid.
* @since 4.5
*/ */
public RefSpec(final String spec) {
public RefSpec(String spec, WildcardMode mode) {
this.allowMismatchedWildcards = mode;
String s = spec; String s = spec;
if (s.startsWith("+")) { //$NON-NLS-1$ if (s.startsWith("+")) { //$NON-NLS-1$
force = true; force = true;
final int c = s.lastIndexOf(':'); final int c = s.lastIndexOf(':');
if (c == 0) { if (c == 0) {
s = s.substring(1); s = s.substring(1);
if (isWildcard(s))
throw new IllegalArgumentException(MessageFormat.format(JGitText.get().invalidWildcards, spec));
if (isWildcard(s)) {
wildcard = true;
if (mode == WildcardMode.REQUIRE_MATCH) {
throw new IllegalArgumentException(MessageFormat
.format(JGitText.get().invalidWildcards, spec));
}
}
dstName = checkValid(s); dstName = checkValid(s);
} else if (c > 0) { } else if (c > 0) {
String src = s.substring(0, c); String src = s.substring(0, c);
// Both contain wildcard // Both contain wildcard
wildcard = true; wildcard = true;
} else if (isWildcard(src) || isWildcard(dst)) { } else if (isWildcard(src) || isWildcard(dst)) {
// If either source or destination has wildcard, the other one
// must have as well.
throw new IllegalArgumentException(MessageFormat.format(JGitText.get().invalidWildcards, spec));
wildcard = true;
if (mode == WildcardMode.REQUIRE_MATCH)
throw new IllegalArgumentException(MessageFormat
.format(JGitText.get().invalidWildcards, spec));
} }
srcName = checkValid(src); srcName = checkValid(src);
dstName = checkValid(dst); dstName = checkValid(dst);
} else { } else {
if (isWildcard(s))
throw new IllegalArgumentException(MessageFormat.format(JGitText.get().invalidWildcards, spec));
if (isWildcard(s)) {
if (mode == WildcardMode.REQUIRE_MATCH) {
throw new IllegalArgumentException(MessageFormat
.format(JGitText.get().invalidWildcards, spec));
}
wildcard = true;
}
srcName = checkValid(s); srcName = checkValid(s);
} }
} }


/**
* Parse a ref specification for use during transport operations.
* <p>
* Specifications are typically one of the following forms:
* <ul>
* <li><code>refs/heads/master</code></li>
* <li><code>refs/heads/master:refs/remotes/origin/master</code></li>
* <li><code>refs/heads/*:refs/remotes/origin/*</code></li>
* <li><code>+refs/heads/master</code></li>
* <li><code>+refs/heads/master:refs/remotes/origin/master</code></li>
* <li><code>+refs/heads/*:refs/remotes/origin/*</code></li>
* <li><code>+refs/pull/&#42;/head:refs/remotes/origin/pr/*</code></li>
* <li><code>:refs/heads/master</code></li>
* </ul>
*
* @param spec
* string describing the specification.
* @throws IllegalArgumentException
* the specification is invalid.
*/
public RefSpec(final String spec) {
this(spec, WildcardMode.REQUIRE_MATCH);
}

private RefSpec(final RefSpec p) { private RefSpec(final RefSpec p) {
force = p.isForceUpdate(); force = p.isForceUpdate();
wildcard = p.isWildcard(); wildcard = p.isWildcard();
srcName = p.getSource(); srcName = p.getSource();
dstName = p.getDestination(); dstName = p.getDestination();
allowMismatchedWildcards = p.allowMismatchedWildcards;
} }


/** /**
* @return a new specification expanded from provided ref name. Result * @return a new specification expanded from provided ref name. Result
* specification is wildcard if and only if provided ref name is * specification is wildcard if and only if provided ref name is
* wildcard. * wildcard.
* @throws IllegalStateException
* when the RefSpec was constructed with wildcard mode that
* doesn't require matching wildcards.
*/ */
public RefSpec expandFromSource(final String r) { public RefSpec expandFromSource(final String r) {
if (allowMismatchedWildcards != WildcardMode.REQUIRE_MATCH) {
throw new IllegalStateException(
JGitText.get().invalidExpandWildcard);
}
return isWildcard() ? new RefSpec(this).expandFromSourceImp(r) : this; return isWildcard() ? new RefSpec(this).expandFromSourceImp(r) : this;
} }


* @return a new specification expanded from provided ref name. Result * @return a new specification expanded from provided ref name. Result
* specification is wildcard if and only if provided ref name is * specification is wildcard if and only if provided ref name is
* wildcard. * wildcard.
* @throws IllegalStateException
* when the RefSpec was constructed with wildcard mode that
* doesn't require matching wildcards.
*/ */
public RefSpec expandFromSource(final Ref r) { public RefSpec expandFromSource(final Ref r) {
return expandFromSource(r.getName()); return expandFromSource(r.getName());
* @return a new specification expanded from provided ref name. Result * @return a new specification expanded from provided ref name. Result
* specification is wildcard if and only if provided ref name is * specification is wildcard if and only if provided ref name is
* wildcard. * wildcard.
* @throws IllegalStateException
* when the RefSpec was constructed with wildcard mode that
* doesn't require matching wildcards.
*/ */
public RefSpec expandFromDestination(final String r) { public RefSpec expandFromDestination(final String r) {
if (allowMismatchedWildcards != WildcardMode.REQUIRE_MATCH) {
throw new IllegalStateException(
JGitText.get().invalidExpandWildcard);
}
return isWildcard() ? new RefSpec(this).expandFromDstImp(r) : this; return isWildcard() ? new RefSpec(this).expandFromDstImp(r) : this;
} }


* @return a new specification expanded from provided ref name. Result * @return a new specification expanded from provided ref name. Result
* specification is wildcard if and only if provided ref name is * specification is wildcard if and only if provided ref name is
* wildcard. * wildcard.
* @throws IllegalStateException
* when the RefSpec was constructed with wildcard mode that
* doesn't require matching wildcards.
*/ */
public RefSpec expandFromDestination(final Ref r) { public RefSpec expandFromDestination(final Ref r) {
return expandFromDestination(r.getName()); return expandFromDestination(r.getName());
private boolean match(final String name, final String s) { private boolean match(final String name, final String s) {
if (s == null) if (s == null)
return false; return false;
if (isWildcard()) {
if (isWildcard(s)) {
int wildcardIndex = s.indexOf('*'); int wildcardIndex = s.indexOf('*');
String prefix = s.substring(0, wildcardIndex); String prefix = s.substring(0, wildcardIndex);
String suffix = s.substring(wildcardIndex + 1); String suffix = s.substring(wildcardIndex + 1);

Loading…
Cancel
Save