blob: 4dd687695d957c1ab314dd472c83d4981071fddd [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
Shawn O. Pearcead3193a2009-04-18 09:54:51 -070017from trace import Trace
Shawn O. Pearced237b692009-04-17 18:49:50 -070018
19HEAD = 'HEAD'
20R_HEADS = 'refs/heads/'
21R_TAGS = 'refs/tags/'
22R_PUB = 'refs/published/'
23R_M = 'refs/remotes/m/'
24
25
26class GitRefs(object):
27 def __init__(self, gitdir):
28 self._gitdir = gitdir
29 self._phyref = None
30 self._symref = None
31 self._mtime = {}
32
33 @property
34 def all(self):
Shawn O. Pearce0f3dd232009-04-17 20:32:44 -070035 self._EnsureLoaded()
Shawn O. Pearced237b692009-04-17 18:49:50 -070036 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. Pearce0f3dd232009-04-17 20:32:44 -070055 def symref(self, name):
56 try:
57 self._EnsureLoaded()
58 return self._symref[name]
59 except KeyError:
60 return ''
61
62 def _EnsureLoaded(self):
63 if self._phyref is None or self._NeedUpdate():
64 self._LoadAll()
65
Shawn O. Pearced237b692009-04-17 18:49:50 -070066 def _NeedUpdate(self):
Shawn O. Pearcead3193a2009-04-18 09:54:51 -070067 Trace(': scan refs %s', self._gitdir)
68
Chirayu Desai217ea7d2013-03-01 19:14:38 +053069 for name, mtime in self._mtime.items():
Shawn O. Pearced237b692009-04-17 18:49:50 -070070 try:
71 if mtime != os.path.getmtime(os.path.join(self._gitdir, name)):
72 return True
73 except OSError:
74 return True
75 return False
76
77 def _LoadAll(self):
Shawn O. Pearcead3193a2009-04-18 09:54:51 -070078 Trace(': load refs %s', self._gitdir)
79
Shawn O. Pearced237b692009-04-17 18:49:50 -070080 self._phyref = {}
81 self._symref = {}
82 self._mtime = {}
83
84 self._ReadPackedRefs()
85 self._ReadLoose('refs/')
86 self._ReadLoose1(os.path.join(self._gitdir, HEAD), HEAD)
87
88 scan = self._symref
89 attempts = 0
90 while scan and attempts < 5:
91 scan_next = {}
Chirayu Desai217ea7d2013-03-01 19:14:38 +053092 for name, dest in scan.items():
Shawn O. Pearced237b692009-04-17 18:49:50 -070093 if dest in self._phyref:
94 self._phyref[name] = self._phyref[dest]
95 else:
96 scan_next[name] = dest
97 scan = scan_next
98 attempts += 1
99
100 def _ReadPackedRefs(self):
101 path = os.path.join(self._gitdir, 'packed-refs')
102 try:
Shawn O. Pearce76ca9f82009-04-18 14:48:03 -0700103 fd = open(path, 'rb')
Shawn O. Pearced237b692009-04-17 18:49:50 -0700104 mtime = os.path.getmtime(path)
105 except IOError:
106 return
107 except OSError:
108 return
109 try:
110 for line in fd:
Chirayu Desai217ea7d2013-03-01 19:14:38 +0530111 line = str(line)
Shawn O. Pearced237b692009-04-17 18:49:50 -0700112 if line[0] == '#':
113 continue
114 if line[0] == '^':
115 continue
116
117 line = line[:-1]
118 p = line.split(' ')
David Pursehouse8a68ff92012-09-24 12:15:13 +0900119 ref_id = p[0]
Shawn O. Pearced237b692009-04-17 18:49:50 -0700120 name = p[1]
121
David Pursehouse8a68ff92012-09-24 12:15:13 +0900122 self._phyref[name] = ref_id
Shawn O. Pearced237b692009-04-17 18:49:50 -0700123 finally:
124 fd.close()
125 self._mtime['packed-refs'] = mtime
126
127 def _ReadLoose(self, prefix):
128 base = os.path.join(self._gitdir, prefix)
129 for name in os.listdir(base):
130 p = os.path.join(base, name)
131 if os.path.isdir(p):
132 self._mtime[prefix] = os.path.getmtime(base)
133 self._ReadLoose(prefix + name + '/')
134 elif name.endswith('.lock'):
135 pass
136 else:
137 self._ReadLoose1(p, prefix + name)
138
139 def _ReadLoose1(self, path, name):
140 try:
Shawn O. Pearce76ca9f82009-04-18 14:48:03 -0700141 fd = open(path, 'rb')
David Pursehouse1d947b32012-10-25 12:23:11 +0900142 except IOError:
Shawn O. Pearced237b692009-04-17 18:49:50 -0700143 return
Shawn O. Pearcecc14fa92011-11-29 12:32:56 -0800144
Shawn O. Pearced237b692009-04-17 18:49:50 -0700145 try:
Shawn O. Pearcecc14fa92011-11-29 12:32:56 -0800146 try:
147 mtime = os.path.getmtime(path)
David Pursehouse8a68ff92012-09-24 12:15:13 +0900148 ref_id = fd.readline()
David Pursehouse1d947b32012-10-25 12:23:11 +0900149 except (IOError, OSError):
Shawn O. Pearcecc14fa92011-11-29 12:32:56 -0800150 return
Shawn O. Pearced237b692009-04-17 18:49:50 -0700151 finally:
152 fd.close()
153
Chirayu Desai217ea7d2013-03-01 19:14:38 +0530154 try:
155 ref_id = ref_id.decode()
156 except AttributeError:
157 pass
David Pursehouse8a68ff92012-09-24 12:15:13 +0900158 if not ref_id:
Shawn O. Pearced237b692009-04-17 18:49:50 -0700159 return
David Pursehouse8a68ff92012-09-24 12:15:13 +0900160 ref_id = ref_id[:-1]
Shawn O. Pearced237b692009-04-17 18:49:50 -0700161
David Pursehouse8a68ff92012-09-24 12:15:13 +0900162 if ref_id.startswith('ref: '):
163 self._symref[name] = ref_id[5:]
Shawn O. Pearced237b692009-04-17 18:49:50 -0700164 else:
David Pursehouse8a68ff92012-09-24 12:15:13 +0900165 self._phyref[name] = ref_id
Shawn O. Pearced237b692009-04-17 18:49:50 -0700166 self._mtime[name] = mtime