about summary refs log tree commit diff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rwxr-xr-xtools/generate-docs-nm-property-infos.py133
-rwxr-xr-xtools/generate-docs-nm-settings-docs-gir.py41
-rwxr-xr-xtools/generate-docs-nm-settings-docs-merge.py4
-rwxr-xr-xtools/run-nm-test.sh8
-rwxr-xr-xtools/test-cloud-meta-mock.py2
-rwxr-xr-xtools/test-networkmanager-service.py17
6 files changed, 158 insertions, 47 deletions
diff --git a/tools/generate-docs-nm-property-infos.py b/tools/generate-docs-nm-property-infos.py
index d7e3c8c2..74dc9d1c 100755
--- a/tools/generate-docs-nm-property-infos.py
+++ b/tools/generate-docs-nm-property-infos.py
@@ -14,6 +14,9 @@ class LineError(Exception):
         self.line_no = line_no
 
 
+enums = {}
+enumvals = {}
+
 _dbg_level = 0
 try:
     _dbg_level = int(os.getenv("NM_DEBUG_GENERATE_DOCS", 0))
@@ -52,6 +55,45 @@ def xnode_get_or_create(root_node, node_name, name):
     return node, created
 
 
+def init_enumvals(girxml):
+    ns_map = {
+        "c": "http://www.gtk.org/introspection/c/1.0",
+        "gi": "http://www.gtk.org/introspection/core/1.0",
+        "glib": "http://www.gtk.org/introspection/glib/1.0",
+    }
+    type_key = "{%s}type" % ns_map["c"]
+    identifier_key = "{%s}identifier" % ns_map["c"]
+    nick_key = "{%s}nick" % ns_map["glib"]
+
+    for enum in girxml.findall("./gi:namespace/gi:enumeration", ns_map):
+        enum_cname = enum.attrib[type_key]
+        enums[enum_cname] = []
+        for enumval in enum.findall("./gi:member", ns_map):
+            cname = enumval.attrib[identifier_key]
+            doc = enumval.find("./gi:doc", ns_map)
+
+            enums[enum_cname].append(cname)
+            enumvals[cname] = {
+                "value": enumval.attrib["value"],
+                "nick": enumval.attrib.get(nick_key, cname),
+                "doc": doc.text if doc is not None else None,
+            }
+
+    for enum in girxml.findall("./gi:namespace/gi:bitfield", ns_map):
+        enum_cname = enum.attrib[type_key]
+        enums[enum_cname] = []
+        for enumval in enum.findall("./gi:member", ns_map):
+            cname = enumval.attrib[identifier_key]
+            doc = enumval.find("./gi:doc", ns_map)
+
+            enums[enum_cname].append(cname)
+            enumvals[cname] = {
+                "value": "0x%x" % int(enumval.attrib["value"]),
+                "nick": enumval.attrib.get(nick_key, cname),
+                "doc": doc.text if doc is not None else None,
+            }
+
+
 def get_setting_names(source_file):
     m = re.match(r"^(.*)/libnm-core-impl/(nm-setting-[^/]*)\.c$", source_file)
     assert m
