diff options
Diffstat (limited to 'gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_53.java')
-rw-r--r-- | gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_53.java | 481 |
1 files changed, 481 insertions, 0 deletions
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_53.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_53.java new file mode 100644 index 0000000000..d49b34e917 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_53.java @@ -0,0 +1,481 @@ +// Copyright (C) 2010 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 com.google.gerrit.common.data.Permission.CREATE; +import static com.google.gerrit.common.data.Permission.FORGE_AUTHOR; +import static com.google.gerrit.common.data.Permission.FORGE_COMMITTER; +import static com.google.gerrit.common.data.Permission.FORGE_SERVER; +import static com.google.gerrit.common.data.Permission.LABEL; +import static com.google.gerrit.common.data.Permission.OWNER; +import static com.google.gerrit.common.data.Permission.PUSH; +import static com.google.gerrit.common.data.Permission.PUSH_MERGE; +import static com.google.gerrit.common.data.Permission.PUSH_TAG; +import static com.google.gerrit.common.data.Permission.READ; +import static com.google.gerrit.common.data.Permission.SUBMIT; + +import com.google.gerrit.common.data.AccessSection; +import com.google.gerrit.common.data.GroupReference; +import com.google.gerrit.common.data.Permission; +import com.google.gerrit.common.data.PermissionRule; +import com.google.gerrit.reviewdb.client.AccountGroup; +import com.google.gerrit.reviewdb.client.ApprovalCategory; +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.account.GroupUUID; +import com.google.gerrit.server.git.GitRepositoryManager; +import com.google.gerrit.server.git.MetaDataUpdate; +import com.google.gerrit.server.git.NoReplication; +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.errors.RepositoryNotFoundException; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.Repository; + +import java.io.IOException; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +class Schema_53 extends SchemaVersion { + private final GitRepositoryManager mgr; + private final PersonIdent serverUser; + + private SystemConfig systemConfig; + private Map<AccountGroup.Id, GroupReference> groupMap; + private Map<ApprovalCategory.Id, ApprovalCategory> categoryMap; + private GroupReference projectOwners; + + private Map<Project.NameKey, Project.NameKey> parentsByProject; + private Map<Project.NameKey, List<OldRefRight>> rightsByProject; + + private final String OLD_SUBMIT = "SUBM"; + private final String OLD_READ = "READ"; + private final String OLD_OWN = "OWN"; + private final String OLD_PUSH_TAG = "pTAG"; + private final String OLD_PUSH_HEAD = "pHD"; + private final String OLD_FORGE_IDENTITY = "FORG"; + + @Inject + Schema_53(Provider<Schema_52> prior, GitRepositoryManager mgr, + @GerritPersonIdent PersonIdent serverUser) { + super(prior); + this.mgr = mgr; + this.serverUser = serverUser; + } + + @Override + protected void migrateData(ReviewDb db, UpdateUI ui) throws OrmException, + SQLException { + systemConfig = db.systemConfig().get(new SystemConfig.Key()); + categoryMap = db.approvalCategories().toMap(db.approvalCategories().all()); + + assignGroupUUIDs(db); + readOldRefRights(db); + readProjectParents(db); + exportProjectConfig(db); + + deleteActionCategories(db); + } + + private void deleteActionCategories(ReviewDb db) throws OrmException { + List<ApprovalCategory> delete = new ArrayList<ApprovalCategory>(); + for (ApprovalCategory category : categoryMap.values()) { + if (category.getPosition() < 0) { + delete.add(category); + } + } + db.approvalCategories().delete(delete); + } + + private void assignGroupUUIDs(ReviewDb db) throws OrmException { + groupMap = new HashMap<AccountGroup.Id, GroupReference>(); + List<AccountGroup> groups = db.accountGroups().all().toList(); + for (AccountGroup g : groups) { + if (g.getId().equals(systemConfig.ownerGroupId)) { + g.setGroupUUID(AccountGroup.PROJECT_OWNERS); + projectOwners = GroupReference.forGroup(g); + + } else if (g.getId().equals(systemConfig.anonymousGroupId)) { + g.setGroupUUID(AccountGroup.ANONYMOUS_USERS); + + } else if (g.getId().equals(systemConfig.registeredGroupId)) { + g.setGroupUUID(AccountGroup.REGISTERED_USERS); + + } else { + g.setGroupUUID(GroupUUID.make(g.getName(), serverUser)); + } + groupMap.put(g.getId(), GroupReference.forGroup(g)); + } + db.accountGroups().update(groups); + + systemConfig.adminGroupUUID = toUUID(systemConfig.adminGroupId); + systemConfig.batchUsersGroupUUID = toUUID(systemConfig.batchUsersGroupId); + db.systemConfig().update(Collections.singleton(systemConfig)); + } + + private AccountGroup.UUID toUUID(AccountGroup.Id id) { + return groupMap.get(id).getUUID(); + } + + private void exportProjectConfig(ReviewDb db) throws OrmException, + SQLException { + Statement stmt = ((JdbcSchema) db).getConnection().createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM projects ORDER BY name"); + while (rs.next()) { + final String name = rs.getString("name"); + final Project.NameKey nameKey = new Project.NameKey(name); + + Repository git; + try { + git = mgr.openRepository(nameKey); + } catch (RepositoryNotFoundException notFound) { + // A repository may be missing if this project existed only to store + // inheritable permissions. For example 'All-Projects'. + try { + git = mgr.createRepository(nameKey); + } catch (RepositoryNotFoundException err) { + throw new OrmException("Cannot create repository " + name, err); + } + } + try { + MetaDataUpdate md = + new MetaDataUpdate(new NoReplication(), nameKey, git); + md.getCommitBuilder().setAuthor(serverUser); + md.getCommitBuilder().setCommitter(serverUser); + + ProjectConfig config = ProjectConfig.read(md); + loadProject(rs, config.getProject()); + config.getAccessSections().clear(); + convertRights(config); + + // Grant out read on the config branch by default. + // + if (config.getProject().getNameKey().equals(systemConfig.wildProjectName)) { + AccessSection meta = config.getAccessSection(GitRepositoryManager.REF_CONFIG, true); + Permission read = meta.getPermission(READ, true); + read.getRule(config.resolve(projectOwners), true); + } + + md.setMessage("Import project configuration from SQL\n"); + if (!config.commit(md)) { + throw new OrmException("Cannot export project " + name); + } + } catch (ConfigInvalidException err) { + throw new OrmException("Cannot read project " + name, err); + } catch (IOException err) { + throw new OrmException("Cannot export project " + name, err); + } finally { + git.close(); + } + } + rs.close(); + stmt.close(); + } + + private void loadProject(ResultSet rs, Project project) throws SQLException, + OrmException { + project.setDescription(rs.getString("description")); + project.setUseContributorAgreements("Y".equals(rs + .getString("use_contributor_agreements"))); + + switch (rs.getString("submit_type").charAt(0)) { + case 'F': + project.setSubmitType(Project.SubmitType.FAST_FORWARD_ONLY); + break; + case 'M': + project.setSubmitType(Project.SubmitType.MERGE_IF_NECESSARY); + break; + case 'A': + project.setSubmitType(Project.SubmitType.MERGE_ALWAYS); + break; + case 'C': + project.setSubmitType(Project.SubmitType.CHERRY_PICK); + break; + default: + throw new OrmException("Unsupported submit_type=" + + rs.getString("submit_type") + " on project " + project.getName()); + } + + project.setUseSignedOffBy("Y".equals(rs.getString("use_signed_off_by"))); + project.setRequireChangeID("Y".equals(rs.getString("require_change_id"))); + project.setUseContentMerge("Y".equals(rs.getString("use_content_merge"))); + project.setParentName(rs.getString("parent_name")); + } + + private void readOldRefRights(ReviewDb db) throws SQLException { + rightsByProject = new HashMap<Project.NameKey, List<OldRefRight>>(); + + Statement stmt = ((JdbcSchema) db).getConnection().createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM ref_rights"); + while (rs.next()) { + OldRefRight right = new OldRefRight(rs); + if (right.group == null || right.category == null) { + continue; + } + + List<OldRefRight> list; + + list = rightsByProject.get(right.project); + if (list == null) { + list = new ArrayList<OldRefRight>(); + rightsByProject.put(right.project, list); + } + list.add(right); + } + rs.close(); + stmt.close(); + } + + private void readProjectParents(ReviewDb db) throws SQLException { + parentsByProject = new HashMap<Project.NameKey, Project.NameKey>(); + Statement stmt = ((JdbcSchema) db).getConnection().createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM projects"); + while (rs.next()) { + String name = rs.getString("name"); + String parent_name = rs.getString("parent_name"); + if (parent_name == null) { + parent_name = systemConfig.wildProjectName.get(); + } + parentsByProject.put(new Project.NameKey(name), // + new Project.NameKey(parent_name)); + } + rs.close(); + stmt.close(); + } + + private void convertRights(ProjectConfig config) { + List<OldRefRight> myRights = + rightsByProject.get(config.getProject().getNameKey()); + if (myRights == null) { + return; + } + + for (OldRefRight old : myRights) { + AccessSection section = config.getAccessSection(old.ref_pattern, true); + GroupReference group = config.resolve(old.group); + + if (OLD_SUBMIT.equals(old.category)) { + PermissionRule submit = rule(group); + if (old.max_value <= 0) { + submit.setDeny(); + } + add(section, SUBMIT, old.exclusive, submit); + + } else if (OLD_READ.equals(old.category)) { + if (old.exclusive) { + section.getPermission(READ, true).setExclusiveGroup(true); + newChangePermission(config, old.ref_pattern).setExclusiveGroup(true); + } + + PermissionRule read = rule(group); + if (old.max_value <= 0) { + read.setDeny(); + } + add(section, READ, old.exclusive, read); + + if (3 <= old.max_value) { + newMergePermission(config, old.ref_pattern).add(rule(group)); + } else if (3 <= inheritedMax(config, old)) { + newMergePermission(config, old.ref_pattern).add(deny(group)); + } + + if (2 <= old.max_value) { + newChangePermission(config, old.ref_pattern).add(rule(group)); + } else if (2 <= inheritedMax(config, old)) { + newChangePermission(config, old.ref_pattern).add(deny(group)); + } + + } else if (OLD_OWN.equals(old.category)) { + add(section, OWNER, false, rule(group)); + + } else if (OLD_PUSH_TAG.equals(old.category)) { + PermissionRule push = rule(group); + if (old.max_value <= 0) { + push.setDeny(); + } + add(section, PUSH_TAG, old.exclusive, push); + + } else if (OLD_PUSH_HEAD.equals(old.category)) { + if (old.exclusive) { + section.getPermission(PUSH, true).setExclusiveGroup(true); + section.getPermission(CREATE, true).setExclusiveGroup(true); + } + + PermissionRule push = rule(group); + if (old.max_value <= 0) { + push.setDeny(); + } + push.setForce(3 <= old.max_value); + add(section, PUSH, old.exclusive, push); + + if (2 <= old.max_value) { + add(section, CREATE, old.exclusive, rule(group)); + } else if (2 <= inheritedMax(config, old)) { + add(section, CREATE, old.exclusive, deny(group)); + } + + } else if (OLD_FORGE_IDENTITY.equals(old.category)) { + if (old.exclusive) { + section.getPermission(FORGE_AUTHOR, true).setExclusiveGroup(true); + section.getPermission(FORGE_COMMITTER, true).setExclusiveGroup(true); + section.getPermission(FORGE_SERVER, true).setExclusiveGroup(true); + } + + if (1 <= old.max_value) { + add(section, FORGE_AUTHOR, old.exclusive, rule(group)); + } + + if (2 <= old.max_value) { + add(section, FORGE_COMMITTER, old.exclusive, rule(group)); + } else if (2 <= inheritedMax(config, old)) { + add(section, FORGE_COMMITTER, old.exclusive, deny(group)); + } + + if (3 <= old.max_value) { + add(section, FORGE_SERVER, old.exclusive, rule(group)); + } else if (3 <= inheritedMax(config, old)) { + add(section, FORGE_SERVER, old.exclusive, deny(group)); + } + + } else { + PermissionRule rule = rule(group); + rule.setRange(old.min_value, old.max_value); + if (old.min_value == 0 && old.max_value == 0) { + rule.setDeny(); + } + add(section, LABEL + varNameOf(old.category), old.exclusive, rule); + } + } + } + + private static Permission newChangePermission(ProjectConfig config, + String name) { + if (name.startsWith(AccessSection.REGEX_PREFIX)) { + name = AccessSection.REGEX_PREFIX + + "refs/for/" + + name.substring(AccessSection.REGEX_PREFIX.length()); + } else { + name = "refs/for/" + name; + } + return config.getAccessSection(name, true).getPermission(PUSH, true); + } + + private static Permission newMergePermission(ProjectConfig config, + String name) { + if (name.startsWith(AccessSection.REGEX_PREFIX)) { + name = AccessSection.REGEX_PREFIX + + "refs/for/" + + name.substring(AccessSection.REGEX_PREFIX.length()); + } else { + name = "refs/for/" + name; + } + return config.getAccessSection(name, true).getPermission(PUSH_MERGE, true); + } + + private static PermissionRule rule(GroupReference group) { + return new PermissionRule(group); + } + + private static PermissionRule deny(GroupReference group) { + PermissionRule rule = rule(group); + rule.setDeny(); + return rule; + } + + private int inheritedMax(ProjectConfig config, OldRefRight old) { + int max = 0; + + String ref = old.ref_pattern; + String category = old.category; + AccountGroup.UUID group = old.group.getUUID(); + + Project.NameKey project = config.getProject().getParent(); + if (project == null) { + project = systemConfig.wildProjectName; + } + do { + List<OldRefRight> rights = rightsByProject.get(project); + if (rights != null) { + for (OldRefRight r : rights) { + if (r.ref_pattern.equals(ref) // + && r.group.getUUID().equals(group) // + && r.category.equals(category)) { + max = Math.max(max, r.max_value); + break; + } + } + } + project = parentsByProject.get(project); + } while (!project.equals(systemConfig.wildProjectName)); + + return max; + } + + private String varNameOf(String id) { + ApprovalCategory category = categoryMap.get(new ApprovalCategory.Id(id)); + if (category == null) { + category = new ApprovalCategory(new ApprovalCategory.Id(id), id); + } + return category.getLabelName(); + } + + private static void add(AccessSection section, String name, + boolean exclusive, PermissionRule rule) { + Permission p = section.getPermission(name, true); + if (exclusive) { + p.setExclusiveGroup(true); + } + p.add(rule); + } + + private class OldRefRight { + final int min_value; + final int max_value; + final String ref_pattern; + final boolean exclusive; + final GroupReference group; + final String category; + final Project.NameKey project; + + OldRefRight(ResultSet rs) throws SQLException { + min_value = rs.getInt("min_value"); + max_value = rs.getInt("max_value"); + project = new Project.NameKey(rs.getString("project_name")); + + String r = rs.getString("ref_pattern"); + exclusive = r.startsWith("-"); + if (exclusive) { + r = r.substring(1); + } + ref_pattern = r; + + category = rs.getString("category_id"); + group = groupMap.get(new AccountGroup.Id(rs.getInt("group_id"))); + } + } +} |