예제 #1
0
 def __call__(self, parser, namespace, values, option_string=None):
     sizes = {}
     specs = values.split(',')
     # First check for extended syntax by splitting on commas.
     for spec in specs:
         index, colon, size = spec.partition(':')
         if colon != ':':
             if len(specs) != 1:
                 raise argparse.ArgumentError(
                     self,
                     'Invalid multi-volume size specification: {}'.format(
                         spec))
             # Backward compatibility.  Since there was no colon to
             # partition the string on, the size argument will be in the
             # index local variable.
             try:
                 sizes = as_size(index)
             except (KeyError, ValueError):
                 raise argparse.ArgumentError(
                     self, 'Invalid size: {}'.format(values))
             break
         try:
             size = as_size(size)
         except (KeyError, ValueError):
             raise argparse.ArgumentError(self,
                                          'Invalid size: {}'.format(values))
         try:
             index = int(index)
         except (ValueError, TypeError):
             pass
         sizes[index] = size
     setattr(namespace, self.dest, sizes)
     # For display purposes.
     namespace.given_image_size = values
예제 #2
0
 def __call__(self, parser, namespace, values, option_string=None):
     sizes = {}
     specs = values.split(',')
     # First check for extended syntax by splitting on commas.
     for spec in specs:
         index, colon, size = spec.partition(':')
         if colon != ':':
             if len(specs) != 1:
                 raise argparse.ArgumentError(
                     self,
                     'Invalid multi-volume size specification: {}'.format(
                         spec))
             # Backward compatibility.  Since there was no colon to
             # partition the string on, the size argument will be in the
             # index local variable.
             try:
                 sizes = as_size(index)
             except (KeyError, ValueError):
                 raise argparse.ArgumentError(
                     self, 'Invalid size: {}'.format(values))
             break
         try:
             size = as_size(size)
         except (KeyError, ValueError):
             raise argparse.ArgumentError(
                 self, 'Invalid size: {}'.format(values))
         try:
             index = int(index)
         except (ValueError, TypeError):
             pass
         sizes[index] = size
     setattr(namespace, self.dest, sizes)
     # For display purposes.
     namespace.given_image_size = values
예제 #3
0
def RelativeOffset(v):
    """From the spec:

    It may be specified relative to another structure item with the
    syntax ``label+1234``.
    """
    label, plus, offset = v.partition('+')
    if len(label) == 0 or plus != '+' or len(offset) == 0:
        raise ValueError(v)
    return label, as_size(offset)
예제 #4
0
 def test_m(self):
     self.assertEqual(as_size('25M'), MiB(25))
예제 #5
0
def Size32bit(v):
    """Coerce size to being a 32 bit integer."""
    return as_size(v, max=GiB(4))
예제 #6
0
 def test_size_min_max(self):
     self.assertEqual(as_size('5', min=4, max=8), 5)
예제 #7
0
 def test_size_max_okay(self):
     self.assertEqual(as_size('5', max=8), 5)
예제 #8
0
 def test_size_min_inclusive_okay(self):
     self.assertEqual(as_size('3', min=3), 3)
예제 #9
0
 def test_size_min_okay(self):
     self.assertEqual(as_size('5', min=4), 5)
예제 #10
0
 def test_bytes(self):
     self.assertEqual(as_size('801'), 801)
