blob: b91abc28e82bf45074891987abf86dadb910bdd1 [file] [log] [blame]
Shawn O. Pearced237b692009-04-17 18:49:50 -07001#
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):
Shawn O. Pearce0f3dd232009-04-17 20:32:44 -070034 self._EnsureLoaded()
Shawn O. Pearced237b692009-04-17 18:49:50 -070035 return self._phyref
36
37 def get(self, name):
38 try:
39 return self.all[name]
40 except KeyError:
41 return ''
42
Shawn O. Pearcefbcde472009-04-17 20:58:02 -070043 def deleted(self, name):
44 if self._phyref is not None:
45 if name in self._phyref:
46 del self._phyref[name]
47
48 if name in self._symref:
49 del self._symref[name]
50
51 if name in self._mtime:
52 del self._mtime[name]
53
Shawn O. Pearce0f3dd232009-04-17 20:32:44 -070054 def symref(self, name):
55 try:
56 self._EnsureLoaded()
57 return self._symref[name]
58 except KeyError:
59 return ''
60
61 def _EnsureLoaded(self):
62 if self._phyref is None or self._NeedUpdate():
63 self._LoadAll()
64
Shawn O. Pearced237b692009-04-17 18:49:50 -070065 def _NeedUpdate(self):
66 for name, mtime in self._mtime.iteritems():
67 try:
68 if mtime != os.path.getmtime(os.path.join(self._gitdir, name)):
69 return True
70 except OSError:
71 return True
72 return False
73
74 def _LoadAll(self):
75 self._phyref = {}
76 self._symref = {}
77 self._mtime = {}
78
79 self._ReadPackedRefs()
80 self._ReadLoose('refs/')
81 self._ReadLoose1(os.path.join(self._gitdir, HEAD), HEAD)
82
83 scan = self._symref
84 attempts = 0
85 while scan and attempts < 5:
86 scan_next = {}
87 for name, dest in scan.iteritems():
88 if dest in self._phyref:
89 self._phyref[name] = self._phyref[dest]
90 else:
91 scan_next[name] = dest
92 scan = scan_next
93 attempts += 1
94
95 def _ReadPackedRefs(self):
96 path = os.path.join(self._gitdir, 'packed-refs')
97 try:
98 fd = open(path, 'r')
99 mtime = os.path.getmtime(path)
100 except IOError:
101 return
102 except OSError:
103 return
104 try:
105 for line in fd:
106 if line[0] == '#':
107 continue
108 if line[0] == '^':
109 continue
110
111 line = line[:-1]
112 p = line.split(' ')
113 id = p[0]
114 name = p[1]
115
116 self._phyref[name] = id
117 finally:
118 fd.close()
119 self._mtime['packed-refs'] = mtime
120
121 def _ReadLoose(self, prefix):
122 base = os.path.join(self._gitdir, prefix)
123 for name in os.listdir(base):
124 p = os.path.join(base, name)
125 if os.path.isdir(p):
126 self._mtime[prefix] = os.path.getmtime(base)
127 self._ReadLoose(prefix + name + '/')
128 elif name.endswith('.lock'):
129 pass
130 else:
131 self._ReadLoose1(p, prefix + name)
132
133 def _ReadLoose1(self, path, name):
134 try:
135 fd = open(path, 'r')
136 mtime = os.path.getmtime(path)
137 except OSError:
138 return
139 except IOError:
140 return
141 try:
142 id = fd.readline()
143 finally:
144 fd.close()
145
146 if not id:
147 return
148 id = id[:-1]
149
150 if id.startswith('ref: '):
151 self._symref[name] = id[5:]
152 else:
153 self._phyref[name] = id
154 self._mtime[name] = mtime