]> sigrok.org Git - sigrok-util.git/blob - source/new-driver
new-driver: Update for new SR_DRIVER() macro
[sigrok-util.git] / source / new-driver
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
21 import os
22 import sys
23 import tempfile
24 from subprocess import Popen, PIPE, check_output
25 import shutil
26 import re
27 import socket
28 import datetime
29
30 TMPL_AUTOCONF_DRIVER = "SR_DRIVER([${name}], [${short}])\n"
31
32 TMPL_HWMAKE_DRIVERLIB = """if HW_${upper}
33 libsigrok_la_SOURCES += \\
34         src/hardware/${short}/protocol.h \\
35         src/hardware/${short}/protocol.c \\
36         src/hardware/${short}/api.c
37 endif
38 """
39 TMPL_DRIVERS_EXTERN = """\
40 #ifdef HAVE_HW_${upper}
41 extern SR_PRIV struct sr_dev_driver ${lib}_driver_info;
42 #endif
43 """
44 TMPL_DRIVERS_POINTER = """\
45 #ifdef HAVE_HW_${upper}
46         (DRVS) {&${lib}_driver_info, NULL},
47 #endif
48 """
49 FILE_DRV_API = 'drv-api.c'
50 FILE_DRV_PROTOCOL = 'drv-protocol.c'
51 FILE_DRV_PROTOCOL_H = 'drv-protocol.h'
52
53 def tmpl(template):
54     out = re.sub(r'\${([^}]+)}', lambda x: str(names[x.group(1)]), template)
55
56     return out
57
58
59 def tmpl_file(filename):
60     template = open(TMPLDIR + '/' + filename).read()
61
62     return tmpl(template)
63
64
65 def 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
85 def 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
109 def 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
150 def 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
177 def 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
185 def 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
200 def command(cmd):
201     out, err = Popen(cmd, shell=True, stderr=PIPE).communicate()
202     if err:
203         raise Exception(err.decode())
204
205
206 def 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
220 scriptdir = os.getcwd()
221 if scriptdir.split('/')[-2:] != ['sigrok-util', 'source']:
222         print("Please call this script from the 'source' directory.")
223         sys.exit(1)
224
225 LIBSR = 'git://sigrok.org/libsigrok'
226 TMPLDIR = scriptdir
227
228 if len(sys.argv) < 2:
229     print("Usage: new-driver <name>")
230     sys.exit()
231
232 author, email = parse_gitconfig()
233 name = ' '.join(sys.argv[1:])
234 names = {
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 }
243 new_driver()
244