<commit_before>// 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.server.notedb;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_LABEL;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_PATCH_SET;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_STATUS;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_SUBMITTED_WITH;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.GERRIT_PLACEHOLDER_HOST;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import com.google.gerrit.common.data.SubmitRecord;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.VersionedMetaData;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.util.LabelVote;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;

import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.FooterKey;
import org.eclipse.jgit.revwalk.RevCommit;

import java.io.IOException;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * A single delta to apply atomically to a change.
 * <p>
 * This delta becomes a single commit on the notes branch, so there are
 * limitations on the set of modifications that can be handled in a single
 * update. In particular, there is a single author and timestamp for each
 * update.
 * <p>
 * This class is not thread-safe.
 */
public class ChangeUpdate extends VersionedMetaData {
  public interface Factory {
    ChangeUpdate create(ChangeControl ctl);
    ChangeUpdate create(ChangeControl ctl, Date when);
    @VisibleForTesting
    ChangeUpdate create(ChangeControl ctl, Date when,
        Comparator<String> labelNameComparator);
  }

  private final NotesMigration migration;
  private final GitRepositoryManager repoManager;
  private final AccountCache accountCache;
  private final MetaDataUpdate.User updateFactory;
  private final ChangeControl ctl;
  private final PersonIdent serverIdent;
  private final Date when;
  private final Map<String, Optional<Short>> approvals;
  private final Map<Account.Id, ReviewerState> reviewers;
  private Change.Status status;
  private String subject;
  private PatchSet.Id psId;
  private List<SubmitRecord> submitRecords;

  @AssistedInject
  private ChangeUpdate(
      @GerritPersonIdent PersonIdent serverIdent,
      GitRepositoryManager repoManager,
      NotesMigration migration,
      AccountCache accountCache,
      MetaDataUpdate.User updateFactory,
      ProjectCache projectCache,
      IdentifiedUser user,
      @Assisted ChangeControl ctl) {
    this(serverIdent, repoManager, migration, accountCache, updateFactory,
        projectCache, ctl, serverIdent.getWhen());
  }

  @AssistedInject
  private ChangeUpdate(
      @GerritPersonIdent PersonIdent serverIdent,
      GitRepositoryManager repoManager,
      NotesMigration migration,
      AccountCache accountCache,
      MetaDataUpdate.User updateFactory,
      ProjectCache projectCache,
      @Assisted ChangeControl ctl,
      @Assisted Date when) {
    this(serverIdent, repoManager, migration, accountCache, updateFactory,
        ctl, when,
        projectCache.get(getProjectName(ctl)).getLabelTypes().nameComparator());
  }

  private static Project.NameKey getProjectName(ChangeControl ctl) {
    return ctl.getChange().getDest().getParentKey();
  }

  @AssistedInject
  private ChangeUpdate(
      @GerritPersonIdent PersonIdent serverIdent,
      GitRepositoryManager repoManager,
      NotesMigration migration,
      AccountCache accountCache,
      MetaDataUpdate.User updateFactory,
      @Assisted ChangeControl ctl,
      @Assisted Date when,
      @Assisted Comparator<String> labelNameComparator) {
    this.repoManager = repoManager;
    this.migration = migration;
    this.accountCache = accountCache;
    this.updateFactory = updateFactory;
    this.ctl = ctl;
    this.when = when;
    this.serverIdent = serverIdent;
    this.approvals = Maps.newTreeMap(labelNameComparator);
    this.reviewers = Maps.newLinkedHashMap();
  }

  public Change getChange() {
    return ctl.getChange();
  }

  public IdentifiedUser getUser() {
    return (IdentifiedUser) ctl.getCurrentUser();
  }

  public Date getWhen() {
    return when;
  }

  public void setStatus(Change.Status status) {
    checkArgument(status != Change.Status.SUBMITTED,
        "use submit(Iterable<PatchSetApproval>)");
    this.status = status;
  }

  public void putApproval(String label, short value) {
    approvals.put(label, Optional.of(value));
  }

  public void removeApproval(String label) {
    approvals.put(label, Optional.<Short> absent());
  }

  public void submit(Iterable<SubmitRecord> submitRecords) {
    status = Change.Status.SUBMITTED;
    this.submitRecords = ImmutableList.copyOf(submitRecords);
    checkArgument(!this.submitRecords.isEmpty(),
        "no submit records specified at submit time");
  }

  public void setSubject(String subject) {
    this.subject = subject;
  }

  public void setPatchSetId(PatchSet.Id psId) {
    checkArgument(psId == null
        || psId.getParentKey().equals(getChange().getKey()));
    this.psId = psId;
  }

  public void putReviewer(Account.Id reviewer, ReviewerState type) {
    checkArgument(type != ReviewerState.REMOVED, "invalid ReviewerType");
    reviewers.put(reviewer, type);
  }

  public void removeReviewer(Account.Id reviewer) {
    reviewers.put(reviewer, ReviewerState.REMOVED);
  }

