In disklabel.py use the abc module for base cls
authorNikos Skalkotos <skalkoto@grnet.gr>
Tue, 4 Mar 2014 11:23:06 +0000 (13:23 +0200)
committerNikos Skalkotos <skalkoto@grnet.gr>
Tue, 4 Mar 2014 11:23:06 +0000 (13:23 +0200)
Make PartitionTableBase and DisklabelBase abstract classes using the
abs module

snf-image-helper/disklabel.py

index fda1964..473b2d5 100755 (executable)
@@ -26,6 +26,7 @@ import sys
 import os
 import cStringIO
 import optparse
+import abc
 
 from collections import namedtuple
 from collections import OrderedDict
@@ -45,7 +46,7 @@ class MBR(object):
     """Represents a Master Boot Record."""
     class Partition(object):
         """Represents a partition entry in MBR"""
-        format = "<B3sB3sLL"
+        fmt = "<B3sB3sLL"
 
         def __init__(self, raw_part):
             """Create a Partition instance"""
@@ -55,11 +56,11 @@ class MBR(object):
              self.end,
              self.first_sector,
              self.sector_count
-             ) = struct.unpack(self.format, raw_part)
+             ) = struct.unpack(self.fmt, raw_part)
 
         def pack(self):
             """Pack the partition values into a binary string"""
