summaryrefslogtreecommitdiff
path: root/lib/glider/repository.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/glider/repository.py')
-rw-r--r--lib/glider/repository.py121
1 files changed, 121 insertions, 0 deletions
diff --git a/lib/glider/repository.py b/lib/glider/repository.py
new file mode 100644
index 0000000..9ec1dc6
--- /dev/null
+++ b/lib/glider/repository.py
@@ -0,0 +1,121 @@
+
+import sexp.parse
+import sexp.access
+import glider.formats
+
+import os
+import threading
+
+class RepositoryFile:
+ def __init__(self, repository, relativePath, schema,
+ needRole=None, signedFormat=True, needSigs=1):
+ self._repository = repository
+ self._relativePath = relativePath
+ self._schema = schema
+ self._needRole = needRole
+ self._signedFormat = signedFormat
+ self._needSigs = needSigs
+
+ self._signed_sexpr = None
+ self._main_sexpr = None
+ self._mtime = None
+
+ def getPath(self):
+ return os.path.join(self._repository._root, self._relativePath)
+
+ def _load(self):
+ fname = self.getPath()
+
+ # Propagate OSError
+ f = None
+ fd = os.open(fname, os.O_RDONLY)
+ try:
+ f = os.fdopen(fd, 'r')
+ except:
+ os.close(fd)
+ raise
+ try:
+ mtime = os.fstat(fd).st_mtime
+ content = f.read()
+ finally:
+ f.close()
+
+ signed_sexpr,main_sexpr = self._checkContent(content)
+
+ self._signed_sexpr = signed_sexpr
+ self._main_sexpr = main_sexpr
+ self._mtime = mtime
+
+ def _save(self, content=None):
+ if content == None:
+ content = sexpr.encode
+
+ signed_sexpr,main_sexpr = self._checkContent(content)
+
+ fname = self.getPath()
+ fname_tmp = fname+"_tmp"
+
+ fd = os.open(fname_tmp, os.WRONLY|os.O_CREAT|os.O_TRUNC, 0644)
+ try:
+ os.write(fd, contents)
+ finally:
+ os.close(fd)
+ if sys.platform in ('cygwin', 'win32'):
+ # Win32 doesn't let rename replace an existing file.
+ try:
+ os.unlink(fname)
+ except OSError:
+ pass
+ os.rename(fname_tmp, fname)
+
+ self._signed_sexpr = signed_sexpr
+ self._main_sexpr = main_sexpr
+ self._mtime = mtime
+
+ def _checkContent(self, content):
+ sexpr = sexp.parse.parse(content)
+ if not sexpr:
+ raise ParseError()
+
+ if self._signedFormat:
+ if not glider.formats.SIGNED_SCHEMA.matches(sexpr):
+ raise FormatError()
+
+ sigs = checkSignatures(sexpr, self._repository._keyDB,
+ self._needRole, self._relativePath)
+ good = sigs[0]
+ # XXXX If good is too low but unknown is high, we may need
+ # a new key file.
+ if len(good) < 1:
+ raise SignatureError()
+
+ main_sexpr = sexpr[1]
+ signed_sexpr = sexpr
+ else:
+ signed_sexpr = None
+ main_sexpr = sexpr
+
+ if self._schema != None and not self._schema.matches(main_sexpr):
+ raise FormatError()
+
+ return signed_sexpr, main_sexpr
+
+ def load(self):
+ if self._main_sexpr == None:
+ self._load()
+
+class LocalRepository:
+ def __init__(self, root):
+ self._root = root
+ self._keyDB = None
+
+ self._keylistFile = RepositoryFile(
+ self, "meta/keys.txt", glider.formats.KEYLIST_SCHEMA,
+ needRole="master")
+ self._timestampFile = RepositoryFile(
+ self, "meta/timestamp.txt", glider.formats.TIMESTAMP_SCHEMA,
+ needRole="timestamp")
+ self._mirrorlistFile = RepositoryFile(
+ self, "meta/mirrors.txt", glider.formats.MIRRORLIST_SCHEMA,
+ needRole="mirrors")
+