blob: 3d5fc9c0e30da9b4c661d6cde86dab56a096d9c5 [file] [log] [blame]
// Copyright (C) 2022 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.plugins.codeowners.backend;
import static com.google.common.base.Preconditions.checkState;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.plugins.codeowners.backend.config.CodeOwnersPluginProjectConfigSnapshot;
import com.google.gerrit.plugins.codeowners.common.ChangedFile;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.patch.DiffNotAvailableException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* Computes and caches the {@link ChangedFile}s for the patch sets of a change.
*
* <p>The changed files for a patch set are computed lazily. This way we do not compute changed
* files unnecessarily that are never requested.
*
* <p>This class is not thread-safe.
*/
public class ChangedFilesByPatchSetCache {
interface Factory {
ChangedFilesByPatchSetCache create(
CodeOwnersPluginProjectConfigSnapshot codeOwnersConfig, ChangeNotes changeNotes);
}
private final ChangedFiles changedFiles;
private final CodeOwnersPluginProjectConfigSnapshot codeOwnersConfig;
private final ChangeNotes changeNotes;
private Map<PatchSet.Id, ImmutableList<ChangedFile>> cache = new HashMap<>();
@Inject
public ChangedFilesByPatchSetCache(
ChangedFiles changedFiles,
@Assisted CodeOwnersPluginProjectConfigSnapshot codeOwnersConfig,
@Assisted ChangeNotes changeNotes) {
this.changedFiles = changedFiles;
this.codeOwnersConfig = codeOwnersConfig;
this.changeNotes = changeNotes;
}
public ImmutableList<ChangedFile> get(PatchSet.Id patchSetId) {
return cache.computeIfAbsent(patchSetId, this::compute);
}
private ImmutableList<ChangedFile> compute(PatchSet.Id patchSetId) {
checkState(
patchSetId.changeId().equals(changeNotes.getChange().getId()),
"patch set %s belongs to other change than change %s",
patchSetId,
changeNotes.getChange().getId().get());
PatchSet patchSet = getPatchSet(patchSetId);
try {
return changedFiles.getFromDiffCache(
changeNotes.getProjectName(),
patchSet.commitId(),
codeOwnersConfig.getMergeCommitStrategy());
} catch (IOException | DiffNotAvailableException e) {
throw new StorageException(
String.format(
"failed to retrieve changed files for patch set %d of change %d"
+ " in project %s (commit=%s)",
patchSetId.get(),
patchSetId.changeId().get(),
changeNotes.getProjectName(),
patchSet.commitId()),
e);
}
}
private PatchSet getPatchSet(PatchSet.Id patchSetId) {
PatchSet patchSet = changeNotes.getPatchSets().get(patchSetId);
if (patchSet == null) {
throw new StorageException(
String.format(
"patch set %s not found in change %d", patchSetId, changeNotes.getChangeId().get()));
}
return patchSet;
}
}