| |
@@ -1,7 +1,6 @@
|
| |
# -*- coding: utf-8 -*-
|
| |
|
| |
-
|
| |
- # Copyright (c) 2016 Red Hat, Inc.
|
| |
+ # Copyright © 2016 - 2018 Red Hat, Inc.
|
| |
#
|
| |
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
| |
# of this software and associated documentation files (the "Software"), to deal
|
| |
@@ -10,8 +9,8 @@
|
| |
# copies of the Software, and to permit persons to whom the Software is
|
| |
# furnished to do so, subject to the following conditions:
|
| |
#
|
| |
- # The above copyright notice and this permission notice shall be included in all
|
| |
- # copies or substantial portions of the Software.
|
| |
+ # The above copyright notice and this permission notice shall be included in
|
| |
+ # all copies or substantial portions of the Software.
|
| |
#
|
| |
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| |
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| |
@@ -40,42 +39,30 @@
|
| |
mmd.dump("out.yaml")
|
| |
"""
|
| |
|
| |
- from collections import OrderedDict
|
| |
import sys
|
| |
import datetime
|
| |
- import dateutil.parser
|
| |
import yaml
|
| |
|
| |
- if sys.version_info > (3,):
|
| |
- long = int
|
| |
-
|
| |
- from modulemd.api import ModuleAPI
|
| |
- from modulemd.artifacts import ModuleArtifacts
|
| |
- from modulemd.buildopts import ModuleBuildopts
|
| |
- from modulemd.buildopts.rpms import ModuleBuildoptsRPMs
|
| |
- from modulemd.components import ModuleComponents
|
| |
- from modulemd.components.module import ModuleComponentModule
|
| |
- from modulemd.components.rpm import ModuleComponentRPM
|
| |
- from modulemd.filter import ModuleFilter
|
| |
- from modulemd.profile import ModuleProfile
|
| |
+ import gi
|
| |
+ from gi.repository import GLib
|
| |
+ gi.require_version('Modulemd', '0.2')
|
| |
+ from gi.repository import Modulemd
|
| |
|
| |
- supported_mdversions = ( 1, )
|
| |
+ from .api import ModuleAPI
|
| |
+ from .artifacts import ModuleArtifacts
|
| |
+ from .buildopts import ModuleBuildopts
|
| |
+ from .components import ModuleComponents
|
| |
+ from .filter import ModuleFilter
|
| |
+ from .profile import ModuleProfile
|
| |
|
| |
- # From https://stackoverflow.com/a/16782282
|
| |
- # Enable yaml handling of OrderedDict, rather than serialize
|
| |
- # dict values alphabetically
|
| |
- def _represent_ordereddict(dumper, data):
|
| |
- value = []
|
| |
|
| |
- for item_key, item_value in data.items():
|
| |
- node_key = dumper.represent_data(item_key)
|
| |
- node_value = dumper.represent_data(item_value)
|
| |
+ if sys.version_info > (3,):
|
| |
+ integer_types = (int,)
|
| |
+ else:
|
| |
+ integer_types = (int, long) # noqa
|
| |
|
| |
- value.append((node_key, node_value))
|
| |
+ supported_mdversions = (1,)
|
| |
|
| |
- return yaml.nodes.MappingNode(u'tag:yaml.org,2002:map', value)
|
| |
- yaml.representer.SafeRepresenter.add_representer(OrderedDict,
|
| |
- _represent_ordereddict)
|
| |
|
| |
def load_all(f):
|
| |
"""Loads a metadata file containing multiple modulemd documents
|
| |
@@ -83,9 +70,16 @@
|
| |
|
| |
:param str f: File name to load
|
| |
"""
|
| |
- with open(f, "r") as infile:
|
| |
- data = infile.read()
|
| |
- return loads_all(data)
|
| |
+ l = list()
|
| |
+ mmd_l = Modulemd.Module.new_all_from_file(f)
|
| |
+
|
| |
+ for mmd in mmd_l:
|
| |
+ m = ModuleMetadata()
|
| |
+ m.module = mmd
|
| |
+ l.append(m)
|
| |
+
|
| |
+ return l
|
| |
+
|
| |
|
| |
def loads_all(s):
|
| |
"""Loads multiple modulemd documents from a YAML multidocument
|
| |
@@ -94,20 +88,28 @@
|
| |
:param str s: String containing multiple YAML documents.
|
| |
"""
|
| |
l = list()
|
| |
- for doc in yaml.safe_load_all(s):
|
| |
+ mmd_l = Modulemd.Module.new_all_from_string(s)
|
| |
+
|
| |
+ for mmd in mmd_l:
|
| |
m = ModuleMetadata()
|
| |
- m.loadd(doc)
|
| |
+ m.module = mmd
|
| |
l.append(m)
|
| |
+
|
| |
return l
|
| |
|
| |
+
|
| |
def dump_all(f, l):
|
| |
"""Dumps a list of ModuleMetadata instances into a file.
|
| |
|
| |
:param str f: Output filename
|
| |
:param list l: List of ModuleMetadata instances
|
| |
"""
|
| |
- with open(f, "w") as outfile:
|
| |
- outfile.write(dumps_all(l))
|
| |
+ mmds = list()
|
| |
+ for module in l:
|
| |
+ mmds.append(module.module)
|
| |
+
|
| |
+ return Modulemd.Module.dump_all(mmds, f)
|
| |
+
|
| |
|
| |
def dumps_all(l):
|
| |
"""Dumps a list of ModuleMetadata instance into a YAML multidocument
|
| |
@@ -115,8 +117,12 @@
|
| |
|
| |
:param list l: List of ModuleMetadata instances
|
| |
"""
|
| |
- return yaml.safe_dump_all([x._dumpd_ordered() for x in l],
|
| |
- explicit_start=True)
|
| |
+ mmds = list()
|
| |
+ for module in l:
|
| |
+ mmds.append(module.module)
|
| |
+
|
| |
+ return Modulemd.Module.dumps_all(mmds)
|
| |
+
|
| |
|
| |
class ModuleMetadata(object):
|
| |
"""Class representing the whole module."""
|
| |
@@ -125,6 +131,28 @@
|
| |
|
| |
def __init__(self):
|
| |
"""Creates a new ModuleMetadata instance."""
|
| |
+ # Under the hood, we will use the ModulemdModule type
|
| |
+ self.module = Modulemd.Module()
|
| |
+
|
| |
+ self.reset()
|
| |
+
|
| |
+ def __repr__(self):
|
| |
+ return ("<ModuleMetadata: mdversion: {!r}, name: {!r}, stream: {!r},"
|
| |
+ " version: {!r}, context: {!r}, arch: {!r}, summary: {!r},"
|
| |
+ " description: {!r}, eol: {!r}, module_licenses: {!r},"
|
| |
+ " content_licenses: {!r}, buildrequires: {!r}, requires: {!r},"
|
| |
+ " community: {!r}, documentation: {!r}, tracker: {!r},"
|
| |
+ " xmd: {!r}, profiles: {!r}, api: {!r}, filter: {!r},"
|
| |
+ " components: {!r}, artifacts: {!r}>").format(
|
| |
+ self.mdversion, self.name, self.stream, self.version,
|
| |
+ self.context, self.arch, self.summary, self.description,
|
| |
+ self.eol, sorted(self.module_licenses),
|
| |
+ sorted(self.content_licenses), sorted(self.buildrequires),
|
| |
+ sorted(self.requires), self.community, self.documentation,
|
| |
+ self.tracker, sorted(self.xmd), sorted(self.profiles),
|
| |
+ self.api, self.filter, self.components, self.artifacts)
|
| |
+
|
| |
+ def reset(self):
|
| |
self.mdversion = max(supported_mdversions)
|
| |
self.name = ""
|
| |
self.stream = ""
|
| |
@@ -134,85 +162,35 @@
|
| |
self.summary = ""
|
| |
self.description = ""
|
| |
self.eol = None
|
| |
+ self.servicelevels = {}
|
| |
self.module_licenses = set()
|
| |
self.content_licenses = set()
|
| |
- self.buildrequires = dict()
|
| |
- self.requires = dict()
|
| |
+ self.buildrequires = {}
|
| |
+ self.requires = {}
|
| |
self.community = ""
|
| |
self.documentation = ""
|
| |
self.tracker = ""
|
| |
- self.xmd = dict()
|
| |
- self.profiles = dict()
|
| |
- self.api = ModuleAPI()
|
| |
- self.filter = ModuleFilter()
|
| |
- self.buildopts = ModuleBuildopts()
|
| |
- self.components = ModuleComponents()
|
| |
- self.artifacts = ModuleArtifacts()
|
| |
-
|
| |
- def __repr__(self):
|
| |
- return ("<ModuleMetadata: "
|
| |
- "mdversion: {0}, "
|
| |
- "name: {1}, "
|
| |
- "stream: {2}, "
|
| |
- "version: {3}, "
|
| |
- "context: {4}, "
|
| |
- "arch: {5}, "
|
| |
- "summary: {6}, "
|
| |
- "description: {7}, "
|
| |
- "eol: {8}, "
|
| |
- "module_licenses: {9}, "
|
| |
- "content_licenses: {10}, "
|
| |
- "buildrequires: {11}, "
|
| |
- "requires: {12}, "
|
| |
- "community: {13}, "
|
| |
- "documentation: {14}, "
|
| |
- "tracker: {15}, "
|
| |
- "xmd: {16}, "
|
| |
- "profiles: {17}, "
|
| |
- "api: {18}, "
|
| |
- "filter: {19}, "
|
| |
- "components: {20}, "
|
| |
- "artifacts: {21}>").format(
|
| |
- repr(self.mdversion),
|
| |
- repr(self.name),
|
| |
- repr(self.stream),
|
| |
- repr(self.version),
|
| |
- repr(self.context),
|
| |
- repr(self.arch),
|
| |
- repr(self.summary),
|
| |
- repr(self.description),
|
| |
- repr(self.eol),
|
| |
- repr(sorted(self.module_licenses)),
|
| |
- repr(sorted(self.content_licenses)),
|
| |
- repr(sorted(self.buildrequires)),
|
| |
- repr(sorted(self.requires)),
|
| |
- repr(self.community),
|
| |
- repr(self.documentation),
|
| |
- repr(self.tracker),
|
| |
- repr(sorted(self.xmd)),
|
| |
- repr(sorted(self.profiles)),
|
| |
- repr(self.api),
|
| |
- repr(self.filter),
|
| |
- repr(self.components),
|
| |
- repr(self.artifacts)
|
| |
- )
|
| |
+ self.xmd = {}
|
| |
+ self.profiles = {}
|
| |
+ self.api = ModuleAPI(parent=self)
|
| |
+ self.filter = ModuleFilter(parent=self)
|
| |
+ self.buildopts = ModuleBuildopts(parent=self)
|
| |
+ self.components = ModuleComponents(parent=self)
|
| |
+ self.artifacts = ModuleArtifacts(parent=self)
|
| |
|
| |
def load(self, f):
|
| |
"""Loads a metadata file into the instance.
|
| |
|
| |
:param str f: File name to load
|
| |
"""
|
| |
- with open(f, "r") as infile:
|
| |
- data = infile.read()
|
| |
- self.loads(data)
|
| |
+ self.module = Modulemd.Module.new_from_file(f)
|
| |
|
| |
def loads(self, s):
|
| |
"""Loads metadata from a string.
|
| |
|
| |
:param str s: Raw metadata in YAML
|
| |
"""
|
| |
- yamld = yaml.safe_load(s)
|
| |
- self.loadd(yamld)
|
| |
+ self.module = Modulemd.Module.new_from_string(s)
|
| |
|
| |
def loadd(self, d):
|
| |
"""Loads metadata from a dictionary.
|
| |
@@ -220,285 +198,29 @@
|
| |
:param dict d: YAML metadata parsed into a dict
|
| |
:raises ValueError: If the metadata is invalid or unsupported.
|
| |
"""
|
| |
- # header
|
| |
- if "document" not in d or d["document"] != "modulemd":
|
| |
- raise ValueError("The supplied data isn't a valid modulemd document")
|
| |
- if "version" not in d:
|
| |
- raise ValueError("Document version is required")
|
| |
- if d["version"] not in supported_mdversions:
|
| |
- raise ValueError("The supplied metadata version isn't supported")
|
| |
- self.mdversion = d["version"]
|
| |
- if "data" not in d or not isinstance(d["data"], dict):
|
| |
- raise ValueError("Data section missing or mangled")
|
| |
- # data
|
| |
- data = d["data"]
|
| |
- if "name" in data:
|
| |
- self.name = str(data["name"])
|
| |
- if "stream" in data:
|
| |
- self.stream = str(data["stream"])
|
| |
- if "version" in data:
|
| |
- self.version = int(data["version"])
|
| |
- if "context" in data:
|
| |
- self.context = str(data["context"])
|
| |
- if "arch" in data:
|
| |
- self.arch = str(data["arch"])
|
| |
- if "summary" in data:
|
| |
- self.summary = str(data["summary"])
|
| |
- if "description" in data:
|
| |
- self.description = str(data["description"])
|
| |
- if "eol" in data:
|
| |
- try:
|
| |
- self.eol = dateutil.parser.parse(str(data["eol"])).date()
|
| |
- except:
|
| |
- self.eol = None
|
| |
- if ("license" in data
|
| |
- and isinstance(data["license"], dict)
|
| |
- and "module" in data["license"]
|
| |
- and data["license"]["module"]):
|
| |
- self.module_licenses = set(data["license"]["module"])
|
| |
- if ("license" in data
|
| |
- and isinstance(data["license"], dict)
|
| |
- and "content" in data["license"]):
|
| |
- self.content_licenses = set(data["license"]["content"])
|
| |
- if ("dependencies" in data
|
| |
- and isinstance(data["dependencies"], dict)):
|
| |
- if ("buildrequires" in data["dependencies"]
|
| |
- and isinstance(data["dependencies"]["buildrequires"], dict)):
|
| |
- for n, s in data["dependencies"]["buildrequires"].items():
|
| |
- self.add_buildrequires(str(n), str(s))
|
| |
- if ("requires" in data["dependencies"]
|
| |
- and isinstance(data["dependencies"]["requires"], dict)):
|
| |
- for n, s in data["dependencies"]["requires"].items():
|
| |
- self.add_requires(str(n), str(s))
|
| |
- if "references" in data and data["references"]:
|
| |
- if "community" in data["references"]:
|
| |
- self.community = data["references"]["community"]
|
| |
- if "documentation" in data["references"]:
|
| |
- self.documentation = data["references"]["documentation"]
|
| |
- if "tracker" in data["references"]:
|
| |
- self.tracker = data["references"]["tracker"]
|
| |
- if "xmd" in data:
|
| |
- self.xmd = data["xmd"]
|
| |
- if ("profiles" in data
|
| |
- and isinstance(data["profiles"], dict)):
|
| |
- for profile in data["profiles"].keys():
|
| |
- self.profiles[profile] = ModuleProfile()
|
| |
- if "description" in data["profiles"][profile]:
|
| |
- self.profiles[profile].description = \
|
| |
- str(data["profiles"][profile]["description"])
|
| |
- if "rpms" in data["profiles"][profile]:
|
| |
- self.profiles[profile].rpms = \
|
| |
- set(data["profiles"][profile]["rpms"])
|
| |
- if ("api" in data
|
| |
- and isinstance(data["api"], dict)):
|
| |
- self.api = ModuleAPI()
|
| |
- if ("rpms" in data["api"]
|
| |
- and isinstance(data["api"]["rpms"],list)):
|
| |
- self.api.rpms = set(data["api"]["rpms"])
|
| |
- if ("filter" in data
|
| |
- and isinstance(data["filter"], dict)):
|
| |
- self.filter = ModuleFilter()
|
| |
- if ("rpms" in data["filter"]
|
| |
- and isinstance(data["filter"]["rpms"],list)):
|
| |
- self.filter.rpms = set(data["filter"]["rpms"])
|
| |
- if ("buildopts" in data
|
| |
- and isinstance(data["buildopts"], dict)):
|
| |
- self.buildopts = ModuleBuildopts()
|
| |
- if ("rpms" in data["buildopts"]
|
| |
- and isinstance(data["buildopts"]["rpms"], dict)):
|
| |
- self.buildopts.rpms = ModuleBuildoptsRPMs()
|
| |
- if ("macros" in data["buildopts"]["rpms"]
|
| |
- and isinstance(data["buildopts"]["rpms"]["macros"], str)):
|
| |
- self.buildopts.rpms.macros = data["buildopts"]["rpms"]["macros"]
|
| |
- if ("components" in data
|
| |
- and isinstance(data["components"], dict)):
|
| |
- self.components = ModuleComponents()
|
| |
- if "rpms" in data["components"]:
|
| |
- for p, e in data["components"]["rpms"].items():
|
| |
- extras = dict()
|
| |
- extras["rationale"] = e["rationale"]
|
| |
- if "buildorder" in e:
|
| |
- extras["buildorder"] = int(e["buildorder"])
|
| |
- if "repository" in e:
|
| |
- extras["repository"] = str(e["repository"])
|
| |
- if "cache" in e:
|
| |
- extras["cache"] = str(e["cache"])
|
| |
- if "ref" in e:
|
| |
- extras["ref"] = str(e["ref"])
|
| |
- if ("arches" in e
|
| |
- and isinstance(e["arches"], list)):
|
| |
- extras["arches"] = set(str(x) for x in e["arches"])
|
| |
- if ("multilib" in e
|
| |
- and isinstance(e["multilib"], list)):
|
| |
- extras["multilib"] = set(str(x) for x in e["multilib"])
|
| |
- self.components.add_rpm(p, **extras)
|
| |
- if "modules" in data["components"]:
|
| |
- for p, e in data["components"]["modules"].items():
|
| |
- extras = dict()
|
| |
- extras["rationale"] = e["rationale"]
|
| |
- if "buildorder" in e:
|
| |
- extras["buildorder"] = int(e["buildorder"])
|
| |
- if "repository" in e:
|
| |
- extras["repository"] = str(e["repository"])
|
| |
- if "ref" in e:
|
| |
- extras["ref"] = str(e["ref"])
|
| |
- self.components.add_module(p, **extras)
|
| |
- if ("artifacts" in data
|
| |
- and isinstance(data["artifacts"], dict)):
|
| |
- self.artifacts = ModuleArtifacts()
|
| |
- if ("rpms" in data["artifacts"]
|
| |
- and isinstance(data["artifacts"]["rpms"],list)):
|
| |
- self.artifacts.rpms = set(data["artifacts"]["rpms"])
|
| |
+ self.loads(yaml.dump(d))
|
| |
+
|
| |
|
| |
def dump(self, f):
|
| |
"""Dumps the metadata into the supplied file.
|
| |
|
| |
:param str f: File name of the destination
|
| |
"""
|
| |
- data = self.dumps()
|
| |
- with open(f, "w") as outfile:
|
| |
- outfile.write(data)
|
| |
-
|
| |
- def _dumpd_ordered(self):
|
| |
- """Dumps the metadata into a OrderedDict.
|
| |
-
|
| |
- :rtype: collections.OrderedDict
|
| |
- """
|
| |
- doc = OrderedDict()
|
| |
- # header
|
| |
- doc["document"] = "modulemd"
|
| |
- doc["version"] = self.mdversion
|
| |
- # data
|
| |
- d = OrderedDict()
|
| |
- if self.name:
|
| |
- d["name"] = self.name
|
| |
- if self.stream:
|
| |
- d["stream"] = self.stream
|
| |
- if self.version:
|
| |
- d["version"] = self.version
|
| |
- if self.context:
|
| |
- d["context"] = self.context
|
| |
- if self.arch:
|
| |
- d["arch"] = self.arch
|
| |
- d["summary"] = self.summary
|
| |
- d["description"] = self.description
|
| |
- if self.eol:
|
| |
- d["eol"] = str(self.eol)
|
| |
- d["license"] = OrderedDict()
|
| |
- d["license"]["module"] = sorted(list(self.module_licenses))
|
| |
- if self.content_licenses:
|
| |
- d["license"]["content"] = sorted(list(self.content_licenses))
|
| |
- if self.buildrequires or self.requires:
|
| |
- d["dependencies"] = OrderedDict()
|
| |
- if self.buildrequires:
|
| |
- d["dependencies"]["buildrequires"] = self.buildrequires
|
| |
- if self.requires:
|
| |
- d["dependencies"]["requires"] = self.requires
|
| |
- if self.community or self.documentation or self.tracker:
|
| |
- d["references"] = OrderedDict()
|
| |
- if self.community:
|
| |
- d["references"]["community"] = self.community
|
| |
- if self.documentation:
|
| |
- d["references"]["documentation"] = self.documentation
|
| |
- if self.tracker:
|
| |
- d["references"]["tracker"] = self.tracker
|
| |
- if self.xmd:
|
| |
- d["xmd"] = self.xmd
|
| |
- if self.profiles:
|
| |
- d["profiles"] = OrderedDict()
|
| |
- for profile in self.profiles.keys():
|
| |
- if self.profiles[profile].description:
|
| |
- if profile not in d["profiles"]:
|
| |
- d["profiles"][profile] = OrderedDict()
|
| |
- d["profiles"][profile]["description"] = \
|
| |
- str(self.profiles[profile].description)
|
| |
- if self.profiles[profile].rpms:
|
| |
- if profile not in d["profiles"]:
|
| |
- d["profiles"][profile] = OrderedDict()
|
| |
- d["profiles"][profile]["rpms"] = \
|
| |
- sorted(list(self.profiles[profile].rpms))
|
| |
- if self.api:
|
| |
- d["api"] = OrderedDict()
|
| |
- if self.api.rpms:
|
| |
- d["api"]["rpms"] = sorted(list(self.api.rpms))
|
| |
- if self.filter:
|
| |
- d["filter"] = OrderedDict()
|
| |
- if self.filter.rpms:
|
| |
- d["filter"]["rpms"] = sorted(list(self.filter.rpms))
|
| |
- if self.buildopts:
|
| |
- d["buildopts"] = OrderedDict()
|
| |
- if self.buildopts.rpms:
|
| |
- d["buildopts"]["rpms"] = OrderedDict()
|
| |
- if self.buildopts.rpms.macros:
|
| |
- d["buildopts"]["rpms"]["macros"] = \
|
| |
- self.buildopts.rpms.macros
|
| |
- if self.components:
|
| |
- d["components"] = OrderedDict()
|
| |
- if self.components.rpms:
|
| |
- d["components"]["rpms"] = OrderedDict()
|
| |
- for p in self.components.rpms.values():
|
| |
- extra = OrderedDict()
|
| |
- extra["rationale"] = p.rationale
|
| |
- if p.buildorder:
|
| |
- extra["buildorder"] = p.buildorder
|
| |
- if p.repository:
|
| |
- extra["repository"] = p.repository
|
| |
- if p.ref:
|
| |
- extra["ref"] = p.ref
|
| |
- if p.cache:
|
| |
- extra["cache"] = p.cache
|
| |
- if p.arches:
|
| |
- extra["arches"] = sorted(list(p.arches))
|
| |
- if p.multilib:
|
| |
- extra["multilib"] = sorted(list(p.multilib))
|
| |
- d["components"]["rpms"][p.name] = extra
|
| |
- if self.components.modules:
|
| |
- d["components"]["modules"] = OrderedDict()
|
| |
- for p in self.components.modules.values():
|
| |
- extra = OrderedDict()
|
| |
- extra["rationale"] = p.rationale
|
| |
- if p.buildorder:
|
| |
- extra["buildorder"] = p.buildorder
|
| |
- if p.repository:
|
| |
- extra["repository"] = p.repository
|
| |
- if p.ref:
|
| |
- extra["ref"] = p.ref
|
| |
- d["components"]["modules"][p.name] = extra
|
| |
- if self.artifacts:
|
| |
- d["artifacts"] = OrderedDict()
|
| |
- if self.artifacts.rpms:
|
| |
- d["artifacts"]["rpms"] = sorted(list(self.artifacts.rpms))
|
| |
- doc["data"] = d
|
| |
- return doc
|
| |
+ self.module.dump(f)
|
| |
|
| |
def dumpd(self):
|
| |
"""Dumps the metadata into a dictionary.
|
| |
|
| |
:rtype: dict
|
| |
"""
|
| |
- def _convert_ordered(orig, new):
|
| |
- """Recurse over a nested OrderedDict, converting each to
|
| |
- a dict()
|
| |
- """
|
| |
- for key, val in orig.items():
|
| |
- if not isinstance(val, OrderedDict):
|
| |
- new[key] = val
|
| |
- continue
|
| |
-
|
| |
- new[key] = dict()
|
| |
- _convert_ordered(val, new[key])
|
| |
-
|
| |
- ordered = self._dumpd_ordered()
|
| |
- converted = dict()
|
| |
- _convert_ordered(ordered, converted)
|
| |
- return converted
|
| |
+ return yaml.safe_load(self.dumps())
|
| |
|
| |
def dumps(self):
|
| |
"""Dumps the metadata into a string.
|
| |
|
| |
:rtype: str
|
| |
"""
|
| |
- return yaml.safe_dump(self._dumpd_ordered(), default_flow_style=False)
|
| |
+ return self.module.dumps()
|
| |
|
| |
@property
|
| |
def mdversion(self):
|
| |
@@ -509,115 +231,139 @@
|
| |
changed to one of the supported_mdversions to alter the output
|
| |
format.
|
| |
"""
|
| |
- return self._mdversion
|
| |
+ return self.module.get_mdversion()
|
| |
|
| |
@mdversion.setter
|
| |
def mdversion(self, i):
|
| |
- if not isinstance(i, (int, long)):
|
| |
+ if not isinstance(i, integer_types):
|
| |
raise TypeError("mdversion: data type not supported")
|
| |
if i not in supported_mdversions:
|
| |
raise ValueError("mdversion: document version not supported")
|
| |
- self._mdversion = int(i)
|
| |
+ self.module.set_mdversion(int(i))
|
| |
|
| |
@property
|
| |
def name(self):
|
| |
"""A string property representing the name of the module."""
|
| |
- return self._name
|
| |
+ return self.module.get_name()
|
| |
|
| |
@name.setter
|
| |
def name(self, s):
|
| |
if not isinstance(s, str):
|
| |
raise TypeError("name: data type not supported")
|
| |
- self._name = s
|
| |
+ self.module.set_name(s)
|
| |
|
| |
@property
|
| |
def stream(self):
|
| |
"""A string property representing the stream name of the module."""
|
| |
- return self._stream
|
| |
+ return self.module.get_stream()
|
| |
|
| |
@stream.setter
|
| |
def stream(self, s):
|
| |
if not isinstance(s, str):
|
| |
raise TypeError("stream: data type not supported")
|
| |
- self._stream = str(s)
|
| |
+ self.module.set_stream(s)
|
| |
|
| |
@property
|
| |
def version(self):
|
| |
"""An integer property representing the version of the module."""
|
| |
- return self._version
|
| |
+ return self.module.get_version()
|
| |
|
| |
@version.setter
|
| |
def version(self, i):
|
| |
- if not isinstance(i, (int, long)):
|
| |
+ if not isinstance(i, integer_types):
|
| |
raise TypeError("version: data type not supported")
|
| |
if i < 0:
|
| |
raise ValueError("version: version cannot be negative")
|
| |
- self._version = i
|
| |
+ self.module.set_version(i)
|
| |
|
| |
@property
|
| |
def context(self):
|
| |
"""A string property representing the context flag of the module."""
|
| |
- return self._context
|
| |
+ return self.module.get_context()
|
| |
|
| |
@context.setter
|
| |
def context(self, s):
|
| |
if not isinstance(s, str):
|
| |
raise TypeError("context: data type not supported")
|
| |
- self._context = s
|
| |
+ self.module.set_context(s)
|
| |
|
| |
@property
|
| |
def arch(self):
|
| |
"""A string property representing the module artifacts' hardware
|
| |
architecture compatibility.
|
| |
"""
|
| |
- return self._arch
|
| |
+ return self.module.get_arch()
|
| |
|
| |
@arch.setter
|
| |
def arch(self, s):
|
| |
if not isinstance(s, str):
|
| |
raise TypeError("arch: data type not supported")
|
| |
- self._arch = s
|
| |
+ self.module.set_arch(s)
|
| |
|
| |
@property
|
| |
def summary(self):
|
| |
"""A string property representing a short summary of the module."""
|
| |
- return self._summary
|
| |
+ return self.module.get_summary()
|
| |
|
| |
@summary.setter
|
| |
def summary(self, s):
|
| |
if not isinstance(s, str):
|
| |
raise TypeError("summary: data type not supported")
|
| |
- self._summary = s
|
| |
+ self.module.set_summary(s)
|
| |
|
| |
@property
|
| |
def description(self):
|
| |
"""A string property representing a detailed description of the
|
| |
module."""
|
| |
- return self._description
|
| |
+ return self.module.get_description()
|
| |
|
| |
@description.setter
|
| |
def description(self, s):
|
| |
if not isinstance(s, str):
|
| |
raise TypeError("description: data type not supported")
|
| |
- self._description = s
|
| |
+ self.module.set_description(s)
|
| |
|
| |
@property
|
| |
def eol(self):
|
| |
"""A datetime.date property representing the module's EOL date.
|
| |
May be None if no EOL is defined."""
|
| |
- return self._eol
|
| |
+
|
| |
+ if not self.module.get_eol():
|
| |
+ return None
|
| |
+
|
| |
+ eol = datetime.date(self.module.get_eol().get_year(),
|
| |
+ self.module.get_eol().get_month(),
|
| |
+ self.module.get_eol().get_day())
|
| |
+ return eol
|
| |
|
| |
@eol.setter
|
| |
def eol(self, o):
|
| |
if not isinstance(o, datetime.date) and o is not None:
|
| |
raise TypeError("eol: data type not supported")
|
| |
- self._eol = o
|
| |
+
|
| |
+ if o:
|
| |
+ d = GLib.Date.new_dmy(o.day, o.month, o.year)
|
| |
+ else:
|
| |
+ d = None
|
| |
+ self.module.set_eol(d)
|
| |
+
|
| |
+ @property
|
| |
+ def servicelevels(self):
|
| |
+ """A dictionary of service levels applying to this module"""
|
| |
+ return self.module.get_servicelevels()
|
| |
+
|
| |
+ @servicelevels.setter
|
| |
+ def servicelevels(self, d):
|
| |
+ if not isinstance(d, dict):
|
| |
+ raise TypeError("servicelevels: data type not supported")
|
| |
+
|
| |
+ self.module.set_servicelevels(d)
|
| |
|
| |
@property
|
| |
def module_licenses(self):
|
| |
"""A set of strings, a property, representing the license terms
|
| |
of the module itself."""
|
| |
- return self._module_licenses
|
| |
+ return set(sorted(self.module.get_module_licenses().get()))
|
| |
|
| |
@module_licenses.setter
|
| |
def module_licenses(self, ss):
|
| |
@@ -626,7 +372,10 @@
|
| |
for s in ss:
|
| |
if not isinstance(s, str):
|
| |
raise TypeError("module_licenses: data type not supported")
|
| |
- self._module_licenses = ss
|
| |
+
|
| |
+ simpleset = Modulemd.SimpleSet()
|
| |
+ simpleset.set(list(ss))
|
| |
+ self.module.set_module_licenses(simpleset)
|
| |
|
| |
def add_module_license(self, s):
|
| |
"""Adds a module license to the set.
|
| |
@@ -635,7 +384,9 @@
|
| |
"""
|
| |
if not isinstance(s, str):
|
| |
raise TypeError("add_module_license: data type not supported")
|
| |
- self._module_licenses.add(s)
|
| |
+ simpleset = self.module.get_module_licenses()
|
| |
+ simpleset.add(s)
|
| |
+ self.module.set_module_licenses(simpleset)
|
| |
|
| |
def del_module_license(self, s):
|
| |
"""Removes the supplied license from the module licenses set.
|
| |
@@ -644,17 +395,19 @@
|
| |
"""
|
| |
if not isinstance(s, str):
|
| |
raise TypeError("del_module_license: data type not supported")
|
| |
- self._module_licenses.discard(s)
|
| |
+ licenses = self.module.get_module_licenses()
|
| |
+ licenses.remove(s)
|
| |
+ self.module.set_module_licenses(licenses)
|
| |
|
| |
def clear_module_licenses(self):
|
| |
"""Clears the module licenses set."""
|
| |
- self._module_licenses.clear()
|
| |
+ self.module.set_module_licenses(Modulemd.SimpleSet())
|
| |
|
| |
@property
|
| |
def content_licenses(self):
|
| |
"""A set of strings, a property, representing the license terms
|
| |
of the module contents."""
|
| |
- return self._content_licenses
|
| |
+ return set(sorted(self.module.get_content_licenses().get()))
|
| |
|
| |
@content_licenses.setter
|
| |
def content_licenses(self, ss):
|
| |
@@ -663,7 +416,9 @@
|
| |
for s in ss:
|
| |
if not isinstance(s, str):
|
| |
raise TypeError("content_licenses: data type not supported")
|
| |
- self._content_licenses = ss
|
| |
+ simpleset = Modulemd.SimpleSet()
|
| |
+ simpleset.set(list(ss))
|
| |
+ self.module.set_content_licenses(simpleset)
|
| |
|
| |
def add_content_license(self, s):
|
| |
"""Adds a content license to the set.
|
| |
@@ -672,7 +427,9 @@
|
| |
"""
|
| |
if not isinstance(s, str):
|
| |
raise TypeError("add_content_license: data type not supported")
|
| |
- self._content_licenses.add(s)
|
| |
+ simpleset = self.module.get_content_licenses()
|
| |
+ simpleset.add(s)
|
| |
+ self.module.set_content_licenses(simpleset)
|
| |
|
| |
def del_content_license(self, s):
|
| |
"""Removes the supplied license from the content licenses set.
|
| |
@@ -681,11 +438,13 @@
|
| |
"""
|
| |
if not isinstance(s, str):
|
| |
raise TypeError("del_content_license: data type not supported")
|
| |
- self._content_licenses.discard(s)
|
| |
+ licenses = self.module.get_content_licenses()
|
| |
+ licenses.remove(s)
|
| |
+ self.module.set_content_licenses(licenses)
|
| |
|
| |
def clear_content_licenses(self):
|
| |
"""Clears the content licenses set."""
|
| |
- self._content_licenses.clear()
|
| |
+ self.module.set_content_licenses(Modulemd.SimpleSet())
|
| |
|
| |
@property
|
| |
def requires(self):
|
| |
@@ -695,7 +454,7 @@
|
| |
Keys are the required module names (strings), values are their
|
| |
required stream names (also strings).
|
| |
"""
|
| |
- return self._requires
|
| |
+ return self.module.get_requires()
|
| |
|
| |
@requires.setter
|
| |
def requires(self, d):
|
| |
@@ -704,7 +463,7 @@
|
| |
for k, v in d.items():
|
| |
if not isinstance(k, str) or not isinstance(v, str):
|
| |
raise TypeError("requires: data type not supported")
|
| |
- self._requires = d
|
| |
+ self.module.set_requires(d)
|
| |
|
| |
def add_requires(self, n, v):
|
| |
"""Adds a required module dependency.
|
| |
@@ -714,7 +473,9 @@
|
| |
"""
|
| |
if not isinstance(n, str) or not isinstance(v, str):
|
| |
raise TypeError("add_requires: data type not supported")
|
| |
- self._requires[n] = v
|
| |
+ d = self.module.get_requires()
|
| |
+ d[n] = v
|
| |
+ self.module.set_requires(d)
|
| |
|
| |
update_requires = add_requires
|
| |
|
| |
@@ -725,12 +486,16 @@
|
| |
"""
|
| |
if not isinstance(n, str):
|
| |
raise TypeError("del_requires: data type not supported")
|
| |
- if n in self._requires:
|
| |
- del self._requires[n]
|
| |
+
|
| |
+ d = self.module.get_requires()
|
| |
+
|
| |
+ if n in d:
|
| |
+ del d[n]
|
| |
+ self.module.set_requires(d)
|
| |
|
| |
def clear_requires(self):
|
| |
"""Removes all required runtime dependencies."""
|
| |
- self._requires.clear()
|
| |
+ self.module.set_requires(dict())
|
| |
|
| |
@property
|
| |
def buildrequires(self):
|
| |
@@ -740,7 +505,7 @@
|
| |
Keys are the required module names (strings), values are their
|
| |
required stream names (also strings).
|
| |
"""
|
| |
- return self._buildrequires
|
| |
+ return self.module.get_buildrequires()
|
| |
|
| |
@buildrequires.setter
|
| |
def buildrequires(self, d):
|
| |
@@ -749,7 +514,7 @@
|
| |
for k, v in d.items():
|
| |
if not isinstance(k, str) or not isinstance(v, str):
|
| |
raise TypeError("buildrequires: data type not supported")
|
| |
- self._buildrequires = d
|
| |
+ self.module.set_buildrequires(d)
|
| |
|
| |
def add_buildrequires(self, n, v):
|
| |
"""Adds a module build dependency.
|
| |
@@ -759,7 +524,10 @@
|
| |
"""
|
| |
if not isinstance(n, str) or not isinstance(v, str):
|
| |
raise TypeError("add_buildrequires: data type not supported")
|
| |
- self._buildrequires[n] = v
|
| |
+
|
| |
+ d = self.module.get_buildrequires()
|
| |
+ d[n] = v
|
| |
+ self.module.set_buildrequires(d)
|
| |
|
| |
update_buildrequires = add_buildrequires
|
| |
|
| |
@@ -770,70 +538,130 @@
|
| |
"""
|
| |
if not isinstance(n, str):
|
| |
raise TypeError("del_buildrequires: data type not supported")
|
| |
- if n in self._buildrequires:
|
| |
- del self._buildrequires[n]
|
| |
+
|
| |
+ d = self.module.get_buildrequires()
|
| |
+
|
| |
+ if n in d:
|
| |
+ del d[n]
|
| |
+ self.module.set_buildrequires(d)
|
| |
|
| |
def clear_buildrequires(self):
|
| |
"""Removes all build dependencies."""
|
| |
- self._buildrequires.clear()
|
| |
+ self.module.set_buildrequires(dict())
|
| |
|
| |
@property
|
| |
def community(self):
|
| |
"""A string property representing a link to the upstream community
|
| |
for this module.
|
| |
"""
|
| |
- return self._community
|
| |
+ return self.module.get_community()
|
| |
|
| |
@community.setter
|
| |
def community(self, s):
|
| |
# TODO: Check if it looks like a link, unless empty
|
| |
if not isinstance(s, str):
|
| |
raise TypeError("community: data type not supported")
|
| |
- self._community = s
|
| |
+ self.module.set_community(s)
|
| |
|
| |
@property
|
| |
def documentation(self):
|
| |
"""A string property representing a link to the upstream
|
| |
documentation for this module.
|
| |
"""
|
| |
- return self._documentation
|
| |
+ return self.module.get_documentation()
|
| |
|
| |
@documentation.setter
|
| |
def documentation(self, s):
|
| |
# TODO: Check if it looks like a link, unless empty
|
| |
if not isinstance(s, str):
|
| |
raise TypeError("documentation: data type not supported")
|
| |
- self._documentation = s
|
| |
+ self.module.set_documentation(s)
|
| |
|
| |
@property
|
| |
def tracker(self):
|
| |
"""A string property representing a link to the upstream bug tracker
|
| |
for this module.
|
| |
"""
|
| |
- return self._tracker
|
| |
+ return self.module.get_tracker()
|
| |
|
| |
@tracker.setter
|
| |
def tracker(self, s):
|
| |
# TODO: Check if it looks like a link, unless empty
|
| |
if not isinstance(s, str):
|
| |
raise TypeError("tracker: data type not supported")
|
| |
- self._tracker = s
|
| |
+ self.module.set_tracker(s)
|
| |
|
| |
@property
|
| |
def xmd(self):
|
| |
"""A dictionary property containing user-defined data."""
|
| |
- return self._xmd
|
| |
+ d = dict()
|
| |
+ for key, value in self.module.get_xmd().items():
|
| |
+ d[key] = value.unpack()
|
| |
+ return d
|
| |
+
|
| |
+ @staticmethod
|
| |
+ def _variant_str(s):
|
| |
+ if not isinstance(s, str):
|
| |
+ raise TypeError ("Only strings are supported for scalars")
|
| |
+
|
| |
+ return GLib.Variant('s', s)
|
| |
+
|
| |
+ @classmethod
|
| |
+ def _variant_list(cls, l):
|
| |
+ l_variant = list()
|
| |
+ for item in l:
|
| |
+ if type(item) == str:
|
| |
+ l_variant.append(ModuleMetadata._variant_str(item))
|
| |
+ elif type(item) == list:
|
| |
+ l_variant.append(ModuleMetadata._variant_list(item))
|
| |
+ elif type(item) == dict:
|
| |
+ l_variant.append(ModuleMetadata._variant_dict(item))
|
| |
+ else:
|
| |
+ raise TypeError("Cannot convert unknown type")
|
| |
+ return GLib.Variant('av', l_variant)
|
| |
+
|
| |
+ @classmethod
|
| |
+ def _variant_dict_values(cls, d):
|
| |
+ if not isinstance(d, dict):
|
| |
+ raise TypeError("Only dictionaries are supported for mappings")
|
| |
+
|
| |
+ d_variant = dict()
|
| |
+ for k, v in d.items():
|
| |
+ if type(v) == str:
|
| |
+ d_variant[k] = cls._variant_str(v)
|
| |
+ pass
|
| |
+ elif type(v) == list:
|
| |
+ d_variant[k] = cls._variant_list(v)
|
| |
+ elif type(v) == dict:
|
| |
+ d_variant[k] = cls._variant_dict(v)
|
| |
+ else:
|
| |
+ raise TypeError("Cannot convert unknown type")
|
| |
+ return d_variant
|
| |
+
|
| |
+ @classmethod
|
| |
+ def _variant_dict(cls, d):
|
| |
+ if not isinstance(d, dict):
|
| |
+ raise TypeError("Only dictionaries are supported for mappings")
|
| |
+
|
| |
+ d_variant = cls._variant_dict_values(d)
|
| |
+
|
| |
+ return GLib.Variant('a{sv}', d_variant)
|
| |
|
| |
@xmd.setter
|
| |
def xmd(self, d):
|
| |
if not isinstance(d, dict):
|
| |
raise TypeError("xmd: data type not supported")
|
| |
- self._xmd = d
|
| |
+
|
| |
+ xmd = self._variant_dict_values(d)
|
| |
+
|
| |
+ self.module.set_xmd(xmd)
|
| |
|
| |
@property
|
| |
def profiles(self):
|
| |
"""A dictionary property representing the module profiles."""
|
| |
- return self._profiles
|
| |
+ return {k: ModuleProfile._new_from_native(native_profile=v,
|
| |
+ bound=True, parent=self)
|
| |
+ for k, v in self.module.get_profiles().items()}
|
| |
|
| |
@profiles.setter
|
| |
def profiles(self, d):
|
| |
@@ -842,63 +670,83 @@
|
| |
for k, v in d.items():
|
| |
if not isinstance(k, str) or not isinstance(v, ModuleProfile):
|
| |
raise TypeError("profiles: data type not supported")
|
| |
- self._profiles = d
|
| |
+
|
| |
+ # ensure keys and names in profiles agree
|
| |
+ for k, v in d.items():
|
| |
+ v.name = k
|
| |
+
|
| |
+ self.module.set_profiles({k: v._to_native() for k, v in d.items()})
|
| |
+
|
| |
+ @property
|
| |
+ def tree_objs(self):
|
| |
+ if not hasattr(self, '_tree_objs'):
|
| |
+ self._tree_objs = {
|
| |
+ 'api': ModuleAPI(parent=self),
|
| |
+ 'filter': ModuleFilter(parent=self),
|
| |
+ 'buildopts': ModuleBuildopts(parent=self),
|
| |
+ 'components': ModuleComponents(parent=self),
|
| |
+ 'artifacts': ModuleArtifacts(parent=self),
|
| |
+ }
|
| |
+ return self._tree_objs
|
| |
|
| |
@property
|
| |
def api(self):
|
| |
"""A ModuleAPI instance representing the module's public API."""
|
| |
- return self._api
|
| |
+ return self.tree_objs['api']
|
| |
|
| |
@api.setter
|
| |
def api(self, o):
|
| |
if not isinstance(o, ModuleAPI):
|
| |
raise TypeError("api: data type not supported")
|
| |
- self._api = o
|
| |
+
|
| |
+ self.tree_objs['api'].replace(o)
|
| |
|
| |
@property
|
| |
def filter(self):
|
| |
"""A ModuleFilter instance representing the module's filter."""
|
| |
- return self._filter
|
| |
+ return self.tree_objs['filter']
|
| |
|
| |
@filter.setter
|
| |
def filter(self, o):
|
| |
if not isinstance(o, ModuleFilter):
|
| |
raise TypeError("filter: data type not supported")
|
| |
- self._filter = o
|
| |
+
|
| |
+ self.tree_objs['filter'].replace(o)
|
| |
|
| |
@property
|
| |
def buildopts(self):
|
| |
"""A ModuleBuildopts instance representing the additional
|
| |
module components build options.
|
| |
"""
|
| |
- return self._buildopts
|
| |
+ return self.tree_objs['buildopts']
|
| |
|
| |
@buildopts.setter
|
| |
def buildopts(self, o):
|
| |
if not isinstance(o, ModuleBuildopts):
|
| |
raise TypeError("buildopts: data type not supported")
|
| |
- self._buildopts = o
|
| |
+
|
| |
+ self.tree_objs['buildopts'].replace(o)
|
| |
|
| |
@property
|
| |
def components(self):
|
| |
"""A ModuleComponents instance property representing the components
|
| |
defining the module.
|
| |
"""
|
| |
- return self._components
|
| |
+ return self.tree_objs['components']
|
| |
|
| |
@components.setter
|
| |
def components(self, o):
|
| |
if not isinstance(o, ModuleComponents):
|
| |
raise TypeError("components: data type not supported")
|
| |
- self._components = o
|
| |
+ self.tree_objs['components'].replace(o)
|
| |
|
| |
@property
|
| |
def artifacts(self):
|
| |
"""A ModuleArtifacts instance representing the module's artifacts."""
|
| |
- return self._artifacts
|
| |
+ return self.tree_objs['artifacts']
|
| |
|
| |
@artifacts.setter
|
| |
def artifacts(self, o):
|
| |
if not isinstance(o, ModuleArtifacts):
|
| |
raise TypeError("artifacts: data type not supported")
|
| |
- self._artifacts = o
|
| |
+ self.tree_objs['artifacts'].replace(o)
|
| |
Additionally: