Package CedarBackup2 :: Module util
[hide private]
[frames] | no frames]

Source Code for Module CedarBackup2.util

   1  # -*- coding: iso-8859-1 -*- 
   2  # vim: set ft=python ts=3 sw=3 expandtab: 
   3  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
   4  # 
   5  #              C E D A R 
   6  #          S O L U T I O N S       "Software done right." 
   7  #           S O F T W A R E 
   8  # 
   9  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
  10  # 
  11  # Copyright (c) 2004-2008,2010 Kenneth J. Pronovici. 
  12  # All rights reserved. 
  13  # 
  14  # Portions copyright (c) 2001, 2002 Python Software Foundation. 
  15  # All Rights Reserved. 
  16  # 
  17  # This program is free software; you can redistribute it and/or 
  18  # modify it under the terms of the GNU General Public License, 
  19  # Version 2, as published by the Free Software Foundation. 
  20  # 
  21  # This program is distributed in the hope that it will be useful, 
  22  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
  23  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
  24  # 
  25  # Copies of the GNU General Public License are available from 
  26  # the Free Software Foundation website, http://www.gnu.org/. 
  27  # 
  28  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
  29  # 
  30  # Author   : Kenneth J. Pronovici <pronovic@ieee.org> 
  31  # Language : Python (>= 2.5) 
  32  # Project  : Cedar Backup, release 2 
  33  # Revision : $Id: util.py 1023 2011-10-11 23:44:50Z pronovic $ 
  34  # Purpose  : Provides general-purpose utilities. 
  35  # 
  36  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
  37   
  38  ######################################################################## 
  39  # Module documentation 
  40  ######################################################################## 
  41   
  42  """ 
  43  Provides general-purpose utilities.  
  44   
  45  @sort: AbsolutePathList, ObjectTypeList, RestrictedContentList, RegexMatchList, 
  46         RegexList, _Vertex, DirectedGraph, PathResolverSingleton,  
  47         sortDict, convertSize, getUidGid, changeOwnership, splitCommandLine, 
  48         resolveCommand, executeCommand, calculateFileAge, encodePath, nullDevice, 
  49         deriveDayOfWeek, isStartOfWeek, buildNormalizedPath,  
  50         ISO_SECTOR_SIZE, BYTES_PER_SECTOR,  
  51         BYTES_PER_KBYTE, BYTES_PER_MBYTE, BYTES_PER_GBYTE, KBYTES_PER_MBYTE, MBYTES_PER_GBYTE,  
  52         SECONDS_PER_MINUTE, MINUTES_PER_HOUR, HOURS_PER_DAY, SECONDS_PER_DAY,  
  53         UNIT_BYTES, UNIT_KBYTES, UNIT_MBYTES, UNIT_GBYTES, UNIT_SECTORS 
  54   
  55  @var ISO_SECTOR_SIZE: Size of an ISO image sector, in bytes. 
  56  @var BYTES_PER_SECTOR: Number of bytes (B) per ISO sector. 
  57  @var BYTES_PER_KBYTE: Number of bytes (B) per kilobyte (kB). 
  58  @var BYTES_PER_MBYTE: Number of bytes (B) per megabyte (MB). 
  59  @var BYTES_PER_GBYTE: Number of bytes (B) per megabyte (GB). 
  60  @var KBYTES_PER_MBYTE: Number of kilobytes (kB) per megabyte (MB). 
  61  @var MBYTES_PER_GBYTE: Number of megabytes (MB) per gigabyte (GB). 
  62  @var SECONDS_PER_MINUTE: Number of seconds per minute. 
  63  @var MINUTES_PER_HOUR: Number of minutes per hour. 
  64  @var HOURS_PER_DAY: Number of hours per day. 
  65  @var SECONDS_PER_DAY: Number of seconds per day. 
  66  @var UNIT_BYTES: Constant representing the byte (B) unit for conversion. 
  67  @var UNIT_KBYTES: Constant representing the kilobyte (kB) unit for conversion. 
  68  @var UNIT_MBYTES: Constant representing the megabyte (MB) unit for conversion. 
  69  @var UNIT_GBYTES: Constant representing the gigabyte (GB) unit for conversion. 
  70  @var UNIT_SECTORS: Constant representing the ISO sector unit for conversion. 
  71   
  72  @author: Kenneth J. Pronovici <pronovic@ieee.org> 
  73  """ 
  74   
  75   
  76  ######################################################################## 
  77  # Imported modules 
  78  ######################################################################## 
  79   
  80  import sys 
  81  import math 
  82  import os 
  83  import re 
  84  import time 
  85  import logging 
  86  import string  # pylint: disable=W0402 
  87  from subprocess import Popen, STDOUT, PIPE 
  88   
  89  from CedarBackup2.release import VERSION, DATE 
  90   
  91  try: 
  92     import pwd 
  93     import grp 
  94     _UID_GID_AVAILABLE = True    
  95  except ImportError: 
  96     _UID_GID_AVAILABLE = False    
  97   
  98   
  99  ######################################################################## 
 100  # Module-wide constants and variables 
 101  ######################################################################## 
 102   
 103  logger = logging.getLogger("CedarBackup2.log.util") 
 104  outputLogger = logging.getLogger("CedarBackup2.output") 
 105   
 106  ISO_SECTOR_SIZE    = 2048.0   # in bytes 
 107  BYTES_PER_SECTOR   = ISO_SECTOR_SIZE 
 108   
 109  BYTES_PER_KBYTE    = 1024.0 
 110  KBYTES_PER_MBYTE   = 1024.0 
 111  MBYTES_PER_GBYTE   = 1024.0 
 112  BYTES_PER_MBYTE    = BYTES_PER_KBYTE * KBYTES_PER_MBYTE 
 113  BYTES_PER_GBYTE    = BYTES_PER_MBYTE * MBYTES_PER_GBYTE 
 114   
 115  SECONDS_PER_MINUTE = 60.0 
 116  MINUTES_PER_HOUR   = 60.0 
 117  HOURS_PER_DAY      = 24.0 
 118  SECONDS_PER_DAY    = SECONDS_PER_MINUTE * MINUTES_PER_HOUR * HOURS_PER_DAY 
 119   
 120  UNIT_BYTES         = 0 
 121  UNIT_KBYTES        = 1 
 122  UNIT_MBYTES        = 2 
 123  UNIT_GBYTES        = 4 
 124  UNIT_SECTORS       = 3 
 125   
 126  MTAB_FILE          = "/etc/mtab" 
 127   
 128  MOUNT_COMMAND      = [ "mount", ] 
 129  UMOUNT_COMMAND     = [ "umount", ] 
 130   
 131  DEFAULT_LANGUAGE   = "C" 
 132  LANG_VAR           = "LANG" 
 133  LOCALE_VARS        = [ "LC_ADDRESS", "LC_ALL", "LC_COLLATE", 
 134                         "LC_CTYPE", "LC_IDENTIFICATION",  
 135                         "LC_MEASUREMENT", "LC_MESSAGES",  
 136                         "LC_MONETARY", "LC_NAME", "LC_NUMERIC", 
 137                         "LC_PAPER", "LC_TELEPHONE", "LC_TIME", ] 
