|
26 | 26 | import os |
27 | 27 | from io import BytesIO |
28 | 28 | import logging |
| 29 | +from collections import defaultdict |
29 | 30 |
|
30 | 31 |
|
31 | 32 | # typing ------------------------------------------------------------------ |
@@ -335,8 +336,70 @@ def stats(self) -> Stats: |
335 | 336 | return Stats._list_from_string(self.repo, text) |
336 | 337 |
|
337 | 338 | @property |
338 | | - def trailers(self) -> Dict: |
339 | | - """Get the trailers of the message as dictionary |
| 339 | + def trailers(self) -> Dict[str, str]: |
| 340 | + """Get the trailers of the message as a dictionary |
| 341 | +
|
| 342 | + Git messages can contain trailer information that are similar to RFC 822 |
| 343 | + e-mail headers (see: https://git-scm.com/docs/git-interpret-trailers). |
| 344 | +
|
| 345 | + WARNING: This function only returns the latest instance of each trailer key |
| 346 | + and will be deprecated soon. Please see either ``Commit.trailers_list`` or ``Commit.trailers_dict``. |
| 347 | +
|
| 348 | + :return: |
| 349 | + Dictionary containing whitespace stripped trailer information. |
| 350 | + Only the latest instance of each trailer key. |
| 351 | + """ |
| 352 | + return { |
| 353 | + k: v[0] for k, v in self.trailers_dict.items() |
| 354 | + } |
| 355 | + |
| 356 | + @property |
| 357 | + def trailers_list(self) -> List[str]: |
| 358 | + """Get the trailers of the message as a list |
| 359 | +
|
| 360 | + Git messages can contain trailer information that are similar to RFC 822 |
| 361 | + e-mail headers (see: https://git-scm.com/docs/git-interpret-trailers). |
| 362 | +
|
| 363 | + This functions calls ``git interpret-trailers --parse`` onto the message |
| 364 | + to extract the trailer information, returns the raw trailer data as a list. |
| 365 | +
|
| 366 | + Valid message with trailer:: |
| 367 | +
|
| 368 | + Subject line |
| 369 | +
|
| 370 | + some body information |
| 371 | +
|
| 372 | + another information |
| 373 | +
|
| 374 | + key1: value1.1 |
| 375 | + key1: value1.2 |
| 376 | + key2 : value 2 with inner spaces |
| 377 | +
|
| 378 | +
|
| 379 | + Returned list will look like this:: |
| 380 | +
|
| 381 | + [ |
| 382 | + "key1: value1.1", |
| 383 | + "key1: value1.2", |
| 384 | + "key2 : value 2 with inner spaces", |
| 385 | + ] |
| 386 | +
|
| 387 | +
|
| 388 | + :return: |
| 389 | + List containing whitespace stripped trailer information. |
| 390 | + """ |
| 391 | + cmd = ["git", "interpret-trailers", "--parse"] |
| 392 | + proc: Git.AutoInterrupt = self.repo.git.execute(cmd, as_process=True, istream=PIPE) # type: ignore |
| 393 | + trailer: str = proc.communicate(str(self.message).encode())[0].decode() |
| 394 | + trailer = trailer.strip() |
| 395 | + if trailer: |
| 396 | + return [t.strip() for t in trailer.split("\n")] |
| 397 | + |
| 398 | + return [] |
| 399 | + |
| 400 | + @property |
| 401 | + def trailers_dict(self) -> Dict[str, List[str]]: |
| 402 | + """Get the trailers of the message as a dictionary |
340 | 403 |
|
341 | 404 | Git messages can contain trailer information that are similar to RFC 822 |
342 | 405 | e-mail headers (see: https://git-scm.com/docs/git-interpret-trailers). |
@@ -345,42 +408,36 @@ def trailers(self) -> Dict: |
345 | 408 | to extract the trailer information. The key value pairs are stripped of |
346 | 409 | leading and trailing whitespaces before they get saved into a dictionary. |
347 | 410 |
|
348 | | - Valid message with trailer: |
349 | | -
|
350 | | - .. code-block:: |
| 411 | + Valid message with trailer:: |
351 | 412 |
|
352 | 413 | Subject line |
353 | 414 |
|
354 | 415 | some body information |
355 | 416 |
|
356 | 417 | another information |
357 | 418 |
|
358 | | - key1: value1 |
| 419 | + key1: value1.1 |
| 420 | + key1: value1.2 |
359 | 421 | key2 : value 2 with inner spaces |
360 | 422 |
|
361 | | - dictionary will look like this: |
362 | 423 |
|
363 | | - .. code-block:: |
| 424 | + Returned dictionary will look like this:: |
364 | 425 |
|
365 | 426 | { |
366 | | - "key1": "value1", |
367 | | - "key2": "value 2 with inner spaces" |
| 427 | + "key1": ["value1.1", "value1.2"], |
| 428 | + "key2": ["value 2 with inner spaces"], |
368 | 429 | } |
369 | 430 |
|
370 | | - :return: Dictionary containing whitespace stripped trailer information |
371 | 431 |
|
| 432 | + :return: |
| 433 | + Dictionary containing whitespace stripped trailer information. |
| 434 | + Mapping trailer keys to a list of their corresponding values. |
372 | 435 | """ |
373 | | - d = {} |
374 | | - cmd = ["git", "interpret-trailers", "--parse"] |
375 | | - proc: Git.AutoInterrupt = self.repo.git.execute(cmd, as_process=True, istream=PIPE) # type: ignore |
376 | | - trailer: str = proc.communicate(str(self.message).encode())[0].decode() |
377 | | - if trailer.endswith("\n"): |
378 | | - trailer = trailer[0:-1] |
379 | | - if trailer != "": |
380 | | - for line in trailer.split("\n"): |
381 | | - key, value = line.split(":", 1) |
382 | | - d[key.strip()] = value.strip() |
383 | | - return d |
| 436 | + d = defaultdict(list) |
| 437 | + for trailer in self.trailers_list: |
| 438 | + key, value = trailer.split(":", 1) |
| 439 | + d[key.strip()].append(value.strip()) |
| 440 | + return dict(d) |
384 | 441 |
|
385 | 442 | @classmethod |
386 | 443 | def _iter_from_process_or_stream(cls, repo: "Repo", proc_or_stream: Union[Popen, IO]) -> Iterator["Commit"]: |
|