-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgit-tool.py
More file actions
181 lines (145 loc) · 5.92 KB
/
git-tool.py
File metadata and controls
181 lines (145 loc) · 5.92 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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#!/usr/bin/env python3
import argparse
import hashlib
import os.path
import shutil
import subprocess
import sys
from typing import List
class CommitLog:
def __init__(self, commit_lines):
self._commit_id = ""
self._author = ""
self._date = ""
self._change_id = ""
self._files = []
self._comments = ""
self._parse_commit_lines(commit_lines)
def get_commit_id(self):
return self._commit_id
def get_changed_files(self):
return self._files
def _parse_commit_lines(self, commit_lines: List[str]):
for line in commit_lines:
if line.startswith("commit"):
self._commit_id = line[len("commit"):].strip()
elif line.startswith("Author:"):
self._author = line[len("Author:"):].strip()
elif line.startswith("Date:"):
self._date = line[len("Date:"):].strip()
elif line.startswith(":"):
self._files.append(line.split()[-1].strip())
else:
line = line.strip()
if line.startswith("Change-Id:"):
self._change_id = line[len("Change-Id:"):].strip()
elif len(line) > 0:
if len(self._comments) <= 0:
self._comments = line
else:
self._comments = "{}\n{}".format(self._comments, line)
class GitTool:
@classmethod
def get_commit_log(cls, filename=None):
command = ["git", "log", "--raw"]
if filename is not None:
command.append(filename)
out = subprocess.check_output(command).decode()
result = []
commit_lines = []
for line in out.split("\n"):
if line.startswith("commit"):
if len(commit_lines) > 0:
result.append(CommitLog(commit_lines))
commit_lines = []
commit_lines.append(line)
return result
@classmethod
def find_commit(cls, filename, changed_text):
result = []
for commit_log in cls.get_commit_log(filename):
commit_id = commit_log.get_commit_id()
command = ['git', 'show', commit_id, filename]
out = subprocess.check_output(command).decode()
if out.find(changed_text) != -1:
result.append(commit_id)
return result
@classmethod
def get_current_branch(cls):
command = ["git", "branch", "-v"]
out = subprocess.check_output(command).decode()
for line in out.split("\n"):
fields = line.split()
if len(fields) >= 3 and fields[0] == '*':
return fields[1]
return None
@classmethod
def checkout(cls, branch_name):
subprocess.check_output(["git", "checkout", branch_name])
def compute_file_md5(filename):
md5_object = hashlib.md5()
block_size = 128 * md5_object.block_size
with open(filename, "rb") as fp:
chunk = fp.read(block_size)
while chunk:
md5_object.update(chunk)
chunk = fp.read(block_size)
return md5_object.hexdigest()
def copy_file(src_file, dest_file=None):
if dest_file is None:
with open(src_file, "r") as fp:
shutil.copyfileobj(fp, sys.stdout)
else:
with open(src_file, "rb") as fp:
with open(dest_file, "wb") as fp2:
shutil.copyfileobj(fp, fp2)
def find_commit(args):
print(GitTool.find_commit(args.file, args.text))
def find_changed_files(args):
for commit_log in GitTool.get_commit_log():
if commit_log.get_commit_id() == args.commit_id:
print("\n".join(commit_log.get_changed_files()))
def get_file(args):
current_branch = GitTool.get_current_branch()
for commit_log in GitTool.get_commit_log(args.file):
if commit_log.get_commit_id() == args.commit_id:
GitTool.checkout(commit_log.get_commit_id())
if os.path.isfile(args.file):
copy_file(args.file, args.dest)
GitTool.checkout(current_branch)
def find_commit_by_file_md5(args):
filename = args.file
file_md5 = args.md5
result = []
current_branch = GitTool.get_current_branch()
for commit_log in GitTool.get_commit_log(filename):
GitTool.checkout(commit_log.get_commit_id())
if compute_file_md5(filename) == file_md5:
result.append(commit_log.get_commit_id())
GitTool.checkout(current_branch)
print(result)
def parse_args():
parser = argparse.ArgumentParser(description="git useful tools")
subparsers = parser.add_subparsers(title="sub commands")
find_commit_parser = subparsers.add_parser("find-commit")
find_commit_parser.add_argument("--file", help="the file name")
find_commit_parser.add_argument("--text", help="the text in the changes", required=True)
find_commit_parser.set_defaults(func=find_commit)
find_changed_files_parser = subparsers.add_parser("find-changed-files")
find_changed_files_parser.add_argument("--commit-id", help="the commit id", required=True)
find_changed_files_parser.set_defaults(func=find_changed_files)
get_file_parser = subparsers.add_parser("get-file")
get_file_parser.add_argument("--commit-id", help="the commit id", required=True)
get_file_parser.add_argument("--file", help="the file name", required=True)
get_file_parser.add_argument("--dest", help="the destination file to save")
get_file_parser.set_defaults(func=get_file)
find_commit_by_file_md5_parser = subparsers.add_parser("find-commit-by-file-md5")
find_commit_by_file_md5_parser.add_argument("--file", help="the file name", required=True)
find_commit_by_file_md5_parser.add_argument("--md5", help="the file md5", required=True)
find_commit_by_file_md5_parser.set_defaults(func=find_commit_by_file_md5)
return parser.parse_args()
def main():
args = parse_args()
args.func(args)
if __name__ == "__main__":
main()