-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgitmtime.py
299 lines (259 loc) · 8 KB
/
gitmtime.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
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
#!/usr/bin/python
import os
import os.path
import subprocess
import sys, getopt
import json
import datetime
import re
from datetime import datetime
import time
import calendar
import logging
import hashlib
VerboseFlag = False
ConfigFile = "gitmtime.cfg"
ConfigData = {}
BUF_SIZE = 65536 # lets read stuff in 64kb chunks!
FLAG_QUICK = 1
FLAG_CFG = 2
#------------------------------------------------------------------------------
# Common Functions
#------------------------------------------------------------------------------
def IsLinux():
if os.name == 'nt':
st = False
else:
st = True
return st
def Exec(cmd):
global VerboseFlag
if VerboseFlag:
print "Exec: %s" % (cmd)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
status = p.wait()
if VerboseFlag:
print out
print "Status=%d, our=[%s], err=[%s]" % (status, out, err)
if out == "":
out = err
return status, out
def WriteDataToFile(fn, text):
fp = open(fn, "w")
fp.write(text)
fp.close()
def ReadDataFromFile(fn):
fp = open(fn, 'r')
data = fp.read()
fp.close()
return data
def DeleteFile(fn):
if os.path.isfile(fn):
os.remove(fn)
def MakeFolder(folder):
if not os.path.exists(folder):
os.makedirs(folder)
def MoveFile(src, dest):
dir = os.path.dirname (dest)
MakeFolder(dir)
os.rename(src, dest)
def json_encode(data):
return json.dumps(data)
def json_decode(data):
return json.loads(data)
def isset(variable):
st = True
try:
variable
except NameError:
st = False
return st
def ReadFileToArray(fn):
with open(fn) as f:
lines = f.readlines()
f.close()
return lines
def WriteArrayToFile(fn, lines):
fo = open(fn, "w")
line = fo.writelines(lines)
fo.close()
def GetFileExtension(fn):
return os.path.splitext(fn)[1]
def GetFileSha1 (fn):
sha1 = hashlib.sha1()
with open(fn, 'rb') as f:
while True:
data = f.read(BUF_SIZE)
if not data:
break
sha1.update(data)
return sha1.hexdigest()
#------------------------------------------------------------------------------
# GIT Functions
#------------------------------------------------------------------------------
class GitFolderClass:
Folder = "."
ValidFlag = False
FileDatabase = {}
def __init__(self, folder = "."):
self.Folder = folder
self.ValidFlag = self.IsValid()
def IsValid(self):
st = False
status, result = Exec("git status %s" % (self.Folder))
if status == 0:
if "Not a git repository" not in result:
st = True
return st
def GetMTimeFromFile(self, fn):
return os.path.getmtime(fn)
def GetFInfoFromDatabase(self, fn):
finfo = False
if fn in self.FileDatabase:
finfo = self.FileDatabase[fn]
return finfo
def GetMTimeFromGit(self, fn):
mtime = False
status, iso_time = Exec("git log --pretty=format:%%cd -n 1 --format=%%ai -- %s" % (fn))
if status == 0 and iso_time != "":
iso_time = iso_time.strip(); # "2017-08-10 12:54:58 +0800" => "2017-08-10 12:54:58"
iso_time = iso_time[:-5].strip()
ftime = datetime.strptime(iso_time, "%Y-%m-%d %H:%M:%S")
mtime = calendar.timegm(ftime.timetuple())
return mtime
def UpdateFileMTime(self, fn, mtime):
os.utime (fn, (mtime, mtime))
iso_time = datetime.fromtimestamp(int(mtime)).strftime('%Y-%m-%d %H:%M:%S')
if VerboseFlag:
print "Info: Update mtime of [%s] to [%s]" % (fn, iso_time)
logging.info('Update mtime of [%s] to [%s]' % (fn, iso_time))
def GetFileListFromGIT(self):
status, result = Exec("git ls-files")
if status == 0:
flist = result.split("\n")
else:
flist = False
return flist
def GetFileListFromCFG(self): # LocalDatabase
flist = []
for fn, fninfo in self.FileDatabase.iteritems():
flist.append(fn)
return flist
def UpdateMTime(self, flags):
if flags & FLAG_CFG:
flist = self.GetFileListFromCFG()
else:
flist = self.GetFileListFromGIT()
if flist != False:
for fn in flist:
fn = fn.strip()
if not fn:
continue
if os.path.isfile(fn) == False:
print "Info: file not found [%s]" % (fn)
continue
finfo = self.GetFInfoFromDatabase(fn)
if finfo == False: # No record in database
if flags & FLAG_QUICK:
mtime = self.GetMTimeFromFile (fn) # Get mtime from File (Quick Mode)
elif flags & FLAG_CFG:
mtime = False
else:
mtime = self.GetMTimeFromGit (fn) # Get mtime from GIT
if mtime != False:
self.UpdateFileMTime (fn, mtime)
finfo = {}
finfo['mtime'] = mtime
finfo['size'] = os.stat(fn).st_size
finfo['sha1'] = GetFileSha1(fn)
self.FileDatabase[fn] = finfo
else: # had record
mtime = self.GetMTimeFromFile(fn)
if finfo['mtime'] != mtime: # but time diff
sha1 = GetFileSha1(fn)
if sha1 == finfo['sha1']: # sha1 is same, update mtime to file
self.UpdateFileMTime (fn, finfo['mtime'])
elif flags & FLAG_CFG:
mtime = False
else: # sha1 is diff, get mtime from GIT
mtime = self.GetMTimeFromGit (fn)
if mtime != False:
finfo = {}
finfo['mtime'] = mtime
finfo['size'] = os.stat(fn).st_size
finfo['sha1'] = sha1
self.FileDatabase[fn] = finfo
#------------------------------------------------------------------------------
# Config Functions
#------------------------------------------------------------------------------
def LoadConfig():
global ConfigFile
global ConfigData
if os.path.isfile(ConfigFile):
jdata = ReadDataFromFile(ConfigFile)
try:
ConfigData = json_decode(jdata)
except:
ConfigData = {}
def SaveConfig():
global ConfigFile
global ConfigData
jdata = json_encode(ConfigData)
WriteDataToFile(ConfigFile, jdata)
#------------------------------------------------------------------------------
# Main
#------------------------------------------------------------------------------
def Usage():
print 'Python gitmtime.py -y -t -v -s'
print ' -u Update database and mtime of all files'
print ' -c Empty database for rebuild'
print ' -q Quick mode, Use Local File System for rebuild'
print ' --cfg Config File Only'
print ' -t Test'
print ' -v Verbose'
def main(argv):
global VerboseFlag
global ConfigData
TestFlag = False
SpaceFlag = False
UpdateFlag = False
ClearMTimeFlag = False
Flags = 0
logging.basicConfig(filename='gitmtime.log', level=logging.INFO)
try:
opts, args = getopt.getopt(argv,"ucqvh",["help", "cfg"])
except getopt.GetoptError:
Usage()
sys.exit(2)
for opt, arg in opts:
if opt == '-h':
Usage()
sys.exit()
elif opt == "-u": # Update mtime database
UpdateFlag = True
elif opt == "-c": # Clear modified time database
ClearMTimeFlag = True
elif opt == "-q": # Quick Flag for rebuild
Flags = Flags | FLAG_QUICK
elif opt == "--cfg": # Config File Only mode
Flags = Flags | FLAG_CFG
elif opt == "-v": # Verbose Flag
VerboseFlag = True
if TestFlag != False:
sys.exit()
sobj = GitFolderClass()
if sobj.ValidFlag == False:
print "Error: not a GIT working copy"
sys.exit(2)
LoadConfig()
print "Flags = 0x%X" % (Flags)
if UpdateFlag:
sobj = GitFolderClass()
if ClearMTimeFlag == False and "FDB" in ConfigData:
sobj.FileDatabase = ConfigData['FDB']
sobj.UpdateMTime (Flags)
ConfigData['FDB'] = sobj.FileDatabase
SaveConfig()
if __name__ == "__main__":
main(sys.argv[1:])