initial commit
[ebuildfind.git] / commands / lib / layman / action.py
blobb7b36b641ce3b36bd894533db6575d4b3b27affd
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3 #################################################################################
4 # LAYMAN ACTIONS
5 #################################################################################
6 # File: action.py
8 # Handles layman actions.
10 # Copyright:
11 # (c) 2005 - 2008 Gunnar Wrobel
12 # Distributed under the terms of the GNU General Public License v2
14 # Author(s):
15 # Gunnar Wrobel <wrobel@gentoo.org>
17 ''' Provides the different actions that can be performed by layman.'''
19 __version__ = "$Id: action.py 312 2007-04-09 19:45:49Z wrobel $"
21 #===============================================================================
23 # Dependencies
25 #-------------------------------------------------------------------------------
27 import os, sys
29 from layman.db import DB, RemoteDB
31 from layman.debug import OUT
33 #===============================================================================
35 # Class Fetch
37 #-------------------------------------------------------------------------------
39 class Fetch:
40 ''' Fetches the overlay listing.
42 >>> import os
43 >>> here = os.path.dirname(os.path.realpath(__file__))
44 >>> cache = os.tmpnam()
45 >>> config = {'overlays' :
46 ... 'file://' + here + '/tests/testfiles/global-overlays.xml',
47 ... 'cache' : cache,
48 ... 'nocheck' : True,
49 ... 'proxy' : None,
50 ... 'quietness':3}
51 >>> a = Fetch(config)
52 >>> a.run()
54 >>> b = open(a.db.path(config['overlays']))
55 >>> b.readlines()[24]
56 ' A collection of ebuilds from Gunnar Wrobel [wrobel@gentoo.org].\\n'
58 >>> b.close()
59 >>> os.unlink(a.db.path(config['overlays']))
61 >>> a.db.overlays.keys()
62 [u'wrobel', u'wrobel-stable']
63 '''
65 def __init__(self, config):
66 self.db = RemoteDB(config)
68 def run(self):
69 '''Fetch the overlay listing.'''
70 try:
71 self.db.cache()
72 except Exception, error:
73 OUT.die('Failed to fetch overlay list!\nError was: '
74 + str(error))
76 return 0
78 #===============================================================================
80 # Class Sync
82 #-------------------------------------------------------------------------------
84 class Sync:
85 ''' Syncs the selected overlays.'''
87 def __init__(self, config):
89 self.db = DB(config)
91 self.rdb = RemoteDB(config)
93 self.quiet = int(config['quietness']) < 3
95 self.selection = config['sync']
97 if config['sync_all'] or 'ALL' in self.selection:
98 self.selection = self.db.overlays.keys()
100 enc = sys.getfilesystemencoding()
101 if enc:
102 self.selection = [i.decode(enc) for i in self.selection]
104 def run(self):
105 '''Synchronize the overlays.'''
107 OUT.debug('Updating selected overlays', 6)
109 warnings = []
110 success = []
111 for i in self.selection:
112 ordb = self.rdb.select(i)
113 odb = self.db.select(i)
114 if ordb and odb and ordb.src != odb.src:
115 warnings.append(
116 'The source of the overlay "' + i + '" seems to have c'
117 'hanged. You currently sync from "' + odb.src + '" whi'
118 'le the global layman list reports "' + ordb.src + '" '
119 'as correct location. Please consider removing and rea'
120 'dding the overlay!')
122 try:
123 self.db.sync(i, self.quiet)
124 success.append('Successfully synchronized overlay "' + i + '".')
125 except Exception, error:
126 warnings.append(
127 'Failed to sync overlay "' + i + '".\nError was: '
128 + str(error))
130 if success:
131 OUT.info('\nSuccess:\n------\n', 3)
132 for i in success:
133 OUT.info(i, 3)
135 if warnings:
136 OUT.warn('\nErrors:\n------\n', 2)
137 for i in warnings:
138 OUT.warn(i + '\n', 2)
139 return 1
141 return 0
143 #===============================================================================
145 # Class Add
147 #-------------------------------------------------------------------------------
149 class Add:
150 ''' Adds the selected overlays.'''
152 def __init__(self, config):
154 self.config = config
156 self.db = DB(config)
158 self.rdb = RemoteDB(config)
160 self.quiet = int(config['quietness']) < 3
162 self.selection = config['add']
164 enc = sys.getfilesystemencoding()
165 if enc:
166 self.selection = [i.decode(enc) for i in self.selection]
168 if 'ALL' in self.selection:
169 self.selection = self.rdb.overlays.keys()
171 def run(self):
172 '''Add the overlay.'''
174 OUT.debug('Adding selected overlays', 6)
176 result = 0
178 for i in self.selection:
179 overlay = self.rdb.select(i)
181 OUT.debug('Selected overlay', 7)
183 if overlay:
184 try:
185 self.db.add(overlay, self.quiet)
186 OUT.info('Successfully added overlay "' + i + '".', 2)
187 except Exception, error:
188 OUT.warn('Failed to add overlay "' + i + '".\nError was: '
189 + str(error), 2)
190 result = 1
191 else:
192 OUT.warn('Overlay "' + i + '" does not exist!', 2)
193 result = 1
195 return result
197 #===============================================================================
199 # Class Delete
201 #-------------------------------------------------------------------------------
203 class Delete:
204 ''' Deletes the selected overlays.'''
206 def __init__(self, config):
208 self.db = DB(config)
210 self.selection = config['delete']
212 enc = sys.getfilesystemencoding()
213 if enc:
214 self.selection = [i.decode(enc) for i in self.selection]
216 if 'ALL' in self.selection:
217 self.selection = self.db.overlays.keys()
219 def run(self):
220 '''Delete the overlay.'''
222 OUT.debug('Deleting selected overlays', 6)
224 result = 0
226 for i in self.selection:
227 overlay = self.db.select(i)
229 OUT.debug('Selected overlay', 7)
231 if overlay:
232 try:
233 self.db.delete(overlay)
234 OUT.info('Successfully deleted overlay "' + i + '".', 2)
235 except Exception, error:
236 OUT.warn('Failed to delete overlay "' + i + '".\nError was: '
237 + str(error), 2)
238 result = 1
239 else:
240 OUT.warn('Overlay "' + i + '" does not exist!', 2)
241 result = 1
243 return result
245 #===============================================================================
247 # Class Info
249 #-------------------------------------------------------------------------------
251 class Info:
252 ''' Print information about the specified overlays.
254 >>> import os
255 >>> here = os.path.dirname(os.path.realpath(__file__))
256 >>> cache = os.tmpnam()
257 >>> config = {'overlays' :
258 ... 'file://' + here + '/tests/testfiles/global-overlays.xml',
259 ... 'cache' : cache,
260 ... 'proxy' : None,
261 ... 'info' : ['wrobel'],
262 ... 'nocheck' : False,
263 ... 'verbose': False,
264 ... 'quietness':3}
265 >>> a = Info(config)
266 >>> a.rdb.cache()
267 >>> OUT.color_off()
268 >>> a.run()
269 * wrobel
270 * ~~~~~~
271 * Source : https://overlays.gentoo.org/svn/dev/wrobel
272 * Contact : nobody@gentoo.org
273 * Type : Subversion; Priority: 10
275 * Description:
276 * Test
281 def __init__(self, config):
283 OUT.debug('Creating RemoteDB handler', 6)
285 self.rdb = RemoteDB(config)
286 self.config = config
288 self.selection = config['info']
290 enc = sys.getfilesystemencoding()
291 if enc:
292 self.selection = [i.decode(enc) for i in self.selection]
294 if 'ALL' in self.selection:
295 self.selection = self.rdb.overlays.keys()
297 def run(self):
298 ''' Print information about the selected overlays.'''
300 result = 0
302 for i in self.selection:
303 overlay = self.rdb.select(i)
305 if overlay:
306 # Is the overlay supported?
307 OUT.info(overlay.__str__(), 1)
308 if not overlay.is_official():
309 OUT.warn('*** This is no official gentoo overlay ***\n', 1)
310 if not overlay.is_supported():
311 OUT.error('*** You are lacking the necessary tools to install t'
312 'his overlay ***\n')
313 else:
314 OUT.warn('Overlay "' + i + '" does not exist!', 2)
315 result = 1
317 return result
319 #===============================================================================
321 # Class List
323 #-------------------------------------------------------------------------------
325 class List:
326 ''' Lists the available overlays.
328 >>> import os
329 >>> here = os.path.dirname(os.path.realpath(__file__))
330 >>> cache = os.tmpnam()
331 >>> config = {'overlays' :
332 ... 'file://' + here + '/tests/testfiles/global-overlays.xml',
333 ... 'cache' : cache,
334 ... 'proxy' : None,
335 ... 'nocheck' : False,
336 ... 'verbose': False,
337 ... 'quietness':3,
338 ... 'width':80}
339 >>> a = List(config)
340 >>> a.rdb.cache()
341 >>> OUT.color_off()
342 >>> a.run()
343 * wrobel [Subversion] (https://o.g.o/svn/dev/wrobel )
345 >>> a.config['verbose'] = True
346 >>> a.run()
347 * wrobel
348 * ~~~~~~
349 * Source : https://overlays.gentoo.org/svn/dev/wrobel
350 * Contact : nobody@gentoo.org
351 * Type : Subversion; Priority: 10
353 * Description:
354 * Test
356 * *** This is no official gentoo overlay ***
358 * wrobel-stable
359 * ~~~~~~~~~~~~~
360 * Source : rsync://gunnarwrobel.de/wrobel-stable
361 * Contact : nobody@gentoo.org
362 * Type : Rsync; Priority: 50
364 * Description:
365 * A collection of ebuilds from Gunnar Wrobel [wrobel@gentoo.org].
370 def __init__(self, config):
372 OUT.debug('Creating RemoteDB handler', 6)
374 self.rdb = RemoteDB(config)
375 self.config = config
377 def run(self):
378 ''' List the available overlays.'''
380 for i in self.rdb.list(self.config['verbose'], self.config['width']):
381 # Is the overlay supported?
382 if i[1]:
383 # Is this an official overlay?
384 if i[2]:
385 OUT.info(i[0], 1)
386 # Unofficial overlays will only be listed if we are not
387 # checking or listing verbose
388 elif self.config['nocheck'] or self.config['verbose']:
389 # Give a reason why this is marked yellow if it is a verbose
390 # listing
391 if self.config['verbose']:
392 OUT.warn('*** This is no official gentoo overlay ***\n', 1)
393 OUT.warn(i[0], 1)
394 # Unsupported overlays will only be listed if we are not checking
395 # or listing verbose
396 elif self.config['nocheck'] or self.config['verbose']:
397 # Give a reason why this is marked red if it is a verbose
398 # listing
399 if self.config['verbose']:
400 OUT.error('*** You are lacking the necessary tools to insta'
401 'll this overlay ***\n')
402 OUT.error(i[0])
404 return 0
406 #===============================================================================
408 # Class ListLocal
410 #-------------------------------------------------------------------------------
412 class ListLocal:
413 ''' Lists the local overlays.'''
415 def __init__(self, config):
416 self.db = DB(config)
417 self.config = config
419 def run(self):
420 '''List the overlays.'''
422 for i in self.db.list(self.config['verbose']):
424 OUT.debug('Printing local overlay.', 8)
426 # Is the overlay supported?
427 if i[1]:
428 # Is this an official overlay?
429 if i[2]:
430 OUT.info(i[0], 1)
431 # Unofficial overlays will only be listed if we are not
432 # checking or listing verbose
433 else:
434 # Give a reason why this is marked yellow if it is a verbose
435 # listing
436 if self.config['verbose']:
437 OUT.warn('*** This is no official gentoo overlay ***\n', 1)
438 OUT.warn(i[0], 1)
439 # Unsupported overlays will only be listed if we are not checking
440 # or listing verbose
441 else:
442 # Give a reason why this is marked red if it is a verbose
443 # listing
444 if self.config['verbose']:
445 OUT.error('*** You are lacking the necessary tools to insta'
446 'll this overlay ***\n')
447 OUT.error(i[0])
449 return 0
451 #===============================================================================
453 # Class Actions
455 #-------------------------------------------------------------------------------
457 class Actions:
458 '''Dispatches to the actions the user selected. '''
460 # Given in order of precedence
461 actions = [('fetch', Fetch),
462 ('add', Add),
463 ('sync', Sync),
464 ('info', Info),
465 ('sync_all', Sync),
466 ('delete', Delete),
467 ('list', List),
468 ('list_local', ListLocal),]
470 def __init__(self, config):
472 # Make fetching the overlay list a default action
473 if not 'nofetch' in config.keys():
474 # Actions that implicitely call the fetch operation before
475 fetch_actions = ['fetch', 'sync', 'sync_all', 'list']
476 for i in fetch_actions:
477 if i in config.keys():
478 # Implicitely call fetch, break loop
479 Fetch(config).run()
480 break
482 result = 0
484 # Set the umask
485 umask = config['umask']
486 try:
487 new_umask = int(umask, 8)
488 old_umask = os.umask(new_umask)
489 except Exception, error:
490 OUT.die('Failed setting to umask "' + umask + '"!\nError was: '
491 + str(error))
493 for i in self.actions:
495 OUT.debug('Checking for action', 7)
497 if i[0] in config.keys():
498 result += i[1](config).run()
500 # Reset umask
501 os.umask(old_umask)
503 if not result:
504 sys.exit(0)
505 else:
506 sys.exit(1)
508 #===============================================================================
510 # Testing
512 #-------------------------------------------------------------------------------
514 if __name__ == '__main__':
515 import doctest, sys
517 # Ignore warnings here. We are just testing
518 from warnings import filterwarnings, resetwarnings
519 filterwarnings('ignore')
521 doctest.testmod(sys.modules[__name__])
523 resetwarnings()