diff --git a/tools/nv-driver-locator/README.md b/tools/nv-driver-locator/README.md index 688ea53..b250fdf 100644 --- a/tools/nv-driver-locator/README.md +++ b/tools/nv-driver-locator/README.md @@ -23,6 +23,7 @@ All scripts may be used both as standalone application and importable module. Fo * mailer.py - module with email routines and minimalistic email client for test purposes. * gfe\_get\_driver.py - GeForce Experience client library (and test util). * get\_nvidia\_downloads.py - Nvidia downloads site parser (and test util). +* get\_vulkan\_downloads.py - Nvidia Developer downloads site parser (and test util). Used for Vulkan Beta Drivers. ### Operation @@ -214,6 +215,20 @@ All scripts may be used both as standalone application and importable module. Fo "type": "cuda_downloads", "name": "cuda toolkit tracker", "params": {} + }, + { + "type": "vulkan_beta", + "name": "vulkan beta windows", + "params": { + "os": "Windows" + } + }, + { + "type": "vulkan_beta", + "name": "vulkan beta linux", + "params": { + "os": "Linux" + } } ], "notifiers": [ @@ -306,6 +321,17 @@ Params: * `timeout` - allowed delay in seconds for each network operation. Default: `10.0` +#### VulkanBetaDownloadsChannel + +Parses Nvidia Developer downloads site for latest Vulkan Beta Drivers. + +Type: `vulkan_beta` + +Params: + +* `os` - OS family. Allowed values: `Linux`, `Windows`. Default: `Linux`. +* `timeout` - allowed delay in seconds for each network operation. Default: `10.0` + ### Notifiers #### CommandNotifier diff --git a/tools/nv-driver-locator/get_vulkan_downloads.py b/tools/nv-driver-locator/get_vulkan_downloads.py new file mode 100755 index 0000000..be0a508 --- /dev/null +++ b/tools/nv-driver-locator/get_vulkan_downloads.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 + +import sys +import urllib.request +import urllib.error +import urllib.parse +import codecs +import enum +import re +from bs4 import BeautifulSoup + +USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64; rv:65.0) '\ + 'Gecko/20100101 Firefox/65.0' +URL = 'https://developer.nvidia.com/vulkan-driver' + +def parse_args(): + import argparse + + def check_positive_float(val): + val = float(val) + if val <= 0: + raise ValueError("Value %s is not valid positive float" % + (repr(val),)) + return val + + parser = argparse.ArgumentParser( + description="Retrieves info about latest NVIDIA Vulkan beta drivers " + "from developer downloads site", + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument("-T", "--timeout", + type=check_positive_float, + default=10., + help="timeout for network operations") + args = parser.parse_args() + return args + + +def fetch_url(url, timeout=10): + http_req = urllib.request.Request( + url, + data=None, + headers={ + 'User-Agent': USER_AGENT + } + ) + with urllib.request.urlopen(http_req, None, timeout) as resp: + coding = resp.headers.get_content_charset() + coding = coding if coding is not None else 'utf-8-sig' + decoder = codecs.getreader(coding)(resp) + res = decoder.read() + return res + + +def get_drivers(*, timeout=10): + body = fetch_url(URL) + soup = BeautifulSoup(body, 'html.parser') + result = [] + for sibling in soup.find('h4', + string=re.compile(r'Vulkan .* Developer Beta Driver Downloads', re.I) + ).next_siblings: + if sibling.name == 'h4': + break + if sibling.name == 'p' and sibling.b is not None: + m = re.match(r'(Windows|Linux)\s+((\d+\.){1,2}\d+)', sibling.b.string) + if m is not None: + ver = m.group(2) + os = m.group(1) + obj = { + "name": "Vulkan Beta Driver for %s" % (os,), + "os": os, + "version": ver, + } + result.append(obj) + return result + + +def main(): + import pprint + args = parse_args() + pprint.pprint(get_drivers(timeout=args.timeout)) + + +if __name__ == '__main__': + main() diff --git a/tools/nv-driver-locator/nv-driver-locator.json.sample b/tools/nv-driver-locator/nv-driver-locator.json.sample index 4325f35..9d1061c 100644 --- a/tools/nv-driver-locator/nv-driver-locator.json.sample +++ b/tools/nv-driver-locator/nv-driver-locator.json.sample @@ -238,6 +238,20 @@ "type": "cuda_downloads", "name": "cuda toolkit tracker", "params": {} + }, + { + "type": "vulkan_beta", + "name": "vulkan beta windows", + "params": { + "os": "Windows" + } + }, + { + "type": "vulkan_beta", + "name": "vulkan beta linux", + "params": { + "os": "Linux" + } } ], "notifiers": [ diff --git a/tools/nv-driver-locator/nv-driver-locator.py b/tools/nv-driver-locator/nv-driver-locator.py index c78bcc7..785ca97 100755 --- a/tools/nv-driver-locator/nv-driver-locator.py +++ b/tools/nv-driver-locator/nv-driver-locator.py @@ -7,6 +7,7 @@ import hashlib import importlib import logging from abc import ABC, abstractmethod +import functools HASH_DELIM = b'\x00' @@ -275,6 +276,33 @@ class CudaToolkitDownloadsChannel(BaseChannel): } } +@functools.lru_cache(maxsize=0) +def vulkan_downloads(*, timeout=10): + gvd = importlib.import_module('get_vulkan_downloads') + return gvd.get_drivers(timeout=timeout) + +class VulkanBetaDownloadsChannel(BaseChannel): + def __init__(self, name, *, + os="Linux", + timeout=10): + self.name = name + self._os = os + self._timeout = timeout + + def get_latest_driver(self): + drivers = vulkan_downloads(timeout=self._timeout) + for drv in drivers: + if drv["os"] == self._os: + return { + 'DriverAttributes': { + 'Version': drv['version'], + 'Name': drv['name'], + 'NameLocalized': drv['name'], + } + } + else: + return None + def parse_args(): parser = argparse.ArgumentParser( @@ -303,6 +331,7 @@ class DriverLocator: 'gfe_client': GFEClientChannel, 'nvidia_downloads': NvidiaDownloadsChannel, 'cuda_downloads': CudaToolkitDownloadsChannel, + 'vulkan_beta': VulkanBetaDownloadsChannel, } channels = []