Line data Source code
1 : // Copyright (C) 2019 The Android Open Source Project 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.server.patch; 16 : 17 : import static com.google.common.base.Preconditions.checkState; 18 : 19 : import com.google.common.collect.ImmutableList; 20 : import com.google.common.flogger.FluentLogger; 21 : import com.google.gerrit.common.data.PatchScript; 22 : import com.google.gerrit.entities.Change; 23 : import com.google.gerrit.entities.FixReplacement; 24 : import com.google.gerrit.entities.PatchSet; 25 : import com.google.gerrit.extensions.client.DiffPreferencesInfo; 26 : import com.google.gerrit.extensions.restapi.AuthException; 27 : import com.google.gerrit.extensions.restapi.ResourceConflictException; 28 : import com.google.gerrit.extensions.restapi.ResourceNotFoundException; 29 : import com.google.gerrit.server.git.LargeObjectException; 30 : import com.google.gerrit.server.notedb.ChangeNotes; 31 : import com.google.gerrit.server.permissions.ChangePermission; 32 : import com.google.gerrit.server.permissions.PermissionBackend; 33 : import com.google.gerrit.server.permissions.PermissionBackendException; 34 : import com.google.gerrit.server.project.InvalidChangeOperationException; 35 : import com.google.gerrit.server.project.NoSuchChangeException; 36 : import com.google.gerrit.server.project.ProjectCache; 37 : import com.google.gerrit.server.project.ProjectState; 38 : import com.google.inject.Provider; 39 : import com.google.inject.assistedinject.Assisted; 40 : import com.google.inject.assistedinject.AssistedInject; 41 : import java.io.IOException; 42 : import java.util.concurrent.Callable; 43 : import org.eclipse.jgit.lib.ObjectId; 44 : import org.eclipse.jgit.lib.Repository; 45 : 46 : public class PatchScriptFactoryForAutoFix implements Callable<PatchScript> { 47 : 48 2 : private static final FluentLogger logger = FluentLogger.forEnclosingClass(); 49 : 50 : public interface Factory { 51 : 52 : PatchScriptFactoryForAutoFix create( 53 : Repository git, 54 : ChangeNotes notes, 55 : String fileName, 56 : PatchSet patchSet, 57 : ImmutableList<FixReplacement> fixReplacements, 58 : DiffPreferencesInfo diffPrefs); 59 : } 60 : 61 : private final PermissionBackend permissionBackend; 62 : private final ProjectCache projectCache; 63 : private final Change.Id changeId; 64 : private final ChangeNotes notes; 65 : private final Provider<PatchScriptBuilder> builderFactory; 66 : private final Repository git; 67 : private final PatchSet patchSet; 68 : private final String fileName; 69 : private final DiffPreferencesInfo diffPrefs; 70 : private final ImmutableList<FixReplacement> fixReplacements; 71 : 72 : @AssistedInject 73 : PatchScriptFactoryForAutoFix( 74 : Provider<PatchScriptBuilder> builderFactory, 75 : PermissionBackend permissionBackend, 76 : ProjectCache projectCache, 77 : @Assisted Repository git, 78 : @Assisted ChangeNotes notes, 79 : @Assisted String fileName, 80 : @Assisted PatchSet patchSet, 81 : @Assisted ImmutableList<FixReplacement> fixReplacements, 82 2 : @Assisted DiffPreferencesInfo diffPrefs) { 83 2 : this.notes = notes; 84 2 : this.permissionBackend = permissionBackend; 85 2 : this.projectCache = projectCache; 86 2 : this.changeId = patchSet.id().changeId(); 87 2 : this.git = git; 88 2 : this.patchSet = patchSet; 89 2 : this.fileName = fileName; 90 2 : this.fixReplacements = fixReplacements; 91 2 : this.builderFactory = builderFactory; 92 2 : this.diffPrefs = diffPrefs; 93 2 : } 94 : 95 : @Override 96 : public PatchScript call() 97 : throws LargeObjectException, AuthException, InvalidChangeOperationException, IOException, 98 : PermissionBackendException, ResourceNotFoundException { 99 : 100 2 : if (!permissionBackend.currentUser().change(notes).test(ChangePermission.READ)) { 101 0 : throw new NoSuchChangeException(changeId); 102 : } 103 : 104 2 : if (!projectCache 105 2 : .get(notes.getProjectName()) 106 2 : .map(ProjectState::statePermitsRead) 107 2 : .orElse(false)) { 108 0 : throw new NoSuchChangeException(changeId); 109 : } 110 : 111 2 : return createPatchScript(); 112 : } 113 : 114 : private PatchScript createPatchScript() throws LargeObjectException, ResourceNotFoundException { 115 2 : checkState(patchSet.id().get() != 0, "edit not supported for left side"); 116 2 : PatchScriptBuilder b = newBuilder(); 117 : try { 118 2 : ObjectId baseId = patchSet.commitId(); 119 2 : return b.toPatchScript(git, baseId, fileName, fixReplacements); 120 0 : } catch (ResourceConflictException e) { 121 0 : logger.atSevere().withCause(e).log("AutoFix replacements is not valid"); 122 0 : throw new IllegalStateException("AutoFix replacements is not valid", e); 123 0 : } catch (IOException e) { 124 0 : logger.atSevere().withCause(e).log("File content unavailable"); 125 0 : throw new NoSuchChangeException(notes.getChangeId(), e); 126 0 : } catch (org.eclipse.jgit.errors.LargeObjectException err) { 127 0 : throw new LargeObjectException("File content is too large", err); 128 : } 129 : } 130 : 131 : private PatchScriptBuilder newBuilder() { 132 2 : PatchScriptBuilder b = builderFactory.get(); 133 2 : b.setDiffPrefs(diffPrefs); 134 2 : return b; 135 : } 136 : }