Write reflog for refs/meta/config changes
A reflog is currently only written for branches under refs/heads/. The refs/meta/config branch has no reflog, but it contains important information such as access rights, and hence it should have a reflog as well. A problem with getting a reflog for refs/meta/config is that JGit (and also native Git) is not creating a reflog for this branch even if core.logAllRefUpdates is set (see section 'core.logAllRefUpdates' in [1]). To make JGit write the reflog for the refs/meta/config branch the reflog file for this branch must already exist. This is why the LocalDiskRepositoryManager now creates an empty reflog file for the refs/meta/config branch when a new repository is created. In addition this change contains a schema migration that creates the reflog file for the refs/meta/config branch in all existing repositories, so that further updates get a reflog entry. This migration is only possible if the repositories are stored on local disk and is not executed if a GitRepositoryManager other than LocalDiskRepositoryManager is used. [1] https://www.kernel.org/pub/software/scm/git/docs/git-config.html#_variables Change-Id: I9b6354cfa51263db10fb99e329b397b86f40156d Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
This commit is contained in:
@@ -20,6 +20,7 @@ import com.google.common.base.MoreObjects;
|
|||||||
import com.google.gerrit.extensions.events.LifecycleListener;
|
import com.google.gerrit.extensions.events.LifecycleListener;
|
||||||
import com.google.gerrit.lifecycle.LifecycleModule;
|
import com.google.gerrit.lifecycle.LifecycleModule;
|
||||||
import com.google.gerrit.reviewdb.client.Project;
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
|
import com.google.gerrit.reviewdb.client.RefNames;
|
||||||
import com.google.gerrit.server.config.GerritServerConfig;
|
import com.google.gerrit.server.config.GerritServerConfig;
|
||||||
import com.google.gerrit.server.config.SitePaths;
|
import com.google.gerrit.server.config.SitePaths;
|
||||||
import com.google.gerrit.server.notedb.NotesMigration;
|
import com.google.gerrit.server.notedb.NotesMigration;
|
||||||
@@ -246,6 +247,18 @@ public class LocalDiskRepositoryManager implements GitRepositoryManager {
|
|||||||
null, ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, true);
|
null, ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, true);
|
||||||
config.save();
|
config.save();
|
||||||
|
|
||||||
|
// JGit only writes to the reflog for refs/meta/config if the log file
|
||||||
|
// already exists.
|
||||||
|
//
|
||||||
|
File metaConfigLog =
|
||||||
|
new File(db.getDirectory(), "logs/" + RefNames.REFS_CONFIG);
|
||||||
|
if (!metaConfigLog.getParentFile().mkdirs()
|
||||||
|
|| !metaConfigLog.createNewFile()) {
|
||||||
|
log.error(String.format(
|
||||||
|
"Failed to create ref log for %s in repository %s",
|
||||||
|
RefNames.REFS_CONFIG, name));
|
||||||
|
}
|
||||||
|
|
||||||
onCreateProject(name);
|
onCreateProject(name);
|
||||||
|
|
||||||
return db;
|
return db;
|
||||||
|
|||||||
@@ -45,7 +45,9 @@ import org.eclipse.jgit.transport.ReceiveCommand;
|
|||||||
import org.eclipse.jgit.treewalk.TreeWalk;
|
import org.eclipse.jgit.treewalk.TreeWalk;
|
||||||
import org.eclipse.jgit.util.RawParseUtils;
|
import org.eclipse.jgit.util.RawParseUtils;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -342,7 +344,12 @@ public abstract class VersionedMetaData {
|
|||||||
RefUpdate ru = db.updateRef(refName);
|
RefUpdate ru = db.updateRef(refName);
|
||||||
ru.setExpectedOldObjectId(oldId);
|
ru.setExpectedOldObjectId(oldId);
|
||||||
ru.setNewObjectId(src);
|
ru.setNewObjectId(src);
|
||||||
ru.disableRefLog();
|
ru.setRefLogIdent(update.getCommitBuilder().getAuthor());
|
||||||
|
try (BufferedReader reader = new BufferedReader(
|
||||||
|
new StringReader(update.getCommitBuilder().getMessage()))) {
|
||||||
|
// read the subject line and use it as reflog message
|
||||||
|
ru.setRefLogMessage("commit: " + reader.readLine(), true);
|
||||||
|
}
|
||||||
inserter.flush();
|
inserter.flush();
|
||||||
RefUpdate.Result result = ru.update();
|
RefUpdate.Result result = ru.update();
|
||||||
switch (result) {
|
switch (result) {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import java.util.List;
|
|||||||
/** A version of the database schema. */
|
/** A version of the database schema. */
|
||||||
public abstract class SchemaVersion {
|
public abstract class SchemaVersion {
|
||||||
/** The current schema version. */
|
/** The current schema version. */
|
||||||
public static final Class<Schema_105> C = Schema_105.class;
|
public static final Class<Schema_106> C = Schema_106.class;
|
||||||
|
|
||||||
public static int getBinaryVersion() {
|
public static int getBinaryVersion() {
|
||||||
return guessVersion(C);
|
return guessVersion(C);
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
// Copyright (C) 2015 The Android Open Source Project
|
||||||
|
//
|
||||||
|
// Licensed 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.
|
||||||
|
|
||||||
|
package com.google.gerrit.server.schema;
|
||||||
|
|
||||||
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
|
|
||||||
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
|
import com.google.gerrit.reviewdb.client.RefNames;
|
||||||
|
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||||
|
import com.google.gerrit.server.GerritPersonIdent;
|
||||||
|
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||||
|
import com.google.gerrit.server.git.LocalDiskRepositoryManager;
|
||||||
|
import com.google.gwtorm.server.OrmException;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Provider;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
|
import org.eclipse.jgit.lib.PersonIdent;
|
||||||
|
import org.eclipse.jgit.lib.Repository;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.util.SortedSet;
|
||||||
|
|
||||||
|
public class Schema_106 extends SchemaVersion {
|
||||||
|
private final GitRepositoryManager repoManager;
|
||||||
|
private final PersonIdent serverUser;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
Schema_106(Provider<Schema_105> prior,
|
||||||
|
GitRepositoryManager repoManager,
|
||||||
|
@GerritPersonIdent PersonIdent serverUser) {
|
||||||
|
super(prior);
|
||||||
|
this.repoManager = repoManager;
|
||||||
|
this.serverUser = serverUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void migrateData(ReviewDb db, UpdateUI ui) throws OrmException {
|
||||||
|
if (!(repoManager instanceof LocalDiskRepositoryManager)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.message("listing all repositories ...");
|
||||||
|
SortedSet<Project.NameKey> repoList = repoManager.list();
|
||||||
|
ui.message("done");
|
||||||
|
|
||||||
|
ui.message(String.format("creating reflog files for %s branches ...",
|
||||||
|
RefNames.REFS_CONFIG));
|
||||||
|
for (Project.NameKey project : repoList) {
|
||||||
|
try {
|
||||||
|
Repository repo = repoManager.openRepository(project);
|
||||||
|
try {
|
||||||
|
File metaConfigLog =
|
||||||
|
new File(repo.getDirectory(), "logs/" + RefNames.REFS_CONFIG);
|
||||||
|
if (metaConfigLog.exists()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!metaConfigLog.getParentFile().mkdirs()
|
||||||
|
|| !metaConfigLog.createNewFile()) {
|
||||||
|
throw new IOException(String.format(
|
||||||
|
"Failed to create reflog for %s in repository %s",
|
||||||
|
RefNames.REFS_CONFIG, project));
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectId metaConfigId = repo.resolve(RefNames.REFS_CONFIG);
|
||||||
|
if (metaConfigId != null) {
|
||||||
|
try (PrintWriter writer =
|
||||||
|
new PrintWriter(metaConfigLog, UTF_8.name())) {
|
||||||
|
writer.print(ObjectId.zeroId().name());
|
||||||
|
writer.print(" ");
|
||||||
|
writer.print(metaConfigId.name());
|
||||||
|
writer.print(" ");
|
||||||
|
writer.print(serverUser.toExternalString());
|
||||||
|
writer.print("\t");
|
||||||
|
writer.print("create reflog");
|
||||||
|
writer.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
repo.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
ui.message(String.format("ERROR: Failed to create reflog file for the"
|
||||||
|
+ " %s branch in repository %s", RefNames.REFS_CONFIG, project.get()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ui.message("done");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user