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