-
Notifications
You must be signed in to change notification settings - Fork 0
/
git_updates.py
255 lines (202 loc) · 9.31 KB
/
git_updates.py
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
import os
import sys
from datetime import datetime
import git
class GitCommands():
def __init__(self, command, dir=".", correction_dir="Korrekturen", correction_file_prefix="korrektur"):
self.dir = dir
self.correction_dir = correction_dir
self.correction_file_prefix = correction_file_prefix
now = datetime.now()
self.log_folder = "_logs"
self.log_filename = now.strftime(f"log-%d_%m_%Y-%H_%M_%S-{command}.txt")
if not os.path.exists(self.log_folder):
os.makedirs(self.log_folder)
self.log_file = open(os.path.join(self.log_folder, self.log_filename), 'w+')
def pull(self):
print("Pulling all repositories...")
for dir in os.listdir(self.dir):
if not os.path.isdir(dir) or dir == self.log_folder:
continue
repo = git.cmd.Git(os.path.join(self.dir, dir))
try:
output = repo.pull()
except git.exc.GitCommandError as e:
output = str(e)
if "Already up to date" in output:
msg = "Already up to date"
elif "file changed, " in output or "files changed, " in output:
matched_lines = [line for line in output.split('\n') if "file changed, " in line or "files changed, " in line]
msg = matched_lines[0][1:]
elif "The project you were looking for could not be found" in output:
msg = "Error: The repository could not be found or you don't have permission to view it"
elif "error: Pulling is not possible because you have unmerged files" in output:
msg = "Error: Conflict with committed files"
elif "error: Your local changes" in output:
msg = "Error: Conflict with local files"
elif "but no such ref was fetched." in output:
msg = "Error: No branch seems to be specified"
else:
msg = output
log = f"{dir} - {msg}"
print(log)
self.log_file.write(log + "\n\n" + output + "\n\n\n")
self.log_file.close()
def commit(self, number):
print(f"Committing correction number {number}...")
for dir in os.listdir(self.dir):
if not os.path.isdir(dir) or dir == self.log_folder:
continue
repo = git.cmd.Git(os.path.join(self.dir, dir))
folder_found = True
# search and stage files
staged_files = {}
try:
for file in os.listdir(os.path.join(self.dir, dir, self.correction_dir)):
if self.correction_file_prefix + number in file:
file_path = os.path.join(self.correction_dir, file)
staged_files[file_path] = file
repo.add(file_path)
except FileNotFoundError:
msg = f"Error: No folder named {self.correction_dir} was found"
folder_found = False
commit_output = ""
if folder_found:
# check what was actually staged
modified = False
status = repo.status("--porcelain")
committed_files = []
for file in staged_files.keys():
if f"A {file}" in status or f"M {file}" in status:
committed_files.append(staged_files[file])
if f"M {file}" in status:
modified = True
# commit and generate message
if len(committed_files) > 0:
commit_msg = f"{'Update ' if modified else ''}Korrektur Übung {number}"
try:
commit_output = repo.commit("-m " + commit_msg)
msg = f"Committed {'update for ' if modified else ''}{', '.join(committed_files)}"
except git.exc.GitCommandError as e:
commit_output = str(e)
if "error: Committing is not possible because you have unmerged files" in commit_output:
msg = "Error: Merge in progress"
elif "Please tell me who you are." in commit_output:
msg = "Error: Commit email and name are not configured"
else:
msg = commit_output
elif len(staged_files) > 0:
file_is_committed = False
show_output = repo.show("--name-only", "--oneline", "HEAD")
for file in staged_files.keys():
if file in show_output:
file_is_committed = True
break
if file_is_committed:
msg = f"Already committed {', '.join(staged_files.values())}"
else:
msg = f"Already up to date: {', '.join(staged_files.values())}"
else:
msg = "Nothing to commit was found"
log = f"{dir} - {msg}"
print(log)
if commit_output:
self.log_file.write(log + "\n\n" + commit_output + "\n\n\n")
else:
self.log_file.write(log + "\n\n\n")
self.log_file.close()
def push(self):
print("Pushing all commits...")
for dir in os.listdir(self.dir):
if not os.path.isdir(dir) or dir == self.log_folder:
continue
repo = git.cmd.Git(os.path.join(self.dir, dir))
try:
output = repo.push("--porcelain")
except git.exc.GitCommandError as e:
output = str(e)
if "[up to date]" in output:
msg = "Nothing to push"
elif "[rejected]" in output:
msg = "Error: Conflicting changes"
elif "error: src refspec" in output:
msg = "Error: No branch seems to be specified"
elif "Done" in output:
msg = "Successful push"
else:
msg = output
log = f"{dir} - {msg}"
print(log)
self.log_file.write(log + "\n\n" + output + "\n\n\n")
self.log_file.close()
def clean(self):
choice = input("This will delete all uncommited changes, this action cannot be reverted. Are you sure? [yes/N]\n")
if choice != "yes":
return
print("Deleting all uncommited changes...")
for dir in os.listdir(self.dir):
if not os.path.isdir(dir) or dir == self.log_folder:
continue
repo = git.cmd.Git(os.path.join(self.dir, dir))
status_full = repo.status()
status = repo.status("--porcelain")
try:
repo.restore(".")
output_clean = repo.clean("-fdx")
except git.exc.GitCommandError as e:
output_clean = str(e)
if "is unmerged" in output_clean:
msg = "Error: Merge in progress"
elif "error: pathspec '.' did not match any file(s) known to git" in output_clean:
msg = "Error: No branch seems to be specified"
elif not status:
msg = "Already clean"
elif not "M" in status and output_clean:
msg = "Deleted untracked files"
elif output_clean:
msg = "Restored files and deleted untracked files"
else:
msg = "Restored files"
log = f"{dir} - {msg}"
print(log)
self.log_file.write(log + "\n\n" + status_full + "\n\n" + output_clean + "\n\n\n")
self.log_file.close()
def show(self):
print("Showing latest commit...")
for dir in os.listdir(self.dir):
if not os.path.isdir(dir) or dir == self.log_folder:
continue
repo = git.cmd.Git(os.path.join(self.dir, dir))
try:
output = repo.show("-q")
lines = output.split("Author: ")[1].split("\n")
author = lines[0].split(" <")[0]
date = lines[1].split(" +")[0][8:]
commit_msg = lines[3].strip()
if "Merge branch" in commit_msg:
commit_msg = "Merge branch"
msg = f"{date}, {author}: {commit_msg}"
except git.exc.GitCommandError:
msg = "No commits yet"
log = f"{dir} - {msg}"
print(log)
self.log_file.write(log + "\n" + output + "\n\n\n")
self.log_file.close()
if __name__ == "__main__":
commands = ["pull", "commit", "push", "clean", "show"]
if len(sys.argv) > 1:
command = sys.argv[1]
else:
command = ""
while not command in commands:
if command != "":
print("Command not recognized, please try again.")
command = input("Do you want to pull, commit, clean, push or show the last commit?\n")
args = []
if command == "commit":
if len(sys.argv) > 2:
args.append(sys.argv[2])
else:
args.append(input("Which correction do you want to commit?\n"))
git_commands = GitCommands(command=command, dir=".", correction_dir="Korrekturen", correction_file_prefix="korrektur")
getattr(git_commands, command)(*args)