summaryrefslogtreecommitdiff
blob: b255b56e255784395dbe090f13c711a5d0ada01a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# Copyright: 2005 Gentoo Foundation
# Author(s): Brian Harring (ferringb@gentoo.org)
# License: GPL2
# $Id: flat_list.py 1911 2005-08-25 03:44:21Z ferringb $

import fs_template
import cache_errors
import errno, os, stat
from mappings import LazyLoad, ProtectedDict
from template import reconstruct_eclasses
# store the current key order *here*.
class database(fs_template.FsBased):

	autocommits = True

	def __init__(self, *args, **config):
		super(database,self).__init__(*args, **config)
		self.location = os.path.join(self.location, 
			self.label.lstrip(os.path.sep).rstrip(os.path.sep))

		if not os.path.exists(self.location):
			self._ensure_dirs()

	def __getitem__(self, cpv):
		fp = os.path.join(self.location, cpv)
		try:
			def curry(*args):
				def callit(*args2):
					return args[0](*args[1:]+args2)
				return callit
			return ProtectedDict(LazyLoad(curry(self._pull, fp, cpv), initial_items=[("_mtime_", os.stat(fp).st_mtime)]))
		except OSError:
			raise KeyError(cpv)
		return self._getitem(cpv)

	def _pull(self, fp, cpv):
		try:
			myf = open(fp,"r")
		except IOError:
			raise KeyError(cpv)
		except OSError, e:
			raise cache_errors.CacheCorruption(cpv, e)
		try:
			d = self._parse_data(myf, cpv)
		except (OSError, ValueError), e:
			myf.close()
			raise cache_errors.CacheCorruption(cpv, e)
		myf.close()
		return d


	def _parse_data(self, data, cpv, mtime=0):
		d = dict(map(lambda x:x.rstrip().split("=", 1), data))
		if mtime != 0:
			d["_mtime_"] = long(mtime)
		if "_eclasses_" in d:
			d["_eclasses_"] = reconstruct_eclasses(cpv, d["_eclasses_"])
		return d
		
		for x in self._known_keys:
			if x not in d:
				d[x] = ''


		return d


	def _setitem(self, cpv, values):
#		import pdb;pdb.set_trace()
		s = cpv.rfind("/")
		fp = os.path.join(self.location,cpv[:s],".update.%i.%s" % (os.getpid(), cpv[s+1:]))
		try:	myf=open(fp, "w")
		except (IOError, OSError), e:
			if errno.ENOENT == e.errno:
				try:
					self._ensure_dirs(cpv)
					myf=open(fp,"w")
				except (OSError, IOError),e:
					raise cache_errors.CacheCorruption(cpv, e)
			else:
				raise cache_errors.CacheCorruption(cpv, e)

		for k, v in values.items():
			if k != "_mtime_" and (k == "_eclasses_" or k in self._known_keys):
				myf.write(("%s=%s\n" % (k, v)).encode("utf-8"))

		myf.close()
		self._ensure_access(fp, mtime=values["_mtime_"])

		#update written.  now we move it.

		new_fp = os.path.join(self.location,cpv)
		try:	os.rename(fp, new_fp)
		except (OSError, IOError), e:
			os.remove(fp)
			raise cache_errors.CacheCorruption(cpv, e)


	def _delitem(self, cpv):
#		import pdb;pdb.set_trace()
		try:
			os.remove(os.path.join(self.location,cpv))
		except OSError, e:
			if errno.ENOENT == e.errno:
				raise KeyError(cpv)
			else:
				raise cache_errors.CacheCorruption(cpv, e)


	def has_key(self, cpv):
		return os.path.exists(os.path.join(self.location, cpv))


	def iterkeys(self):
		"""generator for walking the dir struct"""
		dirs = [self.location]
		len_base = len(self.location)
		while len(dirs):
			for l in os.listdir(dirs[0]):
				if l.endswith(".cpickle"):
					continue
				p = os.path.join(dirs[0],l)
				st = os.lstat(p)
				if stat.S_ISDIR(st.st_mode):
					dirs.append(p)
					continue
				yield p[len_base+1:]
			dirs.pop(0)