1 /*
2 * LICENSE
3 *
4 * "THE BEER-WARE LICENSE" (Revision 42):
5 * "Sven Strittmatter" <ich@weltraumschaf.de> wrote this file.
6 * As long as you retain this notice you can do whatever you want with
7 * this stuff. If we meet some day, and you think this stuff is worth it,
8 * you can buy me a beer in return.
9 */
10 package org.jenkinsci.plugins.darcs;
11
12 import hudson.model.User;
13 import hudson.scm.ChangeLogSet;
14 import hudson.scm.EditType;
15
16 import java.util.ArrayList;
17 import java.util.Arrays;
18 import java.util.List;
19
20 import org.kohsuke.stapler.export.Exported;
21
22 /**
23 * Represents a change set (aka. a patch in Darcs).
24 *
25 * <p>
26 * The object should be treated like an immutable object.
27 *
28 * @author Sven Strittmatter <ich@weltraumschaf.de>
29 */
30 public class DarcsChangeSet extends ChangeLogSet.Entry {
31
32 /**
33 * The patch author.
34 */
35 private String author;
36 /**
37 * The patch date in UTC.
38 */
39 private String date;
40 /**
41 * Localized patch date.
42 */
43 private String localDate;
44 /**
45 * Whether it is an inversion of an other patch.
46 */
47 private boolean inverted;
48 /**
49 * The patches unique has.
50 */
51 private String hash;
52 /**
53 * The patch name.
54 */
55 private String name;
56 /**
57 * The patch long comment.
58 */
59 private String comment;
60 /**
61 * Filles added by this patch.
62 */
63 private List<String> added = new ArrayList<String>();
64 /**
65 * Filles deleted by this patch.
66 */
67 private List<String> deleted = new ArrayList<String>();
68 /**
69 * Filles modified by this patch.
70 */
71 private List<String> modified = new ArrayList<String>();
72
73 /**
74 * Returns the author as User object.
75 *
76 * If you want the parsed author string from Darcs call getPlainAuthor().
77 *
78 * @return a Jenkins user object
79 */
80 @Exported
81 public User getAuthor() {
82 return User.get(getPlainAuthor());
83 }
84
85 /**
86 * Returns the plain author string used in the Darcs repository.
87 *
88 * @return author name
89 */
90 public String getPlainAuthor() {
91 return author;
92 }
93
94 /**
95 * Returns the patch comment.
96 *
97 * @return comment message
98 */
99 @Exported
100 public String getComment() {
101 return comment;
102 }
103
104 /**
105 * Returns the patch date as string.
106 *
107 * @return date string in UTC
108 */
109 @Exported
110 public String getDate() {
111 return date;
112 }
113
114 /**
115 * Returns the unique hash string of the patch.
116 *
117 * @return hash string
118 */
119 @Exported
120 public String getHash() {
121 return hash;
122 }
123
124 /**
125 * Returns whether the patch is inverted or not.
126 *
127 * @return {@code true} if it is an inverse patch, else {@code false}
128 */
129 @Exported
130 public boolean isInverted() {
131 return inverted;
132 }
133
134 /**
135 * Returns the localized date string.
136 *
137 * @return local date string in UTC
138 */
139 @Exported
140 public String getLocalDate() {
141 return localDate;
142 }
143
144 /**
145 * Returns the patch name.
146 *
147 * @return the patch name
148 */
149 @Exported
150 public String getName() {
151 return name;
152 }
153
154 /**
155 * Method for fulfill the interface.
156 *
157 * Delegates to {@link #getComment()}.
158 *
159 * @return same as {@link #getComment()}
160 */
161 @Override
162 public String getMsg() {
163 return getComment();
164 }
165
166 /**
167 * Sets the author string from Darcs.
168 *
169 * Thus this object should be treated as immutable, this setter should only be called from the DarcsChangeLogParser.
170 *
171 * @param anAuthor author name string
172 */
173 public void setAuthor(final String anAuthor) {
174 author = anAuthor;
175 }
176
177 /**
178 * Sets the comment string.
179 *
180 * Thus this object should be treated as immutable, this setter should only be called from the DarcsChangeLogParser.
181 *
182 * @param aComment patch comment message
183 */
184 public void setComment(final String aComment) {
185 comment = aComment;
186 }
187
188 /**
189 * Sets the date string.
190 *
191 * Thus this object should be treated as immutable, this setter should only be called from the DarcsChangeLogParser.
192 *
193 * @param aDate date in UTC
194 */
195 public void setDate(final String aDate) {
196 date = aDate;
197 }
198
199 /**
200 * Sets the hash string.
201 *
202 * Thus this object should be treated as immutable, this setter should only be called from the DarcsChangeLogParser.
203 *
204 * @param aHash hash string
205 */
206 public void setHash(final String aHash) {
207 hash = aHash;
208 }
209
210 /**
211 * Sets the inverted flag.
212 *
213 * Thus this object should be treated as immutable, this setter should only be called from the DarcsChangeLogParser.
214 *
215 * @param isInverted {@code true} if it is an inverse patch, else {@code false}
216 */
217 public void setInverted(final boolean isInverted) {
218 inverted = isInverted;
219 }
220
221 /**
222 * Sets the localized date string.
223 *
224 * Thus this object should be treated as immutable, this setter should only be called from the DarcsChangeLogParser.
225 *
226 * @param aLocalDate date in UTC
227 */
228 public void setLocalDate(final String aLocalDate) {
229 localDate = aLocalDate;
230 }
231
232 /**
233 * Sets the patch name.
234 *
235 * Thus this object should be treated as immutable, this setter should only be called from the DarcsChangeLogParser.
236 *
237 * @param aName patch name
238 */
239 public void setName(final String aName) {
240 name = aName;
241 }
242
243 /**
244 * Returns a lazy computed list of all files affected by this patch.
245 *
246 * @return the list is recalculated on each call
247 */
248 @Override
249 public List<String> getAffectedPaths() {
250 return new ArrayList<String>() {
251 {
252 addAll(added);
253 addAll(deleted);
254 addAll(modified);
255 }
256 };
257 }
258
259 /**
260 * Gets all the files that were added.
261 *
262 * @return modifiable list
263 */
264 @Exported
265 public List<String> getAddedPaths() {
266 return added;
267 }
268
269 /**
270 * Gets all the files that were deleted.
271 *
272 * @return modifiable list
273 */
274 @Exported
275 public List<String> getDeletedPaths() {
276 return deleted;
277 }
278
279 /**
280 * Gets all the files that were modified.
281 *
282 * @return modifiable list
283 */
284 @Exported
285 public List<String> getModifiedPaths() {
286 return modified;
287 }
288
289 /**
290 * Convenience method for getting affected paths by type.
291 *
292 * @param kind one of {@link EditType#ADD}, {@link EditType#EDIT}, {@link EditType#DELETE}
293 * @return list associated to the edit type
294 */
295 public List<String> getPaths(final EditType kind) {
296 if (kind == EditType.ADD) {
297 return getAddedPaths();
298 }
299
300 if (kind == EditType.EDIT) {
301 return getModifiedPaths();
302 }
303
304 if (kind == EditType.DELETE) {
305 return getDeletedPaths();
306 }
307
308 return null;
309 }
310
311 @Override
312 protected void setParent(final ChangeLogSet parent) {
313 super.setParent(parent);
314 }
315
316 /**
317 * Returns all three variations of {@link EditType}. Placed here to simplify access from views.
318 *
319 * @return available edit types
320 */
321 public List<EditType> getEditTypes() {
322 return Arrays.asList(EditType.ADD, EditType.EDIT, EditType.DELETE);
323 }
324
325 @Override
326 public String toString() {
327 return "DarcsChangeSet{"
328 + "hash=" + hash
329 + ", name=" + name
330 + ", author=" + author
331 + ", date=" + date
332 + ", localDate=" + localDate
333 + ", inverted=" + inverted
334 + ", added=" + added
335 + ", modified=" + modified
336 + ", deleted=" + deleted
337 + '}';
338 }
339
340 @Override
341 public int hashCode() {
342 return Arrays.hashCode(new Object[]{
343 added,
344 author,
345 comment,
346 date,
347 deleted,
348 hash,
349 inverted,
350 localDate,
351 modified,
352 name,
353 });
354 }
355
356 @Override
357 public boolean equals(final Object obj) {
358 if (!(obj instanceof DarcsChangeSet)) {
359 return false;
360 }
361
362 final DarcsChangeSet other = (DarcsChangeSet) obj;
363
364 if (!equal(added, other.added)) {
365 return false;
366 }
367
368 if (!equal(author, other.author)) {
369 return false;
370 }
371
372 if (!equal(comment, other.comment)) {
373 return false;
374 }
375
376 if (!equal(date, other.date)) {
377 return false;
378 }
379
380 if (!equal(deleted, other.deleted)) {
381 return false;
382 }
383
384 if (!equal(hash, other.hash)) {
385 return false;
386 }
387
388 if (!equal(localDate, other.localDate)) {
389 return false;
390 }
391
392 if (!equal(modified, other.modified)) {
393 return false;
394 }
395
396 if (!equal(inverted, other.inverted)) {
397 return false;
398 }
399
400 if (!equal(name, other.name)) {
401 return false;
402 }
403
404 return true;
405 }
406
407 /**
408 * Helper which respects {@code null} values.
409 *
410 * @param a first object to compare
411 * @param b second object to compare
412 * @return {@code true} if a and b are equal, else {@code false}
413 */
414 private static boolean equal(final Object a, final Object b) {
415 return a == b || (a != null && a.equals(b));
416 }
417
418 }