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