]> sigrok.org Git - sigrok-util.git/blame_incremental - source/new-driver
Create bundle.sh
[sigrok-util.git] / source / new-driver
... / ...
CommitLineData
1#!/usr/bin/python3
2##
3## This file is part of the sigrok-util project.
4##
5## Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
6##
7## This program is free software: you can redistribute it and/or modify
8## it under the terms of the GNU General Public License as published by
9## the Free Software Foundation, either version 3 of the License, or
10## (at your option) any later version.
11##
12## This program is distributed in the hope that it will be useful,
13## but WITHOUT ANY WARRANTY; without even the implied warranty of
14## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15## GNU General Public License for more details.
16##
17## You should have received a copy of the GNU General Public License
18## along with this program. If not, see <http://www.gnu.org/licenses/>.
19##
20
21import os
22import sys
23import tempfile
24from subprocess import Popen, PIPE, check_output
25import shutil
26import re
27import socket
28import datetime
29
30TMPL_AUTOCONF_DRIVER = "SR_DRIVER([${name}], [${short}])\n"
31
32TMPL_HWMAKE_DRIVERLIB = """if HW_${upper}
33libsigrok_la_SOURCES += \\
34 src/hardware/${short}/protocol.h \\
35 src/hardware/${short}/protocol.c \\
36 src/hardware/${short}/api.c
37endif
38"""
39TMPL_DRIVERS_EXTERN = """\
40#ifdef HAVE_HW_${upper}
41extern SR_PRIV struct sr_dev_driver ${lib}_driver_info;
42#endif
43"""
44TMPL_DRIVERS_POINTER = """\
45#ifdef HAVE_HW_${upper}
46 (DRVS) {&${lib}_driver_info, NULL},
47#endif
48"""
49FILE_DRV_API = 'drv-api.c'
50FILE_DRV_PROTOCOL = 'drv-protocol.c'
51FILE_DRV_PROTOCOL_H = 'drv-protocol.h'
52
53def tmpl(template):
54 out = re.sub(r'\${([^}]+)}', lambda x: str(names[x.group(1)]), template)
55
56 return out
57
58
59def tmpl_file(filename):
60 template = open(TMPLDIR + '/' + filename).read()
61
62 return tmpl(template)
63
64
65def new_driver():
66 tmp = tempfile.mkdtemp()
67 try:
68 os.chdir(tmp)
69 process = Popen("git clone --depth=1 " + LIBSR, shell=True, stderr=PIPE)
70 out, err = process.communicate()
71 if process.returncode:
72 raise Exception(err.decode())
73 gitdir = tmp + '/libsigrok/'
74 do_autoconf(gitdir)
75 do_drivers(gitdir)
76 do_automake(gitdir)
77 do_driverskel(gitdir)
78 make_patch(gitdir)
79 except Exception as e:
80 print(e)
81 shutil.rmtree(tmp)
82
83
84# add DRIVER and DRIVER2 entries to configure.ac
85def do_autoconf(gitdir):
86 cacpath = gitdir + 'configure.ac'
87 configure_ac = open(cacpath).read()
88
89 out = ''
90 state = 'driver'
91 active = False
92 for line in configure_ac.split('\n')[:-1]:
93 if state == 'driver':
94 m = re.match(r'SR_DRIVER\(\[([^\]]+)', line)
95 if m:
96 active = True
97 if active:
98 if (m and m.group(1).upper() > names['name'].upper()) or m is None:
99 out += tmpl(TMPL_AUTOCONF_DRIVER)
100 state = 'done'
101 active = False
102 out += line + '\n'
103 if state != 'done':
104 raise Exception('No SR_DRIVER entries found in configure.ac')
105 open(cacpath, 'w').write(out)
106
107
108# add HAVE_HW_ extern and pointers to drivers.c
109def do_drivers(gitdir):
110 path = gitdir + 'src/drivers.c'
111 source = open(path).read()
112 out = ''
113 iflevel = 0
114 state = 'extern'
115 first_entry = ''
116 for line in source.split('\n')[:-1]:
117 m = re.match(r'\s*#\s*if(?:def)?\s+HAVE_HW_(\w+)', line)
118 if m:
119 if iflevel == 0:
120 if not first_entry:
121 first_entry = m.group(1)
122 elif m.group(1) == first_entry:
123 # second time we see this, so we're past the externs
124 if state != 'idle':
125 # tack driver on to the end of the list
126 out += tmpl(TMPL_DRIVERS_EXTERN)
127 state = 'pointer'
128 if state == 'extern':
129 if m.group(1) > names['upper']:
130 out += tmpl(TMPL_DRIVERS_EXTERN)
131 state = 'idle'
132 elif state == 'pointer':
133 if m.group(1) > names['upper']:
134 out += tmpl(TMPL_DRIVERS_POINTER)
135 state = 'done'
136 iflevel += 1
137 elif re.match(r'\s*#\s*endif\b', line):
138 iflevel -= 1
139 elif iflevel == 0 and state == 'pointer':
140 # we passed the last entry
141 out += tmpl(TMPL_DRIVERS_POINTER)
142 state = 'done'
143 out += line + '\n'
144 if state != 'done':
145 raise Exception('No "HAVE_HW_*" markers found in drivers.c' + state)
146 open(path, 'w').write(out)
147
148
149# add HW_ entry to Makefile.am
150def do_automake(gitdir):
151 path = gitdir + 'Makefile.am'
152 hwmake = open(path).read()
153
154 out = ''
155 state = 'copy'
156 for line in hwmake.split('\n')[:-1]:
157 if state == 'copy' and re.match(r'if\s+HW_\w+$', line):
158 state = 'drivers'
159 if state == 'drivers':
160 m = re.match(r'if\s+HW_(\w+)$', line)
161 if m:
162 drv_short = m.group(1)
163 if drv_short > names['upper']:
164 out += tmpl(TMPL_HWMAKE_DRIVERLIB)
165 state = 'done'
166 elif not re.match(r'\s*libsigrok_la_SOURCES\b|\s*src/hardware/|endif\b', line):
167 print("[%s]" % line.strip())
168 # we passed the last entry
169 out += tmpl(TMPL_HWMAKE_DRIVERLIB)
170 state = 'done'
171 out += line + '\n'
172 if state != 'done':
173 raise Exception('No "if HW_" markers found in Makefile.am')
174 open(path, 'w').write(out)
175
176
177def do_driverskel(gitdir):
178 drvdir = gitdir + 'src/hardware/' + names['short']
179 os.mkdir(drvdir)
180 open(drvdir + '/api.c', 'w').write(tmpl_file(FILE_DRV_API))
181 open(drvdir + '/protocol.c', 'w').write(tmpl_file(FILE_DRV_PROTOCOL))
182 open(drvdir + '/protocol.h', 'w').write(tmpl_file(FILE_DRV_PROTOCOL_H))
183
184
185def make_patch(gitdir):
186 os.chdir(gitdir)
187 command('git add src/hardware/' + names['short'])
188 cmd = 'git commit -m "%s: Initial driver skeleton." ' % names['short']
189 cmd += 'configure.ac Makefile.am src/drivers.c src/hardware/' + names['short']
190 command(cmd)
191 cmd = "git format-patch HEAD~1"
192 out, err = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE).communicate()
193 if err:
194 raise Exception(err.decode())
195 patch = out.decode().strip()
196 shutil.move(gitdir + '/' + patch, scriptdir + '/' + patch)
197 print(patch)
198
199
200def command(cmd):
201 out, err = Popen(cmd, shell=True, stderr=PIPE).communicate()
202 if err:
203 raise Exception(err.decode())
204
205
206def parse_gitconfig():
207 author = email = None
208 try:
209 author = check_output(["git", "config", "user.name"]).decode().strip();
210 email = check_output(["git", "config", "user.email"]).decode().strip();
211 except:
212 print("Please set your name and email in your git config")
213 sys.exit()
214 return author, email
215
216#
217# main
218#
219
220scriptdir = os.getcwd()
221if scriptdir.split('/')[-2:] != ['sigrok-util', 'source']:
222 print("Please call this script from the 'source' directory.")
223 sys.exit(1)
224
225LIBSR = 'git://sigrok.org/libsigrok'
226TMPLDIR = scriptdir
227
228if len(sys.argv) < 2:
229 print("Usage: new-driver <name>")
230 sys.exit()
231
232author, email = parse_gitconfig()
233name = ' '.join(sys.argv[1:])
234names = {
235 'name': name,
236 'short': re.sub('[^a-z0-9]', '-', name.lower()),
237 'lib': re.sub('[^a-z0-9]', '_', name.lower()),
238 'upper': re.sub('[^A-Z0-9]', '_', name.upper()),
239 'year': datetime.datetime.now().year,
240 'author': author,
241 'email': email,
242}
243new_driver()
244