summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--git_refs.py133
-rw-r--r--project.py30
2 files changed, 137 insertions, 26 deletions
diff --git a/git_refs.py b/git_refs.py
new file mode 100644
index 00000000..9851e78b
--- /dev/null
+++ b/git_refs.py
@@ -0,0 +1,133 @@
1#
2# Copyright (C) 2009 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16import os
17
18HEAD = 'HEAD'
19R_HEADS = 'refs/heads/'
20R_TAGS = 'refs/tags/'
21R_PUB = 'refs/published/'
22R_M = 'refs/remotes/m/'
23
24
25class GitRefs(object):
26 def __init__(self, gitdir):
27 self._gitdir = gitdir
28 self._phyref = None
29 self._symref = None
30 self._mtime = {}
31
32 @property
33 def all(self):
34 if self._phyref is None or self._NeedUpdate():
35 self._LoadAll()
36 return self._phyref
37
38 def get(self, name):
39 try:
40 return self.all[name]
41 except KeyError:
42 return ''
43
44 def _NeedUpdate(self):
45 for name, mtime in self._mtime.iteritems():
46 try:
47 if mtime != os.path.getmtime(os.path.join(self._gitdir, name)):
48 return True
49 except OSError:
50 return True
51 return False
52
53 def _LoadAll(self):
54 self._phyref = {}
55 self._symref = {}
56 self._mtime = {}
57
58 self._ReadPackedRefs()
59 self._ReadLoose('refs/')
60 self._ReadLoose1(os.path.join(self._gitdir, HEAD), HEAD)
61
62 scan = self._symref
63 attempts = 0
64 while scan and attempts < 5:
65 scan_next = {}
66 for name, dest in scan.iteritems():
67 if dest in self._phyref:
68 self._phyref[name] = self._phyref[dest]
69 else:
70 scan_next[name] = dest
71 scan = scan_next
72 attempts += 1
73
74 def _ReadPackedRefs(self):
75 path = os.path.join(self._gitdir, 'packed-refs')
76 try:
77 fd = open(path, 'r')
78 mtime = os.path.getmtime(path)
79 except IOError:
80 return
81 except OSError:
82 return
83 try:
84 for line in fd:
85 if line[0] == '#':
86 continue
87 if line[0] == '^':
88 continue
89
90 line = line[:-1]
91 p = line.split(' ')
92 id = p[0]
93 name = p[1]
94
95 self._phyref[name] = id
96 finally:
97 fd.close()
98 self._mtime['packed-refs'] = mtime
99
100 def _ReadLoose(self, prefix):
101 base = os.path.join(self._gitdir, prefix)
102 for name in os.listdir(base):
103 p = os.path.join(base, name)
104 if os.path.isdir(p):
105 self._mtime[prefix] = os.path.getmtime(base)
106 self._ReadLoose(prefix + name + '/')
107 elif name.endswith('.lock'):
108 pass
109 else:
110 self._ReadLoose1(p, prefix + name)
111
112 def _ReadLoose1(self, path, name):
113 try:
114 fd = open(path, 'r')
115 mtime = os.path.getmtime(path)
116 except OSError:
117 return
118 except IOError:
119 return
120 try:
121 id = fd.readline()
122 finally:
123 fd.close()
124
125 if not id:
126 return
127 id = id[:-1]
128
129 if id.startswith('ref: '):
130 self._symref[name] = id[5:]
131 else:
132 self._phyref[name] = id
133 self._mtime[name] = mtime
diff --git a/project.py b/project.py
index 311379ca..086f0d77 100644
--- a/project.py
+++ b/project.py
@@ -28,11 +28,7 @@ from error import GitError, ImportError, UploadError
28from error import ManifestInvalidRevisionError 28from error import ManifestInvalidRevisionError
29from remote import Remote 29from remote import Remote
30 30
31HEAD = 'HEAD' 31from git_refs import GitRefs, HEAD, R_HEADS, R_TAGS, R_PUB, R_M
32R_HEADS = 'refs/heads/'
33R_TAGS = 'refs/tags/'
34R_PUB = 'refs/published/'
35R_M = 'refs/remotes/m/'
36 32
37def _error(fmt, *args): 33def _error(fmt, *args):
38 msg = fmt % args 34 msg = fmt % args
@@ -226,6 +222,7 @@ class Project(object):
226 else: 222 else:
227 self.work_git = None 223 self.work_git = None
228 self.bare_git = self._GitGetByExec(self, bare=True) 224 self.bare_git = self._GitGetByExec(self, bare=True)
225 self.bare_ref = GitRefs(gitdir)
229 226
230 @property 227 @property
231 def Exists(self): 228 def Exists(self):
@@ -301,7 +298,7 @@ class Project(object):
301 """Get all existing local branches. 298 """Get all existing local branches.
302 """ 299 """
303 current = self.CurrentBranch 300 current = self.CurrentBranch
304 all = self.bare_git.ListRefs() 301 all = self._allrefs
305 heads = {} 302 heads = {}
306 pubd = {} 303 pubd = {}
307 304
@@ -1030,32 +1027,13 @@ class Project(object):
1030 1027
1031 @property 1028 @property
1032 def _allrefs(self): 1029 def _allrefs(self):
1033 return self.bare_git.ListRefs() 1030 return self.bare_ref.all
1034 1031
1035 class _GitGetByExec(object): 1032 class _GitGetByExec(object):
1036 def __init__(self, project, bare): 1033 def __init__(self, project, bare):
1037 self._project = project 1034 self._project = project
1038 self._bare = bare 1035 self._bare = bare
1039 1036
1040 def ListRefs(self, *args):
1041 cmdv = ['for-each-ref', '--format=%(objectname) %(refname)']
1042 cmdv.extend(args)
1043 p = GitCommand(self._project,
1044 cmdv,
1045 bare = self._bare,
1046 capture_stdout = True,
1047 capture_stderr = True)
1048 r = {}
1049 for line in p.process.stdout:
1050 id, name = line[:-1].split(' ', 2)
1051 r[name] = id
1052 if p.Wait() != 0:
1053 raise GitError('%s for-each-ref %s: %s' % (
1054 self._project.name,
1055 str(args),
1056 p.stderr))
1057 return r
1058
1059 def LsOthers(self): 1037 def LsOthers(self):
1060 p = GitCommand(self._project, 1038 p = GitCommand(self._project,
1061 ['ls-files', 1039 ['ls-files',