Line data Source code
1 : // Copyright (C) 2011 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.git.meta;
16 :
17 : import com.google.gerrit.common.Nullable;
18 : import com.google.gerrit.entities.Project;
19 : import com.google.gerrit.server.GerritPersonIdent;
20 : import com.google.gerrit.server.IdentifiedUser;
21 : import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
22 : import com.google.gerrit.server.git.GitRepositoryManager;
23 : import com.google.inject.Inject;
24 : import com.google.inject.Provider;
25 : import com.google.inject.Singleton;
26 : import com.google.inject.assistedinject.Assisted;
27 : import java.io.IOException;
28 : import org.eclipse.jgit.errors.RepositoryNotFoundException;
29 : import org.eclipse.jgit.lib.BatchRefUpdate;
30 : import org.eclipse.jgit.lib.CommitBuilder;
31 : import org.eclipse.jgit.lib.PersonIdent;
32 : import org.eclipse.jgit.lib.RefUpdate;
33 : import org.eclipse.jgit.lib.Repository;
34 :
35 : /** Helps with the updating of a {@link VersionedMetaData}. */
36 : public class MetaDataUpdate implements AutoCloseable {
37 : @Singleton
38 : public static class User {
39 : private final InternalFactory factory;
40 : private final GitRepositoryManager mgr;
41 : private final Provider<PersonIdent> serverIdentProvider;
42 : private final Provider<IdentifiedUser> identifiedUser;
43 :
44 : @Inject
45 : User(
46 : InternalFactory factory,
47 : GitRepositoryManager mgr,
48 : @GerritPersonIdent Provider<PersonIdent> serverIdentProvider,
49 147 : Provider<IdentifiedUser> identifiedUser) {
50 147 : this.factory = factory;
51 147 : this.mgr = mgr;
52 147 : this.serverIdentProvider = serverIdentProvider;
53 147 : this.identifiedUser = identifiedUser;
54 147 : }
55 :
56 : public PersonIdent getUserPersonIdent() {
57 135 : return createPersonIdent(identifiedUser.get());
58 : }
59 :
60 : public MetaDataUpdate create(Project.NameKey name)
61 : throws RepositoryNotFoundException, IOException {
62 144 : return create(name, identifiedUser.get());
63 : }
64 :
65 : public MetaDataUpdate create(Project.NameKey name, IdentifiedUser user)
66 : throws RepositoryNotFoundException, IOException {
67 145 : return create(name, user, null);
68 : }
69 :
70 : /**
71 : * Create an update using an existing batch ref update.
72 : *
73 : * <p>This allows batching together updates to multiple metadata refs. For making multiple
74 : * commits to a single metadata ref, see {@link VersionedMetaData#openUpdate(MetaDataUpdate)}.
75 : *
76 : * @param name project name.
77 : * @param user user for the update.
78 : * @param batch batch update to use; the caller is responsible for committing the update.
79 : */
80 : public MetaDataUpdate create(Project.NameKey name, IdentifiedUser user, BatchRefUpdate batch)
81 : throws RepositoryNotFoundException, IOException {
82 145 : Repository repo = mgr.openRepository(name);
83 145 : MetaDataUpdate md = create(name, repo, user, batch);
84 145 : md.setCloseRepository(true);
85 145 : return md;
86 : }
87 :
88 : /**
89 : * Create an update using an existing batch ref update.
90 : *
91 : * <p>This allows batching together updates to multiple metadata refs. For making multiple
92 : * commits to a single metadata ref, see {@link VersionedMetaData#openUpdate(MetaDataUpdate)}.
93 : *
94 : * <p>Important: Create a new MetaDataUpdate instance for each update:
95 : *
96 : * <pre>
97 : * <code>
98 : * try (Repository repo = repoMgr.openRepository(allUsersName);
99 : * RevWalk rw = new RevWalk(repo)) {
100 : * BatchRefUpdate batchUpdate = repo.getRefDatabase().newBatchUpdate();
101 : * // WRONG: create the MetaDataUpdate instance here and reuse it for
102 : * // all updates in the loop
103 : * for{@code (Map.Entry<Account.Id, DiffPreferencesInfo> e : diffPrefsFromDb)} {
104 : * // CORRECT: create a new MetaDataUpdate instance for each update
105 : * try (MetaDataUpdate md =
106 : * metaDataUpdateFactory.create(allUsersName, batchUpdate)) {
107 : * md.setMessage("Import diff preferences from reviewdb\n");
108 : * VersionedAccountPreferences vPrefs =
109 : * VersionedAccountPreferences.forUser(e.getKey());
110 : * storeSection(vPrefs.getConfig(), UserConfigSections.DIFF, null,
111 : * e.getValue(), DiffPreferencesInfo.defaults());
112 : * vPrefs.commit(md);
113 : * } catch (ConfigInvalidException e) {
114 : * // TODO handle exception
115 : * }
116 : * }
117 : * batchUpdate.execute(rw, NullProgressMonitor.INSTANCE);
118 : * }
119 : * </code>
120 : * </pre>
121 : *
122 : * @param name project name.
123 : * @param repository the repository to update; the caller is responsible for closing the
124 : * repository.
125 : * @param user user for the update.
126 : * @param batch batch update to use; the caller is responsible for committing the update.
127 : */
128 : public MetaDataUpdate create(
129 : Project.NameKey name, Repository repository, IdentifiedUser user, BatchRefUpdate batch) {
130 145 : MetaDataUpdate md = factory.create(name, repository, batch);
131 145 : md.getCommitBuilder().setCommitter(serverIdentProvider.get());
132 145 : md.setAuthor(user);
133 145 : return md;
134 : }
135 :
136 : private PersonIdent createPersonIdent(IdentifiedUser user) {
137 135 : PersonIdent serverIdent = serverIdentProvider.get();
138 135 : return user.newCommitterIdent(serverIdent);
139 : }
140 : }
141 :
142 : @Singleton
143 : public static class Server {
144 : private final InternalFactory factory;
145 : private final GitRepositoryManager mgr;
146 : private final Provider<PersonIdent> serverIdentProvider;
147 :
148 : @Inject
149 : Server(
150 : InternalFactory factory,
151 : GitRepositoryManager mgr,
152 147 : @GerritPersonIdent Provider<PersonIdent> serverIdentProvider) {
153 147 : this.factory = factory;
154 147 : this.mgr = mgr;
155 147 : this.serverIdentProvider = serverIdentProvider;
156 147 : }
157 :
158 : public MetaDataUpdate create(Project.NameKey name)
159 : throws RepositoryNotFoundException, IOException {
160 94 : return create(name, null);
161 : }
162 :
163 : /** See {@link User#create(Project.NameKey, IdentifiedUser, BatchRefUpdate)} */
164 : public MetaDataUpdate create(Project.NameKey name, BatchRefUpdate batch)
165 : throws RepositoryNotFoundException, IOException {
166 94 : Repository repo = mgr.openRepository(name);
167 94 : MetaDataUpdate md = factory.create(name, repo, batch);
168 94 : md.setCloseRepository(true);
169 94 : PersonIdent serverIdent = serverIdentProvider.get();
170 94 : md.getCommitBuilder().setAuthor(serverIdent);
171 94 : md.getCommitBuilder().setCommitter(serverIdent);
172 94 : return md;
173 : }
174 : }
175 :
176 : public interface InternalFactory {
177 : MetaDataUpdate create(
178 : @Assisted Project.NameKey projectName,
179 : @Assisted Repository repository,
180 : @Assisted @Nullable BatchRefUpdate batch);
181 : }
182 :
183 : private final GitReferenceUpdated gitRefUpdated;
184 : private final Project.NameKey projectName;
185 : private final Repository repository;
186 : private final BatchRefUpdate batch;
187 : private final CommitBuilder commit;
188 : private boolean allowEmpty;
189 : private boolean insertChangeId;
190 : private boolean closeRepository;
191 : private IdentifiedUser author;
192 :
193 : @Inject
194 : public MetaDataUpdate(
195 : GitReferenceUpdated gitRefUpdated,
196 : @Assisted Project.NameKey projectName,
197 : @Assisted Repository repository,
198 152 : @Assisted @Nullable BatchRefUpdate batch) {
199 152 : this.gitRefUpdated = gitRefUpdated;
200 152 : this.projectName = projectName;
201 152 : this.repository = repository;
202 152 : this.batch = batch;
203 152 : this.commit = new CommitBuilder();
204 152 : }
205 :
206 : public MetaDataUpdate(
207 : GitReferenceUpdated gitRefUpdated, Project.NameKey projectName, Repository repository) {
208 152 : this(gitRefUpdated, projectName, repository, null);
209 152 : }
210 :
211 : /** Set the commit message used when committing the update. */
212 : public void setMessage(String message) {
213 151 : getCommitBuilder().setMessage(message);
214 151 : }
215 :
216 : public void setAuthor(IdentifiedUser author) {
217 151 : this.author = author;
218 151 : getCommitBuilder().setAuthor(author.newCommitterIdent(getCommitBuilder().getCommitter()));
219 151 : }
220 :
221 : public void setAllowEmpty(boolean allowEmpty) {
222 151 : this.allowEmpty = allowEmpty;
223 151 : }
224 :
225 : public void setInsertChangeId(boolean insertChangeId) {
226 2 : this.insertChangeId = insertChangeId;
227 2 : }
228 :
229 : public void setCloseRepository(boolean closeRepository) {
230 145 : this.closeRepository = closeRepository;
231 145 : }
232 :
233 : /** Returns batch in which to run the update, or {@code null} for no batch. */
234 : BatchRefUpdate getBatch() {
235 152 : return batch;
236 : }
237 :
238 : /** Close the cached Repository handle. */
239 : @Override
240 : public void close() {
241 152 : if (closeRepository) {
242 145 : getRepository().close();
243 : }
244 152 : }
245 :
246 : public Project.NameKey getProjectName() {
247 151 : return projectName;
248 : }
249 :
250 : public Repository getRepository() {
251 152 : return repository;
252 : }
253 :
254 : boolean allowEmpty() {
255 152 : return allowEmpty;
256 : }
257 :
258 : boolean insertChangeId() {
259 152 : return insertChangeId;
260 : }
261 :
262 : public CommitBuilder getCommitBuilder() {
263 152 : return commit;
264 : }
265 :
266 : protected void fireGitRefUpdatedEvent(RefUpdate ru) {
267 152 : gitRefUpdated.fire(projectName, ru, author == null ? null : author.state());
268 152 : }
269 : }
|