예제 #11
0
def parse(stream):
    """Parse the YAML read from the stream.

    The YAML is parsed and validated against the schema defined in
    docs/image-yaml.rst.

    :param stream: A file-like object containing an image.yaml
        specification.  The file should be open for reading with a UTF-8
        encoding.
    :type image_yaml: file
    :return: A specification of the image.
    :rtype: ImageSpec
    :raises ValueError: If the schema is violated.
    """
    # For now, all the logic and constraints are codified in this
    # function.  At some point it may make sense to refactor that into
    # subclasses, but for now there's enough cross-level requirements
    # that it makes that refactoring tricky.
    yaml = load(stream)
    scheme = yaml['partition-scheme']
    if scheme not in ('MBR', 'GPT'):
        raise ValueError(scheme)
    partitions = []
    for partition in yaml['partitions']:
        name = partition.get('name')
        role = partition['role']
        guid = partition.get('guid')
        partition_offset = partition.get('offset')
        size = partition.get('size')
        fs_type = partition.get('fs-type')
        # Sanity check the values for the partition role.
        if role == 'ESP':
            if fs_type is not None:
                raise ValueError(
                    'Invalid explicit fs-type: {}'.format(fs_type))
            fs_type = 'vfat'
            if guid is not None:
                raise ValueError('Invalid explicit guid: {}'.format(guid))
            if partition.get('type') is not None:
                raise ValueError('Invalid explicit type id: {}'.format(
                    partition.get('type')))
            type_id = ('EF' if scheme == 'MBR'
                       else 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B')
        elif role == 'raw':
            if fs_type is not None:
                raise ValueError(
                    'No fs-type allowed for raw partitions: {}'.format(
                        fs_type))
            type_id = ('DA' if scheme == 'MBR'
                       else '21686148-6449-6E6F-744E-656564454649')
        elif role == 'custom':
            fs_type = partition.get('fs-type')
            if fs_type is None:
                raise ValueError('fs-type is required')
            elif fs_type not in ('vfat', 'ext4'):
                raise ValueError('Invalid fs-type: {}'.format(fs_type))
            type_id = ('83' if scheme == 'MBR'
                       else '0FC63DAF-8483-4772-8E79-3D69D8477DE4')
        else:
            raise ValueError('Bad role: {}'.format(role))
        # Sanity check other values.
        if scheme == 'MBR':
            guid = None
            # Allow MBRs to override the partition type identifier.
            type_id = partition.get('type', type_id)
        if partition_offset is not None:
            # If there is no unit suffix, then the YAML parser will have
            # already converted it to an integer, which we'll interpret
            # as a byte count.
            if not isinstance(partition_offset, int):
                partition_offset = as_size(partition_offset)
        if size is not None:
            size = as_size(size)
        # Handle files.
        files = []
        offset_defaulted = False
        for section in partition.get('files', []):
            source = section['source']
            if fs_type is None:
                if 'dest' in section:
                    raise ValueError('No dest allowed')
                offset = section.get('offset')
                if offset is None:
                    if offset_defaulted:
                        raise ValueError('Only one default offset allowed')
                    offset = 0
                    offset_defaulted = True
                else:
                    # Similar to above, if there was no unit suffix,
                    # offset will already be an integer.
                    if not isinstance(offset, int):
                        offset = as_size(offset)
                files.append((source, offset))
            else:
                if 'offset' in section:
                    raise ValueError('offset not allowed')
                dest = section.get('dest')
                if dest is None:
                    raise ValueError(
                        'dest required for source: {}'.format(source))
                files.append((source, dest))
        # XXX "It is also an error for files in the list to overlap."
        partitions.append(PartitionSpec(
            name, role, guid, type_id, partition_offset, size, fs_type, files))
    return ImageSpec(scheme, partitions)
예제 #12
0
 def test_size_max_okay(self):
     self.assertEqual(as_size('5', max=8), 5)
예제 #13
0
 def test_size_min_max(self):
     self.assertEqual(as_size('5', min=4, max=8), 5)
예제 #14
0
 def test_size_min_inclusive_okay(self):
     self.assertEqual(as_size('3', min=3), 3)
예제 #15
0
 def test_size_min_okay(self):
     self.assertEqual(as_size('5', min=4), 5)
예제 #16
0
 def test_bytes(self):
     self.assertEqual(as_size('801'), 801)
예제 #17
0
 def test_g(self):
     self.assertEqual(as_size('30G'), GiB(30))
예제 #18
0
 def test_m(self):
     self.assertEqual(as_size('25M'), MiB(25))
예제 #19
0
def Size32bit(v):
    """Coerce size to being a 32 bit integer."""
    return as_size(v, max=GiB(4))
예제 #20
0
 def test_g(self):
     self.assertEqual(as_size('30G'), GiB(30))