A throw away script to validate that the generated XML has the
correct versions. It checks if $keyword is present in $git_tag and
also in the $next_git_tag but not in the $previous_git_tag.
Takes almost a minute to run, in my computer.
| python3 ./scripts/version-quest.py -i ./include/ -d ./build/docs/
| # libvirt has 2101 symbols
| # libvirt-qemu has 19 symbols
| # libvirt-lxc has 4 symbols
| # libvirt-admin has 63 symbols
| # Total of 2187 symbols checked
Signed-off-by: Victor Toso <victortoso(a)redhat.com>
---
scripts/version-quest.py | 190 +++++++++++++++++++++++++++++++++++++++
1 file changed, 190 insertions(+)
create mode 100644 scripts/version-quest.py
diff --git a/scripts/version-quest.py b/scripts/version-quest.py
new file mode 100644
index 0000000000..01e5d28c59
--- /dev/null
+++ b/scripts/version-quest.py
@@ -0,0 +1,190 @@
+#!/usr/bin/env python3
+#
+# This is a simple utitly script to help check version of exported
+# types in XML built with scripts/apibuild.py
+#
+# See Copyright for the status of this software.
+#
+# victortoso(a)redhat.com
+#
+
+import os
+import re
+import argparse
+
+tags = []
+includedir = ""
+xmldir = ""
+next_release = "v8.3.0"
+
+allowlist = {
+ 'virDomainSetBlockThreshold': '3.2.0',
+ 'virGetLastErrorMessage': '1.0.5.2',
+ 'virNodeDeviceCreate': '0.5.0',
+ 'virAdmClientClose': '1.3.5',
+ 'virAdmClientFree': '1.3.5',
+ 'virAdmClientGetID': '1.3.5',
+ 'virAdmClientGetInfo': '1.3.5',
+ 'virAdmClientGetTimestamp': '1.3.5',
+ 'virAdmClientGetTransport': '1.3.5',
+ 'virAdmConnectClose': '1.2.17',
+ 'virAdmConnectGetLibVersion': '1.3.1',
+ 'virAdmConnectGetURI': '1.3.1',
+ 'virAdmConnectIsAlive': '1.3.1',
+ 'virAdmConnectListServers': '1.3.2',
+ 'virAdmConnectLookupServer': '1.3.3',
+ 'virAdmConnectOpen': '1.2.17',
+ 'virAdmConnectRef': '1.2.17',
+ 'virAdmConnectRegisterCloseCallback': '1.3.1',
+ 'virAdmConnectUnregisterCloseCallback': '1.3.1',
+ 'virAdmGetVersion': '1.3.0',
+ 'virAdmServerFree': '1.3.2',
+ 'virAdmServerGetClientLimits': '1.3.5',
+ 'virAdmServerGetName': '1.3.2',
+ 'virAdmServerGetThreadPoolParameters': '1.3.4',
+ 'virAdmServerListClients': '1.3.5',
+ 'virAdmServerLookupClient': '1.3.5',
+ 'virAdmServerSetClientLimits': '1.3.5',
+ 'virAdmServerSetThreadPoolParameters': '1.3.4',
+ 'virAdmServerUpdateTlsFiles': '6.2.0',
+ 'virConnectFindStoragePoolSources': '0.4.6',
+ 'virConnectNumOfDefinedDomains': '0.1.6',
+ 'virConnectOpenAuth': '0.4.1',
+ 'virDomainBlockPeek': '0.4.4',
+ 'virDomainMemoryPeek': '0.4.4',
+ 'virNetworkUpdate': '1.0.0',
+ 'virConnectClose': '0.0.1',
+ 'virConnectGetType': '0.0.1',
+ 'virConnectGetVersion': '0.0.1',
+ 'virConnectListDomains': '0.0.1',
+ 'virConnectNumOfDomains': '0.0.1',
+ 'virConnectOpen': '0.0.1',
+ 'virConnectOpenReadOnly': '0.0.1',
+ 'virDomainCreateLinux': '0.0.1',
+ 'virDomainDestroy': '0.0.1',
+ 'virDomainFree': '0.0.1',
+ 'virDomainGetID': '0.0.1',
+ 'virDomainGetInfo': '0.0.1',
+ 'virDomainGetMaxMemory': '0.0.1',
+ 'virDomainGetName': '0.0.1',
+ 'virDomainGetOSType': '0.0.1',
+ 'virDomainGetXMLDesc': '0.0.1',
+ 'virDomainLookupByID': '0.0.1',
+ 'virDomainLookupByName': '0.0.1',
+ 'virDomainRestore': '0.0.2',
+ 'virDomainResume': '0.0.1',
+ 'virDomainSave': '0.0.2',
+ 'virDomainSetMaxMemory': '0.0.1',
+ 'virDomainShutdown': '0.0.1',
+ 'virDomainSuspend': '0.0.1',
+ 'virGetVersion': '0.0.1',
+}
+
+
+def get_symbols(xmlpath: str):
+ symbols = []
+ expression = "<(.*?) name='(.*?)'.*version='(.*?)'"
+ with open(xmlpath) as file:
+ for line in file:
+ r = re.search(expression, line)
+ if r is not None:
+ symbols.append(r.groups())
+
+ return symbols
+
+
+def find_version(symbol, start_version):
+ index = start_version == "" and -1 or tags.index(start_version)
+ for i in range(index + 1, len(tags)):
+ if git_check_symbol(symbol, tags[i]):
+ return tags[i]
+
+ assert False
+
+
+def get_tags_array() -> list[str]:
+ # We will be looking symbols at released tags. Only vx.y.z are
+ # interesting to us.
+ k = os.popen("git tag --list 'v*' | grep -v 'rc' | sort
-V")
+ alltags = k.read().split()
+ return alltags
+
+
+def git_check_symbol(symbol, version, full=False) -> bool:
+ path = full and "" or includedir
+ s = os.system(f"git grep -rqw {symbol} {version} {path}")
+ return os.waitstatus_to_exitcode(s) == 0
+
+
+def check_symbol(symbol, xml_version) -> (bool, str):
+ # For functions that were released with wrong sym version
+ if symbol in allowlist:
+ docversion = f"v{allowlist[symbol]}"
+ if docversion == xml_version:
+ return (False, f"{symbol} allowlist versions match:
{xml_version}")
+
+ if not git_check_symbol(symbol, docversion, True):
+ version = find_version(symbol, docversion)
+ return (False, f"{symbol} allowlist {docversion} => {version}")
+
+ return (True, "")
+
+ # Too recent, just skip.
+ if xml_version == next_release:
+ return (True, "")
+
+ if xml_version not in tags:
+ return (False, f"{symbol}'s {xml_version} does not exist in git
tags")
+
+ index = tags.index(xml_version)
+
+ if not git_check_symbol(symbol, tags[index]):
+ return (False, f"{symbol} does not exist in version {xml_version}")
+
+ # Added in the first release. Seems fine.
+ if index == 0:
+ return (True, "")
+
+ # Ooops. Symbol was found in the previous release too.
+ if git_check_symbol(symbol, tags[index - 1]):
+ version = find_version(symbol, "")
+ return (False, f"{symbol} {tags[index]} => real: {version}")
+
+ # Added in the last tag, nothing else to do.
+ if index == len(tags) - 1:
+ return (True, "")
+
+ # Ooops. Symbol was not found in the next release.
+ if not git_check_symbol(symbol, tags[index + 1]):
+ return (False, f"{symbol} in {tags[index]} but not {tags[index + 1]}")
+
+ return (True, "")
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description="Quest: Versions!")
+ parser.add_argument("-d", "--xmldir", type=str,
+ help="Directory of libvirt-.*.xml APIs")
+ parser.add_argument("-i", "--includedir", type=str,
+ help="Include directory of libvirt")
+
+ args = parser.parse_args()
+ includedir = args.includedir
+ xmldir = args.xmldir
+ tags = get_tags_array()
+
+ counter = {}
+ xmlfiles = ["libvirt", "libvirt-qemu", "libvirt-lxc",
"libvirt-admin"]
+ for xml in xmlfiles:
+ symbols = get_symbols(f"{xmldir}/{xml}-api.xml")
+ counter[xml] = len(symbols)
+ for (symbol_type, symbol_name, symbol_version) in symbols:
+ ok, errmsg = check_symbol(symbol_name, f"v{symbol_version}")
+ if not ok:
+ print(f"{xml}: {symbol_type}: Failed: {errmsg}")
+
+ total = 0
+ for xml in counter.keys():
+ total += counter[xml]
+ print(f"# {xml} has {counter[xml]} symbols")
+ print(f"# Total of {total} symbols checked")
--
2.35.1