diff --git a/doc/composeinfo-1.1.rst b/doc/composeinfo-1.1.rst new file mode 100644 index 0000000..45820c5 --- /dev/null +++ b/doc/composeinfo-1.1.rst @@ -0,0 +1,68 @@ +=========================== +Composeinfo file format 1.1 +=========================== + +composeifo.json files provide details about composes which includes +product information, variants, architectures and paths. + + +Changes from 1.0 +================ + +* Added 'type' field to 'header', "productmd.composeinfo" required +* Added 'type' field to 'release' +* Added 'type' field to 'base_product' + + +File Format +=========== +Composeinfo is stored as a JSON serialized dictionary. +It's recommended to sort keys alphabetically and use 4 spaces for indentation +in order to read and diff composeinfo.json files easily. + + +:: + + { + "header": { + "type": "productmd.composeinfo", # metadata type; "productmd.composeinfo" required; [new in 1.1] + "version": "1.1" # metadata version; format: $major.$minor + }, + "payload": { + "compose": { + "id": , + "date": , + "respin": , + "type": , + "label": , + "final": # true if a compose is final for a milestone (for example latest Beta-1.x) + }, + "release": { + "name": , + "version": , + "short": , + "type": , # [new in 1.1] + "is_layered": , + }, + "base_product": { + "name": , + "version": , + "short": , + "type": , # [new in 1.1] + }, + "variants": { + variant_uid: { + "id": , + "uid": , + "name": , + "type": , + "arches": [], + "paths": { + path_category: { + arch: , + }, + }, + }, + }, + }, + } diff --git a/doc/conf.py b/doc/conf.py index 44f3066..eec1774 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -217,29 +217,29 @@ [u'Daniel Mach '], 7), # modules - ('compose', 'compose', u'productmd Documentation', + ('compose', 'productmd-compose', u'productmd Documentation', [u'Daniel Mach '], 1), - ('composeinfo', 'composeinfo', u'productmd Documentation', + ('composeinfo', 'productmd-composeinfo', u'productmd Documentation', [u'Daniel Mach '], 1), - ('discinfo', 'discinfo', u'productmd Documentation', + ('discinfo', 'productmd-discinfo', u'productmd Documentation', [u'Daniel Mach '], 1), - ('images', 'images', u'productmd Documentation', + ('images', 'productmd-images', u'productmd Documentation', [u'Daniel Mach '], 1), - ('rpms', 'rpms', u'productmd Documentation', + ('rpms', 'productmd-rpms', u'productmd Documentation', [u'Daniel Mach '], 1), - ('treeinfo', 'treeinfo', u'productmd Documentation', + ('treeinfo', 'productmd-treeinfo', u'productmd Documentation', [u'Daniel Mach '], 1), # file formats - ('composeinfo-1.0', 'composeinfo', u'productmd Documentation', + ('composeinfo-1.1', 'productmd-composeinfo', u'productmd Documentation', [u'Daniel Mach '], 5), - ('discinfo-1.0', 'discinfo', u'productmd Documentation', + ('discinfo-1.0', 'productmd-discinfo', u'productmd Documentation', [u'Daniel Mach '], 5), - ('images-1.0', 'images', u'productmd Documentation', + ('images-1.1', 'productmd-images', u'productmd Documentation', [u'Daniel Mach '], 5), - ('rpms-1.0', 'rpms', u'productmd Documentation', + ('rpms-1.0', 'productmd-rpms', u'productmd Documentation', [u'Daniel Mach '], 5), - ('treeinfo-1.0', 'treeinfo', u'productmd Documentation', + ('treeinfo-1.1', 'productmd-treeinfo', u'productmd Documentation', [u'Daniel Mach '], 5), ] diff --git a/doc/images-1.0.rst b/doc/images-1.0.rst index 6ac36b7..fa04ad3 100644 --- a/doc/images-1.0.rst +++ b/doc/images-1.0.rst @@ -40,7 +40,6 @@ in order to read and diff images.json files easily. "implant_md5": , # md5 checksum implanted directly on media (see implantisomd5 and checkisomd5 commands) "mtime": , # mtime of the image stored as a decimal unix timestamp "path": , # relative path to the image - "subvariant": , # image content (e.g. 'Workstation' or 'KDE') "size": , # file size of the image "type": , # see productmd.images.SUPPORTED_IMAGE_TYPES "volume_id": # volume ID; null if not available/applicable diff --git a/doc/images-1.1.rst b/doc/images-1.1.rst new file mode 100644 index 0000000..3ca3340 --- /dev/null +++ b/doc/images-1.1.rst @@ -0,0 +1,60 @@ +====================== +Images file format 1.1 +====================== + +images.json files provide details about images included in composes. + + +Changes from 1.0 +================ + +* Added 'type' field to 'header', "productmd.images" required +* Added 'subvariant' field to image + + +File Format +=========== + +Compose images metadata is stored as a JSON serialized dictionary. +It's recommended to sort keys alphabetically and use 4 spaces for indentation +in order to read and diff images.json files easily. + +:: + + { + "header": { + "type": "productmd.images", # metadata type; "productmd.images" required; [new in 1.1] + "version": "1.1" # metadata version; format: $major.$minor + }, + "payload": { + "compose": { # see composeinfo for details + "date": , + "id": , + "respin": , + "type": + }, + "images": { + variant_uid: { # compose variant UID + arch: [ # compose variant arch + { + "arch": , # image arch + "bootable": , # can the image be booted? + "checksums": { + type: # + }, + "disc_count": , # number of discs in media set + "disc_number": , # disc number + "format": , # see productmd.images.SUPPORTED_IMAGE_FORMATS + "implant_md5": , # md5 checksum implanted directly on media (see implantisomd5 and checkisomd5 commands) + "mtime": , # mtime of the image stored as a decimal unix timestamp + "path": , # relative path to the image + "subvariant": , # image content (e.g. 'Workstation' or 'KDE'); [new in 1.1] + "size": , # file size of the image + "type": , # see productmd.images.SUPPORTED_IMAGE_TYPES + "volume_id": # volume ID; null if not available/applicable + } + ] + } + } + } + } diff --git a/doc/index.rst b/doc/index.rst index 47396f3..ce87aa2 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -31,8 +31,18 @@ File formats: .. toctree:: :maxdepth: 2 - composeinfo-1.0 + composeinfo-1.1 discinfo-1.0 + images-1.1 + rpms-1.1 + treeinfo-1.1 + +Old file formats: + +.. toctree:: + :maxdepth: 1 + + composeinfo-1.0 images-1.0 rpms-1.0 treeinfo-1.0 diff --git a/doc/rpms-1.1.rst b/doc/rpms-1.1.rst new file mode 100644 index 0000000..84dba1e --- /dev/null +++ b/doc/rpms-1.1.rst @@ -0,0 +1,159 @@ +==================== +RPMs file format 1.1 +==================== + +rpms.json files provide details about RPMs included in composes. + + +Changes from 1.0 +================ + +* Added 'type' field to 'header', "productmd.rpms" required + + +File Format +=========== + +Compose RPMs metadata is stored as a JSON serialized dictionary. +It's recommended to sort keys alphabetically and use 4 spaces for indentation +in order to read and diff rpms.json files easily. + +:: + + { + "header": { + "type": "productmd.rpms", # metadata type; "productmd.rpms" required; [new in 1.1] + "version": "1.1" # metadata version; format: $major.$minor + }, + "payload": { + "compose": { # see composeinfo for details + "date": , + "id": , + "respin": , + "type": + }, + "rpms": { + variant_uid: { # compose variant UID + arch: { # compose variant arch + srpm_nevra: { # %name-%epoch:%version-%release-%arch of source RPM (koji build with epoch included) + rpm_nevra: { # %name-%epoch:%version-%release-%arch of RPM file + "path": , # relative path to RPM file + "sigkey": , # sigkey ID: hex string 8 characters long, lower case; null for unsigned RPMs + "category": # binary, debug, source + } + } + } + } + } + } + } + + +Examples +======== + +Bash in Fedora 21:: + + { + "header": { + "version": "1.0" + }, + "payload": { + "compose": { + "date": "20141203", + "id": "Fedora-21-20141203.0", + "respin": 0, + "type": "production" + }, + "rpms": { + "Server": { + "armhfp": { + "bash-0:4.3.30-2.fc21.src": { + "bash-0:4.3.30-2.fc21.armv7hl": { + "path": "Server/armhfp/os/Packages/b/bash-4.3.30-2.fc21.armv7hl.rpm", + "sigkey": "95a43f54", + "category": "binary" + }, + "bash-0:4.3.30-2.fc21.src": { + "path": "Server/source/SRPMS/b/bash-4.3.30-2.fc21.src.rpm", + "sigkey": "95a43f54", + "category": "binary" + } + } + }, + "i386": { + "bash-0:4.3.30-2.fc21.src": { + "bash-0:4.3.30-2.fc21.i686": { + "path": "Server/i386/os/Packages/b/bash-4.3.30-2.fc21.i686.rpm", + "sigkey": "95a43f54", + "category": "binary" + }, + "bash-0:4.3.30-2.fc21.src": { + "path": "Server/source/SRPMS/b/bash-4.3.30-2.fc21.src.rpm", + "sigkey": "95a43f54", + "category": "binary" + } + } + }, + "x86_64": { + "bash-0:4.3.30-2.fc21.src": { + "bash-0:4.3.30-2.fc21.x86_64": { + "path": "Server/x86_64/os/Packages/b/bash-4.3.30-2.fc21.x86_64.rpm", + "sigkey": "95a43f54", + "category": "binary" + }, + "bash-0:4.3.30-2.fc21.src": { + "path": "Server/source/SRPMS/b/bash-4.3.30-2.fc21.src.rpm", + "sigkey": "95a43f54", + "category": "binary" + } + } + } + }, + "Workstation": { + "armhfp": { + "bash-0:4.3.30-2.fc21.src": { + "bash-0:4.3.30-2.fc21.armv7hl": { + "path": "Workstation/armhfp/os/Packages/b/bash-4.3.30-2.fc21.armv7hl.rpm", + "sigkey": "95a43f54", + "category": "binary" + }, + "bash-0:4.3.30-2.fc21.src": { + "path": "Workstation/source/SRPMS/b/bash-4.3.30-2.fc21.src.rpm", + "sigkey": "95a43f54", + "category": "binary" + } + } + }, + "i386": { + "bash-0:4.3.30-2.fc21.src": { + "bash-0:4.3.30-2.fc21.i686": { + "path": "Workstation/i386/os/Packages/b/bash-4.3.30-2.fc21.i686.rpm", + "sigkey": "95a43f54", + "category": "binary" + }, + "bash-0:4.3.30-2.fc21.src": { + "path": "Workstation/source/SRPMS/b/bash-4.3.30-2.fc21.src.rpm", + "sigkey": "95a43f54", + "category": "binary" + } + } + }, + "x86_64": { + "bash-0:4.3.30-2.fc21.src": { + "bash-0:4.3.30-2.fc21.x86_64": { + "path": "Workstation/x86_64/os/Packages/b/bash-4.3.30-2.fc21.x86_64.rpm", + "sigkey": "95a43f54", + "category": "binary" + }, + "bash-0:4.3.30-2.fc21.src": { + "path": "Workstation/source/SRPMS/b/bash-4.3.30-2.fc21.src.rpm", + "sigkey": "95a43f54", + "category": "binary" + } + } + } + } + } + } + } diff --git a/doc/treeinfo-1.1.rst b/doc/treeinfo-1.1.rst new file mode 100644 index 0000000..ad29fa0 --- /dev/null +++ b/doc/treeinfo-1.1.rst @@ -0,0 +1,206 @@ +======================== +Treeinfo file format 1.1 +======================== + +Treeinfo files provide details about installable trees in Fedora composes and media. + + +Changes from 1.0 +================ + +* Added 'type' field to 'header', "productmd.treeinfo" required +* Added 'type' field to 'release' +* Added 'type' field to 'base_product' + + +File Format +=========== + +Treeinfo is an INI file. +It's recommended to sort sections and keys alphabetically +in order to diff .treeinfo files easily. + +:: + + [header] + type = ; metadata type; "productmd.treeinfo" required; [new in 1.1] + version = 1.1 ; metadata version; format: $major.$minor + + [release] + name = ; release name, for example: "Fedora", "Red Hat Enterprise Linux", "Spacewalk" + short = ; release short name, for example: "F", "RHEL", "Spacewalk" + version = ; release version, for example: "21", "7.0", "2.1" + type = ; release type, for example: "ga", "updates", "eus"; [new in 1.1] + is_layered = ; typically False for an operating system, True otherwise + + [base_product] + name = ; base product name, for example: "Fedora", "Red Hat Enterprise Linux" + short = ; base product short name, for example: "F", "RHEL" + version = ; base product *major* version, for example: "21", "7" + type = ; base product release type, for example: "ga", "eus"; [new in 1.1] + + [tree] + arch = ; tree architecture, for example x86_64 + build_timestamp = ; tree build time timestamp; format: unix time + platforms = [, ...] ; supported platforms; for example x86_64,xen + variants = [, ...] ; UIDs of available variants, for example "Server,Workstation" + + [checksums] + ; checksums of selected files in a tree: + ; * all repodata/repomd.xml + ; * all images captured in [images-*] and [stage2] sections + $path = $checksum_type:checksum_value + + [images-$platform] + ; images compatible with particular $platform + $file_name = $relative_path + + [stage2] + ; optional section, available only on bootable media with Anaconda installer + instimage = ; relative path to Anaconda instimage (obsolete) + mainimage = ; relative path to Anaconda stage2 image + + [media] + ; optional section, available only on media + discnum = ; disc number + totaldiscs = ; number of discs in media set + + [variant-$variant_uid] + id = ; variant ID + uid = ; variant UID ($parent_UID.$ID) + name = ; variant name + type = ; variant, optional + variants = [,...] ; UIDs of child variants + addons = [,...] ; UIDs of child addons + + ; variant paths + ; all paths are relative to .treeinfo location + packages = ; directory with binary RPMs + repository = ; YUM repository with binary RPMs + source_packages = ; directory with source RPMs + source_repository = ; YUM repository with source RPMs + debug_packages = ; directory with debug RPMs + debug_repository = ; YUM repository with debug RPMs + identity = ; path to a pem file that identifies a product + + [addon-$addon_uid] + id = ; addon ID + uid = ; addon UID ($parent_UID.$ID) + name = ; addon name + type = addon + + ; addon paths + ; see variant paths + + [general] + ; WARNING.0 = This section provides compatibility with pre-productmd treeinfos. + ; WARNING.1 = Read productmd documentation for details about new format. + family = ; equal to [release]/name + version = ; equal to [release]/version + name = ; equal to "$family $version" + arch = ; equal to [tree]/arch + platforms = [,...] ; equal to [tree]/platforms + packagedir = ; equal to [variant-*]/packages + repository = ; equal to [variant-*]/repository + timestamp = ; equal to [tree]/build_timestamp + variant = ; variant UID of first variant (sorted alphabetically) + + +Examples +======== + +Fedora 21 Server.x86_64 .treinfo converted to 1.0 format:: + + [checksums] + images/boot.iso = sha256:56af126a50c227d779a200b414f68ea7bcf58e21c8035500cd21ba164f85b9b4 + images/efiboot.img = sha256:de48c8b25f03861c00c355ccf78108159f1f2aa63d0d63f92815146c24f60164 + images/macboot.img = sha256:da76ff5490b4ae7e123f19b8f4b36efd6b7c435073551978d50c5181852a87f5 + images/product.img = sha256:ffce14a7a95be20b36f302cb0698be8c19fda798807d3d63a491d6f7c1b23b5b + images/pxeboot/initrd.img = sha256:aadebd07c4c0f19304f0df7535a8f4218e5141602f95adec08ad1e22ff1e2d43 + images/pxeboot/upgrade.img = sha256:224d098fb3903583b491692c5e0e1d20ea840d51f4da671ced97d422402bbf1c + images/pxeboot/vmlinuz = sha256:81c28a439f1d23786057d3b57db66e00b2b1a39b64d54de1a90cf2617e53c986 + repodata/repomd.xml = sha256:3af1609aa27949bf1e02e9204a7d4da7efee470063dadbc3ea0be3ef7f1f4d14 + + [general] + arch = x86_64 + family = Fedora + name = Fedora 21 + packagedir = Packages + platforms = x86_64,xen + repository = . + timestamp = 1417653911 + variant = Server + version = 21 + + [header] + version = 1.0 + + [images-x86_64] + boot.iso = images/boot.iso + initrd = images/pxeboot/initrd.img + kernel = images/pxeboot/vmlinuz + upgrade = images/pxeboot/upgrade.img + + [images-xen] + initrd = images/pxeboot/initrd.img + kernel = images/pxeboot/vmlinuz + upgrade = images/pxeboot/upgrade.img + + [release] + name = Fedora + short = Fedora + version = 21 + type = ga + + [stage2] + mainimage = LiveOS/squashfs.img + + [tree] + arch = x86_64 + build_timestamp = 1417653911 + platforms = x86_64,xen + variants = Server + + [variant-Server] + id = Server + name = Server + packages = Packages + repository = . + type = variant + uid = Server + + +Original Fedora 21 Server.x86_64 .treinfo file (before conversion):: + + [general] + name = Fedora-Server-21 + family = Fedora-Server + timestamp = 1417653911.68 + variant = Server + version = 21 + packagedir = + arch = x86_64 + + [stage2] + mainimage = LiveOS/squashfs.img + + [images-x86_64] + kernel = images/pxeboot/vmlinuz + initrd = images/pxeboot/initrd.img + upgrade = images/pxeboot/upgrade.img + boot.iso = images/boot.iso + + [images-xen] + kernel = images/pxeboot/vmlinuz + initrd = images/pxeboot/initrd.img + upgrade = images/pxeboot/upgrade.img + + [checksums] + images/efiboot.img = sha256:de48c8b25f03861c00c355ccf78108159f1f2aa63d0d63f92815146c24f60164 + images/macboot.img = sha256:da76ff5490b4ae7e123f19b8f4b36efd6b7c435073551978d50c5181852a87f5 + images/product.img = sha256:ffce14a7a95be20b36f302cb0698be8c19fda798807d3d63a491d6f7c1b23b5b + images/boot.iso = sha256:56af126a50c227d779a200b414f68ea7bcf58e21c8035500cd21ba164f85b9b4 + images/pxeboot/vmlinuz = sha256:81c28a439f1d23786057d3b57db66e00b2b1a39b64d54de1a90cf2617e53c986 + images/pxeboot/initrd.img = sha256:aadebd07c4c0f19304f0df7535a8f4218e5141602f95adec08ad1e22ff1e2d43 + images/pxeboot/upgrade.img = sha256:224d098fb3903583b491692c5e0e1d20ea840d51f4da671ced97d422402bbf1c + repodata/repomd.xml = sha256:3af1609aa27949bf1e02e9204a7d4da7efee470063dadbc3ea0be3ef7f1f4d14 diff --git a/productmd/common.py b/productmd/common.py index 6c30065..132a0a4 100644 --- a/productmd/common.py +++ b/productmd/common.py @@ -25,7 +25,7 @@ """ -VERSION = (1, 0) +VERSION = (1, 1) __all__ = ( @@ -264,10 +264,11 @@ def serialize(self, parser): class Header(MetadataBase): - def __init__(self, parent): + def __init__(self, parent, metadata_type): self._section = "header" self.parent = parent self.version = "0.0" + self.metadata_type = metadata_type def _validate_version(self): self._assert_type("version", six.string_types) @@ -287,11 +288,16 @@ def serialize(self, parser): self.validate() data = parser data[self._section] = {} + data[self._section]["type"] = self.metadata_type data[self._section]["version"] = self.version def deserialize(self, parser): data = parser self.version = data[self._section]["version"] + if self.version_tuple >= (1, 1): + metadata_type = data[self._section]["type"] + if metadata_type != self.metadata_type: + raise ValueError("Invalid metadata type '%s', expected '%s'" % (metadata_type, self.metadata_type)) self.validate() diff --git a/productmd/composeinfo.py b/productmd/composeinfo.py index 16e43c2..2fce1e0 100644 --- a/productmd/composeinfo.py +++ b/productmd/composeinfo.py @@ -92,7 +92,7 @@ class ComposeInfo(productmd.common.MetadataBase): def __init__(self): super(ComposeInfo, self).__init__() - self.header = Header(self) #: (:class:`.Header`) -- Metadata header + self.header = Header(self, "productmd.composeinfo") #: (:class:`.Header`) -- Metadata header self.compose = Compose(self) #: (:class:`.Compose`) -- Compose details self.release = Release(self) #: (:class:`.Release`) -- Release details self.base_product = BaseProduct(self) #: (:class:`.BaseProduct`) -- Base product details (optional) diff --git a/productmd/images.py b/productmd/images.py index 9762b4e..ddc0469 100644 --- a/productmd/images.py +++ b/productmd/images.py @@ -51,7 +51,7 @@ class Images(productmd.common.MetadataBase): def __init__(self): super(Images, self).__init__() - self.header = Header(self) + self.header = Header(self, "productmd.images") self.compose = Compose(self) self.images = {} @@ -119,7 +119,7 @@ def __init__(self, parent): self.checksums = {} #: (*str*) -- Release name, for example: "Fedora", "Red Hat Enterprise Linux" self.implant_md5 = None #: (*str* or *None*) -- value of implanted md5 self.bootable = False #: (*bool=False*) -- - self.subvariant = None #: (*str*) -- image contents, may be same as variant or e.g. 'KDE', 'LXDE' + self.subvariant = None #: (*str*) -- image contents, may be same as variant or e.g. 'KDE', 'LXDE' def __repr__(self): return "".format(self) @@ -172,7 +172,6 @@ def _validate_bootable(self): def _validate_subvariant(self): self._assert_type("subvariant", list(six.string_types)) - self._assert_not_blank("subvariant") def serialize(self, parser): data = parser @@ -207,7 +206,11 @@ def deserialize(self, data): self.checksums = data["checksums"] self.implant_md5 = data["implant_md5"] self.bootable = bool(data["bootable"]) - self.subvariant = data["subvariant"] + if self.parent.header.version_tuple <= (1, 0): + self.subvariant = data.get("subvariant", "") + else: + # 1.1+ + self.subvariant = data["subvariant"] self.validate() def add_checksum(self, root, checksum_type, checksum_value): diff --git a/productmd/rpms.py b/productmd/rpms.py index f043ea5..22b1a9f 100644 --- a/productmd/rpms.py +++ b/productmd/rpms.py @@ -40,7 +40,7 @@ class Rpms(productmd.common.MetadataBase): def __init__(self): super(Rpms, self).__init__() - self.header = Header(self) + self.header = Header(self, "productmd.rpms") self.compose = Compose(self) self.rpms = {} diff --git a/productmd/treeinfo.py b/productmd/treeinfo.py index 67f5ed9..d467812 100644 --- a/productmd/treeinfo.py +++ b/productmd/treeinfo.py @@ -64,7 +64,7 @@ def compute_checksum(path, checksum_type): class TreeInfo(productmd.common.MetadataBase): def __init__(self): super(productmd.common.MetadataBase, self) - self.header = Header(self) #: (:class:`productmd.common.Header`) -- Metadata header + self.header = Header(self, "productmd.treeinfo") #: (:class:`productmd.common.Header`) -- Metadata header self.release = Release(self) #: (:class:`.Release`) -- Release details self.base_product = BaseProduct(self) #: (:class:`.BaseProduct`) -- Base product details (optional) self.tree = Tree(self) #: (:class:`.Tree`) -- Tree details @@ -141,10 +141,15 @@ def serialize(self, parser): parser.add_section(self._section) # write *current* version, because format gets converted on save parser.set(self._section, "version", ".".join([str(i) for i in productmd.common.VERSION])) + parser.set(self._section, "type", self.metadata_type) def deserialize(self, parser): if parser.has_option(self._section, "version"): self.version = parser.get(self._section, "version") + if self.version_tuple >= (1, 1): + metadata_type = parser.get(self._section, "type") + if metadata_type != self.metadata_type: + raise ValueError("Invalid metadata type '%s', expected '%s'" % (metadata_type, self.metadata_type)) self.validate() diff --git a/setup.py b/setup.py index e6fb0c6..0f067b9 100755 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ setup( name = "productmd", - version = "1.0", + version = "1.1", description = "Product, compose and installation media metadata library", url = "https://github.com/release-engineering/productmd", author = "Daniel Mach", diff --git a/tests/images/f20.json b/tests/images/f20.json new file mode 100644 index 0000000..25012d6 --- /dev/null +++ b/tests/images/f20.json @@ -0,0 +1,55 @@ +{ + "header": { + "version": "1.0" + }, + "payload": { + "compose": { + "date": "20131212", + "id": "Fedora-20-20131212.0", + "respin": 0, + "type": "production" + }, + "images": { + "Fedora": { + "x86_64": [ + { + "arch": "x86_64", + "bootable": true, + "checksums": { + "md5": "9a190c8b2bd382c2d046dbc855cd2f2b", + "sha1": "36dd25d7a6df45cdf19b85ad1bf2a2ccbf34f991", + "sha256": "f2eeed5102b8890e9e6f4b9053717fe73031e699c4b76dc7028749ab66e7f917" + }, + "disc_count": 1, + "disc_number": 1, + "format": "iso", + "implant_md5": "b39b2f6770ca015f300af01cb54db75c", + "mtime": 1410855216, + "path": "Fedora/x86_64/iso/Fedora-20-x86_64-DVD.iso", + "size": 4603248640, + "type": "dvd", + "volume_id": "Fedora 20 x86_64" + }, + { + "arch": "x86_64", + "bootable": true, + "checksums": { + "md5": "82716caf39ce9fd88e7cfc66ca219db8", + "sha1": "cb8b3e285fc1336cbbd7ba4b0381095dd0e159b0", + "sha256": "376be7d4855ad6281cb139430606a782fd6189dcb01d7b61448e915802cc350f" + }, + "disc_count": 1, + "disc_number": 1, + "format": "iso", + "implant_md5": "62cc05b03d28881c88ff1e949d6fc0b7", + "mtime": 1410855243, + "path": "Fedora/x86_64/iso/Fedora-20-x86_64-netinst.iso", + "size": 336592896, + "type": "netinst", + "volume_id": "Fedora 20 x86_64" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/images/f23.json b/tests/images/f23.json new file mode 100644 index 0000000..30c4ab5 --- /dev/null +++ b/tests/images/f23.json @@ -0,0 +1,75 @@ +{ + "header": { + "type": "productmd.images", + "version": "1.1" + }, + "payload": { + "compose": { + "date": "20151030", + "id": "Fedora-23-20151030.0", + "respin": 0, + "type": "production" + }, + "images": { + "Live": { + "x86_64": [ + { + "arch": "x86_64", + "bootable": true, + "checksums": { + "sha256": "ef7e5ed9eee6dbcde1e0a4d69c76ce6fb552f75ccad879fa0f93031ceb950f27" + }, + "disc_count": 1, + "disc_number": 1, + "format": "iso", + "implant_md5": "8bc179ecdd48e0b019365104f081a83e", + "mtime": 1446154932, + "path": "Live/x86_64/iso/Fedora-Live-KDE-x86_64-23-10.iso", + "size": 1291845632, + "subvariant": "KDE", + "type": "live", + "volume_id": "Fedora-Live-KDE-x86_64-23-10" + } + ] + }, + "Server": { + "x86_64": [ + { + "arch": "x86_64", + "bootable": true, + "checksums": { + "sha256": "30758dc821d1530de427c9e35212bd79b058bd4282e64b7b34ae1a40c87c05ae" + }, + "disc_count": 1, + "disc_number": 1, + "format": "iso", + "implant_md5": "1cd120922a791d03e829392a2b6b2107", + "mtime": 1446169817, + "path": "Server/x86_64/iso/Fedora-Server-DVD-x86_64-23.iso", + "size": 2149580800, + "subvariant": "", + "type": "dvd", + "volume_id": "Fedora-S-23-x86_64" + }, + { + "arch": "x86_64", + "bootable": true, + "checksums": { + "sha256": "32e0a15a1c71d0e2fd36a0af5b67a3b3af82976d2dfca0aefcb90d42f2ae6844" + }, + "disc_count": 1, + "disc_number": 1, + "format": "iso", + "implant_md5": "6ccc75afc55855ece24ee84e62e6dcc0", + "mtime": 1458057407, + "path": "Server/x86_64/iso/Fedora-Server-netinst-x86_64-23.iso", + "size": 8011776, + "subvariant": "", + "type": "netinst", + "volume_id": "Fedora-S-23-x86_64" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/test_header.py b/tests/test_header.py index 206307a..a770f05 100755 --- a/tests/test_header.py +++ b/tests/test_header.py @@ -33,7 +33,7 @@ class TestHeader(unittest.TestCase): def test_version(self): - hdr = Header(None) + hdr = Header(None, "productmd.header") # empty version hdr.version = None @@ -54,9 +54,10 @@ def test_version(self): hdr.validate() def test_deserialize(self): - hdr = Header(None) + hdr = Header(None, "productmd.header") data = { "header": { + "type": "productmd.header", "version": "1.0", } } @@ -64,13 +65,14 @@ def test_deserialize(self): self.assertEqual(hdr.version, "1.0") def test_serialize(self): - hdr = Header(None) + hdr = Header(None, "productmd.header") hdr.version = "1.0" serialized_data = {} hdr.serialize(serialized_data) expected_data = { "header": { - "version": "1.0", + "type": "productmd.header", + "version": "1.1", } } self.assertEqual(serialized_data, expected_data) diff --git a/tests/test_images.py b/tests/test_images.py index 861839f..61cce88 100755 --- a/tests/test_images.py +++ b/tests/test_images.py @@ -72,7 +72,7 @@ def test_fedora_20(self): im.compose.respin = 0 i = Image(im) - i.path = "Fedora/x86_64/iso/Fedora-Server-dvd-x86_64-20.iso" + i.path = "Fedora/x86_64/iso/Fedora-20-x86_64-DVD.iso" i.mtime = 1410855216 i.size = 4603248640 i.arch = "x86_64" @@ -80,8 +80,8 @@ def test_fedora_20(self): i.format = "iso" i.disc_number = 1 i.disc_count = 1 - i.volume_id = "Fedora-S-dvd-x86_64-20" - i.subvariant = "Server" + i.volume_id = "Fedora 20 x86_64" + i.subvariant = "" # checksums i.add_checksum(root=None, checksum_type="sha256", checksum_value="f2eeed5102b8890e9e6f4b9053717fe73031e699c4b76dc7028749ab66e7f917") @@ -99,16 +99,16 @@ def test_fedora_20(self): im.add("Fedora", "x86_64", i) i = Image(im) - i.path = "Fedora/x86_64/iso/Fedora-Server-boot-x86_64-20.iso" + i.path = "Fedora/x86_64/iso/Fedora-20-x86_64-netinst.iso" i.mtime = 1410855243 i.size = 336592896 i.arch = "x86_64" - i.type = "boot" + i.type = "netinst" i.format = "iso" i.disc_number = 1 i.disc_count = 1 - i.volume_id = "Fedora-S-boot-x86_64-20" - i.subvariant = "Server" + i.volume_id = "Fedora 20 x86_64" + i.subvariant = "" # checksums i.add_checksum(root=None, checksum_type="sha256", checksum_value="376be7d4855ad6281cb139430606a782fd6189dcb01d7b61448e915802cc350f") @@ -125,16 +125,103 @@ def test_fedora_20(self): i.bootable = True im.add("Fedora", "x86_64", i) - # im.dump("image_manifest.json") + # im.dump("f20.json") self._test_identity(im) - # 1 arch + # Server: 1 arch, 2 images self.assertEqual(len(im["Fedora"]), 1) - - # 2 images self.assertEqual(len(im["Fedora"]["x86_64"]), 2) + def test_fedora_23(self): + im = Images() + im.header.version = "1.0" + im.compose.id = "Fedora-23-20151030.0" + im.compose.type = "production" + im.compose.date = "20151030" + im.compose.respin = 0 + + i = Image(im) + i.path = "Server/x86_64/iso/Fedora-Server-DVD-x86_64-23.iso" + i.mtime = 1446169817 + i.size = 2149580800 + i.arch = "x86_64" + i.type = "dvd" + i.format = "iso" + i.disc_number = 1 + i.disc_count = 1 + i.volume_id = "Fedora-S-23-x86_64" + i.subvariant = "" + + # checksums + i.add_checksum(root=None, checksum_type="sha256", checksum_value="30758dc821d1530de427c9e35212bd79b058bd4282e64b7b34ae1a40c87c05ae") + self.assertEqual(i.checksums, { + "sha256": "30758dc821d1530de427c9e35212bd79b058bd4282e64b7b34ae1a40c87c05ae", + }) + self.assertRaises(ValueError, i.add_checksum, root=None, checksum_type="sha256", checksum_value="foo") + + i.implant_md5 = "1cd120922a791d03e829392a2b6b2107" + i.bootable = True + im.add("Server", "x86_64", i) + + i = Image(im) + i.path = "Server/x86_64/iso/Fedora-Server-netinst-x86_64-23.iso" + i.mtime = 1458057407 + i.size = 8011776 + i.arch = "x86_64" + i.type = "netinst" + i.format = "iso" + i.disc_number = 1 + i.disc_count = 1 + i.volume_id = "Fedora-S-23-x86_64" + i.subvariant = "" + + # checksums + i.add_checksum(root=None, checksum_type="sha256", checksum_value="32e0a15a1c71d0e2fd36a0af5b67a3b3af82976d2dfca0aefcb90d42f2ae6844") + self.assertEqual(i.checksums, { + "sha256": "32e0a15a1c71d0e2fd36a0af5b67a3b3af82976d2dfca0aefcb90d42f2ae6844", + }) + self.assertRaises(ValueError, i.add_checksum, root=None, checksum_type="sha256", checksum_value="foo") + + i.implant_md5 = "6ccc75afc55855ece24ee84e62e6dcc0" + i.bootable = True + im.add("Server", "x86_64", i) + + i = Image(im) + i.path = "Live/x86_64/iso/Fedora-Live-KDE-x86_64-23-10.iso" + i.mtime = 1446154932 + i.size = 1291845632 + i.arch = "x86_64" + i.type = "live" + i.format = "iso" + i.disc_number = 1 + i.disc_count = 1 + i.volume_id = "Fedora-Live-KDE-x86_64-23-10" + i.subvariant = "KDE" + + # checksums + i.add_checksum(root=None, checksum_type="sha256", checksum_value="ef7e5ed9eee6dbcde1e0a4d69c76ce6fb552f75ccad879fa0f93031ceb950f27") + self.assertEqual(i.checksums, { + "sha256": "ef7e5ed9eee6dbcde1e0a4d69c76ce6fb552f75ccad879fa0f93031ceb950f27", + }) + self.assertRaises(ValueError, i.add_checksum, root=None, checksum_type="sha256", checksum_value="foo") + + i.implant_md5 = "8bc179ecdd48e0b019365104f081a83e" + i.bootable = True + im.add("Live", "x86_64", i) + + # im.dump("f23.json") + + self._test_identity(im) + + # Server: 1 arch, 2 images + self.assertEqual(len(im["Server"]), 1) + self.assertEqual(len(im["Server"]["x86_64"]), 2) + + # Live: 1 arch, 1 images + self.assertEqual(len(im["Live"]), 1) + self.assertEqual(len(im["Live"]["x86_64"]), 1) + def test_image_repr(self): i = Image(None) i.path = "Fedora/x86_64/iso/Fedora-20-x86_64-DVD.iso" @@ -156,6 +243,14 @@ def test_image_repr_incomplete(self): self.assertEqual(repr(i), '') + def test_f20_format_10(self): + im = Images() + im.load(os.path.join(DIR, "images/f20.json")) + + def test_f23_format_11(self): + im = Images() + im.load(os.path.join(DIR, "images/f23.json")) + if __name__ == "__main__": unittest.main()