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/overlay/manifest/, roverlay/overlay/
Date: Mon, 30 Jul 2012 08:55:24
Message-Id: 1343144347.ee870b2a6f8a3df4a794dc82fda1bd63a4f6d147.dywi@gentoo
1 commit: ee870b2a6f8a3df4a794dc82fda1bd63a4f6d147
2 Author: André Erdmann <dywi <AT> mailerd <DOT> de>
3 AuthorDate: Tue Jul 24 15:39:07 2012 +0000
4 Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
5 CommitDate: Tue Jul 24 15:39:07 2012 +0000
6 URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=ee870b2a
7
8 incremental overlay writing: merge write() funcs
9
10 * one write function for overlay/{root,category,package}.py
11 that replaces write_incremental, write, finalize_write_incremental
12
13 * also fixed some issues (proper PackageDir cleanup, make threaded writing
14 controllable)
15
16 geändert: roverlay/overlay/category.py
17 geändert: roverlay/overlay/creator.py
18 geändert: roverlay/overlay/manifest/__init__.py
19 geändert: roverlay/overlay/package.py
20 geändert: roverlay/overlay/root.py
21
22 ---
23 roverlay/overlay/category.py | 141 +++++++----------
24 roverlay/overlay/creator.py | 29 +---
25 roverlay/overlay/manifest/__init__.py | 4 +-
26 roverlay/overlay/package.py | 278 +++++++++++++++++++++------------
27 roverlay/overlay/root.py | 96 +++---------
28 5 files changed, 266 insertions(+), 282 deletions(-)
29
30 diff --git a/roverlay/overlay/category.py b/roverlay/overlay/category.py
31 index 33149c4..fab6373 100644
32 --- a/roverlay/overlay/category.py
33 +++ b/roverlay/overlay/category.py
34 @@ -12,8 +12,6 @@ except ImportError:
35
36 from roverlay.overlay.package import PackageDir
37
38 -import roverlay.util
39 -
40 class Category ( object ):
41
42 WRITE_JOBCOUNT = 3
43 @@ -49,8 +47,6 @@ class Category ( object ):
44 incremental = self.incremental
45 )
46 self._subdirs [pkg_name] = newpkg
47 - if self.incremental:
48 - roverlay.util.dodir ( newpkg.physical_location )
49 finally:
50 self._lock.release()
51
52 @@ -76,26 +72,6 @@ class Category ( object ):
53 not False in ( d.empty() for d in self._subdirs.values() )
54 # --- end of empty (...) ---
55
56 - def finalize_write_incremental ( self ):
57 - for subdir in self._subdirs.values():
58 - if subdir.modified:
59 - subdir.write_incremental()
60 - subdir.finalize_write_incremental()
61 - # --- end of finalize_write_incremental (...) ---
62 -
63 - def generate_metadata ( self, **metadata_kw ):
64 - """Generates metadata for all packages in this category.
65 - Metadata are automatically generated when calling write().
66 -
67 - arguments:
68 - * **metadata_kw -- see PackageDir.generate_metadata(...)
69 -
70 - returns: None (implicit)
71 - """
72 - for package in self._subdirs.values():
73 - package.generate_metadata ( **metadata_kw )
74 - # --- end of generate_metadata (...) ---
75 -
76 def has ( self, subdir ):
77 return subdir in self._subdirs
78 # --- end of has (...) ---
79 @@ -104,13 +80,6 @@ class Category ( object ):
80 return os.path.isdir ( self.physical_location + os.sep + _dir )
81 # --- end of has_category (...) ---
82
83 - def keep_nth_latest ( self, *args, **kwargs ):
84 - """See package.py:PackageDir:keep_nth_latest."""
85 - for subdir in self._subdirs.values():
86 - subdir.keep_nth_latest ( *args, **kwargs )
87 - subdir.fs_cleanup()
88 - # --- end of keep_nth_latest (...) ---
89 -
90 def list_packages ( self, for_deprules=False ):
91 """Lists all packages in this category.
92 Yields <category>/<package name> or a dict (see for_deprules below).
93 @@ -130,6 +99,14 @@ class Category ( object ):
94 yield self.name + os.sep + name
95 # --- end of list_packages (...) ---
96
97 + def remove_empty ( self ):
98 + """This removes all empty PackageDirs."""
99 + with self._lock:
100 + for key in tuple ( self._subdirs.keys() ):
101 + if self._subdirs [key].check_empty():
102 + del self._subdirs [key]
103 + # --- end of remove_empty (...) ---
104 +
105 def scan ( self, **kw ):
106 """Scans this category for existing ebuilds."""
107 for subdir in os.listdir ( self.physical_location ):
108 @@ -146,7 +123,7 @@ class Category ( object ):
109 package.show ( **show_kw )
110 # --- end of show (...) ---
111
112 - def write ( self, **write_kw ):
113 + def write ( self, overwrite_ebuilds, keep_n_ebuilds, cautious ):
114 """Writes this category to its filesystem location.
115
116 returns: None (implicit)
117 @@ -156,75 +133,75 @@ class Category ( object ):
118
119 arguments:
120 * q -- queue
121 - * write_kw --
122 + * write_kw -- keywords for write(...)
123 """
124 try:
125 while not q.empty():
126 - pkg = q.get_nowait()
127 - pkg.write ( write_manifest=False, **write_kw )
128 -
129 + try:
130 + pkg = q.get_nowait()
131 + # remove manifest writing from threaded writing since it's
132 + # single-threaded
133 + pkg.write ( write_manifest=False, **write_kw )
134 + #except ( Exception, KeyboardInterrupt ) as e:
135 + except Exception as e:
136 + # FIXME: reintroduce RERAISE
137 + self.logger.exception ( e )
138 except queue.Empty:
139 pass
140 - except ( Exception, KeyboardInterrupt ) as e:
141 - self.RERAISE_EXCEPTION = e
142 # --- end of run_write_queue (...) ---
143
144 + if len ( self._subdirs ) == 0: return
145 +
146 + # determine write keyword args
147 + write_kwargs = dict (
148 + overwrite_ebuilds = overwrite_ebuilds,
149 + keep_n_ebuilds = keep_n_ebuilds,
150 + cautious = cautious,
151 + )
152 +
153 + # start writing:
154 +
155 max_jobs = self.__class__.WRITE_JOBCOUNT
156
157 - # todo len.. > 3: what's an reasonable number of min package dirs to
158 - # start threaded writing?
159 - if max_jobs > 1 and len ( self._subdirs ) > 3:
160 + # FIXME/TODO: what's an reasonable number of min package dirs to
161 + # start threaded writing?
162 + # Ignoring it for now (and expecting enough pkg dirs)
163 + if max_jobs > 1:
164
165 - # writing 1..self.__class__.WRITE_JOBCOUNT package dirs at once
166 + # writing <=max_jobs package dirs at once
167
168 - modified_packages = tuple (
169 - p for p in self._subdirs.values() if p.modified
170 - )
171 - if len ( modified_packages ) > 0:
172 - write_queue = queue.Queue()
173 - for package in modified_packages:
174 - roverlay.util.dodir ( package.physical_location )
175 - write_queue.put_nowait ( package )
176 + # don't create more workers than write jobs available
177 + max_jobs = min ( max_jobs, len ( self._subdirs ) )
178
179 - workers = (
180 - threading.Thread (
181 - target=run_write_queue,
182 - args=( write_queue, write_kw )
183 - ) for n in range ( max_jobs )
184 - )
185 + write_queue = queue.Queue()
186 + for package in self._subdirs.values():
187 + write_queue.put_nowait ( package )
188
189 - for w in workers: w.start()
190 - for w in workers: w.join()
191 + workers = frozenset (
192 + threading.Thread (
193 + target=run_write_queue,
194 + args=( write_queue, write_kwargs )
195 + ) for n in range ( max_jobs )
196 + )
197 +
198 + for w in workers: w.start()
199 + for w in workers: w.join()
200
201 - if hasattr ( self, 'RERAISE_EXCEPTION' ):
202 - raise self.RERAISE_EXCEPTION
203 + self.remove_empty()
204
205 - # write manifest files
206 - for package in modified_packages:
207 - package.write_manifest()
208 + # write manifest files
209 + # fixme: debug print
210 + #self.logger.info ( "Writing Manifest files for {}".format ( name ) )
211 + print ( "Writing Manifest files ..." )
212 + for package in self._subdirs.values():
213 + package.write_manifest ( ignore_empty=True )
214
215 else:
216 for package in self._subdirs.values():
217 - if package.modified:
218 - roverlay.util.dodir ( package.physical_location )
219 - package.write ( write_manifest=True, **write_kw )
220 - # --- end of write (...) ---
221 + package.write ( **write_kwargs )
222
223 - def write_incremental ( self, **write_kw ):
224 - """Writes this category incrementally."""
225 - try:
226 - with self._lock:
227 - # new package dirs could be added during overlay writing,
228 - # so collect the list of package dirs before iterating over it
229 - subdirs = tuple ( self._subdirs.values() )
230 -
231 - for subdir in subdirs:
232 - if subdir.modified:
233 - roverlay.util.dodir ( subdir.physical_location )
234 - subdir.write_incremental ( **write_kw )
235 - except Exception as e:
236 - self.logger.exception ( e )
237 - # --- end of write_incremental (...) ---
238 + self.remove_empty()
239 + # --- end of write (...) ---
240
241 def write_manifest ( self, **manifest_kw ):
242 """Generates Manifest files for all packages in this category.
243
244 diff --git a/roverlay/overlay/creator.py b/roverlay/overlay/creator.py
245 index 9de063c..d12e0a5 100644
246 --- a/roverlay/overlay/creator.py
247 +++ b/roverlay/overlay/creator.py
248 @@ -214,32 +214,15 @@ class OverlayCreator ( object ):
249 self.package_added.inc()
250 # --- end of add_package (...) ---
251
252 - def add_package_file ( self, package_file ):
253 - """Adds a single R package."""
254 - raise Exception ( "to be removed" )
255 - self._pkg_queue.put ( PackageInfo ( filepath=package_file ) )
256 - self.package_added.inc()
257 - # --- end of add_package_file (...) ---
258 -
259 - def add_package_files ( self, *package_files ):
260 - """Adds multiple R packages."""
261 - raise Exception ( "to be removed" )
262 - for p in package_files: self.add_package_file ( p )
263 - self.package_added.inc()
264 - # --- end of add_package_files (...) ---
265 -
266 def write_overlay ( self ):
267 """Writes the overlay.
268
269 arguments:
270 """
271 if self.can_write_overlay:
272 - if self.write_incremental:
273 - self.overlay.finalize_write_incremental()
274 - else:
275 - start = time.time()
276 - self.overlay.write()
277 - self._timestamp ( "overlay written", start )
278 + start = time.time()
279 + self.overlay.write()
280 + self._timestamp ( "overlay written", start )
281 else:
282 self.logger.warning ( "Not allowed to write overlay!" )
283 # --- end of write_overlay (...) ---
284 @@ -304,7 +287,6 @@ class OverlayCreator ( object ):
285
286 self._close_workers()
287 close_resolver()
288 - self.overlay.keep_nth_latest ( n=1 )
289 self.closed = True
290 # --- end of close (...) ---
291
292 @@ -429,8 +411,9 @@ class OverlayCreator ( object ):
293 if self.NUMTHREADS > 0:
294 start = time.time()
295 self.logger.warning (
296 - "Running in concurrent mode with %i threads." % self.NUMTHREADS
297 - )
298 + "Running in concurrent mode with {num} threads.".format (
299 + num=self.NUMTHREADS
300 + ) )
301 self._workers = frozenset (
302 self._get_worker ( start_now=True ) \
303 for n in range ( self.NUMTHREADS )
304
305 diff --git a/roverlay/overlay/manifest/__init__.py b/roverlay/overlay/manifest/__init__.py
306 index 9a49c7f..d9f9c0a 100644
307 --- a/roverlay/overlay/manifest/__init__.py
308 +++ b/roverlay/overlay/manifest/__init__.py
309 @@ -11,8 +11,6 @@ _manifest_creation = helpers.ExternalManifestCreation()
310 # for one directory/overlay
311 _manifest_lock = threading.Lock()
312
313 -
314 -
315 def create_manifest ( package_info_list, nofail=False ):
316 """Creates a Manifest for package_info, using the <<best>> implementation
317 available.
318 @@ -35,4 +33,6 @@ def create_manifest ( package_info_list, nofail=False ):
319 raise
320 finally:
321 _manifest_lock.release()
322 +
323 + return ret
324 # --- end of create_manifest (...) ---
325
326 diff --git a/roverlay/overlay/package.py b/roverlay/overlay/package.py
327 index a2e4d9b..d2662bd 100644
328 --- a/roverlay/overlay/package.py
329 +++ b/roverlay/overlay/package.py
330 @@ -120,6 +120,21 @@ class PackageDir ( object ):
331 return False
332 # --- end of add (...) ---
333
334 + def check_empty ( self ):
335 + """Similar to empty(),
336 + but also removes the directory of this PackageDir.
337 + """
338 + if len ( self._packages ) == 0:
339 + if os.path.isdir ( self.physical_location ):
340 + try:
341 + os.rmdir ( self.physical_location )
342 + except Exception as e:
343 + self.logger.exception ( e )
344 + return True
345 + else:
346 + return False
347 + # --- end of check_empty (...) ---
348 +
349 def empty ( self ):
350 """Returns True if no ebuilds stored, else False.
351 Note that "not empty" doesn't mean "has ebuilds to write" or "has
352 @@ -129,25 +144,6 @@ class PackageDir ( object ):
353 return len ( self._packages ) == 0
354 # --- end of empty (...) ---
355
356 - def finalize_write_incremental ( self ):
357 - """Method that finalizes incremental writing, i.e. write outstanding
358 - ebuilds and write metadata.xml, Manifest.
359 - """
360 - with self._lock:
361 - if self.has_ebuilds():
362 - if self.modified:
363 - self.write_ebuilds ( overwrite=False )
364 - if self._need_metadata:
365 - self.write_metadata()
366 - if self._need_manifest:
367 - self.write_manifest()
368 - else:
369 - self.logger.critical (
370 - "<<todo>>: please clean up this dir: {}.".format (
371 - self.physical_location
372 - ) )
373 - # --- end of finalize_write_incremental (...) ---
374 -
375 def fs_cleanup ( self ):
376 """Cleans up the filesystem location of this package dir.
377 To be called after keep_nth_latest, calls finalize_write_incremental().
378 @@ -158,11 +154,9 @@ class PackageDir ( object ):
379 # --- end of rmtree_error (...) ---
380
381 with self._lock:
382 - if self.has_ebuilds():
383 - # !!! FIXME this doesn't work if no ebuilds written, but
384 - # old ones removed -> DISTDIR unknown during Manifest creation
385 - self.finalize_write_incremental()
386 - elif os.path.isdir ( self.physical_location ):
387 + if os.path.isdir ( self.physical_location ) \
388 + and not self.has_ebuilds() \
389 + :
390 # destroy self.physical_location
391 shutil.rmtree ( self.physical_location, onerror=rmtree_error )
392 # --- end of fs_cleanup (...) ---
393 @@ -193,53 +187,58 @@ class PackageDir ( object ):
394 arguments:
395 * n -- # of packages/ebuilds to keep
396 * cautious -- if True: be extra careful, verify that ebuilds exist
397 + as file; note that this will ignore all
398 + ebuilds that haven't been written to the file-
399 + system yet (which implies an extra overhead,
400 + you'll have to write all ebuilds first)
401 """
402 -
403 - # create the list of packages to iterate over,
404 - # * package has to have an ebuild_file
405 - # * sort them by version in reverse order (latest package gets index 0)
406 + def is_ebuild_cautious ( p_tuple ):
407 + # package has to have an ebuild_file that exists
408 + efile = p_tuple [1] ['ebuild_file' ]
409 + if efile is not None:
410 + return os.path.isfile ( efile )
411 + else:
412 + return False
413 + # --- end of is_ebuild_cautious (...) ---
414 +
415 + def is_ebuild ( p_tuple ):
416 + # package has to have an ebuild_file or an ebuild entry
417 + return (
418 + p_tuple [1] ['ebuild_file'] or p_tuple [1] ['ebuild']
419 + ) is not None
420 + # --- end of is_ebuild (...) ---
421 +
422 + # create the list of packages to iterate over (cautious/non-cautious),
423 + # sort them by version in reverse order
424 packages = reversed ( sorted (
425 filter (
426 - lambda p : p [1] ['ebuild_file'] is not None,
427 - self._packages.items()
428 + function=is_ebuild if not cautious else is_ebuild_cautious,
429 + iterable=self._packages.items()
430 ),
431 key=lambda p : p [1] ['version']
432 ) )
433
434 + if n < 1:
435 + raise Exception ( "Must keep more than zero ebuilds." )
436 +
437 kept = 0
438 ecount = 0
439 - if not cautious:
440 - # could use a slice here, too
441 - for pvr, pkg in packages:
442 - ecount += 1
443 - if kept < n:
444 - printself.logger.debug ( "Keeping {pvr}.".format ( pvr=pvr ) )
445 - kept += 1
446 - else:
447 - self.logger.debug ( "Removing {pvr}.".format ( pvr=pvr ) )
448 - self.purge_package ( pvr )
449 - else:
450 - for pvr, pkg in packages:
451 - ecount += 1
452 - if os.path.isfile ( pkg ['ebuild_file'] ):
453 - if kept < n:
454 - self.logger.debug ( "Keeping {pvr}.".format ( pvr=pvr ) )
455 - kept += 1
456 - else:
457 - self.logger.debug ( "Removing {pvr}.".format ( pvr=pvr ) )
458 - self.purge_package ( pvr )
459 - else:
460 - self.logger.error (
461 - "{efile} is assumed to exist as file but doesn't!".format (
462 - efile=pkg ['ebuild_file']
463 - ) )
464
465 - # FIXME/IGNORE: this doesn't count inexistent files as kept
466 + for pvr, pkg in packages:
467 + ecount += 1
468 + if kept < n:
469 + self.logger.debug ( "Keeping {pvr}.".format ( pvr=pvr ) )
470 + kept += 1
471 + else:
472 + self.logger.debug ( "Removing {pvr}.".format ( pvr=pvr ) )
473 + self.purge_package ( pvr )
474 +
475 self.logger.debug (
476 "Kept {kept}/{total} ebuilds.".format ( kept=kept, total=ecount )
477 )
478
479 # FIXME: Manifest is now invalid and dir could be "empty" (no ebuilds)
480 + # FIXME: force metadata regeneration
481 # --- end of keep_nth_latest (...) ---
482
483 def list_versions ( self ):
484 @@ -252,7 +251,8 @@ class PackageDir ( object ):
485 self._need_metadata = True
486 self.modified = True
487 if self.runtime_incremental:
488 - return self.write_incremental()
489 + with self._lock:
490 + return self.write_ebuilds ( overwrite=False )
491 else:
492 return True
493 # --- end of new_ebuild (...) ---
494 @@ -325,48 +325,104 @@ class PackageDir ( object ):
495 arguments:
496 * stream -- stream to use, defaults to sys.stderr
497
498 - returns: None (implicit)
499 + returns: True
500
501 raises:
502 - * IOError
503 + * passes all exceptions (IOError, ..)
504 """
505 - return self.write ( shared_fh=stream )
506 + self.write_ebuilds ( overwrite=True, shared_fh=stream )
507 + self.write_metadata ( shared_fh=stream )
508 + return True
509 # --- end of show (...) ---
510
511 + def virtual_cleanup ( self ):
512 + """Removes all PackageInfos from this structure that don't have an
513 + 'ebuild_file' entry.
514 + """
515 + with self._lock:
516 + # keyset may change during this method
517 + for pvr in tuple ( self._packages.keys() ):
518 + if self._packages [pvr] ['ebuild_file'] is None:
519 + del self._packages [pvr]
520 + # -- lock
521 + # --- end of virtual_cleanup (...) ---
522 +
523 def write ( self,
524 - shared_fh=None, overwrite_ebuilds=True,
525 - write_ebuilds=True, write_manifest=True, write_metadata=True
526 + overwrite_ebuilds=False,
527 + write_ebuilds=True, write_manifest=True, write_metadata=True,
528 + cleanup=True, keep_n_ebuilds=None, cautious=True
529 ):
530 """Writes this directory to its (existent!) filesystem location.
531
532 arguments:
533 - * shared_fh -- if set and not None: write everyting into <fh>
534 * write_ebuilds -- if set and False: don't write ebuilds
535 * write_manifest -- if set and False: don't write the Manifest file
536 * write_metadata -- if set and False: don't write the metadata file
537 - * overwrite_ebuilds -- if set and False: don't overwrite ebuilds
538 -
539 - returns: None (implicit)
540 + * overwrite_ebuilds -- whether to overwrite ebuilds,
541 + None means autodetect, enable overwriting
542 + if not modified since last write
543 + Defaults to False
544 + * cleanup -- clean up after writing
545 + Defaults to True
546 + * keep_n_ebuilds -- # of ebuilds to keep (remove all others),
547 + Defaults to None (disable) and implies cleanup
548 + * cautious -- be cautious when keeping the nth latest ebuilds,
549 + this has some overhead
550 + Defaults to True
551 +
552 + returns: success (True/False)
553
554 raises:
555 - * IOError (?)
556 + * passes IOError
557 """
558 - with self._lock:
559 - # mkdir not required here, overlay.Category does this
560 + # NOTE, replaces:
561 + # * old write: overwrite_ebuilds=True
562 + # * finalize_write_incremental : no extra args
563 + # * write_incremental : write_manifest=False, write_metadata=False,
564 + # cleanup=False (or use write_ebuilds)
565 + # BREAKS: show(), which has its own method/function now
566
567 - # write ebuilds
568 - if write_ebuilds:
569 - self.write_ebuilds (
570 - overwrite=overwrite_ebuilds, shared_fh=shared_fh
571 - )
572 + cleanup = cleanup or ( keep_n_ebuilds is not None )
573
574 - # write metadata
575 - if write_metadata:
576 - self.write_metadata ( shared_fh=shared_fh )
577 + success = True
578 + with self._lock:
579 + if self.has_ebuilds():
580 + # not cautious: remove ebuilds before writing them
581 + if not cautious and keep_n_ebuilds is not None:
582 + self.keep_nth_latest ( n=keep_n_ebuilds, cautious=False )
583 +
584 + # write ebuilds
585 + if self.modified and write_ebuilds:
586 + success = self.write_ebuilds (
587 + # None ~ not modified
588 + overwrite = overwrite_ebuilds \
589 + if overwrite_ebuilds is not None \
590 + else not self.modified
591 + )
592
593 - # write manifest (only if shared_fh is None)
594 - if write_manifest and shared_fh is None:
595 - self.write_manifest()
596 + # cautious: remove ebuilds after writing them
597 + if cautious and keep_n_ebuilds is not None:
598 + self.keep_nth_latest ( n=keep_n_ebuilds, cautious=True )
599 +
600 + # write metadata
601 + if self._need_metadata and write_metadata:
602 + # don't mess around with short-circuit bool evaluation
603 + if not self.write_metadata():
604 + success = False
605 +
606 + # write manifest (only if shared_fh is None)
607 + if self._need_manifest and write_manifest:
608 + if not self.write_manifest():
609 + success = False
610 + # -- has_ebuilds?
611 +
612 + if cleanup:
613 + self.virtual_cleanup()
614 + self.fs_cleanup()
615 +
616 + # FIXME / TODO call fs_cleanup
617 + # -- lock
618 + return success
619 # --- end of write (...) ---
620
621 def write_ebuilds ( self, overwrite, shared_fh=None ):
622 @@ -390,7 +446,6 @@ class PackageDir ( object ):
623 """
624 _success = False
625 try:
626 - util.dodir ( self.physical_location )
627 fh = open ( efile, 'w' ) if shared_fh is None else shared_fh
628 if ebuild_header is not None:
629 fh.write ( str ( ebuild_header ) )
630 @@ -426,7 +481,14 @@ class PackageDir ( object ):
631
632 all_ebuilds_written = True
633
634 + # don't call dodir if shared_fh is set
635 + hasdir = bool ( shared_fh is not None )
636 +
637 for efile, p_info in ebuilds_to_write():
638 + if not hasdir:
639 + util.dodir ( self.physical_location, mkdir_p=True )
640 + hasdir = True
641 +
642 if write_ebuild ( efile, p_info ['ebuild'] ):
643 self._need_manifest = True
644
645 @@ -452,17 +514,12 @@ class PackageDir ( object ):
646 return all_ebuilds_written
647 # --- end of write_ebuilds (...) ---
648
649 - def write_incremental ( self ):
650 - with self._lock:
651 - return self.write_ebuilds ( overwrite=False )
652 - # --- end of write_incremental (...) ---
653 -
654 - def write_manifest ( self ):
655 + def write_manifest ( self, ignore_empty=False ):
656 """Generates and writes the Manifest file for this package.
657
658 expects: called after writing metadata/ebuilds
659
660 - returns: None (implicit)
661 + returns: success (True/False)
662
663 raises:
664 * Exception if no ebuild exists
665 @@ -471,47 +528,64 @@ class PackageDir ( object ):
666 # it should be sufficient to call create_manifest for one ebuild,
667 # choosing the latest one that exists in self.physical_location and
668 # has enough data (DISTDIR, EBUILD_FILE) for this task.
669 + # Additionally, all DISTDIRs (multiple repos, sub directories) have
670 + # to be collected and passed to Manifest creation.
671 + # => collect suitable PackageInfo objects from self._packages
672 #
673 - # metadata.xml's full path cannot be used for manifest creation here
674 - # 'cause DISTDIR would be unknown
675 - #
676 -
677 - # collect suitable PackageInfo instances
678 pkgs_for_manifest = tuple (
679 p for p in self._packages.values() \
680 if p.has ( 'distdir', 'ebuild_file' )
681 )
682
683 if pkgs_for_manifest:
684 - manifest.create_manifest ( pkgs_for_manifest, nofail=False )
685 - self._need_manifest = False
686 + if manifest.create_manifest ( pkgs_for_manifest, nofail=False ):
687 + self._need_manifest = False
688 + return True
689 + elif ignore_empty:
690 + return True
691 else:
692 + # FIXME: debug statements
693 + # FIXME: remove excpetion, maybe delete Manifest in this case,..
694 + for pvr, p in self._packages.items():
695 + print ( "{} {} ebuild={} efile={} has={}".format (
696 + pvr, p, p.has ('ebuild'), p ['ebuild_file'], self.has_ebuilds()
697 + ) )
698 +
699 raise Exception (
700 - "No ebuild written so far! I really don't know what do to!"
701 - )
702 + 'In {mydir}: No ebuild written so far! '
703 + 'I really don\'t know what do to!'.format (
704 + mydir=self.physical_location
705 + ) )
706 +
707 + return False
708 # --- end of write_manifest (...) ---
709
710 def write_metadata ( self, shared_fh=None ):
711 - """Writes metadata for this package."""
712 + """Writes metadata for this package.
713 +
714 + returns: success (True/False)
715 + """
716 + success = False
717 try:
718 self.generate_metadata ( skip_if_existent=True )
719
720 if shared_fh is None:
721 + util.dodir ( self.physical_location, mkdir_p=True )
722 if self._metadata.write():
723 self._need_metadata = False
724 self._need_manifest = True
725 - return True
726 + success = True
727 else:
728 self.logger.error (
729 "Failed to write metadata file {}.".format (
730 self._metadata.filepath
731 )
732 )
733 - return False
734 else:
735 self._metadata.show ( shared_fh )
736 - return True
737 + success = True
738 except Exception as e:
739 self.logger.exception ( e )
740 - return False
741 +
742 + return success
743 # --- end of write_metadata (...) ---
744
745 diff --git a/roverlay/overlay/root.py b/roverlay/overlay/root.py
746 index 363bdb5..219fd70 100644
747 --- a/roverlay/overlay/root.py
748 +++ b/roverlay/overlay/root.py
749 @@ -48,10 +48,10 @@ class Overlay ( object ):
750
751 self.incremental = incremental
752 if self.incremental:
753 -
754 - self._incremental_write_lock = threading.Lock()
755 + # this is multiple-run incremental writing (in contrast to runtime
756 + # incremental writing, which writes ebuilds as soon as they're
757 + # ready) FIXME: split incremental <-> runtime_incremental
758 self.scan()
759 - self._init_overlay ( reimport_eclass=True )
760
761 # --- end of __init__ (...) ---
762
763 @@ -73,8 +73,6 @@ class Overlay ( object ):
764 incremental=self.incremental
765 )
766 self._categories [category] = newcat
767 - if self.incremental:
768 - util.dodir ( newcat.physical_location )
769 finally:
770 self._catlock.release()
771
772 @@ -226,50 +224,10 @@ class Overlay ( object ):
773 return cat.add ( package_info )
774 # --- end of add (...) ---
775
776 - def finalize_write_incremental ( self ):
777 - """Writes metadata + Manifest for all packages."""
778 - for cat in self._categories.values():
779 - cat.finalize_write_incremental()
780 - # --- end of finalize_incremental (...) ---
781 -
782 - def generate_manifest ( self, **manifest_kw ):
783 - """Generates Manifest files for all ebuilds in this overlay that exist
784 - physically/in filesystem.
785 - Manifest files are automatically created when calling write().
786 -
787 - arguments:
788 - * **manifest_kw -- see PackageDir.generate_manifest(...)
789 -
790 - returns: None (implicit)
791 - """
792 - for cat in self._categories.values():
793 - cat.generate_manifest ( **manifest_kw )
794 - # --- end of generate_manifest (...) ---
795 -
796 - def generate_metadata ( self, **metadata_kw ):
797 - """Tells the overlay's categories to create metadata.
798 - You don't have to call this before write()/show() unless you want to use
799 - special metadata options.
800 -
801 - arguments:
802 - * **metadata_kw -- keywords for package.PackageDir.generate_metadata(...)
803 -
804 - returns: None (implicit)
805 - """
806 - for cat in self._categories.values():
807 - cat.generate_metadata ( **metadata_kw )
808 - # --- end of generate_metadata (...) ---
809 -
810 def has_dir ( self, _dir ):
811 return os.path.isdir ( self.physical_location + os.sep + _dir )
812 # --- end of has_category (...) ---
813
814 - def keep_nth_latest ( self, *args, **kwargs ):
815 - """See package.py:PackageDir:keep_nth_latest."""
816 - for cat in self._categories.values():
817 - cat.keep_nth_latest ( *args, **kwargs )
818 - # --- end of keep_nth_latest (...) ---
819 -
820 def list_packages ( self, for_deprules=True ):
821 for cat in self._categories.values():
822 for package in cat.list_packages ( for_deprules=True ):
823 @@ -313,9 +271,9 @@ class Overlay ( object ):
824 cat.show ( **show_kw )
825 # --- end of show (...) ---
826
827 - def write ( self, **write_kw ):
828 + def write ( self ):
829 """Writes the overlay to its physical location (filesystem), including
830 - metadata and Manifest files.
831 + metadata and Manifest files as well as cleanup actions.
832
833 arguments:
834 * **write_kw -- keywords for package.PackageDir.write(...)
835 @@ -327,35 +285,27 @@ class Overlay ( object ):
836 ! TODO/FIXME/DOC: This is not thread-safe, it's expected to be called
837 when ebuild creation is done.
838 """
839 - raise Exception ( "to be removed/replaced" )
840 - # writing profiles/ here, rewriting categories/ later
841 self._init_overlay ( reimport_eclass=True )
842
843 for cat in self._categories.values():
844 - if not cat.empty():
845 - util.dodir ( cat.physical_location )
846 - cat.write ( **write_kw )
847 + cat.write (
848 + overwrite_ebuilds=False,
849 + keep_n_ebuilds=config.get ( 'OVERLAY.keep_nth_latest', None ),
850 + cautious=True
851 + )
852 # --- end of write (...) ---
853
854 - def write_incremental ( self, **write_kw ):
855 - """Writes all ebuilds that have been modified since the last write call.
856 - Note that there are currently two modes of incremental writing:
857 - (a) per-PackageDir incremental writing triggered by the new_ebuild()
858 - event method and (b) "batched" incremental writing (this method) which
859 - writes all modified PackageDirs.
860 - """
861 - # FIXME merge with write(), making incremental writing the only option
862 - # FIXME finalize_write_incremental?
863 - if not self._incremental_write_lock.acquire():
864 - # another incremental write is running, drop this request
865 - return
866 + def write_manifest ( self, **manifest_kw ):
867 + """Generates Manifest files for all ebuilds in this overlay that exist
868 + physically/in filesystem.
869 + Manifest files are automatically created when calling write().
870
871 - try:
872 - util.dodir ( self.physical_location )
873 - cats = tuple ( self._categories.values() )
874 - for cat in cats:
875 - util.dodir ( cat.physical_location )
876 - cat.write_incremental ( **write_kw )
877 - finally:
878 - self._incremental_write_lock.release()
879 - # --- end of write_incremental (...) ---
880 + arguments:
881 + * **manifest_kw -- see PackageDir.generate_manifest(...)
882 +
883 + returns: None (implicit)
884 + """
885 + # FIXME: it would be good to ensure that profiles/categories exist
886 + for cat in self._categories.values():
887 + cat.write_manifest ( **manifest_kw )
888 + # --- end of write_manifest (...) ---