@@ -125,6 +167,7 @@ keywords = collections.OrderedDict(
         ("variable", KEYWORD_XML_TYPE_ATTR),
         ("format", KEYWORD_XML_TYPE_ATTR),
         ("values", KEYWORD_XML_TYPE_ATTR),
+        ("special-values", KEYWORD_XML_TYPE_ATTR),
         ("default", KEYWORD_XML_TYPE_ATTR),
         ("example", KEYWORD_XML_TYPE_ATTR),
         ("description", KEYWORD_XML_TYPE_ELEM),
@@ -141,7 +184,6 @@ def keywords_allowed(tag, keyword):
 
 
 def write_data(tag, setting_node, line_no, parsed_data):
-
     for k in parsed_data.keys():
         assert keywords_allowed(tag, k)
         assert k in keywords
@@ -171,15 +213,50 @@ def write_data(tag, setting_node, line_no, parsed_data):
         else:
             assert False
 
+
+def expand_enumval(enumval_name, nick_first):
+    if enumval_name not in enumvals:
+        return enumval_name
+
+    enumval = enumvals[enumval_name]
+    if nick_first:
+        return "%s (%s)" % (enumval["nick"], enumval["value"])
+    else:
+        return "%s (%s)" % (enumval["value"], enumval["nick"])
+
+
+def expand_all_enumvals(enum, nick_first):
+    assert enum in enums, "Enum name not found: %s" % enum
+    return ", ".join(expand_enumval(val_name, nick_first) for val_name in enums[enum])
+
+
+def expand_all_enumvals_with_docs(enum, nick_first):
+    assert enum in enums, "Enum name not found: %s" % enum
+
+    out_str = "<itemizedlist>"
+    for enumval_name in enums[enum]:
+        assert enumval_name in enumvals
+        enumval = enumvals[enumval_name]
+        out_str += "<listitem><para><literal>%s</literal>%s</para></listitem>" % (
+            expand_enumval(enumval_name, nick_first),
+            " - " + enumval["doc"] if enumval["doc"] else "",
+        )
+    out_str += "</itemizedlist>"
+
+    return out_str
+
+
+def format_descriptions(tag, parsed_data):
     if (
         parsed_data.get("description", None) is not None
         and parsed_data.get("description-docbook", None) is None
     ):
         # we have a description, but no docbook. Generate one.
-        node = ET.SubElement(property_node, "description-docbook")
-        for l in re.split("\n", parsed_data["description"]):
-            paragraph = ET.SubElement(node, "para")
-            paragraph.text = l
+        parsed_data["description-docbook"] = ""
+        for line in parsed_data["description"].split("\n"):
+            para = ET.Element("para")
+            para.text = line
+            parsed_data["description-docbook"] += ET.tostring(para, encoding="unicode")
     elif (
         parsed_data.get("description-docbook", None) is not None
         and parsed_data.get("description", None) is None
@@ -187,10 +264,35 @@ def write_data(tag, setting_node, line_no, parsed_data):
         raise Exception(
             'Invalid configuration. When specifying "description-docbook:" there MUST be also a  "description:"'
         )
+    elif parsed_data.get("description", None) is None:
+        return
+
+    # Expand enumvals expressions (%ENUM_VALUE and #EnumName:*)
+    nick_first = tag == "nmcli"
+
+    parsed_data["description"] = re.sub(
+        r"#([A-Za-z0-9_]*):\*",
+        lambda match: expand_all_enumvals(match.group(1), nick_first),
+        parsed_data["description"],
+    )
+
+    parsed_data["description"] = re.sub(
+        r"%([^%]\w*)",
+        lambda match: expand_enumval(match.group(1), nick_first),
+        parsed_data["description"],
+    )
 
+    parsed_data["description-docbook"] = re.sub(
+        r"#([A-Za-z0-9_]*):\*",
+        lambda match: expand_all_enumvals_with_docs(match.group(1), nick_first),
+        parsed_data["description-docbook"],
+    )
 
-kwd_first_line_re = re.compile(r"^ *\* ([-a-z0-9]+): (.*)$")
-kwd_more_line_re = re.compile(r"^ *\*( *)(.*?)\s*$")
+    parsed_data["description-docbook"] = re.sub(
+        r"%([^%]\w*)",
+        lambda match: expand_enumval(match.group(1), nick_first),
+        parsed_data["description-docbook"],
+    )
 
 
 def parse_data(tag, line_no, lines):
@@ -272,7 +374,6 @@ def parse_data(tag, line_no, lines):
 
 
 def process_setting(tag, root_node, source_file, setting_name):
-
     dbg(
         "> > tag:%s, source_file:%s, setting_name:%s" % (tag, source_file, setting_name)
     )
@@ -325,6 +426,7 @@ def process_setting(tag, root_node, source_file, setting_name):
                 parsed_data = parse_data(tag, line_no_start, lines)
                 if not parsed_data:
                     raise Exception('invalid data: line %s, "%s"' % (line_no, lines))
+                format_descriptions(tag, parsed_data)
                 dbg("> > > property: %s" % (parsed_data["property"],))
                 if _dbg_level > 1:
                     for keyword in sorted(parsed_data.keys()):
@@ -343,12 +445,13 @@ def process_setting(tag, root_node, source_file, setting_name):
             raise LineError(line_no_start, "Unterminated start tag")
 
 
-def process_settings_docs(tag, output, source_files):
-
+def process_settings_docs(tag, output, gir_file, source_files):
     dbg("> tag:%s, output:%s" % (tag, output))
 
     root_node = ET.Element("nm-setting-docs")
 
+    init_enumvals(ET.parse(gir_file).getroot())
+
     for setting_name, source_file in get_file_infos(source_files):
         try:
             process_setting(tag, root_node, source_file, setting_name)
@@ -368,11 +471,16 @@ def process_settings_docs(tag, output, source_files):
 
 def main():
     if len(sys.argv) < 4:
-        print("Usage: %s [tag] [output-xml-file] [srcfiles...]" % (sys.argv[0]))
+        print(
+            "Usage: %s [tag] [output-xml-file] [gir-file] [srcfiles...]" % (sys.argv[0])
+        )
         exit(1)
 
     process_settings_docs(
-        tag=sys.argv[1], output=sys.argv[2], source_files=sys.argv[3:]
+        tag=sys.argv[1],
+        output=sys.argv[2],
+        gir_file=sys.argv[3],
+        source_files=sys.argv[4:],
     )
 
 
@@ -420,7 +528,6 @@ def test_get_setting_names():
 
 
 def test_get_file_infos():
-
     t = ["connection", "ip-config", "ip4-config", "proxy", "wired"]
 
     assert [
diff --git a/tools/generate-docs-nm-settings-docs-gir.py b/tools/generate-docs-nm-settings-docs-gir.py
index b8f29d3b..e438d87a 100755
--- a/tools/generate-docs-nm-settings-docs-gir.py
+++ b/tools/generate-docs-nm-settings-docs-gir.py
@@ -57,6 +57,7 @@ ns_map = {
 identifier_key = "{%s}identifier" % ns_map["c"]
 nick_key = "{%s}nick" % ns_map["glib"]
 symbol_prefix_key = "{%s}symbol-prefix" % ns_map["c"]
+nick_key = "{%s}nick" % ns_map["glib"]
 
 constants = {
     "TRUE": "TRUE",
@@ -74,25 +75,37 @@ def get_setting_name_define(setting):
     raise Exception('Unexpected symbol_prefix_key "%s"' % (n))
 
 
-def init_constants(girxml, settings):
+def init_constants(girxml, settings, output_target):
     for const in girxml.findall("./gi:namespace/gi:constant", ns_map):
         cname = const.attrib["{%s}type" % ns_map["c"]]
-        cvalue = const.attrib["value"]
+        value = const.attrib["value"]
         if const.find('./gi:type[@name="utf8"]', ns_map) is not None:
-            cvalue = '"%s"' % cvalue
-        constants[cname] = cvalue
+            value = '"%s"' % value
+        constants[cname] = value
 
     for enum in girxml.findall("./gi:namespace/gi:enumeration", ns_map):
         for enumval in enum.findall("./gi:member", ns_map):
             cname = enumval.attrib[identifier_key]
-            cvalue = "%s (%s)" % (cname, enumval.attrib["value"])
-            constants[cname] = cvalue
+            nick = enumval.attrib.get(nick_key, cname)
+            if output_target == "nmcli":
+                value = '"%s" (%s)' % (nick, enumval.attrib["value"])
+            elif output_target is not None:
+                value = "%s (%s)" % (enumval.attrib["value"], nick)
+            else:
+                value = "%s (%s)" % (cname, enumval.attrib["value"])
+            constants[cname] = value
 
     for enum in girxml.findall("./gi:namespace/gi:bitfield", ns_map):
         for enumval in enum.findall("./gi:member", ns_map):
             cname = enumval.attrib[identifier_key]
-            cvalue = "%s (0x%x)" % (cname, int(enumval.attrib["value"]))
-            constants[cname] = cvalue
+            nick = enumval.attrib.get(nick_key, cname)
+            if output_target == "nmcli":
+                value = '"%s" (0x%x)' % (nick, int(enumval.attrib["value"]))
+            elif output_target is not None:
+                value = "0x%x (%s)" % (int(enumval.attrib["value"]), nick)
+            else:
+                value = "%s (0x%x)" % (cname, int(enumval.attrib["value"]))
+            constants[cname] = value
 
     for setting in settings:
         setting_type_name = "NM" + setting.attrib["name"]
@@ -217,7 +230,7 @@ def create_desc_docbook(desc_docbook, description):
         paragraph.text = l
 
 
-def main(gir_path_str, output_path_str):
+def main(gir_path_str, output_path_str, output_target):
     girxml = ET.parse(gir_path_str).getroot()
 
     basexml = girxml.find('./gi:namespace/gi:class[@name="Setting"]', ns_map)
@@ -229,7 +242,7 @@ def main(gir_path_str, output_path_str):
     )
     settings = sorted(settings, key=settings_sort_key)
 
-    init_constants(girxml, settings)
+    init_constants(girxml, settings, output_target)
 
     nm_settings_docs_element = ET.Element("nm-setting-docs")
     docs_gir = ET.ElementTree(nm_settings_docs_element)
@@ -362,6 +375,12 @@ if __name__ == "__main__":
         help="output file",
         required=True,
     )
+    parser.add_argument(
+        "-t",
+        "--target",
+        choices=["nmcli", "dbus", "keyfile", "ifcfg-rh"],
+        help="target where the output will be used (i.e. nmcli)",
+    )
 
     args = parser.parse_args()
 
@@ -369,4 +388,4 @@ if __name__ == "__main__":
         for lib in args.lib_path:
             GIRepository.Repository.prepend_library_path(lib)
 
-    main(args.gir, args.output)
+    main(args.gir, args.output, args.target)
diff --git a/tools/generate-docs-nm-settings-docs-merge.py b/tools/generate-docs-nm-settings-docs-merge.py
index a927400f..3ad8755d 100755
--- a/tools/generate-docs-nm-settings-docs-merge.py
+++ b/tools/generate-docs-nm-settings-docs-merge.py
@@ -250,7 +250,6 @@ settings_roots = [node_to_dict(root, "setting", "name") for root in xml_roots]
 root_node = ET.Element("nm-setting-docs")
 
 for setting_name in iter_keys_of_dicts(settings_roots, key_fcn_setting_name):
-
     dbg("> > setting_name: %s" % (setting_name))
 
     if skip_property(setting_name, None):
@@ -272,7 +271,6 @@ for setting_name in iter_keys_of_dicts(settings_roots, key_fcn_setting_name):
     dbg("> > > create node")
 
     for property_name in iter_keys_of_dicts(properties):
-
         dbg("> > > > property_name: %s" % (property_name))
 
         properties_attrs = [p.get(property_name) for p in properties]
@@ -296,6 +294,8 @@ for setting_name in iter_keys_of_dicts(settings_roots, key_fcn_setting_name):
         else:
             node_set_attr(property_node, "type", properties_attrs)
 
+        node_set_attr(property_node, "values", properties_attrs)
+        node_set_attr(property_node, "special-values", properties_attrs)
         node_set_attr(property_node, "default", properties_attrs)
         node_set_attr(property_node, "alias", properties_attrs)
 
diff --git a/tools/run-nm-test.sh b/tools/run-nm-test.sh
index c88a1bd5..264fc48d 100755
--- a/tools/run-nm-test.sh
+++ b/tools/run-nm-test.sh
@@ -135,12 +135,12 @@ else
         NMTST_USE_VALGRIND=0
     fi
 
-    if [ -z "${NMTST_LIBTOOL+x}" ]; then
+    if [ -n "$NMTST_LIBTOOL" ] ; then
+        NMTST_LIBTOOL=("$NMTST_LIBTOOL" "--mode=execute")
+    elif [ -z "${NMTST_LIBTOOL+x}" -a -f "$SCRIPT_PATH/../libtool" ]; then
         NMTST_LIBTOOL=(sh "$SCRIPT_PATH/../libtool" "--mode=execute")
-    elif [ -z "$NMTST_LIBTOOL" ]; then
-        NMTST_LIBTOOL=()
     else
-        NMTST_LIBTOOL=("$NMTST_LIBTOOL" "--mode=execute")
+        NMTST_LIBTOOL=()
     fi
     TEST_ARGV=()
     unset TEST
diff --git a/tools/test-cloud-meta-mock.py b/tools/test-cloud-meta-mock.py
index bc0a829e..a396e0da 100755
--- a/tools/test-cloud-meta-mock.py
+++ b/tools/test-cloud-meta-mock.py
@@ -169,7 +169,6 @@ class SocketHTTPServer(HTTPServer):
 
 
 def create_default_resources_for_provider(provider):
-
     mac1 = b"cc:00:00:00:00:01"
     mac2 = b"cc:00:00:00:00:02"
 
@@ -244,7 +243,6 @@ def create_default_resources_for_provider(provider):
 
 
 def create_default_resources():
-
     return {p: create_default_resources_for_provider(p) for p in PROVIDERS}
 
 
diff --git a/tools/test-networkmanager-service.py b/tools/test-networkmanager-service.py
index 9a423123..f274a460 100755
--- a/tools/test-networkmanager-service.py
+++ b/tools/test-networkmanager-service.py
@@ -50,7 +50,6 @@ class TestError(AssertionError):
 
 
 class Util:
-
     PY3 = sys.version_info[0] == 3
 
     @staticmethod
@@ -509,7 +508,6 @@ class BusErr:
 class NmUtil:
     @staticmethod
     def con_hash_to_connection(con_hash, do_verify=False, do_normalize=False):
-
         x_con = []
         for v_setting_name, v_setting in list(con_hash.items()):
             if isinstance(v_setting_name, (dbus.String, str)):
@@ -628,7 +626,6 @@ class NmUtil:
 
 
 class ExportedObj(dbus.service.Object):
-
     DBusInterface = collections.namedtuple("DBusInterface", ["dbus_iface", "props"])
 
     @staticmethod
@@ -820,12 +817,10 @@ PRP_DEVICE_INTERFACE_FLAGS = "InterfaceFlags"
 
 
 class Device(ExportedObj):
-
     path_counter_next = 1
     path_prefix = "/org/freedesktop/NetworkManager/Devices/"
 
     def __init__(self, iface, devtype, ident=None):
-
         if ident is None:
             ident = iface
 
@@ -1210,10 +1205,10 @@ PRP_WIFI_AP_MODE = "Mode"
 PRP_WIFI_AP_MAX_BITRATE = "MaxBitrate"
 PRP_WIFI_AP_STRENGTH = "Strength"
 PRP_WIFI_AP_LAST_SEEN = "LastSeen"
+PRP_WIFI_AP_BANDWIDTH = "Bandwidth"
 
 
 class WifiAp(ExportedObj):
-
     path_counter_next = 1
     path_prefix = "/org/freedesktop/NetworkManager/AccessPoint/"
 
@@ -1228,7 +1223,6 @@ class WifiAp(ExportedObj):
         strength=None,
         ident=None,
     ):
-
         ExportedObj.__init__(self, ExportedObj.create_path(WifiAp), ident)
 
         NM_AP_FLAGS = getattr(NM, "80211ApSecurityFlags")
@@ -1268,6 +1262,7 @@ class WifiAp(ExportedObj):
             PRP_WIFI_AP_MAX_BITRATE: dbus.UInt32(54000),
             PRP_WIFI_AP_STRENGTH: dbus.Byte(strength),
             PRP_WIFI_AP_LAST_SEEN: dbus.Int32(NM.utils_get_timestamp_msec() / 1000),
+            PRP_WIFI_AP_BANDWIDTH: dbus.UInt32(40),
         }
 
         self.dbus_interface_add(IFACE_WIFI_AP, props)
@@ -1402,12 +1397,10 @@ PRP_VPN_CONNECTION_BANNER = "Banner"
 
 
 class ActiveConnection(ExportedObj):
-
     path_counter_next = 1
     path_prefix = "/org/freedesktop/NetworkManager/ActiveConnection/"
 
     def __init__(self, device, con_inst, specific_object):
-
         ExportedObj.__init__(self, ExportedObj.create_path(ActiveConnection))
 
         self.device = device
@@ -2034,7 +2027,6 @@ PRP_CONNECTION_FILENAME = "Filename"
 
 class Connection(ExportedObj):
     def __init__(self, path_counter, con_hash, do_verify_strict=True):
-
         path = "/org/freedesktop/NetworkManager/Settings/Connection/%s" % (path_counter)
 
         ExportedObj.__init__(self, path)
@@ -2077,7 +2069,6 @@ class Connection(ExportedObj):
         return self.get_type() == NM.SETTING_VPN_SETTING_NAME
 
     def update_connection(self, con_hash, do_verify_strict):
-
         NmUtil.con_hash_verify(con_hash, do_verify_strict=do_verify_strict)
 
         old_uuid = self.get_uuid()
@@ -2301,7 +2292,6 @@ PRP_IP4_CONFIG_WINSSERVERS = "WinsServers"
 
 
 class IP4Config(ExportedObj):
-
     path_counter_next = 1
     path_prefix = "/org/freedesktop/NetworkManager/IP4Config/"
 
@@ -2500,7 +2490,6 @@ PRP_IP6_CONFIG_DNSPRIORITY = "DnsPriority"
 
 
 class IP6Config(ExportedObj):
-
     path_counter_next = 1
     path_prefix = "/org/freedesktop/NetworkManager/IP6Config/"
 
@@ -2674,7 +2663,6 @@ PRP_DHCP4_CONFIG_OPTIONS = "Options"
 
 
 class Dhcp4Config(ExportedObj):
-
     path_counter_next = 1
     path_prefix = "/org/freedesktop/NetworkManager/DHCP4Config/"
 
@@ -2715,7 +2703,6 @@ PRP_DHCP6_CONFIG_OPTIONS = "Options"
 
 
 class Dhcp6Config(ExportedObj):
-
     path_counter_next = 1
     path_prefix = "/org/freedesktop/NetworkManager/DHCP6Config/"