-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgitcommit.py
More file actions
123 lines (97 loc) · 3.63 KB
/
gitcommit.py
File metadata and controls
123 lines (97 loc) · 3.63 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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
from gitobject import GitObject
def kvlm_parse(raw, start=0, dct=None):
if not dct:
dct = dict()
# You CANNOT declare the argument as dct=dict() or all call to
# the functions will endlessly grow the same dict.
# This function is recursive: it reads a key/value pair, then call
# itself back with the new position. So we first need to know
# where we are: at a keyword, or already in the messageQ
# We search for the next space and the next newline.
spc = raw.find(b" ", start)
nl = raw.find(b"\n", start)
# If space appears before newline, we have a keyword. Otherwise,
# it's the final message, which we just read to the end of the file.
# Base case
# =========
# If newline appears first (or there's no space at all, in which
# case find returns -1), we assume a blank line. A blank line
# means the remainder of the data is the message. We store it in
# the dictionary, with None as the key, and return.
if (spc < 0) or (nl < spc):
assert nl == start
dct[None] = raw[start + 1 :]
return dct
# Recursive case
# ==============
# we read a key-value pair and recurse for the next.
key = raw[start:spc]
# Find the end of the value. Continuation lines begin with a
# space, so we loop until we find a "\n" not followed by a space.
end = start
while True:
end = raw.find(b"\n", end + 1)
if raw[end + 1] != ord(" "):
break
# Grab the value
# Also, drop the leading space on continuation lines
value = raw[spc + 1 : end].replace(b"\n ", b"\n")
# Don't overwrite existing data contents
if key in dct:
if type(dct[key]) == list:
dct[key].append(value)
else:
dct[key] = [dct[key], value]
else:
dct[key] = value
return kvlm_parse(raw, start=end + 1, dct=dct)
def kvlm_serialize(kvlm):
"""serializing the key value list message to the git format"""
ret = b""
# Output fields
for k in kvlm.keys():
# Skip the message itself
if k == None:
continue
val = kvlm[k]
# Normalize to a list
if type(val) != list:
val = [val]
for v in val:
ret += k + b" " + (v.replace(b"\n", b"\n ")) + b"\n"
# Append message
ret += b"\n" + kvlm[None]
return ret
class GitCommit(GitObject):
fmt = b'commit'
def init(self):
super().init()
self.kvlm = dict()
def serialize(self):
#convert python dict to git commit format
return kvlm_serialize(self.kvlm)
def deserialize(self, data):
self.kvlm = kvlm_parse(data)
def commit_create(repo, tree, parent, author, timestamp, message):
# Note: for the timestamp argument, you must provide a datetime object.
commit = GitCommit() # Create the new commit object.
commit.kvlm[b"tree"] = tree.encode("ascii")
if parent:
commit.kvlm[b"parent"] = parent.encode("ascii")
# Trim message and add a trailing \n
message = message.strip() + "\n"
if not message:
print("please provide a commit message")
return
# Format timezone
offset = int(timestamp.astimezone().utcoffset().total_seconds())
sign = "+" if offset >= 0 else "-"
offset = abs(offset)
hours = offset // 3600
minutes = (offset % 3600) // 60
tz = f"{sign}{hours:02}{minutes:02}"
author = author + " " + str(int(timestamp.timestamp())) + " " + tz
commit.kvlm[b"author"] = author.encode("utf8")
commit.kvlm[b"committer"] = author.encode("utf8")
commit.kvlm[None] = message.encode("utf8")
return commit