blender/tools/utils/git_log.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

192 lines
4.2 KiB
Python
Raw Normal View History

# SPDX-License-Identifier: GPL-2.0-or-later
# Simple module for inspecting git commits
import os
import subprocess
class GitCommit:
__slots__ = (
"sha1",
# to extract more info
"_git_dir",
# cached values
"_author",
"_date",
"_body",
"_files",
"_files_status",
)
def __init__(self, sha1, git_dir):
self.sha1 = sha1
self._git_dir = git_dir
self._author = \
self._date = \
self._body = \
self._files = \
self._files_status = \
None
def cache(self):
""" Cache all properties
"""
self.author
self.date
self.body
self.files
self.files_status
def _log_format(self, format, args=()):
# sha1 = self.sha1.decode('ascii')
cmd = (
"git",
"--git-dir",
self._git_dir,
"log",
"-1", # only this rev
self.sha1,
"--format=" + format,
) + args
# print(" ".join(cmd))
p = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
)
return p.stdout.read()
@property
def sha1_short(self):
cmd = (
"git",
"--git-dir",
self._git_dir,
"rev-parse",
"--short",
self.sha1,
)
p = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
)
return p.stdout.read().strip().decode('ascii')
@property
def author(self):
ret = self._author
if ret is None:
content = self._log_format("%an")[:-1]
ret = content.decode("utf8", errors="ignore")
self._author = ret
return ret
@property
def date(self):
ret = self._date
if ret is None:
import datetime
ret = datetime.datetime.fromtimestamp(int(self._log_format("%ct")))
self._date = ret
return ret
@property
def body(self):
ret = self._body
if ret is None:
content = self._log_format("%B")[:-1]
ret = content.decode("utf8", errors="ignore")
self._body = ret
return ret
@property
def subject(self):
return self.body.lstrip().partition("\n")[0]
@property
def files(self):
ret = self._files
if ret is None:
ret = [f for f in self._log_format("format:", args=("--name-only",)).split(b"\n") if f]
self._files = ret
return ret
@property
def files_status(self):
ret = self._files_status
if ret is None:
ret = [f.split(None, 1) for f in self._log_format("format:", args=("--name-status",)).split(b"\n") if f]
self._files_status = ret
return ret
class GitCommitIter:
__slots__ = (
"_path",
"_git_dir",
"_sha1_range",
"_process",
)
def __init__(self, path, sha1_range):
self._path = path
self._git_dir = os.path.join(path, ".git")
self._sha1_range = sha1_range
self._process = None
def __iter__(self):
cmd = (
"git",
"--git-dir",
self._git_dir,
"log",
self._sha1_range,
"--format=%H",
)
# print(" ".join(cmd))
self._process = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
)
return self
def __next__(self):
sha1 = self._process.stdout.readline()[:-1]
if sha1:
return GitCommit(sha1, self._git_dir)
else:
raise StopIteration
class GitRepo:
__slots__ = (
"_path",
"_git_dir",
)
def __init__(self, path):
self._path = path
self._git_dir = os.path.join(path, ".git")
@property
def branch(self):
cmd = (
"git",
"--git-dir",
self._git_dir,
"rev-parse",
"--abbrev-ref",
"HEAD",
)
# print(" ".join(cmd))
p = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
)
return p.stdout.read()