mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-11-02 21:09:05 +00:00
8af1404e54
From nm-settings-dbus(5): Before (ugly, offensive, possibly in violation of geneva protocol): ... | set, the authentication retries for 3 | times before failing the connection. | | Currently, this only applies to 802-1x | authentication. After (beautiful, smells good, in harmony with nature): ... | set, the authentication retries for 3 | times before failing the connection. | | Currently, this only applies to 802-1x | authentication.
375 lines
11 KiB
Python
Executable file
375 lines
11 KiB
Python
Executable file
#!/usr/bin/env python
|
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
|
#
|
|
# Copyright (C) 2009 - 2017 Red Hat, Inc.
|
|
#
|
|
from __future__ import print_function, unicode_literals
|
|
import xml.etree.ElementTree as ET
|
|
import argparse
|
|
import os
|
|
import gi
|
|
import re
|
|
|
|
gi.require_version("GIRepository", "2.0")
|
|
from gi.repository import GIRepository
|
|
|
|
try:
|
|
libs = os.environ["LD_LIBRARY_PATH"].split(":")
|
|
libs.reverse()
|
|
for lib in libs:
|
|
GIRepository.Repository.prepend_library_path(lib)
|
|
except AttributeError:
|
|
# An old GI version, that has no prepend_library_path
|
|
# It's alright, it probably interprets LD_LIBRARY_PATH
|
|
# correctly.
|
|
pass
|
|
except KeyError:
|
|
pass
|
|
|
|
gi.require_version("NM", "1.0")
|
|
from gi.repository import NM, GObject
|
|
|
|
dbus_type_name_map = {
|
|
"b": "boolean",
|
|
"s": "string",
|
|
"i": "int32",
|
|
"u": "uint32",
|
|
"t": "uint64",
|
|
"x": "int64",
|
|
"y": "byte",
|
|
"as": "array of string",
|
|
"au": "array of uint32",
|
|
"ay": "byte array",
|
|
"a{ss}": "dict of string to string",
|
|
"a{sv}": "vardict",
|
|
"aa{sv}": "array of vardict",
|
|
"aau": "array of array of uint32",
|
|
"aay": "array of byte array",
|
|
"a(ayuay)": "array of legacy IPv6 address struct",
|
|
"a(ayuayu)": "array of legacy IPv6 route struct",
|
|
}
|
|
|
|
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",
|
|
}
|
|
identifier_key = "{%s}identifier" % ns_map["c"]
|
|
nick_key = "{%s}nick" % ns_map["glib"]
|
|
symbol_prefix_key = "{%s}symbol-prefix" % ns_map["c"]
|
|
|
|
constants = {
|
|
"TRUE": "TRUE",
|
|
"FALSE": "FALSE",
|
|
"G_MAXUINT32": "G_MAXUINT32",
|
|
"NULL": "NULL",
|
|
}
|
|
setting_names = {}
|
|
|
|
|
|
def get_setting_name_define(setting):
|
|
n = setting.attrib[symbol_prefix_key]
|
|
if n and n.startswith("setting_"):
|
|
return n[8:].upper()
|
|
raise Exception('Unexpected symbol_prefix_key "%s"' % (n))
|
|
|
|
|
|
def init_constants(girxml, settings):
|
|
for const in girxml.findall("./gi:namespace/gi:constant", ns_map):
|
|
cname = const.attrib["{%s}type" % ns_map["c"]]
|
|
cvalue = const.attrib["value"]
|
|
if const.find('./gi:type[@name="utf8"]', ns_map) is not None:
|
|
cvalue = '"%s"' % cvalue
|
|
constants[cname] = cvalue
|
|
|
|
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
|
|
|
|
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
|
|
|
|
for setting in settings:
|
|
setting_type_name = "NM" + setting.attrib["name"]
|
|
setting_name_symbol = (
|
|
"NM_SETTING_" + get_setting_name_define(setting) + "_SETTING_NAME"
|
|
)
|
|
if setting_name_symbol in constants:
|
|
setting_name = constants[setting_name_symbol]
|
|
setting_names[setting_type_name] = setting_name
|
|
|
|
|
|
def get_prop_type(setting, pspec):
|
|
dbus_type = setting.get_dbus_property_type(pspec.name).dup_string()
|
|
prop_type = dbus_type_name_map[dbus_type]
|
|
|
|
if GObject.type_is_a(pspec.value_type, GObject.TYPE_ENUM) or GObject.type_is_a(
|
|
pspec.value_type, GObject.TYPE_FLAGS
|
|
):
|
|
prop_type = "%s (%s)" % (pspec.value_type.name, prop_type)
|
|
|
|
return prop_type
|
|
|
|
|
|
def remove_prefix(line, prefix):
|
|
return line[len(prefix) :] if line.startswith(prefix) else line
|
|
|
|
|
|
def format_docs(doc_xml):
|
|
doc = doc_xml.text
|
|
|
|
# split docs into lines
|
|
lines = re.split("\n", doc)
|
|
# strip leading *char and strip white spaces
|
|
lines = [remove_prefix(l, "*").strip() for l in lines]
|
|
doc = ""
|
|
for l in lines:
|
|
if l:
|
|
doc += l + " "
|
|
else:
|
|
doc = doc.strip(" ") + "\n\n"
|
|
|
|
doc = doc.strip("\n ")
|
|
|
|
# Expand constants
|
|
doc = re.sub(r"%([^%]\w*)", lambda match: constants[match.group(1)], doc)
|
|
|
|
# #NMSettingWired:mac-address -> "mac-address"
|
|
doc = re.sub(r"#[A-Za-z0-9_]*:([A-Za-z0-9_-]*)", r'"\1"', doc)
|
|
|
|
# #NMSettingWired setting -> "802-3-ethernet" setting
|
|
doc = re.sub(
|
|
r"#([A-Z]\w*) setting",
|
|
lambda match: setting_names[match.group(1)] + " setting",
|
|
doc,
|
|
)
|
|
|
|
# remaining gtk-doc cleanup
|
|
doc = doc.replace("%%", "%")
|
|
doc = doc.replace("<!-- -->", "")
|
|
doc = re.sub(r" Element-.ype:.*", "", doc)
|
|
doc = re.sub(r"#([A-Z]\w*)", r"\1", doc)
|
|
|
|
# Remove sentences that refer to functions
|
|
if "FindProxyForURL()" in doc:
|
|
# FIXME: this would break the description for "proxy.pac-script"
|
|
# Work around. But really the entire approach here is flawed
|
|
# and needs improvement.
|
|
pass
|
|
else:
|
|
doc = re.sub(r"\.\s+[^.]*\w\(\)[^.]*\.", r".", doc)
|
|
|
|
return doc
|
|
|
|
|
|
def get_docs(propxml):
|
|
doc_xml = propxml.find("gi:doc", ns_map)
|
|
if doc_xml is None:
|
|
return None
|
|
else:
|
|
return format_docs(doc_xml)
|
|
|
|
|
|
def get_default_value(setting, pspec, propxml):
|
|
default_value = setting.get_property(pspec.name.replace("-", "_"))
|
|
if default_value is None:
|
|
return default_value
|
|
|
|
value_type = get_prop_type(setting, pspec)
|
|
if value_type == "string" and default_value != "" and pspec.name != "name":
|
|
default_value = '"%s"' % default_value
|
|
elif value_type == "boolean":
|
|
default_value = str(default_value).upper()
|
|
elif value_type == "byte array":
|
|
default_value = "[]"
|
|
elif str(default_value).startswith("<"):
|
|
default_value = None
|
|
elif str(default_value).startswith("["):
|
|
default_value = None
|
|
|
|
return default_value
|
|
|
|
|
|
def settings_sort_key(x):
|
|
x_prefix = x.attrib["{%s}symbol-prefix" % ns_map["c"]]
|
|
# always sort NMSettingConnection first
|
|
return (x_prefix != "setting_connection", x_prefix)
|
|
|
|
|
|
def create_desc_docbook(desc_docbook, description):
|
|
lines = re.split("\n", description)
|
|
in_par = True
|
|
|
|
paragraph = ET.SubElement(
|
|
desc_docbook,
|
|
"para",
|
|
)
|
|
|
|
for l in lines:
|
|
if l and in_par:
|
|
paragraph.text = l
|
|
else:
|
|
paragraph = ET.SubElement(desc_docbook, "para")
|
|
|
|
|
|
def main(gir_path_str, output_path_str):
|
|
girxml = ET.parse(gir_path_str).getroot()
|
|
|
|
basexml = girxml.find('./gi:namespace/gi:class[@name="Setting"]', ns_map)
|
|
settings = girxml.findall('./gi:namespace/gi:class[@parent="Setting"]', ns_map)
|
|
# Hack. Need a better way to do this
|
|
ipxml = girxml.find('./gi:namespace/gi:class[@name="SettingIPConfig"]', ns_map)
|
|
settings.extend(
|
|
girxml.findall('./gi:namespace/gi:class[@parent="SettingIPConfig"]', ns_map)
|
|
)
|
|
settings = sorted(settings, key=settings_sort_key)
|
|
|
|
init_constants(girxml, settings)
|
|
|
|
nm_settings_docs_element = ET.Element("nm-setting-docs")
|
|
docs_gir = ET.ElementTree(nm_settings_docs_element)
|
|
|
|
for settingxml in settings:
|
|
if "abstract" in settingxml.attrib:
|
|
continue
|
|
|
|
new_func = NM.__getattr__(settingxml.attrib["name"])
|
|
setting = new_func()
|
|
|
|
class_desc = get_docs(settingxml)
|
|
if class_desc is None:
|
|
raise Exception(
|
|
"%s needs a gtk-doc block with one-line description"
|
|
% setting.props.name
|
|
)
|
|
setting_element = ET.SubElement(
|
|
nm_settings_docs_element,
|
|
"setting",
|
|
attrib={
|
|
"name": setting.props.name,
|
|
"description": class_desc,
|
|
"name_upper": get_setting_name_define(settingxml),
|
|
},
|
|
)
|
|
|
|
setting_properties = {
|
|
prop.name: prop
|
|
for prop in GObject.list_properties(setting)
|
|
if prop.name != "name"
|
|
}
|
|
|
|
for prop in sorted(setting_properties):
|
|
pspec = setting_properties[prop]
|
|
|
|
propxml = settingxml.find('./gi:property[@name="%s"]' % pspec.name, ns_map)
|
|
if propxml is None:
|
|
propxml = basexml.find('./gi:property[@name="%s"]' % pspec.name, ns_map)
|
|
if propxml is None:
|
|
propxml = ipxml.find('./gi:property[@name="%s"]' % pspec.name, ns_map)
|
|
|
|
value_type = get_prop_type(setting, pspec)
|
|
value_desc = get_docs(propxml)
|
|
default_value = get_default_value(setting, pspec, propxml)
|
|
|
|
if "deprecated" in propxml.attrib:
|
|
deprecated = True
|
|
deprecated_since = propxml.attrib["deprecated-version"]
|
|
deprecated_desc = format_docs(propxml.find("gi:doc-deprecated", ns_map))
|
|
else:
|
|
deprecated = False
|
|
|
|
prop_upper = prop.upper().replace("-", "_")
|
|
|
|
if value_desc is None:
|
|
raise Exception(
|
|
"%s.%s needs a documentation description"
|
|
% (setting.props.name, prop)
|
|
)
|
|
|
|
property_attributes = {
|
|
"name": prop,
|
|
"name_upper": prop_upper,
|
|
"type": value_type,
|
|
}
|
|
|
|
if default_value is not None:
|
|
property_attributes["default"] = str(default_value)
|
|
|
|
property_element = ET.SubElement(
|
|
setting_element,
|
|
"property",
|
|
attrib=property_attributes,
|
|
)
|
|
|
|
ET.SubElement(
|
|
property_element,
|
|
"description",
|
|
).text = value_desc
|
|
|
|
if value_desc:
|
|
description_docbook = ET.SubElement(
|
|
property_element,
|
|
"description-docbook",
|
|
)
|
|
|
|
create_desc_docbook(description_docbook, value_desc)
|
|
|
|
if deprecated:
|
|
ET.SubElement(
|
|
property_element,
|
|
"deprecated",
|
|
attrib={
|
|
"since": deprecated_since,
|
|
},
|
|
).text = deprecated_desc
|
|
|
|
deprecated_docbook = ET.SubElement(
|
|
property_element,
|
|
"deprecated-docbook",
|
|
)
|
|
|
|
create_desc_docbook(deprecated_docbook, deprecated_desc)
|
|
|
|
docs_gir.write(
|
|
output_path_str,
|
|
xml_declaration=True,
|
|
encoding="utf-8",
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument(
|
|
"-l",
|
|
"--lib-path",
|
|
metavar="PATH",
|
|
action="append",
|
|
help="path to scan for shared libraries",
|
|
)
|
|
parser.add_argument(
|
|
"-g",
|
|
"--gir",
|
|
metavar="FILE",
|
|
help="NM-1.0.gir file",
|
|
required=True,
|
|
)
|
|
parser.add_argument(
|
|
"-o",
|
|
"--output",
|
|
metavar="FILE",
|
|
help="output file",
|
|
required=True,
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
if args.lib_path:
|
|
for lib in args.lib_path:
|
|
GIRepository.Repository.prepend_library_path(lib)
|
|
|
|
main(args.gir, args.output)
|