1 |
commit: 34861f2cd5d5db7ca3ba99a8bc62ab5e75bbfd34 |
2 |
Author: André Erdmann <dywi <AT> mailerd <DOT> de> |
3 |
AuthorDate: Fri Jul 20 16:14:04 2012 +0000 |
4 |
Commit: André Erdmann <dywi <AT> mailerd <DOT> de> |
5 |
CommitDate: Fri Jul 20 16:14:04 2012 +0000 |
6 |
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=34861f2c |
7 |
|
8 |
incremental overlay writing (#3) |
9 |
|
10 |
* Ebuilds can now be written incrementally (but without deletion of old ebuilds) |
11 |
* Can now create dependency rules for scanned ebuilds / ebuilds in the overlay |
12 |
* Ebuilds will now only be created if necessary (= does not already exist as file |
13 |
or Manifest is missing). This will later be configurable. |
14 |
|
15 |
geändert: roverlay.py |
16 |
geändert: roverlay/overlay/category.py |
17 |
geändert: roverlay/overlay/creator.py |
18 |
neue Datei: roverlay/overlay/header.py |
19 |
geändert: roverlay/overlay/package.py |
20 |
geändert: roverlay/overlay/root.py |
21 |
geändert: roverlay/packageinfo.py |
22 |
|
23 |
--- |
24 |
roverlay.py | 6 +- |
25 |
roverlay/overlay/category.py | 202 ++++++++++++++++++++++-------------------- |
26 |
roverlay/overlay/creator.py | 78 ++++++++-------- |
27 |
roverlay/overlay/header.py | 37 ++++++++ |
28 |
roverlay/overlay/package.py | 147 +++++++++++++++++-------------- |
29 |
roverlay/overlay/root.py | 96 +++++++------------- |
30 |
roverlay/packageinfo.py | 7 +- |
31 |
7 files changed, 304 insertions(+), 269 deletions(-) |
32 |
|
33 |
diff --git a/roverlay.py b/roverlay.py |
34 |
index ae67d6a..3504fab 100755 |
35 |
--- a/roverlay.py |
36 |
+++ b/roverlay.py |
37 |
@@ -221,9 +221,7 @@ def run_overlay_create(): |
38 |
#run_sync() |
39 |
try: |
40 |
global overlay |
41 |
- overlay = OverlayCreator() |
42 |
- # explicitly allow overlay writing (FIXME: remove that in OverlayCreator) |
43 |
- overlay.can_write_overlay = OPTION ( 'write_overlay' ) |
44 |
+ overlay = OverlayCreator ( allow_write=OPTION ( 'write_overlay' ) ) |
45 |
|
46 |
repo_list.add_packages ( overlay.add_package ) |
47 |
|
48 |
@@ -259,6 +257,6 @@ if 'create' in actions: run_overlay_create() |
49 |
|
50 |
if len ( actions ) > len ( actions_done ): |
51 |
die ( |
52 |
- "Some actions (out of %r) could not be performed!" % actions, |
53 |
+ "Some actions (out of {!r}) could not be performed!".format ( actions ), |
54 |
DIE.CMD_LEFTOVER |
55 |
) |
56 |
|
57 |
diff --git a/roverlay/overlay/category.py b/roverlay/overlay/category.py |
58 |
index 9cf8ad9..1d0bf97 100644 |
59 |
--- a/roverlay/overlay/category.py |
60 |
+++ b/roverlay/overlay/category.py |
61 |
@@ -18,73 +18,39 @@ class Category ( object ): |
62 |
|
63 |
WRITE_JOBCOUNT = 3 |
64 |
|
65 |
- def __init__ ( self, name, logger, directory ): |
66 |
+ def __init__ ( self, name, logger, directory, get_header, incremental ): |
67 |
"""Initializes a overlay/portage category (such as 'app-text', 'sci-R'). |
68 |
|
69 |
arguments: |
70 |
- * name -- name of the category |
71 |
- * logger -- parent logger |
72 |
- * directory -- filesystem location |
73 |
+ * name -- name of the category |
74 |
+ * logger -- parent logger |
75 |
+ * directory -- filesystem location |
76 |
+ * get_header -- function that returns an ebuild header |
77 |
""" |
78 |
self.logger = logger.getChild ( name ) |
79 |
self.name = name |
80 |
self._lock = threading.RLock() |
81 |
self._subdirs = dict() |
82 |
self.physical_location = directory |
83 |
+ self.get_header = get_header |
84 |
+ self.incremental = incremental |
85 |
# --- end of __init__ (...) --- |
86 |
|
87 |
- def has ( self, subdir ): |
88 |
- return subdir in self._subdirs |
89 |
- # --- end of has (...) --- |
90 |
- |
91 |
- def list_packages ( self, print_category=True ): |
92 |
- if print_category: |
93 |
- for package in self._subdirs.keys(): |
94 |
- yield self.name + os.sep + package |
95 |
- else: |
96 |
- for package in self._subdirs.keys(): |
97 |
- yield package |
98 |
- # --- end of list_packages (...) --- |
99 |
- |
100 |
- def has_dir ( self, _dir ): |
101 |
- return os.path.isdir ( self.physical_location + os.sep + _dir ) |
102 |
- # --- end of has_category (...) --- |
103 |
- |
104 |
- def _scan_packages ( self ): |
105 |
- for x in os.listdir ( self.physical_location ): |
106 |
- if self.has_dir ( x ): |
107 |
- yield self._get_package_dir ( x ) |
108 |
- # --- end of _scan_packages (...) --- |
109 |
- |
110 |
- def scan ( self, **kw ): |
111 |
- for pkg in self._scan_packages(): |
112 |
- pkg.scan ( **kw ) |
113 |
- # --- end of scan (...) --- |
114 |
- |
115 |
- def empty ( self ): |
116 |
- """Returns True if this category contains 0 ebuilds.""" |
117 |
- return \ |
118 |
- len ( self._subdirs ) == 0 or \ |
119 |
- not False in ( d.empty() for d in self._subdirs.values() ) |
120 |
- # --- end of empty (...) --- |
121 |
- |
122 |
- def finalize_write_incremental ( self ): |
123 |
- for subdir in self._subdirs.values(): |
124 |
- if subdir.modified: |
125 |
- subdir.write_incremental() |
126 |
- subdir.finalize_write_incremental() |
127 |
- # --- end of finalize_write_incremental (...) --- |
128 |
- |
129 |
def _get_package_dir ( self, pkg_name ): |
130 |
if not pkg_name in self._subdirs: |
131 |
self._lock.acquire() |
132 |
try: |
133 |
if not pkg_name in self._subdirs: |
134 |
- self._subdirs [pkg_name] = PackageDir ( |
135 |
- pkg_name, |
136 |
- self.logger, |
137 |
- self.physical_location + os.sep + pkg_name |
138 |
+ newpkg = PackageDir ( |
139 |
+ name = pkg_name, |
140 |
+ logger = self.logger, |
141 |
+ directory = self.physical_location + os.sep + pkg_name, |
142 |
+ get_header = self.get_header, |
143 |
+ incremental = self.incremental |
144 |
) |
145 |
+ self._subdirs [pkg_name] = newpkg |
146 |
+ if self.incremental: |
147 |
+ roverlay.util.dodir ( newpkg.physical_location ) |
148 |
finally: |
149 |
self._lock.release() |
150 |
|
151 |
@@ -103,6 +69,20 @@ class Category ( object ): |
152 |
return subdir.add ( package_info, **pkg_add_kw ) |
153 |
# --- end of add (...) --- |
154 |
|
155 |
+ def empty ( self ): |
156 |
+ """Returns True if this category contains 0 ebuilds.""" |
157 |
+ return \ |
158 |
+ len ( self._subdirs ) == 0 or \ |
159 |
+ not False in ( d.empty() for d in self._subdirs.values() ) |
160 |
+ # --- end of empty (...) --- |
161 |
+ |
162 |
+ def finalize_write_incremental ( self ): |
163 |
+ for subdir in self._subdirs.values(): |
164 |
+ if subdir.modified: |
165 |
+ subdir.write_incremental() |
166 |
+ subdir.finalize_write_incremental() |
167 |
+ # --- end of finalize_write_incremental (...) --- |
168 |
+ |
169 |
def generate_metadata ( self, **metadata_kw ): |
170 |
"""Generates metadata for all packages in this category. |
171 |
Metadata are automatically generated when calling write(). |
172 |
@@ -116,18 +96,39 @@ class Category ( object ): |
173 |
package.generate_metadata ( **metadata_kw ) |
174 |
# --- end of generate_metadata (...) --- |
175 |
|
176 |
- def write_manifest ( self, **manifest_kw ): |
177 |
- """Generates Manifest files for all packages in this category. |
178 |
- Manifest files are automatically created when calling write(). |
179 |
+ def has ( self, subdir ): |
180 |
+ return subdir in self._subdirs |
181 |
+ # --- end of has (...) --- |
182 |
|
183 |
- arguments: |
184 |
- * **manifest_kw -- see PackageDir.write_manifest(...) |
185 |
+ def has_dir ( self, _dir ): |
186 |
+ return os.path.isdir ( self.physical_location + os.sep + _dir ) |
187 |
+ # --- end of has_category (...) --- |
188 |
|
189 |
- returns: None (implicit) |
190 |
+ def list_packages ( self, for_deprules=False ): |
191 |
+ """Lists all packages in this category. |
192 |
+ Yields <category>/<package name> or a dict (see for_deprules below). |
193 |
+ |
194 |
+ arguments: |
195 |
+ * for_deprules -- if set and True: |
196 |
+ yield keyword args for dependency rules |
197 |
""" |
198 |
- for package in self._subdirs.values(): |
199 |
- package.write_manifest ( **manifest_kw ) |
200 |
- # --- end of write_manifest (...) --- |
201 |
+ |
202 |
+ for name, subdir in self._subdirs.items(): |
203 |
+ if not subdir.empty(): |
204 |
+ if for_deprules: |
205 |
+ yield dict ( |
206 |
+ dep_str=name, resolving_package=self.name + os.sep + name |
207 |
+ ) |
208 |
+ else: |
209 |
+ yield self.name + os.sep + name |
210 |
+ # --- end of list_packages (...) --- |
211 |
+ |
212 |
+ def scan ( self, **kw ): |
213 |
+ """Scans this category for existing ebuilds.""" |
214 |
+ for subdir in os.listdir ( self.physical_location ): |
215 |
+ if self.has_dir ( subdir ): |
216 |
+ self._get_package_dir ( subdir ).scan ( **kw ) |
217 |
+ # --- end of scan (...) --- |
218 |
|
219 |
def show ( self, **show_kw ): |
220 |
"""Prints this category (its ebuild and metadata files). |
221 |
@@ -138,46 +139,28 @@ class Category ( object ): |
222 |
package.show ( **show_kw ) |
223 |
# --- end of show (...) --- |
224 |
|
225 |
- def _run_write_queue ( self, q, write_kw ): |
226 |
- """Calls <package>.write for every <package> received from the queue. |
227 |
- |
228 |
- arguments: |
229 |
- * q -- queue |
230 |
- * write_kw -- |
231 |
- """ |
232 |
- try: |
233 |
- while not q.empty(): |
234 |
- pkg = q.get_nowait() |
235 |
- pkg.write ( write_manifest=False, **write_kw ) |
236 |
- |
237 |
- except queue.Empty: |
238 |
- pass |
239 |
- except ( Exception, KeyboardInterrupt ) as e: |
240 |
- self.RERAISE_EXCEPTION = e |
241 |
- |
242 |
- # --- end of _run_write_queue (...) --- |
243 |
- |
244 |
- def write_incremental ( self, **write_kw ): |
245 |
- """Writes this category incrementally.""" |
246 |
- try: |
247 |
- with self._lock: |
248 |
- # new package dirs could be added during overlay writing, |
249 |
- # so collect the list of package dirs before iterating over it |
250 |
- subdirs = tuple ( self._subdirs.values() ) |
251 |
- |
252 |
- for subdir in subdirs: |
253 |
- if subdir.modified: |
254 |
- roverlay.util.dodir ( subdir.physical_location ) |
255 |
- subdir.write_incremental ( **write_kw ) |
256 |
- except Exception as e: |
257 |
- self.logger.exception ( e ) |
258 |
- # --- end of write_incremental (...) --- |
259 |
- |
260 |
def write ( self, **write_kw ): |
261 |
"""Writes this category to its filesystem location. |
262 |
|
263 |
returns: None (implicit) |
264 |
""" |
265 |
+ def run_write_queue ( q, write_kw ): |
266 |
+ """Calls <package>.write for every <package> received from the queue. |
267 |
+ |
268 |
+ arguments: |
269 |
+ * q -- queue |
270 |
+ * write_kw -- |
271 |
+ """ |
272 |
+ try: |
273 |
+ while not q.empty(): |
274 |
+ pkg = q.get_nowait() |
275 |
+ pkg.write ( write_manifest=False, **write_kw ) |
276 |
+ |
277 |
+ except queue.Empty: |
278 |
+ pass |
279 |
+ except ( Exception, KeyboardInterrupt ) as e: |
280 |
+ self.RERAISE_EXCEPTION = e |
281 |
+ # --- end of run_write_queue (...) --- |
282 |
|
283 |
max_jobs = self.__class__.WRITE_JOBCOUNT |
284 |
|
285 |
@@ -198,7 +181,7 @@ class Category ( object ): |
286 |
|
287 |
workers = ( |
288 |
threading.Thread ( |
289 |
- target=self._run_write_queue, |
290 |
+ target=run_write_queue, |
291 |
args=( write_queue, write_kw ) |
292 |
) for n in range ( max_jobs ) |
293 |
) |
294 |
@@ -219,3 +202,32 @@ class Category ( object ): |
295 |
roverlay.util.dodir ( package.physical_location ) |
296 |
package.write ( write_manifest=True, **write_kw ) |
297 |
# --- end of write (...) --- |
298 |
+ |
299 |
+ def write_incremental ( self, **write_kw ): |
300 |
+ """Writes this category incrementally.""" |
301 |
+ try: |
302 |
+ with self._lock: |
303 |
+ # new package dirs could be added during overlay writing, |
304 |
+ # so collect the list of package dirs before iterating over it |
305 |
+ subdirs = tuple ( self._subdirs.values() ) |
306 |
+ |
307 |
+ for subdir in subdirs: |
308 |
+ if subdir.modified: |
309 |
+ roverlay.util.dodir ( subdir.physical_location ) |
310 |
+ subdir.write_incremental ( **write_kw ) |
311 |
+ except Exception as e: |
312 |
+ self.logger.exception ( e ) |
313 |
+ # --- end of write_incremental (...) --- |
314 |
+ |
315 |
+ def write_manifest ( self, **manifest_kw ): |
316 |
+ """Generates Manifest files for all packages in this category. |
317 |
+ Manifest files are automatically created when calling write(). |
318 |
+ |
319 |
+ arguments: |
320 |
+ * **manifest_kw -- see PackageDir.write_manifest(...) |
321 |
+ |
322 |
+ returns: None (implicit) |
323 |
+ """ |
324 |
+ for package in self._subdirs.values(): |
325 |
+ package.write_manifest ( **manifest_kw ) |
326 |
+ # --- end of write_manifest (...) --- |
327 |
|
328 |
diff --git a/roverlay/overlay/creator.py b/roverlay/overlay/creator.py |
329 |
index dd7c11e..114f12d 100644 |
330 |
--- a/roverlay/overlay/creator.py |
331 |
+++ b/roverlay/overlay/creator.py |
332 |
@@ -23,9 +23,7 @@ from roverlay.packageinfo import PackageInfo |
333 |
|
334 |
from roverlay.recipe import easyresolver |
335 |
|
336 |
-# this is used as the default value for can_write_overlay in OverlayCreator |
337 |
-# instances |
338 |
-OVERLAY_WRITE_ALLOWED = False |
339 |
+USE_INCREMENTAL_WRITE = True |
340 |
|
341 |
class PseudoAtomicCounter ( object ): |
342 |
|
343 |
@@ -74,7 +72,7 @@ class OverlayCreator ( object ): |
344 |
|
345 |
LOGGER = logging.getLogger ( 'OverlayCreator' ) |
346 |
|
347 |
- def __init__ ( self, logger=None ): |
348 |
+ def __init__ ( self, logger=None, allow_write=True ): |
349 |
|
350 |
if logger is None: |
351 |
self.logger = self.__class__.LOGGER |
352 |
@@ -84,6 +82,9 @@ class OverlayCreator ( object ): |
353 |
# this queue is used to propagate exceptions from threads |
354 |
self._err_queue = errorqueue.ErrorQueue() |
355 |
|
356 |
+ self.can_write_overlay = allow_write |
357 |
+ self.write_incremental = allow_write and USE_INCREMENTAL_WRITE |
358 |
+ |
359 |
# init overlay using config values |
360 |
self.overlay = Overlay ( |
361 |
name=config.get_or_fail ( 'OVERLAY.name' ), |
362 |
@@ -91,10 +92,12 @@ class OverlayCreator ( object ): |
363 |
directory=config.get_or_fail ( 'OVERLAY.dir' ), |
364 |
default_category= config.get_or_fail ( 'OVERLAY.category' ), |
365 |
eclass_files=config.get ( 'OVERLAY.eclass_files', None ), |
366 |
- ebuild_header=config.get ( 'EBUILD.default_header', None ) |
367 |
+ ebuild_header=config.get ( 'EBUILD.default_header', None ), |
368 |
+ incremental=self.write_incremental |
369 |
) |
370 |
|
371 |
self.depresolver = easyresolver.setup ( self._err_queue ) |
372 |
+ self.depresolver.make_selfdep_pool ( self.overlay.list_rule_kwargs ) |
373 |
|
374 |
self.NUMTHREADS = config.get ( 'EBUILD.jobcount', 0 ) |
375 |
|
376 |
@@ -107,9 +110,6 @@ class OverlayCreator ( object ): |
377 |
self._workers = None |
378 |
self._runlock = threading.RLock() |
379 |
|
380 |
- self.can_write_overlay = OVERLAY_WRITE_ALLOWED |
381 |
- self.write_incremental = True |
382 |
- |
383 |
self.closed = False |
384 |
|
385 |
# queued packages counter, |
386 |
@@ -208,8 +208,10 @@ class OverlayCreator ( object ): |
387 |
arguments: |
388 |
* package_info -- |
389 |
""" |
390 |
- self._pkg_queue.put ( package_info ) |
391 |
- self.package_added.inc() |
392 |
+ if self.overlay.add ( package_info ): |
393 |
+ self._pkg_queue.put ( package_info ) |
394 |
+ # FIXME package_added is now the # of packages queued for creation |
395 |
+ self.package_added.inc() |
396 |
# --- end of add_package (...) --- |
397 |
|
398 |
def add_package_file ( self, package_file ): |
399 |
@@ -226,19 +228,18 @@ class OverlayCreator ( object ): |
400 |
self.package_added.inc() |
401 |
# --- end of add_package_files (...) --- |
402 |
|
403 |
- def write_overlay ( self, incremental=False ): |
404 |
+ def write_overlay ( self ): |
405 |
"""Writes the overlay. |
406 |
|
407 |
arguments: |
408 |
- * incremental -- (TODO) |
409 |
""" |
410 |
if self.can_write_overlay: |
411 |
- start = time.time() |
412 |
- if incremental: |
413 |
- self.overlay.write_incremental() |
414 |
+ if self.write_incremental: |
415 |
+ self.overlay.finalize_write_incremental() |
416 |
else: |
417 |
+ start = time.time() |
418 |
self.overlay.write() |
419 |
- self._timestamp ( "overlay written", start ) |
420 |
+ self._timestamp ( "overlay written", start ) |
421 |
else: |
422 |
self.logger.warning ( "Not allowed to write overlay!" ) |
423 |
# --- end of write_overlay (...) --- |
424 |
@@ -267,6 +268,7 @@ class OverlayCreator ( object ): |
425 |
self._runlock.acquire() |
426 |
try: |
427 |
self.join() |
428 |
+ self.depresolver.reload_pools() |
429 |
self._make_workers() |
430 |
except: |
431 |
self._err_queue.push ( context=-1, error=None ) |
432 |
@@ -282,28 +284,28 @@ class OverlayCreator ( object ): |
433 |
|
434 |
def close ( self ): |
435 |
"""Closes this OverlayCreator.""" |
436 |
- self._close_workers() |
437 |
- self._close_resolver() |
438 |
- self.closed = True |
439 |
- # --- end of close (...) --- |
440 |
+ def close_resolver(): |
441 |
+ """Tells the dependency resolver to close. |
442 |
+ This is useful 'cause certain depres listener modules will write files |
443 |
+ when told to exit. |
444 |
+ """ |
445 |
+ if self.depresolver is None: return |
446 |
|
447 |
- def _close_resolver ( self ): |
448 |
- """Tells the dependency resolver to close. |
449 |
- This is useful 'cause certain depres listener modules will write files |
450 |
- when told to exit. |
451 |
- """ |
452 |
- if self.depresolver is None: return |
453 |
+ self._runlock.acquire() |
454 |
|
455 |
- self._runlock.acquire() |
456 |
+ try: |
457 |
+ if self.depresolver is not None: |
458 |
+ self.depresolver.close() |
459 |
+ del self.depresolver |
460 |
+ self.depresolver = None |
461 |
+ finally: |
462 |
+ self._runlock.release() |
463 |
+ # --- end of close_resolver (...) --- |
464 |
|
465 |
- try: |
466 |
- if self.depresolver is not None: |
467 |
- self.depresolver.close() |
468 |
- del self.depresolver |
469 |
- self.depresolver = None |
470 |
- finally: |
471 |
- self._runlock.release() |
472 |
- # --- end of _close_resolver (...) --- |
473 |
+ self._close_workers() |
474 |
+ close_resolver() |
475 |
+ self.closed = True |
476 |
+ # --- end of close (...) --- |
477 |
|
478 |
def _waitfor_workers ( self, do_close ): |
479 |
"""Waits until the workers are done. |
480 |
@@ -396,12 +398,8 @@ class OverlayCreator ( object ): |
481 |
# if <>: |
482 |
if package_info ['ebuild'] is not None: |
483 |
self.create_success.inc() |
484 |
- if self.overlay.add ( |
485 |
- package_info, |
486 |
- write_after_add=self.write_incremental and self.can_write_overlay |
487 |
- ): |
488 |
+ if package_info.overlay_package_ref.new_ebuild(): |
489 |
self.overlay_added.inc() |
490 |
- |
491 |
else: |
492 |
self.create_fail.inc() |
493 |
|
494 |
|
495 |
diff --git a/roverlay/overlay/header.py b/roverlay/overlay/header.py |
496 |
new file mode 100644 |
497 |
index 0000000..b6d15d7 |
498 |
--- /dev/null |
499 |
+++ b/roverlay/overlay/header.py |
500 |
@@ -0,0 +1,37 @@ |
501 |
+class EbuildHeader ( object ): |
502 |
+ def __init__ ( self, default_header ): |
503 |
+ self.default_header = default_header |
504 |
+ self.eclasses = () |
505 |
+ |
506 |
+ self._cached_header = None |
507 |
+ # --- end of __init__ (...) --- |
508 |
+ |
509 |
+ def set_eclasses ( self, eclass_names ): |
510 |
+ self.eclasses = eclass_names |
511 |
+ # --- end of set_eclasses (...) --- |
512 |
+ |
513 |
+ def get ( self, use_cached=True ): |
514 |
+ if self._cached_header is None or not use_cached: |
515 |
+ self._cached_header = self._make() |
516 |
+ return self._cached_header |
517 |
+ # --- end of get (...) --- |
518 |
+ |
519 |
+ def _make ( self ): |
520 |
+ if self.eclasses: |
521 |
+ inherit = 'inherit ' + ' '.join ( sorted ( self.eclasses ) ) |
522 |
+ else: |
523 |
+ inherit = None |
524 |
+ |
525 |
+ # header and inherit is expected and therefore the first condition here |
526 |
+ if inherit and self.default_header: |
527 |
+ return self.default_header + '\n' + inherit |
528 |
+ |
529 |
+ elif inherit: |
530 |
+ return inherit |
531 |
+ |
532 |
+ elif self.default_header: |
533 |
+ return self.default_header |
534 |
+ |
535 |
+ else: |
536 |
+ return None |
537 |
+ # --- end of _make (...) --- |
538 |
|
539 |
diff --git a/roverlay/overlay/package.py b/roverlay/overlay/package.py |
540 |
index 71b7ea9..5b73788 100644 |
541 |
--- a/roverlay/overlay/package.py |
542 |
+++ b/roverlay/overlay/package.py |
543 |
@@ -1,10 +1,8 @@ |
544 |
-# replacement for package.py |
545 |
- |
546 |
import os |
547 |
import sys |
548 |
import threading |
549 |
|
550 |
-from roverlay import manifest |
551 |
+from roverlay.overlay import manifest |
552 |
from roverlay.packageinfo import PackageInfo |
553 |
from roverlay.overlay.metadata import MetadataJob |
554 |
|
555 |
@@ -14,23 +12,26 @@ SUPPRESS_EXCEPTIONS = True |
556 |
class PackageDir ( object ): |
557 |
EBUILD_SUFFIX = '.ebuild' |
558 |
|
559 |
- def __init__ ( self, name, logger, directory ): |
560 |
+ def __init__ ( self, name, logger, directory, get_header, incremental ): |
561 |
"""Initializes a PackageDir which contains ebuilds, metadata and |
562 |
a Manifest file. |
563 |
|
564 |
arguments: |
565 |
- * name -- name of the directory (${PN} in ebuilds) |
566 |
- * logger -- parent logger |
567 |
- * directory -- filesystem location of this PackageDir |
568 |
+ * name -- name of the directory (${PN} in ebuilds) |
569 |
+ * logger -- parent logger |
570 |
+ * directory -- filesystem location of this PackageDir |
571 |
+ * get_header -- function that returns an ebuild header |
572 |
""" |
573 |
- self.logger = logger.getChild ( name ) |
574 |
- self.name = name |
575 |
- self._lock = threading.RLock() |
576 |
+ self.logger = logger.getChild ( name ) |
577 |
+ self.name = name |
578 |
+ self._lock = threading.RLock() |
579 |
# { <version> : <PackageInfo> } |
580 |
- self._packages = dict() |
581 |
- self.physical_location = directory |
582 |
+ self._packages = dict() |
583 |
+ self.physical_location = directory |
584 |
+ self.get_header = get_header |
585 |
+ self.runtime_incremental = incremental |
586 |
|
587 |
- self._metadata = MetadataJob ( |
588 |
+ self._metadata = MetadataJob ( |
589 |
filepath = self.physical_location + os.sep + 'metadata.xml', |
590 |
logger = self.logger |
591 |
) |
592 |
@@ -41,18 +42,12 @@ class PackageDir ( object ): |
593 |
self.name + "-{PVR}" + self.__class__.EBUILD_SUFFIX |
594 |
|
595 |
# used to track changes for this package dir |
596 |
- self.modified = False |
597 |
+ self.modified = False |
598 |
self._manifest_package = None |
599 |
- self._need_manifest = False |
600 |
- self._need_metadata = False |
601 |
+ self._need_manifest = False |
602 |
+ self._need_metadata = False |
603 |
# --- end of __init__ (...) --- |
604 |
|
605 |
- def new_ebuild ( self ): |
606 |
- """Called when a new ebuild has been created for this PackageDir.""" |
607 |
- self._need_manifest = True |
608 |
- self.modified = True |
609 |
- # --- end of new_ebuild (...) --- |
610 |
- |
611 |
def add ( self, package_info, add_if_physical=False ): |
612 |
"""Adds a package to this PackageDir. |
613 |
|
614 |
@@ -66,7 +61,7 @@ class PackageDir ( object ): |
615 |
raises: Exception when ebuild already exists. |
616 |
""" |
617 |
shortver = package_info ['ebuild_verstr'] |
618 |
- _success = False |
619 |
+ added = False |
620 |
try: |
621 |
self._lock.acquire() |
622 |
if shortver in self._packages: |
623 |
@@ -75,7 +70,8 @@ class PackageDir ( object ): |
624 |
if not skip_if_physical: |
625 |
# ignore ebuilds that exist as file |
626 |
self._packages [shortver] = package_info |
627 |
- _success = True |
628 |
+ added = True |
629 |
+ |
630 |
else: |
631 |
self.logger.debug ( |
632 |
"'{PN}-{PVR}.ebuild' exists as file, skipping.".format ( |
633 |
@@ -91,12 +87,20 @@ class PackageDir ( object ): |
634 |
) |
635 |
else: |
636 |
self._packages [shortver] = package_info |
637 |
- _success = True |
638 |
+ added = True |
639 |
|
640 |
finally: |
641 |
self._lock.release() |
642 |
|
643 |
- return _success |
644 |
+ if added: |
645 |
+ # add a link to this PackageDir into the package info, |
646 |
+ # !! package_info <-> self (double-linked) |
647 |
+ # FIXME: remove physical_only flag from PackageInfo if |
648 |
+ # overlay_package_ref can be used for that |
649 |
+ package_info.overlay_package_ref = self |
650 |
+ return True |
651 |
+ else: |
652 |
+ return False |
653 |
# --- end of add (...) --- |
654 |
|
655 |
def empty ( self ): |
656 |
@@ -129,6 +133,17 @@ class PackageDir ( object ): |
657 |
return self._packages.keys() |
658 |
# --- end of list_versions (...) --- |
659 |
|
660 |
+ def new_ebuild ( self, write=False ): |
661 |
+ """Called when a new ebuild has been created for this PackageDir.""" |
662 |
+ self._need_manifest = True |
663 |
+ self._need_metadata = True |
664 |
+ self.modified = True |
665 |
+ if self.runtime_incremental: |
666 |
+ return self.write_incremental() |
667 |
+ else: |
668 |
+ return True |
669 |
+ # --- end of new_ebuild (...) --- |
670 |
+ |
671 |
def scan ( self, **kw ): |
672 |
"""Scans the filesystem location of this package for existing |
673 |
ebuilds and adds them. |
674 |
@@ -166,13 +181,15 @@ class PackageDir ( object ): |
675 |
) |
676 |
# --- end of scan_ebuilds (...) --- |
677 |
|
678 |
- for pvr in scan_ebuilds(): |
679 |
- if pvr not in self._packages: |
680 |
- p = PackageInfo ( physical_only=True, pvr=pvr ) |
681 |
- self._packages [ p ['ebuild_verstr'] ] = p |
682 |
+ # ignore directories without a Manifest file |
683 |
+ if os.path.isfile ( self.physical_location + os.sep + 'Manifest' ): |
684 |
+ for pvr in scan_ebuilds(): |
685 |
+ if pvr not in self._packages: |
686 |
+ p = PackageInfo ( physical_only=True, pvr=pvr ) |
687 |
+ self._packages [ p ['ebuild_verstr'] ] = p |
688 |
# --- end of scan (...) --- |
689 |
|
690 |
- def show ( self, stream=sys.stderr, default_header=None ): |
691 |
+ def show ( self, stream=sys.stderr ): |
692 |
"""Prints this dir (the ebuilds and the metadata) into a stream. |
693 |
|
694 |
arguments: |
695 |
@@ -183,18 +200,16 @@ class PackageDir ( object ): |
696 |
raises: |
697 |
* IOError |
698 |
""" |
699 |
- return self.write ( default_header=default_header, shared_fh=stream ) |
700 |
+ return self.write ( shared_fh=stream ) |
701 |
# --- end of show (...) --- |
702 |
|
703 |
def write ( self, |
704 |
- default_header=None, shared_fh=None, |
705 |
- write_ebuilds=True, write_manifest=True, write_metadata=True, |
706 |
- overwrite_ebuilds=True |
707 |
+ shared_fh=None, overwrite_ebuilds=True, |
708 |
+ write_ebuilds=True, write_manifest=True, write_metadata=True |
709 |
): |
710 |
"""Writes this directory to its (existent!) filesystem location. |
711 |
|
712 |
arguments: |
713 |
- * default_header -- ebuild header to write |
714 |
* shared_fh -- if set and not None: write everyting into <fh> |
715 |
* write_ebuilds -- if set and False: don't write ebuilds |
716 |
* write_manifest -- if set and False: don't write the Manifest file |
717 |
@@ -212,8 +227,7 @@ class PackageDir ( object ): |
718 |
# write ebuilds |
719 |
if write_ebuilds: |
720 |
self.write_ebuilds ( |
721 |
- default_header=default_header, shared_fh=shared_fh, |
722 |
- overwrite=overwrite_ebuilds |
723 |
+ overwrite=overwrite_ebuilds, shared_fh=shared_fh |
724 |
) |
725 |
|
726 |
# write metadata |
727 |
@@ -225,30 +239,30 @@ class PackageDir ( object ): |
728 |
self.write_manifest() |
729 |
# --- end of write (...) --- |
730 |
|
731 |
- def write_ebuilds ( self, default_header, overwrite, shared_fh=None ): |
732 |
+ def write_ebuilds ( self, overwrite, shared_fh=None ): |
733 |
"""Writes all ebuilds. |
734 |
|
735 |
arguments: |
736 |
- * default_header -- ebuild header |
737 |
* shared_fh -- if set and not None: don't use own file handles |
738 |
(i.e. write files), write everything into shared_fh |
739 |
* overwrite -- write ebuilds that have been written before, |
740 |
defaults to True |
741 |
""" |
742 |
+ ebuild_header = self.get_header() |
743 |
+ |
744 |
def write_ebuild ( efile, ebuild ): |
745 |
"""Writes an ebuild. |
746 |
|
747 |
arguments: |
748 |
* efile -- file to write |
749 |
* ebuild -- ebuild object to write (has to have a __str__ method) |
750 |
- * (default_header from write_ebuilds()) |
751 |
* (shared_fh from write_ebuilds()) |
752 |
""" |
753 |
_success = False |
754 |
try: |
755 |
fh = open ( efile, 'w' ) if shared_fh is None else shared_fh |
756 |
- if default_header is not None: |
757 |
- fh.write ( str ( default_header ) ) |
758 |
+ if ebuild_header is not None: |
759 |
+ fh.write ( str ( ebuild_header ) ) |
760 |
fh.write ( '\n\n' ) |
761 |
fh.write ( str ( ebuild ) ) |
762 |
fh.write ( '\n' ) |
763 |
@@ -304,11 +318,12 @@ class PackageDir ( object ): |
764 |
) |
765 |
|
766 |
self.modified = not all_ebuilds_written |
767 |
+ return all_ebuilds_written |
768 |
# --- end of write_ebuilds (...) --- |
769 |
|
770 |
- def write_incremental ( self, default_header ): |
771 |
+ def write_incremental ( self ): |
772 |
with self._lock: |
773 |
- self.write_ebuilds ( default_header=default_header, overwrite=False ) |
774 |
+ return self.write_ebuilds ( overwrite=False ) |
775 |
# --- end of write_incremental (...) --- |
776 |
|
777 |
def write_manifest ( self ): |
778 |
@@ -330,8 +345,14 @@ class PackageDir ( object ): |
779 |
# 'cause DISTDIR would be unknown |
780 |
# |
781 |
|
782 |
- if self._manifest_package is not None: |
783 |
- manifest.create_manifest ( self._manifest_package, nofail=False ) |
784 |
+ # collect suitable PackageInfo instances |
785 |
+ pkgs_for_manifest = tuple ( |
786 |
+ p for p in self._packages.values() \ |
787 |
+ if p.has ( 'distdir', 'ebuild_file' ) |
788 |
+ ) |
789 |
+ |
790 |
+ if pkgs_for_manifest: |
791 |
+ manifest.create_manifest ( pkgs_for_manifest, nofail=False ) |
792 |
self._need_manifest = False |
793 |
else: |
794 |
raise Exception ( |
795 |
@@ -341,28 +362,24 @@ class PackageDir ( object ): |
796 |
|
797 |
def write_metadata ( self, shared_fh=None ): |
798 |
"""Writes metadata for this package.""" |
799 |
- if self._manifest_package is None and not shared_fh: |
800 |
- self.logger.error ( |
801 |
- 'write_metadata() requested, but no ebuild written so far! ' |
802 |
- 'This will most likely result in a corrupt Manifest.' |
803 |
- ) |
804 |
- |
805 |
try: |
806 |
self.generate_metadata ( skip_if_existent=True ) |
807 |
|
808 |
- if self._metadata.write() \ |
809 |
- if shared_fh is None else self._metadata.show ( shared_fh ) \ |
810 |
- : |
811 |
- self._need_metadata = False |
812 |
- self._need_manifest = True |
813 |
- return True |
814 |
- else: |
815 |
- self.logger.error ( |
816 |
- "Failed to write metadata file {}.".format ( |
817 |
- self._metadata.filepath |
818 |
+ if shared_fh is None: |
819 |
+ if self._metadata.write(): |
820 |
+ self._need_metadata = False |
821 |
+ self._need_manifest = True |
822 |
+ return True |
823 |
+ else: |
824 |
+ self.logger.error ( |
825 |
+ "Failed to write metadata file {}.".format ( |
826 |
+ self._metadata.filepath |
827 |
+ ) |
828 |
) |
829 |
- ) |
830 |
- return False |
831 |
+ return False |
832 |
+ else: |
833 |
+ self._metadata.show ( shared_fh ) |
834 |
+ return True |
835 |
except: |
836 |
# already logged |
837 |
return False |
838 |
|
839 |
diff --git a/roverlay/overlay/root.py b/roverlay/overlay/root.py |
840 |
index e0446df..4766b02 100644 |
841 |
--- a/roverlay/overlay/root.py |
842 |
+++ b/roverlay/overlay/root.py |
843 |
@@ -10,50 +10,13 @@ import os |
844 |
from roverlay import config, util |
845 |
|
846 |
from roverlay.overlay.category import Category |
847 |
+from roverlay.overlay.header import EbuildHeader |
848 |
|
849 |
DEFAULT_USE_DESC = '\n'.join ( [ |
850 |
'byte-compile - enable byte compiling', |
851 |
'R_suggests - install recommended packages' |
852 |
] ) |
853 |
|
854 |
-class EbuildHeader ( object ): |
855 |
- def __init__ ( self, default_header ): |
856 |
- self.default_header = default_header |
857 |
- self.eclasses = () |
858 |
- |
859 |
- self._cached_header = None |
860 |
- # --- end of __init__ (...) --- |
861 |
- |
862 |
- def set_eclasses ( self, eclass_names ): |
863 |
- self.eclasses = eclass_names |
864 |
- # --- end of set_eclasses (...) --- |
865 |
- |
866 |
- def get ( self, use_cached=True ): |
867 |
- if self._cached_header is None or not use_cached: |
868 |
- self._cached_header = self._make() |
869 |
- return self._cached_header |
870 |
- # --- end of get (...) --- |
871 |
- |
872 |
- def _make ( self ): |
873 |
- if self.eclasses: |
874 |
- inherit = 'inherit ' + ' '.join ( self.eclasses ) |
875 |
- else: |
876 |
- inherit = None |
877 |
- |
878 |
- # header and inherit is expected and therefore the first condition here |
879 |
- if inherit and self.default_header: |
880 |
- return self.default_header + '\n' + inherit |
881 |
- |
882 |
- elif inherit: |
883 |
- return inherit |
884 |
- |
885 |
- elif self.default_header: |
886 |
- return self.default_header |
887 |
- |
888 |
- else: |
889 |
- return None |
890 |
- # --- end of _make (...) --- |
891 |
- |
892 |
|
893 |
class Overlay ( object ): |
894 |
|
895 |
@@ -61,7 +24,8 @@ class Overlay ( object ): |
896 |
self, |
897 |
name, logger, directory, |
898 |
default_category, eclass_files, |
899 |
- ebuild_header |
900 |
+ ebuild_header, |
901 |
+ incremental |
902 |
): |
903 |
if directory is None: |
904 |
raise Exception ( |
905 |
@@ -80,20 +44,23 @@ class Overlay ( object ): |
906 |
self._catlock = threading.Lock() |
907 |
self._categories = dict() |
908 |
self._header = EbuildHeader ( ebuild_header ) |
909 |
- self._get_header = self._header.get |
910 |
|
911 |
# fixme or ignore: calculating eclass names twice, |
912 |
# once here and another time when calling _init_overlay |
913 |
- self._header.set_eclasses ( tuple ( |
914 |
+ self._header.set_eclasses ( set ( |
915 |
self._get_eclass_import_info ( only_eclass_names=True ) |
916 |
) ) |
917 |
|
918 |
- self._incremental_write_lock = threading.Lock() |
919 |
+ self.incremental = incremental |
920 |
+ if self.incremental: |
921 |
|
922 |
+ self._incremental_write_lock = threading.Lock() |
923 |
+ self.scan() |
924 |
+ self._init_overlay ( reimport_eclass=True, make_profiles_dir=True ) |
925 |
|
926 |
+ for c in self.list_packages ( for_deprules=True ): |
927 |
+ print ( str ( c ) ) |
928 |
|
929 |
- #self.scan() |
930 |
- #raise Exception ( "^" ) |
931 |
# --- end of __init__ (...) --- |
932 |
|
933 |
def scan ( self, **kw ): |
934 |
@@ -107,12 +74,18 @@ class Overlay ( object ): |
935 |
# print ( package ) |
936 |
# --- end of scan (...) --- |
937 |
|
938 |
- def list_packages ( self ): |
939 |
+ def list_packages ( self, for_deprules=True ): |
940 |
for cat in self._categories.values(): |
941 |
- for package in cat.list_packages(): |
942 |
+ for package in cat.list_packages ( for_deprules=True ): |
943 |
yield package |
944 |
# --- end of list_packages (...) --- |
945 |
|
946 |
+ def list_rule_kwargs ( self ): |
947 |
+ for cat in self._categories.values(): |
948 |
+ for kwargs in cat.list_packages ( for_deprules=True ): |
949 |
+ yield kwargs |
950 |
+ # --- end of list_rule_kwargs (...) --- |
951 |
+ |
952 |
def has_dir ( self, _dir ): |
953 |
return os.path.isdir ( self.physical_location + os.sep + _dir ) |
954 |
# --- end of has_category (...) --- |
955 |
@@ -134,11 +107,16 @@ class Overlay ( object ): |
956 |
self._catlock.acquire() |
957 |
try: |
958 |
if not category in self._categories: |
959 |
- self._categories [category] = Category ( |
960 |
+ newcat = Category ( |
961 |
category, |
962 |
self.logger, |
963 |
- self.physical_location + os.sep + category |
964 |
+ self.physical_location + os.sep + category, |
965 |
+ get_header=self._header.get, |
966 |
+ incremental=self.incremental |
967 |
) |
968 |
+ self._categories [category] = newcat |
969 |
+ if self.incremental: |
970 |
+ util.dodir ( newcat.physical_location ) |
971 |
finally: |
972 |
self._catlock.release() |
973 |
|
974 |
@@ -158,18 +136,14 @@ class Overlay ( object ): |
975 |
cat = self._get_category ( |
976 |
self.default_category if category is None else category |
977 |
) |
978 |
- |
979 |
- if write_after_add: |
980 |
- raise Exception ( "add~write_after_add: to be removed." ) |
981 |
- |
982 |
- return cat.add ( package_info, write_after_add=False ) |
983 |
+ return cat.add ( package_info ) |
984 |
# --- end of add (...) --- |
985 |
|
986 |
def show ( self, **show_kw ): |
987 |
"""Presents the ebuilds/metadata stored in this overlay. |
988 |
|
989 |
arguments: |
990 |
- * **show_kw -- ignored! (keywords for package.PackageDir.show(...)) |
991 |
+ * **show_kw -- keywords for package.PackageDir.show(...) |
992 |
|
993 |
returns: None (implicit) |
994 |
""" |
995 |
@@ -177,7 +151,7 @@ class Overlay ( object ): |
996 |
tuple ( self._get_eclass_import_info ( only_eclass_names=True ) ) |
997 |
) |
998 |
for cat in self._categories.values(): |
999 |
- cat.show ( default_header=self._get_header() ) |
1000 |
+ cat.show ( **show_kw ) |
1001 |
# --- end of show (...) --- |
1002 |
|
1003 |
def write ( self, **write_kw ): |
1004 |
@@ -185,7 +159,7 @@ class Overlay ( object ): |
1005 |
metadata and Manifest files. |
1006 |
|
1007 |
arguments: |
1008 |
- * **write_kw -- ignored! (keywords for package.PackageDir.write(...)) |
1009 |
+ * **write_kw -- keywords for package.PackageDir.write(...) |
1010 |
|
1011 |
returns: None (implicit) |
1012 |
|
1013 |
@@ -194,13 +168,14 @@ class Overlay ( object ): |
1014 |
! TODO/FIXME/DOC: This is not thread-safe, it's expected to be called |
1015 |
when ebuild creation is done. |
1016 |
""" |
1017 |
+ raise Exception ( "^,^" ) |
1018 |
# writing profiles/ here, rewriting categories/ later |
1019 |
self._init_overlay ( reimport_eclass=True, make_profiles_dir=True ) |
1020 |
|
1021 |
for cat in self._categories.values(): |
1022 |
if not cat.empty(): |
1023 |
util.dodir ( cat.physical_location ) |
1024 |
- cat.write ( default_header=self._get_header() ) |
1025 |
+ cat.write ( **write_kw ) |
1026 |
|
1027 |
self._write_categories ( only_active=True ) |
1028 |
# --- end of write (...) --- |
1029 |
@@ -222,18 +197,15 @@ class Overlay ( object ): |
1030 |
cats = tuple ( self._categories.values() ) |
1031 |
for cat in cats: |
1032 |
util.dodir ( cat.physical_location ) |
1033 |
- cat.write_incremental ( default_header=self._get_header() ) |
1034 |
+ cat.write_incremental ( **write_kw ) |
1035 |
finally: |
1036 |
self._incremental_write_lock.release() |
1037 |
# --- end of write_incremental (...) --- |
1038 |
|
1039 |
def finalize_write_incremental ( self ): |
1040 |
"""Writes metadata + Manifest for all packages.""" |
1041 |
- self._init_overlay ( reimport_eclass=True, make_profiles_dir=True ) |
1042 |
- |
1043 |
for cat in self._categories.values(): |
1044 |
cat.finalize_write_incremental() |
1045 |
- |
1046 |
self._write_categories ( only_active=True ) |
1047 |
# --- end of finalize_incremental (...) --- |
1048 |
|
1049 |
@@ -394,7 +366,7 @@ class Overlay ( object ): |
1050 |
raise |
1051 |
# --- end of _import_eclass (...) --- |
1052 |
|
1053 |
- def _init_overlay ( self, reimport_eclass=False, make_profiles_dir=False ): |
1054 |
+ def _init_overlay ( self, reimport_eclass, make_profiles_dir ): |
1055 |
"""Initializes the overlay at its physical/filesystem location. |
1056 |
|
1057 |
arguments: |
1058 |
|
1059 |
diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py |
1060 |
index f9d26d1..829b798 100644 |
1061 |
--- a/roverlay/packageinfo.py |
1062 |
+++ b/roverlay/packageinfo.py |
1063 |
@@ -45,9 +45,10 @@ class PackageInfo ( object ): |
1064 |
arguments: |
1065 |
* **initial_info -- passed to update ( **kw ) |
1066 |
""" |
1067 |
- self._info = dict() |
1068 |
- self.readonly = False |
1069 |
- self._update_lock = threading.RLock() |
1070 |
+ self._info = dict() |
1071 |
+ self.readonly = False |
1072 |
+ self._update_lock = threading.RLock() |
1073 |
+ self.overlay_package_ref = None |
1074 |
|
1075 |
self.update ( **initial_info ) |
1076 |
# --- end of __init__ (...) --- |