1 |
Author: zmedico |
2 |
Date: 2009-03-01 20:39:41 +0000 (Sun, 01 Mar 2009) |
3 |
New Revision: 12737 |
4 |
|
5 |
Added: |
6 |
main/trunk/pym/portage/cache/ebuild_xattr.py |
7 |
Log: |
8 |
Thanks to Petteri R?\195?\164ty <betelgeuse@g.o> for this new cache module which |
9 |
uses extended attributes (via pyxattr) to attach metadata cache directly to |
10 |
the ebuild files themselves. |
11 |
|
12 |
|
13 |
Added: main/trunk/pym/portage/cache/ebuild_xattr.py |
14 |
=================================================================== |
15 |
--- main/trunk/pym/portage/cache/ebuild_xattr.py (rev 0) |
16 |
+++ main/trunk/pym/portage/cache/ebuild_xattr.py 2009-03-01 20:39:41 UTC (rev 12737) |
17 |
@@ -0,0 +1,163 @@ |
18 |
+# -*- coding: UTF8 -*- |
19 |
+# Copyright: 2009 Gentoo Foundation |
20 |
+# Author(s): Petteri Räty (betelgeuse@g.o) |
21 |
+# License: GPL2 |
22 |
+# $Id$ |
23 |
+ |
24 |
+__all__ = ['database'] |
25 |
+ |
26 |
+from portage.cache import fs_template |
27 |
+from portage.versions import catsplit |
28 |
+from portage import cpv_getkey |
29 |
+from portage.util import writemsg |
30 |
+import os |
31 |
+import xattr |
32 |
+from errno import ENODATA,ENOSPC,E2BIG |
33 |
+ |
34 |
+class NoValueException(Exception): |
35 |
+ pass |
36 |
+ |
37 |
+class database(fs_template.FsBased): |
38 |
+ |
39 |
+ autocommits = True |
40 |
+ |
41 |
+ def __init__(self, *args, **config): |
42 |
+ super(database,self).__init__(*args, **config) |
43 |
+ self.portdir = self.label |
44 |
+ self.ns = xattr.NS_USER + '.gentoo.cache' |
45 |
+ self.keys = set(self._known_keys) |
46 |
+ self.keys.add('_mtime_') |
47 |
+ self.keys.add('_eclasses_') |
48 |
+ # xattrs have an upper length |
49 |
+ self.max_len = self.__get_max() |
50 |
+ |
51 |
+ def __get_max(self): |
52 |
+ path = os.path.join(self.portdir,'profiles/repo_name') |
53 |
+ try: |
54 |
+ return int(self.__get(path,'value_max_len')) |
55 |
+ except NoValueException,e: |
56 |
+ max = self.__calc_max(path) |
57 |
+ self.__set(path,'value_max_len',str(max)) |
58 |
+ return max |
59 |
+ |
60 |
+ def __calc_max(self,path): |
61 |
+ """ Find out max attribute length supported by the file system """ |
62 |
+ |
63 |
+ hundred = '' |
64 |
+ for i in range(100): |
65 |
+ hundred+='a' |
66 |
+ |
67 |
+ s=hundred |
68 |
+ |
69 |
+ # Could use finally but needs python 2.5 then |
70 |
+ try: |
71 |
+ while True: |
72 |
+ self.__set(path,'test_max',s) |
73 |
+ s+=hundred |
74 |
+ except IOError,e: |
75 |
+ # ext based give wrong errno |
76 |
+ # http://bugzilla.kernel.org/show_bug.cgi?id=12793 |
77 |
+ if e.errno in (E2BIG,ENOSPC): |
78 |
+ result = len(s)-100 |
79 |
+ else: |
80 |
+ raise e |
81 |
+ |
82 |
+ try: |
83 |
+ self.__remove(path,'test_max') |
84 |
+ except IOError,e: |
85 |
+ if e.errno is not ENODATA: |
86 |
+ raise e |
87 |
+ |
88 |
+ return result |
89 |
+ |
90 |
+ def __get_path(self,cpv): |
91 |
+ cat,pn = catsplit(cpv_getkey(cpv)) |
92 |
+ return os.path.join(self.portdir,cat,pn,os.path.basename(cpv) + ".ebuild") |
93 |
+ |
94 |
+ def __has_cache(self,path): |
95 |
+ try: |
96 |
+ self.__get(path,'_mtime_') |
97 |
+ except NoValueException,e: |
98 |
+ return False |
99 |
+ |
100 |
+ return True |
101 |
+ |
102 |
+ def __get(self,path,key,default=None): |
103 |
+ try: |
104 |
+ return xattr.get(path,key,namespace=self.ns) |
105 |
+ except IOError,e: |
106 |
+ if not default is None and ENODATA == e.errno: |
107 |
+ return default |
108 |
+ else: |
109 |
+ raise NoValueException() |
110 |
+ |
111 |
+ def __remove(self,path,key): |
112 |
+ xattr.remove(path,key,namespace=self.ns) |
113 |
+ |
114 |
+ def __set(self,path,key,value): |
115 |
+ xattr.set(path,key,value,namespace=self.ns) |
116 |
+ |
117 |
+ def _getitem(self, cpv): |
118 |
+ values = {} |
119 |
+ path = self.__get_path(cpv) |
120 |
+ all = {} |
121 |
+ for tuple in xattr.get_all(path,namespace=self.ns): |
122 |
+ key,value = tuple |
123 |
+ all[key] = value |
124 |
+ |
125 |
+ if not '_mtime_' in all: |
126 |
+ raise KeyError(cpv) |
127 |
+ |
128 |
+ # We default to '' like other caches |
129 |
+ for key in self.keys: |
130 |
+ attr_value = all.get(key,'1:') |
131 |
+ parts,sep,value = attr_value.partition(':') |
132 |
+ parts = int(parts) |
133 |
+ if parts > 1: |
134 |
+ for i in range(1,parts): |
135 |
+ value += all.get(key+str(i)) |
136 |
+ values[key] = value |
137 |
+ |
138 |
+ return values |
139 |
+ |
140 |
+ def _setitem(self, cpv, values): |
141 |
+ path = self.__get_path(cpv) |
142 |
+ max = self.max_len |
143 |
+ for key,value in values.iteritems(): |
144 |
+ # mtime comes in as long so need to convert to strings |
145 |
+ s = str(value) |
146 |
+ # We need to split long values |
147 |
+ value_len = len(s) |
148 |
+ parts = 0 |
149 |
+ if value_len > max: |
150 |
+ # Find out how many parts we need |
151 |
+ parts = value_len/max |
152 |
+ if value_len % max > 0: |
153 |
+ parts += 1 |
154 |
+ |
155 |
+ # Only the first entry carries the number of parts |
156 |
+ self.__set(path,key,'%s:%s'%(parts,s[0:max])) |
157 |
+ |
158 |
+ # Write out the rest |
159 |
+ for i in range(1,parts): |
160 |
+ start = i * max |
161 |
+ val = s[start:start+max] |
162 |
+ self.__set(path,key+str(i),val) |
163 |
+ else: |
164 |
+ self.__set(path,key,"%s:%s"%(1,s)) |
165 |
+ |
166 |
+ def _delitem(self, cpv): |
167 |
+ pass # Will be gone with the ebuild |
168 |
+ |
169 |
+ def __contains__(self, cpv): |
170 |
+ return os.path.exists(self.__get_path(cpv)) |
171 |
+ |
172 |
+ def __iter__(self): |
173 |
+ for root,dirs,files in os.walk(self.portdir): |
174 |
+ for file in files: |
175 |
+ if file[-7:] == '.ebuild': |
176 |
+ cat = os.path.basename(os.path.dirname(root)) |
177 |
+ pn_pv = file[:-7] |
178 |
+ path = os.path.join(root,file) |
179 |
+ if self.__has_cache(path): |
180 |
+ yield "%s/%s/%s" % (cat,os.path.basename(root),file[:-7]) |
181 |
|
182 |
|
183 |
Property changes on: main/trunk/pym/portage/cache/ebuild_xattr.py |
184 |
___________________________________________________________________ |
185 |
Name: svn:keywords |
186 |
+ Id |