|
|
@@ -0,0 +1,133 @@
|
|
|
+#
|
|
|
+# Copyright (C) 2009 The Android Open Source Project
|
|
|
+#
|
|
|
+# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
+# you may not use this file except in compliance with the License.
|
|
|
+# You may obtain a copy of the License at
|
|
|
+#
|
|
|
+# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
+#
|
|
|
+# Unless required by applicable law or agreed to in writing, software
|
|
|
+# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
+# See the License for the specific language governing permissions and
|
|
|
+# limitations under the License.
|
|
|
+
|
|
|
+import os
|
|
|
+
|
|
|
+HEAD = 'HEAD'
|
|
|
+R_HEADS = 'refs/heads/'
|
|
|
+R_TAGS = 'refs/tags/'
|
|
|
+R_PUB = 'refs/published/'
|
|
|
+R_M = 'refs/remotes/m/'
|
|
|
+
|
|
|
+
|
|
|
+class GitRefs(object):
|
|
|
+ def __init__(self, gitdir):
|
|
|
+ self._gitdir = gitdir
|
|
|
+ self._phyref = None
|
|
|
+ self._symref = None
|
|
|
+ self._mtime = {}
|
|
|
+
|
|
|
+ @property
|
|
|
+ def all(self):
|
|
|
+ if self._phyref is None or self._NeedUpdate():
|
|
|
+ self._LoadAll()
|
|
|
+ return self._phyref
|
|
|
+
|
|
|
+ def get(self, name):
|
|
|
+ try:
|
|
|
+ return self.all[name]
|
|
|
+ except KeyError:
|
|
|
+ return ''
|
|
|
+
|
|
|
+ def _NeedUpdate(self):
|
|
|
+ for name, mtime in self._mtime.iteritems():
|
|
|
+ try:
|
|
|
+ if mtime != os.path.getmtime(os.path.join(self._gitdir, name)):
|
|
|
+ return True
|
|
|
+ except OSError:
|
|
|
+ return True
|
|
|
+ return False
|
|
|
+
|
|
|
+ def _LoadAll(self):
|
|
|
+ self._phyref = {}
|
|
|
+ self._symref = {}
|
|
|
+ self._mtime = {}
|
|
|
+
|
|
|
+ self._ReadPackedRefs()
|
|
|
+ self._ReadLoose('refs/')
|
|
|
+ self._ReadLoose1(os.path.join(self._gitdir, HEAD), HEAD)
|
|
|
+
|
|
|
+ scan = self._symref
|
|
|
+ attempts = 0
|
|
|
+ while scan and attempts < 5:
|
|
|
+ scan_next = {}
|
|
|
+ for name, dest in scan.iteritems():
|
|
|
+ if dest in self._phyref:
|
|
|
+ self._phyref[name] = self._phyref[dest]
|
|
|
+ else:
|
|
|
+ scan_next[name] = dest
|
|
|
+ scan = scan_next
|
|
|
+ attempts += 1
|
|
|
+
|
|
|
+ def _ReadPackedRefs(self):
|
|
|
+ path = os.path.join(self._gitdir, 'packed-refs')
|
|
|
+ try:
|
|
|
+ fd = open(path, 'r')
|
|
|
+ mtime = os.path.getmtime(path)
|
|
|
+ except IOError:
|
|
|
+ return
|
|
|
+ except OSError:
|
|
|
+ return
|
|
|
+ try:
|
|
|
+ for line in fd:
|
|
|
+ if line[0] == '#':
|
|
|
+ continue
|
|
|
+ if line[0] == '^':
|
|
|
+ continue
|
|
|
+
|
|
|
+ line = line[:-1]
|
|
|
+ p = line.split(' ')
|
|
|
+ id = p[0]
|
|
|
+ name = p[1]
|
|
|
+
|
|
|
+ self._phyref[name] = id
|
|
|
+ finally:
|
|
|
+ fd.close()
|
|
|
+ self._mtime['packed-refs'] = mtime
|
|
|
+
|
|
|
+ def _ReadLoose(self, prefix):
|
|
|
+ base = os.path.join(self._gitdir, prefix)
|
|
|
+ for name in os.listdir(base):
|
|
|
+ p = os.path.join(base, name)
|
|
|
+ if os.path.isdir(p):
|
|
|
+ self._mtime[prefix] = os.path.getmtime(base)
|
|
|
+ self._ReadLoose(prefix + name + '/')
|
|
|
+ elif name.endswith('.lock'):
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ self._ReadLoose1(p, prefix + name)
|
|
|
+
|
|
|
+ def _ReadLoose1(self, path, name):
|
|
|
+ try:
|
|
|
+ fd = open(path, 'r')
|
|
|
+ mtime = os.path.getmtime(path)
|
|
|
+ except OSError:
|
|
|
+ return
|
|
|
+ except IOError:
|
|
|
+ return
|
|
|
+ try:
|
|
|
+ id = fd.readline()
|
|
|
+ finally:
|
|
|
+ fd.close()
|
|
|
+
|
|
|
+ if not id:
|
|
|
+ return
|
|
|
+ id = id[:-1]
|
|
|
+
|
|
|
+ if id.startswith('ref: '):
|
|
|
+ self._symref[name] = id[5:]
|
|
|
+ else:
|
|
|
+ self._phyref[name] = id
|
|
|
+ self._mtime[name] = mtime
|