#
# Copyright (c) 2018 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
#
"""
SizeString - LVM-style size strings
$Id: //eng/vdo-releases/magnesium/src/python/vdo/vdomgmnt/SizeString.py#1 $
"""
import locale
from . import Constants
class SizeString(object):
"""Represents the size of an object such as a disk partition.
Conversions are provided to and from suffixed size strings as used
by LVM commands like lvcreate(8). These strings consist of a
(possibly floating-point) number followed by an optional unit
suffix: B (bytes), S (512-byte sectors), and KMGTPE for kilobytes
through exabytes, respectively. Suffixes are not case-sensitive; the
default unit is Megabytes. Currently, we reject negative sizes.
Unlike some (but not all) LVM commands we do not interpret the upper-case
version of a suffix as a power of ten.
Attributes:
_originalString (str): the original string we were constructed
with, mainly used for debugging
_bytes (int): the value of this object in bytes
"""
######################################################################
# Public methods
######################################################################
def __add__(self, rhs):
retval = SizeString("")
retval._bytes = self._bytes + int(rhs)
return retval
######################################################################
def __bool__(self):
return self._bytes != 0
######################################################################
def __cmp__(self, rhs):
result = 0
if not isinstance(rhs, SizeString):
result = NotImplemented
else:
result = cmp(self._bytes, rhs.toBytes())
return result
######################################################################
def __iadd__(self, rhs):
self._bytes += int(rhs)
return self
######################################################################
def __int__(self):
return self._bytes
######################################################################
def __nonzero__(self):
return self.__bool__()
######################################################################
def asLvmText(self):
"""Returns this object as a size string without a decimal point."""
suffix = Constants.lvmDefaultSuffix
size = self._bytes
if size > 0:
for click in Constants.lvmSiSuffixes[::-1]:
divisor = Constants.lvmSiSuffixSizeMap[click]
if size % divisor == 0:
size = size // divisor
suffix = click
break
else:
suffix = Constants.lvmByteSuffix
return str(size) + suffix.upper()
######################################################################
def roundToBlock(self):
"""Rounds this object down to a multiple of the block size."""
self._bytes = self.toBlocks() * Constants.VDO_BLOCK_SIZE
return self
######################################################################
def toBlocks(self):
"""Returns this object as a count of 4K blocks, rounding down."""
return (self._bytes // Constants.VDO_BLOCK_SIZE)
######################################################################
def toBytes(self):
"""Returns the count of bytes represented by this object."""
return self._bytes
######################################################################
def toSectors(self):
"""Returns this object as a count of 512-byte sectors, rounding up."""
bytesPerSector = Constants.lvmSuffixSizeMap[Constants.lvmSectorSuffix]
return (self._bytes + (bytesPerSector - 1)) / bytesPerSector
######################################################################
# Overridden methods
######################################################################
def __init__(self, sz):
self._originalString = sz
if sz:
try:
suffix = sz[-1:].lower()
if suffix in Constants.lvmSuffixes:
nbytes = self._atof(sz[:-1])
else:
nbytes = self._atof(sz)
suffix = Constants.lvmDefaultSuffix
except ValueError:
raise ValueError(_("invalid size string \"{size}\"").format(size=sz))
nbytes *= float(Constants.lvmSuffixSizeMap[suffix])
self._bytes = int(nbytes)
if self._bytes < 0:
raise ValueError(_("invalid size string \"{size}\"").format(size=sz))
else:
self._bytes = 0
######################################################################
def __repr__(self):
return "{0} ({1}{2})".format(self._originalString,
self._bytes,
Constants.lvmByteSuffix.upper())
######################################################################
def __str__(self):
return self.asLvmText()
######################################################################
# Protected methods
######################################################################
@staticmethod
def _atof(s):
"""Tries to convert a float using the current LC_NUMERIC settings.
If something goes wrong, tries float().
"""
try:
return locale.atof(s)
except Exception:
return float(s)