-            return struct.pack(self.format,
+            return struct.pack(self.fmt,
                                self.status,
                                self.start,
                                self.type,
@@ -70,7 +71,7 @@ class MBR(object):
         @staticmethod
         def size():
             """Returns the size of an MBR partition entry"""
-            return struct.calcsize(MBR.Partition.format)
+            return struct.calcsize(MBR.Partition.fmt)
 
         def __str__(self):
             start = self.unpack_chs(self.start)
@@ -115,7 +116,7 @@ class MBR(object):
     def __init__(self, block):
         """Create an MBR instance"""
 
-        self.format = "<444s2x16s16s16s16s2s"
+        self.fmt = "<444s2x16s16s16s16s2s"
         raw_part = {}     # Offset  Length          Contents
         (self.code_area,  # 0       440(max. 446)   code area
                           # 440     2(optional)     disk signature
@@ -125,7 +126,7 @@ class MBR(object):
          raw_part[2],     # 478     16              Partition 2
          raw_part[3],     # 494     16              Partition 3
          self.signature   # 510     2               MBR signature
-         ) = struct.unpack(self.format, block)
+         ) = struct.unpack(self.fmt, block)
 
         self.part = {}
         for i in range(4):
@@ -133,11 +134,11 @@ class MBR(object):
 
     def size(self):
         """Return the size of a Master Boot Record."""
-        return struct.calcsize(self.format)
+        return struct.calcsize(self.fmt)
 
     def pack(self):
         """Pack an MBR to a binary string."""
-        return struct.pack(self.format,
+        return struct.pack(self.fmt,
                            self.code_area,
                            self.part[0].pack(),
                            self.part[1].pack(),
@@ -233,25 +234,19 @@ class Disk(object):
 
 class DisklabelBase(object):
     """Disklabel base class"""
+    __metaclass__ = abc.ABCMeta
 
     def __init__(self, device):
         """Create a Disklabel instance"""
-        pass
 
-    @property
-    def format(self):
-        """Fields format string"""
-        raise NotImplementedError
-
-    @property
-    def field(self):
-        """Diskalabel Fields data structure"""
-        raise NotImplementedError
+        # Subclasses need to overwrite this
+        self.field = None
+        self.ptable = None
 
-    @property
-    def ptable(self):
-        """Partition Table data structure"""
-        raise NotImplementedError
+    @abc.abstractproperty
+    def fmt(self):
+        """Fields format string for the disklabel fields"""
+        pass
 
     def pack(self, checksum=None):
         """Return a binary copy of the Disklabel block"""
@@ -263,7 +258,7 @@ class DisklabelBase(object):
         if checksum is not None:
             out['checksum'] = checksum
 
-        return struct.pack(self.format, * out.values() + [self.ptable.pack()])
+        return struct.pack(self.fmt, * out.values() + [self.ptable.pack()])
 
     def compute_checksum(self):
         """Compute the checksum of the disklabel"""
@@ -280,9 +275,10 @@ class DisklabelBase(object):
 
         return checksum
 
+    @abc.abstractmethod
     def enlarge(self, new_size):
         """Enlarge the disk and return the last usable sector"""
-        raise NotImplementedError
+        pass
 
     def write_to(self, device):
         """Write the disklabel to a device"""
@@ -291,40 +287,48 @@ class DisklabelBase(object):
         device.seek(BLOCKSIZE, os.SEEK_CUR)
         device.write(self.pack())
 
+    @abc.abstractmethod
     def enlarge_last_partition(self):
         """Enlarge the last partition to consume all the usable space"""
-        raise NotImplementedError
+        pass
 
+    @abc.abstractmethod
     def get_last_partition_id(self):
         """Get the ID of the last partition"""
-        raise NotImplementedError
+        pass
 
+    @abc.abstractmethod
     def __str__(self):
         """Print the Disklabel"""
-        raise NotImplementedError
+        pass
 
 
 class PartitionTableBase(object):
     """Base Class for disklabel partition tables"""
+    __metaclass__ = abc.ABCMeta
 
-    @property
-    def format(self):
-        """Partition table format string"""
-        raise NotImplementedError
+    @abc.abstractproperty
+    def fmt(self):
+        """Partition fields format string"""
+        pass
 
-    Partition = namedtuple('Partition', '')
+    @abc.abstractproperty
+    def fields(self):
+        """The partition fields"""
+        pass
 
     def __init__(self, ptable, pnumber):
         """Create a Partition Table instance"""
-        self.part = []
 
-        size = struct.calcsize(self.format)
+        self.Partition = namedtuple('Partition', self.fields)
+        self.part = []
 
+        size = struct.calcsize(self.fmt)
         raw = cStringIO.StringIO(ptable)
         try:
             for _ in xrange(pnumber):
                 self.part.append(
-                    self.Partition(*struct.unpack(self.format, raw.read(size)))
+                    self.Partition(*struct.unpack(self.fmt, raw.read(size)))
                     )
         finally:
             raw.close()
@@ -340,7 +344,7 @@ class PartitionTableBase(object):
         """Packs the partition table into a binary string."""
         ret = ""
         for i in xrange(len(self.part)):
-            ret += struct.pack(self.format, *self.part[i])
+            ret += struct.pack(self.fmt, *self.part[i])
         return ret + ((364 - len(self.part) * 16) * '\x00')
 
 
@@ -350,16 +354,26 @@ class BSD_Disklabel(DisklabelBase):
     class PartitionTable(PartitionTableBase):
         """Represents a BSD Partition Table"""
 
-        format = "<IIIBBH"
-        Partition = namedtuple(
-            'Partition',  # Offset  Length Contents
-            ['size',      # 0       4      Number of sectors in partition
-             'offset',    # 4       4      Starting sector
-             'fsize',     # 8       4      Filesystem basic fragment size
-             'fstype',    # 12      1      Filesystem type
-             'frag',      # 13      1      Filesystem fragments per block
-             'cpg'        # 14      2      Filesystem cylinders per group
-             ])
+        @property
+        def fmt(self):
+            """Partition fields format string"""
+            return "<IIIBBH"
+
+        @property
+        def fields(self):
+            """The partition fields"""
+            return [    # Offset  Length Contents
+                'size',     # 0       4      Number of sectors in partition
+                'offset',   # 4       4      Starting sector of the partition
+                'fsize',    # 8       4      File system basic fragment size
+                'fstype',   # 12      1      File system type
+                'frag',     # 13      1      File system fragments per block
+                'cpg'       # 14      2      File system cylinders per group
+                ]
+
+    @property
+    def fmt(self):
+        return "<IHH16s16sIIIIIIHHIHHHHIII20s20sIHHII364s"
 
     def __init__(self, device):
         """Create a BSD DiskLabel instance"""
@@ -369,7 +383,6 @@ class BSD_Disklabel(DisklabelBase):
         device.seek(BLOCKSIZE, os.SEEK_CUR)
         sector1 = device.read(BLOCKSIZE)
 
-        self.format = "<IHH16s16sIIIIIIHHIHHHHIII20s20sIHHII364s"
         d_ = OrderedDict()      # Off  Len    Content
         (d_["magic"],           # 0    4      Magic
          d_["dtype"],           # 4    2      Drive Type
@@ -400,12 +413,21 @@ class BSD_Disklabel(DisklabelBase):
          d_["bbsize"],          # 132  4      size of boot area at sn0, bytes
          d_["sbsize"],          # 136  4      Max size of fs superblock, bytes
          ptable_raw             # 140  16*16  Partition Table
-         ) = struct.unpack(self.format, sector1)
+         ) = struct.unpack(self.fmt, sector1)
 
         assert d_['magic'] == d_['magic2'] == DISKMAGIC, "Disklabel not valid"
         self.ptable = self.PartitionTable(ptable_raw, d_['npartitions'])
         self.field = d_
 
+    def enlarge(self, new_size):
+        raise NotImplementedError
+
+    def enlarge_last_partition(self):
+        raise NotImplementedError
+
+    def get_last_partition_id(self):
+        raise NotImplementedError
+
     def __str__(self):
         """Print the Disklabel"""
 
@@ -453,17 +475,22 @@ class OpenBSD_Disklabel(DisklabelBase):
 
     class PartitionTable(PartitionTableBase):
         """Reprepsents an OpenBSD Partition Table"""
-        format = "<IIHHBBH"
-        Partition = namedtuple(
-            'Partition',  # Offset  Length Contents
-            ['size',      # 0       4      Number of sectors in the partition
-             'offset',    # 4       4      Starting sector
-             'offseth',   # 8       2      Starting sector (high part)
-             'sizeh',     # 10      2      Number of sectors (high part)
-             'fstype',    # 12      1      Filesystem type
-             'frag',      # 13      1      Filesystem Fragments per block
-             'cpg'        # 14      2      FS cylinders per group
-             ])
+
+        @property
+        def fmt(self):
+            return "<IIHHBBH"
+
+        @property
+        def fields(self):
+            return [    # Offset  Length Contents
+                'size',     # 0       4      Number of sectors in the partition
+                'offset',   # 4       4      Starting sector of the partition
+                'offseth',  # 8       2      Starting sector (high part)
+                'sizeh',    # 10      2      Number of sectors (high part)
+                'fstype',   # 12      1      Filesystem type
+                'frag',     # 13      1      Filesystem Fragments per block
+                'cpg'       # 14      2      FS cylinders per group
+                ]
 
         def setpsize(self, i, size):
             """Set size for partition i"""
@@ -487,15 +514,19 @@ class OpenBSD_Disklabel(DisklabelBase):
             """Get offset for partition i"""
             return (self.part[i].offseth << 32) + self.part[i].offset
 
+    @property
+    def fmt(self):
+        return "<IHH16s16sIIIIII8sIHHIII20sHH16sIHHII364s"
+
     def __init__(self, device):
         """Create a DiskLabel instance"""
+
         super(OpenBSD_Disklabel, self).__init__(device)
 
         # Disklabel starts at offset one
         device.seek(BLOCKSIZE, os.SEEK_CUR)
         sector1 = device.read(BLOCKSIZE)
 
-        self.format = "<IHH16s16sIIIIII8sIHHIII20sHH16sIHHII364s"
         d_ = OrderedDict()   # Off  Len    Content
         (d_["magic"],        # 0    4      Magic
          d_["dtype"],        # 4    2      Drive Type
@@ -525,7 +556,7 @@ class OpenBSD_Disklabel(DisklabelBase):
          d_["bbsize"],       # 132  4      size of boot area at sn0, bytes
          d_["sbsize"],       # 136  4      Max size of fs superblock, bytes
          ptable_raw          # 140  16*16  Partition Table
-         ) = struct.unpack(self.format, sector1)
+         ) = struct.unpack(self.fmt, sector1)
 
         assert d_['magic'] == d_['magic2'] == DISKMAGIC, "Disklabel not valid"
         self.ptable = self.PartitionTable(ptable_raw, d_['npartitions'])