// Copyright (C) 2011 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 com.google.gerrit.common.data.AccessSection; import com.google.gerrit.common.data.GlobalCapability; import com.google.gerrit.common.data.PermissionRule; import com.google.gerrit.common.data.PermissionRule.Action; import com.google.gerrit.reviewdb.client.AccountGroup; import com.google.gerrit.reviewdb.client.AccountGroupName; import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.SystemConfig; import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.server.GerritPersonIdent; import com.google.gerrit.server.config.AllProjectsNameProvider; import com.google.gerrit.server.config.SitePaths; import com.google.gerrit.server.extensions.events.GitReferenceUpdated; import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.git.MetaDataUpdate; import com.google.gerrit.server.git.ProjectConfig; import com.google.gwtorm.jdbc.JdbcSchema; import com.google.gwtorm.server.OrmException; import com.google.inject.Inject; import com.google.inject.Provider; import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.storage.file.FileBasedConfig; import org.eclipse.jgit.util.FS; import java.io.IOException; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Collections; public class Schema_57 extends SchemaVersion { private final SitePaths site; private final GitRepositoryManager mgr; private final PersonIdent serverUser; @Inject Schema_57(Provider<Schema_56> prior, SitePaths site, GitRepositoryManager mgr, @GerritPersonIdent PersonIdent serverUser) { super(prior); this.site = site; this.mgr = mgr; this.serverUser = serverUser; } @Override protected void migrateData(ReviewDb db, UpdateUI ui) throws OrmException { SystemConfig sc = db.systemConfig().get(new SystemConfig.Key()); Project.NameKey allProjects = sc.wildProjectName; FileBasedConfig cfg = new FileBasedConfig(site.gerrit_config, FS.DETECTED); boolean cfgDirty = false; try { cfg.load(); } catch (ConfigInvalidException err) { throw new OrmException("Cannot read " + site.gerrit_config, err); } catch (IOException err) { throw new OrmException("Cannot read " + site.gerrit_config, err); } if (!allProjects.get().equals(AllProjectsNameProvider.DEFAULT)) { ui.message("Setting gerrit.allProjects = " + allProjects.get()); cfg.setString("gerrit", null, "allProjects", allProjects.get()); cfgDirty = true; } try { Repository git = mgr.openRepository(allProjects); try { MetaDataUpdate md = new MetaDataUpdate(GitReferenceUpdated.DISABLED, allProjects, git); md.getCommitBuilder().setAuthor(serverUser); md.getCommitBuilder().setCommitter(serverUser); ProjectConfig config = ProjectConfig.read(md); AccessSection cap = config.getAccessSection(AccessSection.GLOBAL_CAPABILITIES, true); // Move the Administrators group reference to All-Projects. cap.getPermission(GlobalCapability.ADMINISTRATE_SERVER, true) .add(new PermissionRule(config.resolve(db.accountGroups().get(sc.adminGroupId)))); // Move the repository.*.createGroup to Create Project. String[] createGroupList = cfg.getStringList("repository", "*", "createGroup"); // Prepare the account_group_includes query PreparedStatement stmt = ((JdbcSchema) db).getConnection(). prepareStatement("SELECT COUNT(1) FROM account_group_includes WHERE group_id = ?"); boolean isAccountGroupEmpty = false; try { stmt.setInt(1, sc.batchUsersGroupId.get()); ResultSet rs = stmt.executeQuery(); if (rs.next()) { isAccountGroupEmpty = rs.getInt(1) == 0; } } finally { stmt.close(); } for (String name : createGroupList) { AccountGroup.NameKey key = new AccountGroup.NameKey(name); AccountGroupName groupName = db.accountGroupNames().get(key); if (groupName == null) { continue; } AccountGroup group = db.accountGroups().get(groupName.getId()); if (group == null) { continue; } cap.getPermission(GlobalCapability.CREATE_PROJECT, true) .add(new PermissionRule(config.resolve(group))); } if (createGroupList.length != 0) { ui.message("Moved repository.*.createGroup to 'Create Project' capability"); cfg.unset("repository", "*", "createGroup"); cfgDirty = true; } AccountGroup batch = db.accountGroups().get(sc.batchUsersGroupId); if (batch != null && db.accountGroupMembers().byGroup(sc.batchUsersGroupId).toList().isEmpty() && !isAccountGroupEmpty) { // If the batch user group is not used, delete it. // db.accountGroups().delete(Collections.singleton(batch)); AccountGroupName name = db.accountGroupNames().get(batch.getNameKey()); if (name != null) { db.accountGroupNames().delete(Collections.singleton(name)); } } else if (batch != null) { cap.getPermission(GlobalCapability.PRIORITY, true) .getRule(config.resolve(batch), true) .setAction(Action.BATCH); } md.setMessage("Upgrade to Gerrit Code Review schema 57\n"); config.commit(md); } catch (SQLException err) { throw new OrmException( "Cannot read account_group_includes", err); } finally { git.close(); } } catch (ConfigInvalidException err) { throw new OrmException("Cannot read " + allProjects, err); } catch (IOException err) { throw new OrmException("Cannot update " + allProjects, err); } if (cfgDirty) { try { cfg.save(); } catch (IOException err) { throw new OrmException("Cannot update " + site.gerrit_config, err); } } // We cannot set the columns to NULL, so use 0 and a DELETED tag. sc.adminGroupId = new AccountGroup.Id(0); sc.adminGroupUUID = new AccountGroup.UUID("DELETED"); sc.anonymousGroupId = new AccountGroup.Id(0); sc.registeredGroupId = new AccountGroup.Id(0); sc.wildProjectName = new Project.NameKey("DELETED"); sc.ownerGroupId = new AccountGroup.Id(0); sc.batchUsersGroupId = new AccountGroup.Id(0); sc.batchUsersGroupUUID = new AccountGroup.UUID("DELETED"); sc.registerEmailPrivateKey = "DELETED"; db.systemConfig().update(Collections.singleton(sc)); } }