2019-11-14 17:54:26 +00:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
import json
|
|
|
|
import os.path
|
|
|
|
from string import Template
|
2019-11-15 01:05:30 +00:00
|
|
|
from enum import IntEnum
|
|
|
|
from itertools import groupby
|
|
|
|
from functools import lru_cache
|
2019-11-14 17:54:26 +00:00
|
|
|
|
|
|
|
BASE_PATH = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
TEMPLATE_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
|
|
|
"templates")
|
|
|
|
DATAFILE_PATH = os.path.join(BASE_PATH,
|
|
|
|
"..", "..", "drivers.json")
|
|
|
|
LINUX_README_PATH = os.path.join(BASE_PATH,
|
|
|
|
"..", "..", "README.md")
|
2019-11-15 01:05:30 +00:00
|
|
|
WINDOWS_README_PATH = os.path.join(BASE_PATH,
|
|
|
|
"..", "..", "win", "README.md")
|
2019-11-14 17:54:26 +00:00
|
|
|
ENCODING="utf-8"
|
|
|
|
|
2019-11-15 01:05:30 +00:00
|
|
|
class Product(IntEnum):
|
|
|
|
GeForce = 10
|
|
|
|
Quadro = 20
|
|
|
|
|
|
|
|
class WinSeries(IntEnum):
|
|
|
|
win10 = 10
|
|
|
|
win7 = 20
|
|
|
|
ws2012 = 30
|
|
|
|
ws2016 = 40
|
|
|
|
|
|
|
|
PRODUCT_LABELS = {
|
|
|
|
Product.GeForce: "GeForce",
|
|
|
|
Product.Quadro: "Quadro",
|
|
|
|
}
|
|
|
|
|
|
|
|
WIN_SERIES_LABELS = {
|
|
|
|
WinSeries.win10: "Windows 10",
|
|
|
|
WinSeries.win7: "Windows 7, Windows 8, Windows 8.1",
|
|
|
|
WinSeries.ws2012: "Windows Server 2008R2, 2012, 2012R2",
|
|
|
|
WinSeries.ws2016: "Windows Server 2016, 2019",
|
|
|
|
}
|
|
|
|
|
|
|
|
@lru_cache(maxsize=None)
|
|
|
|
def template(filename, strip_newlines=False):
|
2019-11-14 17:54:26 +00:00
|
|
|
filename = os.path.join(TEMPLATE_PATH, filename)
|
|
|
|
with open(filename, encoding=ENCODING) as f:
|
2019-11-15 01:05:30 +00:00
|
|
|
text = f.read()
|
|
|
|
if strip_newlines:
|
|
|
|
text = text.rstrip('\r\n')
|
|
|
|
t = Template(text)
|
2019-11-14 17:54:26 +00:00
|
|
|
return t
|
|
|
|
|
|
|
|
def version_key_fun(ver):
|
|
|
|
return tuple(map(int, ver.split('.')))
|
|
|
|
|
|
|
|
def find_driver(drivers, version, low=0, hi=None):
|
2019-11-15 01:05:30 +00:00
|
|
|
""" Bisect search on sorted linux drivers list """
|
2019-11-14 17:54:26 +00:00
|
|
|
if hi is None:
|
|
|
|
hi = len(drivers)
|
|
|
|
L = hi - low
|
|
|
|
if L == 0:
|
|
|
|
return None
|
|
|
|
elif L == 1:
|
|
|
|
return drivers[low] if drivers[low]['version'] == version else None
|
|
|
|
else:
|
|
|
|
vkf_left = version_key_fun(drivers[low + L // 2]['version'])
|
|
|
|
vkf_right = version_key_fun(version)
|
|
|
|
if vkf_left < vkf_right:
|
|
|
|
return find_driver(drivers, version, low + L // 2, hi)
|
|
|
|
elif vkf_left > vkf_right:
|
|
|
|
return find_driver(drivers, version, low, low + L // 2)
|
|
|
|
else:
|
|
|
|
return drivers[low + L // 2]
|
|
|
|
|
|
|
|
def linux_readme(data):
|
2019-11-15 01:05:30 +00:00
|
|
|
master_tmpl = template('linux_readme_master.tmpl')
|
|
|
|
nolink_row_tmpl = template('linux_nolink_row.tmpl', True)
|
|
|
|
link_row_tmpl = template('linux_link_row.tmpl', True)
|
2019-11-14 17:54:26 +00:00
|
|
|
drivers = sorted(data['drivers'],
|
|
|
|
key=lambda d: version_key_fun(d['version']))
|
|
|
|
def row_gen():
|
|
|
|
for drv in drivers:
|
|
|
|
driver_url = drv.get('driver_url')
|
2019-11-15 01:05:30 +00:00
|
|
|
t = nolink_row_tmpl if driver_url is None else link_row_tmpl
|
2019-11-14 17:54:26 +00:00
|
|
|
yield t.substitute(driver_version=drv['version'],
|
2019-11-15 01:05:30 +00:00
|
|
|
driver_url=driver_url)
|
2019-11-14 17:54:26 +00:00
|
|
|
version_list = "\n".join(row_gen())
|
|
|
|
latest_version = drivers[-1]['version']
|
|
|
|
example_driver = find_driver(drivers, data['example']['version'])
|
|
|
|
example_driver_url = example_driver['driver_url']
|
|
|
|
return master_tmpl.substitute(version_list=version_list,
|
|
|
|
latest_version=latest_version,
|
|
|
|
example_driver_url=example_driver_url,
|
|
|
|
example_driver_version=example_driver['version'],
|
|
|
|
example_driver_file=os.path.basename(example_driver_url))
|
|
|
|
|
2019-11-15 01:05:30 +00:00
|
|
|
def windows_driver_rows(drivers):
|
|
|
|
driver_row_tmpl = template('windows_driver_row.tmpl', True)
|
|
|
|
markdown_link_tmpl = template('markdown_link.tmpl', True)
|
|
|
|
def row_gen():
|
|
|
|
for d in drivers:
|
|
|
|
product = PRODUCT_LABELS[Product[d['product']]]
|
|
|
|
variant = d.get('variant')
|
|
|
|
version_variant = d['version']
|
|
|
|
version_variant += (" " + variant) if variant else ''
|
|
|
|
patch64_url = d.get('patch64_url')
|
|
|
|
patch32_url = d.get('patch32_url')
|
|
|
|
driver_url = d.get('driver_url')
|
|
|
|
patch64_link = markdown_link_tmpl.substitute(text="Direct link",
|
|
|
|
url=patch64_url) if patch64_url else ''
|
|
|
|
patch32_link = markdown_link_tmpl.substitute(text="Direct link",
|
|
|
|
url=patch32_url) if patch32_url else ''
|
|
|
|
driver_link = markdown_link_tmpl.substitute(text="Direct link",
|
|
|
|
url=driver_url) if driver_url else ''
|
|
|
|
yield driver_row_tmpl.substitute(product=product,
|
|
|
|
version_variant=version_variant,
|
|
|
|
patch64_link=patch64_link,
|
|
|
|
patch32_link=patch32_link,
|
|
|
|
driver_link=driver_link)
|
|
|
|
return "\n".join(row_gen())
|
|
|
|
|
|
|
|
def windows_product_sections(drivers):
|
|
|
|
product_section_tmpl = template('windows_product_section.tmpl')
|
|
|
|
def section_gen():
|
|
|
|
for k, g in groupby(drivers, lambda d: Product[d['product']]):
|
|
|
|
driver_rows = windows_driver_rows(g)
|
|
|
|
yield product_section_tmpl.substitute(driver_rows=driver_rows)
|
|
|
|
return '\n\n'.join(section_gen())
|
|
|
|
|
|
|
|
def windows_driver_table(drivers):
|
|
|
|
os_section_tmpl = template('windows_os_section.tmpl', True)
|
|
|
|
def section_gen():
|
|
|
|
for k, g in groupby(drivers, lambda d: WinSeries[d['os']]):
|
|
|
|
os = WIN_SERIES_LABELS[k]
|
|
|
|
product_sections = windows_product_sections(g)
|
|
|
|
yield os_section_tmpl.substitute(os=os,
|
|
|
|
product_sections=product_sections)
|
|
|
|
return '\n\n'.join(section_gen())
|
|
|
|
|
|
|
|
def windows_readme(data):
|
|
|
|
master_tmpl = template('windows_readme_master.tmpl')
|
|
|
|
def driver_key_fun(d):
|
|
|
|
return ((WinSeries[d['os']], Product[d['product']]) +
|
|
|
|
version_key_fun(d['version']) +
|
|
|
|
(d.get('variant'),))
|
|
|
|
drivers = sorted(data['drivers'], key=driver_key_fun)
|
|
|
|
version_table = windows_driver_table(drivers)
|
|
|
|
|
|
|
|
geforce_drivers = filter(lambda d: Product[d['product']] is Product.GeForce, drivers)
|
|
|
|
quadro_drivers = filter(lambda d: Product[d['product']] is Product.Quadro, drivers)
|
|
|
|
latest_geforce_version = max(geforce_drivers, default='xxx.xx',
|
|
|
|
key=lambda d: version_key_fun(d['version']))['version']
|
|
|
|
latest_quadro_version = max(quadro_drivers, default='xxx.xx',
|
|
|
|
key=lambda d: version_key_fun(d['version']))['version']
|
|
|
|
return master_tmpl.substitute(version_table=version_table,
|
|
|
|
latest_geforce_version=latest_geforce_version,
|
|
|
|
latest_quadro_version=latest_quadro_version)
|
|
|
|
|
2019-11-14 17:54:26 +00:00
|
|
|
def main():
|
|
|
|
with open(DATAFILE_PATH) as data_file:
|
|
|
|
data = json.load(data_file)
|
|
|
|
res = linux_readme(data['linux']['x86_64'])
|
|
|
|
with open(LINUX_README_PATH, 'w', encoding=ENCODING) as out:
|
|
|
|
out.write(res)
|
2019-11-15 01:05:30 +00:00
|
|
|
res = windows_readme(data['win']['x86_64'])
|
|
|
|
with open(WINDOWS_README_PATH, 'w', encoding=ENCODING) as out:
|
|
|
|
out.write(res)
|
2019-11-14 17:54:26 +00:00
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|