One version of runProgram is enough.
[hgct.git] / git.py
blobd69f1f5b872c0c23ae205767ff94c6189ac470c5
1 import sys, os, re
3 from ctcore import *
5 def repoValid():
6 if not os.environ.has_key('GIT_DIR'):
7 os.environ['GIT_DIR'] = '.git'
9 def basicsFailed(msg):
10 print "'git-cat-file -t HEAD' failed: " + msg
11 print "Make sure that the current working directory contains a '.git' directory, or\nthat GIT_DIR is set appropriately."
12 sys.exit(1)
14 try:
15 runProgram('git-cat-file -t HEAD')
16 except OSError, e:
17 basicsFailed(e.strerror)
18 except ProgramError, e:
19 basicsFailed(e.error)
23 parseDiffRE = re.compile(':([0-9]+) ([0-9]+) ([0-9a-f]{40}) ([0-9a-f]{40}) ([MCRNADUT])([0-9]*)')
24 def parseDiff(prog):
25 inp = runProgram(prog)
26 ret = []
27 try:
28 recs = inp.split("\0")
29 recs.pop() # remove last entry (which is '')
30 it = recs.__iter__()
31 while True:
32 rec = it.next()
33 m = parseDiffRE.match(rec)
35 if not m:
36 print "Unknown output from " + str(prog) + "!: " + rec + "\n"
37 continue
39 f = File()
40 f.srcMode = m.group(1)
41 f.dstMode = m.group(2)
42 f.srcSHA = m.group(3)
43 f.dstSHA = m.group(4)
44 if m.group(5) == 'N':
45 f.change = 'A'
46 else:
47 f.change = m.group(5)
48 f.score = m.group(6)
49 f.srcName = f.dstName = it.next()
51 if f.change == 'C' or f.change == 'R':
52 f.dstName = it.next()
53 f.patch = getPatch(f.srcName, f.dstName)
54 else:
55 f.patch = getPatch(f.srcName)
57 ret.append(f)
58 except StopIteration:
59 pass
60 return ret
63 # HEAD is src in the returned File objects. That is, srcName is the
64 # name in HEAD and dstName is the name in the cache.
65 def getFiles():
66 files = parseDiff('git-diff-cache -z -M --cached HEAD')
67 for f in files:
68 c = f.change
69 if c == 'C':
70 f.text = 'Copy from ' + f.srcName + ' to ' + f.dstName
71 elif c == 'R':
72 f.text = 'Rename from ' + f.srcName + ' to ' + f.dstName
73 elif c == 'A':
74 f.text = 'New file: ' + f.srcName
75 elif c == 'D':
76 f.text = 'Deleted file: ' + f.srcName
77 elif c == 'T':
78 f.text = 'Type change: ' + f.srcName
79 else:
80 f.text = f.srcName
82 if len(parseDiff(['git-diff-files', '-z', f.dstName])) > 0:
83 f.updated = False
84 else:
85 f.updated = True
86 return files
89 def getPatch(file, otherFile = None):
90 if otherFile:
91 f = [file, otherFile]
92 else:
93 f = [file]
94 return runProgram(['git-diff-cache', '-p', '-M', '--cached', 'HEAD'] + f)
96 def updateCache():
97 cacheHeadDiff = parseDiff('git-diff-cache -z --cached HEAD')
99 # The set of files that are different in the cache compared to HEAD
100 cacheHeadChange = {}
101 for f in cacheHeadDiff:
102 cacheHeadChange[f.srcName] = True
104 noncacheHeadDiff = parseDiff('git-diff-cache -z HEAD')
105 for f in noncacheHeadDiff:
106 if (f.srcSHA == '0'*40 or f.dstSHA == '0'*40) and not cacheHeadChange.has_key(f.srcName):
107 runProgram(['git-update-cache', '--remove', f.srcName])
109 def doUpdateCache(filename):
110 runProgram(['git-update-cache', '--remove', '--add', '--replace', filename])
113 def doCommit(filesToKeep, fileRealNames, msg):
114 for file in filesToKeep:
115 # If we have a new file in the cache which we do not want to
116 # commit we have to remove it from the cache. We will add this
117 # cache entry back in to the cache at the end of this
118 # function.
119 if file.change == 'N':
120 runProgram(['git-update-cache', '--force-remove', file.srcName])
121 else:
122 runProgram(['git-update-cache', '--add', '--replace', '--cacheinfo',
123 file.srcMode, file.srcSHA, file.srcName])
125 tree = runProgram(['git-write-tree'])
126 tree = tree.rstrip()
127 commit = runProgram(['git-commit-tree', tree, '-p', 'HEAD'], msg)
128 commit = commit.rstrip()
130 try:
131 f = open(os.environ['GIT_DIR'] + '/HEAD', 'w+')
132 f.write(commit)
133 f.close()
134 except OSError, e:
135 raise CommitError('write to ' + os.environ['GIT_DIR'] + '/HEAD', e.strerror)
137 try:
138 os.unlink(os.environ['GIT_DIR'] + '/MERGE_HEAD')
139 except OSError:
140 pass
142 for file in filesToKeep:
143 # Don't add files that are going to be deleted back to the cache
144 if file.change != 'D':
145 runProgram(['git-update-cache', '--add', '--replace', '--cacheinfo',
146 file.dstMode, file.dstSHA, file.dstName])