Package com.google.gerrit.server.schema

Source Code of com.google.gerrit.server.schema.Schema_53

// 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.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.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 (IOException err) {
          throw new OrmException("Cannot create repository " + name, err);
        }
      } catch (IOException e) {
        throw new OrmException(e);
      }
      try {
        MetaDataUpdate md =
            new MetaDataUpdate(GitReferenceUpdated.DISABLED, 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");
        config.commit(md);
      } 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")));
    }
  }
}
TOP

Related Classes of com.google.gerrit.server.schema.Schema_53

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.