Gentoo Archives: gentoo-commits

From: "André Erdmann" <dywi@×××××××.de>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/R_overlay:master commit in: /, roverlay/, roverlay/overlay/
Date: Mon, 30 Jul 2012 08:54:58
Message-Id: 1342800844.34861f2cd5d5db7ca3ba99a8bc62ab5e75bbfd34.dywi@gentoo
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__ (...) ---