#!/usr/bin/python3 ## ## This file is part of the sigrok-util project. ## ## Copyright (C) 2012 Bert Vermeulen ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . ## import os import sys import tempfile from subprocess import Popen, PIPE import shutil import re import socket import datetime TMPL_AUTOCONF_DRIVER = "DRIVER([${name}], [${short}])\n" TMPL_AUTOCONF_DRIVER2 = "DRIVER2([HW_${upper}], [$HW_${upper}], [HAVE_HW_${upper}])\n" TMPL_HWMAKE_DRIVERLIB = """if HW_${upper} libsigrok_la_SOURCES += \\ src/hardware/${short}/protocol.h \\ src/hardware/${short}/protocol.c \\ src/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' def tmpl(template): out = re.sub(r'\${([^}]+)}', lambda x: str(names[x.group(1)]), template) return out def tmpl_file(filename): template = open(TMPLDIR + '/' + filename).read() return tmpl(template) def new_driver(): tmp = tempfile.mkdtemp() try: os.chdir(tmp) process = Popen("git clone " + LIBSR, shell=True, 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) except Exception as e: print(e) shutil.rmtree(tmp) # add DRIVER and DRIVER2 entries to configure.ac def do_autoconf(gitdir): cacpath = gitdir + 'configure.ac' configure_ac = open(cacpath).read() out = '' state = 'driver' active = False for line in configure_ac.split('\n')[:-1]: if state == 'driver': m = re.match('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('DRIVER2\(\[([^\]]+)', line) if m: active = True else: submatch = re.match('DRIVER2\(\[([^\]]+)', line) if active and submatch is None: # we're past the DRIVER2 list out += tmpl(TMPL_AUTOCONF_DRIVER2) state = 'done' if active: if (m and m.group(1) > 'HW_' + names['upper']): out += tmpl(TMPL_AUTOCONF_DRIVER2) state = 'done' out += line + '\n' if state != 'done': raise Exception('No 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 + 'src/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' hwmake = open(path).read() out = '' state = 'copy' for line in hwmake.split('\n')[:-1]: if state == 'copy' and re.match('if HW_(.*)$', line): state = 'drivers' if state == 'drivers': m = re.match('if HW_(.*)$', line) if m: drv_short = m.group(1) if drv_short > names['upper']: out += tmpl(TMPL_HWMAKE_DRIVERLIB) state = 'done' elif not re.match('(libsigrok_la_SOURCES|\s*src/hardware/|endif)', line): print("[%s]" % line.strip()) # we passed the last entry out += tmpl(TMPL_HWMAKE_DRIVERLIB) state = 'done' out += line + '\n' if state != 'done': raise Exception('No "if HW_" markers found in Makefile.am') open(path, 'w').write(out) def do_driverskel(gitdir): drvdir = 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)) def make_patch(gitdir): os.chdir(gitdir) command('git add src/hardware/' + names['short']) cmd = 'git commit -m "%s: Initial driver skeleton." ' % names['short'] cmd += 'configure.ac Makefile.am src/drivers.c src/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 command(cmd): out, err = Popen(cmd, shell=True, 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 except: pass if not author or not email: print("Please put your name and email in ~/.gitconfig") sys.exit() 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' 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()