-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathgit.py
More file actions
72 lines (61 loc) · 2.47 KB
/
git.py
File metadata and controls
72 lines (61 loc) · 2.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
"""
This module defines a ContributionsReader that obtains contributors' list for a page
from the Git history. Note that this ContributionsReader won't work well in case of
history rewrites or files renamed without keeping contributor's history.
For this reason, it should be used together with a
"""
import re
import subprocess
from datetime import datetime
from pathlib import Path
from typing import Iterable, List, Tuple
from dateutil.parser import ParserError
from dateutil.parser import parse as parse_date
from neoteroi.mkdocs.contribs.domain import ContributionsReader, Contributor
class GitContributionsReader(ContributionsReader):
_name_email_rx = re.compile(r"(?P<name>[^\<]+)<(?P<email>[^\>]+)>")
def _decode(self, value: bytes) -> str:
try:
return value.decode("utf8")
except UnicodeDecodeError:
return value.decode("ISO-8859-1")
def _parse_name_and_email(self, name_and_email) -> Tuple[str, str]:
match = self._name_email_rx.search(name_and_email)
if match:
name = match.groupdict()["name"].strip()
email = match.groupdict()["email"].strip()
else:
name, email = ("", "")
return name, email
def parse_committers(self, output: str) -> Iterable[Contributor]:
for line in output.splitlines():
count, name_and_email = line.split("\t")
name, email = self._parse_name_and_email(name_and_email)
yield Contributor(name, email, int(count))
def get_contributors(self, file_path: Path) -> List[Contributor]:
"""
Obtains the list of contributors for a file with the given path,
using the Git CLI.
"""
in_process = subprocess.Popen(
["git", "log", "--pretty=short", "--follow", str(file_path)],
stdout=subprocess.PIPE,
)
result = self._decode(
subprocess.check_output(
["git", "shortlog", "--summary", "--numbered", "--email"],
stdin=in_process.stdout,
)
)
return list(self.parse_committers(result))
def get_last_modified_date(self, file_path: Path) -> datetime:
"""Reads the last commit on a file."""
result = self._decode(
subprocess.check_output(
["git", "log", "-1", "--pretty=format:%ci", str(file_path)]
)
)
try:
return parse_date(result)
except ParserError:
return datetime.min