You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PersonIdent.java 9.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. /*
  2. * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
  3. * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
  4. * Copyright (C) 2006-2008, Shawn O. Pearce <spearce@spearce.org> and others
  5. *
  6. * This program and the accompanying materials are made available under the
  7. * terms of the Eclipse Distribution License v. 1.0 which is available at
  8. * https://www.eclipse.org/org/documents/edl-v10.php.
  9. *
  10. * SPDX-License-Identifier: BSD-3-Clause
  11. */
  12. package org.eclipse.jgit.lib;
  13. import java.io.Serializable;
  14. import java.text.SimpleDateFormat;
  15. import java.util.Date;
  16. import java.util.Locale;
  17. import java.util.TimeZone;
  18. import org.eclipse.jgit.internal.JGitText;
  19. import org.eclipse.jgit.util.SystemReader;
  20. import org.eclipse.jgit.util.time.ProposedTimestamp;
  21. /**
  22. * A combination of a person identity and time in Git.
  23. *
  24. * Git combines Name + email + time + time zone to specify who wrote or
  25. * committed something.
  26. */
  27. public class PersonIdent implements Serializable {
  28. private static final long serialVersionUID = 1L;
  29. /**
  30. * Get timezone object for the given offset.
  31. *
  32. * @param tzOffset
  33. * timezone offset as in {@link #getTimeZoneOffset()}.
  34. * @return time zone object for the given offset.
  35. * @since 4.1
  36. */
  37. public static TimeZone getTimeZone(int tzOffset) {
  38. StringBuilder tzId = new StringBuilder(8);
  39. tzId.append("GMT"); //$NON-NLS-1$
  40. appendTimezone(tzId, tzOffset);
  41. return TimeZone.getTimeZone(tzId.toString());
  42. }
  43. /**
  44. * Format a timezone offset.
  45. *
  46. * @param r
  47. * string builder to append to.
  48. * @param offset
  49. * timezone offset as in {@link #getTimeZoneOffset()}.
  50. * @since 4.1
  51. */
  52. public static void appendTimezone(StringBuilder r, int offset) {
  53. final char sign;
  54. final int offsetHours;
  55. final int offsetMins;
  56. if (offset < 0) {
  57. sign = '-';
  58. offset = -offset;
  59. } else {
  60. sign = '+';
  61. }
  62. offsetHours = offset / 60;
  63. offsetMins = offset % 60;
  64. r.append(sign);
  65. if (offsetHours < 10) {
  66. r.append('0');
  67. }
  68. r.append(offsetHours);
  69. if (offsetMins < 10) {
  70. r.append('0');
  71. }
  72. r.append(offsetMins);
  73. }
  74. /**
  75. * Sanitize the given string for use in an identity and append to output.
  76. * <p>
  77. * Trims whitespace from both ends and special characters {@code \n < >} that
  78. * interfere with parsing; appends all other characters to the output.
  79. * Analogous to the C git function {@code strbuf_addstr_without_crud}.
  80. *
  81. * @param r
  82. * string builder to append to.
  83. * @param str
  84. * input string.
  85. * @since 4.4
  86. */
  87. public static void appendSanitized(StringBuilder r, String str) {
  88. // Trim any whitespace less than \u0020 as in String#trim().
  89. int i = 0;
  90. while (i < str.length() && str.charAt(i) <= ' ') {
  91. i++;
  92. }
  93. int end = str.length();
  94. while (end > i && str.charAt(end - 1) <= ' ') {
  95. end--;
  96. }
  97. for (; i < end; i++) {
  98. char c = str.charAt(i);
  99. switch (c) {
  100. case '\n':
  101. case '<':
  102. case '>':
  103. continue;
  104. default:
  105. r.append(c);
  106. break;
  107. }
  108. }
  109. }
  110. private final String name;
  111. private final String emailAddress;
  112. private final long when;
  113. private final int tzOffset;
  114. /**
  115. * Creates new PersonIdent from config info in repository, with current time.
  116. * This new PersonIdent gets the info from the default committer as available
  117. * from the configuration.
  118. *
  119. * @param repo a {@link org.eclipse.jgit.lib.Repository} object.
  120. */
  121. public PersonIdent(Repository repo) {
  122. this(repo.getConfig().get(UserConfig.KEY));
  123. }
  124. /**
  125. * Copy a {@link org.eclipse.jgit.lib.PersonIdent}.
  126. *
  127. * @param pi
  128. * Original {@link org.eclipse.jgit.lib.PersonIdent}
  129. */
  130. public PersonIdent(PersonIdent pi) {
  131. this(pi.getName(), pi.getEmailAddress());
  132. }
  133. /**
  134. * Construct a new {@link org.eclipse.jgit.lib.PersonIdent} with current
  135. * time.
  136. *
  137. * @param aName
  138. * a {@link java.lang.String} object.
  139. * @param aEmailAddress
  140. * a {@link java.lang.String} object.
  141. */
  142. public PersonIdent(String aName, String aEmailAddress) {
  143. this(aName, aEmailAddress, SystemReader.getInstance().getCurrentTime());
  144. }
  145. /**
  146. * Construct a new {@link org.eclipse.jgit.lib.PersonIdent} with current
  147. * time.
  148. *
  149. * @param aName
  150. * a {@link java.lang.String} object.
  151. * @param aEmailAddress
  152. * a {@link java.lang.String} object.
  153. * @param when
  154. * a {@link org.eclipse.jgit.util.time.ProposedTimestamp} object.
  155. * @since 4.6
  156. */
  157. public PersonIdent(String aName, String aEmailAddress,
  158. ProposedTimestamp when) {
  159. this(aName, aEmailAddress, when.millis());
  160. }
  161. /**
  162. * Copy a PersonIdent, but alter the clone's time stamp
  163. *
  164. * @param pi
  165. * original {@link org.eclipse.jgit.lib.PersonIdent}
  166. * @param when
  167. * local time
  168. * @param tz
  169. * time zone
  170. */
  171. public PersonIdent(PersonIdent pi, Date when, TimeZone tz) {
  172. this(pi.getName(), pi.getEmailAddress(), when, tz);
  173. }
  174. /**
  175. * Copy a {@link org.eclipse.jgit.lib.PersonIdent}, but alter the clone's
  176. * time stamp
  177. *
  178. * @param pi
  179. * original {@link org.eclipse.jgit.lib.PersonIdent}
  180. * @param aWhen
  181. * local time
  182. */
  183. public PersonIdent(PersonIdent pi, Date aWhen) {
  184. this(pi.getName(), pi.getEmailAddress(), aWhen.getTime(), pi.tzOffset);
  185. }
  186. /**
  187. * Construct a PersonIdent from simple data
  188. *
  189. * @param aName a {@link java.lang.String} object.
  190. * @param aEmailAddress a {@link java.lang.String} object.
  191. * @param aWhen
  192. * local time stamp
  193. * @param aTZ
  194. * time zone
  195. */
  196. public PersonIdent(final String aName, final String aEmailAddress,
  197. final Date aWhen, final TimeZone aTZ) {
  198. this(aName, aEmailAddress, aWhen.getTime(), aTZ.getOffset(aWhen
  199. .getTime()) / (60 * 1000));
  200. }
  201. /**
  202. * Copy a PersonIdent, but alter the clone's time stamp
  203. *
  204. * @param pi
  205. * original {@link org.eclipse.jgit.lib.PersonIdent}
  206. * @param aWhen
  207. * local time stamp
  208. * @param aTZ
  209. * time zone
  210. */
  211. public PersonIdent(PersonIdent pi, long aWhen, int aTZ) {
  212. this(pi.getName(), pi.getEmailAddress(), aWhen, aTZ);
  213. }
  214. private PersonIdent(final String aName, final String aEmailAddress,
  215. long when) {
  216. this(aName, aEmailAddress, when, SystemReader.getInstance()
  217. .getTimezone(when));
  218. }
  219. private PersonIdent(UserConfig config) {
  220. this(config.getCommitterName(), config.getCommitterEmail());
  221. }
  222. /**
  223. * Construct a {@link org.eclipse.jgit.lib.PersonIdent}.
  224. * <p>
  225. * Whitespace in the name and email is preserved for the lifetime of this
  226. * object, but are trimmed by {@link #toExternalString()}. This means that
  227. * parsing the result of {@link #toExternalString()} may not return an
  228. * equivalent instance.
  229. *
  230. * @param aName
  231. * a {@link java.lang.String} object.
  232. * @param aEmailAddress
  233. * a {@link java.lang.String} object.
  234. * @param aWhen
  235. * local time stamp
  236. * @param aTZ
  237. * time zone
  238. */
  239. public PersonIdent(final String aName, final String aEmailAddress,
  240. final long aWhen, final int aTZ) {
  241. if (aName == null)
  242. throw new IllegalArgumentException(
  243. JGitText.get().personIdentNameNonNull);
  244. if (aEmailAddress == null)
  245. throw new IllegalArgumentException(
  246. JGitText.get().personIdentEmailNonNull);
  247. name = aName;
  248. emailAddress = aEmailAddress;
  249. when = aWhen;
  250. tzOffset = aTZ;
  251. }
  252. /**
  253. * Get name of person
  254. *
  255. * @return Name of person
  256. */
  257. public String getName() {
  258. return name;
  259. }
  260. /**
  261. * Get email address of person
  262. *
  263. * @return email address of person
  264. */
  265. public String getEmailAddress() {
  266. return emailAddress;
  267. }
  268. /**
  269. * Get timestamp
  270. *
  271. * @return timestamp
  272. */
  273. public Date getWhen() {
  274. return new Date(when);
  275. }
  276. /**
  277. * Get this person's declared time zone
  278. *
  279. * @return this person's declared time zone; null if time zone is unknown.
  280. */
  281. public TimeZone getTimeZone() {
  282. return getTimeZone(tzOffset);
  283. }
  284. /**
  285. * Get this person's declared time zone as minutes east of UTC.
  286. *
  287. * @return this person's declared time zone as minutes east of UTC. If the
  288. * timezone is to the west of UTC it is negative.
  289. */
  290. public int getTimeZoneOffset() {
  291. return tzOffset;
  292. }
  293. /**
  294. * {@inheritDoc}
  295. * <p>
  296. * Hashcode is based only on the email address and timestamp.
  297. */
  298. @Override
  299. public int hashCode() {
  300. int hc = getEmailAddress().hashCode();
  301. hc *= 31;
  302. hc += (int) (when / 1000L);
  303. return hc;
  304. }
  305. /** {@inheritDoc} */
  306. @Override
  307. public boolean equals(Object o) {
  308. if (o instanceof PersonIdent) {
  309. final PersonIdent p = (PersonIdent) o;
  310. return getName().equals(p.getName())
  311. && getEmailAddress().equals(p.getEmailAddress())
  312. && when / 1000L == p.when / 1000L;
  313. }
  314. return false;
  315. }
  316. /**
  317. * Format for Git storage.
  318. *
  319. * @return a string in the git author format
  320. */
  321. public String toExternalString() {
  322. final StringBuilder r = new StringBuilder();
  323. appendSanitized(r, getName());
  324. r.append(" <"); //$NON-NLS-1$
  325. appendSanitized(r, getEmailAddress());
  326. r.append("> "); //$NON-NLS-1$
  327. r.append(when / 1000);
  328. r.append(' ');
  329. appendTimezone(r, tzOffset);
  330. return r.toString();
  331. }
  332. /** {@inheritDoc} */
  333. @Override
  334. @SuppressWarnings("nls")
  335. public String toString() {
  336. final StringBuilder r = new StringBuilder();
  337. final SimpleDateFormat dtfmt;
  338. dtfmt = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy Z", Locale.US);
  339. dtfmt.setTimeZone(getTimeZone());
  340. r.append("PersonIdent[");
  341. r.append(getName());
  342. r.append(", ");
  343. r.append(getEmailAddress());
  344. r.append(", ");
  345. r.append(dtfmt.format(Long.valueOf(when)));
  346. r.append("]");
  347. return r.toString();
  348. }
  349. }