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.restapi.change;
16 :
17 : import static com.google.gerrit.server.project.ProjectCache.illegalState;
18 : import static java.util.stream.Collectors.groupingBy;
19 :
20 : import com.google.common.base.MoreObjects;
21 : import com.google.common.collect.ImmutableList;
22 : import com.google.gerrit.common.data.PatchScript;
23 : import com.google.gerrit.entities.Change;
24 : import com.google.gerrit.entities.Comment.Range;
25 : import com.google.gerrit.entities.FixReplacement;
26 : import com.google.gerrit.entities.PatchSet;
27 : import com.google.gerrit.extensions.client.DiffPreferencesInfo;
28 : import com.google.gerrit.extensions.common.ApplyProvidedFixInput;
29 : import com.google.gerrit.extensions.common.DiffInfo;
30 : import com.google.gerrit.extensions.common.DiffWebLinkInfo;
31 : import com.google.gerrit.extensions.common.WebLinkInfo;
32 : import com.google.gerrit.extensions.restapi.AuthException;
33 : import com.google.gerrit.extensions.restapi.BadRequestException;
34 : import com.google.gerrit.extensions.restapi.ResourceConflictException;
35 : import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
36 : import com.google.gerrit.extensions.restapi.Response;
37 : import com.google.gerrit.extensions.restapi.RestModifyView;
38 : import com.google.gerrit.extensions.restapi.RestReadView;
39 : import com.google.gerrit.server.change.FixResource;
40 : import com.google.gerrit.server.change.RevisionResource;
41 : import com.google.gerrit.server.diff.DiffInfoCreator;
42 : import com.google.gerrit.server.diff.DiffSide;
43 : import com.google.gerrit.server.diff.DiffWebLinksProvider;
44 : import com.google.gerrit.server.git.GitRepositoryManager;
45 : import com.google.gerrit.server.git.LargeObjectException;
46 : import com.google.gerrit.server.notedb.ChangeNotes;
47 : import com.google.gerrit.server.patch.PatchScriptFactoryForAutoFix;
48 : import com.google.gerrit.server.permissions.PermissionBackendException;
49 : import com.google.gerrit.server.project.InvalidChangeOperationException;
50 : import com.google.gerrit.server.project.NoSuchChangeException;
51 : import com.google.gerrit.server.project.ProjectCache;
52 : import com.google.gerrit.server.project.ProjectState;
53 : import com.google.inject.Inject;
54 : import com.google.inject.Singleton;
55 : import com.google.inject.assistedinject.Assisted;
56 : import java.io.IOException;
57 : import java.util.HashMap;
58 : import java.util.List;
59 : import java.util.Map;
60 : import org.eclipse.jgit.lib.Repository;
61 :
62 : public class PreviewFix {
63 : public interface Factory {
64 : PreviewFix create(RevisionResource revisionResource);
65 : }
66 :
67 : private final GitRepositoryManager repoManager;
68 : private final PatchScriptFactoryForAutoFix.Factory patchScriptFactoryFactory;
69 : private final PatchSet patchSet;
70 : private final ChangeNotes notes;
71 : private final ProjectState state;
72 :
73 : @Inject
74 : PreviewFix(
75 : GitRepositoryManager repoManager,
76 : PatchScriptFactoryForAutoFix.Factory patchScriptFactoryFactory,
77 : ProjectCache projectCache,
78 2 : @Assisted RevisionResource revisionResource) {
79 2 : this.repoManager = repoManager;
80 2 : this.patchScriptFactoryFactory = patchScriptFactoryFactory;
81 2 : patchSet = revisionResource.getPatchSet();
82 2 : notes = revisionResource.getNotes();
83 2 : Change change = notes.getChange();
84 2 : state = projectCache.get(change.getProject()).orElseThrow(illegalState(change.getProject()));
85 2 : }
86 :
87 : @Singleton
88 : public static class Stored implements RestReadView<FixResource> {
89 : private final PreviewFix.Factory previewFixFactory;
90 :
91 : @Inject
92 142 : Stored(PreviewFix.Factory previewFixFactory) {
93 142 : this.previewFixFactory = previewFixFactory;
94 142 : }
95 :
96 : @Override
97 : public Response<Map<String, DiffInfo>> apply(FixResource fixResource)
98 : throws PermissionBackendException, ResourceNotFoundException, ResourceConflictException,
99 : AuthException, IOException, InvalidChangeOperationException {
100 :
101 1 : PreviewFix previewFix = previewFixFactory.create(fixResource.getRevisionResource());
102 :
103 1 : Map<String, List<FixReplacement>> fixReplacementsPerFilePath =
104 1 : fixResource.getFixReplacements().stream()
105 1 : .collect(groupingBy(fixReplacement -> fixReplacement.path));
106 :
107 1 : return Response.ok(previewFix.previewAllFiles(fixReplacementsPerFilePath));
108 : }
109 : }
110 :
111 : @Singleton
112 : public static class Provided implements RestModifyView<RevisionResource, ApplyProvidedFixInput> {
113 : private final PreviewFix.Factory previewFixFactory;
114 :
115 : @Inject
116 145 : Provided(PreviewFix.Factory previewFixFactory) {
117 145 : this.previewFixFactory = previewFixFactory;
118 145 : }
119 :
120 : @Override
121 : public Response<Map<String, DiffInfo>> apply(
122 : RevisionResource revisionResource, ApplyProvidedFixInput applyProvidedFixInput)
123 : throws BadRequestException, PermissionBackendException, ResourceNotFoundException,
124 : ResourceConflictException, AuthException, IOException, InvalidChangeOperationException {
125 2 : if (applyProvidedFixInput == null) {
126 0 : throw new BadRequestException("applyProvidedFixInput is required");
127 : }
128 2 : if (applyProvidedFixInput.fixReplacementInfos == null) {
129 1 : throw new BadRequestException("applyProvidedFixInput.fixReplacementInfos is required");
130 : }
131 :
132 1 : PreviewFix previewFix = previewFixFactory.create(revisionResource);
133 :
134 1 : Map<String, List<FixReplacement>> fixReplacementsPerFilePath =
135 1 : applyProvidedFixInput.fixReplacementInfos.stream()
136 1 : .map(fix -> new FixReplacement(fix.path, new Range(fix.range), fix.replacement))
137 1 : .collect(groupingBy(fixReplacement -> fixReplacement.path));
138 :
139 1 : return Response.ok(previewFix.previewAllFiles(fixReplacementsPerFilePath));
140 : }
141 : }
142 :
143 : private Map<String, DiffInfo> previewAllFiles(
144 : Map<String, List<FixReplacement>> fixReplacementsPerFilePath)
145 : throws PermissionBackendException, ResourceNotFoundException, ResourceConflictException,
146 : AuthException, IOException, InvalidChangeOperationException {
147 2 : Map<String, DiffInfo> result = new HashMap<>();
148 2 : try (Repository git = repoManager.openRepository(notes.getProjectName())) {
149 2 : for (Map.Entry<String, List<FixReplacement>> entry : fixReplacementsPerFilePath.entrySet()) {
150 2 : String fileName = entry.getKey();
151 2 : DiffInfo diffInfo =
152 2 : previewSingleFile(git, fileName, ImmutableList.copyOf(entry.getValue()));
153 2 : result.put(fileName, diffInfo);
154 2 : }
155 0 : } catch (NoSuchChangeException e) {
156 0 : throw new ResourceNotFoundException(e.getMessage(), e);
157 0 : } catch (LargeObjectException e) {
158 0 : throw new ResourceConflictException(e.getMessage(), e);
159 2 : }
160 2 : return result;
161 : }
162 :
163 : private DiffInfo previewSingleFile(
164 : Repository git, String fileName, ImmutableList<FixReplacement> fixReplacements)
165 : throws PermissionBackendException, AuthException, LargeObjectException,
166 : InvalidChangeOperationException, IOException, ResourceNotFoundException {
167 2 : PatchScriptFactoryForAutoFix psf =
168 2 : patchScriptFactoryFactory.create(
169 2 : git, notes, fileName, patchSet, fixReplacements, DiffPreferencesInfo.defaults());
170 2 : PatchScript ps = psf.call();
171 :
172 2 : DiffSide sideA =
173 2 : DiffSide.create(
174 2 : ps.getFileInfoA(),
175 2 : MoreObjects.firstNonNull(ps.getOldName(), ps.getNewName()),
176 : DiffSide.Type.SIDE_A);
177 2 : DiffSide sideB = DiffSide.create(ps.getFileInfoB(), ps.getNewName(), DiffSide.Type.SIDE_B);
178 :
179 2 : DiffInfoCreator diffInfoCreator =
180 : new DiffInfoCreator(state, new DiffWebLinksProviderImpl(), true);
181 2 : return diffInfoCreator.create(ps, sideA, sideB);
182 : }
183 :
184 : private static class DiffWebLinksProviderImpl implements DiffWebLinksProvider {
185 :
186 : @Override
187 : public ImmutableList<DiffWebLinkInfo> getDiffLinks() {
188 2 : return ImmutableList.of();
189 : }
190 :
191 : @Override
192 : public ImmutableList<WebLinkInfo> getEditWebLinks() {
193 2 : return ImmutableList.of();
194 : }
195 :
196 : @Override
197 : public ImmutableList<WebLinkInfo> getFileWebLinks(DiffSide.Type fileInfoType) {
198 2 : return ImmutableList.of();
199 : }
200 : }
201 : }
|