* stable-5.6: Bump required Bazel version to 2.1.0 Upgrade bazlets to the latest master revision Change the wildcard import to explicit ones. Prepare 5.3.8-SNAPSHOT builds JGit v5.3.7.202002110540-r Prepare 5.1.14-SNAPSHOT builds JGit v5.1.13.202002110435-r reftable: don't check deadline on the first try reftable: clarify comment reftable: clear cache on full compaction reftable: remove outdated comment reftable: clarify that LogCursor may return a null ReflogEntry Restore behavior of CloneCommand Change-Id: Ifc30b40ef58d5cda4b1cf3694488424beb182cfc Signed-off-by: David Pursehouse <david.pursehouse@gmail.com>tags/v5.7.0.202002241735-m3
1.0.0 | |||||
2.1.0 |
load("//tools:bazlets.bzl", "load_bazlets") | load("//tools:bazlets.bzl", "load_bazlets") | ||||
load_bazlets(commit = "09a035e98077dce549d5f6a7472d06c4b8f792d2") | |||||
load_bazlets(commit = "f30a992da9fc855dce819875afb59f9dd6f860cd") | |||||
load( | load( | ||||
"@com_googlesource_gerrit_bazlets//tools:maven_jar.bzl", | "@com_googlesource_gerrit_bazlets//tools:maven_jar.bzl", |
Git git2 = command.call(); | Git git2 = command.call(); | ||||
addRepoToClose(git2.getRepository()); | addRepoToClose(git2.getRepository()); | ||||
assertNotNull(git2); | assertNotNull(git2); | ||||
assertTrue(git2.getRepository().isBare()); | |||||
assertNotNull(git2.getRepository().resolve("tag-for-blob")); | assertNotNull(git2.getRepository().resolve("tag-for-blob")); | ||||
assertNotNull(git2.getRepository().resolve("tag-initial")); | assertNotNull(git2.getRepository().resolve("tag-initial")); | ||||
assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master"); | assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master"); | ||||
specs.get(0)); | specs.get(0)); | ||||
} | } | ||||
@Test | |||||
public void testCloneRepositoryAllBranchesTakesPreference() | |||||
throws Exception { | |||||
File directory = createTempDirectory( | |||||
"testCloneRepositoryAllBranchesTakesPreference"); | |||||
CloneCommand command = Git.cloneRepository(); | |||||
command.setCloneAllBranches(true); | |||||
command.setBranchesToClone( | |||||
Collections.singletonList("refs/heads/test")); | |||||
command.setDirectory(directory); | |||||
command.setURI(fileUri()); | |||||
Git git2 = command.call(); | |||||
addRepoToClose(git2.getRepository()); | |||||
assertNotNull(git2); | |||||
assertEquals(git2.getRepository().getFullBranch(), "refs/heads/test"); | |||||
// Expect both remote branches to exist; setCloneAllBranches(true) | |||||
// should override any setBranchesToClone(). | |||||
assertNotNull( | |||||
git2.getRepository().resolve("refs/remotes/origin/master")); | |||||
assertNotNull(git2.getRepository().resolve("refs/remotes/origin/test")); | |||||
RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(), | |||||
Constants.DEFAULT_REMOTE_NAME); | |||||
List<RefSpec> specs = cfg.getFetchRefSpecs(); | |||||
assertEquals(1, specs.size()); | |||||
assertEquals(new RefSpec("+refs/heads/*:refs/remotes/origin/*"), | |||||
specs.get(0)); | |||||
} | |||||
@Test | |||||
public void testCloneRepositoryAllBranchesIndependent() throws Exception { | |||||
File directory = createTempDirectory( | |||||
"testCloneRepositoryAllBranchesIndependent"); | |||||
CloneCommand command = Git.cloneRepository(); | |||||
command.setCloneAllBranches(true); | |||||
command.setBranchesToClone( | |||||
Collections.singletonList("refs/heads/test")); | |||||
command.setCloneAllBranches(false); | |||||
command.setDirectory(directory); | |||||
command.setURI(fileUri()); | |||||
Git git2 = command.call(); | |||||
addRepoToClose(git2.getRepository()); | |||||
assertNotNull(git2); | |||||
assertEquals(git2.getRepository().getFullBranch(), "refs/heads/test"); | |||||
// Expect only the test branch; allBranches was re-set to false | |||||
assertNull(git2.getRepository().resolve("refs/remotes/origin/master")); | |||||
assertNotNull(git2.getRepository().resolve("refs/remotes/origin/test")); | |||||
RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(), | |||||
Constants.DEFAULT_REMOTE_NAME); | |||||
List<RefSpec> specs = cfg.getFetchRefSpecs(); | |||||
assertEquals(1, specs.size()); | |||||
assertEquals(new RefSpec("+refs/heads/test:refs/remotes/origin/test"), | |||||
specs.get(0)); | |||||
} | |||||
public static String allRefNames(List<Ref> refs) { | public static String allRefNames(List<Ref> refs) { | ||||
StringBuilder sb = new StringBuilder(); | StringBuilder sb = new StringBuilder(); | ||||
for (Ref f : refs) { | for (Ref f : refs) { |
import java.io.File; | import java.io.File; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.security.SecureRandom; | |||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.List; | import java.util.List; | ||||
assertEquals(RefUpdate.Result.LOCK_FAILURE, rename.rename()); | assertEquals(RefUpdate.Result.LOCK_FAILURE, rename.rename()); | ||||
} | } | ||||
@Test | |||||
public void compactFully() throws Exception { | |||||
FileReftableDatabase refDb = (FileReftableDatabase) db.getRefDatabase(); | |||||
PersonIdent person = new PersonIdent("jane", "jane@invalid"); | |||||
ObjectId aId = db.exactRef("refs/heads/a").getObjectId(); | |||||
ObjectId bId = db.exactRef("refs/heads/b").getObjectId(); | |||||
SecureRandom random = new SecureRandom(); | |||||
List<String> strs = new ArrayList<>(); | |||||
for (int i = 0; i < 1024; i++) { | |||||
strs.add(String.format("%02x", | |||||
Integer.valueOf(random.nextInt(256)))); | |||||
} | |||||
String randomStr = String.join("", strs); | |||||
String refName = "branch"; | |||||
for (long i = 0; i < 2; i++) { | |||||
RefUpdate ru = refDb.newUpdate(refName, false); | |||||
ru.setNewObjectId(i % 2 == 0 ? aId : bId); | |||||
ru.setForceUpdate(true); | |||||
// Only write a large string in the first table, so it becomes much larger | |||||
// than the second, and the result is not autocompacted. | |||||
ru.setRefLogMessage(i == 0 ? randomStr : "short", false); | |||||
ru.setRefLogIdent(person); | |||||
RefUpdate.Result res = ru.update(); | |||||
assertTrue(res == Result.NEW || res == FORCED); | |||||
} | |||||
assertEquals(refDb.exactRef(refName).getObjectId(), bId); | |||||
assertTrue(randomStr.equals(refDb.getReflogReader(refName).getReverseEntry(1).getComment())); | |||||
refDb.compactFully(); | |||||
assertEquals(refDb.exactRef(refName).getObjectId(), bId); | |||||
assertTrue(randomStr.equals(refDb.getReflogReader(refName).getReverseEntry(1).getComment())); | |||||
} | |||||
@Test | @Test | ||||
public void reftableRefsStorageClass() throws IOException { | public void reftableRefsStorageClass() throws IOException { | ||||
Ref b = db.exactRef("refs/heads/b"); | Ref b = db.exactRef("refs/heads/b"); |
private ProgressMonitor monitor = NullProgressMonitor.INSTANCE; | private ProgressMonitor monitor = NullProgressMonitor.INSTANCE; | ||||
private FETCH_TYPE fetchType = FETCH_TYPE.ALL_BRANCHES; | |||||
private boolean cloneAllBranches; | |||||
private boolean mirror; | |||||
private boolean cloneSubmodules; | private boolean cloneSubmodules; | ||||
private boolean gitDirExistsInitially; | private boolean gitDirExistsInitially; | ||||
private FETCH_TYPE fetchType; | |||||
private enum FETCH_TYPE { | private enum FETCH_TYPE { | ||||
MULTIPLE_BRANCHES, ALL_BRANCHES, MIRROR | MULTIPLE_BRANCHES, ALL_BRANCHES, MIRROR | ||||
} | } | ||||
throw new InvalidRemoteException( | throw new InvalidRemoteException( | ||||
MessageFormat.format(JGitText.get().invalidURL, uri)); | MessageFormat.format(JGitText.get().invalidURL, uri)); | ||||
} | } | ||||
setFetchType(); | |||||
@SuppressWarnings("resource") // Closed by caller | @SuppressWarnings("resource") // Closed by caller | ||||
Repository repository = init(); | Repository repository = init(); | ||||
FetchResult fetchResult = null; | FetchResult fetchResult = null; | ||||
return new Git(repository, true); | return new Git(repository, true); | ||||
} | } | ||||
private void setFetchType() { | |||||
if (mirror) { | |||||
fetchType = FETCH_TYPE.MIRROR; | |||||
setBare(true); | |||||
} else if (cloneAllBranches) { | |||||
fetchType = FETCH_TYPE.ALL_BRANCHES; | |||||
} else if (branchesToClone != null && !branchesToClone.isEmpty()) { | |||||
fetchType = FETCH_TYPE.MULTIPLE_BRANCHES; | |||||
} else { | |||||
// Default: neither mirror nor all nor specific refs given | |||||
fetchType = FETCH_TYPE.ALL_BRANCHES; | |||||
} | |||||
} | |||||
private static boolean isNonEmptyDirectory(File dir) { | private static boolean isNonEmptyDirectory(File dir) { | ||||
if (dir != null && dir.exists()) { | if (dir != null && dir.exists()) { | ||||
File[] files = dir.listFiles(); | File[] files = dir.listFiles(); | ||||
* @return {@code this} | * @return {@code this} | ||||
*/ | */ | ||||
public CloneCommand setCloneAllBranches(boolean cloneAllBranches) { | public CloneCommand setCloneAllBranches(boolean cloneAllBranches) { | ||||
this.fetchType = cloneAllBranches ? FETCH_TYPE.ALL_BRANCHES | |||||
: this.fetchType; | |||||
this.cloneAllBranches = cloneAllBranches; | |||||
return this; | return this; | ||||
} | } | ||||
* @since 5.6 | * @since 5.6 | ||||
*/ | */ | ||||
public CloneCommand setMirror(boolean mirror) { | public CloneCommand setMirror(boolean mirror) { | ||||
if (mirror) { | |||||
this.fetchType = FETCH_TYPE.MIRROR; | |||||
setBare(true); | |||||
} | |||||
this.mirror = mirror; | |||||
return this; | return this; | ||||
} | } | ||||
* Set the branches or tags to clone. | * Set the branches or tags to clone. | ||||
* <p> | * <p> | ||||
* This is ignored if {@link #setCloneAllBranches(boolean) | * This is ignored if {@link #setCloneAllBranches(boolean) | ||||
* setCloneAllBranches(true)} is used. If {@code branchesToClone} is | |||||
* {@code null} or empty, it's also ignored and all branches will be cloned. | |||||
* setCloneAllBranches(true)} or {@link #setMirror(boolean) setMirror(true)} | |||||
* is used. If {@code branchesToClone} is {@code null} or empty, it's also | |||||
* ignored. | |||||
* </p> | * </p> | ||||
* | * | ||||
* @param branchesToClone | * @param branchesToClone | ||||
* @return {@code this} | * @return {@code this} | ||||
*/ | */ | ||||
public CloneCommand setBranchesToClone(Collection<String> branchesToClone) { | public CloneCommand setBranchesToClone(Collection<String> branchesToClone) { | ||||
if (branchesToClone == null || branchesToClone.isEmpty()) { | |||||
// fallback to default | |||||
fetchType = FETCH_TYPE.ALL_BRANCHES; | |||||
} else { | |||||
this.fetchType = FETCH_TYPE.MULTIPLE_BRANCHES; | |||||
this.branchesToClone = branchesToClone; | |||||
} | |||||
this.branchesToClone = branchesToClone; | |||||
return this; | return this; | ||||
} | } | ||||
reftableDatabase.getLock().lock(); | reftableDatabase.getLock().lock(); | ||||
try { | try { | ||||
reftableStack.compactFully(); | reftableStack.compactFully(); | ||||
reftableDatabase.clearCache(); | |||||
} finally { | } finally { | ||||
reftableDatabase.getLock().unlock(); | reftableDatabase.getLock().unlock(); | ||||
} | } |
long max = 1000; | long max = 1000; | ||||
long delay = 0; | long delay = 0; | ||||
boolean success = false; | boolean success = false; | ||||
while (System.currentTimeMillis() < deadline) { | |||||
// Don't check deadline for the first 3 retries, so we can step with a | |||||
// debugger without worrying about deadlines. | |||||
int tries = 0; | |||||
while (tries < 3 || System.currentTimeMillis() < deadline) { | |||||
List<String> names = readTableNames(); | List<String> names = readTableNames(); | ||||
tries++; | |||||
try { | try { | ||||
reloadOnce(names); | reloadOnce(names); | ||||
success = true; | success = true; | ||||
} | } | ||||
if (!success) { | if (!success) { | ||||
// TODO: should reexamine the 'refs' file to see if it was the same | |||||
// if it didn't change, then we must have corruption. If it did, | |||||
// retry. | |||||
throw new LockFailedException(stackPath); | throw new LockFailedException(stackPath); | ||||
} | } | ||||
* | * | ||||
* @param w | * @param w | ||||
* writer to write data to a reftable under construction | * writer to write data to a reftable under construction | ||||
* @return true if the transaction. | |||||
* @return true if the transaction was successful. | |||||
* @throws IOException | * @throws IOException | ||||
* on I/O problems | * on I/O problems | ||||
*/ | */ |
import java.io.IOException; | import java.io.IOException; | ||||
import org.eclipse.jgit.annotations.Nullable; | |||||
import org.eclipse.jgit.lib.ReflogEntry; | import org.eclipse.jgit.lib.ReflogEntry; | ||||
/** | /** | ||||
/** | /** | ||||
* Get current log entry. | * Get current log entry. | ||||
* | * | ||||
* @return current log entry. | |||||
* @return current log entry. Maybe null if we are producing deletions. | |||||
*/ | */ | ||||
@Nullable | |||||
public abstract ReflogEntry getReflogEntry(); | public abstract ReflogEntry getReflogEntry(); | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ |