// Copyright (C) 2013 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.pgm.init; import com.google.gerrit.reviewdb.client.RefNames; import com.google.gerrit.server.config.SitePaths; import com.google.gerrit.server.git.ProjectConfig; import com.google.gerrit.server.git.VersionedMetaData; import com.google.inject.Inject; import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.internal.storage.file.FileRepository; import org.eclipse.jgit.lib.CommitBuilder; import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryCache.FileKey; import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.util.FS; import java.io.File; import java.io.IOException; public class AllProjectsConfig extends VersionedMetaData { private final String project; private final SitePaths site; private final InitFlags flags; private Config cfg; private ObjectId revision; @Inject AllProjectsConfig(AllProjectsNameOnInitProvider allProjects, SitePaths site, InitFlags flags) { this.project = allProjects.get(); this.site = site; this.flags = flags; } @Override protected String getRefName() { return RefNames.REFS_CONFIG; } private File getPath() { File basePath = site.resolve(flags.cfg.getString("gerrit", null, "basePath")); if (basePath == null) { throw new IllegalStateException("gerrit.basePath must be configured"); } return FileKey.resolve(new File(basePath, project), FS.DETECTED); } public Config load() throws IOException, ConfigInvalidException { File path = getPath(); if (path == null) { return null; } Repository repo = new FileRepository(path); try { load(repo); } finally { repo.close(); } return cfg; } @Override protected void onLoad() throws IOException, ConfigInvalidException { cfg = readConfig(ProjectConfig.PROJECT_CONFIG); revision = getRevision(); } @Override protected boolean onSave(CommitBuilder commit) throws IOException, ConfigInvalidException { throw new UnsupportedOperationException(); } void save(String message) throws IOException { save(new PersonIdent("Gerrit Initialization", "init@gerrit"), message); } public void save(String pluginName, String message) throws IOException { save(new PersonIdent(pluginName, pluginName + "@gerrit"), "Update from plugin " + pluginName + ": " + message); } private void save(PersonIdent ident, String msg) throws IOException { File path = getPath(); if (path == null) { throw new IOException("All-Projects does not exist."); } Repository repo = new FileRepository(path); try { inserter = repo.newObjectInserter(); reader = repo.newObjectReader(); try { RevWalk rw = new RevWalk(reader); try { RevTree srcTree = revision != null ? rw.parseTree(revision) : null; newTree = readTree(srcTree); saveConfig(ProjectConfig.PROJECT_CONFIG, cfg); ObjectId res = newTree.writeTree(inserter); if (res.equals(srcTree)) { // If there are no changes to the content, don't create the commit. return; } CommitBuilder commit = new CommitBuilder(); commit.setAuthor(ident); commit.setCommitter(ident); commit.setMessage(msg); commit.setTreeId(res); if (revision != null) { commit.addParentId(revision); } ObjectId newRevision = inserter.insert(commit); updateRef(repo, ident, newRevision, "commit: " + msg); revision = newRevision; } finally { rw.release(); } } finally { if (inserter != null) { inserter.release(); inserter = null; } if (reader != null) { reader.release(); reader = null; } } } finally { repo.close(); } } private void updateRef(Repository repo, PersonIdent ident, ObjectId newRevision, String refLogMsg) throws IOException { RefUpdate ru = repo.updateRef(getRefName()); ru.setRefLogIdent(ident); ru.setNewObjectId(newRevision); ru.setExpectedOldObjectId(revision); ru.setRefLogMessage(refLogMsg, false); RefUpdate.Result r = ru.update(); switch(r) { case FAST_FORWARD: case NEW: case NO_CHANGE: break; default: throw new IOException("Failed to update " + getRefName() + " of " + project + ": " + r.name()); } } }