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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
|
# -*- coding: utf-8 -*-
# Copyright: 2009-2011 Gentoo Foundation
# Author(s): Petteri Räty (betelgeuse@gentoo.org)
# License: GPL2
__all__ = ['database']
import errno
import portage
from portage.cache import fs_template
from portage.versions import catsplit
from portage import cpv_getkey
from portage import os
from portage import _encodings
from portage import _unicode_decode
portage.proxy.lazyimport.lazyimport(globals(),
'xattr')
class NoValueException(Exception):
pass
class database(fs_template.FsBased):
autocommits = True
def __init__(self, *args, **config):
super(database,self).__init__(*args, **config)
self.portdir = self.label
self.ns = xattr.NS_USER + '.gentoo.cache'
self.keys = set(self._known_keys)
self.keys.add('_mtime_')
self.keys.add('_eclasses_')
# xattrs have an upper length
self.max_len = self.__get_max()
def __get_max(self):
path = os.path.join(self.portdir,'profiles/repo_name')
try:
return int(self.__get(path,'value_max_len'))
except NoValueException as e:
max = self.__calc_max(path)
self.__set(path,'value_max_len',str(max))
return max
def __calc_max(self,path):
""" Find out max attribute length supported by the file system """
hundred = ''
for i in range(100):
hundred+='a'
s=hundred
# Could use finally but needs python 2.5 then
try:
while True:
self.__set(path,'test_max',s)
s+=hundred
except IOError as e:
# ext based give wrong errno
# http://bugzilla.kernel.org/show_bug.cgi?id=12793
if e.errno in (errno.E2BIG, errno.ENOSPC):
result = len(s)-100
else:
raise
try:
self.__remove(path,'test_max')
except IOError as e:
if e.errno != errno.ENODATA:
raise
return result
def __get_path(self,cpv):
cat,pn = catsplit(cpv_getkey(cpv))
return os.path.join(self.portdir,cat,pn,os.path.basename(cpv) + ".ebuild")
def __has_cache(self,path):
try:
self.__get(path,'_mtime_')
except NoValueException as e:
return False
return True
def __get(self,path,key,default=None):
try:
return xattr.get(path,key,namespace=self.ns)
except IOError as e:
if not default is None and errno.ENODATA == e.errno:
return default
else:
raise NoValueException()
def __remove(self,path,key):
xattr.remove(path,key,namespace=self.ns)
def __set(self,path,key,value):
xattr.set(path,key,value,namespace=self.ns)
def _getitem(self, cpv):
values = {}
path = self.__get_path(cpv)
all = {}
for tuple in xattr.get_all(path,namespace=self.ns):
key,value = tuple
all[key] = value
if not '_mtime_' in all:
raise KeyError(cpv)
# We default to '' like other caches
for key in self.keys:
attr_value = all.get(key,'1:')
parts,sep,value = attr_value.partition(':')
parts = int(parts)
if parts > 1:
for i in range(1,parts):
value += all.get(key+str(i))
values[key] = value
return values
def _setitem(self, cpv, values):
path = self.__get_path(cpv)
max = self.max_len
for key,value in values.items():
# mtime comes in as long so need to convert to strings
s = str(value)
# We need to split long values
value_len = len(s)
parts = 0
if value_len > max:
# Find out how many parts we need
parts = value_len/max
if value_len % max > 0:
parts += 1
# Only the first entry carries the number of parts
self.__set(path,key,'%s:%s'%(parts,s[0:max]))
# Write out the rest
for i in range(1,parts):
start = i * max
val = s[start:start+max]
self.__set(path,key+str(i),val)
else:
self.__set(path,key,"%s:%s"%(1,s))
def _delitem(self, cpv):
pass # Will be gone with the ebuild
def __contains__(self, cpv):
return os.path.exists(self.__get_path(cpv))
def __iter__(self):
for root, dirs, files in os.walk(self.portdir):
for file in files:
try:
file = _unicode_decode(file,
encoding=_encodings['fs'], errors='strict')
except UnicodeDecodeError:
continue
if file[-7:] == '.ebuild':
cat = os.path.basename(os.path.dirname(root))
pn_pv = file[:-7]
path = os.path.join(root,file)
if self.__has_cache(path):
yield "%s/%s/%s" % (cat,os.path.basename(root),file[:-7])
|