  private void load() throws IOException {
    if (migration.write() && getRevision() == null) {
      Repository repo = repoManager.openRepository(getChange().getProject());
      try {<commit_msg>ChangeUpdate: fix comparison of Change.Id to Change.Key<commit_after>// 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.server.notedb;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_LABEL;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_PATCH_SET;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_STATUS;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_SUBMITTED_WITH;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.GERRIT_PLACEHOLDER_HOST;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import com.google.gerrit.common.data.SubmitRecord;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.VersionedMetaData;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.util.LabelVote;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;

import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.FooterKey;
import org.eclipse.jgit.revwalk.RevCommit;

import java.io.IOException;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * A single delta to apply atomically to a change.
 * <p>
 * This delta becomes a single commit on the notes branch, so there are
 * limitations on the set of modifications that can be handled in a single
 * update. In particular, there is a single author and timestamp for each
 * update.
 * <p>
 * This class is not thread-safe.
 */
public class ChangeUpdate extends VersionedMetaData {
  public interface Factory {
    ChangeUpdate create(ChangeControl ctl);
    ChangeUpdate create(ChangeControl ctl, Date when);
    @VisibleForTesting
    ChangeUpdate create(ChangeControl ctl, Date when,
        Comparator<String> labelNameComparator);
  }

  private final NotesMigration migration;
  private final GitRepositoryManager repoManager;
  private final AccountCache accountCache;
  private final MetaDataUpdate.User updateFactory;
  private final ChangeControl ctl;
  private final PersonIdent serverIdent;
  private final Date when;
  private final Map<String, Optional<Short>> approvals;
  private final Map<Account.Id, ReviewerState> reviewers;
  private Change.Status status;
  private String subject;
  private PatchSet.Id psId;
  private List<SubmitRecord> submitRecords;

  @AssistedInject
  private ChangeUpdate(
      @GerritPersonIdent PersonIdent serverIdent,
      GitRepositoryManager repoManager,
      NotesMigration migration,
      AccountCache accountCache,
      MetaDataUpdate.User updateFactory,
      ProjectCache projectCache,
      IdentifiedUser user,
      @Assisted ChangeControl ctl) {
    this(serverIdent, repoManager, migration, accountCache, updateFactory,
        projectCache, ctl, serverIdent.getWhen());
  }

  @AssistedInject
  private ChangeUpdate(
      @GerritPersonIdent PersonIdent serverIdent,
      GitRepositoryManager repoManager,
      NotesMigration migration,
      AccountCache accountCache,
      MetaDataUpdate.User updateFactory,
      ProjectCache projectCache,
      @Assisted ChangeControl ctl,
      @Assisted Date when) {
    this(serverIdent, repoManager, migration, accountCache, updateFactory,
        ctl, when,
        projectCache.get(getProjectName(ctl)).getLabelTypes().nameComparator());
  }

  private static Project.NameKey getProjectName(ChangeControl ctl) {
    return ctl.getChange().getDest().getParentKey();
  }

  @AssistedInject
  private ChangeUpdate(
      @GerritPersonIdent PersonIdent serverIdent,
      GitRepositoryManager repoManager,
      NotesMigration migration,
      AccountCache accountCache,
      MetaDataUpdate.User updateFactory,
      @Assisted ChangeControl ctl,
      @Assisted Date when,
      @Assisted Comparator<String> labelNameComparator) {
    this.repoManager = repoManager;
    this.migration = migration;
    this.accountCache = accountCache;
    this.updateFactory = updateFactory;
    this.ctl = ctl;
    this.when = when;
    this.serverIdent = serverIdent;
    this.approvals = Maps.newTreeMap(labelNameComparator);
    this.reviewers = Maps.newLinkedHashMap();
  }

  public Change getChange() {
    return ctl.getChange();
  }

  public IdentifiedUser getUser() {
    return (IdentifiedUser) ctl.getCurrentUser();
  }

  public Date getWhen() {
    return when;
  }

  public void setStatus(Change.Status status) {
    checkArgument(status != Change.Status.SUBMITTED,
        "use submit(Iterable<PatchSetApproval>)");
    this.status = status;
  }

  public void putApproval(String label, short value) {
    approvals.put(label, Optional.of(value));
  }

  public void removeApproval(String label) {
    approvals.put(label, Optional.<Short> absent());
  }

  public void submit(Iterable<SubmitRecord> submitRecords) {
    status = Change.Status.SUBMITTED;
    this.submitRecords = ImmutableList.copyOf(submitRecords);
    checkArgument(!this.submitRecords.isEmpty(),
        "no submit records specified at submit time");
  }

  public void setSubject(String subject) {
    this.subject = subject;
  }

  public void setPatchSetId(PatchSet.Id psId) {
    checkArgument(psId == null
        || psId.getParentKey().equals(getChange().getId()));
    this.psId = psId;
  }

  public void putReviewer(Account.Id reviewer, ReviewerState type) {
    checkArgument(type != ReviewerState.REMOVED, "invalid ReviewerType");
    reviewers.put(reviewer, type);
  }

  public void removeReviewer(Account.Id reviewer) {
    reviewers.put(reviewer, ReviewerState.REMOVED);
  }

  private void load() throws IOException {
    if (migration.write() && getRevision() == null) {
      Repository repo = repoManager.openRepository(getChange().getProject());
      try {
{'fraction_non_alphanumeric': 0.0911115751374678, 'fraction_numerical': 0.001113663256072945, 'mean_word_length': 4.371214953271028, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3525825', 'n_tokens_mistral': 4153, 'n_tokens_neox': 4070, 'n_words': 1026}