X-Git-Url: https://sigrok.org/gitweb/?p=sigrok-util.git;a=blobdiff_plain;f=source%2Fnew-driver;h=14178d3241dfb5849abe4886aff646601444f6d1;hp=dea8a1fb26a5ab900326046e02f855f3567207a0;hb=4e20cf8ffda277860b350a98fb86bf5d07ce1a80;hpb=3e61a9d88b4bf56277fdb8b6f86061aa05ae08cf diff --git a/source/new-driver b/source/new-driver index dea8a1f..14178d3 100755 --- a/source/new-driver +++ b/source/new-driver @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 ## ## This file is part of the sigrok-util project. ## @@ -21,76 +21,55 @@ import os import sys import tempfile -from subprocess import Popen, PIPE +from subprocess import Popen, PIPE, check_output import shutil import re import socket import datetime -TMPL_AUTOCONF_DRIVER = "DRIVER([${name}], [${short}])\n" -TMPL_AUTOCONF_AM_CONDITIONAL = """\ -AM_CONDITIONAL(HW_${upper}, test x$HW_${upper} = xyes) -if test "x$HW_${upper}" = "xyes"; then - AC_DEFINE(HAVE_HW_${upper}, 1, [${name} support]) -fi +TMPL_AUTOCONF_DRIVER = "SR_DRIVER([{name}], [{short}])\n" -""" +TMPL_FILES = ('protocol.h', 'protocol.c', 'api.c') -TMPL_HWMAKE_DRIVERLIB = """if HW_${upper} -libsigrok_la_SOURCES += \\ - hardware/${short}/protocol.h \\ - hardware/${short}/protocol.c \\ - hardware/${short}/api.c -endif -""" -TMPL_DRIVERS_EXTERN = """\ -#ifdef HAVE_HW_${upper} -extern SR_PRIV struct sr_dev_driver ${lib}_driver_info; -#endif -""" -TMPL_DRIVERS_POINTER = """\ -#ifdef HAVE_HW_${upper} - &${lib}_driver_info, -#endif -""" -FILE_DRV_API = 'drv-api.c' -FILE_DRV_PROTOCOL = 'drv-protocol.c' -FILE_DRV_PROTOCOL_H = 'drv-protocol.h' +TMPL_HWMAKE_DRIVERLIB = """if HW_{upper} +src_libdrivers_la_SOURCES +=""" +for tmpl_file in TMPL_FILES: + TMPL_HWMAKE_DRIVERLIB += " \\\n\tsrc/hardware/{short}/" + tmpl_file +TMPL_HWMAKE_DRIVERLIB += "\nendif\n" -def tmpl(template): - out = re.sub(r'\${([^}]+)}', lambda x: str(names[x.group(1)]), template) - return out +def tmpl(template, names): + return template.format(**names) -def tmpl_file(filename): - template = open(TMPLDIR + '/' + filename).read() +def tmpl_file(filename, tmpldir, names): + with open(os.path.join(tmpldir, filename)) as template: + return tmpl(template.read(), names) - return tmpl(template) - -def new_driver(): +def new_driver(srcurl, tmpldir, names): tmp = tempfile.mkdtemp() try: - os.chdir(tmp) - process = Popen("git clone " + LIBSR, shell=True, stderr=PIPE) + process = Popen(['git', 'clone', '--depth=1', srcurl, tmp], + stdout=PIPE, stderr=PIPE) out, err = process.communicate() if process.returncode: raise Exception(err.decode()) - gitdir = tmp + '/libsigrok/' - do_autoconf(gitdir) - do_drivers(gitdir) - do_automake(gitdir) - do_driverskel(gitdir) - make_patch(gitdir) + gitdir = tmp + do_autoconf(gitdir, names) + do_automake(gitdir, names) + do_driverskel(gitdir, tmpldir, names) + make_patch(gitdir, names) except Exception as e: + raise print(e) - shutil.rmtree(tmp) + finally: + shutil.rmtree(tmp) -# add DRIVER and AM_CONDITIONAL/AC_DEFINE entries to configure.ac -def do_autoconf(gitdir): - cacpath = gitdir + 'configure.ac' +# add DRIVER entry to configure.ac +def do_autoconf(gitdir, names): + cacpath = os.path.join(gitdir, 'configure.ac') configure_ac = open(cacpath).read() out = '' @@ -98,91 +77,41 @@ def do_autoconf(gitdir): active = False for line in configure_ac.split('\n')[:-1]: if state == 'driver': - m = re.match('DRIVER\(\[([^\]]+)', line) + m = re.match(r'SR_DRIVER\(\[([^\]]+)', line) if m: active = True if active: if (m and m.group(1).upper() > names['name'].upper()) or m is None: - out += tmpl(TMPL_AUTOCONF_DRIVER) - state = 'automake' - active = False - elif state == 'automake': - m = re.match('AM_CONDITIONAL\(HW_([^,]+)', line) - if m: - active = True - else: - submatch = re.match('(if|\s*AC_DEFINE|fi|$)', line) - if active and submatch is None: - # we're past the conditionals - out += tmpl(TMPL_AUTOCONF_AM_CONDITIONAL) - state = 'done' - if active: - if (m and m.group(1) > names['upper']): - out += tmpl(TMPL_AUTOCONF_AM_CONDITIONAL) + out += tmpl(TMPL_AUTOCONF_DRIVER, names) state = 'done' + active = False out += line + '\n' if state != 'done': - raise Exception('No DRIVER entries found in configure.ac') + raise Exception('No SR_DRIVER entries found in configure.ac') open(cacpath, 'w').write(out) -# add HAVE_HW_ extern and pointers to drivers.c -def do_drivers(gitdir): - path = gitdir + 'drivers.c' - source = open(path).read() - out = '' - state = 'extern' - first_entry = '' - for line in source.split('\n')[:-1]: - m = re.match('#ifdef HAVE_HW_(.*)', line) - if m: - if not first_entry: - first_entry = m.group(1) - elif m.group(1) == first_entry: - # second time we see this, so we're past the externs - if state != 'idle': - # tack driver on to the end of the list - out += tmpl(TMPL_DRIVERS_EXTERN) - state = 'pointer' - if state == 'extern': - if m.group(1) > names['upper']: - out += tmpl(TMPL_DRIVERS_EXTERN) - state = 'idle' - elif state == 'pointer': - if m.group(1) > names['upper']: - out += tmpl(TMPL_DRIVERS_POINTER) - state = 'done' - elif state == 'pointer' and not re.match('(\s*&|#endif|$)', line): - # we passed the last entry - out += tmpl(TMPL_DRIVERS_POINTER) - state = 'done' - out += line + '\n' - if state != 'done': - raise Exception('No "HAVE_HW_*" markers found in drivers.c' + state) - open(path, 'w').write(out) - - # add HW_ entry to Makefile.am -def do_automake(gitdir): - path = gitdir + 'Makefile.am' +def do_automake(gitdir, names): + path = os.path.join(gitdir, 'Makefile.am') hwmake = open(path).read() out = '' state = 'copy' for line in hwmake.split('\n')[:-1]: - if state == 'copy' and re.match('if HW_(.*)$', line): + if state == 'copy' and re.match(r'if\s+HW_\w+$', line): state = 'drivers' if state == 'drivers': - m = re.match('if HW_(.*)$', line) + m = re.match(r'if\s+HW_(\w+)$', line) if m: drv_short = m.group(1) if drv_short > names['upper']: - out += tmpl(TMPL_HWMAKE_DRIVERLIB) + out += tmpl(TMPL_HWMAKE_DRIVERLIB, names) state = 'done' - elif not re.match('(libsigrok_la_SOURCES|\s*hardware/|endif)', line): + elif not re.match(r'\s*src_libdrivers_la_SOURCES\b|\s*src/hardware/|endif\b', line): print("[%s]" % line.strip()) # we passed the last entry - out += tmpl(TMPL_HWMAKE_DRIVERLIB) + out += tmpl(TMPL_HWMAKE_DRIVERLIB, names) state = 'done' out += line + '\n' if state != 'done': @@ -190,84 +119,92 @@ def do_automake(gitdir): open(path, 'w').write(out) -def do_driverskel(gitdir): - drvdir = gitdir + 'hardware/' + names['short'] +def do_driverskel(gitdir, tmpldir, names): + drvdir = os.path.join(gitdir, 'src', 'hardware', names['short']) os.mkdir(drvdir) - open(drvdir + '/api.c', 'w').write(tmpl_file(FILE_DRV_API)) - open(drvdir + '/protocol.c', 'w').write(tmpl_file(FILE_DRV_PROTOCOL)) - open(drvdir + '/protocol.h', 'w').write(tmpl_file(FILE_DRV_PROTOCOL_H)) + for fname in TMPL_FILES: + with open(os.path.join(drvdir, fname), 'w') as outf: + outf.write(tmpl_file('drv-{0}'.format(fname), tmpldir, names)) -def make_patch(gitdir): - os.chdir(gitdir) - command('git add hardware/' + names['short']) - cmd = 'git commit -m "%s: Initial driver skeleton." ' % names['short'] - cmd += 'configure.ac Makefile.am drivers.c hardware/' + names['short'] - command(cmd) - cmd = "git format-patch HEAD~1" - out, err = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE).communicate() - if err: - raise Exception(err.decode()) - patch = out.decode().strip() - shutil.move(gitdir + '/' + patch, scriptdir + '/' + patch) - print(patch) +def make_patch(gitdir, names): + cwd = os.getcwd() + try: + os.chdir(gitdir) + command(['git', 'add', os.path.join('src', 'hardware', names['short'])]) + cmd = ['git', 'commit', + '-m', '%s: Initial driver skeleton.' % names['short'], + 'configure.ac', 'Makefile.am', + os.path.join('src', 'hardware', names['short'])] + command(cmd) + cmd = ['git', 'format-patch', 'HEAD~1'] + out, err = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate() + if err: + raise Exception(err.decode()) + patch = out.decode().strip() + shutil.move(os.path.join(gitdir, patch), cwd) + print("Patch {0} has been generated in {1}".format(patch, cwd)) + finally: + os.chdir(cwd) def command(cmd): - out, err = Popen(cmd, shell=True, stderr=PIPE).communicate() + out, err = Popen(cmd, stderr=PIPE).communicate() if err: raise Exception(err.decode()) def parse_gitconfig(): try: - author = email = None - for line in open(os.environ['HOME'] + '/.gitconfig').readlines(): - m = re.match('\s*(\w+)\s*=\s*(.*)\s*$', line) - if m: - key, value = m.groups() - if key == 'name': - author = value - elif key == 'email': - email = value - if author and email: - break + author = check_output(["git", "config", "user.name"]).decode().strip(); except: - pass - if not author or not email: - print("Please put your name and email in ~/.gitconfig") - sys.exit() - + author = None + try: + email = check_output(["git", "config", "user.email"]).decode().strip(); + except: + email = None return author, email + # # main # -scriptdir = os.getcwd() -if scriptdir.split('/')[-2:] != ['sigrok-util', 'source']: - print("Please call this script from the 'source' directory.") - sys.exit(1) - -LIBSR = 'git://sigrok.org/libsigrok' -LIBSR = 'file:///home/bert/sigrok/libsigrok' -TMPLDIR = scriptdir - -if len(sys.argv) < 2: - print("Usage: new-driver ") - sys.exit() - -author, email = parse_gitconfig() -name = ' '.join(sys.argv[1:]) -names = { - 'name': name, - 'short': re.sub('[^a-z0-9]', '-', name.lower()), - 'lib': re.sub('[^a-z0-9]', '_', name.lower()), - 'upper': re.sub('[^A-Z0-9]', '_', name.upper()), - 'libupper': re.sub('[^A-Z0-9]', '', name.upper()), - 'year': datetime.datetime.now().year, - 'author': author, - 'email': email, -} -new_driver() +if __name__ == '__main__': + from argparse import ArgumentParser + + defaulturl = 'git://sigrok.org/libsigrok' + defaultdir = os.path.abspath(os.path.dirname(__file__)) + author, email = parse_gitconfig() + + parser = ArgumentParser(description='Bootstrap a new sigrok hardware driver') + parser.add_argument('name', nargs='*', default=[], help='new driver name') + parser.add_argument('--giturl', default=defaulturl, + help='URL of the libsigrok git repository ' + '(defaults to {0})'.format(defaulturl)) + parser.add_argument('--tmpl-dir', default=defaultdir, + help='Directory in which the templates are stored ' + '(defaults to {0})'.format(defaultdir)) + parser.add_argument('--author', default=author, required=not author, + help='User name to write the Copyright lines') + parser.add_argument('--email', default=email, required=not email, + help='Email address to write the Copyright lines') + opts = parser.parse_args() + + if not opts.author or not opts.email: + parser.error('Please provide your username and email address, ' + 'or set your git configuration up.') + name = ' '.join(opts.name) + if not name: + parser.error('Please provide a driver name.') + names = { + 'name': name, + 'short': re.sub('[^a-z0-9]', '-', name.lower()), + 'lib': re.sub('[^a-z0-9]', '_', name.lower()), + 'upper': re.sub('[^A-Z0-9]', '_', name.upper()), + 'year': datetime.datetime.now().year, + 'author': opts.author, + 'email': opts.email, + } + new_driver(opts.giturl, opts.tmpl_dir, names)