138 139 140 ######################################################################## 141 # UnorderedList class definition 142 ######################################################################## 143 144 -class UnorderedList(list):
145 146 """ 147 Class representing an "unordered list". 148 149 An "unordered list" is a list in which only the contents matter, not the 150 order in which the contents appear in the list. 151 152 For instance, we might be keeping track of set of paths in a list, because 153 it's convenient to have them in that form. However, for comparison 154 purposes, we would only care that the lists contain exactly the same 155 contents, regardless of order. 156 157 I have come up with two reasonable ways of doing this, plus a couple more 158 that would work but would be a pain to implement. My first method is to 159 copy and sort each list, comparing the sorted versions. This will only work 160 if two lists with exactly the same members are guaranteed to sort in exactly 161 the same order. The second way would be to create two Sets and then compare 162 the sets. However, this would lose information about any duplicates in 163 either list. I've decided to go with option #1 for now. I'll modify this 164 code if I run into problems in the future. 165 166 We override the original C{__eq__}, C{__ne__}, C{__ge__}, C{__gt__}, 167 C{__le__} and C{__lt__} list methods to change the definition of the various 168 comparison operators. In all cases, the comparison is changed to return the 169 result of the original operation I{but instead comparing sorted lists}. 170 This is going to be quite a bit slower than a normal list, so you probably 171 only want to use it on small lists. 172 """ 173
174 - def __eq__(self, other):
175 """ 176 Definition of C{==} operator for this class. 177 @param other: Other object to compare to. 178 @return: True/false depending on whether C{self == other}. 179 """ 180 if other is None: 181 return False 182 selfSorted = self[:] 183 otherSorted = other[:] 184 selfSorted.sort() 185 otherSorted.sort() 186 return selfSorted.__eq__(otherSorted)
187
188 - def __ne__(self, other):
189 """ 190 Definition of C{!=} operator for this class. 191 @param other: Other object to compare to. 192 @return: True/false depending on whether C{self != other}. 193 """ 194 if other is None: 195 return True 196 selfSorted = self[:] 197 otherSorted = other[:] 198 selfSorted.sort() 199 otherSorted.sort() 200 return selfSorted.__ne__(otherSorted)
201
202 - def __ge__(self, other):
203 """ 204 Definition of S{>=} operator for this class. 205 @param other: Other object to compare to. 206 @return: True/false depending on whether C{self >= other}. 207 """ 208 if other is None: 209 return True 210 selfSorted = self[:] 211 otherSorted = other[:] 212 selfSorted.sort() 213 otherSorted.sort() 214 return selfSorted.__ge__(otherSorted)
215
216 - def __gt__(self, other):
217 """ 218 Definition of C{>} operator for this class. 219 @param other: Other object to compare to. 220 @return: True/false depending on whether C{self > other}. 221 """ 222 if other is None: 223 return True 224 selfSorted = self[:] 225 otherSorted = other[:] 226 selfSorted.sort() 227 otherSorted.sort() 228 return selfSorted.__gt__(otherSorted)
229
230 - def __le__(self, other):
231 """ 232 Definition of S{<=} operator for this class. 233 @param other: Other object to compare to. 234 @return: True/false depending on whether C{self <= other}. 235 """ 236 if other is None: 237 return False 238 selfSorted = self[:] 239 otherSorted = other[:] 240 selfSorted.sort() 241 otherSorted.sort() 242 return selfSorted.__le__(otherSorted)
243
244 - def __lt__(self, other):
245 """ 246 Definition of C{<} operator for this class. 247 @param other: Other object to compare to. 248 @return: True/false depending on whether C{self < other}. 249 """ 250 if other is None: 251 return False 252 selfSorted = self[:] 253 otherSorted = other[:] 254 selfSorted.sort() 255 otherSorted.sort() 256 return selfSorted.__lt__(otherSorted)
257
258 259 ######################################################################## 260 # AbsolutePathList class definition 261 ######################################################################## 262 263 -class AbsolutePathList(UnorderedList):
264 265 """ 266 Class representing a list of absolute paths. 267 268 This is an unordered list. 269 270 We override the C{append}, C{insert} and C{extend} methods to ensure that 271 any item added to the list is an absolute path. 272 273 Each item added to the list is encoded using L{encodePath}. If we don't do 274 this, we have problems trying certain operations between strings and unicode 275 objects, particularly for "odd" filenames that can't be encoded in standard 276 ASCII. 277 """ 278
279 - def append(self, item):
280 """ 281 Overrides the standard C{append} method. 282 @raise ValueError: If item is not an absolute path. 283 """ 284 if not os.path.isabs(item): 285 raise ValueError("Not an absolute path: [%s]" % item) 286 list.append(self, encodePath(item))
287
288 - def insert(self, index, item):
289 """ 290 Overrides the standard C{insert} method. 291 @raise ValueError: If item is not an absolute path. 292 """ 293 if not os.path.isabs(item): 294 raise ValueError("Not an absolute path: [%s]" % item) 295 list.insert(self, index, encodePath(item))
296
297 - def extend(self, seq):
298 """ 299 Overrides the standard C{insert} method. 300 @raise ValueError: If any item is not an absolute path. 301 """ 302 for item in seq: 303 if not os.path.isabs(item): 304 raise ValueError("Not an absolute path: [%s]" % item) 305 for item in seq: 306 list.append(self, encodePath(item))
307
308 309 ######################################################################## 310 # ObjectTypeList class definition 311 ######################################################################## 312 313 -class ObjectTypeList(UnorderedList):
314 315 """ 316 Class representing a list containing only objects with a certain type. 317 318 This is an unordered list. 319 320 We override the C{append}, C{insert} and C{extend} methods to ensure that 321 any item added to the list matches the type that is requested. The 322 comparison uses the built-in C{isinstance}, which should allow subclasses of 323 of the requested type to be added to the list as well. 324 325 The C{objectName} value will be used in exceptions, i.e. C{"Item must be a 326 CollectDir object."} if C{objectName} is C{"CollectDir"}. 327 """ 328
329 - def __init__(self, objectType, objectName):
330 """ 331 Initializes a typed list for a particular type. 332 @param objectType: Type that the list elements must match. 333 @param objectName: Short string containing the "name" of the type. 334 """ 335 super(ObjectTypeList, self).__init__() 336 self.objectType = objectType 337 self.objectName = objectName
338
339 - def append(self, item):
340 """ 341 Overrides the standard C{append} method. 342 @raise ValueError: If item does not match requested type. 343 """ 344 if not isinstance(item, self.objectType): 345 raise ValueError("Item must be a %s object." % self.objectName) 346 list.append(self, item)
347
348 - def insert(self, index, item):
349 """ 350 Overrides the standard C{insert} method. 351 @raise ValueError: If item does not match requested type. 352 """ 353 if not isinstance(item, self.objectType): 354 raise ValueError("Item must be a %s object." % self.objectName) 355 list.insert(self, index, item)
356
357 - def extend(self, seq):
358 """ 359 Overrides the standard C{insert} method. 360 @raise ValueError: If item does not match requested type. 361 """ 362 for item in seq: 363 if not isinstance(item, self.objectType): 364 raise ValueError("All items must be %s objects." % self.objectName) 365 list.extend(self, seq)
366
367 368 ######################################################################## 369 # RestrictedContentList class definition 370 ######################################################################## 371 372 -class RestrictedContentList(UnorderedList):
373 374 """ 375 Class representing a list containing only object with certain values. 376 377 This is an unordered list. 378 379 We override the C{append}, C{insert} and C{extend} methods to ensure that 380 any item added to the list is among the valid values. We use a standard 381 comparison, so pretty much anything can be in the list of valid values. 382 383 The C{valuesDescr} value will be used in exceptions, i.e. C{"Item must be 384 one of values in VALID_ACTIONS"} if C{valuesDescr} is C{"VALID_ACTIONS"}. 385 386 @note: This class doesn't make any attempt to trap for nonsensical 387 arguments. All of the values in the values list should be of the same type 388 (i.e. strings). Then, all list operations also need to be of that type 389 (i.e. you should always insert or append just strings). If you mix types -- 390 for instance lists and strings -- you will likely see AttributeError 391 exceptions or other problems. 392 """ 393
394 - def __init__(self, valuesList, valuesDescr, prefix=None):
395 """ 396 Initializes a list restricted to containing certain values. 397 @param valuesList: List of valid values. 398 @param valuesDescr: Short string describing list of values. 399 @param prefix: Prefix to use in error messages (None results in prefix "Item") 400 """ 401 super(RestrictedContentList, self).__init__() 402 self.prefix = "Item" 403 if prefix is not None: self.prefix = prefix 404 self.valuesList = valuesList 405 self.valuesDescr = valuesDescr
406
407 - def append(self, item):
408 """ 409 Overrides the standard C{append} method. 410 @raise ValueError: If item is not in the values list. 411 """ 412 if item not in self.valuesList: 413 raise ValueError("%s must be one of the values in %s." % (self.prefix, self.valuesDescr)) 414 list.append(self, item)
415
416 - def insert(self, index, item):
417 """ 418 Overrides the standard C{insert} method. 419 @raise ValueError: If item is not in the values list. 420 """ 421 if item not in self.valuesList: 422 raise ValueError("%s must be one of the values in %s." % (self.prefix, self.valuesDescr)) 423 list.insert(self, index, item)
424
425 - def extend(self, seq):
426 """ 427 Overrides the standard C{insert} method. 428 @raise ValueError: If item is not in the values list. 429 """ 430 for item in seq: 431 if item not in self.valuesList: 432 raise ValueError("%s must be one of the values in %s." % (self.prefix, self.valuesDescr)) 433 list.extend(self, seq)
434
435 436 ######################################################################## 437 # RegexMatchList class definition 438 ######################################################################## 439 440 -class RegexMatchList(UnorderedList):
441 442 """ 443 Class representing a list containing only strings that match a regular expression. 444 445 If C{emptyAllowed} is passed in as C{False}, then empty strings are 446 explicitly disallowed, even if they happen to match the regular expression. 447 (C{None} values are always disallowed, since string operations are not 448 permitted on C{None}.) 449 450 This is an unordered list. 451 452 We override the C{append}, C{insert} and C{extend} methods to ensure that 453 any item added to the list matches the indicated regular expression. 454 455 @note: If you try to put values that are not strings into the list, you will 456 likely get either TypeError or AttributeError exceptions as a result. 457 """ 458
459 - def __init__(self, valuesRegex, emptyAllowed=True, prefix=None):
460 """ 461 Initializes a list restricted to containing certain values. 462 @param valuesRegex: Regular expression that must be matched, as a string 463 @param emptyAllowed: Indicates whether empty or None values are allowed. 464 @param prefix: Prefix to use in error messages (None results in prefix "Item") 465 """ 466 super(RegexMatchList, self).__init__() 467 self.prefix = "Item" 468 if prefix is not None: self.prefix = prefix 469 self.valuesRegex = valuesRegex 470 self.emptyAllowed = emptyAllowed 471 self.pattern = re.compile(self.valuesRegex)
472
473 - def append(self, item):
474 """ 475 Overrides the standard C{append} method. 476 @raise ValueError: If item is None 477 @raise ValueError: If item is empty and empty values are not allowed 478 @raise ValueError: If item does not match the configured regular expression 479 """ 480 if item is None or (not self.emptyAllowed and item == ""): 481 raise ValueError("%s cannot be empty." % self.prefix) 482 if not self.pattern.search(item): 483 raise ValueError("%s is not valid: [%s]" % (self.prefix, item)) 484 list.append(self, item)
485
486 - def insert(self, index, item):
487 """ 488 Overrides the standard C{insert} method. 489 @raise ValueError: If item is None 490 @raise ValueError: If item is empty and empty values are not allowed 491 @raise ValueError: If item does not match the configured regular expression 492 """ 493 if item is None or (not self.emptyAllowed and item == ""): 494 raise ValueError("%s cannot be empty." % self.prefix) 495 if not self.pattern.search(item): 496 raise ValueError("%s is not valid [%s]" % (self.prefix, item)) 497 list.insert(self, index, item)
498
499 - def extend(self, seq):
500 """ 501 Overrides the standard C{insert} method. 502 @raise ValueError: If any item is None 503 @raise ValueError: If any item is empty and empty values are not allowed 504 @raise ValueError: If any item does not match the configured regular expression 505 """ 506 for item in seq: 507 if item is None or (not self.emptyAllowed and item == ""): 508 raise ValueError("%s cannot be empty.", self.prefix) 509 if not self.pattern.search(item): 510 raise ValueError("%s is not valid: [%s]" % (self.prefix, item)) 511 list.extend(self, seq)
512
513 514 ######################################################################## 515 # RegexList class definition 516 ######################################################################## 517 518 -class RegexList(UnorderedList):
519 520 """ 521 Class representing a list of valid regular expression strings. 522 523 This is an unordered list. 524 525 We override the C{append}, C{insert} and C{extend} methods to ensure that 526 any item added to the list is a valid regular expression. 527 """ 528
529 - def append(self, item):
530 """ 531 Overrides the standard C{append} method. 532 @raise ValueError: If item is not an absolute path. 533 """ 534 try: 535 re.compile(item) 536 except re.error: 537 raise ValueError("Not a valid regular expression: [%s]" % item) 538 list.append(self, item)
539
540 - def insert(self, index, item):
541 """ 542 Overrides the standard C{insert} method. 543 @raise ValueError: If item is not an absolute path. 544 """ 545 try: 546 re.compile(item) 547 except re.error: 548 raise ValueError("Not a valid regular expression: [%s]" % item) 549 list.insert(self, index, item)
550
551 - def extend(self, seq):
552 """ 553 Overrides the standard C{insert} method. 554 @raise ValueError: If any item is not an absolute path. 555 """ 556 for item in seq: 557 try: 558 re.compile(item) 559 except re.error: 560 raise ValueError("Not a valid regular expression: [%s]" % item) 561 for item in seq: 562 list.append(self, item)
563
564 565 ######################################################################## 566 # Directed graph implementation 567 ######################################################################## 568 569 -class _Vertex(object):
570 571 """ 572 Represents a vertex (or node) in a directed graph. 573 """ 574
575 - def __init__(self, name):
576 """ 577 Constructor. 578 @param name: Name of this graph vertex. 579 @type name: String value. 580 """ 581 self.name = name 582 self.endpoints = [] 583 self.state = None
584
585 -class DirectedGraph(object):
586 587 """ 588 Represents a directed graph. 589 590 A graph B{G=(V,E)} consists of a set of vertices B{V} together with a set 591 B{E} of vertex pairs or edges. In a directed graph, each edge also has an 592 associated direction (from vertext B{v1} to vertex B{v2}). A C{DirectedGraph} 593 object provides a way to construct a directed graph and execute a depth- 594 first search. 595 596 This data structure was designed based on the graphing chapter in 597 U{The Algorithm Design Manual<http://www2.toki.or.id/book/AlgDesignManual/>}, 598 by Steven S. Skiena. 599 600 This class is intended to be used by Cedar Backup for dependency ordering. 601 Because of this, it's not quite general-purpose. Unlike a "general" graph, 602 every vertex in this graph has at least one edge pointing to it, from a 603 special "start" vertex. This is so no vertices get "lost" either because 604 they have no dependencies or because nothing depends on them. 605 """ 606 607 _UNDISCOVERED = 0 608 _DISCOVERED = 1 609 _EXPLORED = 2 610
611 - def __init__(self, name):
612 """ 613 Directed graph constructor. 614 615 @param name: Name of this graph. 616 @type name: String value. 617 """ 618 if name is None or name == "": 619 raise ValueError("Graph name must be non-empty.") 620 self._name = name 621 self._vertices = {} 622 self._startVertex = _Vertex(None) # start vertex is only vertex with no name
623
624 - def __repr__(self):
625 """ 626 Official string representation for class instance. 627 """ 628 return "DirectedGraph(%s)" % self.name
629
630 - def __str__(self):
631 """ 632 Informal string representation for class instance. 633 """ 634 return self.__repr__()
635
636 - def __cmp__(self, other):
637 """ 638 Definition of equals operator for this class. 639 @param other: Other object to compare to. 640 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 641 """ 642 # pylint: disable=W0212 643 if other is None: 644 return 1 645 if self.name != other.name: 646 if self.name < other.name: 647 return -1 648 else: 649 return 1 650 if self._vertices != other._vertices: 651 if self._vertices < other._vertices: 652 return -1 653 else: 654 return 1 655 return 0
656
657 - def _getName(self):
658 """ 659 Property target used to get the graph name. 660 """ 661 return self._name
662 663 name = property(_getName, None, None, "Name of the graph.") 664
665 - def createVertex(self, name):
666 """ 667 Creates a named vertex. 668 @param name: vertex name 669 @raise ValueError: If the vertex name is C{None} or empty. 670 """ 671 if name is None or name == "": 672 raise ValueError("Vertex name must be non-empty.") 673 vertex = _Vertex(name) 674 self._startVertex.endpoints.append(vertex) # so every vertex is connected at least once 675 self._vertices[name] = vertex
676
677 - def createEdge(self, start, finish):
678 """ 679 Adds an edge with an associated direction, from C{start} vertex to C{finish} vertex. 680 @param start: Name of start vertex. 681 @param finish: Name of finish vertex. 682 @raise ValueError: If one of the named vertices is unknown. 683 """ 684 try: 685 startVertex = self._vertices[start] 686 finishVertex = self._vertices[finish] 687 startVertex.endpoints.append(finishVertex) 688 except KeyError, e: 689 raise ValueError("Vertex [%s] could not be found." % e)
690
691 - def topologicalSort(self):
692 """ 693 Implements a topological sort of the graph. 694 695 This method also enforces that the graph is a directed acyclic graph, 696 which is a requirement of a topological sort. 697 698 A directed acyclic graph (or "DAG") is a directed graph with no directed 699 cycles. A topological sort of a DAG is an ordering on the vertices such 700 that all edges go from left to right. Only an acyclic graph can have a 701 topological sort, but any DAG has at least one topological sort. 702 703 Since a topological sort only makes sense for an acyclic graph, this 704 method throws an exception if a cycle is found. 705 706 A depth-first search only makes sense if the graph is acyclic. If the 707 graph contains any cycles, it is not possible to determine a consistent 708 ordering for the vertices. 709 710 @note: If a particular vertex has no edges, then its position in the 711 final list depends on the order in which the vertices were created in the 712 graph. If you're using this method to determine a dependency order, this 713 makes sense: a vertex with no dependencies can go anywhere (and will). 714 715 @return: Ordering on the vertices so that all edges go from left to right. 716 717 @raise ValueError: If a cycle is found in the graph. 718 """ 719 ordering = [] 720 for key in self._vertices: 721 vertex = self._vertices[key] 722 vertex.state = self._UNDISCOVERED 723 for key in self._vertices: 724 vertex = self._vertices[key] 725 if vertex.state == self._UNDISCOVERED: 726 self._topologicalSort(self._startVertex, ordering) 727 return ordering
728
729 - def _topologicalSort(self, vertex, ordering):
730 """ 731 Recursive depth first search function implementing topological sort. 732 @param vertex: Vertex to search 733 @param ordering: List of vertices in proper order 734 """ 735 vertex.state = self._DISCOVERED 736 for endpoint in vertex.endpoints: 737 if endpoint.state == self._UNDISCOVERED: 738 self._topologicalSort(endpoint, ordering) 739 elif endpoint.state != self._EXPLORED: 740 raise ValueError("Cycle found in graph (found '%s' while searching '%s')." % (vertex.name, endpoint.name)) 741 if vertex.name is not None: 742 ordering.insert(0, vertex.name) 743 vertex.state = self._EXPLORED
744
745 746 ######################################################################## 747 # PathResolverSingleton class definition 748 ######################################################################## 749 750 -class PathResolverSingleton(object):
751 752 """ 753 Singleton used for resolving executable paths. 754 755 Various functions throughout Cedar Backup (including extensions) need a way 756 to resolve the path of executables that they use. For instance, the image 757 functionality needs to find the C{mkisofs} executable, and the Subversion 758 extension needs to find the C{svnlook} executable. Cedar Backup's original 759 behavior was to assume that the simple name (C{"svnlook"} or whatever) was 760 available on the caller's C{$PATH}, and to fail otherwise. However, this 761 turns out to be less than ideal, since for instance the root user might not 762 always have executables like C{svnlook} in its path. 763 764 One solution is to specify a path (either via an absolute path or some sort 765 of path insertion or path appending mechanism) that would apply to the 766 C{executeCommand()} function. This is not difficult to implement, but it 767 seem like kind of a "big hammer" solution. Besides that, it might also 768 represent a security flaw (for instance, I prefer not to mess with root's 769 C{$PATH} on the application level if I don't have to). 770 771 The alternative is to set up some sort of configuration for the path to 772 certain executables, i.e. "find C{svnlook} in C{/usr/local/bin/svnlook}" or 773 whatever. This PathResolverSingleton aims to provide a good solution to the 774 mapping problem. Callers of all sorts (extensions or not) can get an 775 instance of the singleton. Then, they call the C{lookup} method to try and 776 resolve the executable they are looking for. Through the C{lookup} method, 777 the caller can also specify a default to use if a mapping is not found. 778 This way, with no real effort on the part of the caller, behavior can neatly 779 degrade to something equivalent to the current behavior if there is no 780 special mapping or if the singleton was never initialized in the first 781 place. 782 783 Even better, extensions automagically get access to the same resolver 784 functionality, and they don't even need to understand how the mapping 785 happens. All extension authors need to do is document what executables 786 their code requires, and the standard resolver configuration section will 787 meet their needs. 788 789 The class should be initialized once through the constructor somewhere in 790 the main routine. Then, the main routine should call the L{fill} method to 791 fill in the resolver's internal structures. Everyone else who needs to 792 resolve a path will get an instance of the class using L{getInstance} and 793 will then just call the L{lookup} method. 794 795 @cvar _instance: Holds a reference to the singleton 796 @ivar _mapping: Internal mapping from resource name to path. 797 """ 798 799 _instance = None # Holds a reference to singleton instance 800
801 - class _Helper:
802 """Helper class to provide a singleton factory method."""
803 - def __init__(self):
804 pass
805 - def __call__(self, *args, **kw):
806 # pylint: disable=W0212,R0201 807 if PathResolverSingleton._instance is None: 808 obj = PathResolverSingleton() 809 PathResolverSingleton._instance = obj 810 return PathResolverSingleton._instance
811 812 getInstance = _Helper() # Method that callers will use to get an instance 813
814 - def __init__(self):
815 """Singleton constructor, which just creates the singleton instance.""" 816 if PathResolverSingleton._instance is not None: 817 raise RuntimeError("Only one instance of PathResolverSingleton is allowed!") 818 PathResolverSingleton._instance = self 819 self._mapping = { }
820
821 - def lookup(self, name, default=None):
822 """ 823 Looks up name and returns the resolved path associated with the name. 824 @param name: Name of the path resource to resolve. 825 @param default: Default to return if resource cannot be resolved. 826 @return: Resolved path associated with name, or default if name can't be resolved. 827 """ 828 value = default 829 if name in self._mapping.keys(): 830 value = self._mapping[name] 831 logger.debug("Resolved command [%s] to [%s]." % (name, value)) 832 return value
833
834 - def fill(self, mapping):
835 """ 836 Fills in the singleton's internal mapping from name to resource. 837 @param mapping: Mapping from resource name to path. 838 @type mapping: Dictionary mapping name to path, both as strings. 839 """ 840 self._mapping = { } 841 for key in mapping.keys(): 842 self._mapping[key] = mapping[key]
843
844 845 ######################################################################## 846 # Pipe class definition 847 ######################################################################## 848 849 -class Pipe(Popen):
850 """ 851 Specialized pipe class for use by C{executeCommand}. 852 853 The L{executeCommand} function needs a specialized way of interacting 854 with a pipe. First, C{executeCommand} only reads from the pipe, and 855 never writes to it. Second, C{executeCommand} needs a way to discard all 856 output written to C{stderr}, as a means of simulating the shell 857 C{2>/dev/null} construct. 858 """
859 - def __init__(self, cmd, bufsize=-1, ignoreStderr=False):
860 stderr = STDOUT 861 if ignoreStderr: 862 devnull = nullDevice() 863 stderr = os.open(devnull, os.O_RDWR) 864 Popen.__init__(self, shell=False, args=cmd, bufsize=bufsize, stdin=None, stdout=PIPE, stderr=stderr)
865
866 867 ######################################################################## 868 # Diagnostics class definition 869 ######################################################################## 870 871 -class Diagnostics(object):
872 873 """ 874 Class holding runtime diagnostic information. 875 876 Diagnostic information is information that is useful to get from users for 877 debugging purposes. I'm consolidating it all here into one object. 878 879 @sort: __init__, __repr__, __str__ 880 """ 881 # pylint: disable=R0201 882
883 - def __init__(self):
884 """ 885 Constructor for the C{Diagnostics} class. 886 """
887
888 - def __repr__(self):
889 """ 890 Official string representation for class instance. 891 """ 892 return "Diagnostics()"
893
894 - def __str__(self):
895 """ 896 Informal string representation for class instance. 897 """ 898 return self.__repr__()
899
900 - def getValues(self):
901 """ 902 Get a map containing all of the diagnostic values. 903 @return: Map from diagnostic name to diagnostic value. 904 """ 905 values = {} 906 values['version'] = self.version 907 values['interpreter'] = self.interpreter 908 values['platform'] = self.platform 909 values['encoding'] = self.encoding 910 values['locale'] = self.locale 911 values['timestamp'] = self.timestamp 912 return values
913
914 - def printDiagnostics(self, fd=sys.stdout, prefix=""):
915 """ 916 Pretty-print diagnostic information to a file descriptor. 917 @param fd: File descriptor used to print information. 918 @param prefix: Prefix string (if any) to place onto printed lines 919 @note: The C{fd} is used rather than C{print} to facilitate unit testing. 920 """ 921 lines = self._buildDiagnosticLines(prefix) 922 for line in lines: 923 fd.write("%s\n" % line)
924
925 - def logDiagnostics(self, method, prefix=""):
926 """ 927 Pretty-print diagnostic information using a logger method. 928 @param method: Logger method to use for logging (i.e. logger.info) 929 @param prefix: Prefix string (if any) to place onto printed lines 930 """ 931 lines = self._buildDiagnosticLines(prefix) 932 for line in lines: 933 method("%s" % line)
934
935 - def _buildDiagnosticLines(self, prefix=""):
936 """ 937 Build a set of pretty-printed diagnostic lines. 938 @param prefix: Prefix string (if any) to place onto printed lines 939 @return: List of strings, not terminated by newlines. 940 """ 941 values = self.getValues() 942 keys = values.keys() 943 keys.sort() 944 tmax = Diagnostics._getMaxLength(keys) + 3 # three extra dots in output 945 lines = [] 946 for key in keys: 947 title = key.title() 948 title += (tmax - len(title)) * '.' 949 value = values[key] 950 line = "%s%s: %s" % (prefix, title, value) 951 lines.append(line) 952 return lines
953 954 @staticmethod
955 - def _getMaxLength(values):
956 """ 957 Get the maximum length from among a list of strings. 958 """ 959 tmax = 0 960 for value in values: 961 if len(value) > tmax: 962 tmax = len(value) 963 return tmax
964
965 - def _getVersion(self):
966 """ 967 Property target to get the Cedar Backup version. 968 """ 969 return "Cedar Backup %s (%s)" % (VERSION, DATE)
970
971 - def _getInterpreter(self):
972 """ 973 Property target to get the Python interpreter version. 974 """ 975 version = sys.version_info 976 return "Python %d.%d.%d (%s)" % (version[0], version[1], version[2], version[3])
977
978 - def _getEncoding(self):
979 """ 980 Property target to get the filesystem encoding. 981 """ 982 return sys.getfilesystemencoding() or sys.getdefaultencoding()
983
984 - def _getPlatform(self):
985 """ 986 Property target to get the operating system platform. 987 """ 988 try: 989 if sys.platform.startswith("win"): 990 windowsPlatforms = [ "Windows 3.1", "Windows 95/98/ME", "Windows NT/2000/XP", "Windows CE", ] 991 wininfo = sys.getwindowsversion() # pylint: disable=E1101 992 winversion = "%d.%d.%d" % (wininfo[0], wininfo[1], wininfo[2]) 993 winplatform = windowsPlatforms[wininfo[3]] 994 wintext = wininfo[4] # i.e. "Service Pack 2" 995 return "%s (%s %s %s)" % (sys.platform, winplatform, winversion, wintext) 996 else: 997 uname = os.uname() 998 sysname = uname[0] # i.e. Linux 999 release = uname[2] # i.e. 2.16.18-2 1000 machine = uname[4] # i.e. i686 1001 return "%s (%s %s %s)" % (sys.platform, sysname, release, machine) 1002 except: 1003 return sys.platform
1004
1005 - def _getLocale(self):
1006 """ 1007 Property target to get the default locale that is in effect. 1008 """ 1009 try: 1010 import locale 1011 return locale.getdefaultlocale()[0] 1012 except: 1013 return "(unknown)"
1014
1015 - def _getTimestamp(self):
1016 """ 1017 Property target to get a current date/time stamp. 1018 """ 1019 try: 1020 import datetime 1021 return datetime.datetime.utcnow().ctime() + " UTC" 1022 except: 1023 return "(unknown)"
1024 1025 version = property(_getVersion, None, None, "Cedar Backup version.") 1026 interpreter = property(_getInterpreter, None, None, "Python interpreter version.") 1027 platform = property(_getPlatform, None, None, "Platform identifying information.") 1028 encoding = property(_getEncoding, None, None, "Filesystem encoding that is in effect.") 1029 locale = property(_getLocale, None, None, "Locale that is in effect.") 1030 timestamp = property(_getTimestamp, None, None, "Current timestamp.")
1031
1032 1033 ######################################################################## 1034 # General utility functions 1035 ######################################################################## 1036 1037 ###################### 1038 # sortDict() function 1039 ###################### 1040 1041 -def sortDict(d):
1042 """ 1043 Returns the keys of the dictionary sorted by value. 1044 1045 There are cuter ways to do this in Python 2.4, but we were originally 1046 attempting to stay compatible with Python 2.3. 1047 1048 @param d: Dictionary to operate on 1049 @return: List of dictionary keys sorted in order by dictionary value. 1050 """ 1051 items = d.items() 1052 items.sort(lambda x, y: cmp(x[1], y[1])) 1053 return [key for key, value in items]
1054
1055 1056 ######################## 1057 # removeKeys() function 1058 ######################## 1059 1060 -def removeKeys(d, keys):
1061 """ 1062 Removes all of the keys from the dictionary. 1063 The dictionary is altered in-place. 1064 Each key must exist in the dictionary. 1065 @param d: Dictionary to operate on 1066 @param keys: List of keys to remove 1067 @raise KeyError: If one of the keys does not exist 1068 """ 1069 for key in keys: 1070 del d[key]
1071
1072 1073 ######################### 1074 # convertSize() function 1075 ######################### 1076 1077 -def convertSize(size, fromUnit, toUnit):
1078 """ 1079 Converts a size in one unit to a size in another unit. 1080 1081 This is just a convenience function so that the functionality can be 1082 implemented in just one place. Internally, we convert values to bytes and 1083 then to the final unit. 1084 1085 The available units are: 1086 1087 - C{UNIT_BYTES} - Bytes 1088 - C{UNIT_KBYTES} - Kilobytes, where 1 kB = 1024 B 1089 - C{UNIT_MBYTES} - Megabytes, where 1 MB = 1024 kB 1090 - C{UNIT_GBYTES} - Gigabytes, where 1 GB = 1024 MB 1091 - C{UNIT_SECTORS} - Sectors, where 1 sector = 2048 B 1092 1093 @param size: Size to convert 1094 @type size: Integer or float value in units of C{fromUnit} 1095 1096 @param fromUnit: Unit to convert from 1097 @type fromUnit: One of the units listed above 1098 1099 @param toUnit: Unit to convert to 1100 @type toUnit: One of the units listed above 1101 1102 @return: Number converted to new unit, as a float. 1103 @raise ValueError: If one of the units is invalid. 1104 """ 1105 if size is None: 1106 raise ValueError("Cannot convert size of None.") 1107 if fromUnit == UNIT_BYTES: 1108 byteSize = float(size) 1109 elif fromUnit == UNIT_KBYTES: 1110 byteSize = float(size) * BYTES_PER_KBYTE 1111 elif fromUnit == UNIT_MBYTES: 1112 byteSize = float(size) * BYTES_PER_MBYTE 1113 elif fromUnit == UNIT_GBYTES: 1114 byteSize = float(size) * BYTES_PER_GBYTE 1115 elif fromUnit == UNIT_SECTORS: 1116 byteSize = float(size) * BYTES_PER_SECTOR 1117 else: 1118 raise ValueError("Unknown 'from' unit %s." % fromUnit) 1119 if toUnit == UNIT_BYTES: 1120 return byteSize 1121 elif toUnit == UNIT_KBYTES: 1122 return byteSize / BYTES_PER_KBYTE 1123 elif toUnit == UNIT_MBYTES: 1124 return byteSize / BYTES_PER_MBYTE 1125 elif toUnit == UNIT_GBYTES: 1126 return byteSize / BYTES_PER_GBYTE 1127 elif toUnit == UNIT_SECTORS: 1128 return byteSize / BYTES_PER_SECTOR 1129 else: 1130 raise ValueError("Unknown 'to' unit %s." % toUnit)
1131
1132 1133 ########################## 1134 # displayBytes() function 1135 ########################## 1136 1137 -def displayBytes(bytes, digits=2): # pylint: disable=W0622
1138 """ 1139 Format a byte quantity so it can be sensibly displayed. 1140 1141 It's rather difficult to look at a number like "72372224 bytes" and get any 1142 meaningful information out of it. It would be more useful to see something 1143 like "69.02 MB". That's what this function does. Any time you wan mea
1072 1073 ######################### 1074 # convertSize() function 1075 ######################### 1076 1077 -def convertSize(size, fromUnit, toUnit):
1078 """ 1079 Converts a size in one unit to a size in another unit. 1080 1081 This is just a convenience function so that the functionality can be 1082 implemented in just one place. Internally, we convert values to bytes and 1083 then to the final unit. 1084 1085 The available units are: 1086 1087 - C{UNIT_BYTES} - Bytes 1088 - C{UNIT_KBYTES} - Kilobytes, where 1 kB = 1024 B 1089 - C{UNIT_MBYTES} - Megabytes, where 1 MB = 1024 kB 1090 - C{UNIT_GBYTES} - Gigabytes, where 1 GB = 1024 MB 1091 - C{UNIT_SECTORS} - Sectors, where 1 sector = 2048 B 1092 1093 @param size: Size to convert 1094 @type size: Integer or float value in units of C{fromUnit} 1095 1096 @param fromUnit: Unit to convert from 1097 @type fromUnit: One of the units listed above 1098 1099 @param toUnit: Unit to convert to 1100 @type toUnit: One of the units listed above 1101 1102 @return: Number converted to new unit, as a float. 1103 @raise ValueError: If one of the units is invalid. 1104 """ 1105 if size is None: 1106 raise ValueError("Cannot convert size of None.") 1107 if fromUnit == UNIT_BYTES: 1108 byteSize = float(size) 1109 elif fromUnit == UNIT_KBYTES: 1110 byteSize = float(size) * BYTES_PER_KBYTE 1111 elif fromUnit == UNIT_MBYTES: 1112 byteSize = float(size) * BYTES_PER_MBYTE 1113 elif fromUnit == UNIT_GBYTES: 1114 byteSize = float(size) * BYTES_PER_GBYTE 1115 elif fromUnit == UNIT_SECTORS: 1116 byteSize = float(size) * BYTES_PER_SECTOR 1117 else: 1118 raise ValueError("Unknown 'from' unit %s." % fromUnit) 1119 if toUnit == UNIT_BYTES: 1120 return byteSize 1121 elif toUnit == UNIT_KBYTES: 1122 return byteSize / BYTES_PER_KBYTE 1123 elif toUnit == UNIT_MBYTES: 1124 return byteSize / BYTES_PER_MBYTE 1125 elif toUnit == UNIT_GBYTES: 1126 return byteSize / BYTES_PER_GBYTE 1127 elif toUnit == UNIT_SECTORS: 1128 return byteSize / BYTES_PER_SECTOR 1129 else: 1130 raise ValueError("Unknown 'to' unit %s." % toUnit)
1131
1132 1133 ########################## 1134 # displayBytes() function 1135 ########################## 1136 1137 -def displayBytes(bytes, digits=2): # pylint: disable=W0622
1138 """ 1139 Format a byte quantity so it can be sensibly displayed. 1140 1141 It's rather difficult to look at a number like "72372224 bytes" and get any 1142 meaningful information out of it. It would be more useful to see something 1143 like "69.02 MB". That's what this function does. Any time you wan mea
1072 1073 ######################### 1074 # convertSize() function 1075 ######################### 1076 1077 -def convertSize(size, fromUnit, toUnit):
1078 """ 1079 Converts a size in one unit to a size in another unit. 1080 1081 This is just a convenience function so that the functionality can be 1082 implemented in just one place. Internally, we convert values to bytes and 1083 then to the final unit. 1084 1085 The available units are: 1086 1087 - C{UNIT_BYTES} - Bytes 1088 - C{UNIT_KBYTES} - Kilobytes, where 1 kB = 1024 B 1089 - C{UNIT_MBYTES} - Megabytes, where 1 MB = 1024 kB 1090 - C{UNIT_GBYTES} - Gigabytes, where 1 GB = 1024 MB 1091 - C{UNIT_SECTORS} - Sectors, where 1 sector = 2048 B 1092 1093 @param size: Size to convert 1094 @type size: Integer or float value in units of C{fromUnit} 1095 1096 @param fromUnit: Unit to convert from 1097 @type fromUnit: One of the units listed above 1098 1099 @param toUnit: Unit to convert to 1100 @type toUnit: One of the units listed above 1101 1102 @return: Number converted to new unit, as a float. 1103 @raise ValueError: If one of the units is invalid. 1104 """ 1105 if size is None: 1106 raise ValueError("Cannot convert size of None.") 1107 if fromUnit == UNIT_BYTES: 1108 byteSize = float(size) 1109 elif fromUnit == UNIT_KBYTES: 1110 byteSize = float(size) * BYTES_PER_KBYTE 1111 elif fromUnit == UNIT_MBYTES: 1112 byteSize = float(size) * BYTES_PER_MBYTE 1113 elif fromUnit == UNIT_GBYTES: 1114 byteSize = float(size) * BYTES_PER_GBYTE 1115 elif fromUnit == UNIT_SECTORS: 1116 byteSize = float(size) * BYTES_PER_SECTOR 1117 else: 1118 raise ValueError("Unknown 'from' unit %s." % fromUnit) 1119 if toUnit == UNIT_BYTES: 1120 return byteSize 1121 elif toUnit == UNIT_KBYTES: 1122 return byteSize / BYTES_PER_KBYTE 1123 elif toUnit == UNIT_MBYTES: 1124 return byteSize / BYTES_PER_MBYTE 1125 elif toUnit == UNIT_GBYTES: 1126 return byteSize / BYTES_PER_GBYTE 1127 elif toUnit == UNIT_SECTORS: 1128 return byteSize / BYTES_PER_SECTOR 1129 else: 1130 raise ValueError("Unknown 'to' unit %s." % toUnit)
1131
1132 1133 ########################## 1134 # displayBytes() function 1135 ########################## 1136 1137 -def displayBytes(bytes, digits=2): # pylint: disable=W0622
1138 """ 1139 Format a byte quantity so it can be sensibly displayed. 1140 1141 It's rather difficult to look at a number like "72372224 bytes" and get any 1142 meaningful information out of it. It would be more useful to see something 1143 like "69.02 MB". That's what this function does. Any time you wan mea
1072 1073 ######################### 1074 # convertSize() function 1075 ######################### 1076 1077 -def convertSize(size, fromUnit, toUnit):
1078 """ 1079 Converts a size in one unit to a size in another unit. 1080 1081 This is just a convenience function so that the functionality can be 1082 implemented in just one place. Internally, we convert values to bytes and 1083 then to the final unit. 1084 1085 The available units are: 1086 1087 - C{UNIT_BYTES} - Bytes 1088 - C{UNIT_KBYTES} - Kilobytes, where 1 kB = 1024 B 1089 - C{UNIT_MBYTES} - Megabytes, where 1 MB = 1024 kB 1090 - C{UNIT_GBYTES} - Gigabytes, where 1 GB = 1024 MB 1091 - C{UNIT_SECTORS} - Sectors, where 1 sector = 2048 B 1092 1093 @param size: Size to convert 1094 @type size: Integer or float value in units of C{fromUnit} 1095 1096 @param fromUnit: Unit to convert from 1097 @type fromUnit: One of the units listed above 1098 1099 @param toUnit: Unit to convert to 1100 @type toUnit: One of the units listed above 1101 1102 @return: Number converted to new unit, as a float. 1103 @raise ValueError: If one of the units is invalid. 1104 """ 1105 if size is None: 1106 raise ValueError("Cannot convert size of None.") 1107 if fromUnit == UNIT_BYTES: 1108 byteSize = float(size) 1109 elif fromUnit == UNIT_KBYTES: 1110 byteSize = float(size) * BYTES_PER_KBYTE 1111 elif fromUnit == UNIT_MBYTES: 1112 byteSize = float(size) * BYTES_PER_MBYTE 1113 elif fromUnit == UNIT_GBYTES: 1114 byteSize = float(size) * BYTES_PER_GBYTE 1115 elif fromUnit == UNIT_SECTORS: 1116 byteSize = float(size) * BYTES_PER_SECTOR 1117 else: 1118 raise ValueError("Unknown 'from' unit %s." % fromUnit) 1119 if toUnit == UNIT_BYTES: 1120 return byteSize 1121 elif toUnit == UNIT_KBYTES: 1122 return byteSize / BYTES_PER_KBYTE 1123 elif toUnit == UNIT_MBYTES: 1124 return byteSize / BYTES_PER_MBYTE 1125 elif toUnit == UNIT_GBYTES: 1126 return byteSize / BYTES_PER_GBYTE 1127 elif toUnit == UNIT_SECTORS: 1128 return byteSize / BYTES_PER_SECTOR 1129 else: 1130 raise ValueError("Unknown 'to' unit %s." % toUnit)
1131
1132 1133 ########################## 1134 # displayBytes() function 1135 ########################## 1136 1137 -def displayBytes(bytes, digits=2): # pylint: disable=W0622
1138 """ 1139 Format a byte quantity so it can be sensibly displayed. 1140 1141 It's rather difficult to look at a number like "72372224 bytes" and get any 1142 meaningful information out of it. It would be more useful to see something 1143 like "69.02 MB". That's what this function does. Any time you wan mea
1072 1073 ######################### 1074 # convertSize() function 1075 ######################### 1076 1077 -def convertSize(size, fromUnit, toUnit):
1078 """ 1079 Converts a size in one unit to a size in another unit. 1080 1081 This is just a convenience function so that the functionality can be 1082 implemented in just one place. Internally, we convert values to bytes and 1083 then to the final unit. 1084 1085 The available units are: 1086 1087 - C{UNIT_BYTES} - Bytes 1088 - C{UNIT_KBYTES} - Kilobytes, where 1 kB = 1024 B 1089 - C{UNIT_MBYTES} - Megabytes, where 1 MB = 1024 kB 1090 - C{UNIT_GBYTES} - Gigabytes, where 1 GB = 1024 MB 1091 - C{UNIT_SECTORS} - Sectors, where 1 sector = 2048 B 1092 1093 @param size: Size to convert 1094 @type size: Integer or float value in units of C{fromUnit} 1095 1096 @param fromUnit: Unit to convert from 1097 @type fromUnit: One of the units listed above 1098 1099 @param toUnit: Unit to convert to 1100 @type toUnit: One of the units listed above 1101 1102 @return: Number converted to new unit, as a float. 1103 @raise ValueError: If one of the units is invalid. 1104 """ 1105 if size is None: 1106 raise ValueError("Cannot convert size of None.") 1107 if fromUnit == UNIT_BYTES: 1108 byteSize = float(size) 1109 elif fromUnit == UNIT_KBYTES: 1110 byteSize = float(size) * BYTES_PER_KBYTE 1111 elif fromUnit == UNIT_MBYTES: 1112 byteSize = float(size) * BYTES_PER_MBYTE 1113 elif fromUnit == UNIT_GBYTES: 1114 byteSize = float(size) * BYTES_PER_GBYTE 1115 elif fromUnit == UNIT_SECTORS: 1116 byteSize = float(size) * BYTES_PER_SECTOR 1117 else: 1118 raise ValueError("Unknown 'from' unit %s." % fromUnit) 1119 if toUnit == UNIT_BYTES: 1120 return byteSize 1121 elif toUnit == UNIT_KBYTES: 1122 return byteSize / BYTES_PER_KBYTE 1123 elif toUnit == UNIT_MBYTES: 1124 return byteSize / BYTES_PER_MBYTE 1125 elif toUnit == UNIT_GBYTES: 1126 return byteSize / BYTES_PER_GBYTE 1127 elif toUnit == UNIT_SECTORS: 1128 return byteSize / BYTES_PER_SECTOR 1129 else: 1130 raise ValueError("Unknown 'to' unit %s." % toUnit)
1131
1132 1133 ########################## 1134 # displayBytes() function 1135 ########################## 1136 1137 -def displayBytes(bytes, digits=2): # pylint: disable=W0622
1138 """ 1139 Format a byte quantity so it can be sensibly displayed. 1140 1141 It's rather difficult to look at a number like "72372224 bytes" and get any 1142 meaningful information out of it. It would be more useful to see something 1143 like "69.02 MB". That's what this function does. Any time you wan mea
1072 1073 ######################### 1074 # convertSize() function 1075 ######################### 1076 1077 -def convertSize(size, fromUnit, toUnit):
1078 """ 1079 Converts a size in one unit to a size in another unit. 1080 1081 This is just a convenience function so that the functionality can be 1082 implemented in just one place. Internally, we convert values to bytes and 1083 then to the final unit. 1084 1085 The available units are: 1086 1087 - C{UNIT_BYTES} - Bytes 1088 - C{UNIT_KBYTES} - Kilobytes, where 1 kB = 1024 B 1089 - C{UNIT_MBYTES} - Megabytes, where 1 MB = 1024 kB 1090 - C{UNIT_GBYTES} - Gigabytes, where 1 GB = 1024 MB 1091 - C{UNIT_SECTORS} - Sectors, where 1 sector = 2048 B 1092 1093 @param size: Size to convert 1094 @type size: Integer or float value in units of C{fromUnit} 1095 1096 @param fromUnit: Unit to convert from 1097 @type fromUnit: One of the units listed above 1098 1099 @param toUnit: Unit to convert to 1100 @type toUnit: One of the units listed above 1101 1102 @return: Number converted to new unit, as a float. 1103 @raise ValueError: If one of the units is invalid. 1104 """ 1105 if size is None: 1106 raise ValueError("Cannot convert size of None.") 1107 if fromUnit == UNIT_BYTES: 1108 byteSize = float(size) 1109 elif fromUnit == UNIT_KBYTES: 1110 byteSize = float(size) * BYTES_PER_KBYTE 1111 elif fromUnit == UNIT_MBYTES: 1112 byteSize = float(size) * BYTES_PER_MBYTE 1113 elif fromUnit == UNIT_GBYTES: 1114 byteSize = float(size) * BYTES_PER_GBYTE 1115 elif fromUnit == UNIT_SECTORS: 1116 byteSize = float(size) * BYTES_PER_SECTOR 1117 else: 1118 raise ValueError("Unknown 'from' unit %s." % fromUnit) 1119 if toUnit == UNIT_BYTES: 1120 return byteSize 1121 elif toUnit == UNIT_KBYTES: 1122 return byteSize / BYTES_PER_KBYTE 1123 elif toUnit == UNIT_MBYTES: 1124 return byteSize / BYTES_PER_MBYTE 1125 elif toUnit == UNIT_GBYTES: 1126 return byteSize / BYTES_PER_GBYTE 1127 elif toUnit == UNIT_SECTORS: 1128 return byteSize / BYTES_PER_SECTOR 1129 else: 1130 raise ValueError("Unknown 'to' unit %s." % toUnit)
1131
1132 1133 ########################## 1134 # displayBytes() function 1135 ########################## 1136 1137 -def displayBytes(bytes, digits=2): # pylint: disable=W0622
1138 """ 1139 Format a byte quantity so it can be sensibly displayed. 1140 1141 It's rather difficult to look at a number like "72372224 bytes" and get any 1142 meaningful information out of it. It would be more useful to see something 1143 like "69.02 MB". That's what this function does. Any time you wan mea
1072 1073 ######################### 1074 # convertSize() function 1075 ######################### 1076 1077 -def convertSize(size, fromUnit, toUnit):
1078 """ 1079 Converts a size in one unit to a size in another unit. 1080 1081 This is just a convenience function so that the functionality can be 1082 implemented in just one place. Internally, we convert values to bytes and 1083 then to the final unit. 1084 1085 The available units are: 1086 1087 - C{UNIT_BYTES} - Bytes 1088 - C{UNIT_KBYTES} - Kilobytes, where 1 kB = 1024 B 1089 - C{UNIT_MBYTES} - Megabytes, where 1 MB = 1024 kB 1090 - C{UNIT_GBYTES} - Gigabytes, where 1 GB = 1024 MB 1091 - C{UNIT_SECTORS} - Sectors, where 1 sector = 2048 B 1092 1093 @param size: Size to convert 1094 @type size: Integer or float value in units of C{fromUnit} 1095 1096 @param fromUnit: Unit to convert from 1097 @type fromUnit: One of the units listed above 1098 1099 @param toUnit: Unit to convert to 1100 @type toUnit: One of the units listed above 1101 1102 @return: Number converted to new unit, as a float. 1103 @raise ValueError: If one of the units is invalid. 1104 """ 1105 if size is None: 1106 raise ValueError("Cannot convert size of None.") 1107 if fromUnit == UNIT_BYTES: 1108 byteSize = float(size) 1109 elif fromUnit == UNIT_KBYTES: 1110 byteSize = float(size) * BYTES_PER_KBYTE 1111 elif fromUnit == UNIT_MBYTES: 1112 byteSize = float(size) * BYTES_PER_MBYTE 1113 elif fromUnit == UNIT_GBYTES: 1114 byteSize = float(size) * BYTES_PER_GBYTE 1115 elif fromUnit == UNIT_SECTORS: 1116 byteSize = float(size) * BYTES_PER_SECTOR 1117 else: 1118 raise ValueError("Unknown 'from' unit %s." % fromUnit) 1119 if toUnit == UNIT_BYTES: 1120 return byteSize 1121 elif toUnit == UNIT_KBYTES: 1122 return byteSize / BYTES_PER_KBYTE 1123 elif toUnit == UNIT_MBYTES: 1124 return byteSize / BYTES_PER_MBYTE 1125 elif toUnit == UNIT_GBYTES: 1126 return byteSize / BYTES_PER_GBYTE 1127 elif toUnit == UNIT_SECTORS: 1128 return byteSize / BYTES_PER_SECTOR 1129 else: 1130 raise ValueError("Unknown 'to' unit %s." % toUnit)
1131
1132 1133 ########################## 1134 # displayBytes() function 1135 ########################## 1136 1137 -def displayBytes(bytes, digits=2): # pylint: disable=W0622
1138 """ 1139 Format a byte quantity so it can be sensibly displayed. 1140 1141 It's rather difficult to look at a number like "72372224 bytes" and get any 1142 meaningful information out of it. It would be more useful to see something 1143 like "69.02 MB". That's what this function does. Any time you wan mea
1072 1073 ######################### 1074 # convertSize() function 1075 ######################### 1076 1077 -def convertSize(size, fromUnit, toUnit):
1078 """ 1079 Converts a size in one unit to a size in another unit. 1080 1081 This is just a convenience function so that the functionality can be 1082 implemented in just one place. Internally, we convert values to bytes and 1083 then to the final unit. 1084 1085 The available units are: 1086 1087 - C{UNIT_BYTES} - Bytes 1088 - C{UNIT_KBYTES} - Kilobytes, where 1 kB = 1024 B 1089 - C{UNIT_MBYTES} - Megabytes, where 1 MB = 1024 kB 1090 - C{UNIT_GBYTES} - Gigabytes, where 1 GB = 1024 MB 1091 - C{UNIT_SECTORS} - Sectors, where 1 sector = 2048 B 1092 1093 @param size: Size to convert 1094 @type size: Integer or float value in units of C{fromUnit} 1095 1096 @param fromUnit: Unit to convert from 1097 @type fromUnit: One of the units listed above 1098 1099 @param toUnit: Unit to convert to 1100 @type toUnit: One of the units listed above 1101 1102 @return: Number converted to new unit, as a float. 1103 @raise ValueError: If one of the units is invalid. 1104 """ 1105 if size is None: 1106 raise ValueError("Cannot convert size of None.") 1107 if fromUnit == UNIT_BYTES: 1108 byteSize = float(size) 1109 elif fromUnit == UNIT_KBYTES: 1110 byteSize = float(size) * BYTES_PER_KBYTE 1111 elif fromUnit == UNIT_MBYTES: 1112 byteSize = float(size) * BYTES_PER_MBYTE 1113 elif fromUnit == UNIT_GBYTES: 1114 byteSize = float(size) * BYTES_PER_GBYTE 1115 elif fromUnit == UNIT_SECTORS: 1116 byteSize = float(size) * BYTES_PER_SECTOR 1117 else: 1118 raise ValueError("Unknown 'from' unit %s." % fromUnit) 1119 if toUnit == UNIT_BYTES: 1120 return byteSize 1121 elif toUnit == UNIT_KBYTES: 1122 return byteSize / BYTES_PER_KBYTE 1123 elif toUnit == UNIT_MBYTES: 1124 return byteSize / BYTES_PER_MBYTE 1125 elif toUnit == UNIT_GBYTES: 1126 return byteSize / BYTES_PER_GBYTE 1127 elif toUnit == UNIT_SECTORS: 1128 return byteSize / BYTES_PER_SECTOR 1129 else: 1130 raise ValueError("Unknown 'to' unit %s." % toUnit)
1131
1132 1133 ########################## 1134 # displayBytes() function 1135 ########################## 1136 1137 -def displayBytes(bytes, digits=2): # pylint: disable=W0622
1138 """ 1139 Format a byte quantity so it can be sensibly displayed. 1140 1141 It's rather difficult to look at a number like "72372224 bytes" and get any 1142 meaningful information out of it. It would be more useful to see something 1143 like "69.02 MB". That's what this function does. Any time you wan mea
1072 1073 ######################### 1074 # convertSize() function 1075 ######################### 1076 1077 -def convertSize(size, fromUnit, toUnit):
1078 """ 1079 Converts a size in one unit to a size in another unit. 1080 1081 This is just a convenience function so that the functionality can be 1082 implemented in just one place. Internally, we convert values to bytes and 1083 then to the final unit. 1084 1085 The available units are: 1086 1087 - C{UNIT_BYTES} - Bytes 1088 - C{UNIT_KBYTES} - Kilobytes, where 1 kB = 1024 B 1089 - C{UNIT_MBYTES} - Megabytes, where 1 MB = 1024 kB 1090 - C{UNIT_GBYTES} - Gigabytes, where 1 GB = 1024 MB 1091 - C{UNIT_SECTORS} - Sectors, where 1 sector = 2048 B 1092 1093 @param size: Size to convert 1094 @type size: Integer or float value in units of C{fromUnit} 1095 1096 @param fromUnit: Unit to convert from 1097 @type fromUnit: One of the units listed above 1098 1099 @param toUnit: Unit to convert to 1100 @type toUnit: One of the units listed above 1101 1102 @return: Number converted to new unit, as a float. 1103 @raise ValueError: If one of the units is invalid. 1104 """ 1105 if size is None: 1106 raise ValueError("Cannot convert size of None.") 1107 if fromUnit == UNIT_BYTES: 1108 byteSize = float(size) 1109 elif fromUnit == UNIT_KBYTES: 1110 byteSize = float(size) * BYTES_PER_KBYTE 1111 elif fromUnit == UNIT_MBYTES: 1112 byteSize = float(size) * BYTES_PER_MBYTE 1113 elif fromUnit == UNIT_GBYTES: 1114 byteSize = float(size) * BYTES_PER_GBYTE 1115 elif fromUnit == UNIT_SECTORS: 1116 byteSize = float(size) * BYTES_PER_SECTOR 1117 else: 1118 raise ValueError("Unknown 'from' unit %s." % fromUnit) 1119 if toUnit == UNIT_BYTES: 1120 return byteSize 1121 elif toUnit == UNIT_KBYTES: 1122 return byteSize / BYTES_PER_KBYTE 1123 elif toUnit == UNIT_MBYTES: 1124 return byteSize / BYTES_PER_MBYTE 1125 elif toUnit == UNIT_GBYTES: 1126 return byteSize / BYTES_PER_GBYTE 1127 elif toUnit == UNIT_SECTORS: 1128 return byteSize / BYTES_PER_SECTOR 1129 else: 1130 raise ValueError("Unknown 'to' unit %s." % toUnit)
1131
1132 1133 ########################## 1134 # displayBytes() function 1135 ########################## 1136 1137 -def displayBytes(bytes, digits=2): # pylint: disable=W0622
1138 """ 1139 Format a byte quantity so it can be sensibly displayed. 1140 1141 It's rather difficult to look at a number like "72372224 bytes" and get any 1142 meaningful information out of it. It would be more useful to see something 1143 like "69.02 MB". That's what this function does. Any time you wan mea
1072 1073 ######################### 1074 # convertSize() function 1075 ######################### 1076 1077 -def convertSize(size, fromUnit, toUnit):
1078 """ 1079 Converts a size in one unit to a size in another unit. 1080 1081 This is just a convenience function so that the functionality can be 1082 implemented in just one place. Internally, we convert values to bytes and 1083 then to the final unit. 1084 1085 The available units are: 1086 1087 - C{UNIT_BYTES} - Bytes 1088 - C{UNIT_KBYTES} - Kilobytes, where 1 kB = 1024 B 1089 - C{UNIT_MBYTES} - Megabytes, where 1 MB = 1024 kB 1090 - C{UNIT_GBYTES} - Gigabytes, where 1 GB = 1024 MB 1091 - C{UNIT_SECTORS} - Sectors, where 1 sector = 2048 B 1092 1093 @param size: Size to convert 1094 @type size: Integer or float value in units of C{fromUnit} 1095 1096 @param fromUnit: Unit to convert from 1097 @type fromUnit: One of the units listed above 1098 1099 @param toUnit: Unit to convert to 1100 @type toUnit: One of the units listed above 1101 1102 @return: Number converted to new unit, as a float. 1103 @raise ValueError: If one of the units is invalid. 1104 """ 1105 if size is None: 1106 raise ValueError("Cannot convert size of None.") 1107 if fromUnit == UNIT_BYTES: 1108 byteSize = float(size) 1109 elif fromUnit == UNIT_KBYTES: 1110 byteSize = float(size) * BYTES_PER_KBYTE 1111 elif fromUnit == UNIT_MBYTES: 1112 byteSize = float(size) * BYTES_PER_MBYTE 1113 elif fromUnit == UNIT_GBYTES: 1114 byteSize = float(size) * BYTES_PER_GBYTE 1115 elif fromUnit == UNIT_SECTORS: 1116 byteSize = float(size) * BYTES_PER_SECTOR 1117 else: 1118 raise ValueError("Unknown 'from' unit %s." % fromUnit) 1119 if toUnit == UNIT_BYTES: 1120 return byteSize 1121 elif toUnit == UNIT_KBYTES: 1122 return byteSize / BYTES_PER_KBYTE 1123 elif toUnit == UNIT_MBYTES: 1124 return byteSize / BYTES_PER_MBYTE 1125 elif toUnit == UNIT_GBYTES: 1126 return byteSize / BYTES_PER_GBYTE 1127 elif toUnit == UNIT_SECTORS: 1128 return byteSize / BYTES_PER_SECTOR 1129 else: 1130 raise ValueError("Unknown 'to' unit %s." % toUnit)
1131
1132 1133 ########################## 1134 # displayBytes() function 1135 ########################## 1136 1137 -def displayBytes(bytes, digits=2): # pylint: disable=W0622
1138 """ 1139 Format a byte quantity so it can be sensibly displayed. 1140 1141 It's rather difficult to look at a number like "72372224 bytes" and get any 1142 meaningful information out of it. It would be more useful to see something 1143 like "69.02 MB". That's what this function does. Any time you wan mea
1072 1073 ######################### 1074 # convertSize() function 1075 ######################### 1076 1077 -def convertSize(size, fromUnit, toUnit):
1078 """ 1079 Converts a size in one unit to a size in another unit. 1080 1081 This is just a convenience function so that the functionality can be 1082 implemented in just one place. Internally, we convert values to bytes and 1083 then to the final unit. 1084 1085 The available units are: 1086 1087 - C{UNIT_BYTES} - Bytes 1088 - C{UNIT_KBYTES} - Kilobytes, where 1 kB = 1024 B 1089 - C{UNIT_MBYTES} - Megabytes, where 1 MB = 1024 kB 1090 - C{UNIT_GBYTES} - Gigabytes, where 1 GB = 1024 MB 1091 - C{UNIT_SECTORS} - Sectors, where 1 sector = 2048 B 1092 1093 @param size: Size to convert 1094 @type size: Integer or float value in units of C{fromUnit} 1095 1096 @param fromUnit: Unit to convert from 1097 @type fromUnit: One of the units listed above 1098 1099 @param toUnit: Unit to convert to 1100 @type toUnit: One of the units listed above 1101 1102 @return: Number converted to new unit, as a float. 1103 @raise ValueError: If one of the units is invalid. 1104 """ 1105 if size is None: 1106 raise ValueError("Cannot convert size of None.") 1107 if fromUnit == UNIT_BYTES: 1108 byteSize = float(size) 1109 elif fromUnit == UNIT_KBYTES: 1110 byteSize = float(size) * BYTES_PER_KBYTE 1111 elif fromUnit == UNIT_MBYTES: 1112 byteSize = float(size) * BYTES_PER_MBYTE 1113 elif fromUnit == UNIT_GBYTES: 1114 byteSize = float(size) * BYTES_PER_GBYTE 1115 elif fromUnit == UNIT_SECTORS: 1116 byteSize = float(size) * BYTES_PER_SECTOR 1117 else: 1118 raise ValueError("Unknown 'from' unit %s." % fromUnit) 1119 if toUnit == UNIT_BYTES: 1120 return byteSize 1121 elif toUnit == UNIT_KBYTES: 1122 return byteSize / BYTES_PER_KBYTE 1123 elif toUnit == UNIT_MBYTES: 1124 return byteSize / BYTES_PER_MBYTE 1125 elif toUnit == UNIT_GBYTES: 1126 return byteSize / BYTES_PER_GBYTE 1127 elif toUnit == UNIT_SECTORS: 1128 return byteSize / BYTES_PER_SECTOR 1129 else: 1130 raise ValueError("Unknown 'to' unit %s." % toUnit)
1131
1132 1133 ########################## 1134 # displayBytes() function 1135 ########################## 1136 1137 -def displayBytes(bytes, digits=2): # pylint: disable=W0622
1138 """ 1139 Format a byte quantity so it can be sensibly displayed. 1140 1141 It's rather difficult to look at a number like "72372224 bytes" and get any 1142 meaningful information out of it. It would be more useful to see something 1143 like "69.02 MB". That's what this function does. Any time you wan mea
1072 1073 ######################### 1074 # convertSize() function 1075 ######################### 1076 1077 -def convertSize(size, fromUnit, toUnit):
1078 """ 1079 Converts a size in one unit to a size in another unit. 1080 1081 This is just a convenience function so that the functionality can be 1082 implemented in just one place. Internally, we convert values to bytes and 1083 then to the final unit. 1084 1085 The available units are: 1086 1087 - C{UNIT_BYTES} - Bytes 1088 - C{UNIT_KBYTES} - Kilobytes, where 1 kB = 1024 B 1089 - C{UNIT_MBYTES} - Megabytes, where 1 MB = 1024 kB 1090 - C{UNIT_GBYTES} - Gigabytes, where 1 GB = 1024 MB 1091 - C{UNIT_SECTORS} - Sectors, where 1 sector = 2048 B 1092 1093 @param size: Size to convert 1094 @type size: Integer or float value in units of C{fromUnit} 1095 1096 @param fromUnit: Unit to convert from 1097 @type fromUnit: One of the units listed above 1098 1099 @param toUnit: Unit to convert to 1100 @type toUnit: One of the units listed above 1101 1102 @return: Number converted to new unit, as a float. 1103 @raise ValueError: If one of the units is invalid. 1104 """ 1105 if size is None: 1106 raise ValueError("Cannot convert size of None.") 1107 if fromUnit == UNIT_BYTES: 1108 byteSize = float(size) 1109 elif fromUnit == UNIT_KBYTES: 1110 byteSize = float(size) * BYTES_PER_KBYTE 1111 elif fromUnit == UNIT_MBYTES: 1112 byteSize = float(size) * BYTES_PER_MBYTE 1113 elif fromUnit == UNIT_GBYTES: 1114 byteSize = float(size) * BYTES_PER_GBYTE 1115 elif fromUnit == UNIT_SECTORS: 1116 byteSize = float(size) * BYTES_PER_SECTOR 1117 else: 1118 raise ValueError("Unknown 'from' unit %s." % fromUnit) 1119 if toUnit == UNIT_BYTES: 1120 return byteSize 1121 elif toUnit == UNIT_KBYTES: 1122 return byteSize / BYTES_PER_KBYTE 1123 elif toUnit == UNIT_MBYTES: 1124 return byteSize / BYTES_PER_MBYTE 1125 elif toUnit == UNIT_GBYTES: 1126 return byteSize / BYTES_PER_GBYTE 1127 elif toUnit == UNIT_SECTORS: 1128 return byteSize / BYTES_PER_SECTOR 1129 else: 1130 raise ValueError("Unknown 'to' unit %s." % toUnit)
1131
1132 1133 ########################## 1134 # displayBytes() function 1135 ########################## 1136 1137 -def displayBytes(bytes, digits=2): # pylint: disable=W0622
1138 """ 1139 Format a byte quantity so it can be sensibly displayed. 1140 1141 It's rather difficult to look at a number like "72372224 bytes" and get any 1142 meaningful information out of it. It would be more useful to see something 1143 like "69.02 MB". That's what this function does. Any time you wan mea
1072 1073 ######################### 1074 # convertSize() function 1075 ######################### 1076 1077 -def convertSize(size, fromUnit, toUnit):
1078 """ 1079 Converts a size in one unit to a size in another unit. 1080 1081 This is just a convenience function so that the functionality can be 1082 implemented in just one place. Internally, we convert values to bytes and 1083 then to the final unit. 1084 1085 The available units are: 1086 1087 - C{UNIT_BYTES} - Bytes 1088 - C{UNIT_KBYTES} - Kilobytes, where 1 kB = 1024 B 1089 - C{UNIT_MBYTES} - Megabytes, where 1 MB = 1024 kB 1090 - C{UNIT_GBYTES} - Gigabytes, where 1 GB = 1024 MB 1091 - C{UNIT_SECTORS} - Sectors, where 1 sector = 2048 B 1092 1093 @param size: Size to convert 1094 @type size: Integer or float value in units of C{fromUnit} 1095 1096 @param fromUnit: Unit to convert from 1097 @type fromUnit: One of the units listed above 1098 1099 @param toUnit: Unit to convert to 1100 @type toUnit: One of the units listed above 1101 1102 @return: Number converted to new unit, as a float. 1103 @raise ValueError: If one of the units is invalid. 1104 """ 1105 if size is None: 1106 raise ValueError("Cannot convert size of None.") 1107 if fromUnit == UNIT_BYTES: 1108 byteSize = float(size) 1109 elif fromUnit == UNIT_KBYTES: 1110 byteSize = float(size) * BYTES_PER_KBYTE 1111 elif fromUnit == UNIT_MBYTES: 1112 byteSize = float(size) * BYTES_PER_MBYTE 1113 elif fromUnit == UNIT_GBYTES: 1114 byteSize = float(size) * BYTES_PER_GBYTE 1115 elif fromUnit == UNIT_SECTORS: 1116 byteSize = float(size) * BYTES_PER_SECTOR 1117 else: 1118 raise ValueError("Unknown 'from' unit %s." % fromUnit) 1119 if toUnit == UNIT_BYTES: 1120 return byteSize 1121 elif toUnit == UNIT_KBYTES: 1122 return byteSize / BYTES_PER_KBYTE 1123 elif toUnit == UNIT_MBYTES: 1124 return byteSize / BYTES_PER_MBYTE 1125 elif toUnit == UNIT_GBYTES: 1126 return byteSize / BYTES_PER_GBYTE 1127 elif toUnit == UNIT_SECTORS: 1128 return byteSize / BYTES_PER_SECTOR 1129 else: 1130 raise ValueError("Unknown 'to' unit %s." % toUnit)
1131
1132 1133 ########################## 1134 # displayBytes() function 1135 ########################## 1136 1137 -def displayBytes(bytes, digits=2): # pylint: disable=W0622
1138 """ 1139 Format a byte quantity so it can be sensibly displayed. 1140 1141 It's rather difficult to look at a number like "72372224 bytes" and get any 1142 meaningful information out of it. It would be more useful to see something 1143 like "69.02 MB". That's what this function does. Any time you wan mea
1072 1073 ######################### 1074 # convertSize() function 1075 ######################### 1076 1077 -def convertSize(size, fromUnit, toUnit):
1078 """ 1079 Converts a size in one unit to a size in another unit. 1080 1081 This is just a convenience function so that the functionality can be 1082 implemented in just one place. Internally, we convert values to bytes and 1083 then to the final unit. 1084 1085 The available units are: 1086 1087 - C{UNIT_BYTES} - Bytes 1088 - C{UNIT_KBYTES} - Kilobytes, where 1 kB = 1024 B 1089 - C{UNIT_MBYTES} - Megabytes, where 1 MB = 1024 kB 1090 - C{UNIT_GBYTES} - Gigabytes, where 1 GB = 1024 MB 1091 - C{UNIT_SECTORS} - Sectors, where 1 sector = 2048 B 1092 1093 @param size: Size to convert 1094 @type size: Integer or float value in units of C{fromUnit} 1095 1096 @param fromUnit: Unit to convert from 1097 @type fromUnit: One of the units listed above 1098 1099 @param toUnit: Unit to convert to 1100 @type toUnit: One of the units listed above 1101 1102 @return: Number converted to new unit, as a float. 1103 @raise ValueError: If one of the units is invalid. 1104 """ 1105 if size is None: 1106 raise ValueError("Cannot convert size of None.") 1107 if fromUnit == UNIT_BYTES: 1108 byteSize = float(size) 1109 elif fromUnit == UNIT_KBYTES: 1110 byteSize = float(size) * BYTES_PER_KBYTE 1111 elif fromUnit == UNIT_MBYTES: 1112 byteSize = float(size) * BYTES_PER_MBYTE 1113 elif fromUnit == UNIT_GBYTES