]> sigrok.org Git - sigrok-util.git/blob - source/new-driver
new-driver: Whitespace and cosmetics.
[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
25 import shutil
26 import re
27 import socket
28 import datetime
29
30 TMPL_AUTOCONF_AC_ARG_ENABLE = """\
31 AC_ARG_ENABLE(${short}, AC_HELP_STRING([--enable-${short}],
32               [enable ${name} driver support [default=yes]]),
33               [HW_${upper}="$enableval"],
34               [HW_${upper}=yes])
35 AM_CONDITIONAL(HW_${upper}, test x$HW_${upper} = xyes)
36 if test "x$HW_${upper}" = "xyes"; then
37         AC_DEFINE(HAVE_HW_${upper}, 1, [${name} driver support])
38 fi
39
40 """
41 TMPL_AUTOCONF_AC_CONFIG_FILES = "\t\t hardware/${short}/Makefile\n"
42 TMPL_AUTOCONF_SUMMARY = 'echo "  - ${summary}"\n'
43 TMPL_HWMAKE_SUBDIR = '\t${short}'
44 FILE_DRV_MAKEFILE = 'drv-Makefile.am'
45 FILE_DRV_API = 'drv-api.c'
46 FILE_DRV_PROTOCOL = 'drv-protocol.c'
47 FILE_DRV_PROTOCOL_H = 'drv-protocol.h'
48
49 def tmpl(template):
50     out = re.sub(r'\${([^}]+)}', lambda x: str(names[x.group(1)]), template)
51
52     return out
53
54
55 def tmpl_file(filename):
56     template = open(TMPLDIR + '/' + filename).read()
57
58     return tmpl(template)
59
60
61 def new_driver():
62     tmp = tempfile.mkdtemp()
63     try:
64         os.chdir(tmp)
65         out, err = Popen("git clone " + LIBSR, shell=True, stderr=PIPE).communicate()
66         if err:
67             raise Exception(err.decode())
68         gitdir = tmp + '/libsigrok/'
69         do_configure_ac(gitdir)
70         do_hwmake(gitdir)
71         do_driverskel(gitdir)
72         make_patch(gitdir)
73     except Exception as e:
74         print(e)
75     shutil.rmtree(tmp)
76
77
78 def do_configure_ac(gitdir):
79     cacpath = gitdir + 'configure.ac'
80     configure_ac = open(cacpath).read()
81
82     # add AC_ARG_ENABLE option
83     out = ''
84     state = 'copy'
85     for line in configure_ac.split('\n')[:-1]:
86         if state == 'copy':
87             if line == "# Hardware support '--enable' options.":
88                 state = 'acarg'
89         elif state == 'acarg':
90             m = re.match('AC_ARG_ENABLE\(([^,]+)', line)
91             if m:
92                 drv_short = m.group(1)
93                 if drv_short.lower() > names['short']:
94                     out += tmpl(TMPL_AUTOCONF_AC_ARG_ENABLE)
95                     state = 'done'
96             if line == '# Checks for libraries.':
97                 # new one at the end
98                 out += tmpl(TMPL_AUTOCONF_AC_ARG_ENABLE)
99                 state = 'done'
100         out += line + '\n'
101     if state != 'done':
102         raise Exception('AC_ARG_ENABLE markers not found in configure.ac')
103     configure_ac = out
104
105     # add driver Makefile to AC_CONFIG_FILES
106     out = ''
107     state = 'copy'
108     for line in configure_ac.split('\n')[:-1]:
109         if state == 'copy':
110             if line.find("AC_CONFIG_FILES([Makefile") > -1:
111                 state = 'acconf'
112         elif state == 'acconf':
113             m = re.match('\t\t hardware/([^/]+)/Makefile', line)
114             if m:
115                 drv_short = m.group(1)
116                 if drv_short.lower() > names['short']:
117                     out += tmpl(TMPL_AUTOCONF_AC_CONFIG_FILES)
118                     state = 'done'
119             else:
120                 # new one at the end
121                 out += tmpl(TMPL_AUTOCONF_AC_CONFIG_FILES)
122                 state = 'done'
123         out += line + '\n'
124     if state != 'done':
125         raise Exception('AC_CONFIG_FILES marker not found in configure.ac')
126     configure_ac = out
127
128     # add summary line
129     out = ''
130     state = 'copy'
131     names['summary'] = "%s%s $HW_%s" % (names['name'],
132             '.' * (32 - len(names['name'])), names['upper'])
133     for line in configure_ac.split('\n')[:-1]:
134         if state == 'copy':
135             if line.find('Enabled hardware drivers') > -1:
136                 state = 'echo'
137         elif state == 'echo':
138             m = re.match('echo "  - ([^\.]+)', line)
139             if m:
140                 drv_short = m.group(1)
141                 if drv_short.lower() > names['name'].lower():
142                     out += tmpl(TMPL_AUTOCONF_SUMMARY)
143                     state = 'done'
144             else:
145                 # new one at the end
146                 out += tmpl(TMPL_AUTOCONF_SUMMARY)
147                 state = 'done'
148         out += line + '\n'
149     if state != 'done':
150         raise Exception('summary marker not found in configure.ac')
151     configure_ac = out
152
153     open(cacpath, 'w').write(configure_ac)
154
155
156 def do_hwmake(gitdir):
157     path = gitdir + 'hardware/Makefile.am'
158     hwmake = open(path).read()
159
160     # add AC_ARG_ENABLE option
161     out = ''
162     state = 'copy'
163     for line in hwmake.split('\n')[:-1]:
164         if state == 'copy':
165             if line.find('SUBDIRS =') > -1:
166                 state = 'subdirs'
167         elif state == 'subdirs':
168             m = re.match('\t([^ \\\]+\s*\\\)', line)
169             if m:
170                 drv_short = m.group(1)
171                 if drv_short.lower() > names['short']:
172                     out += tmpl(TMPL_HWMAKE_SUBDIR) + ' \\\n'
173                     state = 'done'
174             else:
175                 out += tmpl(TMPL_HWMAKE_SUBDIR) + ' \\\n'
176                 state = 'done'
177         out += line + '\n'
178     if state != 'done':
179         raise Exception('SUBDIRS markers not found in hardware/Makefile.am')
180     hwmake = out
181
182     open(path, 'w').write(hwmake)
183
184
185 def do_driverskel(gitdir):
186     drvdir = gitdir + 'hardware/' + names['short']
187     os.mkdir(drvdir)
188     open(drvdir + '/Makefile.am', 'w').write(tmpl_file(FILE_DRV_MAKEFILE))
189     open(drvdir + '/api.c', 'w').write(tmpl_file(FILE_DRV_API))
190     open(drvdir + '/protocol.c', 'w').write(tmpl_file(FILE_DRV_PROTOCOL))
191     open(drvdir + '/protocol.h', 'w').write(tmpl_file(FILE_DRV_PROTOCOL_H))
192
193
194 def make_patch(gitdir):
195     os.chdir(gitdir)
196     command('git add hardware/' + names['short'])
197     cmd = 'git commit -m "%s: Initial driver skeleton." ' % names['short']
198     cmd += 'configure.ac hardware/Makefile.am hardware/' + names['short']
199     command(cmd)
200     cmd = "git format-patch HEAD~1"
201     out, err = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE).communicate()
202     if err:
203         raise Exception(err.decode())
204     patch = out.decode().strip()
205     shutil.move(gitdir + '/' + patch, scriptdir + '/' + patch)
206     print(patch)
207
208
209 def command(cmd):
210     out, err = Popen(cmd, shell=True, stderr=PIPE).communicate()
211     if err:
212         raise Exception(err.decode())
213
214
215 def parse_gitconfig():
216     try:
217         author = email = None
218         for line in open(os.environ['HOME'] + '/.gitconfig').readlines():
219             m = re.match('\s*(\w+)\s*=\s*(.*)\s*$', line)
220             if m:
221                 key, value = m.groups()
222                 if key == 'name':
223                     author = value
224                 elif key == 'email':
225                     email = value
226                 if author and email:
227                     break
228     except:
229         pass
230     if not author or not email:
231         print("Please put your name and email in ~/.gitconfig")
232         sys.exit()
233
234     return author, email
235
236 #
237 # main
238 #
239
240 scriptdir = os.getcwd()
241 if socket.gethostname() == 'sigrok':
242     LIBSR = '/data/git/libsigrok'
243     TMPLDIR = '/data/tools/tmpl'
244 else:
245     LIBSR = 'git://sigrok.org/libsigrok'
246     TMPLDIR = scriptdir
247
248 if len(sys.argv) < 2:
249     print("Usage: new-driver <name>")
250     sys.exit()
251
252 author, email = parse_gitconfig()
253 name = ' '.join(sys.argv[1:])
254 names = {
255     'name': name,
256     'short': re.sub('[^a-z0-9]', '-', name.lower()),
257     'lib': re.sub('[^a-z0-9]', '_', name.lower()),
258     'upper': re.sub('[^A-Z0-9]', '_', name.upper()),
259     'libupper': re.sub('[^A-Z0-9]', '', name.upper()),
260     'year': datetime.datetime.now().year,
261     'author': author,
262     'email': email,
263 }
264 new_driver()
265